-
Notifications
You must be signed in to change notification settings - Fork 10
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
Initial implementation of a division migrator #17
Conversation
There's now a `Migrator` class that additional migrators can extend. Most migrators will want to extend `MigratorBase`, which handles the tree traversal. For now, `MigratorBase` only operates on a single stylesheet, with the dependency migration implemented only by `ModuleMigrator`.
--migrate-deps is now a global flag, so additional migrators should not need to re-implement dependency migration unless they need additional special logic like the module migrator needs. The generic migration classes are now split into Migrator and MigrationVisitor. Each Migrator is a Command and should contain state for the entire migration run. Most migrators will also want to create a private subclass of MigrationVisitor that they call from Migrator.migrateFile. A new instance of the MigrationVisitor will be created for each stylesheet being migrated, so it contains per-stylesheet state, similar to what StylesheetMigration used to be for the module migrator.
The migrator now uses URLs instead of paths, and loads files using the FilesystemImporter. `Migrator.migrated` has been removed in favor of having `Migrator.migrateFile` and `MigrationVisitor.run` return it.
A single MigrationVisitor is now reused instead of constructing a new instance for each dependency. This also removes support for configurable variables, since the previous implementation of this was both hard to implement with a single MigrationVisitor and incorrect when the configurable variables were declared in an indirect dependency. A subsequent PR will add this back with a new implementation that fixes the bug with indirect dependencies.
This adds a new migrator that migrates the `/` operator to the division function. By default, this migrator migrates only cases where the `/` is known to be division. In cases the `/` could be division, but whether it is division is not statically known, a warning is emitted instead. The `--aggressive` flag can be used to migrate cases like `3 / $x + 1`, `3 / $x - 1`, and `fn() / 3` by assuming that `+` and `-` always operate on numbers and that function calls in an expression with `/` always return numbers.
7483385
to
6156b06
Compare
Replaced --aggressive with --pessimistic, with the previous behavior for aggressive now the default. Also made other minor changes in response to review.
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.
This is looking really good 👍. It should be ready to go once slash-list()
support is in.
lib/src/migrators/division.dart
Outdated
"will be migrated."); | ||
..addFlag('pessimistic', | ||
abbr: 'p', | ||
help: r"Only migrate / expressions that are unambiguously division."); |
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.
help: r"Only migrate / expressions that are unambiguously division."); | |
help: "Only migrate / expressions that are unambiguously division."); |
lib/src/migrators/division.dart
Outdated
var expression = node.expression; | ||
if (expression is BinaryOperationExpression && | ||
expression.operator == BinaryOperator.dividedBy) { | ||
withContext(true, _expectsNumericResult, () { |
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.
Ideally, these methods that return booleans wouldn't also produce side effects... is there a way you can make that work? If it's too complicated, though, that's fine.
Refactored the patching logic from |
lib/src/migrators/division.dart
Outdated
_patchParensIfAny(expression.right); | ||
} | ||
super.visitBinaryOperationExpression(expression); | ||
_visitSlashOperation(expression, surroundingParens: node); |
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.
Rather than passing in surroundingParens
, which requires _visitSlashOperation()
to understand a lot about what context it might be called in, consider having this code delete the parentheses itself and just call _visitSlashOperation(expression)
.
lib/src/migrators/division.dart
Outdated
var start = node.text.span.start.offset; | ||
var end = node.text.span.end.offset; | ||
// Remove `#{` and `}` | ||
addPatch(Patch(node.span.file.span(start, start + 2), "")); |
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.
Consider a patchDelete()
utility function.
: super(migrateDependencies: migrateDependencies); | ||
|
||
/// True when division is allowed by the context the current node is in. | ||
var _isDivisionAllowed = false; |
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.
I just realized, this should also be set to true in argument lists for functions and mixins, except for the specific case of new-syntax rgb()
et al functions. Feel free to fix after landing this PR, though.
Nothing to migrate! | ||
<==> output/entrypoint.scss | ||
:foo(#{slash-list(6, 3)}) { | ||
b: slash-list(6px, 3px); |
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.
Actually, looking at these examples, they're really hard on the eyes. After this lands, can we make the migrator smart enough to only migrate to slash-list()
in a non-plain-CSS context? Basically, we should generate slash-list()
only if either _isDivisionAllowed
is true
or one of the arguments (possibly deeply-nested) is an interpolation expression.
Resolves #20.
This adds a new migrator that migrates the
/
operator to the division function.By default, this migrator migrates only cases where the
/
is known to be division. In cases the/
could be division, but whether it is division is not statically known, a warning is emitted instead.The
--aggressive
flag can be used to migrate cases like3 / $x + 1
,3 / $x - 1
, andfn() / 3
by assuming that+
and-
always operate on numbers and that function calls in an expression with/
always return numbers.Note: I'm setting the base for this to the
generalization
branch for better diffs, but this should be merged after #16.