-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Warn instead of crashing for bad URLs #63
Changes from 4 commits
f82a135
627d0be
fdf7c60
ae8a678
56eded3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -13,6 +13,7 @@ import 'package:sass/src/ast/sass.dart'; | |||||
import 'package:sass/src/visitor/recursive_ast.dart'; | ||||||
|
||||||
import 'package:meta/meta.dart'; | ||||||
import 'package:source_span/source_span.dart'; | ||||||
|
||||||
import 'patch.dart'; | ||||||
import 'utils.dart'; | ||||||
|
@@ -34,6 +35,11 @@ abstract class MigrationVisitor extends RecursiveAstVisitor { | |||||
/// True if dependencies should be migrated as well. | ||||||
final bool migrateDependencies; | ||||||
|
||||||
/// Map of missing dependency URLs to the spans that import/use them. | ||||||
UnmodifiableMapView<Uri, FileSpan> get missingDependencies => | ||||||
UnmodifiableMapView(_missingDependencies); | ||||||
final _missingDependencies = <Uri, FileSpan>{}; | ||||||
|
||||||
/// The patches to be applied to the stylesheet being migrated. | ||||||
UnmodifiableListView<Patch> get patches => UnmodifiableListView(_patches); | ||||||
List<Patch> _patches; | ||||||
|
@@ -67,9 +73,14 @@ abstract class MigrationVisitor extends RecursiveAstVisitor { | |||||
|
||||||
/// Visits the stylesheet at [dependency], resolved relative to [source]. | ||||||
@protected | ||||||
void visitDependency(Uri dependency, Uri source) { | ||||||
var stylesheet = parseStylesheet(source.resolveUri(dependency)); | ||||||
visitStylesheet(stylesheet); | ||||||
void visitDependency(Uri dependency, Uri source, [FileSpan context]) { | ||||||
var url = source.resolveUri(dependency); | ||||||
var stylesheet = parseStylesheet(url); | ||||||
if (stylesheet != null) { | ||||||
visitStylesheet(stylesheet); | ||||||
} else { | ||||||
_missingDependencies[url] = context; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This is minor, but I think it's more likely that an earlier import is more relevant to the user. |
||||||
} | ||||||
} | ||||||
|
||||||
/// Returns the migrated contents of this file, or null if the file does not | ||||||
|
@@ -96,7 +107,8 @@ abstract class MigrationVisitor extends RecursiveAstVisitor { | |||||
if (migrateDependencies) { | ||||||
for (var import in node.imports) { | ||||||
if (import is DynamicImport) { | ||||||
visitDependency(Uri.parse(import.url), node.span.sourceUrl); | ||||||
visitDependency( | ||||||
Uri.parse(import.url), node.span.sourceUrl, import.span); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
@@ -108,7 +120,7 @@ abstract class MigrationVisitor extends RecursiveAstVisitor { | |||||
visitUseRule(UseRule node) { | ||||||
super.visitUseRule(node); | ||||||
if (migrateDependencies) { | ||||||
visitDependency(node.url, node.span.sourceUrl); | ||||||
visitDependency(node.url, node.span.sourceUrl, node.span); | ||||||
} | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,8 @@ | |
|
||
import 'package:args/command_runner.dart'; | ||
import 'package:meta/meta.dart'; | ||
import 'package:path/path.dart' as p; | ||
import 'package:source_span/source_span.dart'; | ||
|
||
import 'utils.dart'; | ||
|
||
|
@@ -26,6 +28,9 @@ abstract class Migrator extends Command<Map<Uri, String>> { | |
/// If true, dependencies will be migrated in addition to the entrypoints. | ||
bool get migrateDependencies => globalResults['migrate-deps'] as bool; | ||
|
||
/// Map of missing dependency URLs to the spans that import/use them. | ||
final missingDependencies = <Uri, FileSpan>{}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document how subclasses are intended to interact with this. |
||
|
||
/// Runs this migrator on [entrypoint] (and its dependencies, if the | ||
/// --migrate-deps flag is passed). | ||
/// | ||
|
@@ -45,7 +50,13 @@ abstract class Migrator extends Command<Map<Uri, String>> { | |
Map<Uri, String> run() { | ||
var allMigrated = Map<Uri, String>(); | ||
for (var entrypoint in argResults.rest) { | ||
var migrated = migrateFile(canonicalize(Uri.parse(entrypoint))); | ||
var canonicalUrl = canonicalize(Uri.parse(entrypoint)); | ||
if (canonicalUrl == null) { | ||
throw MigrationException( | ||
"Error: Could not find Sass file at '$entrypoint'."); | ||
nex3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
jathak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
var migrated = migrateFile(canonicalUrl); | ||
for (var file in migrated.keys) { | ||
if (allMigrated.containsKey(file) && | ||
migrated[file] != allMigrated[file]) { | ||
|
@@ -55,6 +66,33 @@ abstract class Migrator extends Command<Map<Uri, String>> { | |
allMigrated[file] = migrated[file]; | ||
} | ||
} | ||
|
||
if (missingDependencies.isNotEmpty) _warnForMissingDependencies(); | ||
return allMigrated; | ||
} | ||
|
||
/// Prints warnings for any missing dependencies encountered during migration. | ||
/// | ||
/// By default, this prints a short warning with one line per missing | ||
/// dependency. | ||
/// | ||
/// In verbose mode, this instead prints a full warning with the source span | ||
/// for each missing dependency. | ||
void _warnForMissingDependencies() { | ||
if (globalResults['verbose'] as bool) { | ||
for (var uri in missingDependencies.keys) { | ||
emitWarning("Could not find Sass file at '${p.prettyUri(uri)}'.", | ||
missingDependencies[uri]); | ||
} | ||
} else { | ||
var count = missingDependencies.length; | ||
emitWarning( | ||
"$count dependenc${count == 1 ? 'y' : 'ies'} could not be found."); | ||
jathak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (var uri in missingDependencies.keys) { | ||
var context = missingDependencies[uri]; | ||
print(' ${p.prettyUri(uri)} ' | ||
'@${p.prettyUri(context.sourceUrl)}:${context.start.line + 1}'); | ||
} | ||
} | ||
jathak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,9 +36,13 @@ More info: https://sass-lang.com/d/slash-div"""; | |
bool get isPessimistic => argResults['pessimistic'] as bool; | ||
|
||
@override | ||
Map<Uri, String> migrateFile(Uri entrypoint) => | ||
_DivisionMigrationVisitor(this.isPessimistic, migrateDependencies) | ||
.run(entrypoint); | ||
Map<Uri, String> migrateFile(Uri entrypoint) { | ||
var visitor = | ||
_DivisionMigrationVisitor(this.isPessimistic, migrateDependencies); | ||
var result = visitor.run(entrypoint); | ||
missingDependencies.addAll(visitor.missingDependencies); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bleh, it sucks that each subclass has to do this manually rather than just having "warn for missing dependencies" be the automatic default behavior. It's not something that needs to happen in this PR, but it's worth thinking about how you could make this more automatic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's why I originally passed in the list for the visitor to add to, but this is probably cleaner than that, particularly right now when there's only one migrator that actually uses |
||
return result; | ||
} | ||
} | ||
|
||
class _DivisionMigrationVisitor extends MigrationVisitor { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<==> arguments | ||
--migrate-deps | ||
|
||
<==> input/entrypoint.scss | ||
@import "does_not_exist"; | ||
@import "does_not_exist2"; | ||
|
||
<==> log.txt | ||
WARNING - 2 dependencies could not be found. | ||
does_not_exist @entrypoint.scss:1 | ||
does_not_exist2 @entrypoint.scss:2 | ||
Nothing to migrate! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<==> arguments | ||
--migrate-deps --verbose | ||
|
||
<==> input/entrypoint.scss | ||
@import "does_not_exist"; | ||
@import "does_not_exist2"; | ||
|
||
<==> log.txt | ||
line 1, column 9 of entrypoint.scss: WARNING - Could not find Sass file at 'does_not_exist'. | ||
, | ||
1 | @import "does_not_exist"; | ||
| ^^^^^^^^^^^^^^^^ | ||
' | ||
line 2, column 9 of entrypoint.scss: WARNING - Could not find Sass file at 'does_not_exist2'. | ||
, | ||
2 | @import "does_not_exist2"; | ||
| ^^^^^^^^^^^^^^^^^ | ||
' | ||
Nothing to migrate! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<==> input/entrypoint.scss | ||
@import "does_not_exist"; | ||
@import "does_not_exist2"; | ||
|
||
<==> log.txt | ||
line 1, column 9 of entrypoint.scss: Error: Could not find Sass file at 'does_not_exist'. | ||
, | ||
1 | @import "does_not_exist"; | ||
| ^^^^^^^^^^^^^^^^ | ||
' | ||
Migration failed! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.