Skip to content

Commit 16f1816

Browse files
committed
Only omit 5 deprecation warnings per feature by default (#1327)
Closes #1323
1 parent d660bf1 commit 16f1816

File tree

13 files changed

+214
-32
lines changed

13 files changed

+214
-32
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,26 @@
22

33
* Don't emit the same warning in the same location multiple times.
44

5+
* Cap deprecation warnings at 5 per feature by default.
6+
57
### Command Line Interface
68

79
* Add a `--quiet-deps` flag which silences compiler warnings from stylesheets
810
loaded through `--load-path`s.
911

12+
* Add a `--verbose` flag which causes the compiler to emit all deprecation
13+
warnings, not just 5 per feature.
14+
1015
### Dart API
1116

1217
* Add a `quietDeps` argument to `compile()`, `compileString()`,
1318
`compileAsync()`, and `compileStringAsync()` which silences compiler warnings
1419
from stylesheets loaded through importers, load paths, and `package:` URLs.
1520

21+
* Add a `verbose` argument to `compile()`, `compileString()`, `compileAsync()`,
22+
and `compileStringAsync()` which causes the compiler to emit all deprecation
23+
warnings, not just 5 per feature.
24+
1625
## 1.33.0
1726

1827
* Deprecate the use of `/` for division. The new `math.div()` function should be

lib/sass.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ export 'src/warn.dart' show warn;
6464
/// If [quietDeps] is `true`, this will silence compiler warnings emitted for
6565
/// stylesheets loaded through [importers], [loadPaths], or [packageConfig].
6666
///
67+
/// By default, once a deprecation warning for a given feature is printed five
68+
/// times, further warnings for that feature are silenced. If [verbose] is true,
69+
/// all deprecation warnings are printed instead.
70+
///
6771
/// If [sourceMap] is passed, it's passed a [SingleMapping] that indicates which
6872
/// sections of the source file(s) correspond to which in the resulting CSS.
6973
/// It's called immediately before this method returns, and only if compilation
@@ -98,6 +102,7 @@ String compile(String path,
98102
Iterable<Callable>? functions,
99103
OutputStyle? style,
100104
bool quietDeps = false,
105+
bool verbose = false,
101106
void sourceMap(SingleMapping map)?,
102107
bool charset = true}) {
103108
logger ??= Logger.stderr(color: color);
@@ -111,6 +116,7 @@ String compile(String path,
111116
functions: functions,
112117
style: style,
113118
quietDeps: quietDeps,
119+
verbose: verbose,
114120
sourceMap: sourceMap != null,
115121
charset: charset);
116122
result.sourceMap.andThen(sourceMap);
@@ -158,6 +164,10 @@ String compile(String path,
158164
/// If [quietDeps] is `true`, this will silence compiler warnings emitted for
159165
/// stylesheets loaded through [importers], [loadPaths], or [packageConfig].
160166
///
167+
/// By default, once a deprecation warning for a given feature is printed five
168+
/// times, further warnings for that feature are silenced. If [verbose] is true,
169+
/// all deprecation warnings are printed instead.
170+
///
161171
/// If [sourceMap] is passed, it's passed a [SingleMapping] that indicates which
162172
/// sections of the source file(s) correspond to which in the resulting CSS.
163173
/// It's called immediately before this method returns, and only if compilation
@@ -195,6 +205,7 @@ String compileString(String source,
195205
Importer? importer,
196206
Object? url,
197207
bool quietDeps = false,
208+
bool verbose = false,
198209
void sourceMap(SingleMapping map)?,
199210
bool charset = true,
200211
@Deprecated("Use syntax instead.") bool indented = false}) {
@@ -212,6 +223,7 @@ String compileString(String source,
212223
importer: importer,
213224
url: url,
214225
quietDeps: quietDeps,
226+
verbose: verbose,
215227
sourceMap: sourceMap != null,
216228
charset: charset);
217229
result.sourceMap.andThen(sourceMap);
@@ -232,6 +244,7 @@ Future<String> compileAsync(String path,
232244
Iterable<AsyncCallable>? functions,
233245
OutputStyle? style,
234246
bool quietDeps = false,
247+
bool verbose = false,
235248
void sourceMap(SingleMapping map)?}) async {
236249
logger ??= Logger.stderr(color: color);
237250
var result = await c.compileAsync(path,
@@ -244,6 +257,7 @@ Future<String> compileAsync(String path,
244257
functions: functions,
245258
style: style,
246259
quietDeps: quietDeps,
260+
verbose: verbose,
247261
sourceMap: sourceMap != null);
248262
result.sourceMap.andThen(sourceMap);
249263
return result.css;
@@ -266,6 +280,7 @@ Future<String> compileStringAsync(String source,
266280
AsyncImporter? importer,
267281
Object? url,
268282
bool quietDeps = false,
283+
bool verbose = false,
269284
void sourceMap(SingleMapping map)?,
270285
bool charset = true,
271286
@Deprecated("Use syntax instead.") bool indented = false}) async {
@@ -283,6 +298,7 @@ Future<String> compileStringAsync(String source,
283298
importer: importer,
284299
url: url,
285300
quietDeps: quietDeps,
301+
verbose: verbose,
286302
sourceMap: sourceMap != null,
287303
charset: charset);
288304
result.sourceMap.andThen(sourceMap);

lib/src/async_compile.dart

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'importer.dart';
1515
import 'importer/node.dart';
1616
import 'io.dart';
1717
import 'logger.dart';
18+
import 'logger/terse.dart';
1819
import 'syntax.dart';
1920
import 'utils.dart';
2021
import 'visitor/async_evaluate.dart';
@@ -35,8 +36,12 @@ Future<CompileResult> compileAsync(String path,
3536
int? indentWidth,
3637
LineFeed? lineFeed,
3738
bool quietDeps = false,
39+
bool verbose = false,
3840
bool sourceMap = false,
3941
bool charset = true}) async {
42+
TerseLogger? terseLogger;
43+
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());
44+
4045
// If the syntax is different than the importer would default to, we have to
4146
// parse the file manually and we can't store it in the cache.
4247
Stylesheet? stylesheet;
@@ -52,7 +57,7 @@ Future<CompileResult> compileAsync(String path,
5257
url: p.toUri(path), logger: logger);
5358
}
5459

55-
return await _compileStylesheet(
60+
var result = await _compileStylesheet(
5661
stylesheet,
5762
logger,
5863
importCache,
@@ -66,6 +71,9 @@ Future<CompileResult> compileAsync(String path,
6671
quietDeps,
6772
sourceMap,
6873
charset);
74+
75+
terseLogger?.summarize(node: nodeImporter != null);
76+
return result;
6977
}
7078

7179
/// Like [compileStringAsync] in `lib/sass.dart`, but provides more options to
@@ -87,12 +95,16 @@ Future<CompileResult> compileStringAsync(String source,
8795
LineFeed? lineFeed,
8896
Object? url,
8997
bool quietDeps = false,
98+
bool verbose = false,
9099
bool sourceMap = false,
91100
bool charset = true}) async {
101+
TerseLogger? terseLogger;
102+
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());
103+
92104
var stylesheet =
93105
Stylesheet.parse(source, syntax ?? Syntax.scss, url: url, logger: logger);
94106

95-
return _compileStylesheet(
107+
var result = await _compileStylesheet(
96108
stylesheet,
97109
logger,
98110
importCache,
@@ -106,6 +118,9 @@ Future<CompileResult> compileStringAsync(String source,
106118
quietDeps,
107119
sourceMap,
108120
charset);
121+
122+
terseLogger?.summarize(node: nodeImporter != null);
123+
return result;
109124
}
110125

111126
/// Compiles [stylesheet] and returns its result.

lib/src/compile.dart

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// DO NOT EDIT. This file was generated from async_compile.dart.
66
// See tool/grind/synchronize.dart for details.
77
//
8-
// Checksum: bdf01f7ff8eea0efafa6c7c93920caf26e324f4e
8+
// Checksum: 8e813f2ead6e78899ce820e279983278809a7ea5
99
//
1010
// ignore_for_file: unused_import
1111

@@ -25,6 +25,7 @@ import 'importer.dart';
2525
import 'importer/node.dart';
2626
import 'io.dart';
2727
import 'logger.dart';
28+
import 'logger/terse.dart';
2829
import 'syntax.dart';
2930
import 'utils.dart';
3031
import 'visitor/evaluate.dart';
@@ -45,8 +46,12 @@ CompileResult compile(String path,
4546
int? indentWidth,
4647
LineFeed? lineFeed,
4748
bool quietDeps = false,
49+
bool verbose = false,
4850
bool sourceMap = false,
4951
bool charset = true}) {
52+
TerseLogger? terseLogger;
53+
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());
54+
5055
// If the syntax is different than the importer would default to, we have to
5156
// parse the file manually and we can't store it in the cache.
5257
Stylesheet? stylesheet;
@@ -62,7 +67,7 @@ CompileResult compile(String path,
6267
url: p.toUri(path), logger: logger);
6368
}
6469

