github.com/dop251/goja_nodejs@v0.0.0-20240418154818-2aae10d4cbcf/url/nodeurl.go (about) 1 package url 2 3 import ( 4 "net/url" 5 "strings" 6 ) 7 8 type searchParam struct { 9 name string 10 value string 11 } 12 13 func (sp *searchParam) Encode() string { 14 return sp.string(true) 15 } 16 17 func escapeSearchParam(s string) string { 18 return escape(s, &tblEscapeURLQueryParam, true) 19 } 20 21 func (sp *searchParam) string(encode bool) string { 22 if encode { 23 return escapeSearchParam(sp.name) + "=" + escapeSearchParam(sp.value) 24 } else { 25 return sp.name + "=" + sp.value 26 } 27 } 28 29 type searchParams []searchParam 30 31 func (s searchParams) Len() int { 32 return len(s) 33 } 34 35 func (s searchParams) Swap(i, j int) { 36 s[i], s[j] = s[j], s[i] 37 } 38 39 func (s searchParams) Less(i, j int) bool { 40 return strings.Compare(s[i].name, s[j].name) < 0 41 } 42 43 func (s searchParams) Encode() string { 44 var sb strings.Builder 45 for i, v := range s { 46 if i > 0 { 47 sb.WriteByte('&') 48 } 49 sb.WriteString(v.Encode()) 50 } 51 return sb.String() 52 } 53 54 func (s searchParams) String() string { 55 var sb strings.Builder 56 for i, v := range s { 57 if i > 0 { 58 sb.WriteByte('&') 59 } 60 sb.WriteString(v.string(false)) 61 } 62 return sb.String() 63 } 64 65 type nodeURL struct { 66 url *url.URL 67 searchParams searchParams 68 } 69 70 type urlSearchParams nodeURL 71 72 // This methods ensures that the url.URL has the proper RawQuery based on the searchParam 73 // structs. If a change is made to the searchParams we need to keep them in sync. 74 func (nu *nodeURL) syncSearchParams() { 75 if nu.rawQueryUpdateNeeded() { 76 nu.url.RawQuery = nu.searchParams.Encode() 77 } 78 } 79 80 func (nu *nodeURL) rawQueryUpdateNeeded() bool { 81 return len(nu.searchParams) > 0 && nu.url.RawQuery == "" 82 } 83 84 func (nu *nodeURL) String() string { 85 return nu.url.String() 86 } 87 88 func (sp *urlSearchParams) hasName(name string) bool { 89 for _, v := range sp.searchParams { 90 if v.name == name { 91 return true 92 } 93 } 94 return false 95 } 96 97 func (sp *urlSearchParams) hasValue(name, value string) bool { 98 for _, v := range sp.searchParams { 99 if v.name == name && v.value == value { 100 return true 101 } 102 } 103 return false 104 } 105 106 func (sp *urlSearchParams) getValues(name string) []string { 107 vals := make([]string, 0, len(sp.searchParams)) 108 for _, v := range sp.searchParams { 109 if v.name == name { 110 vals = append(vals, v.value) 111 } 112 } 113 114 return vals 115 } 116 117 func (sp *urlSearchParams) getFirstValue(name string) (string, bool) { 118 for _, v := range sp.searchParams { 119 if v.name == name { 120 return v.value, true 121 } 122 } 123 124 return "", false 125 } 126 127 func parseSearchQuery(query string) (ret searchParams) { 128 if query == "" { 129 return 130 } 131 132 query = strings.TrimPrefix(query, "?") 133 134 for _, v := range strings.Split(query, "&") { 135 if v == "" { 136 continue 137 } 138 pair := strings.SplitN(v, "=", 2) 139 l := len(pair) 140 if l == 1 { 141 ret = append(ret, searchParam{name: unescapeSearchParam(pair[0]), value: ""}) 142 } else if l == 2 { 143 ret = append(ret, searchParam{name: unescapeSearchParam(pair[0]), value: unescapeSearchParam(pair[1])}) 144 } 145 } 146 147 return 148 }