normalize-url 8.0.2 → 8.1.1
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/index.d.ts +39 -0
- package/index.js +34 -14
- package/package.json +1 -1
- package/readme.md +35 -0
package/index.d.ts
CHANGED
|
@@ -278,6 +278,45 @@ export type Options = {
|
|
|
278
278
|
```
|
|
279
279
|
*/
|
|
280
280
|
readonly sortQueryParameters?: boolean;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
Removes the entire URL path, leaving only the domain.
|
|
284
|
+
|
|
285
|
+
@default false
|
|
286
|
+
|
|
287
|
+
@example
|
|
288
|
+
```
|
|
289
|
+
normalizeUrl('https://example.com/path/to/page', {
|
|
290
|
+
removePath: true
|
|
291
|
+
});
|
|
292
|
+
//=> 'https://example.com'
|
|
293
|
+
```
|
|
294
|
+
*/
|
|
295
|
+
readonly removePath?: boolean;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
Custom function to transform the URL path components.
|
|
299
|
+
|
|
300
|
+
The function receives an array of non-empty path components and should return a modified array.
|
|
301
|
+
|
|
302
|
+
@default false
|
|
303
|
+
|
|
304
|
+
@example
|
|
305
|
+
```
|
|
306
|
+
// Keep only the first path component
|
|
307
|
+
normalizeUrl('https://example.com/api/v1/users', {
|
|
308
|
+
transformPath: (pathComponents) => pathComponents.slice(0, 1)
|
|
309
|
+
});
|
|
310
|
+
//=> 'https://example.com/api'
|
|
311
|
+
|
|
312
|
+
// Remove specific components
|
|
313
|
+
normalizeUrl('https://example.com/admin/users', {
|
|
314
|
+
transformPath: (pathComponents) => pathComponents.filter(c => c !== 'admin')
|
|
315
|
+
});
|
|
316
|
+
//=> 'https://example.com/users'
|
|
317
|
+
```
|
|
318
|
+
*/
|
|
319
|
+
readonly transformPath?: (pathComponents: string[]) => string[];
|
|
281
320
|
};
|
|
282
321
|
|
|
283
322
|
/**
|
package/index.js
CHANGED
|
@@ -29,14 +29,12 @@ const normalizeDataURL = (urlString, {stripHash}) => {
|
|
|
29
29
|
throw new Error(`Invalid URL: ${urlString}`);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
const {type, data, hash} = match.groups;
|
|
33
33
|
const mediaType = type.split(';');
|
|
34
|
-
hash = stripHash ? '' : hash;
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
if (
|
|
35
|
+
const isBase64 = mediaType.at(-1) === 'base64';
|
|
36
|
+
if (isBase64) {
|
|
38
37
|
mediaType.pop();
|
|
39
|
-
isBase64 = true;
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
// Lowercase MIME type
|
|
@@ -58,9 +56,7 @@ const normalizeDataURL = (urlString, {stripHash}) => {
|
|
|
58
56
|
})
|
|
59
57
|
.filter(Boolean);
|
|
60
58
|
|
|
61
|
-
const normalizedMediaType = [
|
|
62
|
-
...attributes,
|
|
63
|
-
];
|
|
59
|
+
const normalizedMediaType = [...attributes];
|
|
64
60
|
|
|
65
61
|
if (isBase64) {
|
|
66
62
|
normalizedMediaType.push('base64');
|
|
@@ -70,7 +66,8 @@ const normalizeDataURL = (urlString, {stripHash}) => {
|
|
|
70
66
|
normalizedMediaType.unshift(mimeType);
|
|
71
67
|
}
|
|
72
68
|
|
|
73
|
-
|
|
69
|
+
const hashPart = stripHash || !hash ? '' : `#${hash}`;
|
|
70
|
+
return `data:${normalizedMediaType.join(';')},${isBase64 ? data.trim() : data}${hashPart}`;
|
|
74
71
|
};
|
|
75
72
|
|
|
76
73
|
export default function normalizeUrl(urlString, options) {
|
|
@@ -89,6 +86,8 @@ export default function normalizeUrl(urlString, options) {
|
|
|
89
86
|
removeDirectoryIndex: false,
|
|
90
87
|
removeExplicitPort: false,
|
|
91
88
|
sortQueryParameters: true,
|
|
89
|
+
removePath: false,
|
|
90
|
+
transformPath: false,
|
|
92
91
|
...options,
|
|
93
92
|
};
|
|
94
93
|
|
|
@@ -191,15 +190,27 @@ export default function normalizeUrl(urlString, options) {
|
|
|
191
190
|
}
|
|
192
191
|
|
|
193
192
|
if (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {
|
|
194
|
-
|
|
195
|
-
const lastComponent = pathComponents
|
|
193
|
+
const pathComponents = urlObject.pathname.split('/').filter(Boolean);
|
|
194
|
+
const lastComponent = pathComponents.at(-1);
|
|
196
195
|
|
|
197
|
-
if (testParameter(lastComponent, options.removeDirectoryIndex)) {
|
|
198
|
-
pathComponents
|
|
199
|
-
urlObject.pathname = pathComponents.
|
|
196
|
+
if (lastComponent && testParameter(lastComponent, options.removeDirectoryIndex)) {
|
|
197
|
+
pathComponents.pop();
|
|
198
|
+
urlObject.pathname = pathComponents.length > 0 ? `/${pathComponents.join('/')}/` : '/';
|
|
200
199
|
}
|
|
201
200
|
}
|
|
202
201
|
|
|
202
|
+
// Remove path
|
|
203
|
+
if (options.removePath) {
|
|
204
|
+
urlObject.pathname = '/';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Transform path components
|
|
208
|
+
if (options.transformPath && typeof options.transformPath === 'function') {
|
|
209
|
+
const pathComponents = urlObject.pathname.split('/').filter(Boolean);
|
|
210
|
+
const newComponents = options.transformPath(pathComponents);
|
|
211
|
+
urlObject.pathname = newComponents?.length > 0 ? `/${newComponents.join('/')}` : '/';
|
|
212
|
+
}
|
|
213
|
+
|
|
203
214
|
if (urlObject.hostname) {
|
|
204
215
|
// Remove trailing dot
|
|
205
216
|
urlObject.hostname = urlObject.hostname.replace(/\.$/, '');
|
|
@@ -240,12 +251,21 @@ export default function normalizeUrl(urlString, options) {
|
|
|
240
251
|
|
|
241
252
|
// Sort query parameters
|
|
242
253
|
if (options.sortQueryParameters) {
|
|
254
|
+
const originalSearch = urlObject.search;
|
|
243
255
|
urlObject.searchParams.sort();
|
|
244
256
|
|
|
245
257
|
// Calling `.sort()` encodes the search parameters, so we need to decode them again.
|
|
246
258
|
try {
|
|
247
259
|
urlObject.search = decodeURIComponent(urlObject.search);
|
|
248
260
|
} catch {}
|
|
261
|
+
|
|
262
|
+
// Fix parameters that originally had no equals sign but got one added by URLSearchParams
|
|
263
|
+
const partsWithoutEquals = originalSearch.slice(1).split('&').filter(p => p && !p.includes('='));
|
|
264
|
+
for (const part of partsWithoutEquals) {
|
|
265
|
+
const decoded = decodeURIComponent(part);
|
|
266
|
+
// Only replace at word boundaries to avoid partial matches
|
|
267
|
+
urlObject.search = urlObject.search.replace(`?${decoded}=`, `?${decoded}`).replace(`&${decoded}=`, `&${decoded}`);
|
|
268
|
+
}
|
|
249
269
|
}
|
|
250
270
|
|
|
251
271
|
if (options.removeTrailingSlash) {
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -307,6 +307,41 @@ normalizeUrl('www.sindresorhus.com?b=two&a=one&c=three', {
|
|
|
307
307
|
//=> 'http://sindresorhus.com/?b=two&a=one&c=three'
|
|
308
308
|
```
|
|
309
309
|
|
|
310
|
+
##### removePath
|
|
311
|
+
|
|
312
|
+
Type: `boolean`\
|
|
313
|
+
Default: `false`
|
|
314
|
+
|
|
315
|
+
Removes the entire URL path, leaving only the domain.
|
|
316
|
+
|
|
317
|
+
```js
|
|
318
|
+
normalizeUrl('https://example.com/path/to/page', {
|
|
319
|
+
removePath: true
|
|
320
|
+
});
|
|
321
|
+
//=> 'https://example.com'
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
##### transformPath
|
|
325
|
+
|
|
326
|
+
Type: `Function`\
|
|
327
|
+
Default: `false`
|
|
328
|
+
|
|
329
|
+
Custom function to transform the URL path components. The function receives an array of non-empty path components and should return a modified array.
|
|
330
|
+
|
|
331
|
+
```js
|
|
332
|
+
// Keep only the first path component
|
|
333
|
+
normalizeUrl('https://example.com/api/v1/users', {
|
|
334
|
+
transformPath: (pathComponents) => pathComponents.slice(0, 1)
|
|
335
|
+
});
|
|
336
|
+
//=> 'https://example.com/api'
|
|
337
|
+
|
|
338
|
+
// Remove specific components
|
|
339
|
+
normalizeUrl('https://example.com/admin/users', {
|
|
340
|
+
transformPath: (pathComponents) => pathComponents.filter(c => c !== 'admin')
|
|
341
|
+
});
|
|
342
|
+
//=> 'https://example.com/users'
|
|
343
|
+
```
|
|
344
|
+
|
|
310
345
|
## Related
|
|
311
346
|
|
|
312
347
|
- [compare-urls](https://github.com/sindresorhus/compare-urls) - Compare URLs by first normalizing them
|