Skip to content

Commit d505390

Browse files
author
bjarneo
committed
initial
0 parents  commit d505390

File tree

10 files changed

+1998
-0
lines changed

10 files changed

+1998
-0
lines changed

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 4
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
12+
[*.md]
13+
trim_trailing_whitespace = false

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
npm-debug.log

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Bjarne Øverli
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
Extract domain from given URL
2+
--
3+
4+
Performant domain extraction. No regex or array magic.
5+
6+
[What is a URL](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_URL)
7+
8+
However. This package will also remove the sub domain.
9+
10+
Support
11+
--
12+
Browser and Node.
13+
14+
Usage
15+
--
16+
17+
* urls = string|array
18+
* returns string|array
19+
20+
```js
21+
extractDomain(urls);
22+
```
23+
24+
ES6
25+
```js
26+
import { extractDomain } from 'extract-domain';
27+
```
28+
29+
```js
30+
const extractDomain = require('extract-domain').extractDomain;
31+
```
32+
33+
```js
34+
const urls = [
35+
'https://www.npmjs.com/package/extract-domain',
36+
'http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument',
37+
'http://user:[email protected]:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument',
38+
'https://npmjs.com/package/extract-domain',
39+
'ftp://example.org/resource.txt'
40+
];
41+
42+
43+
extractDomain(urls[0]); // npmjs.com
44+
45+
extractDomain(urls); // [ 'npmjs.com', 'example.com', 'example.com', 'npmjs.com', 'example.org' ]
46+
47+
```
48+
49+
Tests
50+
--
51+
```bash
52+
$ npm test
53+
```
54+
55+
Coding style
56+
--
57+
```bash
58+
$ npm run pretty
59+
```
60+
61+
Contribution
62+
------
63+
Contributions are appreciated.
64+
65+
License
66+
------
67+
MIT-licensed. See LICENSE.

dist/extract-domain.min.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
function throwTypeError() {
2+
throw new TypeError('The given URL is not a string. Please verify your string|array.');
3+
}
4+
5+
// Easy to read they said?
6+
// Function has to many lines they said?
7+
function getDomainFromUrl(url) {
8+
if (typeof url !== 'string') {
9+
throwTypeError();
10+
}
11+
12+
let domainInc = 0;
13+
let offsetDomain = 0;
14+
let offsetStartSlice = 0;
15+
let offsetPath = 0;
16+
let len = url.length;
17+
let i = 0;
18+
19+
// Find offset of the domain
20+
while (len-- && ++i) {
21+
if (domainInc && url[i] === '/') {
22+
break;
23+
}
24+
25+
if (url[i] !== '.') {
26+
continue;
27+
}
28+
29+
++domainInc;
30+
31+
offsetDomain = i;
32+
}
33+
34+
i = offsetDomain;
35+
36+
// Find offset before domain name.
37+
while (i--) {
38+
// Look for sub domain or protocol
39+
if (url[i] !== '.' && url[i] !== '/' && url[i] !== '@') {
40+
continue;
41+
}
42+
43+
offsetStartSlice = i + 1;
44+
45+
break;
46+
}
47+
48+
i = offsetDomain;
49+
50+
// Get the offset path
51+
while (i++) {
52+
if (i >= url.length) {
53+
break;
54+
}
55+
56+
// If we hit the port, set the offsetPath and break the loop
57+
if (url[i] === ':') {
58+
offsetPath = i;
59+
60+
break;
61+
}
62+
63+
// Continue until we find the start of a path
64+
if (url[i] !== '/') {
65+
continue;
66+
}
67+
68+
offsetPath = i;
69+
70+
break;
71+
}
72+
73+
// offsetStartSlice should always be larger than protocol
74+
if (offsetStartSlice < 6) {
75+
return '';
76+
}
77+
78+
// It has been a wild ride
79+
// .. slice
80+
// Tried several approaches slicing a string. Can't get it any faster than this.
81+
return url.slice(offsetStartSlice, offsetPath);
82+
}
83+
84+
module.exports = function extractDomain(urls) {
85+
if (typeof urls === 'string') {
86+
return getDomainFromUrl(urls);
87+
} else if (Array.isArray(urls)) {
88+
const extractedUrls = [];
89+
let len;
90+
91+
for (let i = 0, len = urls.length; i < len; i++) {
92+
extractedUrls.push(getDomainFromUrl(urls[i]));
93+
}
94+
95+
return extractedUrls;
96+
} else {
97+
throwTypeError();
98+
}
99+
};

