discoverAssets function

Future<AssetDiscoveryResult> discoverAssets(
  1. AssetXConfig config, {
  2. String? baseDir,
})

Discovers all assets based on AssetXConfig rules

Recursively scans directories according to the configuration and returns all files and folders that match the inclusion/exclusion rules.

Parameters:

  • config: The AssetX configuration containing source paths and patterns
  • baseDir: Optional base directory for resolving relative paths (defaults to current directory)

Returns: AssetDiscoveryResult containing lists of discovered files and folders

Process:

  1. Processes all sources_include paths
  2. Applies recursive scanning if enabled
  3. Filters by patterns_include (if specified)
  4. Removes files matching patterns_exclude
  5. Removes files from sources_exclude paths
  6. Respects ignore patterns within each source

Example:

final config = AssetXConfig.fromJson(configMap);
final result = await discoverAssets(config);

for (final file in result.files) {
  print('Found file: ${file.path}');
}

Implementation

Future<AssetDiscoveryResult> discoverAssets(
  AssetXConfig config, {
  String? baseDir,
}) async {
  final workingDir = baseDir ?? Directory.current.path;
  final allFiles = <AssetLookupFile>[];
  final allFolders = <AssetLookupFolder>[];
  int filesSkipped = 0; // Track actually skipped files

  // Process included sources (initially assume fully indexed)
  if (config.sourcesInclude != null) {
    for (final source in config.sourcesInclude!) {
      final sourcePath = p.isAbsolute(source.path)
          ? source.path
          : p.join(workingDir, source.path);

      final sourceDir = Directory(sourcePath);
      if (!await sourceDir.exists()) {
        continue; // Skip non-existent paths
      }

      final result = await _scanDirectory(
        sourcePath,
        source.recursive ?? false,
        source.ignore ?? [],
        null, // parent folder
        true, // Initially assume fully indexed
      );

      allFiles.addAll(result.files);
      allFolders.addAll(result.folders);
      filesSkipped += result.wasFiltered
          ? 1
          : 0; // Track if scanning had filtering
    }
  }

  final originalFileCount = allFiles.length;
  var filteredFiles = allFiles;

  // Filter by include patterns
  if (config.patternsInclude != null && config.patternsInclude!.isNotEmpty) {
    filteredFiles = allFiles.where((file) {
      return config.patternsInclude!.any(
        (pattern) => _matchesPattern(file.normalizedPath, pattern),
      );
    }).toList();
    filesSkipped += originalFileCount - filteredFiles.length;
  }

  // Remove files matching exclude patterns
  if (config.patternsExclude != null) {
    final beforeExclude = filteredFiles.length;
    filteredFiles = filteredFiles.where((file) {
      return !config.patternsExclude!.any(
        (pattern) => _matchesPattern(file.normalizedPath, pattern),
      );
    }).toList();
    filesSkipped += beforeExclude - filteredFiles.length;
  }

  // Remove files from excluded sources
  if (config.sourcesExclude != null) {
    final beforeSourceExclude = filteredFiles.length;
    for (final excludeSource in config.sourcesExclude!) {
      final excludePath = p.isAbsolute(excludeSource.path)
          ? excludeSource.path
          : p.join(workingDir, excludeSource.path);

      filteredFiles = filteredFiles.where((file) {
        if (excludeSource.recursive ?? false) {
          return !file.path.startsWith(excludePath);
        } else {
          return p.dirname(file.path) != excludePath;
        }
      }).toList();
    }
    filesSkipped += beforeSourceExclude - filteredFiles.length;
  }

  final wasFiltered = filesSkipped > 0;

  // Update folder children to only contain filtered files
  _updateFolderChildren(allFolders, filteredFiles);

  // Update fullyIndexed status based on whether each folder lost any files
  _updateFolderIndexingStatus(allFolders);

  return AssetDiscoveryResult(filteredFiles, allFolders, wasFiltered);
}