normalize-url 2.0.1 → 3.2.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 (3) hide show
  1. package/index.js +35 -77
  2. package/package.json +38 -44
  3. package/readme.md +17 -0
package/index.js CHANGED
@@ -1,38 +1,16 @@
1
1
  'use strict';
2
- const url = require('url');
3
- const punycode = require('punycode');
4
- const queryString = require('query-string');
5
- const prependHttp = require('prepend-http');
6
- const sortKeys = require('sort-keys');
7
-
8
- const DEFAULT_PORTS = {
9
- 'http:': 80,
10
- 'https:': 443,
11
- 'ftp:': 21
12
- };
13
-
14
- // Protocols that always contain a `//`` bit
15
- const slashedProtocol = {
16
- http: true,
17
- https: true,
18
- ftp: true,
19
- gopher: true,
20
- file: true,
21
- 'http:': true,
22
- 'https:': true,
23
- 'ftp:': true,
24
- 'gopher:': true,
25
- 'file:': true
26
- };
2
+ // TODO: Use the `URL` global when targeting Node.js 10
3
+ const URLParser = typeof URL === 'undefined' ? require('url').URL : URL;
27
4
 
28
5
  function testParameter(name, filters) {
29
6
  return filters.some(filter => filter instanceof RegExp ? filter.test(name) : filter === name);
30
7
  }
31
8
 
