trousse 3.5.0 → 3.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/objects.js +1 -1
- package/dist/urls.d.ts +5 -3
- package/dist/urls.js +52 -16
- package/package.json +2 -2
package/dist/objects.js
CHANGED
|
@@ -14,7 +14,7 @@ const setKey = (object, key, value) => {
|
|
|
14
14
|
};
|
|
15
15
|
const pick = (object, keys) => {
|
|
16
16
|
const result = {};
|
|
17
|
-
for (const key of keys) if (key
|
|
17
|
+
for (const key of keys) if (Object.hasOwn(object, key)) setKey(result, key, object[key]);
|
|
18
18
|
return result;
|
|
19
19
|
};
|
|
20
20
|
const omit = (object, keys) => {
|
package/dist/urls.d.ts
CHANGED
|
@@ -18,8 +18,9 @@ export declare const hasFragmentParam: (source: ParamSource | undefined, name: s
|
|
|
18
18
|
export declare const getFragmentParamValues: (source: ParamSource | undefined, name: string, options?: ParamOptions) => Array<string>;
|
|
19
19
|
export declare const getFragmentParam: (source: ParamSource | undefined, name: string, options?: ParamOptions) => string | undefined;
|
|
20
20
|
export declare const getFragmentParams: (source: ParamSource | undefined, names: ReadonlyArray<string>, options?: ParamOptions) => Record<string, string>;
|
|
21
|
-
|
|
22
|
-
export declare const
|
|
21
|
+
type QueryValue = string | number | true;
|
|
22
|
+
export declare const composeQuery: (params?: Record<string, QueryValue>) => string;
|
|
23
|
+
export declare const composeFragment: (params?: Record<string, QueryValue>) => string;
|
|
23
24
|
export declare const fixMalformedScheme: (url: string) => string;
|
|
24
25
|
export declare const fixMalformedQuery: (url: string) => string;
|
|
25
26
|
export declare const trimUrlValues: (url: string) => string;
|
|
@@ -40,4 +41,5 @@ export declare const resolveFeedProtocol: typeof resolveFeedScheme;
|
|
|
40
41
|
/** @deprecated Use `addMissingScheme` instead. */
|
|
41
42
|
export declare const addMissingProtocol: typeof addMissingScheme;
|
|
42
43
|
/** @deprecated Use `upgradeScheme` instead. */
|
|
43
|
-
export declare const upgradeProtocol: typeof upgradeScheme;
|
|
44
|
+
export declare const upgradeProtocol: typeof upgradeScheme;
|
|
45
|
+
export {};
|
package/dist/urls.js
CHANGED
|
@@ -183,6 +183,10 @@ const composePairs = (params) => {
|
|
|
183
183
|
};
|
|
184
184
|
const pairs = [];
|
|
185
185
|
for (const [name, value] of Object.entries(params ?? {})) {
|
|
186
|
+
if (value === true) {
|
|
187
|
+
pairs.push(escapePart(name));
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
186
190
|
const text = String(value);
|
|
187
191
|
if (!text) continue;
|
|
188
192
|
pairs.push(`${escapePart(name)}=${escapePart(text)}`);
|
|
@@ -423,6 +427,18 @@ const resolveUrl = (url, base) => {
|
|
|
423
427
|
if (!parsed || !isHttpUrl(parsed)) return;
|
|
424
428
|
return parsed.href;
|
|
425
429
|
};
|
|
430
|
+
const valueShapeEscapeRegex = /(%(?:26|23|25|2B|3B))/gi;
|
|
431
|
+
const nameShapeEscapeRegex = /(%(?:26|23|25|2B|3B|3D))/gi;
|
|
432
|
+
const decodeQueryPart = (part, shapeRegex) => {
|
|
433
|
+
return part.replace(plusRegex, "%20").split(shapeRegex).map((chunk, index) => index % 2 ? chunk.toUpperCase() : decodePercent(chunk)).join("");
|
|
434
|
+
};
|
|
435
|
+
const canonicalizeQuery = (search) => {
|
|
436
|
+
return `?${search.slice(1).split("&").map((pair) => {
|
|
437
|
+
const at = pair.indexOf("=");
|
|
438
|
+
if (at === -1) return decodeQueryPart(pair, nameShapeEscapeRegex);
|
|
439
|
+
return `${decodeQueryPart(pair.slice(0, at), nameShapeEscapeRegex)}=${decodeQueryPart(pair.slice(at + 1), valueShapeEscapeRegex)}`;
|
|
440
|
+
}).join("&")}`;
|
|
441
|
+
};
|
|
426
442
|
const decodeAndNormalizeEncoding = (value) => {
|
|
427
443
|
if (!value.includes("%")) return value;
|
|
428
444
|
return value.replace(percentEscapeRegex, (hex) => {
|
|
@@ -467,7 +483,10 @@ const normalizeUrl = (url, options) => {
|
|
|
467
483
|
if (options.collapseSlashes) pathname = pathname.replace(repeatedSlashesRegex, "/");
|
|
468
484
|
if (options.stripTrailingSlash && pathname.length > 1 && pathname.endsWith("/")) pathname = pathname.slice(0, -1);
|
|
469
485
|
parsed.pathname = pathname;
|
|
470
|
-
if (options.normalizeEncoding && parsed.search.
|
|
486
|
+
if (options.normalizeEncoding && parsed.search.length > 1) {
|
|
487
|
+
parsed.search = canonicalizeQuery(parsed.search);
|
|
488
|
+
parsed.search = parsed.search.replace(percentEscapeRegex, (hex) => hex.toUpperCase());
|
|
489
|
+
}
|
|
471
490
|
if (options.normalizeEncoding && parsed.hash.includes("%")) parsed.hash = decodeAndNormalizeEncoding(parsed.hash);
|
|
472
491
|
if (options.stripQuery) parsed.search = "";
|
|
473
492
|
if (parsed.search && (options.stripQueryParams || options.lowercaseQuery)) {
|
|
@@ -518,7 +537,15 @@ const createUrlVariants = (url) => {
|
|
|
518
537
|
const sameQuerySpellings = [
|
|
519
538
|
["+", "%20"],
|
|
520
539
|
[":", "%3A"],
|
|
521
|
-
["@", "%40"]
|
|
540
|
+
["@", "%40"],
|
|
541
|
+
["/", "%2F"],
|
|
542
|
+
[",", "%2C"],
|
|
543
|
+
["(", "%28"],
|
|
544
|
+
[")", "%29"],
|
|
545
|
+
["*", "%2A"],
|
|
546
|
+
["!", "%21"],
|
|
547
|
+
["'", "%27"],
|
|
548
|
+
["$", "%24"]
|
|
522
549
|
];
|
|
523
550
|
const percentEscapeRegex = /%[0-9a-f]{2}/gi;
|
|
524
551
|
const addLowercaseHexSpellings = (url, spellings) => {
|
|
@@ -528,25 +555,34 @@ const addLowercaseHexSpellings = (url, spellings) => {
|
|
|
528
555
|
});
|
|
529
556
|
return [.../* @__PURE__ */ new Set([...spellings, ...lowercaseHexSpellings])];
|
|
530
557
|
};
|
|
558
|
+
const maxMixedQuerySpellings = 4;
|
|
559
|
+
const respellQuery = (spelling, queryIndex, pairs, toEncoded) => {
|
|
560
|
+
const fragmentIndex = spelling.indexOf("#");
|
|
561
|
+
const queryEnd = fragmentIndex === -1 ? spelling.length : fragmentIndex;
|
|
562
|
+
let query = spelling.slice(queryIndex, queryEnd);
|
|
563
|
+
for (const [written, encoded] of pairs) query = toEncoded ? query.replaceAll(written, encoded) : query.replaceAll(encoded, written);
|
|
564
|
+
return `${spelling.slice(0, queryIndex)}${query}${spelling.slice(queryEnd)}`;
|
|
565
|
+
};
|
|
531
566
|
const createUrlSpellings = (url) => {
|
|
532
567
|
const uppercaseHexUrl = url.replace(percentEscapeRegex, (hex) => hex.toUpperCase());
|
|
533
|
-
let spellings = [.../* @__PURE__ */ new Set([url, uppercaseHexUrl])];
|
|
534
568
|
const hashIndex = url.indexOf("#");
|
|
535
569
|
const queryEnd = hashIndex === -1 ? url.length : hashIndex;
|
|
536
570
|
const queryIndex = url.indexOf("?");
|
|
537
|
-
if (queryIndex === -1 || queryIndex > queryEnd) return addLowercaseHexSpellings(url,
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
571
|
+
if (queryIndex === -1 || queryIndex > queryEnd) return addLowercaseHexSpellings(url, [.../* @__PURE__ */ new Set([url, uppercaseHexUrl])]);
|
|
572
|
+
const query = uppercaseHexUrl.slice(queryIndex, queryEnd);
|
|
573
|
+
const present = sameQuerySpellings.filter(([written, encoded]) => {
|
|
574
|
+
return query.includes(written) || query.includes(encoded);
|
|
575
|
+
});
|
|
576
|
+
const bases = [.../* @__PURE__ */ new Set([url, uppercaseHexUrl])];
|
|
577
|
+
const throughout = bases.flatMap((base) => [respellQuery(base, queryIndex, present, false), respellQuery(base, queryIndex, present, true)]);
|
|
578
|
+
let mixes = bases;
|
|
579
|
+
if (present.length <= maxMixedQuerySpellings) for (const pair of present) mixes = mixes.flatMap((spelling) => [respellQuery(spelling, queryIndex, [pair], false), respellQuery(spelling, queryIndex, [pair], true)]);
|
|
580
|
+
return addLowercaseHexSpellings(url, [.../* @__PURE__ */ new Set([
|
|
581
|
+
url,
|
|
582
|
+
uppercaseHexUrl,
|
|
583
|
+
...throughout,
|
|
584
|
+
...mixes
|
|
585
|
+
])]);
|
|
550
586
|
};
|
|
551
587
|
const genericSecondLevels = [
|
|
552
588
|
"ac",
|
package/package.json
CHANGED