1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15interface NativeUri { 16 new(input: string): NativeUri; 17 normalize(): string; 18 equals(other: NativeUri): boolean; 19 equalsTo(other: NativeUri): boolean; 20 checkIsAbsolute(): boolean; 21 toString(): string; 22 checkIsRelative(): boolean; 23 checkIsOpaque(): boolean; 24 checkIsHierarchical(): boolean; 25 addQueryValue(key: string, value: string): string; 26 addSegment(pathSegment: string):string; 27 getSegment(): string[]; 28 clearQuery(): string; 29 scheme: string | null; 30 authority: string | null; 31 ssp: string; 32 userInfo: string | null; 33 host: string | null; 34 port: string; 35 path: string | null; 36 query: string | null; 37 fragment: string | null; 38 isFailed: string; 39 encodedUserInfo: string | null; 40 encodedPath: string | null; 41 encodedQuery: string | null; 42 encodedFragment: string | null; 43 encodedAuthority: string | null; 44 encodedSSP: string | null; 45} 46interface UriInterface { 47 Uri: NativeUri; 48} 49declare function requireInternal(s: string): UriInterface; 50const uri = requireInternal('uri'); 51 52const TypeErrorCodeId = 401; 53const SyntaxErrorCodeId = 10200002; 54 55class BusinessError extends Error { 56 code: number; 57 constructor(msg: string) { 58 super(msg); 59 this.name = 'BusinessError'; 60 this.code = TypeErrorCodeId; 61 } 62} 63 64class URI { 65 uricalss: NativeUri; 66 constructor(input: string) { 67 if (typeof input !== 'string' || input.length === 0) { 68 throw new BusinessError(`Parameter error. The type of ${input} must be string`); 69 } 70 this.uricalss = new uri.Uri(input); 71 let errStr: string = this.uricalss.isFailed; 72 if (errStr.length !== 0) { 73 let err : BusinessError = new BusinessError(`Syntax Error. Invalid Uri string: The ${errStr}`); 74 err.code = SyntaxErrorCodeId; 75 throw err; 76 } 77 } 78 79 static createFromParts(scheme: string, ssp: string, fragment: string): URI { 80 if (scheme === null || typeof scheme !== 'string') { 81 throw new BusinessError(`Parameter error. The type of ${scheme} must be string`); 82 } 83 if (ssp === null || typeof ssp !== 'string') { 84 throw new BusinessError(`Parameter error. The type of ${ssp} must be string`); 85 } 86 if (typeof fragment !== 'string') { 87 throw new BusinessError(`Parameter error. The type of ${fragment} must be string`); 88 } 89 let uriStr: string = scheme; 90 uriStr += ':' + encodeURIComponent(ssp); 91 if (fragment !== null && fragment !== '') { 92 uriStr += '#' + encodeURIComponent(fragment); 93 } 94 return createNewUri(uriStr); 95 } 96 97 toString(): string { 98 return toAscllString(this.uricalss.toString()); 99 } 100 101 equals(other: URI): boolean { 102 return this.uricalss.equals(other.uricalss); 103 } 104 105 equalsTo(other: URI): boolean { 106 if (other instanceof URI) { 107 return this.uricalss.equals(other.uricalss); 108 } 109 throw new BusinessError(`Parameter error. The type of ${other} must be URI`); 110 } 111 112 checkIsAbsolute(): boolean { 113 return this.uricalss.checkIsAbsolute(); 114 } 115 116 checkRelative(): boolean { 117 return this.uricalss.checkIsRelative(); 118 } 119 120 checkOpaque(): boolean { 121 return this.uricalss.checkIsOpaque(); 122 } 123 124 checkHierarchical(): boolean { 125 return this.uricalss.checkIsHierarchical(); 126 } 127 128 addQueryValue(key: string, value: string): URI { 129 if (key === null || typeof key !== 'string') { 130 throw new BusinessError(`Parameter error. The type of ${key} must be string`); 131 } 132 if (value === null || typeof value !== 'string') { 133 throw new BusinessError(`Parameter error. The type of ${value} must be string`); 134 } 135 let uriStr = this.uricalss.addQueryValue(encodeURIComponent(key), encodeURIComponent(value)); 136 return createNewUri(uriStr); 137 } 138 139 addEncodedSegment(pathSegment: string): URI { 140 if (pathSegment === null || typeof pathSegment !== 'string') { 141 throw new BusinessError(`Parameter error. The type of ${pathSegment} must be string`); 142 } 143 let uriStr: string = this.uricalss.addSegment(pathSegment); 144 return createNewUri(uriStr); 145 } 146 147 addSegment(pathSegment: string): URI { 148 if (pathSegment === null || typeof pathSegment !== 'string') { 149 throw new BusinessError(`Parameter error. The type of ${pathSegment} must be string`); 150 } 151 let uriStr = this.uricalss.addSegment(encodeURIComponent(pathSegment)); 152 return createNewUri(uriStr); 153 } 154 155 getQueryValue(key: string): string | null { 156 if (key === null || typeof key !== 'string') { 157 throw new BusinessError(`Parameter error. The type of ${key} must be string`); 158 } 159 let value: string | null = null; 160 if (this.uricalss.query === null) { 161 return null; 162 } 163 let queryStrs: string[] = this.uricalss.query.split('&') || []; 164 for (let item of queryStrs) { 165 if (key === '' && item === '') { 166 return ''; 167 } 168 let str = item.split('=') || []; 169 if (str.length === 1 && this.decodeSafelyInner(str[0]) === key) { 170 return ''; 171 } else if (this.decodeSafelyInner(str[0]) === key) { 172 return this.decodeSafelyInner(item.substring(str[0].length + 1).replace(/\+/g, ' ')); 173 } 174 } 175 return value; 176 } 177 178 decodeSafelyOut(input: string): string { 179 let decodedString: string = ''; 180 let decodedTemp: string = ''; 181 let index: number = 0; 182 while (index < input.length) { 183 if (input[index] === '%' && /[0-9A-Fa-f]{2}/.test(input.slice(index + 1, index + 3))) { 184 const encodedChar = input.slice(index, index + 3); 185 try { 186 decodedString += decodeURIComponent(decodedTemp + encodedChar); 187 decodedTemp = ''; 188 } catch (e) { 189 decodedTemp += encodedChar; 190 } 191 index += 3; 192 continue; 193 } 194 if (decodedTemp === '') { 195 decodedString += input[index]; 196 } else { 197 decodedString += decodedTemp; 198 decodedString += input[index]; 199 decodedTemp = ''; 200 } 201 index++; 202 } 203 return decodedTemp === '' ? decodedString : decodedString += decodedTemp; 204 } 205 206 decodeSafelyInner(input: string): string { 207 if (input === undefined || input === '') { 208 return input; 209 } 210 let strVal: string = ''; 211 try { 212 strVal = decodeURIComponent(input); 213 } catch (e) { 214 strVal = this.decodeSafelyOut(input); 215 } 216 return strVal; 217 } 218 219 getQueryNames(): string[] { 220 let names: Set<string> = new Set<string>(); 221 if (this.uricalss.query === null) { 222 return []; 223 } 224 let start: number = 0; 225 while (start < this.uricalss.query.length) { 226 let next: number = this.uricalss.query.indexOf('&', start); 227 let end: number = (next === -1) ? this.uricalss.query.length : next; 228 let separator: number = this.uricalss.query.indexOf('=', start); 229 if (separator > end || separator === -1) { 230 separator = end; 231 } 232 let name: string = this.uricalss.query.substring(start, separator); 233 names.add(this.decodeSafelyInner(name)); 234 start = end + 1; 235 } 236 return Array.from(names); 237 } 238 239 getQueryValues(key: string): string[] { 240 if (key === null || typeof key !== 'string') { 241 throw new BusinessError(`Parameter error. The type of ${key} must be string`); 242 } 243 let values = new Array(); 244 if (this.uricalss.query === null) { 245 return values; 246 } 247 let queryStrs: string[] = this.uricalss.query.split('&') || []; 248 for (let item of queryStrs) { 249 if (key === '' && item === '') { 250 values.push(item); 251 } 252 let str = item.split('=') || []; 253 if (str.length === 1 && this.decodeSafelyInner(str[0]) === key) { 254 values.push(''); 255 } else if (this.decodeSafelyInner(str[0]) === key) { 256 values.push(this.decodeSafelyInner(item.substring(str[0].length + 1))); 257 } 258 } 259 return values; 260 } 261 262 getBooleanQueryValue(key: string, defaultValue: boolean): boolean { 263 if (key === null || typeof key !== 'string') { 264 throw new BusinessError(`Parameter error. The type of ${key} must be string`); 265 } 266 if (defaultValue === null || typeof defaultValue !== 'boolean') { 267 throw new BusinessError(`Parameter error. The type of ${key} must be boolean`); 268 } 269 let flag = this.getQueryValue(key); 270 if (flag == null) { 271 return defaultValue; 272 } 273 flag = flag.toLocaleLowerCase(); 274 return 'false' !== flag && '0' !== flag; 275 } 276 277 getLastSegment(): string { 278 let segments = this.uricalss.getSegment(); 279 if (!segments) { 280 return ''; 281 } 282 return this.decodeSafelyInner(segments[segments.length - 1]); 283 } 284 285 getSegment(): string[] { 286 let array = new Array(); 287 let segments = this.uricalss.getSegment(); 288 if (segments) { 289 segments.forEach(element => { 290 array.push(this.decodeSafelyInner(element)); 291 }); 292 } 293 return array; 294 } 295 296 clearQuery(): URI { 297 let uriStr: string = this.uricalss.clearQuery(); 298 return createNewUri(uriStr); 299 } 300 301 normalize(): URI { 302 let uriStr: string = this.uricalss.normalize(); 303 return createNewUri(uriStr); 304 } 305 306 get scheme(): string | null { 307 return this.uricalss.scheme; 308 } 309 310 get authority(): string | null { 311 if (this.uricalss.authority === null) { 312 return null; 313 } 314 let thisAuthority: string = this.uricalss.authority; 315 if (thisAuthority.indexOf('[') !== -1) { 316 let arr: string[] = thisAuthority.split('['); 317 let brr: string[] = arr[1].split(']'); 318 arr[1] = '[' + brr[0] + ']'; 319 arr[2] = brr[1]; 320 arr[0] = this.decodeSafelyInner(arr[0]); 321 arr[2] = this.decodeSafelyInner(arr[2]); 322 return arr.join(''); 323 } else { 324 return this.decodeSafelyInner(thisAuthority); 325 } 326 } 327 328 get ssp(): string { 329 let thisSsp: string = this.uricalss.ssp; 330 if (thisSsp.indexOf('[') !== -1) { 331 let arr: string[] = thisSsp.split('['); 332 let brr: string[] = arr[1].split(']'); 333 arr[1] = '[' + brr[0] + ']'; 334 arr[2] = brr[1]; 335 arr[0] = this.decodeSafelyInner(arr[0]); 336 arr[2] = this.decodeSafelyInner(arr[2]); 337 return arr.join(''); 338 } else { 339 return this.decodeSafelyInner(thisSsp); 340 } 341 } 342 343 get userInfo(): string | null { 344 return this.uricalss.userInfo === null ? null : this.decodeSafelyInner(this.uricalss.userInfo); 345 } 346 347 get host(): string | null { 348 return this.uricalss.host; 349 } 350 351 get port(): string { 352 return this.uricalss.port; 353 } 354 355 get path(): string | null { 356 return this.uricalss.path === null ? null : this.decodeSafelyInner(this.uricalss.path); 357 } 358 359 get query(): string | null { 360 return this.uricalss.query === null ? null : this.decodeSafelyInner(this.uricalss.query); 361 } 362 363 get fragment(): string | null { 364 return this.uricalss.fragment === null ? null : this.decodeSafelyInner(this.uricalss.fragment); 365 } 366 367 get encodedUserInfo(): string | null { 368 return this.uricalss.userInfo; 369 } 370 371 get encodedPath(): string | null { 372 return this.uricalss.path; 373 } 374 375 get encodedQuery(): string | null { 376 return this.uricalss.query; 377 } 378 379 get encodedFragment(): string | null { 380 return this.uricalss.fragment; 381 } 382 383 get encodedAuthority(): string | null { 384 if (this.uricalss.authority === null) { 385 return null; 386 } 387 let thisAuthority: string = this.uricalss.authority; 388 if (thisAuthority.indexOf('[') !== -1) { 389 let arr: string[] = thisAuthority.split('['); 390 let brr: string[] = arr[1].split(']'); 391 arr[1] = '[' + brr[0] + ']'; 392 arr[2] = brr[1]; 393 return arr.join(''); 394 } else { 395 return thisAuthority; 396 } 397 } 398 399 get encodedSSP(): string { 400 let thisSsp: string = this.uricalss.ssp; 401 if (thisSsp.indexOf('[') !== -1) { 402 let arr: string[] = thisSsp.split('['); 403 let brr: string[] = arr[1].split(']'); 404 arr[1] = '[' + brr[0] + ']'; 405 arr[2] = brr[1]; 406 return arr.join(''); 407 } else { 408 return thisSsp; 409 } 410 } 411} 412 413function toAscllString(uriStr: string): string { 414 return encodeURI(uriStr).replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/%25/g, '%'); 415} 416 417function createNewUri(uriStr: string): URI { 418 return new URI(uriStr); 419} 420 421export default { 422 URI: URI 423};