@@ -519,7 +519,8 @@ void _validateFlutter(YamlMap? yaml, List<String> errors) {
519
519
_validateFonts (yamlValue, errors);
520
520
}
521
521
case 'licenses' :
522
- errors.addAll (_validateList <String >(yamlValue, '"$yamlKey "' , 'files' ));
522
+ final (_, List <String > filesErrors) = _parseList <String >(yamlValue, '"$yamlKey "' , 'files' );
523
+ errors.addAll (filesErrors);
523
524
case 'module' :
524
525
if (yamlValue is ! YamlMap ) {
525
526
errors.add ('Expected "$yamlKey " to be an object, but got $yamlValue (${yamlValue .runtimeType }).' );
@@ -553,11 +554,12 @@ void _validateFlutter(YamlMap? yaml, List<String> errors) {
553
554
}
554
555
}
555
556
556
- List <String > _validateList <T >(Object ? yamlList, String context, String typeAlias) {
557
+ ( List <T > ? result, List < String > errors) _parseList <T >(Object ? yamlList, String context, String typeAlias) {
557
558
final List <String > errors = < String > [];
558
559
559
560
if (yamlList is ! YamlList ) {
560
- return < String > ['Expected $context to be a list of $typeAlias , but got $yamlList (${yamlList .runtimeType }).' ];
561
+ final String message = 'Expected $context to be a list of $typeAlias , but got $yamlList (${yamlList .runtimeType }).' ;
562
+ return (null , < String > [message]);
561
563
}
562
564
563
565
for (int i = 0 ; i < yamlList.length; i++ ) {
@@ -567,8 +569,9 @@ List<String> _validateList<T>(Object? yamlList, String context, String typeAlias
567
569
}
568
570
}
569
571
570
- return errors;
572
+ return errors.isEmpty ? ( List < T >. from (yamlList), errors) : ( null , errors) ;
571
573
}
574
+
572
575
void _validateDeferredComponents (MapEntry <Object ?, Object ?> kvp, List <String > errors) {
573
576
final Object ? yamlList = kvp.value;
574
577
if (yamlList != null && (yamlList is ! YamlList || yamlList[0 ] is ! YamlMap )) {
@@ -585,11 +588,12 @@ void _validateDeferredComponents(MapEntry<Object?, Object?> kvp, List<String> er
585
588
errors.add ('Expected the $i element in "${kvp .key }" to have required key "name" of type String' );
586
589
}
587
590
if (valueMap.containsKey ('libraries' )) {
588
- errors. addAll ( _validateList <String >(
591
+ final (_, List < String > librariesErrors) = _parseList <String >(
589
592
valueMap['libraries' ],
590
593
'"libraries" key in the element at index $i of "${kvp .key }"' ,
591
594
'String' ,
592
- ));
595
+ );
596
+ errors.addAll (librariesErrors);
593
597
}
594
598
if (valueMap.containsKey ('assets' )) {
595
599
errors.addAll (_validateAssets (valueMap['assets' ]));
@@ -697,13 +701,16 @@ class AssetsEntry {
697
701
const AssetsEntry ({
698
702
required this .uri,
699
703
this .flavors = const < String > {},
704
+ this .transformers = const < AssetTransformerEntry > [],
700
705
});
701
706
702
707
final Uri uri;
703
708
final Set <String > flavors;
709
+ final List <AssetTransformerEntry > transformers;
704
710
705
711
static const String _pathKey = 'path' ;
706
712
static const String _flavorKey = 'flavors' ;
713
+ static const String _transformersKey = 'transformers' ;
707
714
708
715
static AssetsEntry ? parseFromYaml (Object ? yaml) {
709
716
final (AssetsEntry ? value, String ? error) = parseFromYamlSafe (yaml);
@@ -738,49 +745,83 @@ class AssetsEntry {
738
745
}
739
746
740
747
final Object ? path = yaml[_pathKey];
741
- final Object ? flavors = yaml[_flavorKey];
742
748
743
749
if (path == null || path is ! String ) {
744
750
return (null , 'Asset manifest entry is malformed. '
745
751
'Expected asset entry to be either a string or a map '
746
752
'containing a "$_pathKey " entry. Got ${path .runtimeType } instead.' );
747
753
}
748
754
749
- final Uri uri = Uri (pathSegments: path.split ('/' ));
750
-
751
- if (flavors == null ) {
752
- return (AssetsEntry (uri: uri), null );
753
- }
754
-
755
- if (flavors is ! YamlList ) {
756
- return (null , 'Asset manifest entry is malformed. '
757
- 'Expected "$_flavorKey " entry to be a list of strings. '
758
- 'Got ${flavors .runtimeType } instead.' );
759
- }
760
-
761
- final List <String > flavorsListErrors = _validateList <String >(
762
- flavors,
763
- 'flavors list of entry "$path "' ,
764
- 'String' ,
765
- );
766
- if (flavorsListErrors.isNotEmpty) {
767
- return (null , 'Asset manifest entry is malformed. '
768
- 'Expected "$_flavorKey " entry to be a list of strings.\n '
769
- '${flavorsListErrors .join ('\n ' )}' );
755
+ final (List <String >? flavors, List <String > flavorsErrors) = _parseFlavorsSection (yaml[_flavorKey]);
756
+ final (List <AssetTransformerEntry >? transformers, List <String > transformersErrors) = _parseTransformersSection (yaml[_transformersKey]);
757
+
758
+ final List <String > errors = < String > [
759
+ ...flavorsErrors.map ((String e) => 'In $_flavorKey section of asset "$path ": $e ' ),
760
+ ...transformersErrors.map ((String e) => 'In $_transformersKey section of asset "$path ": $e ' ),
761
+ ];
762
+ if (errors.isNotEmpty) {
763
+ return (
764
+ null ,
765
+ < String > [
766
+ 'Unable to parse assets section.' ,
767
+ ...errors
768
+ ].join ('\n ' ),
769
+ );
770
770
}
771
771
772
- final AssetsEntry entry = AssetsEntry (
773
- uri: Uri (pathSegments: path.split ('/' )),
774
- flavors: Set <String >.from (flavors),
772
+ return (
773
+ AssetsEntry (
774
+ uri: Uri (pathSegments: path.split ('/' )),
775
+ flavors: Set <String >.from (flavors ?? < String > []),
776
+ transformers: transformers ?? < AssetTransformerEntry > [],
777
+ ),
778
+ null ,
775
779
);
776
-
777
- return (entry, null );
778
780
}
779
781
780
782
return (null , 'Assets entry had unexpected shape. '
781
783
'Expected a string or an object. Got ${yaml .runtimeType } instead.' );
782
784
}
783
785
786
+ static (List <String >? flavors, List <String > errors) _parseFlavorsSection (Object ? yaml) {
787
+ if (yaml == null ) {
788
+ return (null , < String > []);
789
+ }
790
+
791
+ return _parseList <String >(yaml, _flavorKey, 'String' );
792
+ }
793
+
794
+ static (List <AssetTransformerEntry >? , List <String > errors) _parseTransformersSection (Object ? yaml) {
795
+ if (yaml == null ) {
796
+ return (null , < String > []);
797
+ }
798
+ final (List <YamlMap >? yamlObjects, List <String > listErrors) = _parseList <YamlMap >(
799
+ yaml,
800
+ '$_transformersKey list' ,
801
+ 'Map' ,
802
+ );
803
+
804
+ if (listErrors.isNotEmpty) {
805
+ return (null , listErrors);
806
+ }
807
+
808
+ final List <AssetTransformerEntry > transformers = < AssetTransformerEntry > [];
809
+ final List <String > errors = < String > [];
810
+ for (final YamlMap yaml in yamlObjects! ) {
811
+ final (AssetTransformerEntry ? transformerEntry, List <String > transformerErrors) = AssetTransformerEntry .tryParse (yaml);
812
+ if (transformerEntry != null ) {
813
+ transformers.add (transformerEntry);
814
+ } else {
815
+ errors.addAll (transformerErrors);
816
+ }
817
+ }
818
+
819
+ if (errors.isEmpty) {
820
+ return (transformers, errors);
821
+ }
822
+ return (null , errors);
823
+ }
824
+
784
825
@override
785
826
bool operator == (Object other) {
786
827
if (other is ! AssetsEntry ) {
@@ -799,3 +840,91 @@ class AssetsEntry {
799
840
@override
800
841
String toString () => 'AssetsEntry(uri: $uri , flavors: $flavors )' ;
801
842
}
843
+
844
+
845
+ /// Represents an entry in the "transformers" section of an asset.
846
+ @immutable
847
+ final class AssetTransformerEntry {
848
+ const AssetTransformerEntry ({
849
+ required this .package,
850
+ required List <String >? args,
851
+ }): args = args ?? const < String > [];
852
+
853
+ final String package;
854
+ final List <String >? args;
855
+
856
+ static (AssetTransformerEntry ? entry, List <String > errors) tryParse (Object ? yaml) {
857
+ if (yaml == null ) {
858
+ return (null , < String > ['Transformer entry is null.' ]);
859
+ }
860
+ if (yaml is ! YamlMap ) {
861
+ return (null , < String > ['Expected entry to be a map. Found ${yaml .runtimeType } instead' ]);
862
+ }
863
+
864
+ final Object ? package = yaml['package' ];
865
+ if (package is ! String || package.isEmpty) {
866
+ return (null , < String > ['Expected "package" to be a String. Found ${package .runtimeType } instead.' ]);
867
+ }
868
+
869
+ final (List <String >? args, List <String > argsErrors) = _parseArgsSection (yaml['args' ]);
870
+ if (argsErrors.isNotEmpty) {
871
+ return (null , argsErrors.map ((String e) => 'In args section of transformer using package "$package ": $e ' ).toList ());
872
+ }
873
+
874
+ return (
875
+ AssetTransformerEntry (
876
+ package: package,
877
+ args: args,
878
+ ),
879
+ < String > [],
880
+ );
881
+ }
882
+
883
+ static (List <String >? args, List <String > errors) _parseArgsSection (Object ? yaml) {
884
+ if (yaml == null ) {
885
+ return (null , < String > []);
886
+ }
887
+ return _parseList (yaml, 'args' , 'String' );
888
+ }
889
+
890
+ @override
891
+ bool operator == (Object other) {
892
+ if (identical (this , other)) {
893
+ return true ;
894
+ }
895
+ if (other is ! AssetTransformerEntry ) {
896
+ return false ;
897
+ }
898
+
899
+ final bool argsAreEqual = (() {
900
+ if (args == null && other.args == null ) {
901
+ return true ;
902
+ }
903
+ if (args? .length != other.args? .length) {
904
+ return false ;
905
+ }
906
+
907
+ for (int index = 0 ; index < args! .length; index += 1 ) {
908
+ if (args! [index] != other.args! [index]) {
909
+ return false ;
910
+ }
911
+ }
912
+ return true ;
913
+ })();
914
+
915
+ return package == other.package && argsAreEqual;
916
+ }
917
+
918
+ @override
919
+ int get hashCode => Object .hashAll (
920
+ < Object ? > [
921
+ package.hashCode,
922
+ args? .map ((String e) => e.hashCode),
923
+ ],
924
+ );
925
+
926
+ @override
927
+ String toString () {
928
+ return 'AssetTransformerEntry(package: $package , args: $args )' ;
929
+ }
930
+ }
0 commit comments