Skip to content

Commit 292c587

Browse files
authored
Add media query migrator (#228)
This PR adds a new `handleDeprecation` method to `Migrator`, which the new migrator uses instead of attempting to duplicate the logic from the parser.
1 parent 874c62f commit 292c587

15 files changed

+131
-112
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 1.7.0
2+
3+
### Media Logic Migrator
4+
5+
* Adds a new migrator for migrating [deprecated `@media` query logic].
6+
7+
[deprecated `@media` query logic]: https://sass-lang.com/d/media-logic
8+
19
## 1.6.0
210

311
### Strict Unary Migrator

lib/src/migrator.dart

+26-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:meta/meta.dart';
1010
import 'package:path/path.dart' as p;
1111
import 'package:sass_api/sass_api.dart';
1212
import 'package:source_span/source_span.dart';
13+
import 'package:stack_trace/stack_trace.dart';
1314

1415
import 'exception.dart';
1516
import 'io.dart';
@@ -57,6 +58,10 @@ abstract class Migrator extends Command<Map<Uri, String>> {
5758
Map<Uri, String> migrateFile(
5859
ImportCache importCache, Stylesheet stylesheet, Importer importer);
5960

61+
/// This is called whenever a deprecation warning is emitted during parsing.
62+
@protected
63+
void handleDeprecation(String message, FileSpan? span) {}
64+
6065
/// Runs this migrator.
6166
///
6267
/// Each entrypoint is migrated separately. If a stylesheet is migrated more
@@ -70,7 +75,8 @@ abstract class Migrator extends Command<Map<Uri, String>> {
7075
var importer = FilesystemImporter('.');
7176
var importCache = ImportCache(
7277
importers: [NodeModulesImporter()],
73-
loadPaths: globalResults!['load-path']);
78+
loadPaths: globalResults!['load-path'],
79+
logger: _DeprecationLogger(this));
7480

7581
var entrypoints = [
7682
for (var argument in argResults!.rest)
@@ -126,3 +132,22 @@ abstract class Migrator extends Command<Map<Uri, String>> {
126132
}
127133
}
128134
}
135+
136+
/// A silent logger that calls [Migrator.handleDeprecation] when it receives a
137+
/// deprecation warning
138+
class _DeprecationLogger implements Logger {
139+
final Migrator migrator;
140+
141+
_DeprecationLogger(this.migrator);
142+
143+
@override
144+
void debug(String message, SourceSpan span) {}
145+
146+
@override
147+
void warn(String message,
148+
{FileSpan? span, Trace? trace, bool deprecation = false}) {
149+
if (deprecation) {
150+
migrator.handleDeprecation(message, span);
151+
}
152+
}
153+
}

lib/src/migrators/media_logic.dart

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Use of this source code is governed by an MIT-style
4+
// license that can be found in the LICENSE file or at
5+
// https://opensource.org/licenses/MIT.
6+
7+
import 'package:sass_api/sass_api.dart';
8+
import 'package:source_span/source_span.dart';
9+
10+
import '../migration_visitor.dart';
11+
import '../migrator.dart';
12+
import '../patch.dart';
13+
14+
/// Migrates deprecated `@media` query syntax to use interpolation.
15+
class MediaLogicMigrator extends Migrator {
16+
final name = 'media-logic';
17+
final description = r'Migrates deprecated `@media` query syntax.\n'
18+
'See https://sass-lang.com/d/media-logic.';
19+
20+
/// For each stylesheet URL, the set of relevant spans that require migration.
21+
final _expressionsToMigrate = <Uri, Set<FileSpan>>{};
22+
23+
@override
24+
void handleDeprecation(String message, FileSpan? span) {
25+
if (span == null) return;
26+
if (!message.startsWith('Starting a @media query with ')) return;
27+
_expressionsToMigrate.putIfAbsent(span.sourceUrl!, () => {}).add(span);
28+
}
29+
30+
@override
31+
Map<Uri, String> migrateFile(
32+
ImportCache importCache, Stylesheet stylesheet, Importer importer) {
33+
var visitor = _MediaLogicVisitor(
34+
importCache, migrateDependencies, _expressionsToMigrate);
35+
var result = visitor.run(stylesheet, importer);
36+
missingDependencies.addAll(visitor.missingDependencies);
37+
return result;
38+
}
39+
}
40+
41+
class _MediaLogicVisitor extends MigrationVisitor {
42+
/// For each stylesheet URL, the set of relevant spans that require migration.
43+
final Map<Uri, Set<FileSpan>> _expressionsToMigrate;
44+
45+
_MediaLogicVisitor(ImportCache importCache, bool migrateDependencies,
46+
this._expressionsToMigrate)
47+
: super(importCache, migrateDependencies);
48+
49+
@override
50+
void beforePatch(Stylesheet node) {
51+
var expressions = _expressionsToMigrate[node.span.sourceUrl] ?? {};
52+
for (var expression in expressions) {
53+
addPatch(Patch.insert(expression.start, '#{'));
54+
addPatch(Patch.insert(expression.end, '}'));
55+
}
56+
}
57+
}

lib/src/runner.dart

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:term_glyph/term_glyph.dart' as glyph;
1414

1515
import 'io.dart';
1616
import 'migrators/division.dart';
17+
import 'migrators/media_logic.dart';
1718
import 'migrators/module.dart';
1819
import 'migrators/namespace.dart';
1920
import 'migrators/strict_unary.dart';
@@ -54,6 +55,7 @@ class MigratorRunner extends CommandRunner<Map<Uri, String>> {
5455
..addFlag('version',
5556
help: 'Print the version of the Sass migrator.', negatable: false);
5657
addCommand(DivisionMigrator());
58+
addCommand(MediaLogicMigrator());
5759
addCommand(ModuleMigrator());
5860
addCommand(NamespaceMigrator());
5961
addCommand(StrictUnaryMigrator());

pubspec.yaml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: sass_migrator
2-
version: 1.6.0
2+
version: 1.7.0
33
description: A tool for running migrations on Sass files
44
homepage: https://github.com/sass/migrator
55

@@ -17,8 +17,9 @@ dependencies:
1717
node_interop: ^2.0.2
1818
node_io: ^2.2.0
1919
path: ^1.8.0
20-
sass_api: ^3.0.0
20+
sass_api: ^3.0.4
2121
source_span: ^1.8.1
22+
stack_trace: ^1.10.0
2223
string_scanner: ^1.1.0
2324
term_glyph: ^1.2.0
2425
tuple: ^2.0.0

test/migrators/README.md

+4-27
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,10 @@
11
# Migration Tests
22

3-
Each migrator should have:
3+
Each migrator should have a directory `<migrator-name>` that contains that
4+
migrator's HRX tests.
45

5-
* A `<migrator-name>_dart_test.dart` file that looks like:
6-
7-
```dart
8-
import '../utils.dart';
9-
10-
main() {
11-
testMigrator("<migrator-name>");
12-
}
13-
```
14-
15-
* A `<migrator-name>_node_test.dart` file that looks like:
16-
17-
```dart
18-
@Tags("node")
19-
20-
import 'package:test/test.dart';
21-
22-
import '../utils.dart';
23-
24-
main() {
25-
runNodeTests = true;
26-
testMigrator("<migrator-name>");
27-
}
28-
```
29-
30-
* A directory `<migrator-name>` that contains that migrator's HRX tests,
6+
A line `testMigrator(<migrator-name>)` should then be added to the `main`
7+
function of `migrator_dart_test.dart`.
318

329
## HRX Format
3310

test/migrators/division_dart_test.dart

-11
This file was deleted.

test/migrators/division_node_test.dart

-16
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<==> input/entrypoint.scss
2+
@media (not (foo)) {
3+
a {b: c}
4+
}
5+
6+
@media ((foo) and (bar)) {
7+
d {e: f}
8+
}
9+
10+
@media ((foo) or (bar)) {
11+
g {h: i}
12+
}
13+
14+
<==> output/entrypoint.scss
15+
@media (#{not (foo)}) {
16+
a {b: c}
17+
}
18+
19+
@media (#{(foo) and (bar)}) {
20+
d {e: f}
21+
}
22+
23+
@media (#{(foo) or (bar)}) {
24+
g {h: i}
25+
}

test/migrators/strict_unary_dart_test.dart test/migrators/migrator_dart_test.dart

+4
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
import '../utils.dart';
88

99
main() {
10+
testMigrator("division");
11+
testMigrator("media_logic");
12+
testMigrator("module");
13+
testMigrator("namespace");
1014
testMigrator("strict_unary");
1115
}

test/migrators/strict_unary_node_test.dart test/migrators/migrator_node_test.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88

99
import 'package:test/test.dart';
1010

11+
import 'migrator_dart_test.dart' as dart;
1112
import '../utils.dart';
1213

1314
main() {
1415
runNodeTests = true;
15-
testMigrator("strict_unary");
16+
dart.main();
1617
}

test/migrators/module_dart_test.dart

-11
This file was deleted.

test/migrators/module_node_test.dart

-16
This file was deleted.

test/migrators/namespace_dart_test.dart

-11
This file was deleted.

test/migrators/namespace_node_test.dart

-16
This file was deleted.

0 commit comments

Comments
 (0)