@pactflow/openapi-pact-comparator 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -883,6 +883,18 @@ function overRest(func, start, transform) {
883
883
  };
884
884
  }
885
885
 
886
+ /**
887
+ * The base implementation of `_.rest` which doesn't validate or coerce arguments.
888
+ *
889
+ * @private
890
+ * @param {Function} func The function to apply a rest parameter to.
891
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
892
+ * @returns {Function} Returns the new function.
893
+ */
894
+ function baseRest(func, start) {
895
+ return setToString(overRest(func, start, identity), func + '');
896
+ }
897
+
886
898
  /** Used as references for various `Number` constants. */
887
899
  var MAX_SAFE_INTEGER = 9007199254740991;
888
900
 
@@ -946,6 +958,63 @@ function isArrayLike(value) {
946
958
  return value != null && isLength(value.length) && !isFunction(value);
947
959
  }
948
960
 
961
+ /**
962
+ * Checks if the given arguments are from an iteratee call.
963
+ *
964
+ * @private
965
+ * @param {*} value The potential iteratee value argument.
966
+ * @param {*} index The potential iteratee index or key argument.
967
+ * @param {*} object The potential iteratee object argument.
968
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
969
+ * else `false`.
970
+ */
971
+ function isIterateeCall(value, index, object) {
972
+ if (!isObject(object)) {
973
+ return false;
974
+ }
975
+ var type = typeof index;
976
+ if (type == 'number'
977
+ ? (isArrayLike(object) && isIndex(index, object.length))
978
+ : (type == 'string' && index in object)
979
+ ) {
980
+ return eq(object[index], value);
981
+ }
982
+ return false;
983
+ }
984
+
985
+ /**
986
+ * Creates a function like `_.assign`.
987
+ *
988
+ * @private
989
+ * @param {Function} assigner The function to assign values.
990
+ * @returns {Function} Returns the new assigner function.
991
+ */
992
+ function createAssigner(assigner) {
993
+ return baseRest(function(object, sources) {
994
+ var index = -1,
995
+ length = sources.length,
996
+ customizer = length > 1 ? sources[length - 1] : undefined,
997
+ guard = length > 2 ? sources[2] : undefined;
998
+
999
+ customizer = (assigner.length > 3 && typeof customizer == 'function')
1000
+ ? (length--, customizer)
1001
+ : undefined;
1002
+
1003
+ if (guard && isIterateeCall(sources[0], sources[1], guard)) {
1004
+ customizer = length < 3 ? undefined : customizer;
1005
+ length = 1;
1006
+ }
1007
+ object = Object(object);
1008
+ while (++index < length) {
1009
+ var source = sources[index];
1010
+ if (source) {
1011
+ assigner(object, source, index, customizer);
1012
+ }
1013
+ }
1014
+ return object;
1015
+ });
1016
+ }
1017
+
949
1018
  /** Used for built-in method references. */
950
1019
  var objectProto$9 = Object.prototype;
951
1020
 
