/
index.ts
112 lines (101 loc) · 2.62 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import parse5 from "parse5";
import * as htmlparser2 from "parse5-htmlparser2-tree-adapter";
/**
* @public
*/
export type ExtractorResultDetailed = {
attributes: {
names: string[];
values: string[];
};
classes: string[];
ids: string[];
tags: string[];
undetermined: string[];
};
const mergedExtractorResults = (
resultLeft: ExtractorResultDetailed,
resultRight: ExtractorResultDetailed
): ExtractorResultDetailed => {
return {
attributes: {
names: [...resultLeft.attributes.names, ...resultRight.attributes.names],
values: [
...resultLeft.attributes.values,
...resultRight.attributes.values,
],
},
classes: [...resultLeft.classes, ...resultRight.classes],
ids: [...resultLeft.ids, ...resultRight.ids],
tags: [...resultLeft.tags, ...resultRight.tags],
undetermined: [],
};
};
const getSelectorsInElement = (
element: htmlparser2.Element
): ExtractorResultDetailed => {
const result: ExtractorResultDetailed = {
attributes: {
names: [],
values: [],
},
classes: [],
ids: [],
tags: [element.name],
undetermined: [],
};
for (const [name, value] of Object.entries(element.attribs)) {
if (name === "class") {
result.classes.push(...value.split(" "));
} else if (name === "id") {
result.ids.push(...value.split(" "));
} else {
result.attributes.names.push(name);
result.attributes.values.push(...value.split(" "));
}
}
return mergedExtractorResults(getSelectorsInNodes(element), result);
};
const getSelectorsInNodes = (
node: htmlparser2.Document | htmlparser2.Element
): ExtractorResultDetailed => {
let result: ExtractorResultDetailed = {
attributes: {
names: [],
values: [],
},
classes: [],
ids: [],
tags: [],
undetermined: [],
};
for (const childNode of node.children) {
const element = childNode as htmlparser2.Element;
switch (element.type) {
case "tag":
result = mergedExtractorResults(result, getSelectorsInElement(element));
break;
case "root":
result = mergedExtractorResults(result, getSelectorsInNodes(element));
break;
default:
break;
}
}
return result;
};
/**
* Get the potential selectors from HTML code
*
* @param content - HTML code
* @returns the attributes, classes, ids, and tags from the HTML code
*
* @public
*/
const purgecssFromHtml = (content: string): ExtractorResultDetailed => {
const tree = parse5.parse(content, {
treeAdapter: htmlparser2,
}) as htmlparser2.Document;
return getSelectorsInNodes(tree);
};
export default purgecssFromHtml;