Skip to content

Commit 18effbe

Browse files
authored
Add removeSingleSlash option (#120)
1 parent ea4706f commit 18effbe

4 files changed

Lines changed: 55 additions & 4 deletions

File tree

index.d.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ declare namespace normalizeUrl {
137137
/**
138138
Removes trailing slash.
139139
140-
__Note__: Trailing slash is always removed if the URL doesn't have a pathname.
140+
__Note__: Trailing slash is always removed if the URL doesn't have a pathname unless the `removeSingleSlash` option is set to `false`.
141141
142142
@default true
143143
@@ -155,6 +155,22 @@ declare namespace normalizeUrl {
155155
*/
156156
readonly removeTrailingSlash?: boolean;
157157

158+
/**
159+
Remove a sole `/` pathname in the output. This option is independant of `removeTrailingSlash`.
160+
161+
@default true
162+
163+
@example
164+
```
165+
normalizeUrl('https://sindresorhus.com/');
166+
//=> 'https://sindresorhus.com'
167+
168+
normalizeUrl('https://sindresorhus.com/', {removeSingleSlash: false});
169+
//=> 'https://sindresorhus.com/'
170+
```
171+
*/
172+
readonly removeSingleSlash?: boolean;
173+
158174
/**
159175
Removes the default directory index file from path that matches any of the provided strings or regexes.
160176
When `true`, the regex `/^index\.[a-z]+$/` is used.

index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const normalizeUrl = (urlString, options) => {
7070
stripWWW: true,
7171
removeQueryParameters: [/^utm_\w+/i],
7272
removeTrailingSlash: true,
73+
removeSingleSlash: true,
7374
removeDirectoryIndex: false,
7475
sortQueryParameters: true,
7576
...options
@@ -177,8 +178,8 @@ const normalizeUrl = (urlString, options) => {
177178
// Take advantage of many of the Node `url` normalizations
178179
urlString = urlObj.toString();
179180

180-
// Remove ending `/`
181-
if ((options.removeTrailingSlash || urlObj.pathname === '/') && urlObj.hash === '') {
181+
// Remove ending `/` unless removeSingleSlash is false
182+
if ((options.removeTrailingSlash || urlObj.pathname === '/') && urlObj.hash === '' && options.removeSingleSlash) {
182183
urlString = urlString.replace(/\/$/, '');
183184
}
184185

readme.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ Default: `true`
171171

172172
Remove trailing slash.
173173

174-
**Note:** Trailing slash is always removed if the URL doesn't have a pathname.
174+
**Note:** Trailing slash is always removed if the URL doesn't have a pathname unless the `removeSingleSlash` option is set to `false`.
175175

176176
```js
177177
normalizeUrl('http://sindresorhus.com/redirect/');
@@ -184,6 +184,22 @@ normalizeUrl('http://sindresorhus.com/', {removeTrailingSlash: false});
184184
//=> 'http://sindresorhus.com'
185185
```
186186

187+
##### removeSingleSlash
188+
189+
Type: `boolean`\
190+
Default: `true`
191+
192+
Remove a sole `/` pathname in the output. This option is independant of `removeTrailingSlash`.
193+
194+
```js
195+
normalizeUrl('https://sindresorhus.com/');
196+
//=> 'https://sindresorhus.com'
197+
198+
normalizeUrl('https://sindresorhus.com/', {removeSingleSlash: false});
199+
//=> 'https://sindresorhus.com/'
200+
```
201+
202+
187203
##### removeDirectoryIndex
188204

189205
Type: `boolean | Array<RegExp | string>`\

test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,24 @@ test('removeTrailingSlash option', t => {
124124
t.is(normalizeUrl('http://sindresorhus.com/redirect/'), 'http://sindresorhus.com/redirect');
125125
t.is(normalizeUrl('http://sindresorhus.com/redirect/', options), 'http://sindresorhus.com/redirect/');
126126
t.is(normalizeUrl('http://sindresorhus.com/#/', options), 'http://sindresorhus.com/#/');
127+
t.is(normalizeUrl('http://sindresorhus.com/?unicorns=true'), 'http://sindresorhus.com/?unicorns=true');
128+
t.is(normalizeUrl('http://sindresorhus.com/?unicorns=true', options), 'http://sindresorhus.com/?unicorns=true');
129+
});
130+
131+
test('removeSingleSlash option', t => {
132+
const options = {removeSingleSlash: false};
133+
t.is(normalizeUrl('https://sindresorhus.com/', options), 'https://sindresorhus.com/');
134+
t.is(normalizeUrl('https://sindresorhus.com/redirect/', options), 'https://sindresorhus.com/redirect');
135+
t.is(normalizeUrl('https://sindresorhus.com/#/', options), 'https://sindresorhus.com/#/');
136+
t.is(normalizeUrl('https://sindresorhus.com/?unicorns=true', options), 'https://sindresorhus.com/?unicorns=true');
137+
});
138+
139+
test('removeSingleSlash option combined with removeTrailingSlash option', t => {
140+
const options = {removeTrailingSlash: true, removeSingleSlash: false};
141+
t.is(normalizeUrl('https://sindresorhus.com/', options), 'https://sindresorhus.com/');
142+
t.is(normalizeUrl('https://sindresorhus.com/redirect/', options), 'https://sindresorhus.com/redirect');
143+
t.is(normalizeUrl('https://sindresorhus.com/#/', options), 'https://sindresorhus.com/#/');
144+
t.is(normalizeUrl('https://sindresorhus.com/?unicorns=true', options), 'https://sindresorhus.com/?unicorns=true');
127145
});
128146

129147
test('removeDirectoryIndex option', t => {

0 commit comments

Comments
 (0)