Skip to content

Commit 5dfd5d9

Browse files
krisbitneydOrgJelli
authored andcommitted
added polywrap uri authority inference for common URI formats to Uri
1 parent 2481d51 commit 5dfd5d9

7 files changed

Lines changed: 89 additions & 31 deletions

File tree

packages/js/core/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ export interface UriConfig {
340340
/**
341341
* A Polywrap URI. Some examples of valid URIs are:
342342
* wrap://ipfs/QmHASH
343-
* wrap://ens/sub.dimain.eth
343+
* wrap://ens/sub.domain.eth
344344
* wrap://fs/directory/file.txt
345345
* wrap://uns/domain.crypto
346346
*

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe("Uri", () => {
1515
});
1616

1717
it("Fails if an authority is not present", () => {
18-
expect(() => new Uri("wrap://path")).toThrowError(/URI is malformed,/);
18+
expect(() => new Uri("wrap://path")).toThrowError(/URI authority is missing,/);
1919
});
2020

2121
it("Fails if a path is not present", () => {
@@ -50,4 +50,31 @@ describe("Uri", () => {
5050
path: "uri",
5151
});
5252
});
53+
54+
it("Infers common URI authorities", () => {
55+
let uri = new Uri("https://domain.com/path/to/thing");
56+
expect(uri.uri).toEqual("wrap://https/https://domain.com/path/to/thing");
57+
expect(uri.authority).toEqual("https");
58+
expect(uri.path).toEqual("https://domain.com/path/to/thing");
59+
60+
uri = new Uri("http://domain.com/path/to/thing");
61+
expect(uri.uri).toEqual("wrap://http/http://domain.com/path/to/thing");
62+
expect(uri.authority).toEqual("http");
63+
expect(uri.path).toEqual("http://domain.com/path/to/thing");
64+
65+
uri = new Uri("ipfs://QmaM318ABUXDhc5eZGGbmDxkb2ZgnbLxigm5TyZcCsh1Kw");
66+
expect(uri.uri).toEqual("wrap://ipfs/QmaM318ABUXDhc5eZGGbmDxkb2ZgnbLxigm5TyZcCsh1Kw");
67+
expect(uri.authority).toEqual("ipfs");
68+
expect(uri.path).toEqual("QmaM318ABUXDhc5eZGGbmDxkb2ZgnbLxigm5TyZcCsh1Kw");
69+
70+
uri = new Uri("ens://domain.eth");
71+
expect(uri.uri).toEqual("wrap://ens/domain.eth");
72+
expect(uri.authority).toEqual("ens");
73+
expect(uri.path).toEqual("domain.eth");
74+
75+
uri = new Uri("ens://domain.eth:pkg@1.0.0");
76+
expect(uri.uri).toEqual("wrap://ens/domain.eth:pkg@1.0.0");
77+
expect(uri.authority).toEqual("ens");
78+
expect(uri.path).toEqual("domain.eth:pkg@1.0.0");
79+
});
5380
});

packages/js/core/src/types/Uri.ts

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

35
// $start: UriConfig
@@ -18,7 +20,7 @@ export interface UriConfig {
1820
/**
1921
* A Polywrap URI. Some examples of valid URIs are:
2022
* wrap://ipfs/QmHASH
21-
* wrap://ens/sub.dimain.eth
23+
* wrap://ens/sub.domain.eth
2224
* wrap://fs/directory/file.txt
2325
* wrap://uns/domain.crypto
2426
*
@@ -135,17 +137,10 @@ export class Uri {
135137
}
136138

137139
// Extract the authoriy & path
138-
const result = processed.match(/wrap:\/\/([a-z][a-z0-9-_]+)\/(.*)/);
139-
let uriParts: string[];
140-
141-
// Remove all empty strings
142-
if (result) {
143-
uriParts = result.filter((str) => !!str);
144-
} else {
145-
uriParts = [];
146-
}
140+
const re = /^wrap:\/\/((?<authority>[a-z][a-z0-9-_]+)\/)?(?<path>.*)$/;
141+
const result: RegExpGroups<"authority" | "path"> = re.exec(processed);
147142

148-
if (uriParts.length !== 3) {
143+
if (!result || !result.groups || !result.groups.path) {
149144
return ResultErr(
150145
Error(
151146
`URI is malformed, here are some examples of valid URIs:\n` +
@@ -157,10 +152,30 @@ export class Uri {
157152
);
158153
}
159154

155+
let { authority, path } = result.groups;
156+
157+
if (!authority) {
158+
const inferred = Uri.inferAuthority(path);
159+
if (!inferred) {
160+
return ResultErr(
161+
Error(
162+
`URI authority is missing, here are some examples of valid URIs:\n` +
163+
`wrap://ipfs/QmHASH\n` +
164+
`wrap://ens/domain.eth\n` +
165+
`ens/domain.eth\n\n` +
166+
`Invalid URI Received: ${uri}`
167+
)
168+
);
169+
}
170+
authority = inferred.authority;
171+
path = inferred.path;
172+
processed = `wrap://${authority}/${path}`;
173+
}
174+
160175
return ResultOk({
161176
uri: processed,
162-
authority: uriParts[1],
163-
path: uriParts[2],
177+
authority,
178+
path,
164179
});
165180
}
166181

@@ -194,4 +209,26 @@ export class Uri {
194209
public toJSON(): string /* $ */ {
195210
return this._config.uri;
196211
}
212+
213+
private static inferAuthority(path: string): UriConfig | undefined {
214+
let authority: string | undefined;
215+
216+
if (path.startsWith("https://")) {
217+
authority = "https";
218+
} else if (path.startsWith("http://")) {
219+
authority = "http";
220+
} else if (path.startsWith("ipfs://")) {
221+
authority = "ipfs";
222+
path = path.substring(7);
223+
} else if (path.startsWith("ens://")) {
224+
authority = "ens";
225+
path = path.substring(6);
226+
}
227+
228+
if (!authority) {
229+
return undefined;
230+
}
231+
232+
return { authority, path, uri: `wrap://${authority}/${path}` };
233+
}
197234
}

