Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 3.3.1

- **Surgical Font Assets & Pubspec Pruning:**
- `AssetAuditor` now explicitly recognizes font assets declared under `flutter -> fonts` in `pubspec.yaml`.
- Improved `_isFontUsed` to accurately match font families as quoted string literals in Dart code (e.g. `fontFamily: 'Cairo'`), preventing false positives when filenames share substrings with family names.
- `AssetCleaner` now surgically prunes unused font declarations (`- asset: ...`) along with their child properties (`weight`, `style`, comments) from `pubspec.yaml`.
- Automatically prunes empty `- family:` blocks when all their font assets are removed.
- Automatically prunes the `fonts:` section when all families are removed, preventing invalid YAML mapping issues.
- Automatically prunes empty directory patterns under `assets:` (e.g. `- assets/fonts/`) when all assets inside the directory are purged.

## 3.3.0

- **AI Agent Optimization (LLMO / GEO Standard Compliance):**
Expand Down
21 changes: 15 additions & 6 deletions lib/src/assets/asset_auditor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ class AssetAuditor {
bool _isFontUsed(File file, PackageDescriptor ownerPkg, String codeCorpus) {
final fileName = file.uri.pathSegments.safeLast ?? '';

// Check if filename is directly referenced
// Check if filename is directly referenced (e.g. 'assets/fonts/Cairo.ttf' or 'Cairo.ttf')
if (codeCorpus.contains(fileName)) return true;

// Check if any declared font family containing this asset is referenced in code
Expand All @@ -337,8 +337,9 @@ class AssetAuditor {
final assets = entry.value;

if (assets.any((a) => a.replaceAll(r'\', '/') == normPath)) {
// If the font family name is referenced in Dart code (e.g. fontFamily: 'MyFont')
if (codeCorpus.contains(family)) {
// If the font family name is referenced as a string literal in Dart code (e.g. fontFamily: 'MyFont' or "MyFont")
final familyPattern = RegExp('[\'"]${RegExp.escape(family)}[\'"]');
if (familyPattern.hasMatch(codeCorpus)) {
return true;
}
}
Expand All @@ -360,11 +361,19 @@ class AssetAuditor {
return '$first$rest';
}

/// Checks if a file path was explicitly declared by full path in pubspec.yaml.
/// Checks if a file path was explicitly declared by full path in pubspec.yaml (assets or fonts).
bool _isExplicitlyDeclared(String relPackage, PackageDescriptor pkg) {
final norm = relPackage.replaceAll(r'\', '/');
return pkg.declaredAssetPatterns
.any((pat) => pat.replaceAll(r'\', '/') == norm);
if (pkg.declaredAssetPatterns
.any((pat) => pat.replaceAll(r'\', '/') == norm)) {
return true;
}
for (final fontList in pkg.declaredFonts.values) {
if (fontList.any((f) => f.replaceAll(r'\', '/') == norm)) {
return true;
}
}
return false;
}
}

Expand Down
Loading
Loading