5
5
* LICENSE file in the root directory of this source tree.
6
6
*
7
7
* @format
8
- * @flow strict-local
9
8
*/
10
9
11
10
'use strict' ;
@@ -47,11 +46,71 @@ if (BlobModule && typeof BlobModule.BLOB_URI_SCHEME === 'string') {
47
46
* </resources>
48
47
* ```
49
48
*/
50
- class URL {
51
- constructor ( ) {
52
- throw new Error ( 'Creating URL objects is not supported yet.' ) ;
49
+
50
+ // Small subset from whatwg-url: https://github.com/jsdom/whatwg-url/tree/master/lib
51
+ // The reference code bloat comes from Unicode issues with URLs, so those won't work here.
52
+ export class URLSearchParams {
53
+ _searchParams = [ ] ;
54
+
55
+ constructor ( params : any ) {
56
+ if ( typeof params === 'object' ) {
57
+ Object . keys ( params ) . forEach ( key => this . append ( key , params [ key ] ) ) ;
58
+ }
59
+ }
60
+
61
+ append ( key : string , value : string ) {
62
+ this . _searchParams . push ( [ key , value ] ) ;
63
+ }
64
+
65
+ delete ( name ) {
66
+ throw new Error ( 'not implemented' ) ;
67
+ }
68
+
69
+ get ( name ) {
70
+ throw new Error ( 'not implemented' ) ;
71
+ }
72
+
73
+ getAll ( name ) {
74
+ throw new Error ( 'not implemented' ) ;
75
+ }
76
+
77
+ has ( name ) {
78
+ throw new Error ( 'not implemented' ) ;
79
+ }
80
+
81
+ set ( name , value ) {
82
+ throw new Error ( 'not implemented' ) ;
53
83
}
54
84
85
+ sort ( ) {
86
+ throw new Error ( 'not implemented' ) ;
87
+ }
88
+
89
+ [ Symbol . iterator ] ( ) {
90
+ return this . _searchParams [ Symbol . iterator ] ( ) ;
91
+ }
92
+
93
+ toString ( ) {
94
+ if ( this . _searchParams . length === 0 ) {
95
+ return '' ;
96
+ }
97
+ const last = this . _searchParams . length - 1 ;
98
+ return this . _searchParams . reduce ( ( acc , curr , index ) => {
99
+ return acc + curr . join ( '=' ) + ( index === last ? '' : '&' ) ;
100
+ } , '' ) ;
101
+ }
102
+ }
103
+
104
+ function validateBaseUrl ( url : string ) {
105
+ // from this MIT-licensed gist: https://gist.github.com/dperini/729294
106
+ return / ^ (?: (?: (?: h t t p s ? | f t p ) : ) ? \/ \/ ) (?: (?: [ 1 - 9 ] \d ? | 1 \d \d | 2 [ 0 1 ] \d | 2 2 [ 0 - 3 ] ) (?: \. (?: 1 ? \d { 1 , 2 } | 2 [ 0 - 4 ] \d | 2 5 [ 0 - 5 ] ) ) { 2 } (?: \. (?: [ 1 - 9 ] \d ? | 1 \d \d | 2 [ 0 - 4 ] \d | 2 5 [ 0 - 4 ] ) ) | (?: (?: [ a - z \u00a1 - \uffff 0 - 9 ] - * ) * [ a - z \u00a1 - \uffff 0 - 9 ] + ) (?: \. (?: [ a - z \u00a1 - \uffff 0 - 9 ] - * ) * [ a - z \u00a1 - \uffff 0 - 9 ] + ) * (?: \. (?: [ a - z \u00a1 - \uffff ] { 2 , } ) ) ) (?: : \d { 2 , 5 } ) ? (?: [ / ? # ] \S * ) ? $ / i. test (
107
+ url ,
108
+ ) ;
109
+ }
110
+
111
+ export class URL {
112
+ _searchParamsInstance = null ;
113
+
55
114
static createObjectURL ( blob : Blob ) {
56
115
if ( BLOB_URL_PREFIX === null ) {
57
116
throw new Error ( 'Cannot create URL for blob!' ) ;
@@ -64,6 +123,93 @@ class URL {
64
123
static revokeObjectURL ( url : string ) {
65
124
// Do nothing.
66
125
}
67
- }
68
126
69
- module . exports = URL ;
127
+ constructor ( url : string , base : string ) {
128
+ let baseUrl = null ;
129
+ if ( base ) {
130
+ if ( typeof base === 'string' ) {
131
+ baseUrl = base ;
132
+ if ( ! validateBaseUrl ( baseUrl ) ) {
133
+ throw new TypeError ( `Invalid base URL: ${ baseUrl } ` ) ;
134
+ }
135
+ } else if ( typeof base === 'object' ) {
136
+ baseUrl = base . toString ( ) ;
137
+ }
138
+ if ( baseUrl . endsWith ( '/' ) && url . startsWith ( '/' ) ) {
139
+ baseUrl = baseUrl . slice ( 0 , baseUrl . length - 1 ) ;
140
+ }
141
+ if ( baseUrl . endsWith ( url ) ) {
142
+ url = '' ;
143
+ }
144
+ this . _url = `${ baseUrl } ${ url } ` ;
145
+ } else {
146
+ this . _url = url ;
147
+ if ( ! this . _url . endsWith ( '/' ) ) {
148
+ this . _url += '/' ;
149
+ }
150
+ }
151
+ }
152
+
153
+ get hash ( ) {
154
+ throw new Error ( 'not implemented' ) ;
155
+ }
156
+
157
+ get host ( ) {
158
+ throw new Error ( 'not implemented' ) ;
159
+ }
160
+
161
+ get hostname ( ) {
162
+ throw new Error ( 'not implemented' ) ;
163
+ }
164
+
165
+ get href ( ) : string {
166
+ return this . toString ( ) ;
167
+ }
168
+
169
+ get origin ( ) {
170
+ throw new Error ( 'not implemented' ) ;
171
+ }
172
+
173
+ get password ( ) {
174
+ throw new Error ( 'not implemented' ) ;
175
+ }
176
+
177
+ get pathname ( ) {
178
+ throw new Error ( 'not implemented' ) ;
179
+ }
180
+
181
+ get port ( ) {
182
+ throw new Error ( 'not implemented' ) ;
183
+ }
184
+
185
+ get protocol ( ) {
186
+ throw new Error ( 'not implemented' ) ;
187
+ }
188
+
189
+ get search ( ) {
190
+ throw new Error ( 'not implemented' ) ;
191
+ }
192
+
193
+ get searchParams ( ) : URLSearchParams {
194
+ if ( this . _searchParamsInstance == null ) {
195
+ this . _searchParamsInstance = new URLSearchParams ( ) ;
196
+ }
197
+ return this . _searchParamsInstance ;
198
+ }
199
+
200
+ toJSON ( ) : string {
201
+ return this . toString ( ) ;
202
+ }
203
+
204
+ toString ( ) : string {
205
+ if ( this . _searchParamsInstance === null ) {
206
+ return this . _url ;
207
+ }
208
+ const separator = this . _url . indexOf ( '?' ) > - 1 ? '&' : '?' ;
209
+ return this . _url + separator + this . _searchParamsInstance . toString ( ) ;
210
+ }
211
+
212
+ get username ( ) {
213
+ throw new Error ( 'not implemented' ) ;
214
+ }
215
+ }
0 commit comments