Skip to content
Open
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
2 changes: 2 additions & 0 deletions pkgs/hooks/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
- Add `ProtocolExtension.setupLogger`, which the hooks runner calls to provide
the logger used for validation diagnostics before any other method is invoked
on the extension.
- Add `HookInputUserDefines.baseUri`, which can be used to resolve paths
from nested user-defined options.

## 2.1.0

Expand Down
74 changes: 60 additions & 14 deletions pkgs/hooks/lib/src/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,21 @@ final class HookInputUserDefines {
/// Then:
/// - `input.userDefines['enable_experimental_features']` returns `true`.
/// - `input.userDefines['optimization_level']` returns `"O3"`.
Object? operator [](String key) {
final syntaxNode = _input._syntax.userDefines;
if (syntaxNode == null) {
return null;
}
final packageUserDefines = PackageUserDefinesSyntaxExtension.fromSyntax(
syntaxNode,
);
final pubspecSource = packageUserDefines.workspacePubspec;
return pubspecSource?.defines[key];
}
Object? operator [](String key) => _findDefine([key])?.$1;

/// An absolute [Uri] that can be used to interpret user-defines as paths.
///
/// This uses the [keyPathDefine] to traverse available options, starting at
/// the root. If the key path contains a string, this enters a YAML map. For
/// an integer element, this enters a YAML sequence. Any other key path
/// element is invalid and throws.
/// If no element exists for any position in the key path, null is returned.
///
/// This is a generalized variant of [path] returning the base URI for all
/// options under [keyPathDefine]. To resolve a top-level string option as a
/// path, use [path] directly.
Uri? baseUri(List<Object /* String|int */> keyPathDefine) =>
_findDefine(keyPathDefine)?.$2.basePath;

/// Resolves the relative path provided in the user-define for [key] to an
/// absolute [Uri] pointing to the file or directory on the host filesystem.
Expand Down Expand Up @@ -268,11 +272,30 @@ final class HookInputUserDefines {
/// // Read assets from the directory...
/// }
/// ```
///
/// See also:
///
/// - [baseUri], which returns the equivalent of [Uri.base] for the source
/// defining a key (e.g. the directory containing a workspace pubspec with
/// a `hooks` entry). Unlike this method, which directly interprets a
/// value as a path, the base uri can be used to [Uri.resolve] arbitrary
/// path values.
Uri? path(String key) {
Comment thread
simolus3 marked this conversation as resolved.
if (_findDefine([key]) case (final String value, final source)?) {
return source.basePath.resolve(value);
}

return null;
}

(Object, PackageUserDefinesSource)? _findDefine(
Iterable<Object?> keyPathDefine,
) {
final syntaxNode = _input._syntax.userDefines;
if (syntaxNode == null) {
return null;
}

final packageUserDefines = PackageUserDefinesSyntaxExtension.fromSyntax(
syntaxNode,
);
Expand All @@ -284,9 +307,32 @@ final class HookInputUserDefines {
// TODO(https://github.com/dart-lang/native/issues/2215): Add commandline
// arguments.
for (final source in sources) {
final relativepath = source.defines[key];
if (relativepath is String) {
return source.basePath.resolve(relativepath);
Object? options = source.defines;

for (final (i, key) in keyPathDefine.indexed) {
if (key is String) {
if (options is Map) {
options = options[key];
} else {
return null;
}
} else if (key is int) {
if (options is List) {
options = options[key];
} else {
return null;
}
} else {
throw ArgumentError.value(
keyPathDefine,
'keyPathDefine',
'Must contain only strings or ints (found `$key` at index $i).',
);
}
}

if (options != null) {
return (options, source);
}
}
return null;
Expand Down
8 changes: 8 additions & 0 deletions pkgs/hooks_runner/test/test_data/user_defines_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ void main() async {
// The native assets build runner must be reinvoked if the pubspec
// changes, as the pubspec could contain user-defines.
expect(result.dependencies, contains(pubspecUri));
expect(
result.dependencies,
contains(packageUri.resolve('assets/data.json')),
);
expect(
result.dependencies,
contains(packageUri.resolve('assets/second.json')),
);
}),
);
}
1 change: 1 addition & 0 deletions pkgs/hooks_runner/test_data/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
- use_all_api/hook/link.dart
- use_all_api/pubspec.yaml
- user_defines/assets/data.json
- user_defines/assets/second.json
- user_defines/bin/user_defines.dart
- user_defines/hook/build.dart
- user_defines/pubspec.yaml
Expand Down
3 changes: 3 additions & 0 deletions pkgs/hooks_runner/test_data/user_defines/assets/second.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"foo": "bar"
}
19 changes: 19 additions & 0 deletions pkgs/hooks_runner/test_data/user_defines/hook/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,24 @@ void main(List<String> arguments) async {
}
final file = File.fromUri(someFile);
output.dependencies.add(file.uri);

final base = input.userDefines.baseUri([
'nested',
'options',
'paths',
0,
]);
if (base == null) {
throw Exception(
'User-define nested.options.paths.0 does not have the right value: '
'${input.userDefines['nested']}.',
);
}

final pathOption =

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lol, now accessing baseUri is easier than the user-defines themselves 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I can add a helper that traverses through options and returns the original define, but I suspect most hooks with complex options would use helper packages like json_serializable for this anyway.

(((input.userDefines['nested'] as Map)['options'] as Map)['paths']
as List)[0]
as String;
output.dependencies.add(base.resolve(pathOption));
});
}
4 changes: 4 additions & 0 deletions pkgs/hooks_runner/test_data/user_defines/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,9 @@ hooks:
user_define_key2:
foo: bar
some_file: assets/data.json
nested:
options:
paths:
- assets/second.json
some_other_package: # package name
user_define_key3: user_define_value3