1 import dateFormat
from "dateformat";
2 import crypto
from "crypto";
3 import { promises as fs
} from "fs";
4 import path
from "path";
5 import { fileURLToPath
} from "url";
8 import filters
from "../../filters.json" with { type
: "json" };
10 const NULL_IP
= "0.0.0.0";
12 // For header example, see https://easylist-downloads.adblockplus.org/easylist.txt
13 const currentDate
= new Date();
14 const version
= dateFormat(currentDate
, "yyyymmddHHMM", true);
15 const lastModified
= dateFormat(currentDate
, "dd mmm yyyy HH:MM Z", true);
17 const __filename
= fileURLToPath(import.meta
.url
);
18 const __dirname
= path
.dirname(__filename
);
20 const calculateChecksum
= (content
) => {
21 const rest
= content
.replace(/! Checksum: #CHECKSUM#\n/, "");
29 const withFinalNL
= (content
) => content
.toString().trim() + "\n";
31 const buildFilters
= async () => {
32 console
.log("Build filters...");
33 for (const filter
of filters
) {
34 if (!filter
.hasOwnProperty("sections")) continue;
35 console
.log(` * Building list: ${filter.output}`);
38 let headerContent
= "";
39 if (filter
.hasOwnProperty("header")) {
40 headerContent
+= withFinalNL(
42 path
.join(__dirname
, `../../sections/headers/${filter.header}`)
45 console
.log(` - Header: ${filter.header} added`);
48 console
.log(` - Sections:`);
50 for (const section
of filter
.sections
) {
51 content
+= withFinalNL(
52 await fs
.readFile(path
.join(__dirname
, `../../sections/${section}`))
54 console
.log(` - ${section} added`);
56 // Handle DNS / hosts filters
57 if (filter
.dns
|| filter
.hosts
) {
58 // TODO: Switch to AGTree and extract domain from pattern with tldts
59 const regex
= /^\|\|([a-z0-9]+([-.][a-z0-9]+)*\.[a-z]{2,})($|\^$)/gm;
60 const matches
= content
.matchAll(regex
);
61 const domains
= Array
.from(matches
, ([_
, domain
]) => domain
);
64 ? domains
.map((domain
) => `${NULL_IP} ${domain}`)
69 const strippedFilters
=
72 .filter((line
) => line
.replace("!", "").trim().length
> 0)
76 if (headerContent
.length
) {
78 headerContent
= headerContent
.replace(/#VERSION#/, version
);
79 headerContent
= headerContent
.replace(/#LAST_MODIFIED#/, lastModified
);
80 headerContent
= headerContent
.replace(/#TITLE#/, filter
.title
|| "hufilter");
82 const checksum
= await
calculateChecksum(headerContent
+ strippedFilters
);
83 headerContent
= headerContent
.replace(/#CHECKSUM#/, checksum
);
85 const fileContent
= headerContent
+ strippedFilters
;
88 path
.join(__dirname
, `../../dist/${filter.output}`),
92 console
.log(` - FAILED: ${err.message}`);
98 // Create dist folder if not exists
100 await fs
.mkdir(path
.join(__dirname
, "../../dist"));
103 await
buildFilters();