packages/js/core/src/types/WrapError.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CleanResolutionStep } from "../algorithms";
2+
import { RegExpGroups } from "../utils/RegExpGroups";
23

34
export type ErrorSource = Readonly<{
45
file?: string;
@@ -52,12 +53,6 @@ export interface WrapErrorOptions {
5253
innerError?: WrapError;
5354
}
5455

55-
type RegExpGroups<T extends string> =
56-
| (RegExpExecArray & {
57-
groups?: { [name in T]: string | undefined } | { [key: string]: string };
58-
})
59-
| null;
60-
6156
export class WrapError extends Error {
6257
readonly name: string = "WrapError";
6358
readonly code: WrapErrorCode;
@@ -174,7 +169,7 @@ export class WrapError extends Error {
174169
| "resolutionStack"
175170
| "cause"
176171
> = WrapError.re.exec(error);
177-
if (!result) {
172+
if (!result || !result.groups) {
178173
return undefined;
179174
}
180175
const {
@@ -188,8 +183,7 @@ export class WrapError extends Error {
188183
col,
189184
resolutionStack: resolutionStackStr,
190185
cause,
191-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
192-
} = result.groups!;
186+
} = result.groups;
193187

194188
const code = parseInt(codeStr as string);
195189

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type RegExpGroups<T extends string> =
2+
| (RegExpExecArray & {
3+
groups?: { [name in T]: string | undefined } | { [key: string]: string };
4+
})
5+
| null;

packages/js/core/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from "./combinePaths";
22
export * from "./getEnvFromUriHistory";
33
export * from "./is-buffer";
44
export * from "./typesHandler";
5+
export * from "./RegExpGroups";

packages/js/plugin/src/utils/getErrorSource.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import { ErrorSource } from "@polywrap/core-js";
2-
3-
type RegExpGroups<T extends string> =
4-
| (RegExpExecArray & {
5-
groups?: { [name in T]: string | undefined } | { [key: string]: string };
6-
})
7-
| null;
1+
import { ErrorSource, RegExpGroups } from "@polywrap/core-js";
82

93
const re = /\((?<file>.*):(?<row>\d+):(?<col>\d+)\)$/;
104

0 commit comments

Comments
 (0)