@@ -3177,6 +3246,209 @@ function createBaseEach(eachFunc, fromRight) {
3177
3246
  */
3178
3247
  var baseEach = createBaseEach(baseForOwn);
3179
3248
 
3249
+ /**
3250
+ * This function is like `assignValue` except that it doesn't assign
3251
+ * `undefined` values.
3252
+ *
3253
+ * @private
3254
+ * @param {Object} object The object to modify.
3255
+ * @param {string} key The key of the property to assign.
3256
+ * @param {*} value The value to assign.
3257
+ */
3258
+ function assignMergeValue(object, key, value) {
3259
+ if ((value !== undefined && !eq(object[key], value)) ||
3260
+ (value === undefined && !(key in object))) {
3261
+ baseAssignValue(object, key, value);
3262
+ }
3263
+ }
3264
+
3265
+ /**
3266
+ * This method is like `_.isArrayLike` except that it also checks if `value`
3267
+ * is an object.
3268
+ *
3269
+ * @static
3270
+ * @memberOf _
3271
+ * @since 4.0.0
3272
+ * @category Lang
3273
+ * @param {*} value The value to check.
3274
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
3275
+ * else `false`.
3276
+ * @example
3277
+ *
3278
+ * _.isArrayLikeObject([1, 2, 3]);
3279
+ * // => true
3280
+ *
3281
+ * _.isArrayLikeObject(document.body.children);
3282
+ * // => true
3283
+ *
3284
+ * _.isArrayLikeObject('abc');
3285
+ * // => false
3286
+ *
3287
+ * _.isArrayLikeObject(_.noop);
3288
+ * // => false
3289
+ */
3290
+ function isArrayLikeObject(value) {
3291
+ return isObjectLike(value) && isArrayLike(value);
3292
+ }
3293
+
3294
+ /**
3295
+ * Gets the value at `key`, unless `key` is "__proto__" or "constructor".
3296
+ *
3297
+ * @private
3298
+ * @param {Object} object The object to query.
3299
+ * @param {string} key The key of the property to get.
3300
+ * @returns {*} Returns the property value.
3301
+ */
3302
+ function safeGet(object, key) {
3303
+ if (key === 'constructor' && typeof object[key] === 'function') {
3304
+ return;
3305
+ }
3306
+
3307
+ if (key == '__proto__') {
3308
+ return;
3309
+ }
3310
+
3311
+ return object[key];
3312
+ }
3313
+
3314
+ /**
3315
+ * Converts `value` to a plain object flattening inherited enumerable string
3316
+ * keyed properties of `value` to own properties of the plain object.
3317
+ *
3318
+ * @static
3319
+ * @memberOf _
3320
+ * @since 3.0.0
3321
+ * @category Lang
3322
+ * @param {*} value The value to convert.
3323
+ * @returns {Object} Returns the converted plain object.
3324
+ * @example
3325
+ *
3326
+ * function Foo() {
3327
+ * this.b = 2;
3328
+ * }
3329
+ *
3330
+ * Foo.prototype.c = 3;
3331
+ *
3332
+ * _.assign({ 'a': 1 }, new Foo);
3333
+ * // => { 'a': 1, 'b': 2 }
3334
+ *
3335
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
3336
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
3337
+ */
3338
+ function toPlainObject(value) {
3339
+ return copyObject(value, keysIn(value));
3340
+ }
3341
+
3342
+ /**
3343
+ * A specialized version of `baseMerge` for arrays and objects which performs
3344
+ * deep merges and tracks traversed objects enabling objects with circular
3345
+ * references to be merged.
3346
+ *
3347
+ * @private
3348
+ * @param {Object} object The destination object.
3349
+ * @param {Object} source The source object.
3350
+ * @param {string} key The key of the value to merge.
3351
+ * @param {number} srcIndex The index of `source`.
3352
+ * @param {Function} mergeFunc The function to merge values.
3353
+ * @param {Function} [customizer] The function to customize assigned values.
3354
+ * @param {Object} [stack] Tracks traversed source values and their merged
3355
+ * counterparts.
3356
+ */
3357
+ function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
3358
+ var objValue = safeGet(object, key),
3359
+ srcValue = safeGet(source, key),
3360
+ stacked = stack.get(srcValue);
3361
+
3362
+ if (stacked) {
3363
+ assignMergeValue(object, key, stacked);
3364
+ return;
3365
+ }
3366
+ var newValue = customizer
3367
+ ? customizer(objValue, srcValue, (key + ''), object, source, stack)
3368
+ : undefined;
3369
+
3370
+ var isCommon = newValue === undefined;
3371
+
3372
+ if (isCommon) {
3373
+ var isArr = isArray(srcValue),
3374
+ isBuff = !isArr && isBuffer(srcValue),
3375
+ isTyped = !isArr && !isBuff && isTypedArray(srcValue);
3376
+
3377
+ newValue = srcValue;
3378
+ if (isArr || isBuff || isTyped) {
3379
+ if (isArray(objValue)) {
3380
+ newValue = objValue;
3381
+ }
3382
+ else if (isArrayLikeObject(objValue)) {
3383
+ newValue = copyArray(objValue);
3384
+ }
3385
+ else if (isBuff) {
3386
+ isCommon = false;
3387
+ newValue = cloneBuffer(srcValue, true);
3388
+ }
3389
+ else if (isTyped) {
3390
+ isCommon = false;
3391
+ newValue = cloneTypedArray(srcValue, true);
3392
+ }
3393
+ else {
3394
+ newValue = [];
3395
+ }
3396
+ }
3397
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
3398
+ newValue = objValue;
3399
+ if (isArguments(objValue)) {
3400
+ newValue = toPlainObject(objValue);
3401
+ }
3402
+ else if (!isObject(objValue) || isFunction(objValue)) {
3403
+ newValue = initCloneObject(srcValue);
3404
+ }
3405
+ }
3406
+ else {
3407
+ isCommon = false;
3408
+ }
3409
+ }
3410
+ if (isCommon) {
3411
+ // Recursively merge objects and arrays (susceptible to call stack limits).
3412
+ stack.set(srcValue, newValue);
3413
+ mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
3414
+ stack['delete'](srcValue);
3415
+ }
3416
+ assignMergeValue(object, key, newValue);
3417
+ }
3418
+
3419
+ /**
3420
+ * The base implementation of `_.merge` without support for multiple sources.
3421
+ *
3422
+ * @private
3423
+ * @param {Object} object The destination object.
3424
+ * @param {Object} source The source object.
3425
+ * @param {number} srcIndex The index of `source`.
3426
+ * @param {Function} [customizer] The function to customize merged values.
3427
+ * @param {Object} [stack] Tracks traversed source values and their merged
3428
+ * counterparts.
3429
+ */
3430
+ function baseMerge(object, source, srcIndex, customizer, stack) {
3431
+ if (object === source) {
3432
+ return;
3433
+ }
3434
+ baseFor(source, function(srcValue, key) {
3435
+ stack || (stack = new Stack);
3436
+ if (isObject(srcValue)) {
3437
+ baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
3438
+ }
3439
+ else {
3440
+ var newValue = customizer
3441
+ ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)
3442
+ : undefined;
3443
+
3444
+ if (newValue === undefined) {
3445
+ newValue = srcValue;
3446
+ }
3447
+ assignMergeValue(object, key, newValue);
3448
+ }
3449
+ }, keysIn);
3450
+ }
3451
+
3180
3452
  /**
3181
3453
  * This function is like `arrayIncludes` except that it accepts a comparator.
3182
3454
  *
@@ -3275,6 +3547,41 @@ function parent(object, path) {
3275
3547
  return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
3276
3548
  }
3277
3549
 
3550
+ /**
3551
+ * This method is like `_.assign` except that it recursively merges own and
3552
+ * inherited enumerable string keyed properties of source objects into the
3553
+ * destination object. Source properties that resolve to `undefined` are
3554
+ * skipped if a destination value exists. Array and plain object properties
3555
+ * are merged recursively. Other objects and value types are overridden by
3556
+ * assignment. Source objects are applied from left to right. Subsequent
3557
+ * sources overwrite property assignments of previous sources.
3558
+ *
3559
+ * **Note:** This method mutates `object`.
3560
+ *
3561
+ * @static
3562
+ * @memberOf _
3563
+ * @since 0.5.0
3564
+ * @category Object
3565
+ * @param {Object} object The destination object.
3566
+ * @param {...Object} [sources] The source objects.
3567
+ * @returns {Object} Returns `object`.
3568
+ * @example
3569
+ *
3570
+ * var object = {
3571
+ * 'a': [{ 'b': 2 }, { 'd': 4 }]
3572
+ * };
3573
+ *
3574
+ * var other = {
3575
+ * 'a': [{ 'c': 3 }, { 'e': 5 }]
3576
+ * };
3577
+ *
3578
+ * _.merge(object, other);
3579
+ * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
3580
+ */
3581
+ var merge = createAssigner(function(object, source, srcIndex) {
3582
+ baseMerge(object, source, srcIndex);
3583
+ });
3584
+
3278
3585
  /**
3279
3586
  * The base implementation of `_.unset`.
3280
3587
  *
@@ -3591,22 +3898,6 @@ const traverseWithDereferencing = (schema, visitor) => {
3591
3898
  _traverseWithDereferencing(schema, schema, [], visitor);
3592
3899
  };
3593
3900
 
3594
- const transformRequestSchema = (schema) => {
3595
- // OpenAPI defines allOf to mean the union of all sub-schemas. JSON-Schema
3596
- // defines allOf to mean that *every* sub-schema needs to be satisfied. In
3597
- // draft 2019-09, JSON-Schema added "unevaluatedProperties" to support this
3598
- // behaviour
3599
- traverseWithDereferencing(schema, (s) => {
3600
- if (s.allOf) {
3601
- forEach(s.allOf, (ss) => {
3602
- delete ss.additionalProperties;
3603
- });
3604
- s.unevaluatedProperties = false;
3605
- }
3606
- });
3607
- return schema;
3608
- };
3609
-
3610
3901
  const transformResponseSchema = (schema, noTransformNonNullableResponseSchema) => {
3611
3902
  // a provider must provide a superset of what the consumer asks for
3612
3903
  // additionalProperties expected in pact response are disallowed
@@ -3630,30 +3921,62 @@ const transformResponseSchema = (schema, noTransformNonNullableResponseSchema) =
3630
3921
  }
3631
3922
  delete s.required;
3632
3923
  });
3633
- // OpenAPI defines allOf to mean the union of all sub-schemas. JSON-Schema
3634
- // defines allOf to mean that *every* sub-schema needs to be satisfied. In
3635
- // draft 2019-09, JSON-Schema added "unevaluatedProperties" to support this
3636
- // behaviour
3637
- traverseWithDereferencing(schema, (s) => {
3638
- if (s.allOf) {
3639
- forEach(s.allOf, (ss) => {
3640
- let subschema = ss;
3641
- if (subschema.$ref) {
3642
- subschema = get$1(schema, splitPath(subschema.$ref));
3643
- }
3644
- delete subschema.additionalProperties;
3645
- if (subschema.allOf) {
3646
- // traversal is depth-first; if nested allOf, remove
3647
- // unevaluatedProperties from previously set deeper schema
3648
- delete subschema.unevaluatedProperties;
3649
- }
3650
- });
3651
- s.unevaluatedProperties = false;
3652
- }
3653
- });
3654
3924
  return schema;
3655
3925
  };
3656
3926
 
3927
+ function _flat(s, root) {
3928
+ if (s.allOf) {
3929
+ const { allOf, ...others } = s;
3930
+ return merge(others, ...allOf.map((ss) => {
3931
+ let dereferenced;
3932
+ if (ss.$ref) {
3933
+ const { $ref, ...others } = ss;
3934
+ dereferenced = {
3935
+ ...others,
3936
+ ...get$1(root, splitPath($ref)),
3937
+ };
3938
+ }
3939
+ return _flat(dereferenced || ss, root);
3940
+ }));
3941
+ }
3942
+ if (s.properties) {
3943
+ for (const ss in s.properties) {
3944
+ s.properties[ss] = _flat(s.properties[ss], root);
3945
+ }
3946
+ return s;
3947
+ }
3948
+ for (const key of [
3949
+ "oneOf",
3950
+ "anyOf",
3951
+ "not",
3952
+ "items",
3953
+ "additionalProperties",
3954
+ ]) {
3955
+ if (s[key]) {
3956
+ return {
3957
+ ...s,
3958
+ [key]: Array.isArray(s[key])
3959
+ ? s[key].map((ss) => _flat(ss, root))
3960
+ : _flat(s[key], root),
3961
+ };
3962
+ }
3963
+ }
3964
+ return s;
3965
+ }
3966
+ // OpenAPI defines allOf to mean the union of all sub-schemas. JSON-Schema
3967
+ // defines allOf to mean that *every* sub-schema needs to be satisfied.
3968
+ // To handle the difference, we flatten 'allOf'
3969
+ function flattenAllOf(s, refs) {
3970
+ // main schema
3971
+ const flattened = _flat(s, s);
3972
+ // any other references
3973
+ for (const ref of refs) {
3974
+ const path = splitPath(ref);
3975
+ set(flattened, path, _flat(get$1(s, path), s));
3976
+ }
3977
+ return flattened;
3978
+ }
3979
+
3657
3980
  // draft-06 onwards converts exclusiveMinimum and exclusiveMaximum to numbers
3658
3981
  const convertExclusiveMinMax = (s) => {
3659
3982
  if (s.exclusiveMaximum === true) {
@@ -3716,12 +4039,13 @@ const minimumSchema = (originalSchema, oas) => {
3716
4039
  const subschema = cloneDeep(get$1(oas, path, {}));
3717
4040
  delete subschema.description;
3718
4041
  delete subschema.example;
4042
+ traverse(subschema, cleanupDiscriminators);
3719
4043
  traverse(subschema, collectReferences);
3720
4044
  traverse(subschema, handleNullableSchema);
3721
4045
  traverse(subschema, convertExclusiveMinMax);
3722
4046
  set(schema, path, subschema);
3723
4047
  }
3724
- return schema;
4048
+ return flattenAllOf(schema, refAdded);
3725
4049
  };
3726
4050
 
3727
4051
  const isSimpleSchema = (s, oas) => {
@@ -7335,7 +7659,7 @@ function* compareReqBody(ajv, route, interaction, index, config) {
7335
7659
  : true)) {
7336
7660
  const value = parseBody(body, requestContentType, config.get("legacy-parser"));
7337
7661
  const schemaId = `[root].paths.${path}.${method}.requestBody.content.${contentType}`;
7338
- const validate = getValidateFunction(ajv, schemaId, () => transformRequestSchema(minimumSchema(schema, oas)));
7662
+ const validate = getValidateFunction(ajv, schemaId, () => minimumSchema(schema, oas));
7339
7663
  if (!validate(value)) {
7340
7664
  for (const error of validate.errors) {
7341
7665
  yield {
@@ -15168,44 +15492,6 @@ var uri = {};
15168
15492
 
15169
15493
  var fastUri = {exports: {}};
15170
15494
 
15171
- var scopedChars;
15172
- var hasRequiredScopedChars;
15173
-
15174
- function requireScopedChars () {
15175
- if (hasRequiredScopedChars) return scopedChars;
15176
- hasRequiredScopedChars = 1;
15177
-
15178
- const HEX = {
15179
- 0: 0,
15180
- 1: 1,
15181
- 2: 2,
15182
- 3: 3,
15183
- 4: 4,
15184
- 5: 5,
15185
- 6: 6,
15186
- 7: 7,
15187
- 8: 8,
15188
- 9: 9,
15189
- a: 10,
15190
- A: 10,
15191
- b: 11,
15192
- B: 11,
15193
- c: 12,
15194
- C: 12,
15195
- d: 13,
15196
- D: 13,
15197
- e: 14,
15198
- E: 14,
15199
- f: 15,
15200
- F: 15
15201
- };
15202
-
15203
- scopedChars = {
15204
- HEX
15205
- };
15206
- return scopedChars;
15207
- }
15208
-
15209
15495
  var utils;
15210
15496
  var hasRequiredUtils;
15211
15497
 
@@ -15213,62 +15499,100 @@ function requireUtils () {
15213
15499
  if (hasRequiredUtils) return utils;
15214
15500
  hasRequiredUtils = 1;
15215
15501
 
15216
- const { HEX } = requireScopedChars();
15502
+ /** @type {(value: string) => boolean} */
15503
+ const isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
15217
15504
 
