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

chore: add dependency manager for Kotlin #1083

Merged
Show file tree
Hide file tree
Changes from 1 commit
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/kotlin/KotlinConstrainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ 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 { KotlinOptions, KotlinTypeMapping } from './KotlinGenerator';

function enumFormatToNumberType(enumValueModel: ConstrainedEnumValueModel, format: string): string {
switch (format) {
Expand Down Expand Up @@ -63,7 +63,7 @@ function interpretUnionValueType(types: string[]): string {
return 'Any';
}

export const KotlinDefaultTypeMapping: TypeMapping<KotlinOptions> = {
export const KotlinDefaultTypeMapping: KotlinTypeMapping = {
Object ({constrainedModel}): string {
return constrainedModel.name;
},
Expand Down
21 changes: 21 additions & 0 deletions src/generators/kotlin/KotlinDependencyManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ConstrainedMetaModel } from '../../models';
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}`);
}
}
67 changes: 50 additions & 17 deletions src/generators/kotlin/KotlinGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<KotlinPreset> {
typeMapping: TypeMapping<KotlinOptions>;
typeMapping: TypeMapping<KotlinOptions, KotlinDependencyManager>;
constraints: Constraints;
collectionType: 'List' | 'Array';
}
export type KotlinTypeMapping = TypeMapping<KotlinOptions, KotlinDependencyManager>;
export interface KotlinRenderCompleteModelOptions {
packageName: string
}
Expand All @@ -38,9 +40,30 @@ export class KotlinGenerator extends AbstractGenerator<KotlinOptions, KotlinRend
constructor(
options?: DeepPartial<KotlinOptions>,
) {
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>): 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.
*/
Expand All @@ -52,13 +75,16 @@ export class KotlinGenerator extends AbstractGenerator<KotlinOptions, KotlinRend
return split(model, metaModelsToSplit);
}

constrainToMetaModel(model: MetaModel): ConstrainedMetaModel {
return constrainMetaModel<KotlinOptions>(
this.options.typeMapping,
this.options.constraints,
constrainToMetaModel(model: MetaModel, options: DeepPartial<KotlinOptions>): ConstrainedMetaModel {
const optionsToUse = KotlinGenerator.getKotlinOptions({...this.options, ...options});
const dependencyManagerToUse = this.getDependencyManager(optionsToUse);
return constrainMetaModel<KotlinOptions, KotlinDependencyManager>(
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
}
);
Expand All @@ -70,11 +96,12 @@ export class KotlinGenerator extends AbstractGenerator<KotlinOptions, KotlinRend
* @param model
* @param inputModel
*/
render(model: ConstrainedMetaModel, inputModel: InputMetaModel): Promise<RenderOutput> {
render(model: ConstrainedMetaModel, inputModel: InputMetaModel, options?: DeepPartial<KotlinOptions>): Promise<RenderOutput> {
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: [] }));
Expand All @@ -90,8 +117,10 @@ export class KotlinGenerator extends AbstractGenerator<KotlinOptions, KotlinRend
* @param options used to render the full output
*/
async renderCompleteModel(model: ConstrainedMetaModel, inputModel: InputMetaModel, options: KotlinRenderCompleteModelOptions): Promise<RenderOutput> {
const outputModel = await this.render(model, inputModel);
const optionsToUse = KotlinGenerator.getKotlinOptions({...this.options, ...options});
const dependencyManagerToUse = this.getDependencyManager(optionsToUse);

const outputModel = await this.render(model, inputModel, optionsToUse);
const packageName = this.sanitizePackageName(options.packageName);
const outputContent = `package ${packageName}
${outputModel.dependencies.join('\n')}
Expand All @@ -107,17 +136,21 @@ ${outputModel.result}`;
.join('.');
}

async renderClass(model: ConstrainedObjectModel, inputModel: InputMetaModel): Promise<RenderOutput> {
async renderClass(model: ConstrainedObjectModel, inputModel: InputMetaModel, options?: DeepPartial<KotlinOptions>): Promise<RenderOutput> {
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<RenderOutput> {
async renderEnum(model: ConstrainedEnumModel, inputModel: InputMetaModel, options?: DeepPartial<KotlinOptions>): Promise<RenderOutput> {
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});
}
}
2 changes: 2 additions & 0 deletions src/generators/kotlin/KotlinRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -15,6 +16,7 @@ export abstract class KotlinRenderer<RendererModelType extends ConstrainedMetaMo
presets: Array<[Preset, unknown]>,
model: RendererModelType,
inputModel: InputMetaModel,
public dependencyManager: KotlinDependencyManager
) {
super(options, generator, presets, model, inputModel);
}
Expand Down
2 changes: 1 addition & 1 deletion src/generators/kotlin/presets/ConstraintsPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}) {
Expand Down
11 changes: 11 additions & 0 deletions test/generators/kotlin/KotlinDependencyManager.spec.ts
Original file line number Diff line number Diff line change
@@ -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.*']);
});
});
});