normalize-url 3.3.0 → 4.3.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 +216 -0
  2. package/index.js +50 -29
  3. package/package.json +10 -8
  4. package/readme.md +39 -9
package/index.d.ts ADDED
@@ -0,0 +1,216 @@
1
+ declare namespace normalizeUrl {
2
+ interface Options {
3
+ /**
4
+ @default 'http:'
5
+ */
6
+ readonly defaultProtocol?: string;
7
+
8
+ /**
9
+ Prepends `defaultProtocol` to the URL if it's protocol-relative.
10
+
11
+ @default true
12
+
13
+ @example
14
+ ```
15
+ normalizeUrl('//sindresorhus.com:80/');
16
+ //=> 'http://sindresorhus.com'
17
+
18
+ normalizeUrl('//sindresorhus.com:80/', {normalizeProtocol: false});
19
+ //=> '//sindresorhus.com'
20
+ ```
21
+ */
22
+ readonly normalizeProtocol?: boolean;
23
+
24
+ /**
25
+ Normalizes `https:` URLs to `http:`.
26
+
27
+ @default false
28
+
29
+ @example
30
+ ```
31
+ normalizeUrl('https://sindresorhus.com:80/');
32
+ //=> 'https://sindresorhus.com'
33
+
34
+ normalizeUrl('https://sindresorhus.com:80/', {forceHttp: true});
35
+ //=> 'http://sindresorhus.com'
36
+ ```
37
+ */
38
+ readonly forceHttp?: boolean;
39
+
40
+ /**
41
+ Normalizes `http:` URLs to `https:`.
42
+
43
+ This option can't be used with the `forceHttp` option at the same time.
44
+
45
+ @default false
46
+
47
+ @example
48
+ ```
49
+ normalizeUrl('https://sindresorhus.com:80/');
50
+ //=> 'https://sindresorhus.com'
51
+
52
+ normalizeUrl('http://sindresorhus.com:80/', {forceHttps: true});
53
+ //=> 'https://sindresorhus.com'
54
+ ```
55
+ */
56
+ readonly forceHttps?: boolean;
57
+
58
+ /**
59
+ Strip the [authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) part of a URL.
60
+
61
+ @default true
62
+
63
+ @example
64
+ ```
65
+ normalizeUrl('user:password@sindresorhus.com');
66
+ //=> 'https://sindresorhus.com'
67
+
68
+ normalizeUrl('user:password@sindresorhus.com', {stripAuthentication: false});
69
+ //=> 'https://user:password@sindresorhus.com'
70
+ ```
71
+ */
72
+ readonly stripAuthentication?: boolean;
73
+
74
+ /**
75
+ Removes hash from the URL.
76
+
77
+ @default false
78
+
79
+ @example
80
+ ```
81
+ normalizeUrl('sindresorhus.com/about.html#contact');
82
+ //=> 'http://sindresorhus.com/about.html#contact'
83
+
84
+ normalizeUrl('sindresorhus.com/about.html#contact', {stripHash: true});
85
+ //=> 'http://sindresorhus.com/about.html'
86
+ ```
87
+ */
88
+ readonly stripHash?: boolean;
89
+
90
+ /**
91
+ Removes HTTP(S) protocol from an URL `http://sindresorhus.com` → `sindresorhus.com`.
92
+
93
+ @default false
94
+
95
+ @example
96
+ ```
97
+ normalizeUrl('https://sindresorhus.com');
98
+ //=> 'https://sindresorhus.com'
99
+
100
+ normalizeUrl('sindresorhus.com', {stripProtocol: true});
101
+ //=> 'sindresorhus.com'
102
+ ```
103
+ */
104
+ readonly stripProtocol?: boolean;
105
+
106
+ /**
107
+ Removes `www.` from the URL.
108
+
109
+ @default true
110
+
111
+ @example
112
+ ```
113
+ normalizeUrl('http://www.sindresorhus.com');
114
+ //=> 'http://sindresorhus.com'
115
+
116
+ normalizeUrl('http://www.sindresorhus.com', {stripWWW: false});
117
+ //=> 'http://www.sindresorhus.com'
118
+ ```
119
+ */
120
+ readonly stripWWW?: boolean;
121
+
122
+ /**
123
+ Removes query parameters that matches any of the provided strings or regexes.
124
+
125
+ @default [/^utm_\w+/i]
126
+
127
+ @example
128
+ ```
129
+ normalizeUrl('www.sindresorhus.com?foo=bar&ref=test_ref', {
130
+ removeQueryParameters: ['ref']
131
+ });
132
+ //=> 'http://sindresorhus.com/?foo=bar'
133
+ ```
134
+ */
135
+ readonly removeQueryParameters?: (RegExp | string)[];
136
+
137
+ /**
138
+ Removes trailing slash.
139
+
140
+ __Note__: Trailing slash is always removed if the URL doesn't have a pathname.
141
+
142
+ @default true
143
+
144
+ @example
145
+ ```
146
+ normalizeUrl('http://sindresorhus.com/redirect/');
147
+ //=> 'http://sindresorhus.com/redirect'
148
+
149
+ normalizeUrl('http://sindresorhus.com/redirect/', {removeTrailingSlash: false});
150
+ //=> 'http://sindresorhus.com/redirect/'
151
+
152
+ normalizeUrl('http://sindresorhus.com/', {removeTrailingSlash: false});
153
+ //=> 'http://sindresorhus.com'
154
+ ```
155
+ */
156
+ readonly removeTrailingSlash?: boolean;
157
+
158
+ /**
159
+ Removes the default directory index file from path that matches any of the provided strings or regexes.
160
+ When `true`, the regex `/^index\.[a-z]+$/` is used.
161
+
162
+ @default false
163
+
164
+ @example
165
+ ```
166
+ normalizeUrl('www.sindresorhus.com/foo/default.php', {
167
+ removeDirectoryIndex: [/^default\.[a-z]+$/]
168
+ });
169
+ //=> 'http://sindresorhus.com/foo'
170
+ ```
171
+ */
172
+ readonly removeDirectoryIndex?: (RegExp | string)[];
173
+
174
+ /**
175
+ Sorts the query parameters alphabetically by key.
176
+
177
+ @default true
178
+
179
+ @example
180
+ ```
181
+ normalizeUrl('www.sindresorhus.com?b=two&a=one&c=three', {
182
+ sortQueryParameters: false
183
+ });
184
+ //=> 'http://sindresorhus.com/?b=two&a=one&c=three'
185
+ ```
186
+ */
187
+ readonly sortQueryParameters?: boolean;
188
+ }
189
+ }
190
+
191
+ declare const normalizeUrl: {
192
+ /**
193
+ [Normalize](https://en.wikipedia.org/wiki/URL_normalization) a URL.
194
+
195
+ @param url - URL to normalize.
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
+ };
215
+
216
+ export = normalizeUrl;
package/index.js CHANGED
@@ -6,31 +6,33 @@ const testParameter = (name, filters) => {
6
6
  return filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);
7
7
  };
8
8
 
9
- module.exports = (urlString, opts) => {
10
- opts = Object.assign({
9
+ const normalizeUrl = (urlString, options) => {
10
+ options = {
11
11
  defaultProtocol: 'http:',
12
12
  normalizeProtocol: true,
13
13
  forceHttp: false,
14
14
  forceHttps: false,
15
- stripHash: true,
15
+ stripAuthentication: true,
16
+ stripHash: false,
16
17
  stripWWW: true,
17
18
  removeQueryParameters: [/^utm_\w+/i],
18
19
  removeTrailingSlash: true,
19
20
  removeDirectoryIndex: false,
20
- sortQueryParameters: true
21
- }, opts);
21
+ sortQueryParameters: true,
22
+ ...options
23
+ };
22
24
 
23
- // Backwards compatibility
24
- if (Reflect.has(opts, 'normalizeHttps')) {
25
- opts.forceHttp = opts.normalizeHttps;
25
+ // TODO: Remove this at some point in the future
26
+ if (Reflect.has(options, 'normalizeHttps')) {
27
+ throw new Error('options.normalizeHttps is renamed to options.forceHttp');
26
28
  }
27
29
 
28
- if (Reflect.has(opts, 'normalizeHttp')) {
29
- opts.forceHttps = opts.normalizeHttp;
30
+ if (Reflect.has(options, 'normalizeHttp')) {
31
+ throw new Error('options.normalizeHttp is renamed to options.forceHttps');
30
32
  }
31
33
 
32
- if (Reflect.has(opts, 'stripFragment')) {
33
- opts.stripHash = opts.stripFragment;
34
+ if (Reflect.has(options, 'stripFragment')) {
35
+ throw new Error('options.stripFragment is renamed to options.stripHash');
34
36
  }
35
37
 
36
38
  urlString = urlString.trim();
@@ -40,25 +42,31 @@ module.exports = (urlString, opts) => {
40
42
 
41
43
  // Prepend protocol
42
44
  if (!isRelativeUrl) {
43
- urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, opts.defaultProtocol);
45
+ urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, options.defaultProtocol);
44
46
  }
45
47
 
46
48
  const urlObj = new URLParser(urlString);
47
49
 
48
- if (opts.forceHttp && opts.forceHttps) {
50
+ if (options.forceHttp && options.forceHttps) {
49
51
  throw new Error('The `forceHttp` and `forceHttps` options cannot be used together');
50
52
  }
51
53
 
52
- if (opts.forceHttp && urlObj.protocol === 'https:') {
54
+ if (options.forceHttp && urlObj.protocol === 'https:') {
53
55
  urlObj.protocol = 'http:';
54
56
  }
55
57
 
56
- if (opts.forceHttps && urlObj.protocol === 'http:') {
58
+ if (options.forceHttps && urlObj.protocol === 'http:') {
57
59
  urlObj.protocol = 'https:';
58
60
  }
59
61
 
62
+ // Remove auth
63
+ if (options.stripAuthentication) {
64
+ urlObj.username = '';
65
+ urlObj.password = '';
66
+ }
67
+
60
68
  // Remove hash
61
- if (opts.stripHash) {
69
+ if (options.stripHash) {
62
70
  urlObj.hash = '';
63
71
  }
64
72
 
@@ -66,10 +74,11 @@ module.exports = (urlString, opts) => {
66
74
  if (urlObj.pathname) {
67
75
  // TODO: Use the following instead when targeting Node.js 10
68
76
  // `urlObj.pathname = urlObj.pathname.replace(/(?<!https?:)\/{2,}/g, '/');`
69
- urlObj.pathname = urlObj.pathname.replace(/((?![https?:]).)\/{2,}/g, (_, p1) => {
77
+ urlObj.pathname = urlObj.pathname.replace(/((?!:).|^)\/{2,}/g, (_, p1) => {
70
78
  if (/^(?!\/)/g.test(p1)) {
71
79
  return `${p1}/`;
72
80
  }
81
+
73
82
  return '/';
74
83
  });
75
84
  }
@@ -80,15 +89,15 @@ module.exports = (urlString, opts) => {
80
89
  }
81
90
 
82
91
  // Remove directory index
83
- if (opts.removeDirectoryIndex === true) {
84
- opts.removeDirectoryIndex = [/^index\.[a-z]+$/];
92
+ if (options.removeDirectoryIndex === true) {
93
+ options.removeDirectoryIndex = [/^index\.[a-z]+$/];
85
94
  }
86
95
 
87
- if (Array.isArray(opts.removeDirectoryIndex) && opts.removeDirectoryIndex.length > 0) {
96
+ if (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {
88
97
  let pathComponents = urlObj.pathname.split('/');
89
98
  const lastComponent = pathComponents[pathComponents.length - 1];
90
99
 
91
- if (testParameter(lastComponent, opts.removeDirectoryIndex)) {
100
+ if (testParameter(lastComponent, options.removeDirectoryIndex)) {
92
101
  pathComponents = pathComponents.slice(0, pathComponents.length - 1);
93
102
  urlObj.pathname = pathComponents.slice(1).join('/') + '/';
94
103
  }
@@ -99,8 +108,7 @@ module.exports = (urlString, opts) => {
99
108
  urlObj.hostname = urlObj.hostname.replace(/\.$/, '');
100
109
 
101
110
  // Remove `www.`
102
- // eslint-disable-next-line no-useless-escape
103
- if (opts.stripWWW && /^www\.([a-z\-\d]{2,63})\.([a-z\.]{2,5})$/.test(urlObj.hostname)) {
111
+ if (options.stripWWW && /^www\.([a-z\-\d]{2,63})\.([a-z.]{2,5})$/.test(urlObj.hostname)) {
104
112
  // Each label should be max 63 at length (min: 2).
105
113
  // The extension should be max 5 at length (min: 2).
106
114
  // Source: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names
@@ -109,31 +117,44 @@ module.exports = (urlString, opts) => {
109
117
  }
110
118
 
111
119
  // Remove query unwanted parameters
112
- if (Array.isArray(opts.removeQueryParameters)) {
120
+ if (Array.isArray(options.removeQueryParameters)) {
113
121
  for (const key of [...urlObj.searchParams.keys()]) {
114
- if (testParameter(key, opts.removeQueryParameters)) {
122
+ if (testParameter(key, options.removeQueryParameters)) {
115
123
  urlObj.searchParams.delete(key);
116
124
  }
117
125
  }
118
126
  }
119
127
 
120
128
  // Sort query parameters
121
- if (opts.sortQueryParameters) {
129
+ if (options.sortQueryParameters) {
122
130
  urlObj.searchParams.sort();
123
131
  }
124
132
 
133
+ if (options.removeTrailingSlash) {
134
+ urlObj.pathname = urlObj.pathname.replace(/\/$/, '');
135
+ }
136
+
125
137
  // Take advantage of many of the Node `url` normalizations
126
138
  urlString = urlObj.toString();
127
139
 
128
140
  // Remove ending `/`
129
- if (opts.removeTrailingSlash || urlObj.pathname === '/') {
141
+ if ((options.removeTrailingSlash || urlObj.pathname === '/') && urlObj.hash === '') {
130
142
  urlString = urlString.replace(/\/$/, '');
131
143
  }
132
144
 
133
145
  // Restore relative protocol, if applicable
134
- if (hasRelativeProtocol && !opts.normalizeProtocol) {
146
+ if (hasRelativeProtocol && !options.normalizeProtocol) {
135
147
  urlString = urlString.replace(/^http:\/\//, '//');
136
148
  }
137
149
 
150
+ // Remove http/https
151
+ if (options.stripProtocol) {
152
+ urlString = urlString.replace(/^(?:https?:)?\/\//, '');
153
+ }
154
+
138
155
  return urlString;
139
156
  };
157
+
158
+ module.exports = normalizeUrl;
159
+ // TODO: Remove this for the next major release
160
+ module.exports.default = normalizeUrl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "normalize-url",
3
- "version": "3.3.0",
3
+ "version": "4.3.0",
4
4
  "description": "Normalize a URL",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/normalize-url",
@@ -10,13 +10,14 @@
10
10
  "url": "sindresorhus.com"
11
11
  },
12
12
  "engines": {
13
- "node": ">=6"
13
+ "node": ">=8"
14
14
  },
15
15
  "scripts": {
16
- "test": "xo && nyc ava"
16
+ "test": "xo && nyc ava && tsd"
17
17
  },
18
18
  "files": [
19
- "index.js"
19
+ "index.js",
20
+ "index.d.ts"
20
21
  ],
21
22
  "keywords": [
22
23
  "normalize",
@@ -34,9 +35,10 @@
34
35
  "canonical"
35
36
  ],
36
37
  "devDependencies": {
37
- "ava": "*",
38
- "coveralls": "^3.0.0",
39
- "nyc": "^12.0.2",
40
- "xo": "*"
38
+ "ava": "^1.4.1",
39
+ "coveralls": "^3.0.3",
40
+ "nyc": "^13.3.0",
41
+ "tsd": "^0.7.2",
42
+ "xo": "^0.24.0"
41
43
  }
42
44
  }
package/readme.md CHANGED
@@ -70,7 +70,7 @@ Normalizes `https:` URLs to `http:`.
70
70
  normalizeUrl('https://sindresorhus.com:80/');
71
71
  //=> 'https://sindresorhus.com'
72
72
 
73
- normalizeUrl('https://sindresorhus.com:80/', {normalizeHttps: true});
73
+ normalizeUrl('https://sindresorhus.com:80/', {forceHttp: true});
74
74
  //=> 'http://sindresorhus.com'
75
75
  ```
76
76
 
@@ -85,25 +85,55 @@ Normalizes `http:` URLs to `https:`.
85
85
  normalizeUrl('https://sindresorhus.com:80/');
86
86
  //=> 'https://sindresorhus.com'
87
87
 
88
- normalizeUrl('http://sindresorhus.com:80/', {normalizeHttp: true});
88
+ normalizeUrl('http://sindresorhus.com:80/', {forceHttps: true});
89
89
  //=> 'https://sindresorhus.com'
90
90
  ```
91
91
 
92
92
  This option can't be used with the `forceHttp` option at the same time.
93
93
 
94
- ##### stripHash
94
+ ##### stripAuthentication
95
95
 
96
96
  Type: `boolean`<br>
97
97
  Default: `true`
98
98
 
99
+ Strip the [authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) part of a URL.
100
+
101
+ ```js
102
+ normalizeUrl('user:password@sindresorhus.com');
103
+ //=> 'https://sindresorhus.com'
104
+
105
+ normalizeUrl('user:password@sindresorhus.com', {stripAuthentication: false});
106
+ //=> 'https://user:password@sindresorhus.com'
107
+ ```
108
+
109
+ ##### stripHash
110
+
111
+ Type: `boolean`<br>
112
+ Default: `false`
113
+
99
114
  Removes hash from the URL.
100
115
 
101
116
  ```js
102
117
  normalizeUrl('sindresorhus.com/about.html#contact');
118
+ //=> 'http://sindresorhus.com/about.html#contact'
119
+
120
+ normalizeUrl('sindresorhus.com/about.html#contact', {stripHash: true});
103
121
  //=> 'http://sindresorhus.com/about.html'
122
+ ```
104
123
 
105
- normalizeUrl('sindresorhus.com/about.html#contact', {stripHash: false});
106
- //=> 'http://sindresorhus.com/about.html#contact'
124
+ ##### stripProtocol
125
+
126
+ Type: `boolean`<br>
127
+ Default: `false`
128
+
129
+ Removes HTTP(S) protocol from an URL `http://sindresorhus.com` → `sindresorhus.com`.
130
+
131
+ ```js
132
+ normalizeUrl('https://sindresorhus.com');
133
+ //=> 'https://sindresorhus.com'
134
+
135
+ normalizeUrl('sindresorhus.com', {stripProtocol: true});
136
+ //=> 'sindresorhus.com'
107
137
  ```
108
138
 
109
139
  ##### stripWWW
@@ -114,11 +144,11 @@ Default: `true`
114
144
  Removes `www.` from the URL.
115
145
 
116
146
  ```js
117
- normalizeUrl('http://www.sindresorhus.com/about.html#contact');
118
- //=> 'http://sindresorhus.com/about.html#contact'
147
+ normalizeUrl('http://www.sindresorhus.com');
148
+ //=> 'http://sindresorhus.com'
119
149
 
120
- normalizeUrl('http://www.sindresorhus.com/about.html#contact', {stripWWW: false});
121
- //=> 'http://www.sindresorhus.com/about.html#contact'
150
+ normalizeUrl('http://www.sindresorhus.com', {stripWWW: false});
151
+ //=> 'http://www.sindresorhus.com'
122
152
  ```
123
153
 
124
154
  ##### removeQueryParameters