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 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
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,17 @@ class MappableBuilder implements Builder {

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

final outputId = buildStep.allowedOutputs.first;
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 \'${uriOfPartial(buildStep.inputId, outputId)}\';\n\n'
'${output.join('\n\n')}\n' //,
);
var outputId = buildStep.inputId.changeExtension('.mapper.dart');

await buildStep.writeAsString(outputId, source);
}

Expand Down Expand Up @@ -138,6 +137,7 @@ class MappableBuilder implements Builder {

output.write('}');

final outputId = buildStep.allowedOutputs.last;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also adjust the code regarding writeImports (see line 125 and 153) , since this currently assumes the output is under the same path as the input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I attempted to follow your instructions, but please double-check them, as I'm uncertain about what you wanted.

var source = DartFormatter(pageWidth: options.lineLength ?? 80).format(
'// coverage:ignore-file\n'
'// GENERATED CODE - DO NOT MODIFY BY HAND\n'
Expand All @@ -146,7 +146,6 @@ class MappableBuilder implements Builder {
'${output.toString()}\n',
);

var outputId = buildStep.inputId.changeExtension('.init.dart');
await buildStep.writeAsString(outputId, source);
}
}
Expand Down
79 changes: 79 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,82 @@ 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;
}

String uriOfPartial(AssetId source, AssetId output) {
assert(source.package == output.package);
String sourcePath = source.path;
String outputPath = output.path;

// Split the paths into individual segments.
List<String> sourceSegments = sourcePath.split('/');
List<String> outputSegments = outputPath.split('/');

// Find the common prefix between source and output paths.
int commonIndex = 0;
for (int i = 0; i < sourceSegments.length && i < outputSegments.length; i++) {
if (sourceSegments[i] != outputSegments[i]) {
break;
}
commonIndex = i;
}

// Calculate the relative path.
List<String> relativeSegments = List.generate(
outputSegments.length - commonIndex - 2,
(_) => '..',
);
relativeSegments.addAll(sourceSegments.sublist(commonIndex + 1));

// Join the segments to form the relative path.
String relativePath = relativeSegments.join('/');
return relativePath;
}
11 changes: 11 additions & 0 deletions packages/dart_mappable_builder/test/simple_model_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:build/build.dart';
import 'package:dart_mappable_builder/src/utils.dart';
import 'package:test/test.dart';

import 'utils/test_mappable.dart';
Expand Down Expand Up @@ -31,5 +33,14 @@ void main() {
},
);
});

test('uriOfPartial', () {
AssetId input = AssetId('package', 'lib/models/model.dart');
AssetId output = AssetId('package',
'lib/models/subfolder1/subfolder2/subfolder3/model.mapper.dart');
expect(uriOfPartial(input, output), '../../../model.dart');
expect(uriOfPartial(output, input),
'subfolder1/subfolder2/subfolder3/model.mapper.dart');
hatch01 marked this conversation as resolved.
Show resolved Hide resolved
});
});
}