32
- module.exports = (str, opts) => {
9
+ module.exports = (urlString, opts) => {
33
10
  opts = Object.assign({
34
11
  normalizeProtocol: true,
35
12
  normalizeHttps: false,
13
+ normalizeHttp: false,
36
14
  stripFragment: true,
37
15
  stripWWW: true,
38
16
  removeQueryParameters: [/^utm_\w+/i],
@@ -41,43 +19,45 @@ module.exports = (str, opts) => {
41
19
  sortQueryParameters: true
42
20
  }, opts);
43
21
 
44
- if (typeof str !== 'string') {
45
- throw new TypeError('Expected a string');
46
- }
22
+ urlString = urlString.trim();
47
23
 
48
- const hasRelativeProtocol = str.startsWith('//');
24
+ const hasRelativeProtocol = urlString.startsWith('//');
25
+ const isRelativeUrl = !hasRelativeProtocol && /^\.*\//.test(urlString);
49
26
 
50
27
  // Prepend protocol
51
- str = prependHttp(str.trim()).replace(/^\/\//, 'http://');
28
+ if (!isRelativeUrl) {
29
+ urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, 'http://');
30
+ }
52
31
 
53
- const urlObj = url.parse(str);
32
+ const urlObj = new URLParser(urlString);
54
33
 
55
- if (opts.normalizeHttps && urlObj.protocol === 'https:') {
56
- urlObj.protocol = 'http:';
34
+ if (opts.normalizeHttps && opts.normalizeHttp) {
35
+ throw new Error('The `normalizeHttp` and `normalizeHttps` options cannot be used together');
57
36
  }
58
37
 
59
- if (!urlObj.hostname && !urlObj.pathname) {
60
- throw new Error('Invalid URL');
38
+ if (opts.normalizeHttp && urlObj.protocol === 'http:') {
39
+ urlObj.protocol = 'https:';
61
40
  }
62
41
 
63
- // Prevent these from being used by `url.format`
64
- delete urlObj.host;
65
- delete urlObj.query;
42
+ if (opts.normalizeHttps && urlObj.protocol === 'https:') {
43
+ urlObj.protocol = 'http:';
44
+ }
66
45
 
67
46
  // Remove fragment
68
47
  if (opts.stripFragment) {
69
- delete urlObj.hash;
48
+ urlObj.hash = '';
70
49
  }
71
50
 
72
- // Remove default port
73
- const port = DEFAULT_PORTS[urlObj.protocol];
74
- if (Number(urlObj.port) === port) {
75
- delete urlObj.port;
76
- }
77
-
78
- // Remove duplicate slashes
51
+ // Remove duplicate slashes if not preceded by a protocol
79
52
  if (urlObj.pathname) {
80
- urlObj.pathname = urlObj.pathname.replace(/\/{2,}/g, '/');
53
+ // TODO: Use the following instead when targeting Node.js 10
54
+ // `urlObj.pathname = urlObj.pathname.replace(/(?<!https?:)\/{2,}/g, '/');`
55
+ urlObj.pathname = urlObj.pathname.replace(/((?![https?:]).)\/{2,}/g, (_, p1) => {
56
+ if (/^(?!\/)/g.test(p1)) {
57
+ return `${p1}/`;
58
+ }
59
+ return '/';
60
+ });
81
61
  }
82
62
 
83
63
  // Decode URI octets
@@ -100,17 +80,7 @@ module.exports = (str, opts) => {
100
80
  }
101
81
  }
102
82
 
103
- // Resolve relative paths, but only for slashed protocols
104
- if (slashedProtocol[urlObj.protocol]) {
105
- const domain = urlObj.protocol + '//' + urlObj.hostname;
106
- const relative = url.resolve(domain, urlObj.pathname);
107
- urlObj.pathname = relative.replace(domain, '');
108
- }
109
-
110
83
  if (urlObj.hostname) {
111
- // IDN to Unicode
112
- urlObj.hostname = punycode.toUnicode(urlObj.hostname).toLowerCase();
113
-
114
84
  // Remove trailing dot
115
85
  urlObj.hostname = urlObj.hostname.replace(/\.$/, '');
116
86
 
@@ -120,44 +90,32 @@ module.exports = (str, opts) => {
120
90
  }
121
91
  }
122
92
 
123
- // Remove URL with empty query string
124
- if (urlObj.search === '?') {
125
- delete urlObj.search;
126
- }
127
-
128
- const queryParameters = queryString.parse(urlObj.search);
129
-
130
93
  // Remove query unwanted parameters
131
94
  if (Array.isArray(opts.removeQueryParameters)) {
132
- for (const key in queryParameters) {
95
+ for (const key of [...urlObj.searchParams.keys()]) {
133
96
  if (testParameter(key, opts.removeQueryParameters)) {
134
- delete queryParameters[key];
97
+ urlObj.searchParams.delete(key);
135
98
  }
136
99
  }
137
100
  }
138
101
 
139
102
  // Sort query parameters
140
103
  if (opts.sortQueryParameters) {
141
- urlObj.search = queryString.stringify(sortKeys(queryParameters));
142
- }
143
-
144
- // Decode query parameters
145
- if (urlObj.search !== null) {
146
- urlObj.search = decodeURIComponent(urlObj.search);
104
+ urlObj.searchParams.sort();
147
105
  }
148
106
 
149
107
  // Take advantage of many of the Node `url` normalizations
150
- str = url.format(urlObj);
108
+ urlString = urlObj.toString();
151
109
 
152
110
  // Remove ending `/`
153
111
  if (opts.removeTrailingSlash || urlObj.pathname === '/') {
154
- str = str.replace(/\/$/, '');
112
+ urlString = urlString.replace(/\/$/, '');
155
113
  }
156
114
 
157
115
  // Restore relative protocol, if applicable
158
116
  if (hasRelativeProtocol && !opts.normalizeProtocol) {
159
- str = str.replace(/^http:\/\//, '//');
117
+ urlString = urlString.replace(/^http:\/\//, '//');
160
118
  }
161
119
 
162
- return str;
120
+ return urlString;
163
121
  };
package/package.json CHANGED
@@ -1,46 +1,40 @@
1
1
  {
2
- "name": "normalize-url",
3
- "version": "2.0.1",
4
- "description": "Normalize a URL",
5
- "license": "MIT",
6
- "repository": "sindresorhus/normalize-url",
7
- "author": {
8
- "name": "Sindre Sorhus",
9
- "email": "sindresorhus@gmail.com",
10
- "url": "sindresorhus.com"
11
- },
12
- "engines": {
13
- "node": ">=4"
14
- },
15
- "scripts": {
16
- "test": "xo && ava"
17
- },
18
- "files": [
19
- "index.js"
20
- ],
21
- "keywords": [
22
- "normalize",
23
- "url",
24
- "uri",
25
- "address",
26
- "string",
27
- "normalization",
28
- "normalisation",
29
- "query",
30
- "querystring",
31
- "unicode",
32
- "simplify",
33
- "strip",
34
- "trim",
35
- "canonical"
36
- ],
37
- "dependencies": {
38
- "prepend-http": "^2.0.0",
39
- "query-string": "^5.0.1",
40
- "sort-keys": "^2.0.0"
41
- },
42
- "devDependencies": {
43
- "ava": "*",
44
- "xo": "*"
45
- }
2
+ "name": "normalize-url",
3
+ "version": "3.2.0",
4
+ "description": "Normalize a URL",
5
+ "license": "MIT",
6
+ "repository": "sindresorhus/normalize-url",
7
+ "author": {
8
+ "name": "Sindre Sorhus",
9
+ "email": "sindresorhus@gmail.com",
10
+ "url": "sindresorhus.com"
11
+ },
12
+ "engines": {
13
+ "node": ">=6"
14
+ },
15
+ "scripts": {
16
+ "test": "xo && ava"
17
+ },
18
+ "files": [
19
+ "index.js"
20
+ ],
21
+ "keywords": [
22
+ "normalize",
23
+ "url",
24
+ "uri",
25
+ "address",
26
+ "string",
27
+ "normalization",
28
+ "normalisation",
29
+ "query",
30
+ "querystring",
31
+ "simplify",
32
+ "strip",
33
+ "trim",
34
+ "canonical"
35
+ ],
36
+ "devDependencies": {
37
+ "ava": "*",
38
+ "xo": "*"
39
+ }
46
40
  }
package/readme.md CHANGED
@@ -69,6 +69,23 @@ normalizeUrl('https://sindresorhus.com:80/', {normalizeHttps: true});
69
69
  //=> 'http://sindresorhus.com'
70
70
  ```
71
71
 
72
+ ##### normalizeHttp
73
+
74
+ Type: `boolean`<br>
75
+ Default: `false`
76
+
77
+ Normalize `http:` URLs to `https:`.
78
+
79
+ ```js
80
+ normalizeUrl('https://sindresorhus.com:80/');
81
+ //=> 'https://sindresorhus.com'
82
+
83
+ normalizeUrl('http://sindresorhus.com:80/', {normalizeHttp: true});
84
+ //=> 'https://sindresorhus.com'
85
+ ```
86
+
87
+ This option is mutually exclusive with the `normalizeHttps` option.
88
+
72
89
  ##### stripFragment
73
90
 
74
91
  Type: `boolean`<br>