diff --git a/README.md b/README.md
index 13012c8..b024446 100644
--- a/README.md
+++ b/README.md
@@ -1,46 +1,28 @@
-Join all arguments together and normalize the resulting url.
+Join all arguments together and normalize the resulting URL.
## Install
-~~~
+```bash
npm install url-join
-~~~
+```
+
+If you want to use it directly in a browser use a CDN like [Skypack](https://www.skypack.dev/view/url-join).
## Usage
-~~~javascript
-var urljoin = require('url-join');
+```javascript
+import urlJoin from 'url-join';
-var fullUrl = urljoin('http://www.google.com', 'a', '/b/cd', '?foo=123');
+const fullUrl = urlJoin('http://www.google.com', 'a', '/b/cd', '?foo=123');
console.log(fullUrl);
-
-~~~
+```
Prints:
-~~~
+```
'http://www.google.com/a/b/cd?foo=123'
-~~~
-
-## Browser and AMD
-
-It also works in the browser, you can either include ```lib/url-join.js``` in your page:
-
-~~~html
-
-
-~~~
-
-Or using an AMD module system like requirejs:
-
-~~~javascript
-define(['path/url-join.js'], function (urljoin) {
- urljoin('http://blabla.com', 'foo?a=1');
-});
-~~~
+```
## License
diff --git a/bin/changelog b/bin/changelog.js
similarity index 96%
rename from bin/changelog
rename to bin/changelog.js
index 32bd741..73771a0 100755
--- a/bin/changelog
+++ b/bin/changelog.js
@@ -1,6 +1,6 @@
#!/usr/bin/env node
+import changelog from 'conventional-changelog';
-var changelog = require('conventional-changelog');
var semver_regex = /\bv?(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?\b/ig;
const commitPartial = ` - {{header}}
diff --git a/lib/url-join.d.ts b/lib/url-join.d.ts
index 9fb12f2..317c2ba 100644
--- a/lib/url-join.d.ts
+++ b/lib/url-join.d.ts
@@ -6,4 +6,4 @@
declare function urlJoin(...parts: string[]): string;
declare function urlJoin(parts: string[]): string;
-export = urlJoin;
+export default urlJoin;
diff --git a/lib/url-join.js b/lib/url-join.js
index e23bb16..37f1303 100644
--- a/lib/url-join.js
+++ b/lib/url-join.js
@@ -1,78 +1,70 @@
-(function (name, context, definition) {
- if (typeof module !== 'undefined' && module.exports) module.exports = definition();
- else if (typeof define === 'function' && define.amd) define(definition);
- else context[name] = definition();
-})('urljoin', this, function () {
-
- function normalize (strArray) {
- var resultArray = [];
- if (strArray.length === 0) { return ''; }
-
- if (typeof strArray[0] !== 'string') {
- throw new TypeError('Url must be a string. Received ' + strArray[0]);
- }
-
- // If the first part is a plain protocol, we combine it with the next part.
- if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
- var first = strArray.shift();
- strArray[0] = first + strArray[0];
- }
+function normalize (strArray) {
+ var resultArray = [];
+ if (strArray.length === 0) { return ''; }
- // There must be two or three slashes in the file protocol, two slashes in anything else.
- if (strArray[0].match(/^file:\/\/\//)) {
- strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1:///');
- } else {
- strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1://');
- }
+ if (typeof strArray[0] !== 'string') {
+ throw new TypeError('Url must be a string. Received ' + strArray[0]);
+ }
- for (var i = 0; i < strArray.length; i++) {
- var component = strArray[i];
+ // If the first part is a plain protocol, we combine it with the next part.
+ if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
+ var first = strArray.shift();
+ strArray[0] = first + strArray[0];
+ }
- if (typeof component !== 'string') {
- throw new TypeError('Url must be a string. Received ' + component);
- }
+ // There must be two or three slashes in the file protocol, two slashes in anything else.
+ if (strArray[0].match(/^file:\/\/\//)) {
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1:///');
+ } else {
+ strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1://');
+ }
- if (component === '') { continue; }
+ for (var i = 0; i < strArray.length; i++) {
+ var component = strArray[i];
- if (i > 0) {
- // Removing the starting slashes for each component but the first.
- component = component.replace(/^[\/]+/, '');
- }
- if (i < strArray.length - 1) {
- // Removing the ending slashes for each component but the last.
- component = component.replace(/[\/]+$/, '');
- } else {
- // For the last component we will combine multiple slashes to a single one.
- component = component.replace(/[\/]+$/, '/');
- }
+ if (typeof component !== 'string') {
+ throw new TypeError('Url must be a string. Received ' + component);
+ }
- resultArray.push(component);
+ if (component === '') { continue; }
+ if (i > 0) {
+ // Removing the starting slashes for each component but the first.
+ component = component.replace(/^[\/]+/, '');
+ }
+ if (i < strArray.length - 1) {
+ // Removing the ending slashes for each component but the last.
+ component = component.replace(/[\/]+$/, '');
+ } else {
+ // For the last component we will combine multiple slashes to a single one.
+ component = component.replace(/[\/]+$/, '/');
}
- var str = resultArray.join('/');
- // Each input component is now separated by a single slash except the possible first plain protocol part.
+ resultArray.push(component);
- // remove trailing slash before parameters or hash
- str = str.replace(/\/(\?|&|#[^!])/g, '$1');
+ }
- // replace ? in parameters with &
- var parts = str.split('?');
- str = parts.shift() + (parts.length > 0 ? '?': '') + parts.join('&');
+ var str = resultArray.join('/');
+ // Each input component is now separated by a single slash except the possible first plain protocol part.
- return str;
- }
+ // remove trailing slash before parameters or hash
+ str = str.replace(/\/(\?|&|#[^!])/g, '$1');
- return function () {
- var input;
+ // replace ? in parameters with &
+ var parts = str.split('?');
+ str = parts.shift() + (parts.length > 0 ? '?': '') + parts.join('&');
- if (typeof arguments[0] === 'object') {
- input = arguments[0];
- } else {
- input = [].slice.call(arguments);
- }
+ return str;
+}
- return normalize(input);
- };
+export default function urlJoin() {
+ var input;
+
+ if (typeof arguments[0] === 'object') {
+ input = arguments[0];
+ } else {
+ input = [].slice.call(arguments);
+ }
-});
+ return normalize(input);
+}
diff --git a/package.json b/package.json
index 34ca8fd..135d38a 100644
--- a/package.json
+++ b/package.json
@@ -2,9 +2,14 @@
"name": "url-join",
"version": "4.0.1",
"description": "Join urls and normalize as in path.join.",
- "main": "lib/url-join.js",
- "types": "lib/url-join.d.ts",
+ "type": "module",
+ "main": "./lib/url-join.js",
+ "exports": "./lib/url-join.js",
+ "types": "./lib/url-join.d.ts",
"sideEffects": false,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
"scripts": {
"test": "mocha --require should"
},
diff --git a/test/tests.js b/test/tests.js
index 6876276..7e3dc48 100644
--- a/test/tests.js
+++ b/test/tests.js
@@ -1,151 +1,151 @@
-var urljoin = require('../lib/url-join');
-var assert = require('assert');
+import assert from 'assert';
+import urlJoin from '../lib/url-join.js';
describe('url join', function () {
it('should work for simple case', function () {
- urljoin('http://www.google.com/', 'foo/bar', '?test=123')
+ urlJoin('http://www.google.com/', 'foo/bar', '?test=123')
.should.eql('http://www.google.com/foo/bar?test=123');
});
it('should work for simple case with new syntax', function () {
- urljoin(['http://www.google.com/', 'foo/bar', '?test=123'])
+ urlJoin(['http://www.google.com/', 'foo/bar', '?test=123'])
.should.eql('http://www.google.com/foo/bar?test=123');
});
it('should work for hashbang urls', function () {
- urljoin(['http://www.google.com', '#!', 'foo/bar', '?test=123'])
+ urlJoin(['http://www.google.com', '#!', 'foo/bar', '?test=123'])
.should.eql('http://www.google.com/#!/foo/bar?test=123');
});
it('should be able to join protocol', function () {
- urljoin('http:', 'www.google.com/', 'foo/bar', '?test=123')
+ urlJoin('http:', 'www.google.com/', 'foo/bar', '?test=123')
.should.eql('http://www.google.com/foo/bar?test=123');
});
it('should be able to join protocol with slashes', function () {
- urljoin('http://', 'www.google.com/', 'foo/bar', '?test=123')
+ urlJoin('http://', 'www.google.com/', 'foo/bar', '?test=123')
.should.eql('http://www.google.com/foo/bar?test=123');
});
it('should remove extra slashes', function () {
- urljoin('http:', 'www.google.com///', 'foo/bar', '?test=123')
+ urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123')
.should.eql('http://www.google.com/foo/bar?test=123');
});
it('should not remove extra slashes in an encoded URL', function () {
- urljoin('http:', 'www.google.com///', 'foo/bar', '?url=http%3A//Ftest.com')
+ urlJoin('http:', 'www.google.com///', 'foo/bar', '?url=http%3A//Ftest.com')
.should.eql('http://www.google.com/foo/bar?url=http%3A//Ftest.com');
- urljoin('http://a.com/23d04b3/', '/b/c.html')
+ urlJoin('http://a.com/23d04b3/', '/b/c.html')
.should.eql('http://a.com/23d04b3/b/c.html')
.should.not.eql('http://a.com/23d04b3//b/c.html');
});
it('should support anchors in urls', function () {
- urljoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '#faaaaa')
+ urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '#faaaaa')
.should.eql('http://www.google.com/foo/bar?test=123#faaaaa');
});
it('should support protocol-relative urls', function () {
- urljoin('//www.google.com', 'foo/bar', '?test=123')
+ urlJoin('//www.google.com', 'foo/bar', '?test=123')
.should.eql('//www.google.com/foo/bar?test=123')
});
it('should support file protocol urls', function () {
- urljoin('file:/', 'android_asset', 'foo/bar')
+ urlJoin('file:/', 'android_asset', 'foo/bar')
.should.eql('file://android_asset/foo/bar')
- urljoin('file:', '/android_asset', 'foo/bar')
+ urlJoin('file:', '/android_asset', 'foo/bar')
.should.eql('file://android_asset/foo/bar')
});
it('should support absolute file protocol urls', function () {
- urljoin('file:', '///android_asset', 'foo/bar')
+ urlJoin('file:', '///android_asset', 'foo/bar')
.should.eql('file:///android_asset/foo/bar')
- urljoin('file:///', 'android_asset', 'foo/bar')
+ urlJoin('file:///', 'android_asset', 'foo/bar')
.should.eql('file:///android_asset/foo/bar')
- urljoin('file:///', '//android_asset', 'foo/bar')
+ urlJoin('file:///', '//android_asset', 'foo/bar')
.should.eql('file:///android_asset/foo/bar')
- urljoin('file:///android_asset', 'foo/bar')
+ urlJoin('file:///android_asset', 'foo/bar')
.should.eql('file:///android_asset/foo/bar')
});
it('should merge multiple query params properly', function () {
- urljoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '?key=456')
+ urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '?key=456')
.should.eql('http://www.google.com/foo/bar?test=123&key=456');
- urljoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '?boom=value', '&key=456')
+ urlJoin('http:', 'www.google.com///', 'foo/bar', '?test=123', '?boom=value', '&key=456')
.should.eql('http://www.google.com/foo/bar?test=123&boom=value&key=456');
- urljoin('http://example.org/x', '?a=1', '?b=2', '?c=3', '?d=4')
+ urlJoin('http://example.org/x', '?a=1', '?b=2', '?c=3', '?d=4')
.should.eql('http://example.org/x?a=1&b=2&c=3&d=4');
});
it('should merge slashes in paths correctly', function () {
- urljoin('http://example.org', 'a//', 'b//', 'A//', 'B//')
+ urlJoin('http://example.org', 'a//', 'b//', 'A//', 'B//')
.should.eql('http://example.org/a/b/A/B/');
});
it('should merge colons in paths correctly', function () {
- urljoin('http://example.org/', ':foo:', 'bar')
+ urlJoin('http://example.org/', ':foo:', 'bar')
.should.eql('http://example.org/:foo:/bar');
});
it('should merge just a simple path without URL correctly', function() {
- urljoin('/', 'test')
+ urlJoin('/', 'test')
.should.eql('/test');
});
it('should fail with segments that are not string', function() {
- assert.throws(() => urljoin(true),
+ assert.throws(() => urlJoin(true),
/Url must be a string. Received true/);
- assert.throws(() => urljoin('http://blabla.com/', 1),
+ assert.throws(() => urlJoin('http://blabla.com/', 1),
/Url must be a string. Received 1/);
- assert.throws(() => urljoin('http://blabla.com/', undefined, 'test'),
+ assert.throws(() => urlJoin('http://blabla.com/', undefined, 'test'),
/Url must be a string. Received undefined/);
- assert.throws(() => urljoin('http://blabla.com/', null, 'test'),
+ assert.throws(() => urlJoin('http://blabla.com/', null, 'test'),
/Url must be a string. Received null/);
- assert.throws(() => urljoin('http://blabla.com/', { foo: 123 }, 'test'),
+ assert.throws(() => urlJoin('http://blabla.com/', { foo: 123 }, 'test'),
/Url must be a string. Received \[object Object\]/);
});
it('should merge a path with colon properly', function(){
- urljoin('/users/:userId', '/cars/:carId')
+ urlJoin('/users/:userId', '/cars/:carId')
.should.eql('/users/:userId/cars/:carId');
});
it('should merge slashes in protocol correctly', function () {
- urljoin('http://example.org', 'a')
+ urlJoin('http://example.org', 'a')
.should.eql('http://example.org/a');
- urljoin('http:', '//example.org', 'a')
+ urlJoin('http:', '//example.org', 'a')
.should.eql('http://example.org/a');
- urljoin('http:///example.org', 'a')
+ urlJoin('http:///example.org', 'a')
.should.eql('http://example.org/a');
- urljoin('file:///example.org', 'a')
+ urlJoin('file:///example.org', 'a')
.should.eql('file:///example.org/a');
- urljoin('file:example.org', 'a')
+ urlJoin('file:example.org', 'a')
.should.eql('file://example.org/a');
- urljoin('file:/', 'example.org', 'a')
+ urlJoin('file:/', 'example.org', 'a')
.should.eql('file://example.org/a');
- urljoin('file:', '/example.org', 'a')
+ urlJoin('file:', '/example.org', 'a')
.should.eql('file://example.org/a');
- urljoin('file:', '//example.org', 'a')
+ urlJoin('file:', '//example.org', 'a')
.should.eql('file://example.org/a');
});
it('should skip empty strings', function() {
- urljoin('http://foobar.com', '', 'test')
+ urlJoin('http://foobar.com', '', 'test')
.should.eql('http://foobar.com/test');
- urljoin('', 'http://foobar.com', '', 'test')
+ urlJoin('', 'http://foobar.com', '', 'test')
.should.eql('http://foobar.com/test');
});
it('should return an empty string if no arguments are supplied', function() {
- urljoin().should.eql('');
+ urlJoin().should.eql('');
});
});