stable-sort-domain.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // tldts-experimental is way faster than tldts, but very little bit inaccurate
  2. // (since it is hashes based). But the result is still deterministic, which is
  3. // enough when sorting.
  4. import { getDomain, getSubdomain } from 'tldts-experimental';
  5. import { sort } from './timsort';
  6. import { looseTldtsOpt } from '../constants/loose-tldts-opt';
  7. export const compare = (a: string, b: string) => {
  8. if (a === b) return 0;
  9. return (a.length - b.length) || a.localeCompare(b);
  10. };
  11. export const buildParseDomainMap = (inputs: string[]) => {
  12. const domainMap = new Map<string, string>();
  13. const subdomainMap = new Map<string, string>();
  14. for (let i = 0, len = inputs.length; i < len; i++) {
  15. const cur = inputs[i];
  16. if (!domainMap.has(cur)) {
  17. const topD = getDomain(cur, looseTldtsOpt);
  18. domainMap.set(cur, topD ?? cur);
  19. }
  20. if (!subdomainMap.has(cur)) {
  21. const subD = getSubdomain(cur, looseTldtsOpt);
  22. subdomainMap.set(cur, subD ?? cur);
  23. }
  24. }
  25. return { domainMap, subdomainMap };
  26. };
  27. export const sortDomains = (
  28. inputs: string[],
  29. domainMap?: Map<string, string>,
  30. subdomainMap?: Map<string, string>
  31. ) => {
  32. if (!domainMap || !subdomainMap) {
  33. const { domainMap: dm, subdomainMap: sm } = buildParseDomainMap(inputs);
  34. domainMap = dm;
  35. subdomainMap = sm;
  36. }
  37. for (let i = 0, len = inputs.length; i < len; i++) {
  38. const cur = inputs[i];
  39. if (!domainMap.has(cur)) {
  40. const topD = getDomain(cur, looseTldtsOpt);
  41. domainMap.set(cur, topD ?? cur);
  42. }
  43. if (!subdomainMap.has(cur)) {
  44. const subD = getSubdomain(cur, looseTldtsOpt);
  45. subdomainMap.set(cur, subD ?? cur);
  46. }
  47. }
  48. const sorter = (a: string, b: string) => {
  49. if (a === b) return 0;
  50. const main_domain_a = domainMap.get(a)!;
  51. const main_domain_b = domainMap.get(b)!;
  52. let t = compare(
  53. main_domain_a,
  54. main_domain_b
  55. ) || compare(
  56. /** subdomain_a */ subdomainMap.get(a)!,
  57. /** subdomain_b */ subdomainMap.get(b)!
  58. );
  59. if (t !== 0) return t;
  60. if (a !== main_domain_a || b !== main_domain_b) {
  61. t = compare(a, b);
  62. }
  63. return t;
  64. };
  65. return sort(inputs, sorter);
  66. };