@@ -17,15 +17,23 @@ export interface UriConfig {
1717// $start: Uri
1818/**
1919 * A Polywrap URI. Some examples of valid URIs are:
20+ * wrap://https/domain.com
2021 * wrap://ipfs/QmHASH
21- * wrap://ens/sub.dimain.eth
22- * wrap://fs/directory/file.txt
23- * wrap://uns/domain.crypto
22+ * wrap://ens/sub.domain.eth
23+ * wrap://file/directory/file.txt
24+ *
25+ * Some example short-hand URIs (utilizing inference):
26+ * ipfs/QmHASH -> wrap://ipfs/QmHASH
27+ * https://domain.com -> wrap://https/domain.com
28+ *
29+ * URI inference is performed in the following ways:
30+ * 1. If wrap:// is missing, it will be added.
31+ * 2. If non-wrap schema exists, it becomes the authority.
2432 *
2533 * Breaking down the various parts of the URI, as it applies
2634 * to [the URI standard](https://tools.ietf.org/html/rfc3986#section-3):
2735 * **wrap://** - URI Scheme: differentiates Polywrap URIs.
28- * **ipfs /** - URI Authority: allows the Polywrap URI resolution algorithm to determine an authoritative URI resolver.
36+ * **ens /** - URI Authority: allows the Polywrap URI resolution algorithm to determine an authoritative URI resolver.
2937 * **sub.domain.eth** - URI Path: tells the Authority where the Wrapper resides.
3038 */
3139export class Uri {
@@ -107,60 +115,87 @@ export class Uri {
107115 * @param uri - a string representation of a wrap URI
108116 * @returns A Result containing a UriConfig, if successful, or an error
109117 */
110- public static parseUri ( uri : string ) : Result < UriConfig , Error > /* $ */ {
111- if ( ! uri ) {
112- 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 (
132+ Error (
133+ "The provided URI is empty, here are some examples of valid URIs:\n" +
134+ validUriExamples
135+ )
136+ ) ;
113137 }
114138
115- let processed = uri ;
139+ let processedUri = input . trim ( ) ;
116140
117- // Trim preceding '/' characters
118- while ( processed [ 0 ] === "/" ) {
119- processed = processed . substring ( 1 ) ;
141+ // Remove leading "/"
142+ if ( processedUri . startsWith ( authorityDelimiter ) ) {
143+ processedUri = processedUri . substring ( 1 ) ;
120144 }
121145
122- // Check for the wrap:// scheme, add if it isn't there
123- const wrapSchemeIdx = processed . indexOf ( "wrap://" ) ;
124-
125- // If it's missing the wrap:// scheme, add it
126- if ( wrapSchemeIdx === - 1 ) {
127- processed = "wrap://" + processed ;
146+ // Check if the string starts with a non-wrap URI scheme
147+ if ( ! processedUri . startsWith ( wrapScheme ) ) {
148+ const schemeIndex = processedUri . indexOf ( schemeDelimiter ) ;
149+ const authorityIndex = processedUri . indexOf ( authorityDelimiter ) ;
150+ if ( schemeIndex !== - 1 ) {
151+ // Make sure the string before the scheme doesn't contain an authority
152+ if ( ! ( authorityIndex !== - 1 && schemeIndex > authorityIndex ) ) {
153+ processedUri =
154+ processedUri . substring ( 0 , schemeIndex ) +
155+ "/" +
156+ processedUri . substring ( schemeIndex + schemeDelimiter . length ) ;
157+ }
158+ }
159+ } else {
160+ processedUri = processedUri . substring ( wrapScheme . length ) ;
128161 }
129162
130- // If the wrap:// is not in the beginning, return an error
131- if ( wrapSchemeIdx > - 1 && wrapSchemeIdx !== 0 ) {
163+ // Split the string into parts, using "/" as a delimeter
164+ const parts = processedUri . split ( authorityDelimiter ) ;
165+
166+ if ( parts . length < 2 ) {
132167 return ResultErr (
133- Error ( "The wrap:// scheme must be at the beginning of the URI string" )
168+ Error (
169+ `URI authority is missing, here are some examples of valid URIs:\n` +
170+ validUriExamples +
171+ `Invalid URI Received: ${ input } `
172+ )
134173 ) ;
135174 }
136175
137- // Extract the authoriy & path
138- const result = processed . match ( / w r a p : \/ \/ ( [ a - z ] [ a - z 0 - 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- }
176+ // Extract the authority and path
177+ const authority = parts [ 0 ] ;
178+ const path = parts . slice ( 1 ) . join ( "/" ) ;
147179
148- if ( uriParts . length !== 3 ) {
180+ if ( ! path ) {
149181 return ResultErr (
150182 Error (
151- `URI is malformed, here are some examples of valid URIs:\n` +
152- `wrap://ipfs/QmHASH\n` +
153- `wrap://ens/domain.eth\n` +
154- `ens/domain.eth\n\n` +
155- `Invalid URI Received: ${ uri } `
183+ `URI path is missing, here are some examples of valid URIs:\n` +
184+ validUriExamples +
185+ `Invalid URI Received: ${ input } `
156186 )
157187 ) ;
158188 }
159189
190+ // Add "wrap://" if not already present
191+ if ( ! processedUri . startsWith ( "wrap://" ) ) {
192+ processedUri = "wrap://" + processedUri ;
193+ }
194+
160195 return ResultOk ( {
161- uri : processed ,
162- authority : uriParts [ 1 ] ,
163- path : uriParts [ 2 ] ,
196+ uri : processedUri ,
197+ authority,
198+ path,
164199 } ) ;
165200 }
166201
0 commit comments