Remove parse-domain dependency (#856)
* Remove parse-domain dependency * Remove only, add commentary * Update lockfile
This commit is contained in:
@@ -1,5 +1,46 @@
|
||||
// @flow
|
||||
import parseDomain from 'parse-domain';
|
||||
import { trim } from 'lodash';
|
||||
|
||||
type Domain = {
|
||||
tld: string,
|
||||
subdomain: string,
|
||||
domain: string,
|
||||
};
|
||||
|
||||
// we originally used the parse-domain npm module however this includes
|
||||
// a large list of possible TLD's which increase the size of the bundle
|
||||
// unneccessarily for our usecase of trusted input.
|
||||
export function parseDomain(url: string): ?Domain {
|
||||
if (typeof url !== 'string') return null;
|
||||
|
||||
// strip extermeties and whitespace from input
|
||||
const normalizedDomain = trim(url.replace(/(https?:)?\/\//, ''));
|
||||
const parts = normalizedDomain.split('.');
|
||||
|
||||
// ensure the last part only includes something that looks like a TLD
|
||||
function cleanTLD(tld = '') {
|
||||
return tld.split(/[/:?]/)[0];
|
||||
}
|
||||
|
||||
// simplistic subdomain parse, we don't need to take into account subdomains
|
||||
// with "." characters as these are not valid in Outline
|
||||
if (parts.length >= 3) {
|
||||
return {
|
||||
subdomain: parts[0],
|
||||
domain: parts[1],
|
||||
tld: cleanTLD(parts.slice(2).join('.')),
|
||||
};
|
||||
}
|
||||
if (parts.length === 2) {
|
||||
return {
|
||||
subdomain: '',
|
||||
domain: parts[0],
|
||||
tld: cleanTLD(parts.slice(1).join('.')),
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function stripSubdomain(hostname: string) {
|
||||
const parsed = parseDomain(hostname);
|
||||
|
||||
@@ -1,5 +1,118 @@
|
||||
/* eslint-disable flowtype/require-valid-file-annotation */
|
||||
import { stripSubdomain, isCustomSubdomain } from './domains';
|
||||
import { stripSubdomain, parseDomain, isCustomSubdomain } from './domains';
|
||||
|
||||
// test suite is based on subset of parse-domain module we want to support
|
||||
// https://github.com/peerigon/parse-domain/blob/master/test/parseDomain.test.js
|
||||
describe('#parseDomain', () => {
|
||||
it('should remove the protocol', () => {
|
||||
expect(parseDomain('http://example.com')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
expect(parseDomain('//example.com')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
expect(parseDomain('https://example.com')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove sub-domains', () => {
|
||||
expect(parseDomain('www.example.com')).toMatchObject({
|
||||
subdomain: 'www',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove the path', () => {
|
||||
expect(parseDomain('example.com/some/path?and&query')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
expect(parseDomain('example.com/')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove the query string', () => {
|
||||
expect(parseDomain('example.com?and&query')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove special characters', () => {
|
||||
expect(parseDomain('http://m.example.com\r')).toMatchObject({
|
||||
subdomain: 'm',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove the port', () => {
|
||||
expect(parseDomain('example.com:8080')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow @ characters in the path', () => {
|
||||
expect(parseDomain('https://medium.com/@username/')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'medium',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should also work with three-level domains like .co.uk', () => {
|
||||
expect(parseDomain('www.example.co.uk')).toMatchObject({
|
||||
subdomain: 'www',
|
||||
domain: 'example',
|
||||
tld: 'co.uk',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not include private domains like blogspot.com by default', () => {
|
||||
expect(parseDomain('foo.blogspot.com')).toMatchObject({
|
||||
subdomain: 'foo',
|
||||
domain: 'blogspot',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should also work with the minimum', () => {
|
||||
expect(parseDomain('example.com')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'example',
|
||||
tld: 'com',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null if the given value is not a string', () => {
|
||||
expect(parseDomain(undefined)).toBe(null);
|
||||
expect(parseDomain({})).toBe(null);
|
||||
expect(parseDomain('')).toBe(null);
|
||||
});
|
||||
|
||||
it('should work with custom top-level domains (eg .local)', () => {
|
||||
expect(parseDomain('mymachine.local')).toMatchObject({
|
||||
subdomain: '',
|
||||
domain: 'mymachine',
|
||||
tld: 'local',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#stripSubdomain', () => {
|
||||
test('to work with localhost', () => {
|
||||
|
||||
Reference in New Issue
Block a user