trousse 2.16.3 → 3.1.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/arrays.js CHANGED
@@ -3,6 +3,7 @@ import { isPresent } from "./is.js";
3
3
  const omitEmpty = (array) => {
4
4
  const result = [];
5
5
  for (const item of array) if (isPresent(item) && item !== "") result.push(item);
6
- return result.length ? result : void 0;
6
+ if (!result.length) return;
7
+ return result;
7
8
  };
8
9
  export { omitEmpty };
package/dist/files.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export declare const audioExtensions: string[];
2
2
  export declare const videoExtensions: string[];
3
3
  export declare const imageExtensions: string[];
4
+ export declare const webImageExtensions: string[];
5
+ export declare const webVideoExtensions: string[];
6
+ export declare const webAudioExtensions: string[];
4
7
  export declare const documentExtensions: string[];
5
8
  export declare const archiveExtensions: string[];
6
9
  export declare const installerExtensions: string[];
package/dist/files.js CHANGED
@@ -48,6 +48,33 @@ const imageExtensions = [
48
48
  "tiff",
49
49
  "webp"
50
50
  ];
51
+ const webImageExtensions = [
52
+ "avif",
53
+ "gif",
54
+ "jpeg",
55
+ "jpg",
56
+ "png",
57
+ "svg",
58
+ "webp"
59
+ ];
60
+ const webVideoExtensions = [
61
+ "m4v",
62
+ "mov",
63
+ "mp4",
64
+ "ogv",
65
+ "webm"
66
+ ];
67
+ const webAudioExtensions = [
68
+ "aac",
69
+ "flac",
70
+ "m4a",
71
+ "mp3",
72
+ "oga",
73
+ "ogg",
74
+ "opus",
75
+ "wav",
76
+ "weba"
77
+ ];
51
78
  const documentExtensions = [
52
79
  "doc",
53
80
  "docx",
@@ -97,4 +124,4 @@ const fontExtensions = [
97
124
  "woff2"
98
125
  ];
99
126
  const subtitleExtensions = ["srt", "vtt"];
100
- export { archiveExtensions, audioExtensions, codeExtensions, documentExtensions, flashExtensions, fontExtensions, imageExtensions, installerExtensions, subtitleExtensions, videoExtensions };
127
+ export { archiveExtensions, audioExtensions, codeExtensions, documentExtensions, flashExtensions, fontExtensions, imageExtensions, installerExtensions, subtitleExtensions, videoExtensions, webAudioExtensions, webImageExtensions, webVideoExtensions };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { omitEmpty } from "./arrays.js";
2
- import { AnyOf, DeepOmit, IsPlainObject, MaybePromise, NormalizeOptions, Nullish, PartialNullish, Pattern, RegistrableDomainOptions, WeightedMimeType } from "./types.js";
2
+ import { AnyOf, DeepOmit, IsPlainObject, MaybePromise, NormalizeOptions, Nullish, ParamSource, PartialNullish, Pattern, RegistrableDomainOptions, WeightedMimeType } from "./types.js";
3
3
  import { coerceArray, coerceBoolean, coerceDate, coerceNumber, coerceSingular, coerceString } from "./coercions.js";
4
- import { archiveExtensions, audioExtensions, codeExtensions, documentExtensions, flashExtensions, fontExtensions, imageExtensions, installerExtensions, subtitleExtensions, videoExtensions } from "./files.js";
4
+ import { archiveExtensions, audioExtensions, codeExtensions, documentExtensions, flashExtensions, fontExtensions, imageExtensions, installerExtensions, subtitleExtensions, videoExtensions, webAudioExtensions, webImageExtensions, webVideoExtensions } from "./files.js";
5
5
  import { isBoolean, isFunction, isNonEmptyString, isNullish, isNumber, isObject, isPlainObject, isPresent, isString, isValidDate } from "./is.js";
6
6
  import { isJsonLike, isParseableJson } from "./json.js";
7
7
  import { escapeHtml, t, tx } from "./locales.js";
@@ -9,5 +9,5 @@ import { anyWordMatchesAnyOf, endsWithAnyOf, escapeRegex, getAnyOf, includesAnyO
9
9
  import { createAcceptHeader, feedMimeTypes, genericFeedMimeTypes, genericHtmlMimeTypes, htmlMimeTypes } from "./mimes.js";
10
10
  import { omit, pick, toMap, trimObject } from "./objects.js";
11
11
  import { sleep } from "./timers.js";
12
- import { addMissingProtocol, addMissingScheme, composeQuery, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, encodePathSegment, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, getPathSegments, getQueryParam, getQueryParams, getRegistrableDomain, getSubdomain, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isSubdomainOf, normalizeUrl, parseUrl, resolveFeedProtocol, resolveFeedScheme, resolveUrl, stripWww, trimUrlValues, upgradeProtocol, upgradeScheme } from "./urls.js";
13
- export { type AnyOf, type DeepOmit, type IsPlainObject, type MaybePromise, type NormalizeOptions, type Nullish, type PartialNullish, type Pattern, type RegistrableDomainOptions, type WeightedMimeType, addMissingProtocol, addMissingScheme, anyWordMatchesAnyOf, archiveExtensions, audioExtensions, codeExtensions, coerceArray, coerceBoolean, coerceDate, coerceNumber, coerceSingular, coerceString, composeQuery, createAcceptHeader, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, documentExtensions, encodePathSegment, endsWithAnyOf, escapeHtml, escapeRegex, feedMimeTypes, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, flashExtensions, fontExtensions, genericFeedMimeTypes, genericHtmlMimeTypes, getAnyOf, getPathSegments, getQueryParam, getQueryParams, getRegistrableDomain, getSubdomain, htmlMimeTypes, imageExtensions, includesAnyOf, installerExtensions, isAnyOf, isBoolean, isFunction, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isJsonLike, isNonEmptyString, isNullish, isNumber, isObject, isParseableJson, isPlainObject, isPresent, isString, isSubdomainOf, isValidDate, normalizeUrl, omit, omitEmpty, parseUrl, pick, resolveFeedProtocol, resolveFeedScheme, resolveUrl, sleep, startsWithAnyOf, stripWww, subtitleExtensions, t, toMap, trimObject, trimUrlValues, tx, upgradeProtocol, upgradeScheme, videoExtensions };
12
+ import { addMissingProtocol, addMissingScheme, composeFragment, composeQuery, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, encodePathSegment, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, getFragmentParam, getFragmentParamValues, getFragmentParams, getPathSegments, getQueryParam, getQueryParamValues, getQueryParams, getRegistrableDomain, getSubdomain, hasFragmentParam, hasQueryParam, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isSubdomainOf, normalizeUrl, parseUrl, resolveFeedProtocol, resolveFeedScheme, resolveUrl, stripWww, trimUrlValues, upgradeProtocol, upgradeScheme } from "./urls.js";
13
+ export { type AnyOf, type DeepOmit, type IsPlainObject, type MaybePromise, type NormalizeOptions, type Nullish, type ParamSource, type PartialNullish, type Pattern, type RegistrableDomainOptions, type WeightedMimeType, addMissingProtocol, addMissingScheme, anyWordMatchesAnyOf, archiveExtensions, audioExtensions, codeExtensions, coerceArray, coerceBoolean, coerceDate, coerceNumber, coerceSingular, coerceString, composeFragment, composeQuery, createAcceptHeader, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, documentExtensions, encodePathSegment, endsWithAnyOf, escapeHtml, escapeRegex, feedMimeTypes, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, flashExtensions, fontExtensions, genericFeedMimeTypes, genericHtmlMimeTypes, getAnyOf, getFragmentParam, getFragmentParamValues, getFragmentParams, getPathSegments, getQueryParam, getQueryParamValues, getQueryParams, getRegistrableDomain, getSubdomain, hasFragmentParam, hasQueryParam, htmlMimeTypes, imageExtensions, includesAnyOf, installerExtensions, isAnyOf, isBoolean, isFunction, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isJsonLike, isNonEmptyString, isNullish, isNumber, isObject, isParseableJson, isPlainObject, isPresent, isString, isSubdomainOf, isValidDate, normalizeUrl, omit, omitEmpty, parseUrl, pick, resolveFeedProtocol, resolveFeedScheme, resolveUrl, sleep, startsWithAnyOf, stripWww, subtitleExtensions, t, toMap, trimObject, trimUrlValues, tx, upgradeProtocol, upgradeScheme, videoExtensions, webAudioExtensions, webImageExtensions, webVideoExtensions };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { isBoolean, isFunction, isNonEmptyString, isNullish, isNumber, isObject, isPlainObject, isPresent, isString, isValidDate } from "./is.js";
2
2
  import { omitEmpty } from "./arrays.js";
3
3
  import { coerceArray, coerceBoolean, coerceDate, coerceNumber, coerceSingular, coerceString } from "./coercions.js";
4
- import { archiveExtensions, audioExtensions, codeExtensions, documentExtensions, flashExtensions, fontExtensions, imageExtensions, installerExtensions, subtitleExtensions, videoExtensions } from "./files.js";
4
+ import { archiveExtensions, audioExtensions, codeExtensions, documentExtensions, flashExtensions, fontExtensions, imageExtensions, installerExtensions, subtitleExtensions, videoExtensions, webAudioExtensions, webImageExtensions, webVideoExtensions } from "./files.js";
5
5
  import { isJsonLike, isParseableJson } from "./json.js";
6
6
  import { escapeHtml, t, tx } from "./locales.js";
7
7
  import { anyWordMatchesAnyOf, endsWithAnyOf, escapeRegex, getAnyOf, includesAnyOf, isAnyOf, startsWithAnyOf } from "./matching.js";
8
8
  import { createAcceptHeader, feedMimeTypes, genericFeedMimeTypes, genericHtmlMimeTypes, htmlMimeTypes } from "./mimes.js";
9
9
  import { omit, pick, toMap, trimObject } from "./objects.js";
10
10
  import { sleep } from "./timers.js";
11
- import { addMissingProtocol, addMissingScheme, composeQuery, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, encodePathSegment, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, getPathSegments, getQueryParam, getQueryParams, getRegistrableDomain, getSubdomain, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isSubdomainOf, normalizeUrl, parseUrl, resolveFeedProtocol, resolveFeedScheme, resolveUrl, stripWww, trimUrlValues, upgradeProtocol, upgradeScheme } from "./urls.js";
12
- export { addMissingProtocol, addMissingScheme, anyWordMatchesAnyOf, archiveExtensions, audioExtensions, codeExtensions, coerceArray, coerceBoolean, coerceDate, coerceNumber, coerceSingular, coerceString, composeQuery, createAcceptHeader, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, documentExtensions, encodePathSegment, endsWithAnyOf, escapeHtml, escapeRegex, feedMimeTypes, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, flashExtensions, fontExtensions, genericFeedMimeTypes, genericHtmlMimeTypes, getAnyOf, getPathSegments, getQueryParam, getQueryParams, getRegistrableDomain, getSubdomain, htmlMimeTypes, imageExtensions, includesAnyOf, installerExtensions, isAnyOf, isBoolean, isFunction, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isJsonLike, isNonEmptyString, isNullish, isNumber, isObject, isParseableJson, isPlainObject, isPresent, isString, isSubdomainOf, isValidDate, normalizeUrl, omit, omitEmpty, parseUrl, pick, resolveFeedProtocol, resolveFeedScheme, resolveUrl, sleep, startsWithAnyOf, stripWww, subtitleExtensions, t, toMap, trimObject, trimUrlValues, tx, upgradeProtocol, upgradeScheme, videoExtensions };
11
+ import { addMissingProtocol, addMissingScheme, composeFragment, composeQuery, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, encodePathSegment, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, getFragmentParam, getFragmentParamValues, getFragmentParams, getPathSegments, getQueryParam, getQueryParamValues, getQueryParams, getRegistrableDomain, getSubdomain, hasFragmentParam, hasQueryParam, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isSubdomainOf, normalizeUrl, parseUrl, resolveFeedProtocol, resolveFeedScheme, resolveUrl, stripWww, trimUrlValues, upgradeProtocol, upgradeScheme } from "./urls.js";
12
+ export { addMissingProtocol, addMissingScheme, anyWordMatchesAnyOf, archiveExtensions, audioExtensions, codeExtensions, coerceArray, coerceBoolean, coerceDate, coerceNumber, coerceSingular, coerceString, composeFragment, composeQuery, createAcceptHeader, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, documentExtensions, encodePathSegment, endsWithAnyOf, escapeHtml, escapeRegex, feedMimeTypes, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, flashExtensions, fontExtensions, genericFeedMimeTypes, genericHtmlMimeTypes, getAnyOf, getFragmentParam, getFragmentParamValues, getFragmentParams, getPathSegments, getQueryParam, getQueryParamValues, getQueryParams, getRegistrableDomain, getSubdomain, hasFragmentParam, hasQueryParam, htmlMimeTypes, imageExtensions, includesAnyOf, installerExtensions, isAnyOf, isBoolean, isFunction, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isJsonLike, isNonEmptyString, isNullish, isNumber, isObject, isParseableJson, isPlainObject, isPresent, isString, isSubdomainOf, isValidDate, normalizeUrl, omit, omitEmpty, parseUrl, pick, resolveFeedProtocol, resolveFeedScheme, resolveUrl, sleep, startsWithAnyOf, stripWww, subtitleExtensions, t, toMap, trimObject, trimUrlValues, tx, upgradeProtocol, upgradeScheme, videoExtensions, webAudioExtensions, webImageExtensions, webVideoExtensions };
package/dist/types.d.ts CHANGED
@@ -5,6 +5,7 @@ export type Nullish<T> = T | null | undefined;
5
5
  export type PartialNullish<T> = { [Key in keyof T]?: Nullish<T[Key]>; };
6
6
  export type MaybePromise<T> = T | Promise<T>;
7
7
  export type Pattern = string | RegExp;
8
+ export type ParamSource = URL | URLSearchParams | string;
8
9
  export type RegistrableDomainOptions = {
9
10
  suffixes?: ReadonlyArray<string>;
10
11
  };
package/dist/urls.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { NormalizeOptions, Nullish, RegistrableDomainOptions } from "./types.js";
1
+ import { NormalizeOptions, Nullish, ParamSource, RegistrableDomainOptions } from "./types.js";
2
2
  export declare const parseUrl: (value: Nullish<string | URL>, base?: string | URL) => URL | undefined;
3
3
  export declare const getPathSegments: (value: string | URL) => Array<string>;
4
4
  export declare const isHostOf: (url: string | URL, hosts: string | ReadonlyArray<string>) => boolean;
@@ -9,9 +9,16 @@ export declare const getSubdomain: (url: string | URL, domains: string | Readonl
9
9
  export declare const decodeSegment: (segment: string | undefined) => string | undefined;
10
10
  export declare const decodePercent: (value: string) => string;
11
11
  export declare const encodePathSegment: (value: string) => string;
12
- export declare const getQueryParams: (params: URLSearchParams | undefined, name: string) => Array<string>;
13
- export declare const getQueryParam: (params: URLSearchParams | undefined, name: string) => string | undefined;
12
+ export declare const hasQueryParam: (source: ParamSource | undefined, name: string) => boolean;
13
+ export declare const getQueryParamValues: (source: ParamSource | undefined, name: string) => Array<string>;
14
+ export declare const getQueryParam: (source: ParamSource | undefined, name: string) => string | undefined;
15
+ export declare const getQueryParams: (source: ParamSource | undefined, names: ReadonlyArray<string>) => Record<string, string>;
16
+ export declare const hasFragmentParam: (source: ParamSource | undefined, name: string) => boolean;
17
+ export declare const getFragmentParamValues: (source: ParamSource | undefined, name: string) => Array<string>;
18
+ export declare const getFragmentParam: (source: ParamSource | undefined, name: string) => string | undefined;
19
+ export declare const getFragmentParams: (source: ParamSource | undefined, names: ReadonlyArray<string>) => Record<string, string>;
14
20
  export declare const composeQuery: (params?: Record<string, string | number>) => string;
21
+ export declare const composeFragment: (params?: Record<string, string | number>) => string;
15
22
  export declare const fixMalformedScheme: (url: string) => string;
16
23
  export declare const fixMalformedQuery: (url: string) => string;
17
24
  export declare const trimUrlValues: (url: string) => string;
package/dist/urls.js CHANGED
@@ -94,25 +94,85 @@ const pathSegmentEscapeRegex = /[/?#\\\s]/g;
94
94
  const encodePathSegment = (value) => {
95
95
  return value.replace(pathSegmentEscapeRegex, (character) => encodeURIComponent(character));
96
96
  };
97
- const getQueryParams = (params, name) => {
97
+ const readQuerySource = (source) => {
98
+ if (source instanceof URL) return source.searchParams;
99
+ if (typeof source === "string") return new URLSearchParams(source);
100
+ return source;
101
+ };
102
+ const readFragmentSource = (source) => {
103
+ if (source instanceof URL) return new URLSearchParams(source.hash.slice(1));
104
+ if (typeof source === "string") return new URLSearchParams(source.startsWith("#") ? source.slice(1) : source);
105
+ return source;
106
+ };
107
+ const readParamValues = (params, name) => {
98
108
  const values = [];
99
109
  if (!params) return values;
100
110
  const lowercaseName = name.toLowerCase();
101
- for (const [key, value] of params) if (key.toLowerCase() === lowercaseName) values.push(value);
111
+ for (const [key, value] of params) {
112
+ if (key.toLowerCase() !== lowercaseName) continue;
113
+ const trimmed = value.trim();
114
+ if (trimmed) values.push(trimmed);
115
+ }
102
116
  return values;
103
117
  };
104
- const getQueryParam = (params, name) => {
105
- return getQueryParams(params, name)[0];
118
+ const hasParam = (params, name) => {
119
+ if (!params) return false;
120
+ const lowercaseName = name.toLowerCase();
121
+ for (const key of params.keys()) if (key.toLowerCase() === lowercaseName) return true;
122
+ return false;
123
+ };
124
+ const readParams = (params, names) => {
125
+ const picked = {};
126
+ for (const name of names) {
127
+ const value = readParamValues(params, name)[0];
128
+ if (value !== void 0) picked[name] = value;
129
+ }
130
+ return picked;
131
+ };
132
+ const hasQueryParam = (source, name) => {
133
+ return hasParam(readQuerySource(source), name);
134
+ };
135
+ const getQueryParamValues = (source, name) => {
136
+ return readParamValues(readQuerySource(source), name);
137
+ };
138
+ const getQueryParam = (source, name) => {
139
+ return getQueryParamValues(source, name)[0];
140
+ };
141
+ const getQueryParams = (source, names) => {
142
+ return readParams(readQuerySource(source), names);
143
+ };
144
+ const hasFragmentParam = (source, name) => {
145
+ return hasParam(readFragmentSource(source), name);
146
+ };
147
+ const getFragmentParamValues = (source, name) => {
148
+ return readParamValues(readFragmentSource(source), name);
149
+ };
150
+ const getFragmentParam = (source, name) => {
151
+ return getFragmentParamValues(source, name)[0];
152
+ };
153
+ const getFragmentParams = (source, names) => {
154
+ return readParams(readFragmentSource(source), names);
106
155
  };
107
156
  const queryPartEscapeRegex = /[&#%+\s]/g;
108
- const composeQuery = (params) => {
157
+ const composePairs = (params) => {
109
158
  const escapePart = (part) => {
110
159
  return part.replace(queryPartEscapeRegex, (character) => encodeURIComponent(character));
111
160
  };
112
- const pairs = Object.entries(params ?? {}).map(([name, value]) => {
113
- return `${escapePart(name)}=${escapePart(String(value))}`;
114
- });
115
- return pairs.length > 0 ? `?${pairs.join("&")}` : "";
161
+ const pairs = [];
162
+ for (const [name, value] of Object.entries(params ?? {})) {
163
+ const text = String(value);
164
+ if (!text) continue;
165
+ pairs.push(`${escapePart(name)}=${escapePart(text)}`);
166
+ }
167
+ return pairs.join("&");
168
+ };
169
+ const composeQuery = (params) => {
170
+ const pairs = composePairs(params);
171
+ return pairs ? `?${pairs}` : "";
172
+ };
173
+ const composeFragment = (params) => {
174
+ const pairs = composePairs(params);
175
+ return pairs ? `#${pairs}` : "";
116
176
  };
117
177
  const strippedParamsCache = /* @__PURE__ */ new WeakMap();
118
178
  const getStrippedParamsSet = (params) => {
@@ -183,6 +243,24 @@ const httpOrSchemeRelativeRegex = /^(?:https?:)?\/\//i;
183
243
  const slugTailRegex = /[/.-]/;
184
244
  const lostSeparatorRegex = /(?<!\s)\s+(?=[A-Za-z_][\w.-]*=)/g;
185
245
  const slashClosedValueRegex = /(=[^&/=]+)\/+(?=&|$)/g;
246
+ const fixFragmentPairs = (fragment) => {
247
+ const nestedOffset = fragment.search(nestedUrlRegex);
248
+ const ownEnd = nestedOffset === -1 ? fragment.length : nestedOffset;
249
+ let fixed = "";
250
+ let hasValue = false;
251
+ for (let index = 0; index < ownEnd; index++) {
252
+ const character = fragment[index];
253
+ if (character === "?" && hasValue) {
254
+ fixed += "&";
255
+ hasValue = false;
256
+ continue;
257
+ }
258
+ if (character === "&") hasValue = false;
259
+ if (character === "=") hasValue = true;
260
+ fixed += character;
261
+ }
262
+ return `${fixed}${fragment.slice(ownEnd)}`;
263
+ };
186
264
  const isGlueTail = (head, glueIndex, pathEnd) => {
187
265
  const tail = head.slice(glueIndex + 1, pathEnd).split("&")[0] ?? "";
188
266
  return tail.includes("=") || !slugTailRegex.test(tail);
@@ -192,7 +270,7 @@ const fixMalformedQuery = (url) => {
192
270
  const hashIndex = url.indexOf("#");
193
271
  const hasFragment = hashIndex !== -1;
194
272
  const head = hasFragment ? url.slice(0, hashIndex) : url;
195
- const fragment = hasFragment ? url.slice(hashIndex) : "";
273
+ const fragment = hasFragment ? fixFragmentPairs(url.slice(hashIndex)) : "";
196
274
  const authorityEnd = head.indexOf("//") + 2;
197
275
  const nestedOffset = head.slice(authorityEnd).search(nestedUrlRegex);
198
276
  const hasNestedUrl = nestedOffset !== -1;
@@ -203,7 +281,7 @@ const fixMalformedQuery = (url) => {
203
281
  const pathEnd = hasMark ? markIndex : ownEnd;
204
282
  const glueIndex = pathIndex !== -1 && pathIndex < pathEnd ? head.indexOf("&", pathIndex) : -1;
205
283
  const isGlued = glueIndex !== -1 && glueIndex < pathEnd && isGlueTail(head, glueIndex, pathEnd);
206
- if (!isGlued && !hasMark) return url;
284
+ if (!isGlued && !hasMark) return `${head}${fragment}`;
207
285
  const queryIndex = isGlued ? glueIndex : markIndex;
208
286
  const queryStart = queryIndex + (isGlued && head[glueIndex + 1] === "?" ? 2 : 1);
209
287
  let query = "";
@@ -229,24 +307,25 @@ const valueEdgeSpaceRegex = new RegExp(`^${valueEdgeSpace}+|(?<!${valueEdgeSpace
229
307
  const trimEdgeSpace = (value, regex) => {
230
308
  return value.replace(regex, "") || value;
231
309
  };
232
- const trimPairValue = (pair) => {
310
+ const trimPairValue = (pair, regex) => {
233
311
  const equalsIndex = pair.indexOf("=");
234
312
  if (equalsIndex === -1) return pair;
235
- const value = trimEdgeSpace(pair.slice(equalsIndex + 1), valueEdgeSpaceRegex);
313
+ const value = trimEdgeSpace(pair.slice(equalsIndex + 1), regex);
236
314
  return `${pair.slice(0, equalsIndex + 1)}${value}`;
237
315
  };
238
316
  const trimUrlValues = (url) => {
239
317
  if (!httpOrSchemeRelativeRegex.test(url)) return url;
240
318
  const hashIndex = url.indexOf("#");
241
319
  const head = hashIndex === -1 ? url : url.slice(0, hashIndex);
242
- const fragment = hashIndex === -1 ? "" : url.slice(hashIndex);
243
320
  const markIndex = head.indexOf("?");
244
321
  const beforeQuery = markIndex === -1 ? head : head.slice(0, markIndex);
245
322
  const pathIndex = beforeQuery.indexOf("/", beforeQuery.indexOf("//") + 2);
246
323
  const authority = pathIndex === -1 ? beforeQuery : beforeQuery.slice(0, pathIndex);
247
324
  const path = (pathIndex === -1 ? [] : beforeQuery.slice(pathIndex).split("/")).map((segment) => trimEdgeSpace(segment, segmentEdgeSpaceRegex)).join("/");
248
325
  const pairs = markIndex === -1 ? [] : head.slice(markIndex + 1).split("&");
249
- return `${authority}${path}${markIndex === -1 ? "" : `?${pairs.map(trimPairValue).join("&")}`}${fragment}`;
326
+ const query = markIndex === -1 ? "" : `?${pairs.map((pair) => trimPairValue(pair, valueEdgeSpaceRegex)).join("&")}`;
327
+ const fragmentPairs = hashIndex === -1 ? [] : url.slice(hashIndex + 1).split("&");
328
+ return `${authority}${path}${query}${hashIndex === -1 ? "" : `#${fragmentPairs.map((pair) => trimPairValue(pair, segmentEdgeSpaceRegex)).join("&")}`}`;
250
329
  };
251
330
  const feedSchemes = [
252
331
  "feed:",
@@ -514,4 +593,4 @@ const resolveFeedProtocol = resolveFeedScheme;
514
593
  const addMissingProtocol = addMissingScheme;
515
594
  /** @deprecated Use `upgradeScheme` instead. */
516
595
  const upgradeProtocol = upgradeScheme;
517
- export { addMissingProtocol, addMissingScheme, composeQuery, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, encodePathSegment, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, getPathSegments, getQueryParam, getQueryParams, getRegistrableDomain, getSubdomain, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isSubdomainOf, normalizeUrl, parseUrl, resolveFeedProtocol, resolveFeedScheme, resolveUrl, stripWww, trimUrlValues, upgradeProtocol, upgradeScheme };
596
+ export { addMissingProtocol, addMissingScheme, composeFragment, composeQuery, createUrlSpellings, createUrlVariants, decodePercent, decodeSegment, encodePathSegment, fixMalformedProtocol, fixMalformedQuery, fixMalformedScheme, getFragmentParam, getFragmentParamValues, getFragmentParams, getPathSegments, getQueryParam, getQueryParamValues, getQueryParams, getRegistrableDomain, getSubdomain, hasFragmentParam, hasQueryParam, isHostOf, isHostOrSubdomainOf, isHttpUrl, isIpAddress, isSubdomainOf, normalizeUrl, parseUrl, resolveFeedProtocol, resolveFeedScheme, resolveUrl, stripWww, trimUrlValues, upgradeProtocol, upgradeScheme };
package/package.json CHANGED
@@ -40,11 +40,11 @@
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/bun": "^1.4.2",
43
- "kvalita": "^1.28.0",
43
+ "kvalita": "^1.30.0",
44
44
  "tsdown": "0.23.1"
45
45
  },
46
46
  "dependencies": {
47
47
  "entities": "^8.1.0"
48
48
  },
49
- "version": "2.16.3"
49
+ "version": "3.1.0"
50
50
  }