diff --git a/src/generators/kotlin/KotlinConstrainer.ts b/src/generators/kotlin/KotlinConstrainer.ts index 189cdb1807..43aa668ac3 100644 --- a/src/generators/kotlin/KotlinConstrainer.ts +++ b/src/generators/kotlin/KotlinConstrainer.ts @@ -1,9 +1,8 @@ import { ConstrainedEnumValueModel } from '../../models'; -import { TypeMapping } from '../../helpers'; import { defaultEnumKeyConstraints, defaultEnumValueConstraints } from './constrainer/EnumConstrainer'; import { defaultModelNameConstraints } from './constrainer/ModelNameConstrainer'; import { defaultPropertyKeyConstraints } from './constrainer/PropertyKeyConstrainer'; -import { KotlinOptions } from './KotlinGenerator'; +import { KotlinTypeMapping } from './KotlinGenerator'; function enumFormatToNumberType(enumValueModel: ConstrainedEnumValueModel, format: string): string { switch (format) { @@ -63,7 +62,7 @@ function interpretUnionValueType(types: string[]): string { return 'Any'; } -export const KotlinDefaultTypeMapping: TypeMapping = { +export const KotlinDefaultTypeMapping: KotlinTypeMapping = { Object ({constrainedModel}): string { return constrainedModel.name; }, diff --git a/src/generators/kotlin/KotlinDependencyManager.ts b/src/generators/kotlin/KotlinDependencyManager.ts new file mode 100644 index 0000000000..5081ac5940 --- /dev/null +++ b/src/generators/kotlin/KotlinDependencyManager.ts @@ -0,0 +1,20 @@ +import { AbstractDependencyManager } from '../AbstractDependencyManager'; +import { KotlinOptions } from './KotlinGenerator'; + +export class KotlinDependencyManager extends AbstractDependencyManager { + constructor( + public options: KotlinOptions, + dependencies: string[] = [] + ) { + super(dependencies); + } + + /** + * Adds a dependency package ensuring correct syntax. + * + * @param dependencyPackage package to import, for example `javax.validation.constraints.*` + */ + addDependency(dependencyPackage: string): void { + super.addDependency(`import ${dependencyPackage}`); + } +} diff --git a/src/generators/kotlin/KotlinGenerator.ts b/src/generators/kotlin/KotlinGenerator.ts index 877ee72be7..04c5c5c12f 100644 --- a/src/generators/kotlin/KotlinGenerator.ts +++ b/src/generators/kotlin/KotlinGenerator.ts @@ -13,12 +13,14 @@ import { Logger } from '../..'; import { constrainMetaModel, Constraints } from '../../helpers/ConstrainHelpers'; import { KotlinDefaultConstraints, KotlinDefaultTypeMapping } from './KotlinConstrainer'; import { DeepPartial, mergePartialAndDefault } from '../../utils/Partials'; +import { KotlinDependencyManager } from './KotlinDependencyManager'; export interface KotlinOptions extends CommonGeneratorOptions { - typeMapping: TypeMapping; + typeMapping: TypeMapping; constraints: Constraints; collectionType: 'List' | 'Array'; } +export type KotlinTypeMapping = TypeMapping; export interface KotlinRenderCompleteModelOptions { packageName: string } @@ -38,9 +40,29 @@ export class KotlinGenerator extends AbstractGenerator, ) { - const realizedOptions = mergePartialAndDefault(KotlinGenerator.defaultOptions, options) as KotlinOptions; + const realizedOptions = KotlinGenerator.getKotlinOptions(options); super('Kotlin', realizedOptions); } + + /** + * Returns the Kotlin options by merging custom options with default ones. + */ + static getKotlinOptions(options?: DeepPartial): KotlinOptions { + const optionsToUse = mergePartialAndDefault(KotlinGenerator.defaultOptions, options) as KotlinOptions; + //Always overwrite the dependency manager unless user explicitly state they want it (ignore default temporary dependency manager) + if (options?.dependencyManager === undefined) { + optionsToUse.dependencyManager = () => { return new KotlinDependencyManager(optionsToUse); }; + } + return optionsToUse; + } + + /** + * Wrapper to get an instance of the dependency manager + */ + getDependencyManager(options: KotlinOptions): KotlinDependencyManager { + return this.getDependencyManagerInstance(options) as KotlinDependencyManager; + } + /** * This function makes sure we split up the MetaModels accordingly to what we want to render as models. */ @@ -52,13 +74,16 @@ export class KotlinGenerator extends AbstractGenerator( - this.options.typeMapping, - this.options.constraints, + constrainToMetaModel(model: MetaModel, options: DeepPartial): ConstrainedMetaModel { + const optionsToUse = KotlinGenerator.getKotlinOptions({...this.options, ...options}); + const dependencyManagerToUse = this.getDependencyManager(optionsToUse); + return constrainMetaModel( + optionsToUse.typeMapping, + optionsToUse.constraints, { metaModel: model, - options: this.options, + dependencyManager: dependencyManagerToUse, + options: optionsToUse, constrainedName: '' //This is just a placeholder, it will be constrained within the function } ); @@ -70,11 +95,12 @@ export class KotlinGenerator extends AbstractGenerator { + render(model: ConstrainedMetaModel, inputModel: InputMetaModel, options?: DeepPartial): Promise { + const optionsToUse = KotlinGenerator.getKotlinOptions({...this.options, ...options}); if (model instanceof ConstrainedObjectModel) { - return this.renderClass(model, inputModel); + return this.renderClass(model, inputModel, optionsToUse); } else if (model instanceof ConstrainedEnumModel) { - return this.renderEnum(model, inputModel); + return this.renderEnum(model, inputModel, optionsToUse); } Logger.warn(`Kotlin generator, cannot generate this type of model, ${model.name}`); return Promise.resolve(RenderOutput.toRenderOutput({ result: '', renderedName: '', dependencies: [] })); @@ -90,8 +116,8 @@ export class KotlinGenerator extends AbstractGenerator { - const outputModel = await this.render(model, inputModel); - + const optionsToUse = KotlinGenerator.getKotlinOptions({...this.options, ...options}); + const outputModel = await this.render(model, inputModel, optionsToUse); const packageName = this.sanitizePackageName(options.packageName); const outputContent = `package ${packageName} ${outputModel.dependencies.join('\n')} @@ -107,17 +133,21 @@ ${outputModel.result}`; .join('.'); } - async renderClass(model: ConstrainedObjectModel, inputModel: InputMetaModel): Promise { + async renderClass(model: ConstrainedObjectModel, inputModel: InputMetaModel, options?: DeepPartial): Promise { + const optionsToUse = KotlinGenerator.getKotlinOptions({...this.options, ...options}); + const dependencyManagerToUse = this.getDependencyManager(optionsToUse); const presets = this.getPresets('class'); - const renderer = new ClassRenderer(this.options, this, presets, model, inputModel); + const renderer = new ClassRenderer(this.options, this, presets, model, inputModel, dependencyManagerToUse); const result = await renderer.runSelfPreset(); - return RenderOutput.toRenderOutput({result, renderedName: model.name, dependencies: renderer.dependencies}); + return RenderOutput.toRenderOutput({result, renderedName: model.name, dependencies: dependencyManagerToUse.dependencies}); } - async renderEnum(model: ConstrainedEnumModel, inputModel: InputMetaModel): Promise { + async renderEnum(model: ConstrainedEnumModel, inputModel: InputMetaModel, options?: DeepPartial): Promise { + const optionsToUse = KotlinGenerator.getKotlinOptions({...this.options, ...options}); + const dependencyManagerToUse = this.getDependencyManager(optionsToUse); const presets = this.getPresets('enum'); - const renderer = new EnumRenderer(this.options, this, presets, model, inputModel); + const renderer = new EnumRenderer(this.options, this, presets, model, inputModel, dependencyManagerToUse); const result = await renderer.runSelfPreset(); - return RenderOutput.toRenderOutput({result, renderedName: model.name, dependencies: renderer.dependencies}); + return RenderOutput.toRenderOutput({result, renderedName: model.name, dependencies: dependencyManagerToUse.dependencies}); } } diff --git a/src/generators/kotlin/KotlinRenderer.ts b/src/generators/kotlin/KotlinRenderer.ts index f2a60fb403..8e1b1d4fd9 100644 --- a/src/generators/kotlin/KotlinRenderer.ts +++ b/src/generators/kotlin/KotlinRenderer.ts @@ -2,6 +2,7 @@ import { AbstractRenderer } from '../AbstractRenderer'; import { KotlinGenerator, KotlinOptions } from './KotlinGenerator'; import { ConstrainedMetaModel, InputMetaModel, Preset } from '../../models'; import { FormatHelpers } from '../../helpers'; +import { KotlinDependencyManager } from './KotlinDependencyManager'; /** * Common renderer for Kotlin @@ -15,6 +16,7 @@ export abstract class KotlinRenderer, model: RendererModelType, inputModel: InputMetaModel, + public dependencyManager: KotlinDependencyManager ) { super(options, generator, presets, model, inputModel); } diff --git a/src/generators/kotlin/presets/ConstraintsPreset.ts b/src/generators/kotlin/presets/ConstraintsPreset.ts index ab4ed43227..73b97ea3dc 100644 --- a/src/generators/kotlin/presets/ConstraintsPreset.ts +++ b/src/generators/kotlin/presets/ConstraintsPreset.ts @@ -11,7 +11,7 @@ import {ClassRenderer} from '../renderers/ClassRenderer'; export const KOTLIN_CONSTRAINTS_PRESET: KotlinPreset = { class: { self({renderer, content}) { - renderer.addDependency('import javax.validation.constraints.*'); + renderer.dependencyManager.addDependency('javax.validation.constraints.*'); return content; }, property({ renderer, property, content}) { diff --git a/test/generators/kotlin/KotlinDependencyManager.spec.ts b/test/generators/kotlin/KotlinDependencyManager.spec.ts new file mode 100644 index 0000000000..e9149e999d --- /dev/null +++ b/test/generators/kotlin/KotlinDependencyManager.spec.ts @@ -0,0 +1,11 @@ +import { KotlinGenerator } from '../../../src/generators'; +import { KotlinDependencyManager } from '../../../src/generators/kotlin/KotlinDependencyManager'; +describe('KotlinDependencyManager', () => { + describe('addDependency()', () => { + test('Should be able to render dependency', () => { + const dependencyManager = new KotlinDependencyManager(KotlinGenerator.defaultOptions, []); + dependencyManager.addDependency('javax.validation.*'); + expect(dependencyManager.dependencies).toEqual(['import javax.validation.*']); + }); + }); +});