mapToUniqueAssetType method

Iterable<UniqueAssetType> mapToUniqueAssetType(
  1. String style(
    1. String
    ), {
  2. bool justBasename = false,
})

Takes a Iterable

The strategy is as follows:

  1. Convert the asset file name, to a valid dart identifier, that is
  • Replace non ASCII chars with ASCII.
  • Ensure the name starts with a letter (not number or _).
  • Style the name per the camelCase or snakeCase rules.
  1. Use the asset name without extension. If unique and not a dart reserved word use that.
  2. Use the asset name with extension. If unique and not a dart reserved word use that.
  3. If there are any collisions, append a underscore suffix to each item until they are unique.

Because the name change can cause it to clash with an existing name, the code is run iteratively until no collision are found. This can be a little more expensive, but it simplier.

Implementation

Iterable<UniqueAssetType> mapToUniqueAssetType(
  String Function(String) style, {
  bool justBasename = false,
}) {
  List<UniqueAssetType> assets = map((e) => UniqueAssetType(
        assetType: e,
        style: style,
        needExtension: false,
        suffix: '',
        basenameOnly: justBasename,
      )).toList();

  while (true) {
    // Check if we have any name collisions.
    final dups = assets.groupBy((e) => e.name).values;

    // No more duplicates, so we can bail.
    if (dups.every((list) => list.length == 1)) break;

    // Otherwise start to process the list and mutate the assets as needed.
    assets = dups
        .map((list) {
          assert(list.isNotEmpty,
              'The groupBy list of assets should not be empty.');

          // Check the first element in the list. Since we grouped by each
          // list element should have the same name.
          final name = list[0].name;
          final isValidIdentifer = isValidVariableIdentifier(name);

          // TODO(bramp): In future we should also check this name doesn't collide
          // with the integration's class name (e.g AssetGenImage).

          // No colissions for this name, carry on.
          if (list.length == 1 && isValidIdentifer) {
            return list;
          }

          // We haven't added filename extensions yet, let's try that first
          if (!list.every((e) => e.needExtension)) {
            for (final e in list) {
              e.needExtension = true;
            }

            return list;
          }

          // Ok, we must resolve the conflicts by adding suffixes.
          String suffix = '';
          list.forEachIndexed((asset, index) {
            // Shouldn't need to mutate the first item (unless it's an invalid
            // identifer).
            if (index == 0 && isValidIdentifer) return;

            // Append a extra suffixes to each item so they hopefully become unique
            suffix = '${suffix}_';
            asset.suffix += suffix;
          });

          return list;
        })
        .flatten()
        .toList();
  }

  assert(assets.map((e) => e.name).distinct().length == assets.length,
      'There are duplicate names in the asset list.');

  return assets;
}