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