Skip to content

Commit

Permalink
feat: added --enum-name-mappings support
Browse files Browse the repository at this point in the history
This allows to change names of enum properties. Especially needed for enums that has `name` as a property which is reserved in `dio` etc

Also fixes #91
  • Loading branch information
gibahjoe committed Nov 8, 2024
1 parent 99f6bec commit 328c9da
Show file tree
Hide file tree
Showing 9 changed files with 348 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ class Openapi {
/// --name-mappings
final Map<String, String>? nameMappings;

/// Specifies mappings between the enum name and the new name in the
/// format of enum_name=AnotherName,enum_name2=OtherName2. You can also
/// have multiple occurrences of this option.
/// --enum-name-mappings
final Map<String, String>? enumNameMappings;

/// specifies mappings between a given class and the import that should
/// be used for that class in the format of type=import,type=import. You
/// can also have multiple occurrences of this option.
Expand Down Expand Up @@ -163,6 +170,7 @@ class Openapi {
this.cleanSubOutputDirectory,
this.typeMappings,
this.nameMappings,
this.enumNameMappings,
this.importMappings,
this.reservedWordsMappings,
this.inlineSchemaNameMappings,
Expand Down Expand Up @@ -197,7 +205,7 @@ class Openapi {
}
if (cleanSubOutputDirectory != null) {
buffer.writeln(
' cleanSubOutputDirectory: [${cleanSubOutputDirectory!.join(", ")}],');
' cleanSubOutputDirectory: ["${cleanSubOutputDirectory!.join('", "')}"],');
}
if (skipSpecValidation != null) {
buffer.writeln(' skipSpecValidation: $skipSpecValidation,');
Expand All @@ -218,6 +226,9 @@ class Openapi {
if (nameMappings != null) {
buffer.writeln(' nameMappings: ${_formatMap(nameMappings!)},');
}
if (enumNameMappings != null) {
buffer.writeln(' enumNameMappings: ${_formatMap(enumNameMappings!)},');
}
if (importMappings != null) {
buffer.writeln(' importMappings: ${_formatMap(importMappings!)},');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void main() {
expect(props.projectPubspecPath, isNull);
expect(props.debugLogging, isFalse);
expect(props.nameMappings, isNull);
expect(props.enumNameMappings, isNull);
expect(props.skipIfSpecIsUnchanged, isTrue);
});
group('NextGen', () {
Expand Down Expand Up @@ -316,6 +317,16 @@ void main() {
contains('nameMappings: {\'name\':\'customName\'}'));
});

test('should include enumNameMappings when set', () {
final openapi = Openapi(
enumNameMappings: {'name': 'customName'},
inputSpec: InputSpec(path: 'example_path'),
generatorName: Generator.dart,
);
expect(openapi.toString().replaceAll('\n', ''),
contains('enumNameMappings: {\'name\':\'customName\'}'));
});

test('should include importMappings when set', () {
final openapi = Openapi(
importMappings: {
Expand Down
1 change: 0 additions & 1 deletion openapi-generator-cli/bin/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ Future<Map<String, dynamic>> loadOrCreateConfig(String configPath) async {

void _logOutput(String message) {
stdout.writeln(message);
print(message);
}

/// Constructs the default OpenAPI Generator JAR file download URL based on the version
Expand Down
5 changes: 5 additions & 0 deletions openapi-generator/lib/src/models/generator_arguments.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ class GeneratorArguments {
/// Defines mappings between OpenAPI spec var/param/model and generated code.
final Map<String, String>? nameMappings;

final Map<String, String>? enumNameMappings;

/// Adds reserved words mappings.
///
/// Supported by [Generator.dio] & [Generator.dioAlt] generators.
Expand All @@ -106,6 +108,7 @@ class GeneratorArguments {
annotations.readPropertyOrDefault('generatorName', Generator.dart),
typeMappings = annotations.readPropertyOrNull('typeMappings'),
nameMappings = annotations.readPropertyOrNull('nameMappings'),
enumNameMappings = annotations.readPropertyOrNull('enumNameMappings'),
importMappings = annotations.readPropertyOrNull('importMappings'),
reservedWordsMappings =
annotations.readPropertyOrNull('reservedWordsMappings'),
Expand Down Expand Up @@ -192,6 +195,8 @@ class GeneratorArguments {
'--type-mappings=${typeMappings!.entries.fold('', foldStringMap())}',
if (nameMappings?.isNotEmpty ?? false)
'--name-mappings=${nameMappings!.entries.fold('', foldStringMap())}',
if (enumNameMappings?.isNotEmpty ?? false)
'--enum-name-mappings=${enumNameMappings!.entries.fold('', foldStringMap())}',
if (inlineSchemaOptions != null)
'--inline-schema-options=${inlineSchemaOptions!.toMap().entries.fold('', foldStringMap(keyModifier: convertToPropertyKey))}',
if (additionalProperties != null)
Expand Down
2 changes: 1 addition & 1 deletion openapi-generator/lib/src/openapi_generator_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
);

if (results.exitCode != 0) {
print('===> args ${await args.jarArgs}');
print('===> args ${args.jarArgs}');
return Future.error(
OutputMessage(
message: 'Failed to generate source code. Build Command output:',
Expand Down
99 changes: 49 additions & 50 deletions openapi-generator/test/builder_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

Expand Down Expand Up @@ -38,40 +37,58 @@ void main() {
});

test('to generate command with import and type mappings', () async {
final annotations = await getReaderForAnnotation('''
@Openapi(
inputSpec: InputSpec(path: '../openapi-spec.yaml'),
typeMappings: {'int-or-string':'IntOrString'},
importMappings: {'IntOrString':'./int_or_string.dart'},
generatorName: Generator.dio,
outputDirectory: '${testSpecPath}output',
)
''');
final args = GeneratorArguments(annotations: annotations);
final annotations = Openapi(
inputSpec: InputSpec(path: '../openapi-spec.yaml'),
typeMappings: {'int-or-string': 'IntOrString'},
importMappings: {'IntOrString': './int_or_string.dart'},
generatorName: Generator.dio,
outputDirectory: '${testSpecPath}output',
);
final args = await getArguments(annotations);
expect(
(await args.jarArgs).join(' '),
args.jarArgs.join(' '),
contains(
'generate -o=${testSpecPath}output -i=../openapi-spec.yaml -g=dart-dio --import-mappings=IntOrString=./int_or_string.dart --type-mappings=int-or-string=IntOrString'));
});

test('to generate command with inline schema mappings', () async {
final annotations = await getReaderForAnnotation('''
@Openapi(
inputSpec: InputSpec(path: '../openapi-spec.yaml'),
typeMappings: {'int-or-string':'IntOrString'},
inlineSchemaNameMappings: {'inline_object_2':'SomethingMapped','inline_object_4':'nothing_new'},
generatorName: Generator.dio,
outputDirectory: '${testSpecPath}output',
)
''');
final args = GeneratorArguments(annotations: annotations);
final annotation = Openapi(
inputSpec: InputSpec(path: '../openapi-spec.yaml'),
typeMappings: {'int-or-string': 'IntOrString'},
inlineSchemaNameMappings: {
'inline_object_2': 'SomethingMapped',
'inline_object_4': 'nothing_new'
},
generatorName: Generator.dio,
outputDirectory: '${testSpecPath}output',
);
final args = await getArguments(annotation);
expect(
(await args.jarArgs).join(' '),
args.jarArgs.join(' '),
equals('''
generate -o=${testSpecPath}output -i=../openapi-spec.yaml -g=dart-dio --inline-schema-name-mappings=inline_object_2=SomethingMapped,inline_object_4=nothing_new --type-mappings=int-or-string=IntOrString
'''
.trim()));
});

test('to generate command with enum name mappings', () async {
final annotation = Openapi(
inputSpec: InputSpec(path: '../openapi-spec.yaml'),
typeMappings: {'int-or-string': 'IntOrString'},
inlineSchemaNameMappings: {
'inline_object_2': 'SomethingMapped',
'inline_object_4': 'nothing_new'
},
enumNameMappings: {'name': 'name_', 'inline_object_4': 'nothing_new'},
generatorName: Generator.dio,
outputDirectory: '${testSpecPath}output',
);
final args = await getArguments(annotation);
expect(
args.jarArgs,
contains(
'--enum-name-mappings=name=name_,inline_object_4=nothing_new'));
});
});

group('generator dioAlt', () {
Expand Down Expand Up @@ -110,18 +127,16 @@ class TestClassConfig extends OpenapiGeneratorConfig {}

test('to generate command with import and type mappings for dioAlt',
() async {
var annots = await getReaderForAnnotation('''
@Openapi(
inputSpec: InputSpec(path:'../openapi-spec.yaml'),
typeMappings: {'int-or-string':'IntOrString'},
importMappings: {'IntOrString':'./int_or_string.dart'},
generatorName: Generator.dioAlt,
outputDirectory: '${testSpecPath}output',
)
''');
var args = GeneratorArguments(annotations: annots);
var annot = Openapi(
inputSpec: InputSpec(path: '../openapi-spec.yaml'),
typeMappings: {'int-or-string': 'IntOrString'},
importMappings: {'IntOrString': './int_or_string.dart'},
generatorName: Generator.dioAlt,
outputDirectory: '${testSpecPath}output',
);
var args = await getArguments(annot);
expect(
(await args.jarArgs).join(' '),
args.jarArgs.join(' '),
equals(
'generate -o=${testSpecPath}output -i=../openapi-spec.yaml -g=dart2-api --import-mappings=IntOrString=./int_or_string.dart --type-mappings=int-or-string=IntOrString'));
});
Expand Down Expand Up @@ -587,19 +602,3 @@ class TestClassConfig extends OpenapiGeneratorConfig {}
});
});
}

Future<ConstantReader> getReaderForAnnotation(String annotationDef) async {
final annotations = (await resolveSource('''
library test_lib;
import 'package:openapi_generator_annotations/openapi_generator_annotations.dart';
$annotationDef
class TestClassConfig {}
''',
(resolver) async => (await resolver.findLibraryByName('test_lib'))!))
.getClass('TestClassConfig')!
.metadata
.map((e) => ConstantReader(e.computeConstantValue()!))
.first;
return annotations;
}
48 changes: 48 additions & 0 deletions openapi-generator/test/github_issues_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:io';

import 'package:openapi_generator/src/process_runner.dart';
import 'package:openapi_generator_annotations/openapi_generator_annotations.dart';
import 'package:path/path.dart' as path;
import 'package:test/expect.dart';
import 'package:test/scaffolding.dart';
Expand All @@ -26,6 +27,53 @@ void main() {
// }
// });

group('#91', () {
var issueNumber = '91';
var parentFolder = path.join(testSpecPath, 'issue', issueNumber);
var workingDirectory = path.join(parentFolder, 'output');
setUpAll(
() {
var workingDirectory = path.join(parentFolder, 'output');
cleanup(workingDirectory);
},
);
test(
'[dart] Test that broken code is not generated for OPENAPI tictactoe example',
() async {
var inputSpecFile =
File('$parentFolder/github_issue_#$issueNumber.json');
var generatedOutput = await generateFromAnnotation(
Openapi(
additionalProperties: AdditionalProperties(
pubName: 'tictactoe_api',
pubAuthor: 'Jon Doe',
pubAuthorEmail: '[email protected]'),
inputSpec: InputSpec(path: inputSpecFile.path),
generatorName: Generator.dart,
cleanSubOutputDirectory: [
'./test/specs/issue/$issueNumber/output'
],
cachePath: './test/specs/issue/$issueNumber/output/cache.json',
outputDirectory: './test/specs/issue/$issueNumber/output'),
process: processRunner,
);

expect(generatedOutput,
contains('Skipping source gen because generator does not need it.'),
reason: generatedOutput);
expect(generatedOutput, contains('Successfully formatted code.'),
reason: generatedOutput);
var analyzeResult = await Process.run(
'dart',
['analyze'],
workingDirectory: workingDirectory,
);
expect(analyzeResult.exitCode, 0,
reason: '${analyzeResult.stdout}\n\n${analyzeResult.stderr}');
cleanup(workingDirectory);
});
});

group('#114', () {
var issueNumber = '114';
var parentFolder = path.join(testSpecPath, 'issue', issueNumber);
Expand Down
Loading

0 comments on commit 328c9da

Please sign in to comment.