normalize-url 4.4.0 → 5.0.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.
Files changed (4) hide show
  1. package/index.d.ts +17 -24
  2. package/index.js +33 -49
  3. package/package.json +6 -5
  4. package/readme.md +13 -17
package/index.d.ts CHANGED
@@ -188,29 +188,22 @@ declare namespace normalizeUrl {
188
188
  }
189
189
  }
190
190
 
191
- declare const normalizeUrl: {
192
- /**
193
- [Normalize](https://en.wikipedia.org/wiki/URL_normalization) a URL.
194
-
195
- @param url - URL to normalize, including [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs).
196
-
197
- @example
198
- ```
199
- import normalizeUrl = require('normalize-url');
200
-
201
- normalizeUrl('sindresorhus.com');
202
- //=> 'http://sindresorhus.com'
203
-
204
- normalizeUrl('HTTP://xn--xample-hva.com:80/?b=bar&a=foo');
205
- //=> 'http://êxample.com/?a=foo&b=bar'
206
- ```
207
- */
208
- (url: string, options?: normalizeUrl.Options): string;
209
-
210
- // TODO: Remove this for the next major release, refactor the whole definition to:
211
- // declare function normalizeUrl(url: string, options?: normalizeUrl.Options): string;
212
- // export = normalizeUrl;
213
- default: typeof normalizeUrl;
214
- };
191
+ /**
192
+ [Normalize](https://en.wikipedia.org/wiki/URL_normalization) a URL.
193
+
194
+ @param url - URL to normalize, including [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs).
195
+
196
+ @example
197
+ ```
198
+ import normalizeUrl = require('normalize-url');
199
+
200
+ normalizeUrl('sindresorhus.com');
201
+ //=> 'http://sindresorhus.com'
202
+
203
+ normalizeUrl('HTTP://xn--xample-hva.com:80/?b=bar&a=foo');
204
+ //=> 'http://êxample.com/?a=foo&b=bar'
205
+ ```
206
+ */
207
+ declare function normalizeUrl(url: string, options?: normalizeUrl.Options): string;
215
208
 
216
209
  export = normalizeUrl;
package/index.js CHANGED
@@ -1,56 +1,62 @@
1
1
  'use strict';
2
- // TODO: Use the `URL` global when targeting Node.js 10
3
- const URLParser = typeof URL === 'undefined' ? require('url').URL : URL;
2
+
3
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
4
+ const DATA_URL_DEFAULT_MIME_TYPE = 'text/plain';
5
+ const DATA_URL_DEFAULT_CHARSET = 'us-ascii';
4
6
 
5
7
  const testParameter = (name, filters) => {
6
8
  return filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);
7
9
  };
8
10
 
