Skip to content

Commit 999389e

Browse files
committed
Support type guards for the output of the parser through the use of a discriminating union
1 parent 09125e4 commit 999389e

File tree

1 file changed

+34
-30
lines changed

1 file changed

+34
-30
lines changed

src/js/saxWasm.ts

+34-30
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,32 @@
1414
* slight performance improvement which becomes more noticeable
1515
* on very large documents.
1616
*/
17-
export enum SaxEventType {
18-
// 1
19-
Text = 0b1,
20-
// 2
21-
ProcessingInstruction = 0b10,
22-
// 4
23-
Declaration = 0b100,
24-
// 8
25-
Doctype = 0b1000,
26-
// 16
27-
Comment = 0b10000,
28-
// 32
29-
OpenTagStart = 0b100000,
30-
// 64
31-
Attribute = 0b1000000,
32-
// 128
33-
OpenTag = 0b10000000,
34-
// 256
35-
CloseTag = 0b100000000,
36-
// 512
37-
Cdata = 0b1000000000,
38-
}
17+
export const SaxEventType = {
18+
Text: 0b1,
19+
ProcessingInstruction: 0b10,
20+
Declaration: 0b100,
21+
Doctype: 0b1000,
22+
Comment: 0b10000,
23+
OpenTagStart: 0b100000,
24+
Attribute: 0b1000000,
25+
OpenTag: 0b10000000,
26+
CloseTag: 0b100000000,
27+
Cdata: 0b1000000000,
28+
} as const;
29+
30+
export type SaxEventType = typeof SaxEventType[keyof typeof SaxEventType]
31+
32+
export type SaxEvent = [typeof SaxEventType.Text, Text]
33+
| [typeof SaxEventType.ProcessingInstruction, ProcInst]
34+
| [typeof SaxEventType.Declaration, Text]
35+
| [typeof SaxEventType.Doctype, Text]
36+
| [typeof SaxEventType.Comment, Text]
37+
| [typeof SaxEventType.OpenTagStart, Tag]
38+
| [typeof SaxEventType.Attribute, Attribute]
39+
| [typeof SaxEventType.OpenTag, Tag]
40+
| [typeof SaxEventType.CloseTag, Tag]
41+
| [typeof SaxEventType.Cdata, Text]
42+
3943
export type AttributeDetail = {
4044
readonly type: 0 | 1;
4145
readonly name: TextDetail;
@@ -488,7 +492,7 @@ export class SAXParser {
488492
public events?: number;
489493
public wasmSaxParser?: WasmSaxParser;
490494

491-
public eventHandler?: (type: SaxEventType, detail: Reader<Detail>) => void;
495+
public eventHandler?: <T extends SaxEvent>(type: T[0], detail: T[1]) => void;
492496

493497
private createDetailConstructor<T extends { new(...args: unknown[]): {}; LENGTH: number }>(Constructor: T) {
494498
return (memoryBuffer: ArrayBuffer, ptr: number): Reader<Detail> => {
@@ -579,10 +583,10 @@ export class SAXParser {
579583
* })();
580584
* ```
581585
*/
582-
public async *parse(reader: ReadableStreamDefaultReader<Uint8Array>): AsyncGenerator<[SaxEventType, Reader<Detail>]> {
583-
let eventAggregator: [SaxEventType, Reader<Detail>][] | null = [];
584-
this.eventHandler = function (event, detail) {
585-
eventAggregator.push([event, detail]);
586+
public async *parse(reader: ReadableStreamDefaultReader<Uint8Array>): AsyncGenerator<SaxEvent> {
587+
let eventAggregator: SaxEvent[] = [];
588+
this.eventHandler = function <T extends SaxEvent> (event:T[0], detail:T[1]) {
589+
eventAggregator.push([event, detail] as T);
586590
};
587591

588592
while (true) {
@@ -747,16 +751,16 @@ export class SAXParser {
747751
throw new Error(`Failed to instantiate the parser.`);
748752
}
749753

750-
public eventTrap = (event: number, ptr: number): void => {
754+
public eventTrap = (event: SaxEventType, ptr: number): void => {
751755
if (!this.wasmSaxParser || !this.eventHandler) {
752756
return;
753757
}
754758
const memoryBuffer = this.wasmSaxParser.memory.buffer;
755-
let detail: Reader<Detail>;
759+
let detail: Attribute | Text | Tag | ProcInst;
756760

757761
const constructor = this.eventToDetailConstructor.get(event);
758762
if (constructor) {
759-
detail = constructor(memoryBuffer, ptr);
763+
detail = constructor(memoryBuffer, ptr) as Attribute | Text | Tag | ProcInst
760764
} else {
761765
throw new Error("No reader for this event type");
762766
}

0 commit comments

Comments
 (0)