[6a3a178] | 1 | 'use strict';
|
---|
| 2 |
|
---|
| 3 | const SAXParser = require('parse5-sax-parser');
|
---|
| 4 | const { escapeString } = require('parse5/lib/serializer');
|
---|
| 5 |
|
---|
| 6 | class RewritingStream extends SAXParser {
|
---|
| 7 | constructor() {
|
---|
| 8 | super({ sourceCodeLocationInfo: true });
|
---|
| 9 |
|
---|
| 10 | this.posTracker = this.locInfoMixin.posTracker;
|
---|
| 11 | }
|
---|
| 12 |
|
---|
| 13 | _transformChunk(chunk) {
|
---|
| 14 | // NOTE: ignore upstream return value as we want to push to
|
---|
| 15 | // the Writable part of Transform stream ourselves.
|
---|
| 16 | super._transformChunk(chunk);
|
---|
| 17 | }
|
---|
| 18 |
|
---|
| 19 | _getRawHtml(location) {
|
---|
| 20 | const droppedBufferSize = this.posTracker.droppedBufferSize;
|
---|
| 21 | const start = location.startOffset - droppedBufferSize;
|
---|
| 22 | const end = location.endOffset - droppedBufferSize;
|
---|
| 23 |
|
---|
| 24 | return this.tokenizer.preprocessor.html.slice(start, end);
|
---|
| 25 | }
|
---|
| 26 |
|
---|
| 27 | // Events
|
---|
| 28 | _handleToken(token) {
|
---|
| 29 | if (!super._handleToken(token)) {
|
---|
| 30 | this.emitRaw(this._getRawHtml(token.location));
|
---|
| 31 | }
|
---|
| 32 |
|
---|
| 33 | // NOTE: don't skip new lines after <pre> and other tags,
|
---|
| 34 | // otherwise we'll have incorrect raw data.
|
---|
| 35 | this.parserFeedbackSimulator.skipNextNewLine = false;
|
---|
| 36 | }
|
---|
| 37 |
|
---|
| 38 | // Emitter API
|
---|
| 39 | _emitToken(eventName, token) {
|
---|
| 40 | this.emit(eventName, token, this._getRawHtml(token.sourceCodeLocation));
|
---|
| 41 | }
|
---|
| 42 |
|
---|
| 43 | emitDoctype(token) {
|
---|
| 44 | let res = `<!DOCTYPE ${token.name}`;
|
---|
| 45 |
|
---|
| 46 | if (token.publicId !== null) {
|
---|
| 47 | res += ` PUBLIC "${token.publicId}"`;
|
---|
| 48 | } else if (token.systemId !== null) {
|
---|
| 49 | res += ' SYSTEM';
|
---|
| 50 | }
|
---|
| 51 |
|
---|
| 52 | if (token.systemId !== null) {
|
---|
| 53 | res += ` "${token.systemId}"`;
|
---|
| 54 | }
|
---|
| 55 |
|
---|
| 56 | res += '>';
|
---|
| 57 |
|
---|
| 58 | this.push(res);
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | emitStartTag(token) {
|
---|
| 62 | let res = `<${token.tagName}`;
|
---|
| 63 |
|
---|
| 64 | const attrs = token.attrs;
|
---|
| 65 |
|
---|
| 66 | for (let i = 0; i < attrs.length; i++) {
|
---|
| 67 | res += ` ${attrs[i].name}="${escapeString(attrs[i].value, true)}"`;
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | res += token.selfClosing ? '/>' : '>';
|
---|
| 71 |
|
---|
| 72 | this.push(res);
|
---|
| 73 | }
|
---|
| 74 |
|
---|
| 75 | emitEndTag(token) {
|
---|
| 76 | this.push(`</${token.tagName}>`);
|
---|
| 77 | }
|
---|
| 78 |
|
---|
| 79 | emitText({ text }) {
|
---|
| 80 | this.push(escapeString(text, false));
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | emitComment(token) {
|
---|
| 84 | this.push(`<!--${token.text}-->`);
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | emitRaw(html) {
|
---|
| 88 | this.push(html);
|
---|
| 89 | }
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | module.exports = RewritingStream;
|
---|