Skip to content

Commit 2906388

Browse files
committed
chore: simplify URI parsing
1 parent b2ba721 commit 2906388

2 files changed

Lines changed: 63 additions & 66 deletions

File tree

packages/core/src/__tests__/Uri.spec.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,7 @@ describe("Uri", () => {
1919
});
2020

2121
it("Fails if a path is not present", () => {
22-
expect(() => new Uri("wrap://authority/")).toThrowError(/URI is malformed,/);
23-
});
24-
25-
it("Fails if scheme is not at the beginning", () => {
26-
expect(() => new Uri("path/wrap://something")).toThrowError(
27-
/The wrap:\/\/ scheme must/
28-
);
22+
expect(() => new Uri("wrap://authority/")).toThrowError(/URI path is missing,/);
2923
});
3024

3125
it("Fails with an empty string", () => {
@@ -77,4 +71,11 @@ describe("Uri", () => {
7771
expect(uri.authority).toEqual("ens");
7872
expect(uri.path).toEqual("domain.eth:pkg@1.0.0");
7973
});
74+
75+
it("Handles cases where the scheme delimiter is nested under an authority", () => {
76+
const uri = new Uri("authority/something?uri=wrap://something/something2");
77+
expect(uri.uri).toEqual("wrap://authority/something?uri=wrap://something/something2");
78+
expect(uri.authority).toEqual("authority");
79+
expect(uri.path).toEqual("something?uri=wrap://something/something2");
80+
});
8081
});

packages/core/src/types/Uri.ts

Lines changed: 55 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { RegExpGroups } from "../utils";
2-
31
import { Result, ResultErr, ResultOk } from "@polywrap/result";
42

53
// $start: UriConfig
@@ -117,71 +115,82 @@ export class Uri {
117115
* @param uri - a string representation of a wrap URI
118116
* @returns A Result containing a UriConfig, if successful, or an error
119117
*/
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+
));
123135
}
124136

125-
let processed = uri;
137+
let processedUri = input.trim();
126138

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);
130142
}
131143

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);
138158
}
139159

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) {
142164
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+
)
144170
);
145171
}
146172

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("/");
150176

151-
if (!result || !result.groups || !result.groups.path) {
177+
if (!path) {
152178
return ResultErr(
153179
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}`
159183
)
160184
);
161185
}
162186

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;
181190
}
182191

183192
return ResultOk({
184-
uri: processed,
193+
uri: processedUri,
185194
authority,
186195
path,
187196
});
@@ -217,17 +226,4 @@ export class Uri {
217226
public toJSON(): string /* $ */ {
218227
return this._config.uri;
219228
}
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-
}
233229
}

0 commit comments

Comments
 (0)