Skip to content

Commit

Permalink
Refactor & improve serializer (#383)
Browse files Browse the repository at this point in the history
Co-authored-by: Joel Denning <5524384+joeldenning@users.noreply.github.com>
  • Loading branch information
fb55 and joeldenning committed Feb 15, 2022
1 parent e69740f commit b3338ff
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 154 deletions.
19 changes: 3 additions & 16 deletions packages/parse5-serializer-stream/lib/index.ts
@@ -1,5 +1,5 @@
import { Readable } from 'node:stream';
import { Serializer, SerializerOptions } from 'parse5/dist/serializer/index.js';
import { serialize, type SerializerOptions } from 'parse5/dist/serializer/index.js';
import type { TreeAdapterTypeMap } from 'parse5/dist/tree-adapters/interface.js';

/**
Expand All @@ -22,32 +22,19 @@ import type { TreeAdapterTypeMap } from 'parse5/dist/tree-adapters/interface.js'
* ```
*/
export class SerializerStream<T extends TreeAdapterTypeMap> extends Readable {
private serializer: Serializer<T>;

/**
* Streaming AST node to an HTML serializer. A readable stream.
*
* @param node Node to serialize.
* @param options Serialization options.
*/
constructor(node: T['parentNode'], options: SerializerOptions<T>) {
constructor(private node: T['parentNode'], private options: SerializerOptions<T>) {
super({ encoding: 'utf8' });

this.serializer = new Serializer(node, options);

Object.defineProperty(this.serializer, 'html', {
//NOTE: To make `+=` concat operator work properly we define
//getter which always returns empty string
get() {
return '';
},
set: (data: string) => this.push(data),
});
}

//Readable stream implementation
override _read(): void {
this.serializer.serialize();
this.push(serialize(this.node, this.options));
this.push(null);
}
}
35 changes: 2 additions & 33 deletions packages/parse5/lib/index.ts
@@ -1,10 +1,10 @@
import { Parser, ParserOptions } from './parser/index.js';
import { Serializer, SerializerOptions } from './serializer/index.js';

import type { DefaultTreeAdapterMap } from './tree-adapters/default.js';
import type { TreeAdapterTypeMap } from './tree-adapters/interface.js';

export { ParserOptions } from './parser/index.js';
export { SerializerOptions } from './serializer/index.js';
export { serialize, serializeOuter, SerializerOptions } from './serializer/index.js';

// Shorthands

Expand Down Expand Up @@ -81,34 +81,3 @@ export function parseFragment<T extends TreeAdapterTypeMap = DefaultTreeAdapterM

return parser.parseFragment(html as string, fragmentContext);
}

/**
* Serializes an AST node to an HTML string.
*
* @example
*
* ```js
* const parse5 = require('parse5');
*
* const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
*
* // Serializes a document.
* const html = parse5.serialize(document);
*
* // Serializes the <html> element content.
* const str = parse5.serialize(document.childNodes[1]);
*
* console.log(str); //> '<head></head><body>Hi there!</body>'
* ```
*
* @param node Node to serialize.
* @param options Serialization options.
*/
export function serialize<T extends TreeAdapterTypeMap = DefaultTreeAdapterMap>(
node: T['parentNode'],
options: SerializerOptions<T>
): string {
const serializer = new Serializer(node, options);

return serializer.serialize();
}
22 changes: 21 additions & 1 deletion packages/parse5/lib/serializer/index.test.ts
Expand Up @@ -2,7 +2,7 @@ import * as assert from 'node:assert';
import * as parse5 from 'parse5';
import { generateSerializerTests } from 'parse5-test-utils/utils/generate-serializer-tests.js';
import { treeAdapters } from 'parse5-test-utils/utils/common.js';
import type { Element } from 'parse5/dist/tree-adapters/default';
import { type Element, isElementNode } from 'parse5/dist/tree-adapters/default';

generateSerializerTests('serializer', 'Serializer', parse5.serialize);

Expand All @@ -22,4 +22,24 @@ describe('serializer', () => {
parse5.serialize(document, { treeAdapter });
});
});

describe('serializeOuter', () => {
it('serializes outerHTML correctly', () => {
const document = parse5.parseFragment('<div><button>Hello</button></div>');
const div = document.childNodes[0];
assert.ok(isElementNode(div));
const html = parse5.serializeOuter(div);

assert.equal(html, '<div><button>Hello</button></div>');
});
});

it('serializes <template> elements inner content', () => {
const document = parse5.parseFragment('<template><button>Hello</button></template>');
const template = document.childNodes[0];
assert.ok(isElementNode(template));
const html = parse5.serialize(template);

assert.equal(html, '<button>Hello</button>');
});
});

0 comments on commit b3338ff

Please sign in to comment.