65-
return _compileStylesheet(
70+
var result = _compileStylesheet(
6671
stylesheet,
6772
logger,
6873
importCache,
@@ -76,6 +81,9 @@ CompileResult compile(String path,
7681
quietDeps,
7782
sourceMap,
7883
charset);
84+
85+
terseLogger?.summarize(node: nodeImporter != null);
86+
return result;
7987
}
8088

8189
/// Like [compileString] in `lib/sass.dart`, but provides more options to
@@ -97,12 +105,16 @@ CompileResult compileString(String source,
97105
LineFeed? lineFeed,
98106
Object? url,
99107
bool quietDeps = false,
108+
bool verbose = false,
100109
bool sourceMap = false,
101110
bool charset = true}) {
111+
TerseLogger? terseLogger;
112+
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());
113+
102114
var stylesheet =
103115
Stylesheet.parse(source, syntax ?? Syntax.scss, url: url, logger: logger);
104116

105-
return _compileStylesheet(
117+
var result = _compileStylesheet(
106118
stylesheet,
107119
logger,
108120
importCache,
@@ -116,6 +128,9 @@ CompileResult compileString(String source,
116128
quietDeps,
117129
sourceMap,
118130
charset);
131+
132+
terseLogger?.summarize(node: nodeImporter != null);
133+
return result;
119134
}
120135

121136
/// Compiles [stylesheet] and returns its result.

lib/src/executable/compile_stylesheet.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
6969
importer: FilesystemImporter('.'),
7070
style: options.style,
7171
quietDeps: options.quietDeps,
72+
verbose: options.verbose,
7273
sourceMap: options.emitSourceMap,
7374
charset: options.charset)
7475
: await compileAsync(source,
@@ -77,6 +78,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
7778
importCache: importCache,
7879
style: options.style,
7980
quietDeps: options.quietDeps,
81+
verbose: options.verbose,
8082
sourceMap: options.emitSourceMap,
8183
charset: options.charset);
8284
} else {
@@ -88,6 +90,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
8890
importer: FilesystemImporter('.'),
8991
style: options.style,
9092
quietDeps: options.quietDeps,
93+
verbose: options.verbose,
9194
sourceMap: options.emitSourceMap,
9295
charset: options.charset)
9396
: compile(source,
@@ -96,6 +99,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
9699
importCache: graph.importCache,
97100
style: options.style,
98101
quietDeps: options.quietDeps,
102+
verbose: options.verbose,
99103
sourceMap: options.emitSourceMap,
100104
charset: options.charset);
101105
}

