-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
111 lines (90 loc) · 2.97 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
import _ = require("lodash");
import url = require("url");
import queryString = require("querystring");
import cheerio = require("cheerio");
import { getNodeLoc } from "./location";
interface IVisiter {
onBeforeVisit?: (node: CheerioElement) => void;
onAfterVisit?: (node: CheerioElement) => void;
onBeforeTag?: (node: CheerioElement) => void;
onAfterTag?: (node: CheerioElement) => void;
onStyle?: (node: CheerioElement) => void;
onText?: (node: CheerioElement) => void;
onComment?: (node: CheerioElement) => void;
context: {
html: string,
currentNode: CheerioElement | null
};
}
export let visiter: IVisiter = {
context: {
html: "",
currentNode: null
}
};
export function loader(source: string, map: any) {
const query = queryString.parse(url.parse(this.query).query);
this.cacheable && this.cacheable();
try {
source = process(source);
} catch (err) {
let message = (typeof err === "string") ? err : err.message;
if (visiter.context.currentNode) {
const { pos } = getNodeLoc(visiter.context, visiter.context.currentNode);
message += ` in line ${pos.line}, col ${pos.col}`;
}
this.callback(new Error(message));
return;
}
this.callback(null, source, map);
};
function process(source: string) {
const cheerioOptions = {lowerCaseTags: false, lowerCaseAttributeNames: false, xmlMode: true, withStartIndices: true}; // xmlMode turned off to allow decode of
const rootNode = cheerio.load(source, cheerioOptions);
const rootTags = _.filter(rootNode.root()[0].children, node => node.type === "tag" || node.type === "style");
const root = rootTags[0] as CheerioElement;
visiter.context.html = rootNode.root().html();
visiter.context.currentNode = root;
if (visiter.onBeforeVisit) {
visiter.onBeforeVisit(root);
}
visit(root);
if (visiter.onAfterVisit) {
visiter.onAfterVisit(root);
}
return rootNode.root().html();
}
function visit(node: CheerioElement): void {
if (node.type === "tag") visitTagNode(node);
else if (node.type === "style") visitStyleNode(node);
else if (node.type === "comment") visitCommentNode(node);
else if (node.type === "text") visitTextNode(node);
}
function visitTagNode(node: CheerioElement): void {
visiter.context.currentNode = node;
if (visiter.onBeforeTag) {
visiter.onBeforeTag(node);
}
_.each(node.children, child => visit(child));
if (visiter.onAfterTag) {
visiter.onAfterTag(node);
}
}
function visitStyleNode(node: CheerioElement): void {
visiter.context.currentNode = node;
if (visiter.onStyle) {
visiter.onStyle(node);
}
}
function visitCommentNode(node: CheerioElement): void {
visiter.context.currentNode = node;
if (visiter.onComment) {
visiter.onComment(node);
}
}
function visitTextNode(node: CheerioElement): void {
visiter.context.currentNode = node;
if (visiter.onText) {
visiter.onText(node);
}
}