1 | 'use strict';
|
2 | const Serializer = require('parse5/lib/serializer');
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | module.exports = class CustomSerializer extends Serializer {
|
15 | constructor(
|
16 | node,
|
17 | { treeAdapter, fullRendering, slotMap, handleTags, pipeTags }
|
18 | ) {
|
19 | super(node, { treeAdapter });
|
20 | this.fullRendering = fullRendering;
|
21 | this.slotMap = slotMap;
|
22 | this.handleTags = handleTags;
|
23 | this.pipeTags = pipeTags;
|
24 | this.isPipeInserted = false;
|
25 | this.lastChildInserted = false;
|
26 | this.defaultSlotsInserted = false;
|
27 | this.serializedList = [];
|
28 | this._serializeNode = this._serializeNode.bind(this);
|
29 | }
|
30 |
|
31 | |
32 |
|
33 |
|
34 |
|
35 |
|
36 | pushBuffer() {
|
37 | if (this.html !== '') {
|
38 | this.serializedList.push(Buffer.from(this.html));
|
39 | this.html = '';
|
40 | }
|
41 | }
|
42 |
|
43 | |
44 |
|
45 |
|
46 |
|
47 |
|
48 | getHtmlContent() {
|
49 | let temp = '';
|
50 | if (this.html !== '') {
|
51 | temp = this.html;
|
52 | this.html = '';
|
53 | }
|
54 | return temp;
|
55 | }
|
56 |
|
57 | |
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | serialize() {
|
64 | this._serializeChildNodes(this.startNode);
|
65 | this.pushBuffer();
|
66 | return this.serializedList;
|
67 | }
|
68 |
|
69 | |
70 |
|
71 |
|
72 |
|
73 |
|
74 | _isPipeNode(node) {
|
75 | return this.pipeTags.includes(node.name);
|
76 | }
|
77 |
|
78 | |
79 |
|
80 |
|
81 |
|
82 |
|
83 | _isSlotNode(node) {
|
84 | const { attribs = {}, name } = node;
|
85 | return (
|
86 | name === 'slot' || (name === 'script' && attribs.type === 'slot')
|
87 | );
|
88 | }
|
89 |
|
90 | |
91 |
|
92 |
|
93 |
|
94 |
|
95 | _isSpecialNode(node) {
|
96 | const { attribs = {}, name } = node;
|
97 | return (
|
98 | this.handleTags.includes(name) ||
|
99 | (name === 'script' && this.handleTags.includes(attribs.type))
|
100 | );
|
101 | }
|
102 |
|
103 | |
104 |
|
105 |
|
106 |
|
107 |
|
108 | _isLastChildOfBody(node) {
|
109 | const { parentNode: { name, lastChild } } = node;
|
110 | return name === 'body' && Object.is(node, lastChild);
|
111 | }
|
112 |
|
113 | |
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | _serializeSpecial(node) {
|
131 | this.pushBuffer();
|
132 | let handledObj;
|
133 | const { name, attribs: attributes } = node;
|
134 | if (this.handleTags.includes(name)) {
|
135 | handledObj = Object.assign({}, { name: name, attributes });
|
136 | this.serializedList.push(handledObj);
|
137 | this._serializeChildNodes(node);
|
138 | this.pushBuffer();
|
139 | } else {
|
140 |
|
141 | this._serializeChildNodes(node);
|
142 | handledObj = Object.assign(
|
143 | {},
|
144 | {
|
145 | name: attributes.type,
|
146 | attributes,
|
147 | textContent: this.getHtmlContent()
|
148 | }
|
149 | );
|
150 | this.serializedList.push(handledObj);
|
151 | }
|
152 | this.serializedList.push({ closingTag: name });
|
153 | }
|
154 |
|
155 | |
156 |
|
157 |
|
158 |
|
159 |
|
160 | _serializeSlot(node) {
|
161 | const slotName = node.attribs.name;
|
162 | if (slotName) {
|
163 | const childNodes = this.treeAdapter.getChildNodes(node);
|
164 | const slots = this.slotMap.has(slotName)
|
165 | ? this.slotMap.get(slotName)
|
166 | : childNodes;
|
167 | slots && slots.forEach(this._serializeNode);
|
168 | } else {
|
169 |
|
170 | if (this.defaultSlotsInserted) {
|
171 | console.warn(
|
172 | 'Encountered duplicate Unnamed slots in the template - Skipping the node'
|
173 | );
|
174 | return;
|
175 | }
|
176 | const defaultSlots = this.slotMap.get('default');
|
177 | this.defaultSlotsInserted = true;
|
178 | defaultSlots && defaultSlots.forEach(this._serializeNode);
|
179 | }
|
180 | }
|
181 |
|
182 | |
183 |
|
184 |
|
185 |
|
186 |
|
187 | _serializePipe(node) {
|
188 | this.pushBuffer();
|
189 | this.serializedList.push({ placeholder: 'pipe' });
|
190 | this.isPipeInserted = true;
|
191 | this._serializeNode(node);
|
192 | }
|
193 |
|
194 | |
195 |
|
196 |
|
197 |
|
198 |
|
199 | _serializeRest() {
|
200 | this.lastChildInserted = true;
|
201 | if (!this.defaultSlotsInserted) {
|
202 | const defaultSlots = this.slotMap.get('default');
|
203 | defaultSlots && defaultSlots.forEach(this._serializeNode);
|
204 | }
|
205 | this.pushBuffer();
|
206 | this.serializedList.push({ placeholder: 'async' });
|
207 | }
|
208 |
|
209 | |
210 |
|
211 |
|
212 |
|
213 |
|
214 | _serializeChildNodes(parentNode) {
|
215 | const childNodes = this.treeAdapter.getChildNodes(parentNode);
|
216 | childNodes && childNodes.forEach(this._serializeNode);
|
217 | }
|
218 |
|
219 | |
220 |
|
221 |
|
222 |
|
223 |
|
224 | _serializeNode(currentNode) {
|
225 | if (
|
226 | this.fullRendering &&
|
227 | !this.isPipeInserted &&
|
228 | this._isPipeNode(currentNode)
|
229 | ) {
|
230 | this._serializePipe(currentNode);
|
231 | } else if (this._isSpecialNode(currentNode)) {
|
232 | this._serializeSpecial(currentNode);
|
233 | } else if (this._isSlotNode(currentNode)) {
|
234 | this._serializeSlot(currentNode);
|
235 | } else if (this.treeAdapter.isElementNode(currentNode)) {
|
236 | this._serializeElement(currentNode);
|
237 | } else if (this.treeAdapter.isTextNode(currentNode)) {
|
238 | this._serializeTextNode(currentNode);
|
239 | } else if (this.treeAdapter.isCommentNode(currentNode)) {
|
240 | this._serializeCommentNode(currentNode);
|
241 | } else if (this.treeAdapter.isDocumentTypeNode(currentNode)) {
|
242 | this._serializeDocumentTypeNode(currentNode);
|
243 | }
|
244 |
|
245 | if (
|
246 | this.fullRendering &&
|
247 | !this.lastChildInserted &&
|
248 | this._isLastChildOfBody(currentNode)
|
249 | ) {
|
250 | this._serializeRest();
|
251 | }
|
252 | }
|
253 | };
|