15218
- const IPV4_REG = /^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u;
15505
+ /** @type {(value: string) => boolean} */
15506
+ const isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
15219
15507
 
15220
- function normalizeIPv4 (host) {
15221
- if (findToken(host, '.') < 3) { return { host, isIPV4: false } }
15222
- const matches = host.match(IPV4_REG) || [];
15223
- const [address] = matches;
15224
- if (address) {
15225
- return { host: stripLeadingZeros(address, '.'), isIPV4: true }
15226
- } else {
15227
- return { host, isIPV4: false }
15508
+ /**
15509
+ * @param {Array<string>} input
15510
+ * @returns {string}
15511
+ */
15512
+ function stringArrayToHexStripped (input) {
15513
+ let acc = '';
15514
+ let code = 0;
15515
+ let i = 0;
15516
+
15517
+ for (i = 0; i < input.length; i++) {
15518
+ code = input[i].charCodeAt(0);
15519
+ if (code === 48) {
15520
+ continue
15521
+ }
15522
+ if (!((code >= 48 && code <= 57) || (code >= 65 && code <= 70) || (code >= 97 && code <= 102))) {
15523
+ return ''
15524
+ }
15525
+ acc += input[i];
15526
+ break
15527
+ }
15528
+
15529
+ for (i += 1; i < input.length; i++) {
15530
+ code = input[i].charCodeAt(0);
15531
+ if (!((code >= 48 && code <= 57) || (code >= 65 && code <= 70) || (code >= 97 && code <= 102))) {
15532
+ return ''
15533
+ }
15534
+ acc += input[i];
15228
15535
  }
15536
+ return acc
15229
15537
  }
15230
15538
 
15231
15539
  /**
15232
- * @param {string[]} input
15233
- * @param {boolean} [keepZero=false]
15234
- * @returns {string|undefined}
15540
+ * @typedef {Object} GetIPV6Result
15541
+ * @property {boolean} error - Indicates if there was an error parsing the IPv6 address.
15542
+ * @property {string} address - The parsed IPv6 address.
15543
+ * @property {string} [zone] - The zone identifier, if present.
15235
15544
  */
15236
- function stringArrayToHexStripped (input, keepZero = false) {
15237
- let acc = '';
15238
- let strip = true;
15239
- for (const c of input) {
15240
- if (HEX[c] === undefined) return undefined
15241
- if (c !== '0' && strip === true) strip = false;
15242
- if (!strip) acc += c;
15545
+
15546
+ /**
15547
+ * @param {string} value
15548
+ * @returns {boolean}
15549
+ */
15550
+ const nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
15551
+
15552
+ /**
15553
+ * @param {Array<string>} buffer
15554
+ * @returns {boolean}
15555
+ */
15556
+ function consumeIsZone (buffer) {
15557
+ buffer.length = 0;
15558
+ return true
15559
+ }
15560
+
15561
+ /**
15562
+ * @param {Array<string>} buffer
15563
+ * @param {Array<string>} address
15564
+ * @param {GetIPV6Result} output
15565
+ * @returns {boolean}
15566
+ */
15567
+ function consumeHextets (buffer, address, output) {
15568
+ if (buffer.length) {
15569
+ const hex = stringArrayToHexStripped(buffer);
15570
+ if (hex !== '') {
15571
+ address.push(hex);
15572
+ } else {
15573
+ output.error = true;
15574
+ return false
15575
+ }
15576
+ buffer.length = 0;
15243
15577
  }
15244
- if (keepZero && acc.length === 0) acc = '0';
15245
- return acc
15578
+ return true
15246
15579
  }
15247
15580
 
15581
+ /**
15582
+ * @param {string} input
15583
+ * @returns {GetIPV6Result}
15584
+ */
15248
15585
  function getIPV6 (input) {
15249
15586
  let tokenCount = 0;
15250
15587
  const output = { error: false, address: '', zone: '' };
15588
+ /** @type {Array<string>} */
15251
15589
  const address = [];
15590
+ /** @type {Array<string>} */
15252
15591
  const buffer = [];
15253
- let isZone = false;
15254
15592
  let endipv6Encountered = false;
15255
15593
  let endIpv6 = false;
15256
15594
 
15257
- function consume () {
15258
- if (buffer.length) {
15259
- if (isZone === false) {
15260
- const hex = stringArrayToHexStripped(buffer);
15261
- if (hex !== undefined) {
15262
- address.push(hex);
15263
- } else {
15264
- output.error = true;
15265
- return false
15266
- }
15267
- }
15268
- buffer.length = 0;
15269
- }
15270
- return true
15271
- }
15595
+ let consume = consumeHextets;
15272
15596
 
15273
15597
  for (let i = 0; i < input.length; i++) {
15274
15598
  const cursor = input[i];
@@ -15277,29 +15601,28 @@ function requireUtils () {
15277
15601
  if (endipv6Encountered === true) {
15278
15602
  endIpv6 = true;
15279
15603
  }
15280
- if (!consume()) { break }
15281
- tokenCount++;
15282
- address.push(':');
15283
- if (tokenCount > 7) {
15604
+ if (!consume(buffer, address, output)) { break }
15605
+ if (++tokenCount > 7) {
15284
15606
  // not valid
15285
15607
  output.error = true;
15286
15608
  break
15287
15609
  }
15288
- if (i - 1 >= 0 && input[i - 1] === ':') {
15610
+ if (i > 0 && input[i - 1] === ':') {
15289
15611
  endipv6Encountered = true;
15290
15612
  }
15613
+ address.push(':');
15291
15614
  continue
15292
15615
  } else if (cursor === '%') {
15293
- if (!consume()) { break }
15616
+ if (!consume(buffer, address, output)) { break }
15294
15617
  // switch to zone detection
15295
- isZone = true;
15618
+ consume = consumeIsZone;
15296
15619
  } else {
15297
15620
  buffer.push(cursor);
15298
15621
  continue
15299
15622
  }
15300
15623
  }
15301
15624
  if (buffer.length) {
15302
- if (isZone) {
15625
+ if (consume === consumeIsZone) {
15303
15626
  output.zone = buffer.join('');
15304
15627
  } else if (endIpv6) {
15305
15628
  address.push(buffer.join(''));
@@ -15311,6 +15634,17 @@ function requireUtils () {
15311
15634
  return output
15312
15635
  }
15313
15636
 
15637
+ /**
15638
+ * @typedef {Object} NormalizeIPv6Result
15639
+ * @property {string} host - The normalized host.
15640
+ * @property {string} [escapedHost] - The escaped host.
15641
+ * @property {boolean} isIPV6 - Indicates if the host is an IPv6 address.
15642
+ */
15643
+
15644
+ /**
15645
+ * @param {string} host
15646
+ * @returns {NormalizeIPv6Result}
15647
+ */
15314
15648
  function normalizeIPv6 (host) {
15315
15649
  if (findToken(host, ':') < 2) { return { host, isIPV6: false } }
15316
15650
  const ipv6 = getIPV6(host);
@@ -15322,35 +15656,17 @@ function requireUtils () {
15322
15656
  newHost += '%' + ipv6.zone;
15323
15657
  escapedHost += '%25' + ipv6.zone;
15324
15658
  }
15325
- return { host: newHost, escapedHost, isIPV6: true }
15659
+ return { host: newHost, isIPV6: true, escapedHost }
15326
15660
  } else {
15327
15661
  return { host, isIPV6: false }
15328
15662
  }
15329
15663
  }
15330
15664
 
15331
- function stripLeadingZeros (str, token) {
15332
- let out = '';
15333
- let skip = true;
15334
- const l = str.length;
15335
- for (let i = 0; i < l; i++) {
15336
- const c = str[i];
15337
- if (c === '0' && skip) {
15338
- if ((i + 1 <= l && str[i + 1] === token) || i + 1 === l) {
15339
- out += c;
15340
- skip = false;
15341
- }
15342
- } else {
15343
- if (c === token) {
15344
- skip = true;
15345
- } else {
15346
- skip = false;
15347
- }
15348
- out += c;
15349
- }
15350
- }
15351
- return out
15352
- }
15353
-
15665
+ /**
15666
+ * @param {string} str
15667
+ * @param {string} token
15668
+ * @returns {number}
15669
+ */
15354
15670
  function findToken (str, token) {
15355
15671
  let ind = 0;
15356
15672
  for (let i = 0; i < str.length; i++) {
@@ -15359,98 +15675,160 @@ function requireUtils () {
15359
15675
  return ind
15360
15676
  }
15361
15677
 
15362
- const RDS1 = /^\.\.?\//u;
15363
- const RDS2 = /^\/\.(?:\/|$)/u;
15364
- const RDS3 = /^\/\.\.(?:\/|$)/u;
15365
- const RDS5 = /^\/?(?:.|\n)*?(?=\/|$)/u;
15366
-
15367
- function removeDotSegments (input) {
15678
+ /**
15679
+ * @param {string} path
15680
+ * @returns {string}
15681
+ *
15682
+ * @see https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
15683
+ */
15684
+ function removeDotSegments (path) {
15685
+ let input = path;
15368
15686
  const output = [];
15687
+ let nextSlash = -1;
15688
+ let len = 0;
15369
15689
 
15370
- while (input.length) {
15371
- if (input.match(RDS1)) {
15372
- input = input.replace(RDS1, '');
15373
- } else if (input.match(RDS2)) {
15374
- input = input.replace(RDS2, '/');
15375
- } else if (input.match(RDS3)) {
15376
- input = input.replace(RDS3, '/');
15377
- output.pop();
15378
- } else if (input === '.' || input === '..') {
15379
- input = '';
15380
- } else {
15381
- const im = input.match(RDS5);
15382
- if (im) {
15383
- const s = im[0];
15384
- input = input.slice(s.length);
15385
- output.push(s);
15690
+ // eslint-disable-next-line no-cond-assign
15691
+ while (len = input.length) {
15692
+ if (len === 1) {
15693
+ if (input === '.') {
15694
+ break
15695
+ } else if (input === '/') {
15696
+ output.push('/');
15697
+ break
15386
15698
  } else {
15387
- throw new Error('Unexpected dot segment condition')
15699
+ output.push(input);
15700
+ break
15701
+ }
15702
+ } else if (len === 2) {
15703
+ if (input[0] === '.') {
15704
+ if (input[1] === '.') {
15705
+ break
15706
+ } else if (input[1] === '/') {
15707
+ input = input.slice(2);
15708
+ continue
15709
+ }
15710
+ } else if (input[0] === '/') {
15711
+ if (input[1] === '.' || input[1] === '/') {
15712
+ output.push('/');
15713
+ break
15714
+ }
15715
+ }
15716
+ } else if (len === 3) {
15717
+ if (input === '/..') {
15718
+ if (output.length !== 0) {
15719
+ output.pop();
15720
+ }
15721
+ output.push('/');
15722
+ break
15723
+ }
15724
+ }
15725
+ if (input[0] === '.') {
15726
+ if (input[1] === '.') {
15727
+ if (input[2] === '/') {
15728
+ input = input.slice(3);
15729
+ continue
15730
+ }
15731
+ } else if (input[1] === '/') {
15732
+ input = input.slice(2);
15733
+ continue
15734
+ }
15735
+ } else if (input[0] === '/') {
15736
+ if (input[1] === '.') {
15737
+ if (input[2] === '/') {
15738
+ input = input.slice(2);
15739
+ continue
15740
+ } else if (input[2] === '.') {
15741
+ if (input[3] === '/') {
15742
+ input = input.slice(3);
15743
+ if (output.length !== 0) {
15744
+ output.pop();
15745
+ }
15746
+ continue
15747
+ }
15748
+ }
15388
15749
  }
15389
15750
  }
15751
+
15752
+ // Rule 2E: Move normal path segment to output
15753
+ if ((nextSlash = input.indexOf('/', 1)) === -1) {
15754
+ output.push(input);
15755
+ break
15756
+ } else {
15757
+ output.push(input.slice(0, nextSlash));
15758
+ input = input.slice(nextSlash);
15759
+ }
15390
15760
  }
15761
+
15391
15762
  return output.join('')
15392
15763
  }
15393
15764
 
15394
- function normalizeComponentEncoding (components, esc) {
15765
+ /**
15766
+ * @param {import('../types/index').URIComponent} component
15767
+ * @param {boolean} esc
15768
+ * @returns {import('../types/index').URIComponent}
15769
+ */
15770
+ function normalizeComponentEncoding (component, esc) {
15395
15771
  const func = esc !== true ? escape : unescape;
15396
- if (components.scheme !== undefined) {
15397
- components.scheme = func(components.scheme);
15772
+ if (component.scheme !== undefined) {
15773
+ component.scheme = func(component.scheme);
15398
15774
  }
15399
- if (components.userinfo !== undefined) {
15400
- components.userinfo = func(components.userinfo);
15775
+ if (component.userinfo !== undefined) {
15776
+ component.userinfo = func(component.userinfo);
15401
15777
  }
15402
- if (components.host !== undefined) {
15403
- components.host = func(components.host);
15778
+ if (component.host !== undefined) {
15779
+ component.host = func(component.host);
15404
15780
  }
15405
- if (components.path !== undefined) {
15406
- components.path = func(components.path);
15781
+ if (component.path !== undefined) {
15782
+ component.path = func(component.path);
15407
15783
  }
15408
- if (components.query !== undefined) {
15409
- components.query = func(components.query);
15784
+ if (component.query !== undefined) {
15785
+ component.query = func(component.query);
15410
15786
  }
15411
- if (components.fragment !== undefined) {
15412
- components.fragment = func(components.fragment);
15787
+ if (component.fragment !== undefined) {
15788
+ component.fragment = func(component.fragment);
15413
15789
  }
15414
- return components
15790
+ return component
15415
15791
  }
15416
15792
 
15417
- function recomposeAuthority (components) {
15793
+ /**
15794
+ * @param {import('../types/index').URIComponent} component
15795
+ * @returns {string|undefined}
15796
+ */
15797
+ function recomposeAuthority (component) {
15418
15798
  const uriTokens = [];
15419
15799
 
15420
- if (components.userinfo !== undefined) {
15421
- uriTokens.push(components.userinfo);
15800
+ if (component.userinfo !== undefined) {
15801
+ uriTokens.push(component.userinfo);
15422
15802
  uriTokens.push('@');
15423
15803
  }
15424
15804
 
15425
- if (components.host !== undefined) {
15426
- let host = unescape(components.host);
15427
- const ipV4res = normalizeIPv4(host);
15428
-
15429
- if (ipV4res.isIPV4) {
15430
- host = ipV4res.host;
15431
- } else {
15432
- const ipV6res = normalizeIPv6(ipV4res.host);
15805
+ if (component.host !== undefined) {
15806
+ let host = unescape(component.host);
15807
+ if (!isIPv4(host)) {
15808
+ const ipV6res = normalizeIPv6(host);
15433
15809
  if (ipV6res.isIPV6 === true) {
15434
15810
  host = `[${ipV6res.escapedHost}]`;
15435
15811
  } else {
15436
- host = components.host;
15812
+ host = component.host;
15437
15813
  }
15438
15814
  }
15439
15815
  uriTokens.push(host);
15440
15816
  }
15441
15817
 
15442
- if (typeof components.port === 'number' || typeof components.port === 'string') {
15818
+ if (typeof component.port === 'number' || typeof component.port === 'string') {
15443
15819
  uriTokens.push(':');
15444
- uriTokens.push(String(components.port));
15820
+ uriTokens.push(String(component.port));
15445
15821
  }
15446
15822
 
15447
15823
  return uriTokens.length ? uriTokens.join('') : undefined
15448
15824
  }
15449
15825
  utils = {
15826
+ nonSimpleDomain,
15450
15827
  recomposeAuthority,
15451
15828
  normalizeComponentEncoding,
15452
15829
  removeDotSegments,
15453
- normalizeIPv4,
15830
+ isIPv4,
15831
+ isUUID,
15454
15832
  normalizeIPv6,
15455
15833
  stringArrayToHexStripped
15456
15834
  };
@@ -15464,192 +15842,271 @@ function requireSchemes () {
15464
15842
  if (hasRequiredSchemes) return schemes;
15465
15843
  hasRequiredSchemes = 1;
15466
15844
 
15467
- const UUID_REG = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu;
15845
+ const { isUUID } = requireUtils();
15468
15846
  const URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
15469
15847
 
15470
- function isSecure (wsComponents) {
15471
- return typeof wsComponents.secure === 'boolean' ? wsComponents.secure : String(wsComponents.scheme).toLowerCase() === 'wss'
15848
+ const supportedSchemeNames = /** @type {const} */ (['http', 'https', 'ws',
15849
+ 'wss', 'urn', 'urn:uuid']);
15850
+
15851
+ /** @typedef {supportedSchemeNames[number]} SchemeName */
15852
+
15853
+ /**
15854
+ * @param {string} name
15855
+ * @returns {name is SchemeName}
15856
+ */
15857
+ function isValidSchemeName (name) {
15858
+ return supportedSchemeNames.indexOf(/** @type {*} */ (name)) !== -1
15859
+ }
15860
+
15861
+ /**
15862
+ * @callback SchemeFn
15863
+ * @param {import('../types/index').URIComponent} component
15864
+ * @param {import('../types/index').Options} options
15865
+ * @returns {import('../types/index').URIComponent}
15866
+ */
15867
+
15868
+ /**
15869
+ * @typedef {Object} SchemeHandler
15870
+ * @property {SchemeName} scheme - The scheme name.
15871
+ * @property {boolean} [domainHost] - Indicates if the scheme supports domain hosts.
15872
+ * @property {SchemeFn} parse - Function to parse the URI component for this scheme.
15873
+ * @property {SchemeFn} serialize - Function to serialize the URI component for this scheme.
15874
+ * @property {boolean} [skipNormalize] - Indicates if normalization should be skipped for this scheme.
15875
+ * @property {boolean} [absolutePath] - Indicates if the scheme uses absolute paths.
15876
+ * @property {boolean} [unicodeSupport] - Indicates if the scheme supports Unicode.
15877
+ */
15878
+
15879
+ /**
15880
+ * @param {import('../types/index').URIComponent} wsComponent
15881
+ * @returns {boolean}
15882
+ */
15883
+ function wsIsSecure (wsComponent) {
15884
+ if (wsComponent.secure === true) {
15885
+ return true
15886
+ } else if (wsComponent.secure === false) {
15887
+ return false
15888
+ } else if (wsComponent.scheme) {
15889
+ return (
15890
+ wsComponent.scheme.length === 3 &&
15891
+ (wsComponent.scheme[0] === 'w' || wsComponent.scheme[0] === 'W') &&
15892
+ (wsComponent.scheme[1] === 's' || wsComponent.scheme[1] === 'S') &&
15893
+ (wsComponent.scheme[2] === 's' || wsComponent.scheme[2] === 'S')
15894
+ )
15895
+ } else {
15896
+ return false
15897
+ }
15472
15898
  }
15473
15899
 
15474
- function httpParse (components) {
15475
- if (!components.host) {
15476
- components.error = components.error || 'HTTP URIs must have a host.';
15900
+ /** @type {SchemeFn} */
15901
+ function httpParse (component) {
15902
+ if (!component.host) {
15903
+ component.error = component.error || 'HTTP URIs must have a host.';
15477
15904
  }
15478
15905
 
15479
- return components
15906
+ return component
15480
15907
  }
15481
15908
 
15482
- function httpSerialize (components) {
15483
- const secure = String(components.scheme).toLowerCase() === 'https';
15909
+ /** @type {SchemeFn} */
15910
+ function httpSerialize (component) {
15911
+ const secure = String(component.scheme).toLowerCase() === 'https';
15484
15912
 
15485
15913
  // normalize the default port
15486
- if (components.port === (secure ? 443 : 80) || components.port === '') {
15487
- components.port = undefined;
15914
+ if (component.port === (secure ? 443 : 80) || component.port === '') {
15915
+ component.port = undefined;
15488
15916
  }
15489
15917
 
15490
15918
  // normalize the empty path
15491
- if (!components.path) {
15492
- components.path = '/';
15919
+ if (!component.path) {
15920
+ component.path = '/';
15493
15921
  }
15494
15922
 
15495
15923
  // NOTE: We do not parse query strings for HTTP URIs
15496
15924
  // as WWW Form Url Encoded query strings are part of the HTML4+ spec,
15497
15925
  // and not the HTTP spec.
15498
15926
 
15499
- return components
15927
+ return component
15500
15928
  }
15501
15929
 
15502
- function wsParse (wsComponents) {
15930
+ /** @type {SchemeFn} */
15931
+ function wsParse (wsComponent) {
15503
15932
  // indicate if the secure flag is set
15504
- wsComponents.secure = isSecure(wsComponents);
15933
+ wsComponent.secure = wsIsSecure(wsComponent);
15505
15934
 
15506
15935
  // construct resouce name
15507
- wsComponents.resourceName = (wsComponents.path || '/') + (wsComponents.query ? '?' + wsComponents.query : '');
15508
- wsComponents.path = undefined;
15509
- wsComponents.query = undefined;
15936
+ wsComponent.resourceName = (wsComponent.path || '/') + (wsComponent.query ? '?' + wsComponent.query : '');
15937
+ wsComponent.path = undefined;
15938
+ wsComponent.query = undefined;
15510
15939
 
15511
- return wsComponents
15940
+ return wsComponent
15512
15941
  }
15513
15942
 
15514
- function wsSerialize (wsComponents) {
15943
+ /** @type {SchemeFn} */
15944
+ function wsSerialize (wsComponent) {
15515
15945
  // normalize the default port
15516
- if (wsComponents.port === (isSecure(wsComponents) ? 443 : 80) || wsComponents.port === '') {
15517
- wsComponents.port = undefined;
15946
+ if (wsComponent.port === (wsIsSecure(wsComponent) ? 443 : 80) || wsComponent.port === '') {
15947
+ wsComponent.port = undefined;
15518
15948
  }
15519
15949
 
15520
15950
  // ensure scheme matches secure flag
15521
- if (typeof wsComponents.secure === 'boolean') {
15522
- wsComponents.scheme = (wsComponents.secure ? 'wss' : 'ws');
15523
- wsComponents.secure = undefined;
15951
+ if (typeof wsComponent.secure === 'boolean') {
15952
+ wsComponent.scheme = (wsComponent.secure ? 'wss' : 'ws');
15953
+ wsComponent.secure = undefined;
15524
15954
  }
15525
15955
 
15526
15956
  // reconstruct path from resource name
15527
- if (wsComponents.resourceName) {
15528
- const [path, query] = wsComponents.resourceName.split('?');
15529
- wsComponents.path = (path && path !== '/' ? path : undefined);
15530
- wsComponents.query = query;
15531
- wsComponents.resourceName = undefined;
15957
+ if (wsComponent.resourceName) {
15958
+ const [path, query] = wsComponent.resourceName.split('?');
15959
+ wsComponent.path = (path && path !== '/' ? path : undefined);
15960
+ wsComponent.query = query;
15961
+ wsComponent.resourceName = undefined;
15532
15962
  }
15533
15963
 
15534
15964
  // forbid fragment component
15535
- wsComponents.fragment = undefined;
15965
+ wsComponent.fragment = undefined;
15536
15966
 
15537
- return wsComponents
15967
+ return wsComponent
15538
15968
  }
15539
15969
 
15540
- function urnParse (urnComponents, options) {
15541
- if (!urnComponents.path) {
15542
- urnComponents.error = 'URN can not be parsed';
15543
- return urnComponents
15970
+ /** @type {SchemeFn} */
15971
+ function urnParse (urnComponent, options) {
15972
+ if (!urnComponent.path) {
15973
+ urnComponent.error = 'URN can not be parsed';
15974
+ return urnComponent
15544
15975
  }
15545
- const matches = urnComponents.path.match(URN_REG);
15976
+ const matches = urnComponent.path.match(URN_REG);
15546
15977
  if (matches) {
15547
- const scheme = options.scheme || urnComponents.scheme || 'urn';
15548
- urnComponents.nid = matches[1].toLowerCase();
15549
- urnComponents.nss = matches[2];
15550
- const urnScheme = `${scheme}:${options.nid || urnComponents.nid}`;
15551
- const schemeHandler = SCHEMES[urnScheme];
15552
- urnComponents.path = undefined;
15978
+ const scheme = options.scheme || urnComponent.scheme || 'urn';
15979
+ urnComponent.nid = matches[1].toLowerCase();
15980
+ urnComponent.nss = matches[2];
15981
+ const urnScheme = `${scheme}:${options.nid || urnComponent.nid}`;
15982
+ const schemeHandler = getSchemeHandler(urnScheme);
15983
+ urnComponent.path = undefined;
15553
15984
 
15554
15985
  if (schemeHandler) {
15555
- urnComponents = schemeHandler.parse(urnComponents, options);
15986
+ urnComponent = schemeHandler.parse(urnComponent, options);
15556
15987
  }
15557
15988
  } else {
15558
- urnComponents.error = urnComponents.error || 'URN can not be parsed.';
15989
+ urnComponent.error = urnComponent.error || 'URN can not be parsed.';
15559
15990
  }
15560
15991
 
15561
- return urnComponents
15992
+ return urnComponent
15562
15993
  }
15563
15994
 
15564
- function urnSerialize (urnComponents, options) {
15565
- const scheme = options.scheme || urnComponents.scheme || 'urn';
15566
- const nid = urnComponents.nid.toLowerCase();
15995
+ /** @type {SchemeFn} */
15996
+ function urnSerialize (urnComponent, options) {
15997
+ if (urnComponent.nid === undefined) {
15998
+ throw new Error('URN without nid cannot be serialized')
15999
+ }
16000
+ const scheme = options.scheme || urnComponent.scheme || 'urn';
16001
+ const nid = urnComponent.nid.toLowerCase();
15567
16002
  const urnScheme = `${scheme}:${options.nid || nid}`;
15568
- const schemeHandler = SCHEMES[urnScheme];
16003
+ const schemeHandler = getSchemeHandler(urnScheme);
15569
16004
 
15570
16005
  if (schemeHandler) {
15571
- urnComponents = schemeHandler.serialize(urnComponents, options);
16006
+ urnComponent = schemeHandler.serialize(urnComponent, options);
15572
16007
  }
15573
16008
 
15574
- const uriComponents = urnComponents;
15575
- const nss = urnComponents.nss;
15576
- uriComponents.path = `${nid || options.nid}:${nss}`;
16009
+ const uriComponent = urnComponent;
16010
+ const nss = urnComponent.nss;
16011
+ uriComponent.path = `${nid || options.nid}:${nss}`;
15577
16012
 
15578
16013
  options.skipEscape = true;
15579
- return uriComponents
16014
+ return uriComponent
15580
16015
  }
15581
16016
 
15582
- function urnuuidParse (urnComponents, options) {
15583
- const uuidComponents = urnComponents;
15584
- uuidComponents.uuid = uuidComponents.nss;
15585
- uuidComponents.nss = undefined;
16017
+ /** @type {SchemeFn} */
16018
+ function urnuuidParse (urnComponent, options) {
16019
+ const uuidComponent = urnComponent;
16020
+ uuidComponent.uuid = uuidComponent.nss;
16021
+ uuidComponent.nss = undefined;
15586
16022
 
15587
- if (!options.tolerant && (!uuidComponents.uuid || !UUID_REG.test(uuidComponents.uuid))) {
15588
- uuidComponents.error = uuidComponents.error || 'UUID is not valid.';
16023
+ if (!options.tolerant && (!uuidComponent.uuid || !isUUID(uuidComponent.uuid))) {
16024
+ uuidComponent.error = uuidComponent.error || 'UUID is not valid.';
15589
16025
  }
15590
16026
 
15591
- return uuidComponents
16027
+ return uuidComponent
15592
16028
  }
15593
16029
 
15594
- function urnuuidSerialize (uuidComponents) {
15595
- const urnComponents = uuidComponents;
16030
+ /** @type {SchemeFn} */
16031
+ function urnuuidSerialize (uuidComponent) {
16032
+ const urnComponent = uuidComponent;
15596
16033
  // normalize UUID
15597
- urnComponents.nss = (uuidComponents.uuid || '').toLowerCase();
15598
- return urnComponents
16034
+ urnComponent.nss = (uuidComponent.uuid || '').toLowerCase();
16035
+ return urnComponent
15599
16036
  }
15600
16037
 
15601
- const http = {
16038
+ const http = /** @type {SchemeHandler} */ ({
15602
16039
  scheme: 'http',
15603
16040
  domainHost: true,
15604
16041
  parse: httpParse,
15605
16042
  serialize: httpSerialize
15606
- };
16043
+ });
15607
16044
 
15608
- const https = {
16045
+ const https = /** @type {SchemeHandler} */ ({
15609
16046
  scheme: 'https',
15610
16047
  domainHost: http.domainHost,
15611
16048
  parse: httpParse,
15612
16049
  serialize: httpSerialize
15613
- };
16050
+ });
15614
16051
 
15615
- const ws = {
16052
+ const ws = /** @type {SchemeHandler} */ ({
15616
16053
  scheme: 'ws',
15617
16054
  domainHost: true,
15618
16055
  parse: wsParse,
15619
16056
  serialize: wsSerialize
15620
- };
16057
+ });
15621
16058
 
15622
- const wss = {
16059
+ const wss = /** @type {SchemeHandler} */ ({
15623
16060
  scheme: 'wss',
15624
16061
  domainHost: ws.domainHost,
15625
16062
  parse: ws.parse,
15626
16063
  serialize: ws.serialize
15627
- };
16064
+ });
15628
16065
 
15629
- const urn = {
16066
+ const urn = /** @type {SchemeHandler} */ ({
15630
16067
  scheme: 'urn',
15631
16068
  parse: urnParse,
15632
16069
  serialize: urnSerialize,
15633
16070
  skipNormalize: true
15634
- };
16071
+ });
15635
16072
 
15636
- const urnuuid = {
16073
+ const urnuuid = /** @type {SchemeHandler} */ ({
15637
16074
  scheme: 'urn:uuid',
15638
16075
  parse: urnuuidParse,
15639
16076
  serialize: urnuuidSerialize,
15640
16077
  skipNormalize: true
15641
- };
16078
+ });
15642
16079
 
15643
- const SCHEMES = {
16080
+ const SCHEMES = /** @type {Record<SchemeName, SchemeHandler>} */ ({
15644
16081
  http,
15645
16082
  https,
15646
16083
  ws,
15647
16084
  wss,
15648
16085
  urn,
15649
16086
  'urn:uuid': urnuuid
15650
- };
16087
+ });
16088
+
16089
+ Object.setPrototypeOf(SCHEMES, null);
16090
+
16091
+ /**
16092
+ * @param {string|undefined} scheme
16093
+ * @returns {SchemeHandler|undefined}
16094
+ */
16095
+ function getSchemeHandler (scheme) {
16096
+ return (
16097
+ scheme && (
16098
+ SCHEMES[/** @type {SchemeName} */ (scheme)] ||
16099
+ SCHEMES[/** @type {SchemeName} */(scheme.toLowerCase())])
16100
+ ) ||
16101
+ undefined
16102
+ }
15651
16103
 
15652
- schemes = SCHEMES;
16104
+ schemes = {
16105
+ wsIsSecure,
16106
+ SCHEMES,
16107
+ isValidSchemeName,
16108
+ getSchemeHandler,
16109
+ };
15653
16110
  return schemes;
15654
16111
  }
15655
16112
 
@@ -15659,29 +16116,50 @@ function requireFastUri () {
15659
16116
  if (hasRequiredFastUri) return fastUri.exports;
15660
16117
  hasRequiredFastUri = 1;
15661
16118
 
15662
- const { normalizeIPv6, normalizeIPv4, removeDotSegments, recomposeAuthority, normalizeComponentEncoding } = requireUtils();
15663
- const SCHEMES = requireSchemes();
16119
+ const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = requireUtils();
16120
+ const { SCHEMES, getSchemeHandler } = requireSchemes();
15664
16121
 
16122
+ /**
16123
+ * @template {import('./types/index').URIComponent|string} T
16124
+ * @param {T} uri
16125
+ * @param {import('./types/index').Options} [options]
16126
+ * @returns {T}
16127
+ */
15665
16128
  function normalize (uri, options) {
15666
16129
  if (typeof uri === 'string') {
15667
- uri = serialize(parse(uri, options), options);
16130
+ uri = /** @type {T} */ (serialize(parse(uri, options), options));
15668
16131
  } else if (typeof uri === 'object') {
15669
- uri = parse(serialize(uri, options), options);
16132
+ uri = /** @type {T} */ (parse(serialize(uri, options), options));
15670
16133
  }
15671
16134
  return uri
15672
16135
  }
15673
16136
 
16137
+ /**
16138
+ * @param {string} baseURI
16139
+ * @param {string} relativeURI
16140
+ * @param {import('./types/index').Options} [options]
16141
+ * @returns {string}
16142
+ */
15674
16143
  function resolve (baseURI, relativeURI, options) {
15675
- const schemelessOptions = Object.assign({ scheme: 'null' }, options);
15676
- const resolved = resolveComponents(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true);
15677
- return serialize(resolved, { ...schemelessOptions, skipEscape: true })
16144
+ const schemelessOptions = options ? Object.assign({ scheme: 'null' }, options) : { scheme: 'null' };
16145
+ const resolved = resolveComponent(parse(baseURI, schemelessOptions), parse(relativeURI, schemelessOptions), schemelessOptions, true);
16146
+ schemelessOptions.skipEscape = true;
16147
+ return serialize(resolved, schemelessOptions)
15678
16148
  }
15679
16149
 
15680
- function resolveComponents (base, relative, options, skipNormalization) {
16150
+ /**
16151
+ * @param {import ('./types/index').URIComponent} base
16152
+ * @param {import ('./types/index').URIComponent} relative
16153
+ * @param {import('./types/index').Options} [options]
16154
+ * @param {boolean} [skipNormalization=false]
16155
+ * @returns {import ('./types/index').URIComponent}
16156
+ */
16157
+ function resolveComponent (base, relative, options, skipNormalization) {
16158
+ /** @type {import('./types/index').URIComponent} */
15681
16159
  const target = {};
15682
16160
  if (!skipNormalization) {
15683
- base = parse(serialize(base, options), options); // normalize base components
15684
- relative = parse(serialize(relative, options), options); // normalize relative components
16161
+ base = parse(serialize(base, options), options); // normalize base component
16162
+ relative = parse(serialize(relative, options), options); // normalize relative component
15685
16163
  }
15686
16164
  options = options || {};
15687
16165
 
@@ -15710,7 +16188,7 @@ function requireFastUri () {
15710
16188
  target.query = base.query;
15711
16189
  }
15712
16190
  } else {
15713
- if (relative.path.charAt(0) === '/') {
16191
+ if (relative.path[0] === '/') {
15714
16192
  target.path = removeDotSegments(relative.path);
15715
16193
  } else {
15716
16194
  if ((base.userinfo !== undefined || base.host !== undefined || base.port !== undefined) && !base.path) {
@@ -15737,6 +16215,12 @@ function requireFastUri () {
15737
16215
  return target
15738
16216
  }
15739
16217
 
16218
+ /**
16219
+ * @param {import ('./types/index').URIComponent|string} uriA
16220
+ * @param {import ('./types/index').URIComponent|string} uriB
16221
+ * @param {import ('./types/index').Options} options
16222
+ * @returns {boolean}
16223
+ */
15740
16224
  function equal (uriA, uriB, options) {
15741
16225
  if (typeof uriA === 'string') {
15742
16226
  uriA = unescape(uriA);
@@ -15755,8 +16239,13 @@ function requireFastUri () {
15755
16239
  return uriA.toLowerCase() === uriB.toLowerCase()
15756
16240
  }
15757
16241
 
16242
+ /**
16243
+ * @param {Readonly<import('./types/index').URIComponent>} cmpts
16244
+ * @param {import('./types/index').Options} [opts]
16245
+ * @returns {string}
16246
+ */
15758
16247
  function serialize (cmpts, opts) {
15759
- const components = {
16248
+ const component = {
15760
16249
  host: cmpts.host,
15761
16250
  scheme: cmpts.scheme,
15762
16251
  userinfo: cmpts.userinfo,
@@ -15776,28 +16265,28 @@ function requireFastUri () {
15776
16265
  const uriTokens = [];
15777
16266
 
15778
16267
  // find scheme handler
15779
- const schemeHandler = SCHEMES[(options.scheme || components.scheme || '').toLowerCase()];
16268
+ const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
15780
16269
 
15781
16270
  // perform scheme specific serialization
15782
- if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(components, options);
16271
+ if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
15783
16272
 
15784
- if (components.path !== undefined) {
16273
+ if (component.path !== undefined) {
15785
16274
  if (!options.skipEscape) {
15786
- components.path = escape(components.path);
16275
+ component.path = escape(component.path);
15787
16276
 
15788
- if (components.scheme !== undefined) {
15789
- components.path = components.path.split('%3A').join(':');
16277
+ if (component.scheme !== undefined) {
16278
+ component.path = component.path.split('%3A').join(':');
15790
16279
  }
15791
16280
  } else {
15792
- components.path = unescape(components.path);
16281
+ component.path = unescape(component.path);
15793
16282
  }
15794
16283
  }
15795
16284
 
15796
- if (options.reference !== 'suffix' && components.scheme) {
15797
- uriTokens.push(components.scheme, ':');
16285
+ if (options.reference !== 'suffix' && component.scheme) {
16286
+ uriTokens.push(component.scheme, ':');
15798
16287
  }
15799
16288
 
15800
- const authority = recomposeAuthority(components);
16289
+ const authority = recomposeAuthority(component);
15801
16290
  if (authority !== undefined) {
15802
16291
  if (options.reference !== 'suffix') {
15803
16292
  uriTokens.push('//');
@@ -15805,51 +16294,49 @@ function requireFastUri () {
15805
16294
 
15806
16295
  uriTokens.push(authority);
15807
16296
 
15808
- if (components.path && components.path.charAt(0) !== '/') {
16297
+ if (component.path && component.path[0] !== '/') {
15809
16298
  uriTokens.push('/');
15810
16299
  }
15811
16300
  }
15812
- if (components.path !== undefined) {
15813
- let s = components.path;
16301
+ if (component.path !== undefined) {
16302
+ let s = component.path;
15814
16303
 
15815
16304
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
15816
16305
  s = removeDotSegments(s);
15817
16306
  }
15818
16307
 
15819
- if (authority === undefined) {
15820
- s = s.replace(/^\/\//u, '/%2F'); // don't allow the path to start with "//"
16308
+ if (
16309
+ authority === undefined &&
16310
+ s[0] === '/' &&
16311
+ s[1] === '/'
16312
+ ) {
16313
+ // don't allow the path to start with "//"
16314
+ s = '/%2F' + s.slice(2);
15821
16315
  }
15822
16316
 
15823
16317
  uriTokens.push(s);
15824
16318
  }
15825
16319
 
15826
- if (components.query !== undefined) {
15827
- uriTokens.push('?', components.query);
16320
+ if (component.query !== undefined) {
16321
+ uriTokens.push('?', component.query);
15828
16322
  }
15829
16323
 
15830
- if (components.fragment !== undefined) {
15831
- uriTokens.push('#', components.fragment);
16324
+ if (component.fragment !== undefined) {
16325
+ uriTokens.push('#', component.fragment);
15832
16326
  }
15833
16327
  return uriTokens.join('')
15834
16328
  }
15835
16329
 
15836
- const hexLookUp = Array.from({ length: 127 }, (_v, k) => /[^!"$&'()*+,\-.;=_`a-z{}~]/u.test(String.fromCharCode(k)));
15837
-
15838
- function nonSimpleDomain (value) {
15839
- let code = 0;
15840
- for (let i = 0, len = value.length; i < len; ++i) {
15841
- code = value.charCodeAt(i);
15842
- if (code > 126 || hexLookUp[code]) {
15843
- return true
15844
- }
15845
- }
15846
- return false
15847
- }
15848
-
15849
16330
  const URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
15850
16331
 
16332
+ /**
16333
+ * @param {string} uri
16334
+ * @param {import('./types/index').Options} [opts]
16335
+ * @returns
16336
+ */
15851
16337
  function parse (uri, opts) {
15852
16338
  const options = Object.assign({}, opts);
16339
+ /** @type {import('./types/index').URIComponent} */
15853
16340
  const parsed = {
15854
16341
  scheme: undefined,
15855
16342
  userinfo: undefined,
@@ -15859,9 +16346,15 @@ function requireFastUri () {
15859
16346
  query: undefined,
15860
16347
  fragment: undefined
15861
16348
  };
15862
- const gotEncoding = uri.indexOf('%') !== -1;
16349
+
15863
16350
  let isIP = false;
15864
- if (options.reference === 'suffix') uri = (options.scheme ? options.scheme + ':' : '') + '//' + uri;
16351
+ if (options.reference === 'suffix') {
16352
+ if (options.scheme) {
16353
+ uri = options.scheme + ':' + uri;
16354
+ } else {
16355
+ uri = '//' + uri;
16356
+ }
16357
+ }
15865
16358
 
15866
16359
  const matches = uri.match(URI_PARSE);
15867
16360
 
@@ -15880,13 +16373,12 @@ function requireFastUri () {
15880
16373
  parsed.port = matches[5];
15881
16374
  }
15882
16375
  if (parsed.host) {
15883
- const ipv4result = normalizeIPv4(parsed.host);
15884
- if (ipv4result.isIPV4 === false) {
15885
- const ipv6result = normalizeIPv6(ipv4result.host);
16376
+ const ipv4result = isIPv4(parsed.host);
16377
+ if (ipv4result === false) {
16378
+ const ipv6result = normalizeIPv6(parsed.host);
15886
16379
  parsed.host = ipv6result.host.toLowerCase();
15887
16380
  isIP = ipv6result.isIPV6;
15888
16381
  } else {
15889
- parsed.host = ipv4result.host;
15890
16382
  isIP = true;
15891
16383
  }
15892
16384
  }
@@ -15906,7 +16398,7 @@ function requireFastUri () {
15906
16398
  }
15907
16399
 
15908
16400
  // find scheme handler
15909
- const schemeHandler = SCHEMES[(options.scheme || parsed.scheme || '').toLowerCase()];
16401
+ const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
15910
16402
 
15911
16403
  // check if scheme can't handle IRIs
15912
16404
  if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
@@ -15923,11 +16415,13 @@ function requireFastUri () {
15923
16415
  }
15924
16416
 
15925
16417
  if (!schemeHandler || (schemeHandler && !schemeHandler.skipNormalize)) {
15926
- if (gotEncoding && parsed.scheme !== undefined) {
15927
- parsed.scheme = unescape(parsed.scheme);
15928
- }
15929
- if (gotEncoding && parsed.host !== undefined) {
15930
- parsed.host = unescape(parsed.host);
16418
+ if (uri.indexOf('%') !== -1) {
16419
+ if (parsed.scheme !== undefined) {
16420
+ parsed.scheme = unescape(parsed.scheme);
16421
+ }
16422
+ if (parsed.host !== undefined) {
16423
+ parsed.host = unescape(parsed.host);
16424
+ }
15931
16425
  }
15932
16426
  if (parsed.path) {
15933
16427
  parsed.path = escape(unescape(parsed.path));
@@ -15951,7 +16445,7 @@ function requireFastUri () {
15951
16445
  SCHEMES,
15952
16446
  normalize,
15953
16447
  resolve,
15954
- resolveComponents,
16448
+ resolveComponent,
15955
16449
  equal,
15956
16450
  serialize,
15957
16451
  parse