Skip to content

Commit

Permalink
Only omit 5 deprecation warnings per feature by default (#1327)
Browse files Browse the repository at this point in the history
Closes #1323
  • Loading branch information
nex3 committed May 22, 2021
1 parent 0bf457f commit 6444f8d
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 32 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,17 +2,26 @@

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

* Cap deprecation warnings at 5 per feature by default.

### Command Line Interface

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

* Add a `--verbose` flag which causes the compiler to emit all deprecation
warnings, not just 5 per feature.

### Dart API

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

* Add a `verbose` argument to `compile()`, `compileString()`, `compileAsync()`,
and `compileStringAsync()` which causes the compiler to emit all deprecation
warnings, not just 5 per feature.

## 1.33.0

* Deprecate the use of `/` for division. The new `math.div()` function should be
Expand Down
16 changes: 16 additions & 0 deletions lib/sass.dart
Expand Up @@ -64,6 +64,10 @@ export 'src/warn.dart' show warn;
/// If [quietDeps] is `true`, this will silence compiler warnings emitted for
/// stylesheets loaded through [importers], [loadPaths], or [packageConfig].
///
/// By default, once a deprecation warning for a given feature is printed five
/// times, further warnings for that feature are silenced. If [verbose] is true,
/// all deprecation warnings are printed instead.
///
/// If [sourceMap] is passed, it's passed a [SingleMapping] that indicates which
/// sections of the source file(s) correspond to which in the resulting CSS.
/// It's called immediately before this method returns, and only if compilation
Expand Down Expand Up @@ -98,6 +102,7 @@ String compile(String path,
Iterable<Callable>? functions,
OutputStyle? style,
bool quietDeps = false,
bool verbose = false,
void sourceMap(SingleMapping map)?,
bool charset = true}) {
logger ??= Logger.stderr(color: color);
Expand All @@ -111,6 +116,7 @@ String compile(String path,
functions: functions,
style: style,
quietDeps: quietDeps,
verbose: verbose,
sourceMap: sourceMap != null,
charset: charset);
result.sourceMap.andThen(sourceMap);
Expand Down Expand Up @@ -158,6 +164,10 @@ String compile(String path,
/// If [quietDeps] is `true`, this will silence compiler warnings emitted for
/// stylesheets loaded through [importers], [loadPaths], or [packageConfig].
///
/// By default, once a deprecation warning for a given feature is printed five
/// times, further warnings for that feature are silenced. If [verbose] is true,
/// all deprecation warnings are printed instead.
///
/// If [sourceMap] is passed, it's passed a [SingleMapping] that indicates which
/// sections of the source file(s) correspond to which in the resulting CSS.
/// It's called immediately before this method returns, and only if compilation
Expand Down Expand Up @@ -195,6 +205,7 @@ String compileString(String source,
Importer? importer,
Object? url,
bool quietDeps = false,
bool verbose = false,
void sourceMap(SingleMapping map)?,
bool charset = true,
@Deprecated("Use syntax instead.") bool indented = false}) {
Expand All @@ -212,6 +223,7 @@ String compileString(String source,
importer: importer,
url: url,
quietDeps: quietDeps,
verbose: verbose,
sourceMap: sourceMap != null,
charset: charset);
result.sourceMap.andThen(sourceMap);
Expand All @@ -232,6 +244,7 @@ Future<String> compileAsync(String path,
Iterable<AsyncCallable>? functions,
OutputStyle? style,
bool quietDeps = false,
bool verbose = false,
void sourceMap(SingleMapping map)?}) async {
logger ??= Logger.stderr(color: color);
var result = await c.compileAsync(path,
Expand All @@ -244,6 +257,7 @@ Future<String> compileAsync(String path,
functions: functions,
style: style,
quietDeps: quietDeps,
verbose: verbose,
sourceMap: sourceMap != null);
result.sourceMap.andThen(sourceMap);
return result.css;
Expand All @@ -266,6 +280,7 @@ Future<String> compileStringAsync(String source,
AsyncImporter? importer,
Object? url,
bool quietDeps = false,
bool verbose = false,
void sourceMap(SingleMapping map)?,
bool charset = true,
@Deprecated("Use syntax instead.") bool indented = false}) async {
Expand All @@ -283,6 +298,7 @@ Future<String> compileStringAsync(String source,
importer: importer,
url: url,
quietDeps: quietDeps,
verbose: verbose,
sourceMap: sourceMap != null,
charset: charset);
result.sourceMap.andThen(sourceMap);
Expand Down
19 changes: 17 additions & 2 deletions lib/src/async_compile.dart
Expand Up @@ -15,6 +15,7 @@ import 'importer.dart';
import 'importer/node.dart';
import 'io.dart';
import 'logger.dart';
import 'logger/terse.dart';
import 'syntax.dart';
import 'utils.dart';
import 'visitor/async_evaluate.dart';
Expand All @@ -35,8 +36,12 @@ Future<CompileResult> compileAsync(String path,
int? indentWidth,
LineFeed? lineFeed,
bool quietDeps = false,
bool verbose = false,
bool sourceMap = false,
bool charset = true}) async {
TerseLogger? terseLogger;
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());

// If the syntax is different than the importer would default to, we have to
// parse the file manually and we can't store it in the cache.
Stylesheet? stylesheet;
Expand All @@ -52,7 +57,7 @@ Future<CompileResult> compileAsync(String path,
url: p.toUri(path), logger: logger);
}

return await _compileStylesheet(
var result = await _compileStylesheet(
stylesheet,
logger,
importCache,
Expand All @@ -66,6 +71,9 @@ Future<CompileResult> compileAsync(String path,
quietDeps,
sourceMap,
charset);

terseLogger?.summarize(node: nodeImporter != null);
return result;
}

/// Like [compileStringAsync] in `lib/sass.dart`, but provides more options to
Expand All @@ -87,12 +95,16 @@ Future<CompileResult> compileStringAsync(String source,
LineFeed? lineFeed,
Object? url,
bool quietDeps = false,
bool verbose = false,
bool sourceMap = false,
bool charset = true}) async {
TerseLogger? terseLogger;
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());

var stylesheet =
Stylesheet.parse(source, syntax ?? Syntax.scss, url: url, logger: logger);

return _compileStylesheet(
var result = await _compileStylesheet(
stylesheet,
logger,
importCache,
Expand All @@ -106,6 +118,9 @@ Future<CompileResult> compileStringAsync(String source,
quietDeps,
sourceMap,
charset);

terseLogger?.summarize(node: nodeImporter != null);
return result;
}

/// Compiles [stylesheet] and returns its result.
Expand Down
21 changes: 18 additions & 3 deletions lib/src/compile.dart
Expand Up @@ -5,7 +5,7 @@
// DO NOT EDIT. This file was generated from async_compile.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: bdf01f7ff8eea0efafa6c7c93920caf26e324f4e
// Checksum: 8e813f2ead6e78899ce820e279983278809a7ea5
//
// ignore_for_file: unused_import

Expand All @@ -25,6 +25,7 @@ import 'importer.dart';
import 'importer/node.dart';
import 'io.dart';
import 'logger.dart';
import 'logger/terse.dart';
import 'syntax.dart';
import 'utils.dart';
import 'visitor/evaluate.dart';
Expand All @@ -45,8 +46,12 @@ CompileResult compile(String path,
int? indentWidth,
LineFeed? lineFeed,
bool quietDeps = false,
bool verbose = false,
bool sourceMap = false,
bool charset = true}) {
TerseLogger? terseLogger;
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());

// If the syntax is different than the importer would default to, we have to
// parse the file manually and we can't store it in the cache.
Stylesheet? stylesheet;
Expand All @@ -62,7 +67,7 @@ CompileResult compile(String path,
url: p.toUri(path), logger: logger);
}

