Skip to content

Commit 44a1af5

Browse files
committed
Limit whitespace to after : and , for named args
1 parent dcc70af commit 44a1af5

File tree

3 files changed

+96
-22
lines changed

3 files changed

+96
-22
lines changed

v2/codetags/parser.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,17 +142,16 @@ func RawValues(enabled bool) ParseOption {
142142
}
143143
}
144144

145-
const (
146-
stTag = "stTag"
147-
stMaybeArgs = "stMaybeArgs"
148-
stArg = "stArg"
149-
stArgEndOfToken = "stArgEndOfToken"
150-
stMaybeValue = "stMaybeValue"
151-
stValue = "stValue"
152-
stMaybeComment = "stMaybeComment"
153-
)
154-
155145
func parseTag(input string, opts parseOpts) (Tag, error) {
146+
const (
147+
stTag = "stTag"
148+
stMaybeArgs = "stMaybeArgs"
149+
stArg = "stArg"
150+
stArgEndOfToken = "stArgEndOfToken"
151+
stMaybeValue = "stMaybeValue"
152+
stValue = "stValue"
153+
stMaybeComment = "stMaybeComment"
154+
)
156155
var startTag, endTag *Tag // both ends of the chain when parsing chained tags
157156

158157
// accumulators
@@ -216,7 +215,7 @@ func parseTag(input string, opts parseOpts) (Tag, error) {
216215
var err error
217216
st := stTag
218217
parseLoop:
219-
for r := s.skipWhitespacePeek(); r != EOF; r = s.skipWhitespacePeek() {
218+
for r := s.peek(); r != EOF; r = s.peek() {
220219
switch st {
221220
case stTag:
222221
switch {
@@ -276,10 +275,14 @@ parseLoop:
276275

277276
switch {
278277
case r == ',' || r == ')': // positional arg
278+
if r == ',' {
279+
r = s.skipWhitespace() // allow whitespace after ,
280+
}
279281
saveBoolOrString(identifier)
280282
st = stArgEndOfToken
281283
case r == ':': // named arg
282-
s.next() // consume :
284+
s.next() // consume :
285+
r = s.skipWhitespace() // allow whitespace after :
283286
saveName(identifier)
284287
st = stArg
285288
default:
@@ -291,7 +294,8 @@ parseLoop:
291294
case stArgEndOfToken:
292295
switch {
293296
case r == ',':
294-
s.next() // consume ,
297+
s.next() // consume ,
298+
r = s.skipWhitespace() // allow whitespace after ,
295299
st = stArg
296300
case r == ')':
297301
s.next() // consume )
@@ -363,7 +367,7 @@ parseLoop:
363367
}
364368
case stMaybeComment:
365369
switch {
366-
case r == '/' && s.peekN(1) == '/':
370+
case s.nextIsTrailingComment():
367371
s.remainder()
368372
default:
369373
break parseLoop

v2/codetags/parser_test.go

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ func TestParse(t *testing.T) {
6767
input: "name // comment",
6868
expect: mkt("name"),
6969
},
70+
{
71+
name: "name with comment after extra spaces",
72+
input: "name \t // comment",
73+
expect: mkt("name"),
74+
},
7075
{
7176
name: "name with dash",
7277
input: "name-dash",
@@ -89,6 +94,16 @@ func TestParse(t *testing.T) {
8994
input: "name=",
9095
wantError: "unexpected end of input",
9196
},
97+
{
98+
name: "space before =",
99+
input: "name =x",
100+
wantError: "unexpected character ' '",
101+
},
102+
{
103+
name: "space after =",
104+
input: "name= x",
105+
wantError: "unexpected character ' '",
106+
},
92107

93108
// String arguments tests
94109
{
@@ -203,6 +218,51 @@ func TestParse(t *testing.T) {
203218
input: "name=+badRaw(missing`)",
204219
wantError: "unexpected character '`'",
205220
},
221+
{
222+
name: "space before (",
223+
input: "name ()",
224+
wantError: "unexpected character ' '",
225+
},
226+
{
227+
name: "space between ( and )",
228+
input: "name ( )",
229+
wantError: "unexpected character ' '",
230+
},
231+
{
232+
name: "space before arg",
233+
input: "name( x)",
234+
wantError: "unexpected character ' '",
235+
},
236+
{
237+
name: "space after arg",
238+
input: "name(x )",
239+
wantError: "unexpected character ' '",
240+
},
241+
{
242+
name: "space before :",
243+
input: "name(k :v)",
244+
wantError: "unexpected character ' '",
245+
},
246+
{
247+
name: "space before value",
248+
input: "name(k:v )",
249+
wantError: "unexpected character ' '",
250+
},
251+
{
252+
name: "space before ,",
253+
input: "name(k:v ,k2:v2)",
254+
wantError: "unexpected character ' '",
255+
},
256+
{
257+
name: "space before =",
258+
input: "name() =x",
259+
wantError: "unexpected character ' '",
260+
},
261+
{
262+
name: "space after =",
263+
input: "name()= x",
264+
wantError: "unexpected character ' '",
265+
},
206266

207267
// Named arguments tests
208268
{
@@ -311,7 +371,7 @@ func TestParse(t *testing.T) {
311371
{
312372
name: "space in value",
313373
input: "key=one two",
314-
wantError: "unexpected character 't'",
374+
wantError: "unexpected character ' '",
315375
},
316376
{
317377
name: "unclosed backtick quoted string",

v2/codetags/scanner.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,28 @@ func (s *scanner) peekN(n int) rune {
4949
return s.buf[s.pos+n]
5050
}
5151

52-
func (s *scanner) skipWhitespace() bool {
53-
found := false
52+
func (s *scanner) skipWhitespace() rune {
5453
for r := s.peek(); unicode.IsSpace(r); r = s.peek() {
5554
s.next()
56-
found = true
5755
}
58-
return found
56+
return s.peek()
5957
}
6058

61-
func (s *scanner) skipWhitespacePeek() rune {
62-
s.skipWhitespace()
63-
return s.peek()
59+
func (s *scanner) nextIsTrailingComment() bool {
60+
if s.pos >= len(s.buf)-1 {
61+
return false
62+
}
63+
for i := s.pos; i < len(s.buf)-1; i++ {
64+
switch {
65+
case unicode.IsSpace(s.buf[i]):
66+
continue
67+
case s.buf[i] == '/' && s.buf[i+1] == '/':
68+
return true
69+
default:
70+
return false
71+
}
72+
}
73+
return false
6474
}
6575

6676
func (s *scanner) remainder() string {

0 commit comments

Comments
 (0)