|
1 | | -import { RegExpGroups } from "../utils"; |
2 | | - |
3 | 1 | import { Result, ResultErr, ResultOk } from "@polywrap/result"; |
4 | 2 |
|
5 | 3 | // $start: UriConfig |
@@ -117,71 +115,82 @@ export class Uri { |
117 | 115 | * @param uri - a string representation of a wrap URI |
118 | 116 | * @returns A Result containing a UriConfig, if successful, or an error |
119 | 117 | */ |
120 | | - public static parseUri(uri: string): Result<UriConfig, Error> /* $ */ { |
121 | | - if (!uri) { |
122 | | - return ResultErr(Error("The provided URI is empty")); |
| 118 | + public static parseUri(input: string): Result<UriConfig, Error> /* $ */ { |
| 119 | + const authorityDelimiter = "/"; |
| 120 | + const schemeDelimiter = "://"; |
| 121 | + const wrapScheme = "wrap://"; |
| 122 | + |
| 123 | + const validUriExamples = |
| 124 | + "wrap://ipfs/QmHASH\n" + |
| 125 | + "wrap://ens/domain.eth\n" + |
| 126 | + "ipfs/QmHASH\n" + |
| 127 | + "ens/domain.eth\n" + |
| 128 | + "https://domain.com/path\n\n"; |
| 129 | + |
| 130 | + if (!input) { |
| 131 | + return ResultErr(Error( |
| 132 | + "The provided URI is empty, here are some examples of valid URIs:\n" + |
| 133 | + validUriExamples |
| 134 | + )); |
123 | 135 | } |
124 | 136 |
|
125 | | - let processed = uri; |
| 137 | + let processedUri = input.trim(); |
126 | 138 |
|
127 | | - // Trim preceding '/' characters |
128 | | - while (processed[0] === "/") { |
129 | | - processed = processed.substring(1); |
| 139 | + // Remove leading "/" |
| 140 | + if (processedUri.startsWith(authorityDelimiter)) { |
| 141 | + processedUri = processedUri.substring(1); |
130 | 142 | } |
131 | 143 |
|
132 | | - // Check for the wrap:// scheme, add if it isn't there |
133 | | - const wrapSchemeIdx = processed.indexOf("wrap://"); |
134 | | - |
135 | | - // If it's missing the wrap:// scheme, add it |
136 | | - if (wrapSchemeIdx === -1) { |
137 | | - processed = "wrap://" + processed; |
| 144 | + // Check if the string starts with a non-wrap URI scheme |
| 145 | + if (!processedUri.startsWith(wrapScheme)) { |
| 146 | + const schemeIndex = processedUri.indexOf(schemeDelimiter); |
| 147 | + const authorityIndex = processedUri.indexOf(authorityDelimiter); |
| 148 | + if (schemeIndex !== -1) { |
| 149 | + // Make sure the string before the scheme doesn't contain an authority |
| 150 | + if (!(authorityIndex !== -1 && schemeIndex > authorityIndex)) { |
| 151 | + processedUri = |
| 152 | + processedUri.substring(0, schemeIndex) + "/" + |
| 153 | + processedUri.substring(schemeIndex + schemeDelimiter.length); |
| 154 | + } |
| 155 | + } |
| 156 | + } else { |
| 157 | + processedUri = processedUri.substring(wrapScheme.length); |
138 | 158 | } |
139 | 159 |
|
140 | | - // If the wrap:// is not in the beginning, return an error |
141 | | - if (wrapSchemeIdx > -1 && wrapSchemeIdx !== 0) { |
| 160 | + // Split the string into parts, using "/" as a delimeter |
| 161 | + const parts = processedUri.split(authorityDelimiter); |
| 162 | + |
| 163 | + if (parts.length < 2) { |
142 | 164 | return ResultErr( |
143 | | - Error("The wrap:// scheme must be at the beginning of the URI string") |
| 165 | + Error( |
| 166 | + `URI authority is missing, here are some examples of valid URIs:\n` + |
| 167 | + validUriExamples + |
| 168 | + `Invalid URI Received: ${input}` |
| 169 | + ) |
144 | 170 | ); |
145 | 171 | } |
146 | 172 |
|
147 | | - // Extract the authoriy & path |
148 | | - const re = /^wrap:\/\/((?<authority>[a-z][a-z0-9-_]+)\/)?(?<path>.*)$/; |
149 | | - const result: RegExpGroups<"authority" | "path"> = re.exec(processed); |
| 173 | + // Extract the authority and path |
| 174 | + const authority = parts[0]; |
| 175 | + const path = parts.slice(1).join("/"); |
150 | 176 |
|
151 | | - if (!result || !result.groups || !result.groups.path) { |
| 177 | + if (!path) { |
152 | 178 | return ResultErr( |
153 | 179 | Error( |
154 | | - `URI is malformed, here are some examples of valid URIs:\n` + |
155 | | - `wrap://ipfs/QmHASH\n` + |
156 | | - `wrap://ens/domain.eth\n` + |
157 | | - `ens/domain.eth\n\n` + |
158 | | - `Invalid URI Received: ${uri}` |
| 180 | + `URI path is missing, here are some examples of valid URIs:\n` + |
| 181 | + validUriExamples + |
| 182 | + `Invalid URI Received: ${input}` |
159 | 183 | ) |
160 | 184 | ); |
161 | 185 | } |
162 | 186 |
|
163 | | - let { authority, path } = result.groups; |
164 | | - |
165 | | - if (!authority) { |
166 | | - const inferred = Uri.inferAuthority(path); |
167 | | - if (!inferred) { |
168 | | - return ResultErr( |
169 | | - Error( |
170 | | - `URI authority is missing, here are some examples of valid URIs:\n` + |
171 | | - `wrap://ipfs/QmHASH\n` + |
172 | | - `wrap://ens/domain.eth\n` + |
173 | | - `ens/domain.eth\n\n` + |
174 | | - `Invalid URI Received: ${uri}` |
175 | | - ) |
176 | | - ); |
177 | | - } |
178 | | - authority = inferred.authority; |
179 | | - path = inferred.path; |
180 | | - processed = `wrap://${authority}/${path}`; |
| 187 | + // Add "wrap://" if not already present |
| 188 | + if (!processedUri.startsWith("wrap://")) { |
| 189 | + processedUri = "wrap://" + processedUri; |
181 | 190 | } |
182 | 191 |
|
183 | 192 | return ResultOk({ |
184 | | - uri: processed, |
| 193 | + uri: processedUri, |
185 | 194 | authority, |
186 | 195 | path, |
187 | 196 | }); |
@@ -217,17 +226,4 @@ export class Uri { |
217 | 226 | public toJSON(): string /* $ */ { |
218 | 227 | return this._config.uri; |
219 | 228 | } |
220 | | - |
221 | | - private static inferAuthority(_path: string): UriConfig | undefined { |
222 | | - const re = /^(?<authority>[a-z][a-z0-9-_]+):\/\/(?<path>.*)$/; |
223 | | - const result: RegExpGroups<"authority" | "path"> = re.exec(_path); |
224 | | - |
225 | | - if (!result || !result.groups) { |
226 | | - return undefined; |
227 | | - } |
228 | | - const authority = result.groups.authority as string; |
229 | | - const path = result.groups.path as string; |
230 | | - |
231 | | - return { authority, path, uri: `wrap://${authority}/${path}` }; |
232 | | - } |
233 | 229 | } |
0 commit comments