@@ -2,6 +2,7 @@ package wit
2
2
3
3
import (
4
4
"errors"
5
+ "strconv"
5
6
"strings"
6
7
7
8
"github.com/coreos/go-semver/semver"
@@ -34,24 +35,32 @@ type Ident struct {
34
35
// returning any errors encountered. The resulting Ident
35
36
// may not be valid.
36
37
func ParseIdent (s string ) (Ident , error ) {
37
- s = strings .ReplaceAll (s , "%" , "" )
38
38
var id Ident
39
39
name , ver , hasVer := strings .Cut (s , "@" )
40
- base , ext , hasExt := strings .Cut (name , "/" )
41
- id .Namespace , id .Package , _ = strings .Cut (base , ":" )
42
40
if hasVer {
43
41
var err error
44
42
id .Version , err = semver .NewVersion (ver )
45
43
if err != nil {
46
44
return id , err
47
45
}
48
46
}
47
+ base , ext , hasExt := strings .Cut (name , "/" )
48
+ ns , pkg , _ := strings .Cut (base , ":" )
49
+ id .Namespace = trimPercent (ns )
50
+ id .Package = trimPercent (pkg )
49
51
if hasExt {
50
- id .Extension = ext
52
+ id .Extension = trimPercent ( ext )
51
53
}
52
54
return id , id .Validate ()
53
55
}
54
56
57
+ func trimPercent (s string ) string {
58
+ if len (s ) > 0 && s [0 ] == '%' {
59
+ return s [1 :]
60
+ }
61
+ return s
62
+ }
63
+
55
64
// Validate validates id, returning any errors.
56
65
func (id * Ident ) Validate () error {
57
66
switch {
@@ -60,6 +69,59 @@ func (id *Ident) Validate() error {
60
69
case id .Package == "" :
61
70
return errors .New ("missing package name" )
62
71
}
72
+ if err := validateName (id .Namespace ); err != nil {
73
+ return err
74
+ }
75
+ if err := validateName (id .Package ); err != nil {
76
+ return err
77
+ }
78
+ return validateName (id .Extension )
79
+ }
80
+
81
+ func validateName (s string ) error {
82
+ if len (s ) == 0 {
83
+ return nil
84
+ }
85
+ var prev rune
86
+ for _ , c := range s {
87
+ switch {
88
+ case c >= 'a' && c <= 'z' :
89
+ switch {
90
+ case prev >= 'A' && prev <= 'Z' :
91
+ return errors .New ("invalid character " + strconv .Quote (string (c )))
92
+ }
93
+ case c >= 'A' && c <= 'Z' :
94
+ switch {
95
+ case prev == 0 : // start of string
96
+ case prev >= 'A' && prev <= 'Z' :
97
+ case prev >= '0' && prev <= '9' :
98
+ case prev == '-' :
99
+ default :
100
+ return errors .New ("invalid character " + strconv .Quote (string (c )))
101
+ }
102
+ case c >= '0' && c <= '9' :
103
+ switch {
104
+ case prev >= 'a' && prev <= 'z' :
105
+ case prev >= 'A' && prev <= 'Z' :
106
+ case prev >= '0' && prev <= '9' :
107
+ default :
108
+ return errors .New ("invalid character " + strconv .Quote (string (c )))
109
+ }
110
+ case c == '-' :
111
+ switch {
112
+ case prev == 0 : // start of string
113
+ return errors .New ("invalid leading -" )
114
+ case prev == '-' :
115
+ return errors .New ("invalid double --" )
116
+ }
117
+ default :
118
+ return errors .New ("invalid character " + strconv .Quote (string (c )))
119
+ }
120
+ prev = c
121
+ }
122
+ if prev == '-' {
123
+ return errors .New ("invalid trailing -" )
124
+ }
63
125
return nil
64
126
}
65
127
0 commit comments