blob: a0008a6da99e17160945591a8bc39b1b0f01936c [file] [view]
> [!CAUTION]
> This is an experimental package. Its API and the underlying JSON format
> **will break** as we are actively iterating. Use at your own discretion.
>
> We are continuously changing the implementation, so a released version of the
> package may only work with one or two [dev releases] of the Dart SDK. This
> version will work with the first dev release _after_ `3.12.0-203.0.dev`.
This package provides the data classes for the usage recording feature in the
Dart SDK.
Dart objects with the `@RecordUse()` annotation are being recorded at compile
time, providing the user with information. The information depends on the object
being recorded.
- If placed on a static method, the annotation means that arguments passed to
the method will be recorded, as far as they can be inferred at compile time.
- If placed on a class, the annotation means that any constant instance of the
class and any constructor invocation will be recorded.
> [!NOTE]
> The `@RecordUse()` annotation is only allowed on definitions within a package's
> `lib/` directory. This includes definitions that are members of a class, such
> as static methods.
## Example
<!-- file://./example/api/usage.dart#usage -->
```dart
void main() {
PirateTranslator.speak('Hello');
print(const PirateShip('Black Pearl', 50));
}
abstract class PirateTranslator {
@RecordUse()
static String speak(String english) => 'Ahoy $english';
}
@RecordUse()
final class PirateShip {
final String name;
final int cannons;
const PirateShip(this.name, this.cannons);
}
```
This code will generate a data file that contains both the field values of
the `PirateShip` instances, as well as the arguments for the `speak`
method annotated with `@RecordUse()`.
This information can then be accessed in a link hook as follows:
<!-- file://./example/api/usage_link.dart#link -->
```dart
void main(List<String> arguments) {
link(arguments, (input, output) async {
final usesUri = input.recordedUsagesFile;
if (usesUri == null) return;
final usesJson = await File.fromUri(usesUri).readAsString();
final uses = Recordings.fromJson(
jsonDecode(usesJson) as Map<String, Object?>,
);
final calls = uses.calls[methodId] ?? [];
for (final call in calls) {
switch (call) {
case CallWithArguments(
positionalArguments: [StringConstant(value: final english), ...],
):
// Shrink a translations file based on all the different translation
// keys.
print('Translating to pirate: $english');
case _:
print('Cannot determine which translations are used.');
}
}
final ships = uses.instances[classId] ?? [];
for (final ship in ships) {
switch (ship) {
case InstanceConstantReference(
instanceConstant: InstanceConstant(
fields: {'name': StringConstant(value: final name)},
),
):
// Include the 3d model for this ship in the application but not
// bundle the other ships.
print('Pirate ship found: $name');
case _:
print('Cannot determine which ships are used.');
}
}
});
}
```
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.
[dev releases]: https://dart.dev/get-dart/archive#dev-channel