• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const assert = require('assert');
4const dedent = require('dedent');
5const RewritingStream = require('../lib');
6const loadSAXParserTestData = require('../../../test/utils/load-sax-parser-test-data');
7const { getStringDiffMsg, writeChunkedToStream, WritableStreamStub } = require('../../../test/utils/common');
8
9const srcHtml = dedent`
10    <!DOCTYPE html "">
11    <html>
12        <!-- comment1 -->
13        <head /// 123>
14        </head>
15        <!-- comment2 -->
16        <body =123>
17            <div>Hey ya</div>
18        </body>
19    </html>
20`;
21
22function createRewriterTest({ src, expected, assignTokenHandlers = () => {} }) {
23    return done => {
24        const rewriter = new RewritingStream();
25        const writable = new WritableStreamStub();
26
27        writable.once('finish', () => {
28            assert.ok(writable.writtenData === expected, getStringDiffMsg(writable.writtenData, expected));
29            done();
30        });
31
32        rewriter.pipe(writable);
33
34        assignTokenHandlers(rewriter);
35        writeChunkedToStream(src, rewriter);
36    };
37}
38
39// Raw data tests
40loadSAXParserTestData().forEach(
41    // NOTE: if we don't have any event handlers assigned, stream should use raw
42    // data for the serialization, so serialized content should identical to the original.
43    (test, idx) =>
44        (exports[`RewritingStream - Raw token serialization - ${idx + 1}.${test.name}`] = createRewriterTest({
45            src: test.src,
46            expected: test.src
47        }))
48);
49
50exports['RewritingStream - rewrite start tags'] = createRewriterTest({
51    src: srcHtml,
52    expected: dedent`
53        <!DOCTYPE html "">
54        <html>
55            <!-- comment1 -->
56            <body 123="">
57            </head>
58            <!-- comment2 -->
59            <head =123="">
60                <div>Hey ya</div>
61            </body>
62        </html>
63    `,
64    assignTokenHandlers: rewriter => {
65        rewriter.on('startTag', token => {
66            if (token.tagName === 'head') {
67                token.tagName = 'body';
68            } else if (token.tagName === 'body') {
69                token.tagName = 'head';
70            }
71
72            rewriter.emitStartTag(token);
73        });
74    }
75});
76
77exports['RewritingStream - rewrite end tags'] = createRewriterTest({
78    src: srcHtml,
79    expected: dedent`
80        <!DOCTYPE html "">
81        <html>
82            <!-- comment1 -->
83            <head /// 123>
84            </rewritten>
85            <!-- comment2 -->
86            <body =123>
87                <div>Hey ya</rewritten>
88            </rewritten>
89        </rewritten>
90    `,
91    assignTokenHandlers: rewriter => {
92        rewriter.on('endTag', token => {
93            token.tagName = 'rewritten';
94
95            rewriter.emitEndTag(token);
96        });
97    }
98});
99
100exports['RewritingStream - rewrite text'] = createRewriterTest({
101    src: srcHtml,
102    expected: dedent`
103        <!DOCTYPE html "">
104        <html>
105            <!-- comment1 -->
106            <head /// 123>
107            </head>
108            <!-- comment2 -->
109            <body =123>
110                <div>42</div>
111            </body>
112        </html>
113    `,
114    assignTokenHandlers: rewriter => {
115        rewriter.on('text', token => {
116            if (token.text.trim().length > 0) {
117                token.text = '42';
118            }
119
120            rewriter.emitText(token);
121        });
122    }
123});
124
125exports['RewritingStream - rewrite comment'] = createRewriterTest({
126    src: srcHtml,
127    expected: dedent`
128        <!DOCTYPE html "">
129        <html>
130            <!--42-->
131            <head /// 123>
132            </head>
133            <!--42-->
134            <body =123>
135                <div>Hey ya</div>
136            </body>
137        </html>
138    `,
139    assignTokenHandlers: rewriter => {
140        rewriter.on('comment', token => {
141            token.text = '42';
142
143            rewriter.emitComment(token);
144        });
145    }
146});
147
148exports['RewritingStream - rewrite doctype'] = createRewriterTest({
149    src: srcHtml,
150    expected: dedent`
151        <!DOCTYPE html PUBLIC "42" "hey">
152        <html>
153            <!-- comment1 -->
154            <head /// 123>
155            </head>
156            <!-- comment2 -->
157            <body =123>
158                <div>Hey ya</div>
159            </body>
160        </html>
161    `,
162    assignTokenHandlers: rewriter => {
163        rewriter.on('doctype', token => {
164            token.publicId = '42';
165            token.systemId = 'hey';
166
167            rewriter.emitDoctype(token);
168        });
169    }
170});
171
172exports['RewritingStream - emit multiple'] = createRewriterTest({
173    src: srcHtml,
174    expected: dedent`
175        <!DOCTYPE html "">
176        <wrap><html></wrap>
177            <!-- comment1 -->
178            <wrap><head 123=""></wrap>
179            </head>
180            <!-- comment2 -->
181            <wrap><body =123=""></wrap>
182                <wrap><div></wrap>Hey ya</div>
183            </body>
184        </html>
185    `,
186    assignTokenHandlers: rewriter => {
187        rewriter.on('startTag', token => {
188            rewriter.emitRaw('<wrap>');
189            rewriter.emitStartTag(token);
190            rewriter.emitRaw('</wrap>');
191        });
192    }
193});
194
195exports['RewritingStream - rewrite raw'] = createRewriterTest({
196    src: srcHtml,
197    expected: dedent`
198        <!DOCTYPE html "">42
199        <html>42
200            <!-- comment1 -->42
201            <head /// 123>42
202            </head>42
203            <!-- comment2 -->42
204            <body =123>42
205                <div>42Hey ya</div>42
206            </body>42
207        </html>42
208    `,
209    assignTokenHandlers: rewriter => {
210        const rewriteRaw = (_, raw) => {
211            rewriter.emitRaw(raw + '42');
212        };
213
214        rewriter
215            .on('doctype', rewriteRaw)
216            .on('startTag', rewriteRaw)
217            .on('endTag', rewriteRaw)
218            .on('comment', rewriteRaw);
219    }
220});
221
222exports['RewritingStream - Should escape entities in attributes and text'] = createRewriterTest({
223    src: dedent`
224        <!DOCTYPE html "">
225        <html>
226            <head foo='bar"baz"'>
227            </head>
228            <body>
229                <div>foo&amp;bar</div>
230            </body>
231        </html>
232    `,
233    expected: dedent`
234        <!DOCTYPE html "">
235        <html>
236            <head foo="bar&quot;baz&quot;">
237            </head>
238            <body>
239                <div>foo&amp;bar</div>
240            </body>
241        </html>
242    `,
243    assignTokenHandlers: rewriter => {
244        rewriter.on('startTag', token => rewriter.emitStartTag(token));
245        rewriter.on('text', token => rewriter.emitText(token));
246    }
247});
248
249exports['Regression - RewritingStream - Last text chunk must be flushed (GH-271)'] = done => {
250    const parser = new RewritingStream();
251    let foundText = false;
252
253    parser.on('text', ({ text }) => {
254        foundText = true;
255        assert.strictEqual(text, 'text');
256    });
257
258    parser.once('finish', () => {
259        assert.ok(foundText);
260        done();
261    });
262
263    parser.write('text');
264    parser.end();
265};
266
267exports['Regression - RewritingStream - Should not accept binary input (GH-269)'] = () => {
268    const stream = new RewritingStream();
269    const buf = Buffer.from('test');
270
271    assert.throws(() => stream.write(buf), TypeError);
272};
273