lib/src/executable/options.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ class ExecutableOptions {
102102
..addFlag('quiet-deps',
103103
help: "Don't print compiler warnings from dependencies.\n"
104104
"Stylesheets imported through load paths count as dependencies.")
105+
..addFlag('verbose',
106+
help: "Print all deprecation warnings even when they're repetitive.")
105107
..addFlag('trace', help: 'Print full Dart stack traces for exceptions.')
106108
..addFlag('help',
107109
abbr: 'h', help: 'Print this usage information.', negatable: false)
@@ -172,6 +174,9 @@ class ExecutableOptions {
172174
/// Whether to silence warnings in dependencies.
173175
bool get quietDeps => _options['quiet-deps'] as bool;
174176

177+
/// Whether to emit all repetitive deprecation warnings.
178+
bool get verbose => _options['verbose'] as bool;
179+
175180
/// The logger to use to emit messages from Sass.
176181
Logger get logger => quiet ? Logger.quiet : Logger.stderr(color: color);
177182

lib/src/logger/terse.dart

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2018 Google Inc. Use of this source code is governed by an
2+
// MIT-style license that can be found in the LICENSE file or at
3+
// https://opensource.org/licenses/MIT.
4+
5+
import 'package:collection/collection.dart';
6+
import 'package:source_span/source_span.dart';
7+
import 'package:stack_trace/stack_trace.dart';
8+
9+
import '../logger.dart';
10+
11+
/// The maximum number of repetitions of the same warning [TerseLogger] will
12+
/// emit before hiding the rest.
13+
const _maxRepetitions = 5;
14+
15+
/// A logger that wraps an inner logger to omit repeated deprecation warnings.
16+
///
17+
/// A warning is considered "repeated" if the first paragraph is the same as
18+
/// another warning that's already been emitted.
19+
class TerseLogger implements Logger {
20+
/// A map from the first paragraph of a warning to the number of times this
21+
/// logger has emitted a warning with that line.
22+
final _warningCounts = <String, int>{};
23+
24+
final Logger _inner;
25+
26+
TerseLogger(this._inner);
27+
28+
void warn(String message,
29+
{FileSpan? span, Trace? trace, bool deprecation = false}) {
30+
if (deprecation) {
31+
var firstParagraph = message.split("\n\n").first;
32+
var count = _warningCounts[firstParagraph] =
33+
(_warningCounts[firstParagraph] ?? 0) + 1;
34+
if (count > _maxRepetitions) return;
35+
}
36+
37+
_inner.warn(message, span: span, trace: trace, deprecation: deprecation);
38+
}
39+
40+
void debug(String message, SourceSpan span) => _inner.debug(message, span);
41+
42+
/// Prints a warning indicating the number of deprecation warnings that were
43+
/// omitted.
44+
///
45+
/// The [node] flag indicates whether this is running in Node.js mode, in
46+
/// which case it doesn't mention "verbose mode" because the Node API doesn't
47+
/// support that.
48+
void summarize({required bool node}) {
49+
var total = _warningCounts.values
50+
.where((count) => count > _maxRepetitions)
51+
.map((count) => count - _maxRepetitions)
52+
.sum;
53+
if (total > 0) {
54+
_inner.warn("$total repetitive deprecation warnings omitted." +
55+
(node ? "" : "\nRun in verbose mode to see all warnings."));
56+
}
57+
}
58+
}

lib/src/parse/scss.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ class ScssParser extends StylesheetParser {
4848
logger.warn(
4949
'@elseif is deprecated and will not be supported in future Sass '
5050
'versions.\n'
51-
'Use "@else if" instead.',
51+
'\n'
52+
'Recommendation: @else if',
5253
span: scanner.spanFrom(beforeAt),
5354
deprecation: true);
5455
scanner.position -= 2;

lib/src/parse/stylesheet.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,10 +1334,13 @@ abstract class StylesheetParser extends Parser {
13341334
var value = buffer.interpolation(scanner.spanFrom(valueStart));
13351335
return _withChildren(_statement, start, (children, span) {
13361336
if (needsDeprecationWarning) {
1337-
logger.warn("""
1338-
@-moz-document is deprecated and support will be removed from Sass in a future
1339-
release. For details, see http://bit.ly/moz-document.
1340-
""", span: span, deprecation: true);
1337+
logger.warn(
1338+
"@-moz-document is deprecated and support will be removed in Dart "
1339+
"Sass 2.0.0.\n"
1340+
"\n"
1341+
"For details, see http://bit.ly/moz-document.",
1342+
span: span,
1343+
deprecation: true);
13411344
}
13421345

13431346
return AtRule(name, span, value: value, children: children);

0 commit comments

Comments
 (0)