parse-domain 2.3.1 → 2.3.2

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.
@@ -6,53 +6,35 @@ var privateTrie = require("../lists/private.complete");
6
6
 
7
7
  var normalize = require("./normalize.js");
8
8
 
9
- var lookUp = require("./tries/lookUp"); // eslint-disable-next-line
9
+ var lookUp = require("./trie/lookUp"); // eslint-disable-next-line
10
10
 
11
11
 
12
- var urlParts = /^(:?\/\/|https?:\/\/)?([^/]*@)?(.+?)(:\d{2,5})?([/?].*)?$/; // 1 = protocol, 2 = auth, 3 = domain, 4 = port, 5 = path
12
+ var urlParts = /^(:?\/\/|https?:\/\/)?([^/]*@)?(.+?)(:\d{2,5})?([/?].*)?$/; // 1 = protocol, 2 = auth, 3 = hostname, 4 = port, 5 = path
13
13
 
14
14
  var dot = /\./g;
15
15
  var emptyArr = [];
16
16
 
17
- function matchTld(domain, options) {
17
+ function matchTld(hostname, options) {
18
18
  // for potentially unrecognized tlds, try matching against custom tlds
19
19
  if (options.customTlds) {
20
20
  // try matching against a built regexp of custom tlds
21
- var tld = domain.match(options.customTlds);
21
+ var tld = hostname.match(options.customTlds);
22
22
 
23
23
  if (tld !== null) {
24
24
  return tld[0];
25
25
  }
26
26
  }
27
27
 
28
- var tries = (options.privateTlds ? [privateTrie] : emptyArr).concat(icannTrie);
29
- var _iteratorNormalCompletion = true;
30
- var _didIteratorError = false;
31
- var _iteratorError = undefined;
28
+ var domains = hostname.split(".");
29
+ var icannTlds = lookUp(icannTrie, domains);
30
+ var privateTlds = options.privateTlds ? lookUp(privateTrie, domains) : emptyArr;
32
31
 
33
- try {
34
- for (var _iterator = tries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
35
- var trie = _step.value;
36
-
37
- var _tld = lookUp(trie, domain);
32
+ if (privateTlds.length > icannTlds.length) {
33
+ return "." + privateTlds.join(".");
34
+ }
38
35
 
39
- if (_tld !== null) {
40
- return "." + _tld;
41
- }
42
- }
43
- } catch (err) {
44
- _didIteratorError = true;
45
- _iteratorError = err;
46
- } finally {
47
- try {
48
- if (!_iteratorNormalCompletion && _iterator["return"] != null) {
49
- _iterator["return"]();
50
- }
51
- } finally {
52
- if (_didIteratorError) {
53
- throw _iteratorError;
54
- }
55
- }
36
+ if (icannTlds.length > 0) {
37
+ return "." + icannTlds.join(".");
56
38
  }
57
39
 
58
40
  return null;
@@ -80,7 +62,7 @@ function parseDomain(url, options) {
80
62
  var normalizedUrl = normalize.url(url);
81
63
  var tld = null;
82
64
  var urlSplit;
83
- var domain;
65
+ var hostname;
84
66
 
85
67
  if (!normalizedUrl) {
86
68
  return null;
@@ -93,27 +75,27 @@ function parseDomain(url, options) {
93
75
  return null;
94
76
  }
95
77
 
96
- domain = urlSplit[3]; // domain will now be something like sub.domain.example.com
78
+ hostname = urlSplit[3]; // domain will now be something like sub.domain.example.com
97
79
 
98
- tld = matchTld(domain, normalizedOptions);
80
+ tld = matchTld(hostname, normalizedOptions);
99
81
 
100
82
  if (tld === null) {
101
83
  return null;
102
84
  } // remove tld and split by dot
103
85
 
104
86
 
105
- urlSplit = domain.slice(0, -tld.length).split(dot);
87
+ urlSplit = hostname.slice(0, -tld.length).split(dot);
106
88
 
107
89
  if (tld.charAt(0) === ".") {
108
90
  // removes the remaining dot, if present (added to handle localhost)
109
91
  tld = tld.slice(1);
110
92
  }
111
93
 
112
- domain = urlSplit.pop();
94
+ hostname = urlSplit.pop();
113
95
  var subdomain = urlSplit.join(".");
114
96
  return {
115
97
  tld: tld,
116
- domain: domain,
98
+ domain: hostname,
117
99
  subdomain: subdomain
118
100
  };
119
101
  }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ UP: "<",
5
+ // one level up
6
+ SAME: ",",
7
+ // same level
8
+ DOWN: ">",
9
+ // one level down
10
+ RESET: "|",
11
+ // reset level index and start new
12
+ WILDCARD: "*",
13
+ // as defined by publicsuffix.org
14
+ EXCEPTION: "!" // as defined by publicsuffix.org
15
+
16
+ };
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ var characters = require("./characters.js");
4
+
5
+ function lookUp(trie, domains) {
6
+ var domainsToCheck = domains.slice();
7
+ var topLevel = [];
8
+ var node = trie;
9
+
10
+ while (domainsToCheck.length) {
11
+ var domain = domainsToCheck.pop();
12
+
13
+ if (node.children.has(characters.WILDCARD)) {
14
+ if (node.children.has(characters.EXCEPTION + domain)) {
15
+ break;
16
+ }
17
+
18
+ node = node.children.get(characters.WILDCARD);
19
+ } else {
20
+ if (node.children.has(domain) === false) {
21
+ break;
22
+ }
23
+
24
+ node = node.children.get(domain);
25
+ }
26
+
27
+ topLevel.unshift(domain);
28
+ }
29
+
30
+ return topLevel;
31
+ }
32
+
33
+ module.exports = lookUp;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ function createNode() {
4
+ var domain = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
5
+ return {
6
+ domain: domain,
7
+ children: new Map(),
8
+ parent: null
9
+ };
10
+ }
11
+
12
+ function createOrGetChild(parent, domain) {
13
+ var child = parent.children.get(domain);
14
+
15
+ if (child === undefined) {
16
+ child = createNode(domain);
17
+ adoptChild(parent, child);
18
+ }
19
+
20
+ return child;
21
+ }
22
+
23
+ function adoptChild(parent, child) {
24
+ if (typeof child.domain !== "string") {
25
+ throw new Error("Cannot adopt child: child.domain must be a string");
26
+ }
27
+
28
+ if (parent.children.has(child.domain)) {
29
+ throw new Error("Cannot adopt child: parent has already a child with the domain '".concat(child.domain, "'"));
30
+ }
31
+
32
+ parent.children.set(child.domain, child);
33
+ child.parent = parent;
34
+ }
35
+
36
+ module.exports = {
37
+ createNode: createNode,
38
+ createOrGetChild: createOrGetChild,
39
+ adoptChild: adoptChild
40
+ };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ var characters = require("./characters");
4
+
5
+ var _require = require("./nodes"),
6
+ createNode = _require.createNode,
7
+ createOrGetChild = _require.createOrGetChild; // Parsing is complex... :)
8
+ // eslint-disable-next-line complexity
9
+
10
+
11
+ function parse(serialized) {
12
+ var rootNode = createNode();
13
+ var domain = "";
14
+ var parentNode = rootNode;
15
+ var node;
16
+
17
+ function addDomain() {
18
+ node = createOrGetChild(parentNode, domain);
19
+ domain = "";
20
+ }
21
+
22
+ for (var i = 0; i < serialized.length; i++) {
23
+ var _char = serialized.charAt(i);
24
+
25
+ switch (_char) {
26
+ case characters.SAME:
27
+ {
28
+ addDomain();
29
+ continue;
30
+ }
31
+
32
+ case characters.DOWN:
33
+ {
34
+ addDomain();
35
+ parentNode = node;
36
+ continue;
37
+ }
38
+
39
+ case characters.RESET:
40
+ {
41
+ addDomain();
42
+ parentNode = rootNode;
43
+ continue;
44
+ }
45
+
46
+ case characters.UP:
47
+ {
48
+ addDomain();
49
+ parentNode = parentNode.parent;
50
+ continue;
51
+ }
52
+ }
53
+
54
+ domain += _char;
55
+ }
56
+
57
+ if (domain !== "") {
58
+ addDomain();
59
+ }
60
+
61
+ return rootNode;
62
+ }
63
+
64
+ module.exports = parse;
File without changes
@@ -4,7 +4,7 @@ var _LINE_FILTERS;
4
4
 
5
5
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
6
 
7
- var SEPARATORS = require("./separators");
7
+ var characters = require("./characters");
8
8
 
9
9
  var TYPE_COMPLETE = "complete";
10
10
  var TYPE_LIGHT = "light";
@@ -54,14 +54,14 @@ function lineToString(line, i, arr) {
54
54
 
55
55
  if (indexOfDifference === 0) {
56
56
  // line and prevLine are completely different
57
- separatorFromPrev = SEPARATORS.RESET;
57
+ separatorFromPrev = characters.RESET;
58
58
  } else if (indexOfDifference === prevLine.length - 1) {
59
59
  // only the last part of line and prevLine are different
60
- separatorFromPrev = SEPARATORS.SAME;
60
+ separatorFromPrev = characters.SAME;
61
61
  } else if (indexOfDifference > prevLine.length - 1) {
62
62
  // we don't need to go up the hierarchy first because prevLine is part of line
63
63
  // so let's just start with an initial down separator
64
- separatorFromPrev = SEPARATORS.DOWN;
64
+ separatorFromPrev = characters.DOWN;
65
65
  } else {
66
66
  // line and prevLine are different, but share a common root at indexOfDifference - 1
67
67
  // we now need to go up the hierarchy to the common root
@@ -76,11 +76,11 @@ function lineToString(line, i, arr) {
76
76
  throw new Error("Cannot serialize trie: The public suffix list contains unexpected rules.");
77
77
  }
78
78
 
79
- separatorFromPrev = new Array(levelsUp).fill(SEPARATORS.UP).join("");
79
+ separatorFromPrev = new Array(levelsUp).fill(characters.UP).join("");
80
80
  }
81
81
  }
82
82
 
83
- return separatorFromPrev + line.slice(indexOfDifference).join(SEPARATORS.DOWN);
83
+ return separatorFromPrev + line.slice(indexOfDifference).join(characters.DOWN);
84
84
  }
85
85
 
86
86
  function serializeTrie(parsedList, type) {
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
 
3
- const parseTrie = require("../lib/tries/parseTrie");
3
+ const parse = require("../lib/trie/parse");
4
4
 
5
- module.exports = parseTrie(require("../build/tries/icann.complete.json").trie);
5
+ module.exports = parse(require("../build/tries/icann.complete.json").trie);
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
 
3
- const parseTrie = require("../lib/tries/parseTrie");
3
+ const parse = require("../lib/trie/parse");
4
4
 
5
- module.exports = parseTrie(require("../build/tries/icann.light.json").trie);
5
+ module.exports = parse(require("../build/tries/icann.light.json").trie);
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
 
3
- const parseTrie = require("../lib/tries/parseTrie");
3
+ const parse = require("../lib/trie/parse");
4
4
 
5
- module.exports = parseTrie(require("../build/tries/private.complete.json").trie);
5
+ module.exports = parse(require("../build/tries/private.complete.json").trie);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "parse-domain",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Splits an url into sub-domain, domain and effective top-level-domain",
5
5
  "main": "./lib/parseDomain.js",
6
6
  "types": "./src/index.d.ts",
@@ -12,7 +12,7 @@ const got = require("got");
12
12
  const mkdirp = require("mkdirp");
13
13
 
14
14
  try {
15
- require.resolve("../lib/tries/parsePubSuffixList");
15
+ require.resolve("../lib/trie/parsePubSuffixList");
16
16
  } catch (error) {
17
17
  // This conditions occurs when the CI system or a developer checks out the repo for the first time.
18
18
  // It happens because the postinstall hook kicks in *before* the lib is built.
@@ -20,8 +20,8 @@ try {
20
20
  console.error("Lib does not exist yet, skipping build-tries step.");
21
21
  process.exit(0); // eslint-disable-line no-process-exit
22
22
  }
23
- const parsePubSuffixList = require("../lib/tries/parsePubSuffixList");
24
- const serializeTrie = require("../lib/tries/serializeTrie");
23
+ const parsePubSuffixList = require("../lib/trie/parsePubSuffixList");
24
+ const serializeTrie = require("../lib/trie/serializeTrie");
25
25
 
26
26
  const PUBLIC_SUFFIX_URL = "https://publicsuffix.org/list/public_suffix_list.dat";
27
27
  const rootPath = path.resolve(__dirname, "..");
@@ -219,7 +219,7 @@ describe("parseDomain(url)", () => {
219
219
  });
220
220
 
221
221
  // See https://github.com/peerigon/parse-domain/issues/67
222
- it.skip("should parse gouv.fr as tld", () => {
222
+ it("should parse gouv.fr as tld", () => {
223
223
  expect(parseDomain("dev.classea12.beta.gouv.fr", {privateTlds: true})).to.eql({
224
224
  tld: "gouv.fr",
225
225
  domain: "beta",
@@ -227,4 +227,127 @@ describe("parseDomain(url)", () => {
227
227
  });
228
228
  });
229
229
  });
230
+
231
+ describe("official test suite", () => {
232
+ it("passes all inputs", () => {
233
+ function checkPublicSuffix(input, expectedTld) {
234
+ console.log(input);
235
+ const result = parseDomain(input, {privateTlds: true});
236
+
237
+ if (expectedTld === null) {
238
+ // When the expectedTld is null it means that the domain
239
+ // should not be registerable.
240
+ // Our module will return an empty string for the domain
241
+ // in that case. The tld should match the input.
242
+ expect(result.tld).to.equal(input.toLowerCase());
243
+ expect(result.domain).to.equal("");
244
+ } else {
245
+ expect(result.domain + "." + result.tld).to.equal(expectedTld);
246
+ }
247
+ }
248
+
249
+ // Any copyright is dedicated to the Public Domain.
250
+ // https://creativecommons.org/publicdomain/zero/1.0/
251
+
252
+ // null input.
253
+ // checkPublicSuffix(null, null);
254
+ // Mixed case.
255
+ checkPublicSuffix("COM", null);
256
+ checkPublicSuffix("example.COM", "example.com");
257
+ checkPublicSuffix("WwW.example.COM", "example.com");
258
+ // Leading dot.
259
+ // TODO: Make this test work
260
+ // checkPublicSuffix(".com", null);
261
+ // checkPublicSuffix(".example", null);
262
+ // checkPublicSuffix(".example.com", null);
263
+ // checkPublicSuffix(".example.example", null);
264
+ // Unlisted TLD.
265
+ // This is a strange test case. Why should 'example.example' be registerable when 'example' is unknown?
266
+ // checkPublicSuffix("example", null);
267
+ // checkPublicSuffix("example.example", "example.example");
268
+ // checkPublicSuffix("b.example.example", "example.example");
269
+ // checkPublicSuffix("a.b.example.example", "example.example");
270
+ // Listed, but non-Internet, TLD.
271
+ // checkPublicSuffix('local', null);
272
+ // checkPublicSuffix('example.local', null);
273
+ // checkPublicSuffix('b.example.local', null);
274
+ // checkPublicSuffix('a.b.example.local', null);
275
+ // TLD with only 1 rule.
276
+ checkPublicSuffix("biz", null);
277
+ checkPublicSuffix("domain.biz", "domain.biz");
278
+ checkPublicSuffix("b.domain.biz", "domain.biz");
279
+ checkPublicSuffix("a.b.domain.biz", "domain.biz");
280
+ // TLD with some 2-level rules.
281
+ checkPublicSuffix("com", null);
282
+ checkPublicSuffix("example.com", "example.com");
283
+ checkPublicSuffix("b.example.com", "example.com");
284
+ checkPublicSuffix("a.b.example.com", "example.com");
285
+ checkPublicSuffix("uk.com", null);
286
+ checkPublicSuffix("example.uk.com", "example.uk.com");
287
+ checkPublicSuffix("b.example.uk.com", "example.uk.com");
288
+ checkPublicSuffix("a.b.example.uk.com", "example.uk.com");
289
+ checkPublicSuffix("test.ac", "test.ac");
290
+ // TLD with only 1 (wildcard) rule.
291
+ checkPublicSuffix("mm", null);
292
+ checkPublicSuffix("c.mm", null);
293
+ checkPublicSuffix("b.c.mm", "b.c.mm");
294
+ checkPublicSuffix("a.b.c.mm", "b.c.mm");
295
+ // More complex TLD.
296
+ checkPublicSuffix("jp", null);
297
+ checkPublicSuffix("test.jp", "test.jp");
298
+ checkPublicSuffix("www.test.jp", "test.jp");
299
+ checkPublicSuffix("ac.jp", null);
300
+ checkPublicSuffix("test.ac.jp", "test.ac.jp");
301
+ checkPublicSuffix("www.test.ac.jp", "test.ac.jp");
302
+ checkPublicSuffix("kyoto.jp", null);
303
+ checkPublicSuffix("test.kyoto.jp", "test.kyoto.jp");
304
+ checkPublicSuffix("ide.kyoto.jp", null);
305
+ checkPublicSuffix("b.ide.kyoto.jp", "b.ide.kyoto.jp");
306
+ checkPublicSuffix("a.b.ide.kyoto.jp", "b.ide.kyoto.jp");
307
+ checkPublicSuffix("c.kobe.jp", null);
308
+ checkPublicSuffix("b.c.kobe.jp", "b.c.kobe.jp");
309
+ checkPublicSuffix("a.b.c.kobe.jp", "b.c.kobe.jp");
310
+ checkPublicSuffix("city.kobe.jp", "city.kobe.jp");
311
+ checkPublicSuffix("www.city.kobe.jp", "city.kobe.jp");
312
+ // TLD with a wildcard rule and exceptions.
313
+ checkPublicSuffix("ck", null);
314
+ checkPublicSuffix("test.ck", null);
315
+ checkPublicSuffix("b.test.ck", "b.test.ck");
316
+ checkPublicSuffix("a.b.test.ck", "b.test.ck");
317
+ checkPublicSuffix("www.ck", "www.ck");
318
+ checkPublicSuffix("www.www.ck", "www.ck");
319
+ // US K12.
320
+ checkPublicSuffix("us", null);
321
+ checkPublicSuffix("test.us", "test.us");
322
+ checkPublicSuffix("www.test.us", "test.us");
323
+ checkPublicSuffix("ak.us", null);
324
+ checkPublicSuffix("test.ak.us", "test.ak.us");
325
+ checkPublicSuffix("www.test.ak.us", "test.ak.us");
326
+ checkPublicSuffix("k12.ak.us", null);
327
+ checkPublicSuffix("test.k12.ak.us", "test.k12.ak.us");
328
+ checkPublicSuffix("www.test.k12.ak.us", "test.k12.ak.us");
329
+ // IDN labels.
330
+ checkPublicSuffix("食狮.com.cn", "食狮.com.cn");
331
+ checkPublicSuffix("食狮.公司.cn", "食狮.公司.cn");
332
+ checkPublicSuffix("www.食狮.公司.cn", "食狮.公司.cn");
333
+ checkPublicSuffix("shishi.公司.cn", "shishi.公司.cn");
334
+ checkPublicSuffix("公司.cn", null);
335
+ checkPublicSuffix("食狮.中国", "食狮.中国");
336
+ checkPublicSuffix("www.食狮.中国", "食狮.中国");
337
+ checkPublicSuffix("shishi.中国", "shishi.中国");
338
+ checkPublicSuffix("中国", null);
339
+ // Same as above, but punycoded.
340
+ // Punycode is currently not supported
341
+ // TODO: Make these tests work
342
+ // checkPublicSuffix("xn--85x722f.com.cn", "xn--85x722f.com.cn");
343
+ // checkPublicSuffix("xn--85x722f.xn--55qx5d.cn", "xn--85x722f.xn--55qx5d.cn");
344
+ // checkPublicSuffix("www.xn--85x722f.xn--55qx5d.cn", "xn--85x722f.xn--55qx5d.cn");
345
+ // checkPublicSuffix("shishi.xn--55qx5d.cn", "shishi.xn--55qx5d.cn");
346
+ // checkPublicSuffix("xn--55qx5d.cn", null);
347
+ // checkPublicSuffix("xn--85x722f.xn--fiqs8s", "xn--85x722f.xn--fiqs8s");
348
+ // checkPublicSuffix("www.xn--85x722f.xn--fiqs8s", "xn--85x722f.xn--fiqs8s");
349
+ // checkPublicSuffix("shishi.xn--fiqs8s", "shishi.xn--fiqs8s");
350
+ // checkPublicSuffix("xn--fiqs8s", null);
351
+ });
352
+ });
230
353
  });
@@ -3,10 +3,8 @@
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
5
  const chai = require("chai");
6
- const parsePubSuffixList = require("../lib/tries/parsePubSuffixList");
7
- const serializeTrie = require("../lib/tries/serializeTrie");
8
- const parseTrie = require("../lib/tries/parseTrie");
9
- const lookUp = require("../lib/tries/lookUp");
6
+ const parsePubSuffixList = require("../lib/trie/parsePubSuffixList");
7
+ const serializeTrie = require("../lib/trie/serializeTrie");
10
8
 
11
9
  const expect = chai.expect;
12
10
  const TEST_SNAPSHOT = true;
@@ -36,23 +34,4 @@ describe("snapshots", () => {
36
34
  fs.writeFileSync(pathToSerializeTrieSnapshot, JSON.stringify(serializedTrie));
37
35
  });
38
36
  });
39
- describe("parseTrie() and lookUp() calling lookUp() with the result from parseTrie(snapshot) and hostname", () => {
40
- const serializedTrie = JSON.parse(fs.readFileSync(pathToSerializeTrieSnapshot, "utf8"));
41
- const parsedTrie = parseTrie(serializedTrie);
42
-
43
- [
44
- ["example.com", "com"],
45
- ["example.a.com", "com"],
46
- ["example.uk", "uk"],
47
- ["example.co.uk", "co.uk"],
48
- ["example.ab.uk", "uk"],
49
- ].forEach(testArgs => {
50
- const hostname = testArgs[0];
51
- const expectedResult = testArgs[1];
52
-
53
- it(`'${hostname}' returns ${expectedResult}`, () => {
54
- expect(lookUp(parsedTrie, hostname)).to.equal(expectedResult);
55
- });
56
- });
57
- });
58
37
  });
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+
3
+ const chai = require("chai");
4
+ const lookUp = require("../../lib/trie/lookUp");
5
+ const characters = require("../../lib/trie/characters");
6
+ const {createNode, adoptChild} = require("../../lib/trie/nodes");
7
+
8
+ const expect = chai.expect;
9
+
10
+ function createOneLevelDeepTrie() {
11
+ const root = createNode();
12
+ const com = createNode("com");
13
+
14
+ adoptChild(root, com);
15
+
16
+ return root;
17
+ }
18
+
19
+ function createTwoLevelDeepTrie() {
20
+ const root = createNode();
21
+ const uk = createNode("uk");
22
+ const co = createNode("co");
23
+
24
+ adoptChild(root, uk);
25
+ adoptChild(uk, co);
26
+
27
+ return root;
28
+ }
29
+
30
+ function createTrieWithWildcardAndException() {
31
+ const root = createNode();
32
+ const wildcard = createNode(characters.WILDCARD);
33
+ const exception = createNode(characters.EXCEPTION + "exception");
34
+
35
+ adoptChild(root, wildcard);
36
+ adoptChild(root, exception);
37
+
38
+ return root;
39
+ }
40
+
41
+ describe("lookUp()", () => {
42
+ describe("with an empty trie", () => {
43
+ it("returns an empty array", () => {
44
+ const root = createNode();
45
+
46
+ expect(lookUp(root, ["com"])).to.eql([]);
47
+ expect(lookUp(root, ["example", "com"])).to.eql([]);
48
+ });
49
+ });
50
+ describe("with a one level deep trie", () => {
51
+ it("returns the known TLD as array", () => {
52
+ const root = createOneLevelDeepTrie();
53
+
54
+ expect(lookUp(root, ["com"])).to.eql(["com"]);
55
+ expect(lookUp(root, ["example", "com"])).to.eql(["com"]);
56
+ expect(lookUp(root, ["www", "example", "com"])).to.eql(["com"]);
57
+ });
58
+ it("returns an empty array if there is no known TLD", () => {
59
+ const root = createOneLevelDeepTrie();
60
+
61
+ expect(lookUp(root, ["de"])).to.eql([]);
62
+ expect(lookUp(root, ["example", "de"])).to.eql([]);
63
+ expect(lookUp(root, ["www", "example", "de"])).to.eql([]);
64
+ });
65
+ });
66
+ describe("with a two level deep trie", () => {
67
+ it("returns the known TLD", () => {
68
+ const root = createTwoLevelDeepTrie();
69
+
70
+ expect(lookUp(root, ["uk"])).to.eql(["uk"]);
71
+ expect(lookUp(root, ["example", "uk"])).to.eql(["uk"]);
72
+ expect(lookUp(root, ["co", "uk"])).to.eql(["co", "uk"]);
73
+ expect(lookUp(root, ["example", "co", "uk"])).to.eql(["co", "uk"]);
74
+ expect(lookUp(root, ["www", "example", "co", "uk"])).to.eql(["co", "uk"]);
75
+ });
76
+
77
+ it("returns an empty array if there is no known TLD", () => {
78
+ const root = createTwoLevelDeepTrie();
79
+
80
+ expect(lookUp(root, ["de"])).to.eql([]);
81
+ expect(lookUp(root, ["example", "de"])).to.eql([]);
82
+ expect(lookUp(root, ["www", "example", "de"])).to.eql([]);
83
+ });
84
+ });
85
+ describe("with a wildcard and exceptions", () => {
86
+ it("does not accept the exception as TLD", () => {
87
+ const root = createTrieWithWildcardAndException();
88
+
89
+ expect(lookUp(root, ["exception"])).to.eql([]);
90
+ expect(lookUp(root, ["www", "exception"])).to.eql([]);
91
+ });
92
+ it("accepts all domain names as TLD in place of the wildcard", () => {
93
+ const root = createTrieWithWildcardAndException();
94
+
95
+ expect(lookUp(root, ["anything"])).to.eql(["anything"]);
96
+ expect(lookUp(root, ["www", "anything"])).to.eql(["anything"]);
97
+ });
98
+ });
99
+ });
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ const chai = require("chai");
4
+ const {createNode, adoptChild} = require("../../lib/trie/nodes");
5
+
6
+ const expect = chai.expect;
7
+
8
+ describe("adoptChild()", () => {
9
+ it("throws an error if the child has no domain", () => {
10
+ expect(() => {
11
+ adoptChild(createNode(), createNode());
12
+ }).to.throw("Cannot adopt child: child.domain must be a string");
13
+ });
14
+ it("throws an error if the parent has already a child with that domain", () => {
15
+ expect(() => {
16
+ const parent = createNode();
17
+
18
+ adoptChild(parent, createNode("some-domain"));
19
+ adoptChild(parent, createNode("some-domain"));
20
+ }).to.throw("Cannot adopt child: parent has already a child with the domain 'some-domain'");
21
+ });
22
+ });