@@ -317,7 +317,7 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument {
317317 // might be a map or slice, parse the string and check for colon
318318 // (blech, basically arbitrary look-ahead due to raw strings).
319319 var keyVal string // just ignore this
320- (& Argument {Type : StringType }).parseString (subScanner , raw , reflect .Indirect (reflect .ValueOf (& keyVal )))
320+ (& Argument {Type : StringType }).parseString (subScanner , raw , reflect .Indirect (reflect .ValueOf (& keyVal )), true )
321321
322322 if token := subScanner .Scan (); token == ':' || hint == '}' {
323323 // it's got a string followed by a colon -- it's a map
@@ -362,15 +362,20 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument {
362362 nextTok = subScanner .Scan ()
363363 }
364364
365- // Only treat as a numeric type if the scanner did not emit errors while
366- // tokenising (e.g. invalid octal "087bdd" produces sc.Int but also
367- // triggers an error). In that case fall through to the bare-string
368- // path so the value is treated as a string.
369- if ! hadScanError {
370- if nextTok == sc .Int {
371- return & Argument {Type : IntType }
372- }
373- if nextTok == sc .Float {
365+ // Only treat as a numeric type if:
366+ // 1. The scanner did not emit errors while tokenising (e.g. invalid
367+ // octal "087bdd" produces sc.Int but also triggers an error).
368+ // 2. The token is immediately followed by a delimiter (comma,
369+ // semicolon, EOF) or whitespace-then-delimiter, meaning there is
370+ // no trailing non-numeric content. Inputs like "123/config",
371+ // "100Mi", "2024-01-15" start with a valid numeric token but
372+ // contain additional characters and must be treated as strings.
373+ if ! hadScanError && (nextTok == sc .Int || nextTok == sc .Float ) {
374+ followTok := peekNoSpace (subScanner )
375+ if followTok == ',' || followTok == ';' || followTok == sc .EOF || followTok == '}' {
376+ if nextTok == sc .Int {
377+ return & Argument {Type : IntType }
378+ }
374379 return & Argument {Type : NumberType }
375380 }
376381 }
@@ -381,7 +386,8 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument {
381386}
382387
383388// parseString parses either of the two accepted string forms (quoted, or bare tokens).
384- func (a * Argument ) parseString (scanner * sc.Scanner , raw string , out reflect.Value ) {
389+ // When inMap is true, ':' is treated as a delimiter (map key separator).
390+ func (a * Argument ) parseString (scanner * sc.Scanner , raw string , out reflect.Value , inMap bool ) {
385391 // we need to temporarily disable the scanner's int/float parsing, since we want to
386392 // prevent number parsing errors.
387393 oldMode := scanner .Mode
@@ -406,10 +412,16 @@ func (a *Argument) parseString(scanner *sc.Scanner, raw string, out reflect.Valu
406412 }
407413
408414 // the "hard" case -- bare tokens not including ',' (the argument
409- // separator), ';' (the slice separator), ':' (the map separator), or '}'
410- // (delimitted slice ender)
415+ // separator), ';' (the slice separator), or '}' (delimitted slice ender).
416+ // ':' (the map separator) is only a delimiter when parsing inside a map.
417+ isDelim := func (hint rune ) bool {
418+ if hint == ',' || hint == ';' || hint == '}' || hint == sc .EOF {
419+ return true
420+ }
421+ return inMap && hint == ':'
422+ }
411423 startPos := scanner .Position .Offset
412- for hint := peekNoSpace (scanner ); hint != ',' && hint != ';' && hint != ':' && hint != '}' && hint != sc . EOF ; hint = peekNoSpace (scanner ) {
424+ for hint := peekNoSpace (scanner ); ! isDelim ( hint ) ; hint = peekNoSpace (scanner ) {
413425 // skip this token
414426 scanner .Scan ()
415427 }
@@ -477,7 +489,7 @@ func (a *Argument) parseMap(scanner *sc.Scanner, raw string, out reflect.Value)
477489 }
478490
479491 for hint := peekNoSpace (scanner ); hint != '}' && hint != sc .EOF ; hint = peekNoSpace (scanner ) {
480- a .parseString (scanner , raw , key )
492+ a .parseString (scanner , raw , key , true )
481493 if ! expect (scanner , ':' , "colon" ) {
482494 return
483495 }
@@ -573,7 +585,7 @@ func (a *Argument) parse(scanner *sc.Scanner, raw string, out reflect.Value, inS
573585 // strings are a bit weird -- the "easy" case is quoted strings (tokenized as strings),
574586 // the "hard" case (present for backwards compat) is a bare sequence of tokens that aren't
575587 // a comma.
576- a .parseString (scanner , raw , out )
588+ a .parseString (scanner , raw , out , false )
577589 case BoolType :
578590 if ! expect (scanner , sc .Ident , "true or false" ) {
579591 return
0 commit comments