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

add the possibility to set a build_extensions option in the build.yaml #140

Merged
merged 5 commits into from
Dec 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 20 additions & 0 deletions packages/dart_mappable/doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,26 @@ global_options:
generateMethods: [decode, encode, copy, stringify, equals]
```

### `build_extensions`

The `build_extensions` option allows you to specify custom paths for the generated files. This is particularly useful when working with certain code generation scenarios. It takes a map where keys are paths to source files and values are lists of corresponding generated file paths.

#### Example:

Here is an example to write in a build.yaml file to generate the generated files in a `generated` folder:
```yaml
targets:
$default:
builders:
# only to resolve build_runner conflicts
dart_mappable_builder:
options:
build_extensions:
'lib/{{path}}/{{file}}.dart':
- 'lib/{{path}}/generated/{{file}}.mapper.dart'
- 'lib/{{path}}/generated/{{file}}.init.dart'
```

---

<p align="right"><a href="../topics/Copy-With-topic.html">Next: Copy-With</a></p>
10 changes: 9 additions & 1 deletion packages/dart_mappable_builder/lib/src/builder_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import 'package:dart_mappable/dart_mappable.dart';

import 'utils.dart';

const _defaultExtensions = {
'.dart': ['.mapper.dart', '.init.dart']
};

/// The builder options for a specific library
class MappableOptions {
final CaseStyle? caseStyle;
Expand All @@ -13,6 +17,7 @@ class MappableOptions {
final InitializerScope? initializerScope;
final int? lineLength;
final Map<String, String> renameMethods;
final Map<String, List<String>> buildExtensions;

MappableOptions({
this.caseStyle,
Expand All @@ -23,6 +28,7 @@ class MappableOptions {
this.initializerScope,
this.lineLength,
this.renameMethods = const {},
this.buildExtensions = _defaultExtensions,
});

MappableOptions.parse(Map options)
Expand All @@ -36,7 +42,9 @@ class MappableOptions {
initializerScope = null,
lineLength =
options['lineLength'] as int? ?? options['line_length'] as int?,
renameMethods = toMap(options['renameMethods'] ?? {});
renameMethods = toMap(options['renameMethods'] ?? {}),
buildExtensions =
validatedBuildExtensionsFrom(options, _defaultExtensions);

MappableOptions apply(MappableOptions? options, {bool forceJoin = true}) {
if (options == null) return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ class MappableBuilder implements Builder {
}

@override
Map<String, List<String>> get buildExtensions => const {
'.dart': ['.mapper.dart', '.init.dart']
};
Map<String, List<String>> get buildExtensions => options.buildExtensions;

Future<MapperElementGroup> createMapperGroup(BuildStep buildStep) async {
var entryLib = await buildStep.inputLibrary;
Expand Down Expand Up @@ -95,16 +93,20 @@ class MappableBuilder implements Builder {

var output = await Future.wait(generators.map((g) => g.generate()));

final outputId = buildStep.allowedOutputs.first;

var libraryPath =
p.relative(buildStep.inputId.path, from: p.dirname(outputId.path));
var source = DartFormatter(pageWidth: options.lineLength ?? 80).format(
'// coverage:ignore-file\n'
'// GENERATED CODE - DO NOT MODIFY BY HAND\n'
'// ignore_for_file: type=lint\n'
'// ignore_for_file: unused_element, unnecessary_cast\n'
'// ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter\n\n'
'part of \'${p.basename(buildStep.inputId.uri.toString())}\';\n\n'
'part of \'$libraryPath\';\n\n'
'${output.join('\n\n')}\n' //,
);
var outputId = buildStep.inputId.changeExtension('.mapper.dart');

await buildStep.writeAsString(outputId, source);
}

Expand All @@ -123,9 +125,12 @@ class MappableBuilder implements Builder {

discovered.sortBy((e) => e.key.source.uri.toString());

final outputId = buildStep.allowedOutputs.last;

output.write(writeImports(
buildStep.inputId,
discovered.map((e) => e.key.source.uri).toList(),
p.dirname(outputId.uri.path),
));

output.write('void initializeMappers() {\n');
Expand All @@ -146,12 +151,11 @@ class MappableBuilder implements Builder {
'${output.toString()}\n',
);

var outputId = buildStep.inputId.changeExtension('.init.dart');
await buildStep.writeAsString(outputId, source);
}
}

String writeImports(AssetId input, List<Uri> imports) {
String writeImports(AssetId input, List<Uri> imports, String outputDirectory) {
List<String> package = [], relative = [];
var prefixes = <String, int?>{};

Expand All @@ -160,21 +164,14 @@ String writeImports(AssetId input, List<Uri> imports) {
for (var i = 0; i < imports.length; i++) {
var import = imports[i];
if (import.isScheme('asset')) {
var relativePath =
path.relative(import.path, from: path.dirname(input.uri.path));
var relativePath = path.relative(import.path, from: outputDirectory);

relative.add(relativePath);
prefixes[relativePath] = i;
} else if (import.isScheme('package') &&
import.pathSegments.first == input.package &&
input.pathSegments.first == 'lib') {
var libPath =
import.replace(pathSegments: import.pathSegments.skip(1)).path;

var inputPath =
input.uri.replace(pathSegments: input.uri.pathSegments.skip(1)).path;

var relativePath = path.relative(libPath, from: path.dirname(inputPath));
var relativePath = path.relative(import.path, from: outputDirectory);

relative.add(relativePath);
prefixes[relativePath] = i;
Expand Down
49 changes: 49 additions & 0 deletions packages/dart_mappable_builder/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,52 @@ extension ObjectReader on DartObject {
return result;
}
}

Map<String, List<String>> validatedBuildExtensionsFrom(
Map? optionsMap,
Map<String, List<String>> defaultExtensions,
) {
final extensionsOption = optionsMap?.remove('build_extensions');
if (extensionsOption == null) {
// defaultExtensions are provided by the builder author, not the end user.
// It should be safe to skip validation.
return defaultExtensions;
}

if (extensionsOption is! Map) {
throw ArgumentError(
'Configured build_extensions should be a map from inputs to outputs.',
);
}

final result = <String, List<String>>{};

for (final entry in extensionsOption.entries) {
final input = entry.key;
if (input is! String || !input.endsWith('.dart')) {
throw ArgumentError(
'Invalid key in build_extensions option: `$input` '
'should be a string ending with `.dart`',
);
}

final output = (entry.value is List) ? entry.value as List : [entry.value];

for (var i = 0; i < output.length; i++) {
final o = output[i];
if (o is! String || (i == 0 && !o.endsWith('.dart'))) {
throw ArgumentError(
'Invalid output extension `${entry.value}`. It should be a string '
'or a list of strings with the first ending with `.dart`',
);
}
}

result[input] = output.cast<String>().toList();
}

if (result.isEmpty) {
throw ArgumentError('Configured build_extensions must not be empty.');
}
return result;
}
Loading