return _compileStylesheet(
var result = _compileStylesheet(
stylesheet,
logger,
importCache,
Expand All @@ -76,6 +81,9 @@ CompileResult compile(String path,
quietDeps,
sourceMap,
charset);

terseLogger?.summarize(node: nodeImporter != null);
return result;
}

/// Like [compileString] in `lib/sass.dart`, but provides more options to
Expand All @@ -97,12 +105,16 @@ CompileResult compileString(String source,
LineFeed? lineFeed,
Object? url,
bool quietDeps = false,
bool verbose = false,
bool sourceMap = false,
bool charset = true}) {
TerseLogger? terseLogger;
if (!verbose) logger = terseLogger = TerseLogger(logger ?? Logger.stderr());

var stylesheet =
Stylesheet.parse(source, syntax ?? Syntax.scss, url: url, logger: logger);

return _compileStylesheet(
var result = _compileStylesheet(
stylesheet,
logger,
importCache,
Expand All @@ -116,6 +128,9 @@ CompileResult compileString(String source,
quietDeps,
sourceMap,
charset);

terseLogger?.summarize(node: nodeImporter != null);
return result;
}

/// Compiles [stylesheet] and returns its result.
Expand Down
4 changes: 4 additions & 0 deletions lib/src/executable/compile_stylesheet.dart
Expand Up @@ -69,6 +69,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
importer: FilesystemImporter('.'),
style: options.style,
quietDeps: options.quietDeps,
verbose: options.verbose,
sourceMap: options.emitSourceMap,
charset: options.charset)
: await compileAsync(source,
Expand All @@ -77,6 +78,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
importCache: importCache,
style: options.style,
quietDeps: options.quietDeps,
verbose: options.verbose,
sourceMap: options.emitSourceMap,
charset: options.charset);
} else {
Expand All @@ -88,6 +90,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
importer: FilesystemImporter('.'),
style: options.style,
quietDeps: options.quietDeps,
verbose: options.verbose,
sourceMap: options.emitSourceMap,
charset: options.charset)
: compile(source,
Expand All @@ -96,6 +99,7 @@ Future<void> compileStylesheet(ExecutableOptions options, StylesheetGraph graph,
importCache: graph.importCache,
style: options.style,
quietDeps: options.quietDeps,
verbose: options.verbose,
sourceMap: options.emitSourceMap,
charset: options.charset);
}
Expand Down
5 changes: 5 additions & 0 deletions lib/src/executable/options.dart
Expand Up @@ -102,6 +102,8 @@ class ExecutableOptions {
..addFlag('quiet-deps',
help: "Don't print compiler warnings from dependencies.\n"
"Stylesheets imported through load paths count as dependencies.")
..addFlag('verbose',
help: "Print all deprecation warnings even when they're repetitive.")
..addFlag('trace', help: 'Print full Dart stack traces for exceptions.')
..addFlag('help',
abbr: 'h', help: 'Print this usage information.', negatable: false)
Expand Down Expand Up @@ -172,6 +174,9 @@ class ExecutableOptions {
/// Whether to silence warnings in dependencies.
bool get quietDeps => _options['quiet-deps'] as bool;

/// Whether to emit all repetitive deprecation warnings.
bool get verbose => _options['verbose'] as bool;

/// The logger to use to emit messages from Sass.
Logger get logger => quiet ? Logger.quiet : Logger.stderr(color: color);

Expand Down
58 changes: 58 additions & 0 deletions lib/src/logger/terse.dart
@@ -0,0 +1,58 @@
// Copyright 2018 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import 'package:collection/collection.dart';
import 'package:source_span/source_span.dart';
import 'package:stack_trace/stack_trace.dart';

import '../logger.dart';

/// The maximum number of repetitions of the same warning [TerseLogger] will
/// emit before hiding the rest.
const _maxRepetitions = 5;

/// A logger that wraps an inner logger to omit repeated deprecation warnings.
///
/// A warning is considered "repeated" if the first paragraph is the same as
/// another warning that's already been emitted.
class TerseLogger implements Logger {
/// A map from the first paragraph of a warning to the number of times this
/// logger has emitted a warning with that line.
final _warningCounts = <String, int>{};

final Logger _inner;

TerseLogger(this._inner);

void warn(String message,
{FileSpan? span, Trace? trace, bool deprecation = false}) {
if (deprecation) {
var firstParagraph = message.split("\n\n").first;
var count = _warningCounts[firstParagraph] =
(_warningCounts[firstParagraph] ?? 0) + 1;
if (count > _maxRepetitions) return;
}

_inner.warn(message, span: span, trace: trace, deprecation: deprecation);
}

void debug(String message, SourceSpan span) => _inner.debug(message, span);

/// Prints a warning indicating the number of deprecation warnings that were
/// omitted.
///
/// The [node] flag indicates whether this is running in Node.js mode, in
/// which case it doesn't mention "verbose mode" because the Node API doesn't
/// support that.
void summarize({required bool node}) {
var total = _warningCounts.values
.where((count) => count > _maxRepetitions)
.map((count) => count - _maxRepetitions)
.sum;
if (total > 0) {
_inner.warn("$total repetitive deprecation warnings omitted." +
(node ? "" : "\nRun in verbose mode to see all warnings."));
}
}
}
3 changes: 2 additions & 1 deletion lib/src/parse/scss.dart
Expand Up @@ -48,7 +48,8 @@ class ScssParser extends StylesheetParser {
logger.warn(
'@elseif is deprecated and will not be supported in future Sass '
'versions.\n'
'Use "@else if" instead.',
'\n'
'Recommendation: @else if',
span: scanner.spanFrom(beforeAt),
deprecation: true);
scanner.position -= 2;
Expand Down
11 changes: 7 additions & 4 deletions lib/src/parse/stylesheet.dart
Expand Up @@ -1334,10 +1334,13 @@ abstract class StylesheetParser extends Parser {
var value = buffer.interpolation(scanner.spanFrom(valueStart));
return _withChildren(_statement, start, (children, span) {
if (needsDeprecationWarning) {
logger.warn("""
@-moz-document is deprecated and support will be removed from Sass in a future
release. For details, see http://bit.ly/moz-document.
""", span: span, deprecation: true);
logger.warn(
"@-moz-document is deprecated and support will be removed in Dart "
"Sass 2.0.0.\n"
"\n"
"For details, see http://bit.ly/moz-document.",
span: span,
deprecation: true);
}

return AtRule(name, span, value: value, children: children);
Expand Down

0 comments on commit 6444f8d

Please sign in to comment.