tldts-tests 7.3.0 → 7.4.0

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.
@@ -65,6 +65,7 @@ export default function test(
65
65
  getPublicSuffix: (url: string, options?: Options) => string | null;
66
66
  getHostname: (url: string, options?: Options) => string | null;
67
67
  getDomain: (url: string, options?: Options) => string | null;
68
+ getFullDomain: (url: string, options?: Options) => string | null;
68
69
  getSubdomain: (url: string, options?: Options) => string | null;
69
70
  parse: (
70
71
  url: string,
@@ -370,6 +371,25 @@ export default function test(
370
371
  expect(tldts.getDomain('s_pf.google.com')).to.equal('google.com'); // middle '_' (reference case)
371
372
  });
372
373
 
374
+ // A label must not BEGIN with a hyphen (RFC 1034 §3.5 / RFC 1035 §2.3.1 LDH;
375
+ // cf. WHATWG "valid domain" / UTS #46 CheckHyphens). validateHostname is on by
376
+ // default, so an invalid host yields a null parse — exercised here at the
377
+ // public-API level (the inline-validation fast path). @see issue #2395.
378
+ it('should reject labels that begin with a hyphen', () => {
379
+ expect(tldts.getHostname('foo.-example.com')).to.equal(null); // interior label
380
+ expect(tldts.getHostname('a.b.-c.com')).to.equal(null); // deeper interior label
381
+ expect(tldts.getHostname('foo.-com')).to.equal(null); // final label
382
+ expect(tldts.getDomain('foo.-example.com')).to.equal(null);
383
+ expect(tldts.getHostname('-example.com')).to.equal(null); // first label (already rejected)
384
+ // Interior hyphens and underscore-leading labels stay valid.
385
+ expect(tldts.getHostname('foo.ex-ample.com')).to.equal(
386
+ 'foo.ex-ample.com',
387
+ );
388
+ expect(tldts.getHostname('_dmarc.example.com')).to.equal(
389
+ '_dmarc.example.com',
390
+ );
391
+ });
392
+
373
393
  // @see https://github.com/oncletom/tld.js/issues/53
374
394
  it('should correctly extract domain from paths including "@" in the path', () => {
375
395
  const domain = tldts.getDomain(
@@ -415,6 +435,134 @@ export default function test(
415
435
  });
416
436
  });
417
437
 
438
+ describe('#getFullDomain', () => {
439
+ it('returns the full hostname (subdomain + domain) for a registrable domain', () => {
440
+ expect(tldts.getFullDomain('foo.bar.example.co.uk')).to.equal(
441
+ 'foo.bar.example.co.uk',
442
+ );
443
+ expect(
444
+ tldts.getFullDomain('https://foo.bar.example.co.uk:8080/path?q=1'),
445
+ ).to.equal('foo.bar.example.co.uk');
446
+ });
447
+
448
+ it('equals the domain when there is no subdomain', () => {
449
+ expect(tldts.getFullDomain('example.com')).to.equal('example.com');
450
+ });
451
+
452
+ it('normalises like the other extractors (lowercase, trailing dot, userinfo/port)', () => {
453
+ expect(tldts.getFullDomain('FOO.Example.COM.')).to.equal(
454
+ 'foo.example.com',
455
+ );
456
+ expect(tldts.getFullDomain('https://user@a.b.example.com:443/')).to.equal(
457
+ 'a.b.example.com',
458
+ );
459
+ });
460
+
461
+ it('returns null when there is no registrable domain', () => {
462
+ expect(tldts.getFullDomain('1.2.3.4')).to.equal(null); // IP
463
+ expect(tldts.getFullDomain('localhost')).to.equal(null); // single label
464
+ expect(tldts.getFullDomain('co.uk')).to.equal(null); // public suffix only
465
+ });
466
+
467
+ it('keeps subdomains that are not valid hostnames (#2322 DNS-record use case)', () => {
468
+ expect(
469
+ tldts.getFullDomain('___sip___._tcp.sipdbw06.rcs01.5gm.example.com'),
470
+ ).to.equal('___sip___._tcp.sipdbw06.rcs01.5gm.example.com');
471
+ });
472
+
473
+ it('validateHostname:false skips character checks but still requires a public suffix', () => {
474
+ // '!' is rejected by the default hostname validation...
475
+ expect(tldts.getFullDomain('a!b.example.com')).to.equal(null);
476
+ // ...but the registrable domain is still found when validation is off.
477
+ expect(
478
+ tldts.getFullDomain('a!b.example.com', { validateHostname: false }),
479
+ ).to.equal('a!b.example.com');
480
+ // A bare label has no registrable domain either way.
481
+ expect(
482
+ tldts.getFullDomain('foo_bar', { validateHostname: false }),
483
+ ).to.equal(null);
484
+ });
485
+
486
+ it('is consistent with getHostname gated on getDomain', () => {
487
+ for (const input of [
488
+ 'foo.bar.example.co.uk',
489
+ 'https://a.b.c.example.com:8080/p',
490
+ 'example.com',
491
+ '1.2.3.4',
492
+ 'localhost',
493
+ 'co.uk',
494
+ ]) {
495
+ const expected =
496
+ tldts.getDomain(input) === null ? null : tldts.getHostname(input);
497
+ expect(tldts.getFullDomain(input)).to.equal(expected);
498
+ }
499
+ });
500
+
501
+ it('avoids the getSubdomain + getDomain join footgun', () => {
502
+ // The naive `getSubdomain(x) + '.' + getDomain(x)` recipe emits a spurious
503
+ // leading dot when there is no subdomain; getFullDomain does not.
504
+ expect(tldts.getFullDomain('example.com')).to.equal('example.com');
505
+ expect(
506
+ `${tldts.getSubdomain('example.com')}.${tldts.getDomain('example.com')}`,
507
+ ).to.equal('.example.com'); // the footgun, shown for contrast
508
+ });
509
+
510
+ it('honors the validHosts option', () => {
511
+ expect(
512
+ tldts.getFullDomain('vhost.intranet', { validHosts: ['intranet'] }),
513
+ ).to.equal('vhost.intranet');
514
+ expect(
515
+ tldts.getFullDomain('intranet', { validHosts: ['intranet'] }),
516
+ ).to.equal('intranet');
517
+ // Without it, a bare unknown single label has no registrable domain.
518
+ expect(tldts.getFullDomain('intranet')).to.equal(null);
519
+ });
520
+
521
+ it('honors allowPrivateDomains (private-suffix gating)', () => {
522
+ // github.io is in the PRIVATE section: by default it is a registrable
523
+ // domain in every build.
524
+ expect(tldts.getFullDomain('github.io')).to.equal('github.io');
525
+ // Once private suffixes count it becomes a bare suffix (=> null). Only
526
+ // meaningful for builds that ship the PRIVATE section (not tldts-icann).
527
+ if (includePrivate) {
528
+ expect(
529
+ tldts.getFullDomain('github.io', { allowPrivateDomains: true }),
530
+ ).to.equal(null);
531
+ expect(
532
+ tldts.getFullDomain('user.github.io', { allowPrivateDomains: true }),
533
+ ).to.equal('user.github.io');
534
+ }
535
+ });
536
+
537
+ it('handles wildcard and exception public-suffix rules', () => {
538
+ expect(tldts.getFullDomain('foo.bar.ck')).to.equal('foo.bar.ck'); // *.ck
539
+ expect(tldts.getFullDomain('foo.ck')).to.equal(null); // bare *.ck suffix
540
+ expect(tldts.getFullDomain('a.www.ck')).to.equal('a.www.ck'); // !www.ck
541
+ });
542
+
543
+ it('preserves IDN / punycode labels without conversion', () => {
544
+ expect(tldts.getFullDomain('a.münchen.de')).to.equal('a.münchen.de');
545
+ expect(tldts.getFullDomain('a.xn--mnchen-3ya.de')).to.equal(
546
+ 'a.xn--mnchen-3ya.de',
547
+ );
548
+ });
549
+
550
+ it('returns null for IP addresses (no registrable domain)', () => {
551
+ expect(tldts.getFullDomain('http://[2a01:e35::1]:443/x')).to.equal(null);
552
+ expect(tldts.getFullDomain('2a01:e35::1')).to.equal(null);
553
+ });
554
+
555
+ it('respects the 255-character hostname length limit', () => {
556
+ const label = 'a'.repeat(63);
557
+ const max = `${label}.${label}.${label}.${'a'.repeat(59)}.com`;
558
+ expect(max).to.have.lengthOf(255);
559
+ expect(tldts.getFullDomain(max)).to.equal(max);
560
+ const tooLong = `${label}.${label}.${label}.${'a'.repeat(60)}.com`;
561
+ expect(tooLong).to.have.lengthOf(256);
562
+ expect(tldts.getFullDomain(tooLong)).to.equal(null);
563
+ });
564
+ });
565
+
418
566
  describe('#getPublicSuffix', () => {
419
567
  if (includePrivate) {
420
568
  describe('allowPrivateDomains', () => {
@@ -1722,6 +1870,7 @@ export default function test(
1722
1870
  expect(tldts.parse(url)).to.deep.equal(tldts.parse(url, {}));
1723
1871
  expect(tldts.getHostname(url)).to.equal(tldts.getHostname(url, {}));
1724
1872
  expect(tldts.getDomain(url)).to.equal(tldts.getDomain(url, {}));
1873
+ expect(tldts.getFullDomain(url)).to.equal(tldts.getFullDomain(url, {}));
1725
1874
  expect(tldts.getPublicSuffix(url)).to.equal(
1726
1875
  tldts.getPublicSuffix(url, {}),
1727
1876
  );