-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5b70e02
commit 781a3e4
Showing
4 changed files
with
108 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:io'; | ||
|
||
import 'package:dart_model/dart_model.dart'; | ||
import 'package:package_config/package_config.dart' as package_config; | ||
|
||
/// Reads a package config to determine information about macros. | ||
class PackageConfig { | ||
final Uri uri; | ||
|
||
PackageConfig({required this.uri}); | ||
|
||
/// Checks whether [name] is a macro annotation. | ||
/// | ||
/// If so, returns the qualified name of the macro implementation. | ||
/// | ||
/// If not, returns `null`. | ||
/// | ||
/// This is a placeholder implementation until `language/3728` is | ||
/// implemented. It expects macros to be marked by a comment in the | ||
/// annotation package `pubspec.yaml` that looks like this: | ||
/// | ||
/// ``` | ||
/// # macro <annotation name> <implementation name> | ||
/// ``` | ||
/// | ||
/// For example: | ||
/// | ||
/// ``` | ||
/// # macro declare_x_macro.dart#DeclareX package:_test_macros/declare_x_macro.dart#DeclareXImplementation | ||
/// ``` | ||
QualifiedName? lookupMacroImplementation(QualifiedName name) { | ||
var packageName = name.uri; | ||
if (packageName.startsWith('package:') && packageName.contains('/')) { | ||
packageName = packageName.substring('package:'.length); | ||
packageName = packageName.substring(0, packageName.indexOf('/')); | ||
} else { | ||
throw ArgumentError('Name must start "package:" and have a path: $name'); | ||
} | ||
final packageConfig = package_config.PackageConfig.parseBytes( | ||
File.fromUri(uri).readAsBytesSync(), uri); | ||
final libraryQualifiedName = | ||
name.string.substring(name.uri.indexOf('/') + 1); | ||
|
||
final matchingPackage = packageConfig.packages | ||
.where((p) => p.name == packageName) | ||
.toList() | ||
.singleOrNull; | ||
|
||
if (matchingPackage == null) { | ||
throw StateError( | ||
'Package "$packageName" not found in package config at "$uri".'); | ||
} | ||
|
||
// TODO(language/3728): read macro annotation identifiers from package | ||
// config. Until then, check the pubsec, to simulate what that feature will | ||
// do. | ||
final packageUri = matchingPackage.root; | ||
final pubspecUri = packageUri.replace( | ||
pathSegments: | ||
packageUri.pathSegments.followedBy(['pubspec.yaml']).toList()); | ||
final lines = File.fromUri(pubspecUri).readAsLinesSync(); | ||
|
||
final implsByLibraryQualifiedName = <String, String>{}; | ||
for (final line in lines) { | ||
if (!line.startsWith('# macro ')) continue; | ||
final items = line.split(' '); | ||
// The rest of the line should be the library qualified name of the | ||
// annotation then the fully qualified name of the implementation. | ||
implsByLibraryQualifiedName[items[2]] = items[3]; | ||
} | ||
|
||
final result = implsByLibraryQualifiedName[libraryQualifiedName]; | ||
return result == null ? null : QualifiedName(result); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:isolate'; | ||
|
||
import 'package:_macro_host/src/package_config.dart'; | ||
import 'package:dart_model/dart_model.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
group(PackageConfig, () { | ||
test('can look up macro implementations', () async { | ||
final packageConfig = PackageConfig(uri: Isolate.packageConfigSync!); | ||
|
||
expect( | ||
packageConfig | ||
.lookupMacroImplementation(QualifiedName( | ||
'package:_test_macros/declare_x_macro.dart#DeclareX'))! | ||
.string, | ||
'package:_test_macros/declare_x_macro.dart#DeclareXImplementation'); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters