@@ -8,6 +8,7 @@ import '../../exception.dart';
8
8
import '../../logger.dart' ;
9
9
import '../../parse/scss.dart' ;
10
10
import '../../utils.dart' ;
11
+ import '../../util/character.dart' ;
11
12
import 'argument.dart' ;
12
13
import 'node.dart' ;
13
14
@@ -22,6 +23,32 @@ class ArgumentDeclaration implements SassNode {
22
23
23
24
final FileSpan span;
24
25
26
+ /// Returns [span] expanded to include an identifier immediately before the
27
+ /// declaration, if possible.
28
+ FileSpan get spanWithName {
29
+ var text = span.file.getText (0 );
30
+
31
+ // Move backwards through and whitspace between the name and the arguments.
32
+ var i = span.start.offset - 1 ;
33
+ while (i > 0 && isWhitespace (text.codeUnitAt (i))) {
34
+ i-- ;
35
+ }
36
+
37
+ // Then move backwards through the name itself.
38
+ if (! isName (text.codeUnitAt (i))) return span;
39
+ i-- ;
40
+ while (i >= 0 && isName (text.codeUnitAt (i))) {
41
+ i-- ;
42
+ }
43
+
44
+ // If the name didn't start with [isNameStart], it's not a valid identifier.
45
+ if (! isNameStart (text.codeUnitAt (i + 1 ))) return span;
46
+
47
+ // Trim because it's possible that this span is empty (for example, a mixin
48
+ // may be declared without an argument list).
49
+ return span.file.span (i + 1 , span.end.offset).trim ();
50
+ }
51
+
25
52
/// The name of the rest argument as written in the document, without
26
53
/// underscores converted to hyphens and including the leading `$` .
27
54
///
@@ -47,16 +74,15 @@ class ArgumentDeclaration implements SassNode {
47
74
: arguments = const [],
48
75
restArgument = null ;
49
76
50
- /// Parses an argument declaration from [contents] , which should not include
51
- /// parentheses .
77
+ /// Parses an argument declaration from [contents] , which should be of the
78
+ /// form `@rule name(args) {` .
52
79
///
53
80
/// If passed, [url] is the name of the file from which [contents] comes.
54
81
///
55
82
/// Throws a [SassFormatException] if parsing fails.
56
83
factory ArgumentDeclaration .parse (String contents,
57
84
{Object url, Logger logger}) =>
58
- ScssParser ("($contents )" , url: url, logger: logger)
59
- .parseArgumentDeclaration ();
85
+ ScssParser (contents, url: url, logger: logger).parseArgumentDeclaration ();
60
86
61
87
/// Throws a [SassScriptException] if [positional] and [names] aren't valid
62
88
/// for this argument declaration.
@@ -73,27 +99,34 @@ class ArgumentDeclaration implements SassNode {
73
99
} else if (names.contains (argument.name)) {
74
100
namedUsed++ ;
75
101
} else if (argument.defaultValue == null ) {
76
- throw SassScriptException (
77
- "Missing argument ${_originalArgumentName (argument .name )}." );
102
+ throw MultiSpanSassScriptException (
103
+ "Missing argument ${_originalArgumentName (argument .name )}." ,
104
+ "invocation" ,
105
+ {spanWithName: "declaration" });
78
106
}
79
107
}
80
108
81
109
if (restArgument != null ) return ;
82
110
83
111
if (positional > arguments.length) {
84
- throw SassScriptException ("Only ${arguments .length } "
85
- "${names .isEmpty ? '' : 'positional ' }"
86
- "${pluralize ('argument' , arguments .length )} allowed, but "
87
- "${positional } ${pluralize ('was' , positional , plural : 'were' )} "
88
- "passed." );
112
+ throw MultiSpanSassScriptException (
113
+ "Only ${arguments .length } "
114
+ "${names .isEmpty ? '' : 'positional ' }"
115
+ "${pluralize ('argument' , arguments .length )} allowed, but "
116
+ "${positional } ${pluralize ('was' , positional , plural : 'were' )} "
117
+ "passed." ,
118
+ "invocation" ,
119
+ {spanWithName: "declaration" });
89
120
}
90
121
91
122
if (namedUsed < names.length) {
92
123
var unknownNames = Set .of (names)
93
124
..removeAll (arguments.map ((argument) => argument.name));
94
- throw SassScriptException (
125
+ throw MultiSpanSassScriptException (
95
126
"No ${pluralize ('argument' , unknownNames .length )} named "
96
- "${toSentence (unknownNames .map ((name ) => "\$ $name " ), 'or' )}." );
127
+ "${toSentence (unknownNames .map ((name ) => "\$ $name " ), 'or' )}." ,
128
+ "invocation" ,
129
+ {spanWithName: "declaration" });
97
130
}
98
131
}
99
132
0 commit comments