mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-30 04:39:03 +01:00
Add quietDeps and verbose to the JS API (#1353)
To support this, we now run Node-Sass-style relative loads outside of the Node importer. This allows the evaluator to check whether a relative load succeeded and use that to determine whether the stylesheet counts as a dependency. See sass/sass#3065
This commit is contained in:
parent
a077094f24
commit
7e371666f4
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,4 +1,4 @@
|
|||||||
## 1.34.2
|
## 1.35.0
|
||||||
|
|
||||||
* Fix a couple bugs that could prevent some members from being found in certain
|
* Fix a couple bugs that could prevent some members from being found in certain
|
||||||
files that use a mix of imports and the module system.
|
files that use a mix of imports and the module system.
|
||||||
@ -6,6 +6,14 @@
|
|||||||
* Fix incorrect recommendation for migrating division expressions that reference
|
* Fix incorrect recommendation for migrating division expressions that reference
|
||||||
namespaced variables.
|
namespaced variables.
|
||||||
|
|
||||||
|
### JS API
|
||||||
|
|
||||||
|
* Add a `quietDeps` option which silences compiler warnings from stylesheets
|
||||||
|
loaded through importers and load paths.
|
||||||
|
|
||||||
|
* Add a `verbose` option which causes the compiler to emit all deprecation
|
||||||
|
warnings, not just 5 per feature.
|
||||||
|
|
||||||
## 1.34.1
|
## 1.34.1
|
||||||
|
|
||||||
* Fix a bug where `--update` would always compile any file that depends on a
|
* Fix a bug where `--update` would always compile any file that depends on a
|
||||||
|
@ -102,8 +102,8 @@ class AsyncImportCache {
|
|||||||
/// canonicalize [url] (resolved relative to [baseUrl] if it's passed).
|
/// canonicalize [url] (resolved relative to [baseUrl] if it's passed).
|
||||||
///
|
///
|
||||||
/// If any importers understand [url], returns that importer as well as the
|
/// If any importers understand [url], returns that importer as well as the
|
||||||
/// canonicalized URL and the original URL resolved relative to [baseUrl] if
|
/// canonicalized URL and the original URL (resolved relative to [baseUrl] if
|
||||||
/// applicable. Otherwise, returns `null`.
|
/// applicable). Otherwise, returns `null`.
|
||||||
Future<Tuple3<AsyncImporter, Uri, Uri>?> canonicalize(Uri url,
|
Future<Tuple3<AsyncImporter, Uri, Uri>?> canonicalize(Uri url,
|
||||||
{AsyncImporter? baseImporter,
|
{AsyncImporter? baseImporter,
|
||||||
Uri? baseUrl,
|
Uri? baseUrl,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// DO NOT EDIT. This file was generated from async_import_cache.dart.
|
// DO NOT EDIT. This file was generated from async_import_cache.dart.
|
||||||
// See tool/grind/synchronize.dart for details.
|
// See tool/grind/synchronize.dart for details.
|
||||||
//
|
//
|
||||||
// Checksum: 6821c9a63333c3c99b0c9515aa04e73a14e0f141
|
// Checksum: 27d8582c2ab318a52d433390ec256497b6af5dec
|
||||||
//
|
//
|
||||||
// ignore_for_file: unused_import
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
@ -108,8 +108,8 @@ class ImportCache {
|
|||||||
/// canonicalize [url] (resolved relative to [baseUrl] if it's passed).
|
/// canonicalize [url] (resolved relative to [baseUrl] if it's passed).
|
||||||
///
|
///
|
||||||
/// If any importers understand [url], returns that importer as well as the
|
/// If any importers understand [url], returns that importer as well as the
|
||||||
/// canonicalized URL and the original URL resolved relative to [baseUrl] if
|
/// canonicalized URL and the original URL (resolved relative to [baseUrl] if
|
||||||
/// applicable. Otherwise, returns `null`.
|
/// applicable). Otherwise, returns `null`.
|
||||||
Tuple3<Importer, Uri, Uri>? canonicalize(Uri url,
|
Tuple3<Importer, Uri, Uri>? canonicalize(Uri url,
|
||||||
{Importer? baseImporter, Uri? baseUrl, bool forImport = false}) {
|
{Importer? baseImporter, Uri? baseUrl, bool forImport = false}) {
|
||||||
if (baseImporter != null) {
|
if (baseImporter != null) {
|
||||||
|
@ -68,18 +68,33 @@ class NodeImporter {
|
|||||||
yield* sassPath.split(isWindows ? ';' : ':');
|
yield* sassPath.split(isWindows ? ';' : ':');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the stylesheet at [url].
|
/// Loads the stylesheet at [url] relative to [previous] if possible.
|
||||||
|
///
|
||||||
|
/// This can also load [url] directly if it's an absolute `file:` URL, even if
|
||||||
|
/// `previous` isn't defined or isn't a `file:` URL.
|
||||||
|
///
|
||||||
|
/// Returns the stylesheet at that path and the URL used to load it, or `null`
|
||||||
|
/// if loading failed.
|
||||||
|
Tuple2<String, String>? loadRelative(
|
||||||
|
String url, Uri? previous, bool forImport) {
|
||||||
|
if (p.url.isAbsolute(url)) {
|
||||||
|
if (!url.startsWith('/') && !url.startsWith('file:')) return null;
|
||||||
|
return _tryPath(p.fromUri(url), forImport);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous?.scheme != 'file') return null;
|
||||||
|
|
||||||
|
// 1: Filesystem imports relative to the base file.
|
||||||
|
return _tryPath(
|
||||||
|
p.join(p.dirname(p.fromUri(previous)), p.fromUri(url)), forImport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads the stylesheet at [url] from an importer or load path.
|
||||||
///
|
///
|
||||||
/// The [previous] URL is the URL of the stylesheet in which the import
|
/// The [previous] URL is the URL of the stylesheet in which the import
|
||||||
/// appeared. Returns the contents of the stylesheet and the URL to use as
|
/// appeared. Returns the contents of the stylesheet and the URL to use as
|
||||||
/// [previous] for imports within the loaded stylesheet.
|
/// [previous] for imports within the loaded stylesheet.
|
||||||
Tuple2<String, String>? load(String url, Uri? previous, bool forImport) {
|
Tuple2<String, String>? load(String url, Uri? previous, bool forImport) {
|
||||||
var parsed = Uri.parse(url);
|
|
||||||
if (parsed.scheme == '' || parsed.scheme == 'file') {
|
|
||||||
var result = _resolveRelativePath(p.fromUri(parsed), previous, forImport);
|
|
||||||
if (result != null) return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The previous URL is always an absolute file path for filesystem imports.
|
// The previous URL is always an absolute file path for filesystem imports.
|
||||||
var previousString = _previousToString(previous);
|
var previousString = _previousToString(previous);
|
||||||
for (var importer in _importers) {
|
for (var importer in _importers) {
|
||||||
@ -90,22 +105,17 @@ class NodeImporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _resolveLoadPathFromUrl(parsed, forImport);
|
return _resolveLoadPathFromUrl(Uri.parse(url), forImport);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronously loads the stylesheet at [url].
|
/// Asynchronously loads the stylesheet at [url] from an importer or load
|
||||||
|
/// path.
|
||||||
///
|
///
|
||||||
/// The [previous] URL is the URL of the stylesheet in which the import
|
/// The [previous] URL is the URL of the stylesheet in which the import
|
||||||
/// appeared. Returns the contents of the stylesheet and the URL to use as
|
/// appeared. Returns the contents of the stylesheet and the URL to use as
|
||||||
/// [previous] for imports within the loaded stylesheet.
|
/// [previous] for imports within the loaded stylesheet.
|
||||||
Future<Tuple2<String, String>?> loadAsync(
|
Future<Tuple2<String, String>?> loadAsync(
|
||||||
String url, Uri? previous, bool forImport) async {
|
String url, Uri? previous, bool forImport) async {
|
||||||
var parsed = Uri.parse(url);
|
|
||||||
if (parsed.scheme == '' || parsed.scheme == 'file') {
|
|
||||||
var result = _resolveRelativePath(p.fromUri(parsed), previous, forImport);
|
|
||||||
if (result != null) return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The previous URL is always an absolute file path for filesystem imports.
|
// The previous URL is always an absolute file path for filesystem imports.
|
||||||
var previousString = _previousToString(previous);
|
var previousString = _previousToString(previous);
|
||||||
for (var importer in _importers) {
|
for (var importer in _importers) {
|
||||||
@ -116,20 +126,7 @@ class NodeImporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _resolveLoadPathFromUrl(parsed, forImport);
|
return _resolveLoadPathFromUrl(Uri.parse(url), forImport);
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to load a stylesheet at the given [path] relative to [previous].
|
|
||||||
///
|
|
||||||
/// Returns the stylesheet at that path and the URL used to load it, or `null`
|
|
||||||
/// if loading failed.
|
|
||||||
Tuple2<String, String>? _resolveRelativePath(
|
|
||||||
String path, Uri? previous, bool forImport) {
|
|
||||||
if (p.isAbsolute(path)) return _tryPath(path, forImport);
|
|
||||||
if (previous?.scheme != 'file') return null;
|
|
||||||
|
|
||||||
// 1: Filesystem imports relative to the base file.
|
|
||||||
return _tryPath(p.join(p.dirname(p.fromUri(previous)), path), forImport);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts [previous] to a string to pass to the importer function.
|
/// Converts [previous] to a string to pass to the importer function.
|
||||||
@ -192,8 +189,9 @@ class NodeImporter {
|
|||||||
} else if (contents != null) {
|
} else if (contents != null) {
|
||||||
return Tuple2(contents, file);
|
return Tuple2(contents, file);
|
||||||
} else {
|
} else {
|
||||||
var resolved = _resolveRelativePath(file, previous, forImport) ??
|
var resolved =
|
||||||
_resolveLoadPath(file, forImport);
|
loadRelative(p.toUri(file).toString(), previous, forImport) ??
|
||||||
|
_resolveLoadPath(file, forImport);
|
||||||
if (resolved != null) return resolved;
|
if (resolved != null) return resolved;
|
||||||
throw "Can't find stylesheet to import.";
|
throw "Can't find stylesheet to import.";
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,10 @@ class NodeImporter {
|
|||||||
NodeImporter(Object options, Iterable<String> includePaths,
|
NodeImporter(Object options, Iterable<String> includePaths,
|
||||||
Iterable<Object> importers);
|
Iterable<Object> importers);
|
||||||
|
|
||||||
|
Tuple2<String, String>? loadRelative(
|
||||||
|
String url, Uri? previous, bool forImport) =>
|
||||||
|
throw '';
|
||||||
|
|
||||||
Tuple2<String, String>? load(String url, Uri? previous, bool forImport) =>
|
Tuple2<String, String>? load(String url, Uri? previous, bool forImport) =>
|
||||||
throw '';
|
throw '';
|
||||||
|
|
||||||
|
@ -106,6 +106,8 @@ Future<RenderResult> _renderAsync(RenderOptions options) async {
|
|||||||
indentWidth: _parseIndentWidth(options.indentWidth),
|
indentWidth: _parseIndentWidth(options.indentWidth),
|
||||||
lineFeed: _parseLineFeed(options.linefeed),
|
lineFeed: _parseLineFeed(options.linefeed),
|
||||||
url: file == null ? 'stdin' : p.toUri(file).toString(),
|
url: file == null ? 'stdin' : p.toUri(file).toString(),
|
||||||
|
quietDeps: options.quietDeps ?? false,
|
||||||
|
verbose: options.verbose ?? false,
|
||||||
sourceMap: _enableSourceMaps(options));
|
sourceMap: _enableSourceMaps(options));
|
||||||
} else if (file != null) {
|
} else if (file != null) {
|
||||||
result = await compileAsync(file,
|
result = await compileAsync(file,
|
||||||
@ -116,6 +118,8 @@ Future<RenderResult> _renderAsync(RenderOptions options) async {
|
|||||||
useSpaces: options.indentType != 'tab',
|
useSpaces: options.indentType != 'tab',
|
||||||
indentWidth: _parseIndentWidth(options.indentWidth),
|
indentWidth: _parseIndentWidth(options.indentWidth),
|
||||||
lineFeed: _parseLineFeed(options.linefeed),
|
lineFeed: _parseLineFeed(options.linefeed),
|
||||||
|
quietDeps: options.quietDeps ?? false,
|
||||||
|
verbose: options.verbose ?? false,
|
||||||
sourceMap: _enableSourceMaps(options));
|
sourceMap: _enableSourceMaps(options));
|
||||||
} else {
|
} else {
|
||||||
throw ArgumentError("Either options.data or options.file must be set.");
|
throw ArgumentError("Either options.data or options.file must be set.");
|
||||||
@ -147,6 +151,8 @@ RenderResult _renderSync(RenderOptions options) {
|
|||||||
indentWidth: _parseIndentWidth(options.indentWidth),
|
indentWidth: _parseIndentWidth(options.indentWidth),
|
||||||
lineFeed: _parseLineFeed(options.linefeed),
|
lineFeed: _parseLineFeed(options.linefeed),
|
||||||
url: file == null ? 'stdin' : p.toUri(file).toString(),
|
url: file == null ? 'stdin' : p.toUri(file).toString(),
|
||||||
|
quietDeps: options.quietDeps ?? false,
|
||||||
|
verbose: options.verbose ?? false,
|
||||||
sourceMap: _enableSourceMaps(options));
|
sourceMap: _enableSourceMaps(options));
|
||||||
} else if (file != null) {
|
} else if (file != null) {
|
||||||
result = compile(file,
|
result = compile(file,
|
||||||
@ -157,6 +163,8 @@ RenderResult _renderSync(RenderOptions options) {
|
|||||||
useSpaces: options.indentType != 'tab',
|
useSpaces: options.indentType != 'tab',
|
||||||
indentWidth: _parseIndentWidth(options.indentWidth),
|
indentWidth: _parseIndentWidth(options.indentWidth),
|
||||||
lineFeed: _parseLineFeed(options.linefeed),
|
lineFeed: _parseLineFeed(options.linefeed),
|
||||||
|
quietDeps: options.quietDeps ?? false,
|
||||||
|
verbose: options.verbose ?? false,
|
||||||
sourceMap: _enableSourceMaps(options));
|
sourceMap: _enableSourceMaps(options));
|
||||||
} else {
|
} else {
|
||||||
throw ArgumentError("Either options.data or options.file must be set.");
|
throw ArgumentError("Either options.data or options.file must be set.");
|
||||||
|
@ -26,6 +26,8 @@ class RenderOptions {
|
|||||||
external bool? get sourceMapContents;
|
external bool? get sourceMapContents;
|
||||||
external bool? get sourceMapEmbed;
|
external bool? get sourceMapEmbed;
|
||||||
external String? get sourceMapRoot;
|
external String? get sourceMapRoot;
|
||||||
|
external bool? get quietDeps;
|
||||||
|
external bool? get verbose;
|
||||||
|
|
||||||
external factory RenderOptions(
|
external factory RenderOptions(
|
||||||
{String? file,
|
{String? file,
|
||||||
@ -44,5 +46,7 @@ class RenderOptions {
|
|||||||
Object? sourceMap,
|
Object? sourceMap,
|
||||||
bool? sourceMapContents,
|
bool? sourceMapContents,
|
||||||
bool? sourceMapEmbed,
|
bool? sourceMapEmbed,
|
||||||
String? sourceMapRoot});
|
String? sourceMapRoot,
|
||||||
|
bool? quietDeps,
|
||||||
|
bool? verbose});
|
||||||
}
|
}
|
||||||
|
@ -157,13 +157,7 @@ class _EvaluateVisitor
|
|||||||
/// consoles with redundant warnings.
|
/// consoles with redundant warnings.
|
||||||
final _warningsEmitted = <Tuple2<String, SourceSpan>>{};
|
final _warningsEmitted = <Tuple2<String, SourceSpan>>{};
|
||||||
|
|
||||||
// The importer from which the entrypoint stylesheet was loaded.
|
|
||||||
late final AsyncImporter? _originalImporter;
|
|
||||||
|
|
||||||
/// Whether to avoid emitting warnings for files loaded from dependencies.
|
/// Whether to avoid emitting warnings for files loaded from dependencies.
|
||||||
///
|
|
||||||
/// A "dependency" in this context is any stylesheet loaded through an
|
|
||||||
/// importer other than [_originalImporter].
|
|
||||||
final bool _quietDeps;
|
final bool _quietDeps;
|
||||||
|
|
||||||
/// Whether to track source map information.
|
/// Whether to track source map information.
|
||||||
@ -266,7 +260,7 @@ class _EvaluateVisitor
|
|||||||
///
|
///
|
||||||
/// A dependency is defined as a stylesheet imported by an importer other than
|
/// A dependency is defined as a stylesheet imported by an importer other than
|
||||||
/// the original. In Node importers, nothing is considered a dependency.
|
/// the original. In Node importers, nothing is considered a dependency.
|
||||||
bool get _inDependency => !_asNodeSass && _importer != _originalImporter;
|
var _inDependency = false;
|
||||||
|
|
||||||
/// The stylesheet that's currently being evaluated.
|
/// The stylesheet that's currently being evaluated.
|
||||||
Stylesheet get _stylesheet => _assertInModule(__stylesheet, "_stylesheet");
|
Stylesheet get _stylesheet => _assertInModule(__stylesheet, "_stylesheet");
|
||||||
@ -523,7 +517,6 @@ class _EvaluateVisitor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_originalImporter = importer;
|
|
||||||
var module = await _execute(importer, node);
|
var module = await _execute(importer, node);
|
||||||
|
|
||||||
return EvaluateResult(_combineCss(module), _includedFiles);
|
return EvaluateResult(_combineCss(module), _includedFiles);
|
||||||
@ -620,8 +613,7 @@ class _EvaluateVisitor
|
|||||||
await _withStackFrame(stackFrame, nodeWithSpan, () async {
|
await _withStackFrame(stackFrame, nodeWithSpan, () async {
|
||||||
var result = await _loadStylesheet(url.toString(), nodeWithSpan.span,
|
var result = await _loadStylesheet(url.toString(), nodeWithSpan.span,
|
||||||
baseUrl: baseUrl);
|
baseUrl: baseUrl);
|
||||||
var importer = result.item1;
|
var stylesheet = result.stylesheet;
|
||||||
var stylesheet = result.item2;
|
|
||||||
|
|
||||||
var canonicalUrl = stylesheet.span.sourceUrl;
|
var canonicalUrl = stylesheet.span.sourceUrl;
|
||||||
if (canonicalUrl != null && _activeModules.containsKey(canonicalUrl)) {
|
if (canonicalUrl != null && _activeModules.containsKey(canonicalUrl)) {
|
||||||
@ -637,14 +629,17 @@ class _EvaluateVisitor
|
|||||||
}
|
}
|
||||||
if (canonicalUrl != null) _activeModules[canonicalUrl] = nodeWithSpan;
|
if (canonicalUrl != null) _activeModules[canonicalUrl] = nodeWithSpan;
|
||||||
|
|
||||||
|
var oldInDependency = _inDependency;
|
||||||
|
_inDependency = result.isDependency;
|
||||||
Module module;
|
Module module;
|
||||||
try {
|
try {
|
||||||
module = await _execute(importer, stylesheet,
|
module = await _execute(result.importer, stylesheet,
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
nodeWithSpan: nodeWithSpan,
|
nodeWithSpan: nodeWithSpan,
|
||||||
namesInErrors: namesInErrors);
|
namesInErrors: namesInErrors);
|
||||||
} finally {
|
} finally {
|
||||||
_activeModules.remove(canonicalUrl);
|
_activeModules.remove(canonicalUrl);
|
||||||
|
_inDependency = oldInDependency;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1465,8 +1460,7 @@ class _EvaluateVisitor
|
|||||||
return _withStackFrame("@import", import, () async {
|
return _withStackFrame("@import", import, () async {
|
||||||
var result =
|
var result =
|
||||||
await _loadStylesheet(import.url, import.span, forImport: true);
|
await _loadStylesheet(import.url, import.span, forImport: true);
|
||||||
var importer = result.item1;
|
var stylesheet = result.stylesheet;
|
||||||
var stylesheet = result.item2;
|
|
||||||
|
|
||||||
var url = stylesheet.span.sourceUrl;
|
var url = stylesheet.span.sourceUrl;
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
@ -1486,7 +1480,7 @@ class _EvaluateVisitor
|
|||||||
if (stylesheet.uses.isEmpty && stylesheet.forwards.isEmpty) {
|
if (stylesheet.uses.isEmpty && stylesheet.forwards.isEmpty) {
|
||||||
var oldImporter = _importer;
|
var oldImporter = _importer;
|
||||||
var oldStylesheet = _stylesheet;
|
var oldStylesheet = _stylesheet;
|
||||||
_importer = importer;
|
_importer = result.importer;
|
||||||
_stylesheet = stylesheet;
|
_stylesheet = stylesheet;
|
||||||
await visitStylesheet(stylesheet);
|
await visitStylesheet(stylesheet);
|
||||||
_importer = oldImporter;
|
_importer = oldImporter;
|
||||||
@ -1505,12 +1499,14 @@ class _EvaluateVisitor
|
|||||||
var oldEndOfImports = _endOfImports;
|
var oldEndOfImports = _endOfImports;
|
||||||
var oldOutOfOrderImports = _outOfOrderImports;
|
var oldOutOfOrderImports = _outOfOrderImports;
|
||||||
var oldConfiguration = _configuration;
|
var oldConfiguration = _configuration;
|
||||||
_importer = importer;
|
var oldInDependency = _inDependency;
|
||||||
|
_importer = result.importer;
|
||||||
_stylesheet = stylesheet;
|
_stylesheet = stylesheet;
|
||||||
_root = ModifiableCssStylesheet(stylesheet.span);
|
_root = ModifiableCssStylesheet(stylesheet.span);
|
||||||
_parent = _root;
|
_parent = _root;
|
||||||
_endOfImports = 0;
|
_endOfImports = 0;
|
||||||
_outOfOrderImports = null;
|
_outOfOrderImports = null;
|
||||||
|
_inDependency = result.isDependency;
|
||||||
|
|
||||||
// This configuration is only used if it passes through a `@forward`
|
// This configuration is only used if it passes through a `@forward`
|
||||||
// rule, so we avoid creating unnecessary ones for performance reasons.
|
// rule, so we avoid creating unnecessary ones for performance reasons.
|
||||||
@ -1528,6 +1524,7 @@ class _EvaluateVisitor
|
|||||||
_endOfImports = oldEndOfImports;
|
_endOfImports = oldEndOfImports;
|
||||||
_outOfOrderImports = oldOutOfOrderImports;
|
_outOfOrderImports = oldOutOfOrderImports;
|
||||||
_configuration = oldConfiguration;
|
_configuration = oldConfiguration;
|
||||||
|
_inDependency = oldInDependency;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a dummy module with empty CSS and no extensions to make forwarded
|
// Create a dummy module with empty CSS and no extensions to make forwarded
|
||||||
@ -1559,8 +1556,7 @@ class _EvaluateVisitor
|
|||||||
///
|
///
|
||||||
/// This first tries loading [url] relative to [baseUrl], which defaults to
|
/// This first tries loading [url] relative to [baseUrl], which defaults to
|
||||||
/// `_stylesheet.span.sourceUrl`.
|
/// `_stylesheet.span.sourceUrl`.
|
||||||
Future<Tuple2<AsyncImporter?, Stylesheet>> _loadStylesheet(
|
Future<_LoadedStylesheet> _loadStylesheet(String url, FileSpan span,
|
||||||
String url, FileSpan span,
|
|
||||||
{Uri? baseUrl, bool forImport = false}) async {
|
{Uri? baseUrl, bool forImport = false}) async {
|
||||||
try {
|
try {
|
||||||
assert(_importSpan == null);
|
assert(_importSpan == null);
|
||||||
@ -1568,21 +1564,23 @@ class _EvaluateVisitor
|
|||||||
|
|
||||||
var importCache = _importCache;
|
var importCache = _importCache;
|
||||||
if (importCache != null) {
|
if (importCache != null) {
|
||||||
|
baseUrl ??= _stylesheet.span.sourceUrl;
|
||||||
var tuple = await importCache.canonicalize(Uri.parse(url),
|
var tuple = await importCache.canonicalize(Uri.parse(url),
|
||||||
baseImporter: _importer,
|
baseImporter: _importer, baseUrl: baseUrl, forImport: forImport);
|
||||||
baseUrl: baseUrl ?? _stylesheet.span.sourceUrl,
|
|
||||||
forImport: forImport);
|
|
||||||
|
|
||||||
if (tuple != null) {
|
if (tuple != null) {
|
||||||
|
var isDependency = _inDependency || tuple.item1 != _importer;
|
||||||
var stylesheet = await importCache.importCanonical(
|
var stylesheet = await importCache.importCanonical(
|
||||||
tuple.item1, tuple.item2,
|
tuple.item1, tuple.item2,
|
||||||
originalUrl: tuple.item3,
|
originalUrl: tuple.item3, quiet: _quietDeps && isDependency);
|
||||||
quiet: _quietDeps && tuple.item1 != _originalImporter);
|
if (stylesheet != null) {
|
||||||
if (stylesheet != null) return Tuple2(tuple.item1, stylesheet);
|
return _LoadedStylesheet(stylesheet,
|
||||||
|
importer: tuple.item1, isDependency: isDependency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var stylesheet = await _importLikeNode(url, forImport);
|
var result = await _importLikeNode(url, forImport);
|
||||||
if (stylesheet != null) return Tuple2(null, stylesheet);
|
if (result != null) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.startsWith('package:') && isNode) {
|
if (url.startsWith('package:') && isNode) {
|
||||||
@ -1610,20 +1608,32 @@ class _EvaluateVisitor
|
|||||||
/// Imports a stylesheet using [_nodeImporter].
|
/// Imports a stylesheet using [_nodeImporter].
|
||||||
///
|
///
|
||||||
/// Returns the [Stylesheet], or `null` if the import failed.
|
/// Returns the [Stylesheet], or `null` if the import failed.
|
||||||
Future<Stylesheet?> _importLikeNode(
|
Future<_LoadedStylesheet?> _importLikeNode(
|
||||||
String originalUrl, bool forImport) async {
|
String originalUrl, bool forImport) async {
|
||||||
var result = await _nodeImporter!
|
var result = _nodeImporter!
|
||||||
.loadAsync(originalUrl, _stylesheet.span.sourceUrl, forImport);
|
.loadRelative(originalUrl, _stylesheet.span.sourceUrl, forImport);
|
||||||
if (result == null) return null;
|
|
||||||
|
bool isDependency;
|
||||||
|
if (result != null) {
|
||||||
|
isDependency = _inDependency;
|
||||||
|
} else {
|
||||||
|
result = await _nodeImporter!
|
||||||
|
.loadAsync(originalUrl, _stylesheet.span.sourceUrl, forImport);
|
||||||
|
if (result == null) return null;
|
||||||
|
isDependency = true;
|
||||||
|
}
|
||||||
|
|
||||||
var contents = result.item1;
|
var contents = result.item1;
|
||||||
var url = result.item2;
|
var url = result.item2;
|
||||||
|
|
||||||
_includedFiles.add(url.startsWith('file:') ? p.fromUri(url) : url);
|
_includedFiles.add(url.startsWith('file:') ? p.fromUri(url) : url);
|
||||||
|
|
||||||
return Stylesheet.parse(
|
return _LoadedStylesheet(
|
||||||
contents, url.startsWith('file') ? Syntax.forPath(url) : Syntax.scss,
|
Stylesheet.parse(contents,
|
||||||
url: url, logger: _logger);
|
url.startsWith('file') ? Syntax.forPath(url) : Syntax.scss,
|
||||||
|
url: url,
|
||||||
|
logger: _quietDeps && isDependency ? Logger.quiet : _logger),
|
||||||
|
isDependency: isDependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a CSS import for [import].
|
/// Adds a CSS import for [import].
|
||||||
@ -3341,3 +3351,23 @@ class _ArgumentResults {
|
|||||||
_ArgumentResults(this.positional, this.positionalNodes, this.named,
|
_ArgumentResults(this.positional, this.positionalNodes, this.named,
|
||||||
this.namedNodes, this.separator);
|
this.namedNodes, this.separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of loading a stylesheet via [AsyncEvaluator._loadStylesheet].
|
||||||
|
class _LoadedStylesheet {
|
||||||
|
/// The stylesheet itself.
|
||||||
|
final Stylesheet stylesheet;
|
||||||
|
|
||||||
|
/// The importer that was used to load the stylesheet.
|
||||||
|
///
|
||||||
|
/// This is `null` when running in Node Sass compatibility mode.
|
||||||
|
final AsyncImporter? importer;
|
||||||
|
|
||||||
|
/// Whether this load counts as a dependency.
|
||||||
|
///
|
||||||
|
/// That is, whether this was (transitively) loaded through a load path or
|
||||||
|
/// importer rather than relative to the entrypoint.
|
||||||
|
final bool isDependency;
|
||||||
|
|
||||||
|
_LoadedStylesheet(this.stylesheet,
|
||||||
|
{this.importer, required this.isDependency});
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// DO NOT EDIT. This file was generated from async_evaluate.dart.
|
// DO NOT EDIT. This file was generated from async_evaluate.dart.
|
||||||
// See tool/grind/synchronize.dart for details.
|
// See tool/grind/synchronize.dart for details.
|
||||||
//
|
//
|
||||||
// Checksum: 24b9012f1cf8908b2cbde11cd10974113d4c8163
|
// Checksum: 203ba98fd9ca92ccc0b6465fd0d617e88c8dd37e
|
||||||
//
|
//
|
||||||
// ignore_for_file: unused_import
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
@ -165,13 +165,7 @@ class _EvaluateVisitor
|
|||||||
/// consoles with redundant warnings.
|
/// consoles with redundant warnings.
|
||||||
final _warningsEmitted = <Tuple2<String, SourceSpan>>{};
|
final _warningsEmitted = <Tuple2<String, SourceSpan>>{};
|
||||||
|
|
||||||
// The importer from which the entrypoint stylesheet was loaded.
|
|
||||||
late final Importer? _originalImporter;
|
|
||||||
|
|
||||||
/// Whether to avoid emitting warnings for files loaded from dependencies.
|
/// Whether to avoid emitting warnings for files loaded from dependencies.
|
||||||
///
|
|
||||||
/// A "dependency" in this context is any stylesheet loaded through an
|
|
||||||
/// importer other than [_originalImporter].
|
|
||||||
final bool _quietDeps;
|
final bool _quietDeps;
|
||||||
|
|
||||||
/// Whether to track source map information.
|
/// Whether to track source map information.
|
||||||
@ -274,7 +268,7 @@ class _EvaluateVisitor
|
|||||||
///
|
///
|
||||||
/// A dependency is defined as a stylesheet imported by an importer other than
|
/// A dependency is defined as a stylesheet imported by an importer other than
|
||||||
/// the original. In Node importers, nothing is considered a dependency.
|
/// the original. In Node importers, nothing is considered a dependency.
|
||||||
bool get _inDependency => !_asNodeSass && _importer != _originalImporter;
|
var _inDependency = false;
|
||||||
|
|
||||||
/// The stylesheet that's currently being evaluated.
|
/// The stylesheet that's currently being evaluated.
|
||||||
Stylesheet get _stylesheet => _assertInModule(__stylesheet, "_stylesheet");
|
Stylesheet get _stylesheet => _assertInModule(__stylesheet, "_stylesheet");
|
||||||
@ -528,7 +522,6 @@ class _EvaluateVisitor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_originalImporter = importer;
|
|
||||||
var module = _execute(importer, node);
|
var module = _execute(importer, node);
|
||||||
|
|
||||||
return EvaluateResult(_combineCss(module), _includedFiles);
|
return EvaluateResult(_combineCss(module), _includedFiles);
|
||||||
@ -625,8 +618,7 @@ class _EvaluateVisitor
|
|||||||
_withStackFrame(stackFrame, nodeWithSpan, () {
|
_withStackFrame(stackFrame, nodeWithSpan, () {
|
||||||
var result =
|
var result =
|
||||||
_loadStylesheet(url.toString(), nodeWithSpan.span, baseUrl: baseUrl);
|
_loadStylesheet(url.toString(), nodeWithSpan.span, baseUrl: baseUrl);
|
||||||
var importer = result.item1;
|
var stylesheet = result.stylesheet;
|
||||||
var stylesheet = result.item2;
|
|
||||||
|
|
||||||
var canonicalUrl = stylesheet.span.sourceUrl;
|
var canonicalUrl = stylesheet.span.sourceUrl;
|
||||||
if (canonicalUrl != null && _activeModules.containsKey(canonicalUrl)) {
|
if (canonicalUrl != null && _activeModules.containsKey(canonicalUrl)) {
|
||||||
@ -642,14 +634,17 @@ class _EvaluateVisitor
|
|||||||
}
|
}
|
||||||
if (canonicalUrl != null) _activeModules[canonicalUrl] = nodeWithSpan;
|
if (canonicalUrl != null) _activeModules[canonicalUrl] = nodeWithSpan;
|
||||||
|
|
||||||
|
var oldInDependency = _inDependency;
|
||||||
|
_inDependency = result.isDependency;
|
||||||
Module<Callable> module;
|
Module<Callable> module;
|
||||||
try {
|
try {
|
||||||
module = _execute(importer, stylesheet,
|
module = _execute(result.importer, stylesheet,
|
||||||
configuration: configuration,
|
configuration: configuration,
|
||||||
nodeWithSpan: nodeWithSpan,
|
nodeWithSpan: nodeWithSpan,
|
||||||
namesInErrors: namesInErrors);
|
namesInErrors: namesInErrors);
|
||||||
} finally {
|
} finally {
|
||||||
_activeModules.remove(canonicalUrl);
|
_activeModules.remove(canonicalUrl);
|
||||||
|
_inDependency = oldInDependency;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1464,8 +1459,7 @@ class _EvaluateVisitor
|
|||||||
void _visitDynamicImport(DynamicImport import) {
|
void _visitDynamicImport(DynamicImport import) {
|
||||||
return _withStackFrame("@import", import, () {
|
return _withStackFrame("@import", import, () {
|
||||||
var result = _loadStylesheet(import.url, import.span, forImport: true);
|
var result = _loadStylesheet(import.url, import.span, forImport: true);
|
||||||
var importer = result.item1;
|
var stylesheet = result.stylesheet;
|
||||||
var stylesheet = result.item2;
|
|
||||||
|
|
||||||
var url = stylesheet.span.sourceUrl;
|
var url = stylesheet.span.sourceUrl;
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
@ -1485,7 +1479,7 @@ class _EvaluateVisitor
|
|||||||
if (stylesheet.uses.isEmpty && stylesheet.forwards.isEmpty) {
|
if (stylesheet.uses.isEmpty && stylesheet.forwards.isEmpty) {
|
||||||
var oldImporter = _importer;
|
var oldImporter = _importer;
|
||||||
var oldStylesheet = _stylesheet;
|
var oldStylesheet = _stylesheet;
|
||||||
_importer = importer;
|
_importer = result.importer;
|
||||||
_stylesheet = stylesheet;
|
_stylesheet = stylesheet;
|
||||||
visitStylesheet(stylesheet);
|
visitStylesheet(stylesheet);
|
||||||
_importer = oldImporter;
|
_importer = oldImporter;
|
||||||
@ -1504,12 +1498,14 @@ class _EvaluateVisitor
|
|||||||
var oldEndOfImports = _endOfImports;
|
var oldEndOfImports = _endOfImports;
|
||||||
var oldOutOfOrderImports = _outOfOrderImports;
|
var oldOutOfOrderImports = _outOfOrderImports;
|
||||||
var oldConfiguration = _configuration;
|
var oldConfiguration = _configuration;
|
||||||
_importer = importer;
|
var oldInDependency = _inDependency;
|
||||||
|
_importer = result.importer;
|
||||||
_stylesheet = stylesheet;
|
_stylesheet = stylesheet;
|
||||||
_root = ModifiableCssStylesheet(stylesheet.span);
|
_root = ModifiableCssStylesheet(stylesheet.span);
|
||||||
_parent = _root;
|
_parent = _root;
|
||||||
_endOfImports = 0;
|
_endOfImports = 0;
|
||||||
_outOfOrderImports = null;
|
_outOfOrderImports = null;
|
||||||
|
_inDependency = result.isDependency;
|
||||||
|
|
||||||
// This configuration is only used if it passes through a `@forward`
|
// This configuration is only used if it passes through a `@forward`
|
||||||
// rule, so we avoid creating unnecessary ones for performance reasons.
|
// rule, so we avoid creating unnecessary ones for performance reasons.
|
||||||
@ -1527,6 +1523,7 @@ class _EvaluateVisitor
|
|||||||
_endOfImports = oldEndOfImports;
|
_endOfImports = oldEndOfImports;
|
||||||
_outOfOrderImports = oldOutOfOrderImports;
|
_outOfOrderImports = oldOutOfOrderImports;
|
||||||
_configuration = oldConfiguration;
|
_configuration = oldConfiguration;
|
||||||
|
_inDependency = oldInDependency;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a dummy module with empty CSS and no extensions to make forwarded
|
// Create a dummy module with empty CSS and no extensions to make forwarded
|
||||||
@ -1558,7 +1555,7 @@ class _EvaluateVisitor
|
|||||||
///
|
///
|
||||||
/// This first tries loading [url] relative to [baseUrl], which defaults to
|
/// This first tries loading [url] relative to [baseUrl], which defaults to
|
||||||
/// `_stylesheet.span.sourceUrl`.
|
/// `_stylesheet.span.sourceUrl`.
|
||||||
Tuple2<Importer?, Stylesheet> _loadStylesheet(String url, FileSpan span,
|
_LoadedStylesheet _loadStylesheet(String url, FileSpan span,
|
||||||
{Uri? baseUrl, bool forImport = false}) {
|
{Uri? baseUrl, bool forImport = false}) {
|
||||||
try {
|
try {
|
||||||
assert(_importSpan == null);
|
assert(_importSpan == null);
|
||||||
@ -1566,20 +1563,22 @@ class _EvaluateVisitor
|
|||||||
|
|
||||||
var importCache = _importCache;
|
var importCache = _importCache;
|
||||||
if (importCache != null) {
|
if (importCache != null) {
|
||||||
|
baseUrl ??= _stylesheet.span.sourceUrl;
|
||||||
var tuple = importCache.canonicalize(Uri.parse(url),
|
var tuple = importCache.canonicalize(Uri.parse(url),
|
||||||
baseImporter: _importer,
|
baseImporter: _importer, baseUrl: baseUrl, forImport: forImport);
|
||||||
baseUrl: baseUrl ?? _stylesheet.span.sourceUrl,
|
|
||||||
forImport: forImport);
|
|
||||||
|
|
||||||
if (tuple != null) {
|
if (tuple != null) {
|
||||||
|
var isDependency = _inDependency || tuple.item1 != _importer;
|
||||||
var stylesheet = importCache.importCanonical(tuple.item1, tuple.item2,
|
var stylesheet = importCache.importCanonical(tuple.item1, tuple.item2,
|
||||||
originalUrl: tuple.item3,
|
originalUrl: tuple.item3, quiet: _quietDeps && isDependency);
|
||||||
quiet: _quietDeps && tuple.item1 != _originalImporter);
|
if (stylesheet != null) {
|
||||||
if (stylesheet != null) return Tuple2(tuple.item1, stylesheet);
|
return _LoadedStylesheet(stylesheet,
|
||||||
|
importer: tuple.item1, isDependency: isDependency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var stylesheet = _importLikeNode(url, forImport);
|
var result = _importLikeNode(url, forImport);
|
||||||
if (stylesheet != null) return Tuple2(null, stylesheet);
|
if (result != null) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.startsWith('package:') && isNode) {
|
if (url.startsWith('package:') && isNode) {
|
||||||
@ -1607,19 +1606,31 @@ class _EvaluateVisitor
|
|||||||
/// Imports a stylesheet using [_nodeImporter].
|
/// Imports a stylesheet using [_nodeImporter].
|
||||||
///
|
///
|
||||||
/// Returns the [Stylesheet], or `null` if the import failed.
|
/// Returns the [Stylesheet], or `null` if the import failed.
|
||||||
Stylesheet? _importLikeNode(String originalUrl, bool forImport) {
|
_LoadedStylesheet? _importLikeNode(String originalUrl, bool forImport) {
|
||||||
var result =
|
var result = _nodeImporter!
|
||||||
_nodeImporter!.load(originalUrl, _stylesheet.span.sourceUrl, forImport);
|
.loadRelative(originalUrl, _stylesheet.span.sourceUrl, forImport);
|
||||||
if (result == null) return null;
|
|
||||||
|
bool isDependency;
|
||||||
|
if (result != null) {
|
||||||
|
isDependency = _inDependency;
|
||||||
|
} else {
|
||||||
|
result = _nodeImporter!
|
||||||
|
.load(originalUrl, _stylesheet.span.sourceUrl, forImport);
|
||||||
|
if (result == null) return null;
|
||||||
|
isDependency = true;
|
||||||
|
}
|
||||||
|
|
||||||
var contents = result.item1;
|
var contents = result.item1;
|
||||||
var url = result.item2;
|
var url = result.item2;
|
||||||
|
|
||||||
_includedFiles.add(url.startsWith('file:') ? p.fromUri(url) : url);
|
_includedFiles.add(url.startsWith('file:') ? p.fromUri(url) : url);
|
||||||
|
|
||||||
return Stylesheet.parse(
|
return _LoadedStylesheet(
|
||||||
contents, url.startsWith('file') ? Syntax.forPath(url) : Syntax.scss,
|
Stylesheet.parse(contents,
|
||||||
url: url, logger: _logger);
|
url.startsWith('file') ? Syntax.forPath(url) : Syntax.scss,
|
||||||
|
url: url,
|
||||||
|
logger: _quietDeps && isDependency ? Logger.quiet : _logger),
|
||||||
|
isDependency: isDependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a CSS import for [import].
|
/// Adds a CSS import for [import].
|
||||||
@ -3278,3 +3289,23 @@ class _ArgumentResults {
|
|||||||
_ArgumentResults(this.positional, this.positionalNodes, this.named,
|
_ArgumentResults(this.positional, this.positionalNodes, this.named,
|
||||||
this.namedNodes, this.separator);
|
this.namedNodes, this.separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of loading a stylesheet via [Evaluator._loadStylesheet].
|
||||||
|
class _LoadedStylesheet {
|
||||||
|
/// The stylesheet itself.
|
||||||
|
final Stylesheet stylesheet;
|
||||||
|
|
||||||
|
/// The importer that was used to load the stylesheet.
|
||||||
|
///
|
||||||
|
/// This is `null` when running in Node Sass compatibility mode.
|
||||||
|
final Importer? importer;
|
||||||
|
|
||||||
|
/// Whether this load counts as a dependency.
|
||||||
|
///
|
||||||
|
/// That is, whether this was (transitively) loaded through a load path or
|
||||||
|
/// importer rather than relative to the entrypoint.
|
||||||
|
final bool isDependency;
|
||||||
|
|
||||||
|
_LoadedStylesheet(this.stylesheet,
|
||||||
|
{this.importer, required this.isDependency});
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name: sass
|
name: sass
|
||||||
version: 1.34.2-dev
|
version: 1.35.0
|
||||||
description: A Sass implementation in Dart.
|
description: A Sass implementation in Dart.
|
||||||
author: Sass Team
|
author: Sass Team
|
||||||
homepage: https://github.com/sass/dart-sass
|
homepage: https://github.com/sass/dart-sass
|
||||||
|
@ -264,6 +264,171 @@ a {
|
|||||||
renderSync(RenderOptions(data: "@debug 'what the heck'")), isEmpty);
|
renderSync(RenderOptions(data: "@debug 'what the heck'")), isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group("with quietDeps", () {
|
||||||
|
group("in a relative load from the entrypoint", () {
|
||||||
|
test("emits @warn", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await writeTextFile(p.join(sandbox, "_other.scss"), "@warn heck");
|
||||||
|
|
||||||
|
expect(const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsThrough(contains("heck")));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"), quietDeps: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("emits @debug", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await writeTextFile(p.join(sandbox, "_other.scss"), "@debug heck");
|
||||||
|
|
||||||
|
expect(const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsThrough(contains("heck")));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"), quietDeps: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("emits parser warnings", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await writeTextFile(p.join(sandbox, "_other.scss"), "a {b: c && d}");
|
||||||
|
|
||||||
|
expect(const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsThrough(contains("&&")));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"), quietDeps: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("emits runner warnings", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await writeTextFile(p.join(sandbox, "_other.scss"), "#{blue} {x: y}");
|
||||||
|
|
||||||
|
expect(const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsThrough(contains("blue")));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"), quietDeps: true));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group("in a load path load", () {
|
||||||
|
test("emits @warn", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await createDirectory(p.join(sandbox, "dir"));
|
||||||
|
await writeTextFile(
|
||||||
|
p.join(sandbox, "dir", "_other.scss"), "@warn heck");
|
||||||
|
|
||||||
|
expect(const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsThrough(contains("heck")));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"),
|
||||||
|
includePaths: [p.join(sandbox, "dir")],
|
||||||
|
quietDeps: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("emits @debug", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await createDirectory(p.join(sandbox, "dir"));
|
||||||
|
await writeTextFile(
|
||||||
|
p.join(sandbox, "dir", "_other.scss"), "@debug heck");
|
||||||
|
|
||||||
|
expect(const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsThrough(contains("heck")));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"),
|
||||||
|
includePaths: [p.join(sandbox, "dir")],
|
||||||
|
quietDeps: true));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("doesn't emit parser warnings", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await createDirectory(p.join(sandbox, "dir"));
|
||||||
|
await writeTextFile(
|
||||||
|
p.join(sandbox, "dir", "_other.scss"), "a {b: c && d}");
|
||||||
|
|
||||||
|
// No stderr should be printed at all.
|
||||||
|
const LineSplitter()
|
||||||
|
.bind(interceptStderr())
|
||||||
|
.listen(expectAsync1((_) {}, count: 0));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"),
|
||||||
|
includePaths: [p.join(sandbox, "dir")],
|
||||||
|
quietDeps: true));
|
||||||
|
|
||||||
|
// Give stderr a chance to be piped through if it's going to be.
|
||||||
|
await pumpEventQueue();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("doesn't emit runner warnings", () async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), "@use 'other'");
|
||||||
|
await createDirectory(p.join(sandbox, "dir"));
|
||||||
|
await writeTextFile(
|
||||||
|
p.join(sandbox, "dir", "_other.scss"), "#{blue} {x: y}");
|
||||||
|
|
||||||
|
// No stderr should be printed at all.
|
||||||
|
const LineSplitter()
|
||||||
|
.bind(interceptStderr())
|
||||||
|
.listen(expectAsync1((_) {}, count: 0));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(
|
||||||
|
file: p.join(sandbox, "test.scss"),
|
||||||
|
includePaths: [p.join(sandbox, "dir")],
|
||||||
|
quietDeps: true));
|
||||||
|
|
||||||
|
// Give stderr a chance to be piped through if it's going to be.
|
||||||
|
await pumpEventQueue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group("with a bunch of deprecation warnings", () {
|
||||||
|
setUp(() async {
|
||||||
|
await writeTextFile(p.join(sandbox, "test.scss"), r"""
|
||||||
|
$_: call("inspect", null);
|
||||||
|
$_: call("rgb", 0, 0, 0);
|
||||||
|
$_: call("nth", null, 1);
|
||||||
|
$_: call("join", null, null);
|
||||||
|
$_: call("if", true, 1, 2);
|
||||||
|
$_: call("hsl", 0, 100%, 100%);
|
||||||
|
|
||||||
|
$_: 1/2;
|
||||||
|
$_: 1/3;
|
||||||
|
$_: 1/4;
|
||||||
|
$_: 1/5;
|
||||||
|
$_: 1/6;
|
||||||
|
$_: 1/7;
|
||||||
|
""");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("without --verbose, only prints five", () async {
|
||||||
|
expect(
|
||||||
|
const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsInOrder([
|
||||||
|
...List.filled(5, emitsThrough(contains("call()"))),
|
||||||
|
...List.filled(5, emitsThrough(contains("math.div"))),
|
||||||
|
emitsThrough(
|
||||||
|
contains("2 repetitive deprecation warnings omitted."))
|
||||||
|
]));
|
||||||
|
|
||||||
|
renderSync(RenderOptions(file: p.join(sandbox, "test.scss")));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("with --verbose, prints all", () async {
|
||||||
|
expect(
|
||||||
|
const LineSplitter().bind(interceptStderr()),
|
||||||
|
emitsInOrder([
|
||||||
|
...List.filled(6, emitsThrough(contains("call()"))),
|
||||||
|
...List.filled(6, emitsThrough(contains("math.div")))
|
||||||
|
]));
|
||||||
|
|
||||||
|
renderSync(
|
||||||
|
RenderOptions(file: p.join(sandbox, "test.scss"), verbose: true));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
group("with both data and file", () {
|
group("with both data and file", () {
|
||||||
test("uses the data parameter as the source", () {
|
test("uses the data parameter as the source", () {
|
||||||
expect(renderSync(RenderOptions(data: "x {y: z}", file: sassPath)),
|
expect(renderSync(RenderOptions(data: "x {y: z}", file: sassPath)),
|
||||||
|
Loading…
Reference in New Issue
Block a user