Skip to content

Commit 3d1dab3

Browse files
Awjinnex3
authored andcommitted
Print call-site for @errors in mixins and functions (#878)
For any @errors encountered in mixins or functions, use the call-site (instead of the @error rule) as the span printed in the error message. Closes #474 See sass/sass-spec#1494
1 parent c4b8932 commit 3d1dab3

File tree

5 files changed

+90
-6
lines changed

5 files changed

+90
-6
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 1.23.5
2+
3+
* When `@error` is used in a function or mixin, print the call site rather than
4+
the location of the `@error` itself to better match the behavior of calling a
5+
built-in function that throws an error.
6+
17
## 1.23.4
28

39
### Command-Line Interface

lib/src/visitor/async_evaluate.dart

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,7 +1469,7 @@ class _EvaluateVisitor
14691469
await _environment.withContent(contentCallable, () async {
14701470
await _environment.asMixin(() async {
14711471
for (var statement in mixin.declaration.children) {
1472-
await statement.accept(this);
1472+
await _addErrorSpan(node, () => statement.accept(this));
14731473
}
14741474
});
14751475
return null;
@@ -1983,7 +1983,8 @@ class _EvaluateVisitor
19831983

19841984
var oldInFunction = _inFunction;
19851985
_inFunction = true;
1986-
var result = await _runFunctionCallable(node.arguments, function, node);
1986+
var result = await _addErrorSpan(
1987+
node, () => _runFunctionCallable(node.arguments, function, node));
19871988
_inFunction = oldInFunction;
19881989
return result;
19891990
}
@@ -2853,6 +2854,19 @@ class _EvaluateVisitor
28532854
throw _exception(error.message, nodeWithSpan.span);
28542855
}
28552856
}
2857+
2858+
/// Runs [callback], and converts any [SassRuntimeException]s containing an
2859+
/// @error to throw a more relevant [SassRuntimeException] with [nodeWithSpan]'s
2860+
/// source span.
2861+
Future<T> _addErrorSpan<T>(AstNode nodeWithSpan, Future<T> callback()) async {
2862+
try {
2863+
return await callback();
2864+
} on SassRuntimeException catch (error) {
2865+
if (!error.span.text.startsWith("@error")) rethrow;
2866+
throw SassRuntimeException(
2867+
error.message, nodeWithSpan.span, _stackTrace());
2868+
}
2869+
}
28562870
}
28572871

28582872
/// A helper class for [_EvaluateVisitor] that adds `@import`ed CSS nodes to the

lib/src/visitor/evaluate.dart

Lines changed: 17 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_evaluate.dart.
66
// See tool/grind/synchronize.dart for details.
77
//
8-
// Checksum: 7bcd07f449d67c0f625de8e505a9c74cfed0b616
8+
// Checksum: 9617d2d08b71858db9228b0858f2f27f87a35bf7
99
//
1010
// ignore_for_file: unused_import
1111

@@ -1468,7 +1468,7 @@ class _EvaluateVisitor
14681468
_environment.withContent(contentCallable, () {
14691469
_environment.asMixin(() {
14701470
for (var statement in mixin.declaration.children) {
1471-
statement.accept(this);
1471+
_addErrorSpan(node, () => statement.accept(this));
14721472
}
14731473
});
14741474
return null;
@@ -1972,7 +1972,8 @@ class _EvaluateVisitor
19721972

19731973
var oldInFunction = _inFunction;
19741974
_inFunction = true;
1975-
var result = _runFunctionCallable(node.arguments, function, node);
1975+
var result = _addErrorSpan(
1976+
node, () => _runFunctionCallable(node.arguments, function, node));
19761977
_inFunction = oldInFunction;
19771978
return result;
19781979
}
@@ -2818,6 +2819,19 @@ class _EvaluateVisitor
28182819
throw _exception(error.message, nodeWithSpan.span);
28192820
}
28202821
}
2822+
2823+
/// Runs [callback], and converts any [SassRuntimeException]s containing an
2824+
/// @error to throw a more relevant [SassRuntimeException] with [nodeWithSpan]'s
2825+
/// source span.
2826+
T _addErrorSpan<T>(AstNode nodeWithSpan, T callback()) {
2827+
try {
2828+
return callback();
2829+
} on SassRuntimeException catch (error) {
2830+
if (!error.span.text.startsWith("@error")) rethrow;
2831+
throw SassRuntimeException(
2832+
error.message, nodeWithSpan.span, _stackTrace());
2833+
}
2834+
}
28212835
}
28222836

28232837
/// A helper class for [_EvaluateVisitor] that adds `@import`ed CSS nodes to the

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: sass
2-
version: 1.23.4
2+
version: 1.23.5-dev
33
description: A Sass implementation in Dart.
44
author: Sass Team
55
homepage: https://github.com/sass/dart-sass

test/cli/shared/errors.dart

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,56 @@ void sharedTests(Future<TestProcess> runSass(Iterable<String> arguments)) {
7272
await sass.shouldExit(65);
7373
});
7474

75+
test("from an error encountered within a function", () async {
76+
await d.file("test.scss", """
77+
@function a() {
78+
@error "Within A.";
79+
}
80+
81+
.b {
82+
c: a();
83+
}
84+
""").create();
85+
86+
var sass = await runSass(["--no-unicode", "test.scss"]);
87+
expect(
88+
sass.stderr,
89+
emitsInOrder([
90+
"Error: \"Within A.\"",
91+
" ,",
92+
"6 | c: a();",
93+
" | ^^^",
94+
" '",
95+
" test.scss 6:6 root stylesheet",
96+
]));
97+
await sass.shouldExit(65);
98+
});
99+
100+
test("from an error encountered within a mixin", () async {
101+
await d.file("test.scss", """
102+
@mixin a() {
103+
@error "Within A.";
104+
}
105+
106+
.b {
107+
@include a();
108+
}
109+
""").create();
110+
111+
var sass = await runSass(["--no-unicode", "test.scss"]);
112+
expect(
113+
sass.stderr,
114+
emitsInOrder([
115+
"Error: \"Within A.\"",
116+
" ,",
117+
"6 | @include a();",
118+
" | ^^^^^^^^^^^^",
119+
" '",
120+
" test.scss 6:3 root stylesheet",
121+
]));
122+
await sass.shouldExit(65);
123+
});
124+
75125
test("with colors with --color", () async {
76126
await d.file("test.scss", "a {b: }").create();
77127

0 commit comments

Comments
 (0)