index.test.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'use strict';
2+
const assert = require('assert');
3+
const extractDomain = require('./index');
4+
5+
const urls = [
6+
'https://www.npmjs.com/package/extract-domain',
7+
'http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument',
8+
'https://npmjs.com/package/extract-domain',
9+
'http://example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument',
10+
'http://www.so.many.sub.domains.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument',
11+
'http://user:[email protected]:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument',
12+
'ftp://example.org/resource.txt'
13+
];
14+
15+
const expected = [
16+
'npmjs.com',
17+
'example.com',
18+
'npmjs.com',
19+
'example.com',
20+
'example.com',
21+
'example.com',
22+
'example.org'
23+
];
24+
25+
describe('extract domain', () => {
26+
it('should extract given domain from string without sub domain', () => {
27+
assert.equal(extractDomain(urls[3]), expected[3]);
28+
assert.equal(extractDomain(urls[1]), expected[1]);
29+
});
30+
31+
it('should extract given domain from string', () => {
32+
assert.equal(extractDomain(urls[1]), expected[1]);
33+
34+
assert.equal(extractDomain(urls[0]), expected[0]);
35+
});
36+
37+
it('should extract given domain from an array of strings', () => {
38+
const domains = extractDomain(urls);
39+
40+
domains.map(domain => assert(expected.indexOf(domain) > -1));
41+
});
42+
43+
it('should return empty string if it is not a domain', () => {
44+
assert.equal(extractDomain('/i.am/just.astring//7test'), '');
45+
});
46+
47+
it('should throw syntax error exception if the argument is not string nor array', () => {
48+
try {
49+
extractDomain('{}');
50+
} catch (e) {
51+
assert.equal(e.name, 'TypeError');
52+
53+
assert.equal(
54+
e.message,
55+
'The given URL is not a string. Please verify your string|array.'
56+
);
57+
}
58+
});
59+
60+
it('should throw syntax error exception if the array value is not a string', () => {
61+
try {
62+
extractDomain([ [ 'wow' ] ]);
63+
} catch (e) {
64+
assert.equal(e.name, 'TypeError');
65+
66+
assert.equal(
67+
e.message,
68+
'The given URL is not a string. Please verify your string|array.'
69+
);
70+
}
71+
});
72+
});

package.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "extract-domain",
3+
"version": "1.0.0",
4+
"description": "Extract domain from given string",
5+
"main": "dist/extract-domain.min.js",
6+
"author": "Bjarne Oeverli",
7+
"license": "MIT",
8+
"scripts": {
9+
"build": "npm run pretty && NODE_ENV=production webpack",
10+
"watch": "webpack --watch",
11+
"test": "mocha -R spec index.test.js",
12+
"pretty": "prettier --tab-width=4 --print-width=100 --single-quote --trailing-coma --write *.js *.js"
13+
},
14+
"repository": {
15+
"type": "git",
16+
"url": "https://github.com/bjarneo/extract-domain.git"
17+
},
18+
"homepage": "https://github.com/bjarneo/extract-domain",
19+
"bugs": {
20+
"url": "https://github.com/bjarneo/extract-domain/issues"
21+
},
22+
"keywords": [
23+
"extract",
24+
"get",
25+
"fetch",
26+
"string",
27+
"url",
28+
"domain",
29+
"browser",
30+
"node"
31+
],
32+
"devDependencies": {
33+
"google-closure-compiler-js": "^20161201.0.0",
34+
"mocha": "^3.2.0",
35+
"webpack": "^1.14.0"
36+
},
37+
"dependencies": {
38+
"pretty": "^1.0.0"
39+
}
40+
}

webpack.config.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const ClosureCompiler = require('google-closure-compiler-js').webpack;
2+
3+
module.exports = {
4+
devtool: null,
5+
entry: { browser: './index.js' },
6+
output: {
7+
path: __dirname,
8+
filename: 'dist/extract-domain.min.js',
9+
library: 'extractDomain',
10+
libraryTarget: 'commonjs'
11+
},
12+
plugins: [
13+
new ClosureCompiler({
14+
options: {
15+
languageIn: 'ECMASCRIPT6',
16+
languageOut: 'ECMASCRIPT3',
17+
compilationLevel: 'ADVANCED'
18+
}
19+
})
20+
]
21+
};

0 commit comments

Comments
 (0)