|
| 1 | +import 'package:analyzer/dart/element/element.dart'; |
| 2 | +import 'package:build/src/builder/build_step.dart'; |
| 3 | +import 'package:openapi_generator/src/utils.dart'; |
| 4 | +import 'package:openapi_generator_annotations/openapi_generator_annotations.dart'; |
| 5 | +import 'package:source_gen/source_gen.dart' as src_gen; |
| 6 | + |
| 7 | +class TestGenerator extends src_gen.GeneratorForAnnotation<Openapi> { |
| 8 | + final bool requireTestClassPrefix; |
| 9 | + |
| 10 | + const TestGenerator({this.requireTestClassPrefix = true}); |
| 11 | + |
| 12 | + @override |
| 13 | + Iterable<String> generateForAnnotatedElement(Element element, |
| 14 | + src_gen.ConstantReader annotation, BuildStep buildStep) sync* { |
| 15 | + assert(!annotation.isNull, 'The source generator should\'nt be null'); |
| 16 | + |
| 17 | + if (element is! ClassElement) { |
| 18 | + throw src_gen.InvalidGenerationSourceError( |
| 19 | + 'Only supports annotated classes.', |
| 20 | + todo: 'Remove `TestAnnotation` from the associated element.', |
| 21 | + element: element, |
| 22 | + ); |
| 23 | + } |
| 24 | + |
| 25 | + if (requireTestClassPrefix && !element.name.startsWith('TestClass')) { |
| 26 | + throw src_gen.InvalidGenerationSourceError( |
| 27 | + 'All classes must start with `TestClass`.', |
| 28 | + todo: 'Rename the type or remove the `TestAnnotation` from class.', |
| 29 | + element: element, |
| 30 | + ); |
| 31 | + } |
| 32 | + |
| 33 | + if (!(annotation.read('useNextGen').literalValue as bool)) { |
| 34 | + if (annotation.read('cachePath').literalValue != null) { |
| 35 | + throw src_gen.InvalidGenerationSourceError( |
| 36 | + 'useNextGen must be set when using cachePath'); |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + // KEEP THIS IN LINE WITH THE FIELDS OF THE ANNOTATION CLASS |
| 41 | + final fields = [ |
| 42 | + SupportedFields(name: 'additionalProperties', type: AdditionalProperties), |
| 43 | + SupportedFields( |
| 44 | + name: 'overwriteExistingFiles', isDeprecated: true, type: bool), |
| 45 | + SupportedFields(name: 'skipSpecValidation', type: bool), |
| 46 | + SupportedFields(name: 'inputSpecFile', isRequired: true, type: String), |
| 47 | + SupportedFields(name: 'templateDirectory', type: String), |
| 48 | + SupportedFields(name: 'generatorName', isRequired: true, type: Generator), |
| 49 | + SupportedFields(name: 'outputDirectory', type: Map), |
| 50 | + SupportedFields(name: 'typeMappings', type: Map), |
| 51 | + SupportedFields(name: 'importMappings', type: Map), |
| 52 | + SupportedFields(name: 'reservedWordsMappings', type: Map), |
| 53 | + SupportedFields(name: 'inlineSchemaNameMappings', type: Map), |
| 54 | + // SupportedFields(name:'inlineSchemaOptions'), |
| 55 | + SupportedFields(name: 'apiPackage', type: String), |
| 56 | + SupportedFields(name: 'fetchDependencies', type: bool), |
| 57 | + SupportedFields(name: 'runSourceGenOnOutput', type: bool), |
| 58 | + SupportedFields(name: 'alwaysRun', isDeprecated: true, type: bool), |
| 59 | + SupportedFields(name: 'cachePath', type: String), |
| 60 | + SupportedFields(name: 'useNextGen', type: bool), |
| 61 | + SupportedFields(name: 'projectPubspecPath', type: String), |
| 62 | + ]..sort((a, b) => a.name.compareTo(b.name)); |
| 63 | + for (final field in fields) { |
| 64 | + final v = annotation.read(field.name); |
| 65 | + try { |
| 66 | + if ([ |
| 67 | + 'inputSpecFile', |
| 68 | + 'projectPubspecPath', |
| 69 | + 'apiPackage', |
| 70 | + 'templateDirectory', |
| 71 | + 'generatorName' |
| 72 | + ].any((element) => field.name == element)) { |
| 73 | + yield 'const ${field.name}=\'${convertToPropertyValue(v.objectValue)}\';\n'; |
| 74 | + } else if (field.name == 'additionalProperties') { |
| 75 | + final mapping = v.revive().namedArguments.map( |
| 76 | + (key, value) => MapEntry(key, convertToPropertyValue(value))); |
| 77 | + // TODO: Is this the expected behaviour? |
| 78 | + // Iterable<MapEntry<String, dynamic>> entries; |
| 79 | + // if (v.objectValue.type is DioProperties) { |
| 80 | + // entries = DioProperties.fromMap(mapping).toMap().entries; |
| 81 | + // } else if (v.objectValue.type is DioAltProperties) { |
| 82 | + // entries = DioAltProperties.fromMap(mapping).toMap().entries; |
| 83 | + // } else { |
| 84 | + // entries = AdditionalProperties.fromMap(mapping).toMap().entries; |
| 85 | + // } |
| 86 | + yield 'const ${field.name}=${mapping.entries.fold('', foldStringMap(valueModifier: (value) => '\'$value\''))};'; |
| 87 | + } else { |
| 88 | + yield 'const ${field.name}=${convertToPropertyValue(v.objectValue)};\n'; |
| 89 | + } |
| 90 | + } catch (_, __) { |
| 91 | + continue; |
| 92 | + } |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + @override |
| 97 | + String toString() => |
| 98 | + 'TestGenerator (requireTestClassPrefix:$requireTestClassPrefix)'; |
| 99 | +} |
| 100 | + |
| 101 | +class SupportedFields<T> { |
| 102 | + final String name; |
| 103 | + final bool isRequired; |
| 104 | + final bool isDeprecated; |
| 105 | + final T? type; |
| 106 | + |
| 107 | + const SupportedFields({ |
| 108 | + required this.name, |
| 109 | + this.isDeprecated = false, |
| 110 | + this.isRequired = false, |
| 111 | + required this.type, |
| 112 | + }); |
| 113 | +} |
0 commit comments