From ce925c92607a968b615a2f06b65e79ab175b0fdf Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 28 Jun 2022 11:19:53 +0200 Subject: [PATCH] chore: refactored dart generator (#778) --- src/generators/dart/DartConstrainer.ts | 74 ++++++++++ src/generators/dart/DartFileGenerator.ts | 4 +- src/generators/dart/DartGenerator.ts | 65 +++++---- src/generators/dart/DartPreset.ts | 10 +- src/generators/dart/DartRenderer.ts | 126 +----------------- .../dart/constrainer/EnumConstrainer.ts | 64 +++++++++ .../dart/constrainer/ModelNameConstrainer.ts | 40 ++++++ .../constrainer/PropertyKeyConstrainer.ts | 44 ++++++ .../dart/presets/JsonSerializablePreset.ts | 16 +-- src/generators/dart/presets/index.ts | 1 - .../dart/renderers/ClassRenderer.ts | 41 ++---- src/generators/dart/renderers/EnumRenderer.ts | 61 ++------- 12 files changed, 303 insertions(+), 243 deletions(-) create mode 100644 src/generators/dart/DartConstrainer.ts create mode 100644 src/generators/dart/constrainer/EnumConstrainer.ts create mode 100644 src/generators/dart/constrainer/ModelNameConstrainer.ts create mode 100644 src/generators/dart/constrainer/PropertyKeyConstrainer.ts diff --git a/src/generators/dart/DartConstrainer.ts b/src/generators/dart/DartConstrainer.ts new file mode 100644 index 0000000000..97ef12f2d7 --- /dev/null +++ b/src/generators/dart/DartConstrainer.ts @@ -0,0 +1,74 @@ +import { TypeMapping } from '../../helpers'; +import { defaultEnumKeyConstraints, defaultEnumValueConstraints } from './constrainer/EnumConstrainer'; +import { defaultModelNameConstraints } from './constrainer/ModelNameConstrainer'; +import { defaultPropertyKeyConstraints } from './constrainer/PropertyKeyConstrainer'; +import { DartOptions } from './DartGenerator'; + +export const DartDefaultTypeMapping: TypeMapping = { + Object ({constrainedModel}): string { + return constrainedModel.name; + }, + Reference ({constrainedModel}): string { + return constrainedModel.name; + }, + Any (): string { + return 'Object'; + }, + Float (): string { + return 'double'; + }, + Integer (): string { + return 'int'; + }, + String ({constrainedModel}): string { + const format = constrainedModel.originalInput['format']; + switch (format) { + case 'date': + return 'DateTime'; + case 'time': + return 'DateTime'; + case 'dateTime': + case 'date-time': + return 'DateTime'; + case 'string': + case 'password': + case 'byte': + return 'String'; + case 'binary': + return 'byte[]'; + default: return 'string'; + } + }, + Boolean (): string { + return 'bool'; + }, + Tuple ({options}): string { + //Since Dart dont support tuples, lets use the most generic type + if (options.collectionType && options.collectionType === 'List') { + return 'List'; + } + return 'Object[]'; + }, + Array ({constrainedModel, options}): string { + if (options.collectionType && options.collectionType === 'List') { + return `List<${constrainedModel.valueModel.type}>`; + } + return `${constrainedModel.valueModel.type}[]`; + }, + Enum ({constrainedModel}): string { + return constrainedModel.name; + }, + Union (): string { + return 'Object'; + }, + Dictionary ({constrainedModel}): string { + return `Map<${constrainedModel.key.type}, ${constrainedModel.value.type}>`; + } +}; + +export const DartDefaultConstraints = { + enumKey: defaultEnumKeyConstraints(), + enumValue: defaultEnumValueConstraints(), + modelName: defaultModelNameConstraints(), + propertyKey: defaultPropertyKeyConstraints() +}; diff --git a/src/generators/dart/DartFileGenerator.ts b/src/generators/dart/DartFileGenerator.ts index 594750705d..54cafbd624 100644 --- a/src/generators/dart/DartFileGenerator.ts +++ b/src/generators/dart/DartFileGenerator.ts @@ -1,5 +1,5 @@ import { DartGenerator, DartRenderCompleteModelOptions } from './'; -import { CommonInputModel, OutputModel } from '../../models'; +import { InputMetaModel, OutputModel } from '../../models'; import * as path from 'path'; import { AbstractFileGenerator } from '../AbstractFileGenerator'; import { FileHelpers } from '../../helpers'; @@ -12,7 +12,7 @@ export class DartFileGenerator extends DartGenerator implements AbstractFileGene * @param outputDirectory where you want the models generated to * @param options */ - public async generateToFiles(input: Record | CommonInputModel, outputDirectory: string, options: DartRenderCompleteModelOptions): Promise { + public async generateToFiles(input: Record | InputMetaModel, outputDirectory: string, options: DartRenderCompleteModelOptions): Promise { let generatedModels = await this.generateCompleteModels(input, options); generatedModels = generatedModels.filter((outputModel) => { return outputModel.modelName !== undefined; }); for (const outputModel of generatedModels) { diff --git a/src/generators/dart/DartGenerator.ts b/src/generators/dart/DartGenerator.ts index 1b13b95cf8..ae346325e0 100644 --- a/src/generators/dart/DartGenerator.ts +++ b/src/generators/dart/DartGenerator.ts @@ -3,18 +3,21 @@ import { CommonGeneratorOptions, defaultGeneratorOptions } from '../AbstractGenerator'; -import {CommonModel, CommonInputModel, RenderOutput} from '../../models'; -import {CommonNamingConvention, CommonNamingConventionImplementation, ModelKind, TypeHelpers} from '../../helpers'; +import {RenderOutput, ConstrainedMetaModel, MetaModel, ConstrainedObjectModel, ConstrainedEnumModel, InputMetaModel} from '../../models'; +import {CommonNamingConvention, CommonNamingConventionImplementation, constrainMetaModel, Constraints, split, TypeMapping} from '../../helpers'; import {DartPreset, DART_DEFAULT_PRESET} from './DartPreset'; import {ClassRenderer} from './renderers/ClassRenderer'; import {EnumRenderer} from './renderers/EnumRenderer'; import {isReservedDartKeyword} from './Constants'; import {Logger} from '../../'; import {FormatHelpers} from '../../helpers/FormatHelpers'; +import { DartDefaultConstraints, DartDefaultTypeMapping } from './DartConstrainer'; export interface DartOptions extends CommonGeneratorOptions { collectionType?: 'List'; namingConvention?: CommonNamingConvention; + typeMapping: TypeMapping; + constraints: Constraints; } export interface DartRenderCompleteModelOptions { @@ -26,30 +29,51 @@ export class DartGenerator extends AbstractGenerator { - const kind = TypeHelpers.extractKind(model); - // We don't support union in Dart generator, however, if union is an object, we render it as a class. - if (kind === ModelKind.OBJECT || (kind === ModelKind.UNION && model.type?.includes('object'))) { + render(model: ConstrainedMetaModel, inputModel: InputMetaModel): Promise { + if (model instanceof ConstrainedObjectModel) { return this.renderClass(model, inputModel); - } else if (kind === ModelKind.ENUM) { + } else if (model instanceof ConstrainedEnumModel) { return this.renderEnum(model, inputModel); - } - Logger.warn(`Dart generator, cannot generate this type of model, ${model.$id}`); + } + Logger.warn(`Dart generator, cannot generate this type of model, ${model.name}`); return Promise.resolve(RenderOutput.toRenderOutput({result: '', renderedName: '', dependencies: []})); } @@ -62,19 +86,14 @@ export class DartGenerator extends AbstractGenerator { + async renderCompleteModel(model: ConstrainedMetaModel, inputModel: InputMetaModel, options: DartRenderCompleteModelOptions): Promise { if (isReservedDartKeyword(options.packageName)) { throw new Error(`You cannot use reserved Dart keyword (${options.packageName}) as package name, please use another.`); } const outputModel = await this.render(model, inputModel); const modelDependencies = model.getNearestDependencies().map((dependencyModelName) => { - const formattedDependencyModelName = this.options.namingConvention?.type ? this.options.namingConvention.type(dependencyModelName, { - inputModel, - model: inputModel.models[String(dependencyModelName)], - reservedKeywordCallback: isReservedDartKeyword - }) : dependencyModelName; - return `import 'package:${options.packageName}/${FormatHelpers.snakeCase(formattedDependencyModelName)}.dart';`; + return `import 'package:${options.packageName}/${FormatHelpers.snakeCase(dependencyModelName.name)}.dart';`; }); const outputContent = `${modelDependencies.join('\n')} ${outputModel.dependencies.join('\n')} @@ -86,19 +105,17 @@ export class DartGenerator extends AbstractGenerator { + async renderClass(model: ConstrainedObjectModel, inputModel: InputMetaModel): Promise { const presets = this.getPresets('class'); const renderer = new ClassRenderer(this.options, this, presets, model, inputModel); const result = await renderer.runSelfPreset(); - const renderedName = FormatHelpers.snakeCase(renderer.nameType(model.$id, model)); - return RenderOutput.toRenderOutput({result, renderedName, dependencies: renderer.dependencies}); + return RenderOutput.toRenderOutput({result, renderedName: model.name, dependencies: renderer.dependencies}); } - async renderEnum(model: CommonModel, inputModel: CommonInputModel): Promise { + async renderEnum(model: ConstrainedEnumModel, inputModel: InputMetaModel): Promise { const presets = this.getPresets('enum'); const renderer = new EnumRenderer(this.options, this, presets, model, inputModel); const result = await renderer.runSelfPreset(); - const renderedName = FormatHelpers.snakeCase(renderer.nameType(model.$id, model)); - return RenderOutput.toRenderOutput({result, renderedName, dependencies: renderer.dependencies}); + return RenderOutput.toRenderOutput({result, renderedName: model.name, dependencies: renderer.dependencies}); } } diff --git a/src/generators/dart/DartPreset.ts b/src/generators/dart/DartPreset.ts index 6d0860927d..61214df0ba 100644 --- a/src/generators/dart/DartPreset.ts +++ b/src/generators/dart/DartPreset.ts @@ -1,10 +1,14 @@ import { Preset, ClassPreset, EnumPreset } from '../../models'; +import { DartOptions } from './DartGenerator'; import { ClassRenderer, DART_DEFAULT_CLASS_PRESET } from './renderers/ClassRenderer'; import { EnumRenderer, DART_DEFAULT_ENUM_PRESET } from './renderers/EnumRenderer'; -export type DartPreset = Preset<{ - class: ClassPreset; - enum: EnumPreset; +export type ClassPresetType = ClassPreset; +export type EnumPresetType = EnumPreset; + +export type DartPreset = Preset<{ + class: ClassPresetType; + enum: EnumPresetType; }>; export const DART_DEFAULT_PRESET: DartPreset = { diff --git a/src/generators/dart/DartRenderer.ts b/src/generators/dart/DartRenderer.ts index c10db5be6d..0ca3bd8ab2 100644 --- a/src/generators/dart/DartRenderer.ts +++ b/src/generators/dart/DartRenderer.ts @@ -1,143 +1,23 @@ import { AbstractRenderer } from '../AbstractRenderer'; import { DartGenerator, DartOptions } from './DartGenerator'; -import { CommonModel, CommonInputModel, Preset } from '../../models'; -import { FormatHelpers, ModelKind, TypeHelpers } from '../../helpers'; -import { isReservedDartKeyword } from './Constants'; +import { Preset, ConstrainedMetaModel } from '../../models'; /** * Common renderer for Dart types * * @extends AbstractRenderer */ -export abstract class DartRenderer extends AbstractRenderer { +export abstract class DartRenderer extends AbstractRenderer { constructor( options: DartOptions, generator: DartGenerator, presets: Array<[Preset, unknown]>, - model: CommonModel, + model: RendererModelType, inputModel: CommonInputModel, ) { super(options, generator, presets, model, inputModel); } - - /** - * Renders the name of a type based on provided generator option naming convention type function. - * - * This is used to render names of models and then later used if it is referenced from other models. - * - * @param name - * @param model - */ - nameType(name: string | undefined, model?: CommonModel): string { - return this.options?.namingConvention?.type - ? this.options.namingConvention.type(name, { model: model || this.model, inputModel: this.inputModel, reservedKeywordCallback: isReservedDartKeyword }) - : name || ''; - } - - /** - * Renders the name of a property based on provided generator option naming convention property function. - * - * @param propertyName - * @param property - */ - nameProperty(propertyName: string | undefined, property?: CommonModel): string { - return this.options?.namingConvention?.property - ? this.options.namingConvention.property(propertyName, { model: this.model, inputModel: this.inputModel, property, reservedKeywordCallback: isReservedDartKeyword }) - : propertyName || ''; - } - /** - * Renders model(s) to Dart type(s). - * - * @param model - */ - renderType(model: CommonModel | CommonModel[]): string { - if (Array.isArray(model) || Array.isArray(model.type)) { - return 'Object'; // fallback - } - if (model.$ref !== undefined) { - return this.nameType(model.$ref, model); - } - const kind = TypeHelpers.extractKind(model); - if ( - kind === ModelKind.PRIMITIVE || - kind === ModelKind.ARRAY - ) { - const format = model.getFromOriginalInput('format'); - return this.toClassType(this.toDartType(format || model.type, model)); - } - return this.nameType(model.$id, model); - } - - /** - * Returns the Dart corresponding type from CommonModel type or JSON schema format - * @param type - * @param model - */ - toDartType(type: string | undefined, model: CommonModel): string { - switch (type) { - case 'integer': - case 'int32': - case 'long': - case 'int64': - return 'int'; - case 'boolean': - return 'bool'; - case 'date': - return 'DateTime'; - case 'time': - return 'DateTime'; - case 'dateTime': - case 'date-time': - return 'DateTime'; - case 'string': - case 'password': - case 'byte': - return 'String'; - case 'float': - case 'double': - case 'number': - return 'double'; - case 'binary': - return 'byte[]'; - case 'array': { - let arrayItemModel = model.items; - //Since Dart dont support tuples, lets make sure that we combine the tuple types to find the appropriate array type - if (Array.isArray(model.items)) { - arrayItemModel = model.items.reduce((prevModel, currentModel) => { - return CommonModel.mergeCommonModels(CommonModel.toCommonModel(prevModel), CommonModel.toCommonModel(currentModel), {}); - }); - //If tuples and additionalItems make sure to find the appropriate type by merging all the tuples and additionalItems model together to find the combined type. - if (model.additionalItems !== undefined) { - arrayItemModel = CommonModel.mergeCommonModels(arrayItemModel, model.additionalItems, {}); - } - } - const newType = arrayItemModel ? this.renderType(arrayItemModel) : 'Object'; - if (this.options.collectionType && this.options.collectionType === 'List') { - return `List<${newType}>`; - } - return `${newType}[]`; - } - default: - return 'Object'; - } - } - - toClassType(type: string): string { - switch (type) { - case 'int': - case 'long': - return 'int'; - case 'boolean': - return 'bool'; - case 'float': - case 'double': - return 'double'; - default: - return `${type}`; - } - } - renderComments(lines: string | string[]): string { lines = FormatHelpers.breakLines(lines); const newLiteral = lines.map(line => ` * ${line}`).join('\n'); diff --git a/src/generators/dart/constrainer/EnumConstrainer.ts b/src/generators/dart/constrainer/EnumConstrainer.ts new file mode 100644 index 0000000000..b73b6e1b7a --- /dev/null +++ b/src/generators/dart/constrainer/EnumConstrainer.ts @@ -0,0 +1,64 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { ConstrainedEnumModel, EnumModel } from '../../../models'; +import { NO_NUMBER_START_CHAR, NO_DUPLICATE_ENUM_KEYS, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints'; +import { EnumKeyConstraint, EnumValueConstraint, FormatHelpers } from '../../../helpers'; +import { isReservedDartKeyword } from '../Constants'; + +export type ModelEnumKeyConstraints = { + NO_SPECIAL_CHAR: (value: string) => string; + NO_NUMBER_START_CHAR: (value: string) => string; + NO_DUPLICATE_KEYS: (constrainedEnumModel: ConstrainedEnumModel, enumModel: EnumModel, value: string, namingFormatter: (value: string) => string) => string; + NO_EMPTY_VALUE: (value: string) => string; + NAMING_FORMATTER: (value: string) => string; + NO_RESERVED_KEYWORDS: (value: string) => string; +}; + +export const DefaultEnumKeyConstraints: ModelEnumKeyConstraints = { + NO_SPECIAL_CHAR: (value: string) => { + return FormatHelpers.replaceSpecialCharacters(value, { exclude: [' '], separator: '_' }); + }, + NO_NUMBER_START_CHAR, + NO_DUPLICATE_KEYS: NO_DUPLICATE_ENUM_KEYS, + NO_EMPTY_VALUE, + NAMING_FORMATTER: FormatHelpers.toConstantCase, + NO_RESERVED_KEYWORDS: (value: string) => { + return NO_RESERVED_KEYWORDS(value, isReservedDartKeyword); + } +}; + +export function defaultEnumKeyConstraints(customConstraints?: Partial): EnumKeyConstraint { + const constraints = {...DefaultEnumKeyConstraints, ...customConstraints}; + + return ({enumKey, enumModel, constrainedEnumModel}) => { + let constrainedEnumKey = enumKey; + constrainedEnumKey = constraints.NO_SPECIAL_CHAR(constrainedEnumKey); + constrainedEnumKey = constraints.NO_NUMBER_START_CHAR(constrainedEnumKey); + constrainedEnumKey = constraints.NO_EMPTY_VALUE(constrainedEnumKey); + constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS(constrainedEnumKey); + constrainedEnumKey = constraints.NAMING_FORMATTER(constrainedEnumKey); + constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER!); + return constrainedEnumKey; + }; +} + +export function defaultEnumValueConstraints(): EnumValueConstraint { + return ({enumValue}) => { + let normalizedEnumValue; + switch (typeof enumValue.value) { + case 'boolean': + case 'bigint': + case 'number': { + normalizedEnumValue = enumValue.value; + break; + } + case 'object': { + normalizedEnumValue = `"${JSON.stringify(enumValue).replace(/"/g, '\\"')}"`; + break; + } + default: { + normalizedEnumValue = `"${enumValue}"`; + } + } + return normalizedEnumValue; + }; +} diff --git a/src/generators/dart/constrainer/ModelNameConstrainer.ts b/src/generators/dart/constrainer/ModelNameConstrainer.ts new file mode 100644 index 0000000000..a1a35baada --- /dev/null +++ b/src/generators/dart/constrainer/ModelNameConstrainer.ts @@ -0,0 +1,40 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints'; +import { FormatHelpers, ModelNameConstraint } from '../../../helpers'; +import { isReservedDartKeyword } from '../Constants'; + +export type ModelNameConstraints = { + NO_SPECIAL_CHAR: (value: string) => string; + NO_NUMBER_START_CHAR: (value: string) => string; + NO_EMPTY_VALUE: (value: string) => string; + NAMING_FORMATTER: (value: string) => string; + NO_RESERVED_KEYWORDS: (value: string) => string; +}; + +export const DefaultModelNameConstraints: ModelNameConstraints = { + NO_SPECIAL_CHAR: (value: string) => { + return FormatHelpers.replaceSpecialCharacters(value, { exclude: [], separator: '_' }); + }, + NO_NUMBER_START_CHAR, + NO_EMPTY_VALUE, + NAMING_FORMATTER: (value: string) => { + return FormatHelpers.toPascalCase(value); + }, + NO_RESERVED_KEYWORDS: (value: string) => { + return NO_RESERVED_KEYWORDS(value, isReservedDartKeyword); + } +}; + +export function defaultModelNameConstraints(customConstraints?: Partial): ModelNameConstraint { + const constraints = {...DefaultModelNameConstraints, ...customConstraints}; + + return ({modelName}) => { + let constrainedValue = modelName; + constrainedValue = constraints.NO_SPECIAL_CHAR(constrainedValue); + constrainedValue = constraints.NO_NUMBER_START_CHAR(constrainedValue); + constrainedValue = constraints.NO_EMPTY_VALUE(constrainedValue); + constrainedValue = constraints.NO_RESERVED_KEYWORDS(constrainedValue); + constrainedValue = constraints.NAMING_FORMATTER(constrainedValue); + return constrainedValue; + }; +} diff --git a/src/generators/dart/constrainer/PropertyKeyConstrainer.ts b/src/generators/dart/constrainer/PropertyKeyConstrainer.ts new file mode 100644 index 0000000000..7129552980 --- /dev/null +++ b/src/generators/dart/constrainer/PropertyKeyConstrainer.ts @@ -0,0 +1,44 @@ +import { ConstrainedObjectModel, ObjectModel } from '../../../models'; +import { NO_NUMBER_START_CHAR, NO_DUPLICATE_PROPERTIES, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints'; +import { FormatHelpers, PropertyKeyConstraint } from '../../../helpers'; +import { isReservedDartKeyword } from '../Constants'; + +export type PropertyKeyConstraintOptions = { + NO_SPECIAL_CHAR: (value: string) => string; + NO_NUMBER_START_CHAR: (value: string) => string; + NO_DUPLICATE_PROPERTIES: (constrainedObjectModel: ConstrainedObjectModel, objectModel: ObjectModel, propertyName: string, namingFormatter: (value: string) => string) => string; + NO_EMPTY_VALUE: (value: string) => string; + NAMING_FORMATTER: (value: string) => string; + NO_RESERVED_KEYWORDS: (value: string) => string; +}; + +export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = { + NO_SPECIAL_CHAR: (value: string) => { + //Exclude ` ` because it gets formatted by NAMING_FORMATTER + //Exclude '_', '$' because they are allowed + return FormatHelpers.replaceSpecialCharacters(value, { exclude: [' ', '_', '$'], separator: '_' }); + }, + NO_NUMBER_START_CHAR, + NO_DUPLICATE_PROPERTIES, + NO_EMPTY_VALUE, + NAMING_FORMATTER: FormatHelpers.toPascalCase, + NO_RESERVED_KEYWORDS: (value: string) => { + return NO_RESERVED_KEYWORDS(value, isReservedDartKeyword); + } +}; + +export function defaultPropertyKeyConstraints(customConstraints?: Partial): PropertyKeyConstraint { + const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints}; + + return ({objectPropertyModel, constrainedObjectModel, objectModel}) => { + let constrainedPropertyKey = objectPropertyModel.propertyName; + + constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey); + constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey); + constrainedPropertyKey = constraints.NO_EMPTY_VALUE(constrainedPropertyKey); + constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS(constrainedPropertyKey); + constrainedPropertyKey = constraints.NAMING_FORMATTER(constrainedPropertyKey); + constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER); + return constrainedPropertyKey; + }; +} diff --git a/src/generators/dart/presets/JsonSerializablePreset.ts b/src/generators/dart/presets/JsonSerializablePreset.ts index d545982e62..a0d8e7bf05 100644 --- a/src/generators/dart/presets/JsonSerializablePreset.ts +++ b/src/generators/dart/presets/JsonSerializablePreset.ts @@ -1,5 +1,4 @@ import {DartPreset} from '../DartPreset'; -import {FormatHelpers} from '../../../helpers/FormatHelpers'; /** * Preset which adds `json_serializable` related annotations to class's property getters. @@ -10,23 +9,18 @@ export const DART_JSON_PRESET: DartPreset = { class: { self({renderer, model, content}) { renderer.addDependency('import \'package:json_annotation/json_annotation.dart\';'); - const formattedModelName = renderer.nameType(model.$id); - const snakeformattedModelName = FormatHelpers.snakeCase(formattedModelName); - renderer.addDependency(`part '${snakeformattedModelName}.g.dart';`); + renderer.addDependency(`part '${model.name}.g.dart';`); renderer.addDependency('@JsonSerializable()'); return content; }, - additionalContent({renderer, model}) { - const formattedModelName = renderer.nameType(model.$id); - return `factory ${formattedModelName}.fromJson(Map json) => _$${formattedModelName}FromJson(json); -Map toJson() => _$${formattedModelName}ToJson(this);`; + additionalContent({model}) { + return `factory ${model.name}.fromJson(Map json) => _$${model.name}FromJson(json); +Map toJson() => _$${model.name}ToJson(this);`; } }, enum: { self({renderer, model, content}) { renderer.addDependency('import \'package:json_annotation/json_annotation.dart\';'); - const formattedModelName = renderer.nameType(model.$id); - const snakeformattedModelName = FormatHelpers.snakeCase(formattedModelName); - renderer.addDependency(`part '${snakeformattedModelName}.g.dart';`); + renderer.addDependency(`part '${model.name}.g.dart';`); renderer.addDependency('@JsonEnum(alwaysCreate:true)'); return content; }, diff --git a/src/generators/dart/presets/index.ts b/src/generators/dart/presets/index.ts index 82b477a887..18212e3649 100644 --- a/src/generators/dart/presets/index.ts +++ b/src/generators/dart/presets/index.ts @@ -1,2 +1 @@ export * from './JsonSerializablePreset'; - diff --git a/src/generators/dart/renderers/ClassRenderer.ts b/src/generators/dart/renderers/ClassRenderer.ts index 3630aa8588..d4fb9fe7d5 100644 --- a/src/generators/dart/renderers/ClassRenderer.ts +++ b/src/generators/dart/renderers/ClassRenderer.ts @@ -1,13 +1,14 @@ import {DartRenderer} from '../DartRenderer'; -import {CommonModel, ClassPreset, PropertyType} from '../../../models'; -import {DefaultPropertyNames, getUniquePropertyName} from '../../../helpers'; +import {ConstrainedObjectModel, ConstrainedObjectPropertyModel} from '../../../models'; +import { ClassPresetType } from '../DartPreset'; +import { DartOptions } from '../DartGenerator'; /** * Renderer for Dart's `class` type * * @extends DartRenderer */ -export class ClassRenderer extends DartRenderer { +export class ClassRenderer extends DartRenderer { async defaultSelf(): Promise { const content = [ await this.renderProperties(), @@ -16,8 +17,7 @@ export class ClassRenderer extends DartRenderer { await this.runAdditionalContentPreset(), ]; - const formattedName = this.nameType(`${this.model.$id}`); - return `class ${formattedName} { + return `class ${this.model.name} { ${this.indent(this.renderBlock(content, 2))} }`; } @@ -33,24 +33,16 @@ ${this.indent(this.renderBlock(content, 2))} const properties = this.model.properties || {}; const content: string[] = []; - for (const [propertyName, property] of Object.entries(properties)) { - const rendererProperty = await this.runPropertyPreset(propertyName, property); + for (const property of Object.values(properties)) { + const rendererProperty = await this.runPropertyPreset(property); content.push(rendererProperty); } - if (this.model.patternProperties !== undefined) { - for (const [pattern, patternModel] of Object.entries(this.model.patternProperties)) { - const propertyName = getUniquePropertyName(this.model, `${pattern}${DefaultPropertyNames.patternProperties}`); - const renderedPatternProperty = await this.runPropertyPreset(propertyName, patternModel, PropertyType.patternProperties); - content.push(renderedPatternProperty); - } - } - return this.renderBlock(content); } - runPropertyPreset(propertyName: string, property: CommonModel, type: PropertyType = PropertyType.property): Promise { - return this.runPreset('property', {propertyName, property, type}); + runPropertyPreset(property: ConstrainedObjectPropertyModel): Promise { + return this.runPreset('property', {property}); } /** @@ -64,19 +56,14 @@ ${this.indent(this.renderBlock(content, 2))} } } -export const DART_DEFAULT_CLASS_PRESET: ClassPreset = { +export const DART_DEFAULT_CLASS_PRESET: ClassPresetType = { self({renderer}) { return renderer.defaultSelf(); }, - property({renderer, propertyName, property, type}) { - propertyName = renderer.nameProperty(propertyName, property); - let propertyType = renderer.renderType(property); - if (type === PropertyType.additionalProperty || type === PropertyType.patternProperties) { - propertyType = `Map`; - } - return `${propertyType}? ${propertyName};`; + property({property}) { + return `${property.property.type}? ${property.propertyName};`; }, - ctor({renderer,model}) { - return `${renderer.nameType(model.$id)}();`; + ctor({model}) { + return `${model.name}();`; } }; diff --git a/src/generators/dart/renderers/EnumRenderer.ts b/src/generators/dart/renderers/EnumRenderer.ts index f92f8a8837..674354b354 100644 --- a/src/generators/dart/renderers/EnumRenderer.ts +++ b/src/generators/dart/renderers/EnumRenderer.ts @@ -1,28 +1,27 @@ import {DartRenderer} from '../DartRenderer'; -import {EnumPreset} from '../../../models'; -import {FormatHelpers} from '../../../helpers'; +import {ConstrainedEnumModel} from '../../../models'; +import { EnumPresetType } from '../DartPreset'; +import { DartOptions } from '../DartGenerator'; /** * Renderer for Dart's `enum` type * * @extends DartRenderer */ -export class EnumRenderer extends DartRenderer { +export class EnumRenderer extends DartRenderer { async defaultSelf(): Promise { const content = [ await this.renderItems(), ]; - const formattedName = this.nameType(this.model.$id); - return `enum ${formattedName} { + return `enum ${this.model.name} { ${this.indent(this.renderBlock(content, 2))} }`; } async renderItems(): Promise { - const enums = this.model.enum || []; const items: string[] = []; - for (const value of enums) { + for (const value of this.model.values) { const renderedItem = await this.runItemPreset(value); items.push(renderedItem); } @@ -30,58 +29,16 @@ ${this.indent(this.renderBlock(content, 2))} const content = items.join(', '); return `${content}`; } - - normalizeKey(value: any): string { - let key; - switch (typeof value) { - case 'bigint': - case 'number': { - key = 'number_${value}'; - break; - } - case 'boolean': { - key = `boolean_${value}`; - break; - } - case 'object': { - key = JSON.stringify(value); - break; - } - default: { - key = FormatHelpers.replaceSpecialCharacters(String(value), {exclude: [' '], separator: '_'}); - //Ensure no special char can be the beginning letter - if (!(/^[a-zA-Z]+$/).test(key.charAt(0))) { - key = `string_${key}`; - } - } - } - return FormatHelpers.toConstantCase(key); - } - - normalizeValue(value: any): string { - if (typeof value === 'number') { - return `NUMBER_${value}`; - } - if (typeof value === 'string') { - return `${value}`; - } - if (typeof value === 'object') { - return `${JSON.stringify(value).replace(/"/g, '\\"')}`; - } - return String(value); - } - runItemPreset(item: any): Promise { return this.runPreset('item', {item}); } } -export const DART_DEFAULT_ENUM_PRESET: EnumPreset = { +export const DART_DEFAULT_ENUM_PRESET: EnumPresetType = { self({renderer}) { return renderer.defaultSelf(); }, - item({renderer, item}) { - const value = renderer.normalizeValue(item); - return `${value}`; + item({item}) { + return `${item.value}`; }, };