// 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 'package:collection/collection.dart'; import 'hooks/syntax.g.dart'; /// An encoded asset. /// /// Use a protocol extension such as `package:code_assets` or /// `package:data_assets` to encode and decode assets. final class EncodedAsset { /// The type of the asset (e.g. whether it's a code asset, data asset or ...) final String type; /// The json encoding of the asset. final UnmodifiableMapView encoding; /// The path of the [encoding] in a larger JSON. /// /// If provided, used for more precise error messages. final List? encodingJsonPath; /// Creates an [EncodedAsset]. EncodedAsset( this.type, Map encoding, { this.encodingJsonPath, }) : encoding = UnmodifiableMapView( // It would be better if `encoding` would be deep copied. // https://github.com/dart-lang/native/issues/2045 Map.of(encoding), ); /// Decode an [EncodedAsset] from json. factory EncodedAsset.fromJson( Map json, [ List? path, ]) => EncodedAssetSyntaxExtension.fromSyntax( AssetSyntax.fromJson(json, path: path ?? []), ); /// Encode this [EncodedAsset] tojson. Map toJson() => toSyntax().json; @override String toString() => 'EncodedAsset($type, $encoding)'; @override int get hashCode => Object.hash(type, const DeepCollectionEquality().hash); @override bool operator ==(Object other) => other is EncodedAsset && type == other.type && const DeepCollectionEquality().equals(encoding, other.encoding); } /// Extension methods for [EncodedAsset] to convert to and from syntax /// nodes. extension EncodedAssetSyntaxExtension on EncodedAsset { /// Creates a [EncodedAsset] from a [AssetSyntax] node. static EncodedAsset fromSyntax(AssetSyntax syntaxNode) => EncodedAsset( syntaxNode.type, syntaxNode.encoding?.json ?? {}, encodingJsonPath: syntaxNode.encoding?.path, ); /// Converts this [EncodedAsset] to a [AssetSyntax] node. AssetSyntax toSyntax() { final path = switch (encodingJsonPath) { // Remove the last element from the encoding path. final List l => l.sublist(0, l.length - 1), null => [], }; return AssetSyntax( encoding: JsonObjectSyntax.fromJson(Map.of(encoding)), type: type, path: path, ); } }