9
- const normalizeDataURL = urlString => {
10
- const parts = urlString.trim().match(/^data:(.*?),(.*)$/);
11
+ const normalizeDataURL = (urlString, {stripHash}) => {
12
+ const match = /^data:(?<type>.*?),(?<data>.*?)(?:#(?<hash>.*))?$/.exec(urlString);
11
13
 
12
- if (!parts) {
14
+ if (!match) {
13
15
  throw new Error(`Invalid URL: ${urlString}`);
14
16
  }
15
17
 
16
- const mediaType = parts[1].split(';');
17
- const body = parts[2];
18
-
19
- let base64 = false;
18
+ let {type, data, hash} = match.groups;
19
+ const mediaType = type.split(';');
20
+ hash = stripHash ? '' : hash;
20
21
 
22
+ let isBase64 = false;
21
23
  if (mediaType[mediaType.length - 1] === 'base64') {
22
24
  mediaType.pop();
23
- base64 = true;
25
+ isBase64 = true;
24
26
  }
25
27
 
26
28
  // Lowercase MIME type
27
29
  const mimeType = (mediaType.shift() || '').toLowerCase();
28
30
  const attributes = mediaType
29
- .filter(Boolean)
30
31
  .map(attribute => {
31
32
  let [key, value = ''] = attribute.split('=').map(string => string.trim());
32
33
 
33
34
  // Lowercase `charset`
34
35
  if (key === 'charset') {
35
36
  value = value.toLowerCase();
37
+
38
+ if (value === DATA_URL_DEFAULT_CHARSET) {
39
+ return '';
40
+ }
36
41
  }
37
42
 
38
- return `${key}=${value}`;
39
- });
43
+ return `${key}${value ? `=${value}` : ''}`;
44
+ })
45
+ .filter(Boolean);
40
46
 
41
47
  const normalizedMediaType = [
42
48
  ...attributes
43
49
  ];
44
50
 
45
- if (base64) {
51
+ if (isBase64) {
46
52
  normalizedMediaType.push('base64');
47
53
  }
48
54
 
49
- if (normalizedMediaType.length !== 0 || mimeType) {
55
+ if (normalizedMediaType.length !== 0 || (mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE)) {
50
56
  normalizedMediaType.unshift(mimeType);
51
57
  }
52
58
 
53
- return `data:${normalizedMediaType.join(';')},${base64 ? body.trim() : body}`;
59
+ return `data:${normalizedMediaType.join(';')},${isBase64 ? data.trim() : data}${hash ? `#${hash}` : ''}`;
54
60
  };
55
61
 
56
62
  const normalizeUrl = (urlString, options) => {
@@ -69,30 +75,22 @@ const normalizeUrl = (urlString, options) => {
69
75
  ...options
70
76
  };
71
77
 
72
- // TODO: Remove this at some point in the future
73
- if (Reflect.has(options, 'normalizeHttps')) {
74
- throw new Error('options.normalizeHttps is renamed to options.forceHttp');
75
- }
76
-
77
- if (Reflect.has(options, 'normalizeHttp')) {
78
- throw new Error('options.normalizeHttp is renamed to options.forceHttps');
79
- }
78
+ urlString = urlString.trim();
80
79
 
81
- if (Reflect.has(options, 'stripFragment')) {
82
- throw new Error('options.stripFragment is renamed to options.stripHash');
80
+ // Data URL
81
+ if (/^data:/i.test(urlString)) {
82
+ return normalizeDataURL(urlString, options);
83
83
  }
84
84
 
85
- urlString = urlString.trim();
86
-
87
85
  const hasRelativeProtocol = urlString.startsWith('//');
88
86
  const isRelativeUrl = !hasRelativeProtocol && /^\.*\//.test(urlString);
89
87
 
90
88
  // Prepend protocol
91
- if (!isRelativeUrl && !/^data:/i.test(urlString)) {
89
+ if (!isRelativeUrl) {
92
90
  urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, options.defaultProtocol);
93
91
  }
94
92
 
95
- const urlObj = new URLParser(urlString);
93
+ const urlObj = new URL(urlString);
96
94
 
97
95
  if (options.forceHttp && options.forceHttps) {
98
96
  throw new Error('The `forceHttp` and `forceHttps` options cannot be used together');
@@ -119,20 +117,14 @@ const normalizeUrl = (urlString, options) => {
119
117
 
120
118
  // Remove duplicate slashes if not preceded by a protocol
121
119
  if (urlObj.pathname) {
122
- // TODO: Use the following instead when targeting Node.js 10
123
- // `urlObj.pathname = urlObj.pathname.replace(/(?<!https?:)\/{2,}/g, '/');`
124
- urlObj.pathname = urlObj.pathname.replace(/((?!:).|^)\/{2,}/g, (_, p1) => {
125
- if (/^(?!\/)/g.test(p1)) {
126
- return `${p1}/`;
127
- }
128
-
129
- return '/';
130
- });
120
+ urlObj.pathname = urlObj.pathname.replace(/(?<!https?:)\/{2,}/g, '/');
131
121
  }
132
122
 
133
123
  // Decode URI octets
134
124
  if (urlObj.pathname) {
135
- urlObj.pathname = decodeURI(urlObj.pathname);
125
+ try {
126
+ urlObj.pathname = decodeURI(urlObj.pathname);
127
+ } catch (_) {}
136
128
  }
137
129
 
138
130
  // Remove directory index
@@ -155,7 +147,7 @@ const normalizeUrl = (urlString, options) => {
155
147
  urlObj.hostname = urlObj.hostname.replace(/\.$/, '');
156
148
 
157
149
  // Remove `www.`
158
- if (options.stripWWW && /^www\.([a-z\-\d]{2,63})\.([a-z.]{2,5})$/.test(urlObj.hostname)) {
150
+ if (options.stripWWW && /^www\.(?:[a-z\-\d]{2,63})\.(?:[a-z.]{2,5})$/.test(urlObj.hostname)) {
159
151
  // Each label should be max 63 at length (min: 2).
160
152
  // The extension should be max 5 at length (min: 2).
161
153
  // Source: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names
@@ -177,12 +169,6 @@ const normalizeUrl = (urlString, options) => {
177
169
  urlObj.searchParams.sort();
178
170
  }
179
171
 
180
- // Data URL
181
- if (urlObj.protocol === 'data:') {
182
- const url = normalizeDataURL(`${urlObj.protocol}${urlObj.pathname}`);
183
- return `${url}${urlObj.search}${urlObj.hash}`;
184
- }
185
-
186
172
  if (options.removeTrailingSlash) {
187
173
  urlObj.pathname = urlObj.pathname.replace(/\/$/, '');
188
174
  }
@@ -209,5 +195,3 @@ const normalizeUrl = (urlString, options) => {
209
195
  };
210
196
 
211
197
  module.exports = normalizeUrl;
212
- // TODO: Remove this for the next major release
213
- module.exports.default = normalizeUrl;
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "normalize-url",
3
- "version": "4.4.0",
3
+ "version": "5.0.0",
4
4
  "description": "Normalize a URL",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/normalize-url",
7
+ "funding": "https://github.com/sponsors/sindresorhus",
7
8
  "author": {
8
9
  "name": "Sindre Sorhus",
9
10
  "email": "sindresorhus@gmail.com",
10
11
  "url": "sindresorhus.com"
11
12
  },
12
13
  "engines": {
13
- "node": ">=8"
14
+ "node": ">=10"
14
15
  },
15
16
  "scripts": {
16
17
  "test": "xo && nyc ava && tsd"
@@ -37,8 +38,8 @@
37
38
  "devDependencies": {
38
39
  "ava": "^2.4.0",
39
40
  "coveralls": "^3.0.6",
40
- "nyc": "^14.1.1",
41
- "tsd": "^0.8.0",
42
- "xo": "^0.24.0"
41
+ "nyc": "^15.0.0",
42
+ "tsd": "^0.11.0",
43
+ "xo": "^0.25.3"
43
44
  }
44
45
  }
package/readme.md CHANGED
@@ -4,14 +4,12 @@
4
4
 
5
5
  Useful when you need to display, store, deduplicate, sort, compare, etc, URLs.
6
6
 
7
-
8
7
  ## Install
9
8
 
10
9
  ```
11
10
  $ npm install normalize-url
12
11
  ```
13
12
 
14
-
15
13
  ## Usage
16
14
 
17
15
  ```js
@@ -24,7 +22,6 @@ normalizeUrl('HTTP://xn--xample-hva.com:80/?b=bar&a=foo');
24
22
  //=> 'http://êxample.com/?a=foo&b=bar'
25
23
  ```
26
24
 
27
-
28
25
  ## API
29
26
 
30
27
  ### normalizeUrl(url, options?)
@@ -41,12 +38,12 @@ Type: `object`
41
38
 
42
39
  ##### defaultProtocol
43
40
 
44
- Type: `string`<br>
41
+ Type: `string`\
45
42
  Default: `http:`
46
43
 
47
44
  ##### normalizeProtocol
48
45
 
49
- Type: `boolean`<br>
46
+ Type: `boolean`\
50
47
  Default: `true`
51
48
 
52
49
  Prepend `defaultProtocol` to the URL if it's protocol-relative.
@@ -61,7 +58,7 @@ normalizeUrl('//sindresorhus.com:80/', {normalizeProtocol: false});
61
58
 
62
59
  ##### forceHttp
63
60
 
64
- Type: `boolean`<br>
61
+ Type: `boolean`\
65
62
  Default: `false`
66
63
 
67
64
  Normalize `https:` to `http:`.
@@ -76,7 +73,7 @@ normalizeUrl('https://sindresorhus.com:80/', {forceHttp: true});
76
73
 
77
74
  ##### forceHttps
78
75
 
79
- Type: `boolean`<br>
76
+ Type: `boolean`\
80
77
  Default: `false`
81
78
 
82
79
  Normalize `http:` to `https:`.
@@ -93,7 +90,7 @@ This option can't be used with the `forceHttp` option at the same time.
93
90
 
94
91
  ##### stripAuthentication
95
92
 
96
- Type: `boolean`<br>
93
+ Type: `boolean`\
97
94
  Default: `true`
98
95
 
99
96
  Strip the [authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) part of the URL.
@@ -108,7 +105,7 @@ normalizeUrl('user:password@sindresorhus.com', {stripAuthentication: false});
108
105
 
109
106
  ##### stripHash
110
107
 
111
- Type: `boolean`<br>
108
+ Type: `boolean`\
112
109
  Default: `false`
113
110
 
114
111
  Strip the hash part of the URL.
@@ -123,7 +120,7 @@ normalizeUrl('sindresorhus.com/about.html#contact', {stripHash: true});
123
120
 
124
121
  ##### stripProtocol
125
122
 
126
- Type: `boolean`<br>
123
+ Type: `boolean`\
127
124
  Default: `false`
128
125
 
129
126
  Remove HTTP(S) protocol from the URL: `http://sindresorhus.com` → `sindresorhus.com`.
@@ -132,13 +129,13 @@ Remove HTTP(S) protocol from the URL: `http://sindresorhus.com` → `sindresorhu
132
129
  normalizeUrl('https://sindresorhus.com');
133
130
  //=> 'https://sindresorhus.com'
134
131
 
135
- normalizeUrl('sindresorhus.com', {stripProtocol: true});
132
+ normalizeUrl('https://sindresorhus.com', {stripProtocol: true});
136
133
  //=> 'sindresorhus.com'
137
134
  ```
138
135
 
139
136
  ##### stripWWW
140
137
 
141
- Type: `boolean`<br>
138
+ Type: `boolean`\
142
139
  Default: `true`
143
140
 
144
141
  Remove `www.` from the URL.
@@ -153,7 +150,7 @@ normalizeUrl('http://www.sindresorhus.com', {stripWWW: false});
153
150
 
154
151
  ##### removeQueryParameters
155
152
 
156
- Type: `Array<RegExp | string>`<br>
153
+ Type: `Array<RegExp | string>`\
157
154
  Default: `[/^utm_\w+/i]`
158
155
 
159
156
  Remove query parameters that matches any of the provided strings or regexes.
@@ -167,7 +164,7 @@ normalizeUrl('www.sindresorhus.com?foo=bar&ref=test_ref', {
167
164
 
168
165
  ##### removeTrailingSlash
169
166
 
170
- Type: `boolean`<br>
167
+ Type: `boolean`\
171
168
  Default: `true`
172
169
 
173
170
  Remove trailing slash.
@@ -187,7 +184,7 @@ normalizeUrl('http://sindresorhus.com/', {removeTrailingSlash: false});
187
184
 
188
185
  ##### removeDirectoryIndex
189
186
 
190
- Type: `boolean | Array<RegExp | string>`<br>
187
+ Type: `boolean | Array<RegExp | string>`\
191
188
  Default: `false`
192
189
 
193
190
  Removes the default directory index file from path that matches any of the provided strings or regexes. When `true`, the regex `/^index\.[a-z]+$/` is used.
@@ -201,7 +198,7 @@ normalizeUrl('www.sindresorhus.com/foo/default.php', {
201
198
 
202
199
  ##### sortQueryParameters
203
200
 
204
- Type: `boolean`<br>
201
+ Type: `boolean`\
205
202
  Default: `true`
206
203
 
207
204
  Sorts the query parameters alphabetically by key.
@@ -213,7 +210,6 @@ normalizeUrl('www.sindresorhus.com?b=two&a=one&c=three', {
213
210
  //=> 'http://sindresorhus.com/?b=two&a=one&c=three'
214
211
  ```
215
212
 
216
-
217
213
  ## Related
218
214
 
219
215
  - [compare-urls](https://github.com/sindresorhus/compare-urls) - Compare URLs by first normalizing them