+15
-9
@@ -232,11 +232,17 @@ 'use strict'; | ||
| async prepareWasm(saxWasm) { | ||
| const result = await WebAssembly.instantiate(saxWasm, { | ||
| env: { | ||
| memoryBase: 0, | ||
| tableBase: 0, | ||
| memory: new WebAssembly.Memory({ initial: 10 }), | ||
| table: new WebAssembly.Table({ initial: 1, element: 'anyfunc' }), | ||
| event_listener: this.eventTrap | ||
| } | ||
| }); | ||
| let result; | ||
| if (saxWasm instanceof Uint8Array) { | ||
| result = await WebAssembly.instantiate(saxWasm, { | ||
| env: { | ||
| memoryBase: 0, | ||
| tableBase: 0, | ||
| memory: new WebAssembly.Memory({ initial: 10 }), | ||
| table: new WebAssembly.Table({ initial: 1, element: 'anyfunc' }), | ||
| event_listener: this.eventTrap | ||
| } | ||
| }); | ||
| } | ||
| else { | ||
| result = await WebAssembly.instantiateStreaming(saxWasm); | ||
| } | ||
| if (result && typeof this.events === 'number') { | ||
@@ -243,0 +249,0 @@ const { parser } = this.wasmSaxParser = result.instance.exports; |
+15
-9
@@ -228,11 +228,17 @@ class SaxEventType { | ||
| async prepareWasm(saxWasm) { | ||
| const result = await WebAssembly.instantiate(saxWasm, { | ||
| env: { | ||
| memoryBase: 0, | ||
| tableBase: 0, | ||
| memory: new WebAssembly.Memory({ initial: 10 }), | ||
| table: new WebAssembly.Table({ initial: 1, element: 'anyfunc' }), | ||
| event_listener: this.eventTrap | ||
| } | ||
| }); | ||
| let result; | ||
| if (saxWasm instanceof Uint8Array) { | ||
| result = await WebAssembly.instantiate(saxWasm, { | ||
| env: { | ||
| memoryBase: 0, | ||
| tableBase: 0, | ||
| memory: new WebAssembly.Memory({ initial: 10 }), | ||
| table: new WebAssembly.Table({ initial: 1, element: 'anyfunc' }), | ||
| event_listener: this.eventTrap | ||
| } | ||
| }); | ||
| } | ||
| else { | ||
| result = await WebAssembly.instantiateStreaming(saxWasm); | ||
| } | ||
| if (result && typeof this.events === 'number') { | ||
@@ -239,0 +245,0 @@ const { parser } = this.wasmSaxParser = result.instance.exports; |
@@ -13,3 +13,3 @@ export declare class SaxEventType { | ||
| } | ||
| export declare type Detail = Position | Attribute | Text | Tag | ProcInst; | ||
| export type Detail = Position | Attribute | Text | Tag | ProcInst; | ||
| export declare abstract class Reader<T = Detail> { | ||
@@ -88,3 +88,3 @@ protected data: Uint8Array; | ||
| } | ||
| declare type TextDecoder = { | ||
| type TextDecoder = { | ||
| decode: (input?: ArrayBufferView | ArrayBuffer, options?: { | ||
@@ -104,2 +104,3 @@ stream?: boolean; | ||
| end(): void; | ||
| prepareWasm(source: Response | Promise<Response>): Promise<boolean>; | ||
| prepareWasm(saxWasm: Uint8Array): Promise<boolean>; | ||
@@ -106,0 +107,0 @@ eventTrap: (event: number, ptr: number, len: number) => void; |
+3
-2
@@ -13,3 +13,3 @@ export declare class SaxEventType { | ||
| } | ||
| export declare type Detail = Position | Attribute | Text | Tag | ProcInst; | ||
| export type Detail = Position | Attribute | Text | Tag | ProcInst; | ||
| export declare abstract class Reader<T = Detail> { | ||
@@ -88,3 +88,3 @@ protected data: Uint8Array; | ||
| } | ||
| declare type TextDecoder = { | ||
| type TextDecoder = { | ||
| decode: (input?: ArrayBufferView | ArrayBuffer, options?: { | ||
@@ -104,2 +104,3 @@ stream?: boolean; | ||
| end(): void; | ||
| prepareWasm(source: Response | Promise<Response>): Promise<boolean>; | ||
| prepareWasm(saxWasm: Uint8Array): Promise<boolean>; | ||
@@ -106,0 +107,0 @@ eventTrap: (event: number, ptr: number, len: number) => void; |
+15
-9
@@ -234,11 +234,17 @@ (function (global, factory) { | ||
| async prepareWasm(saxWasm) { | ||
| const result = await WebAssembly.instantiate(saxWasm, { | ||
| env: { | ||
| memoryBase: 0, | ||
| tableBase: 0, | ||
| memory: new WebAssembly.Memory({ initial: 10 }), | ||
| table: new WebAssembly.Table({ initial: 1, element: 'anyfunc' }), | ||
| event_listener: this.eventTrap | ||
| } | ||
| }); | ||
| let result; | ||
| if (saxWasm instanceof Uint8Array) { | ||
| result = await WebAssembly.instantiate(saxWasm, { | ||
| env: { | ||
| memoryBase: 0, | ||
| tableBase: 0, | ||
| memory: new WebAssembly.Memory({ initial: 10 }), | ||
| table: new WebAssembly.Table({ initial: 1, element: 'anyfunc' }), | ||
| event_listener: this.eventTrap | ||
| } | ||
| }); | ||
| } | ||
| else { | ||
| result = await WebAssembly.instantiateStreaming(saxWasm); | ||
| } | ||
| if (result && typeof this.events === 'number') { | ||
@@ -245,0 +251,0 @@ const { parser } = this.wasmSaxParser = result.instance.exports; |
@@ -13,3 +13,3 @@ export declare class SaxEventType { | ||
| } | ||
| export declare type Detail = Position | Attribute | Text | Tag | ProcInst; | ||
| export type Detail = Position | Attribute | Text | Tag | ProcInst; | ||
| export declare abstract class Reader<T = Detail> { | ||
@@ -88,3 +88,3 @@ protected data: Uint8Array; | ||
| } | ||
| declare type TextDecoder = { | ||
| type TextDecoder = { | ||
| decode: (input?: ArrayBufferView | ArrayBuffer, options?: { | ||
@@ -104,2 +104,3 @@ stream?: boolean; | ||
| end(): void; | ||
| prepareWasm(source: Response | Promise<Response>): Promise<boolean>; | ||
| prepareWasm(saxWasm: Uint8Array): Promise<boolean>; | ||
@@ -106,0 +107,0 @@ eventTrap: (event: number, ptr: number, len: number) => void; |
+4
-5
| { | ||
| "name": "sax-wasm", | ||
| "version": "2.2.3", | ||
| "version": "2.2.4", | ||
| "repository": "https://github.com/justinwilaby/sax-wasm", | ||
@@ -43,4 +43,3 @@ "description": "An extremely fast JSX, HTML and XML parser written in Rust compiled to WebAssembly for Node and the Web", | ||
| "libxmljs": "^0.19.7", | ||
| "ltx": "^2.9.2", | ||
| "node-expat": "^2.4.0", | ||
| "ltx": "^3.0.0", | ||
| "node-xml": "^1.0.2", | ||
@@ -50,5 +49,5 @@ "rollup": "^2.75.3", | ||
| "ts-jest": "^28.0.2", | ||
| "ts-node": "9.0.0", | ||
| "typescript": "^4.6.4" | ||
| "ts-node": "^10.9.1", | ||
| "typescript": "^5.1.6" | ||
| } | ||
| } |
+19
-19
@@ -18,3 +18,3 @@ # SAX (Simple API for XML) for WebAssembly | ||
| ## Benchmarks (Node v16.14.0 / 2.7 GHz Quad-Core Intel Core i7) | ||
| ## Benchmarks (Node v18.16.1 / 2.7 GHz Quad-Core Intel Core i7) | ||
| All parsers are tested using a large XML document (2.1 MB) containing a variety of elements and is streamed when supported | ||
@@ -29,3 +29,2 @@ by the parser. This attempts to recreate the best real-world use case for parsing XML. Other libraries test benchmarks using a | ||
| | [sax-js](https://github.com/isaacs/sax-js) | 155.77 | ☑ | ☑* | | ||
| | [node-expat](https://github.com/node-xmpp/node-expat) | 234.78 | ☐ | ☐ | | ||
| | [libxmljs](https://github.com/polotek/libxmljs) | 274.95 | ☐ | ☐ | | ||
@@ -73,3 +72,6 @@ | [node-xml](https://github.com/dylang/node-xml) | 685.00 | ☑ | ☐ | | ||
| ## Usage for the web | ||
| 1. Instantiate and prepare the wasm for parsing | ||
| 2. Pipe the document stream to sax-wasm using [ReadableStream.getReader()](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/getReader) | ||
| **NOTE** This uses [WebAssembly.instantiateStreaming](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiateStreaming) | ||
| under the hood to load the wasm. | ||
| ```js | ||
@@ -79,8 +81,6 @@ import { SaxEventType, SAXParser } from 'sax-wasm'; | ||
| async function loadAndPrepareWasm() { | ||
| const saxWasmResponse = await fetch('./path/to/wasm/sax-wasm.wasm'); | ||
| const saxWasmbuffer = await saxWasmResponse.arrayBuffer(); | ||
| const parser = new SAXParser(SaxEventType.Attribute | SaxEventType.OpenTag, {highWaterMark: 64 * 1024}); // 64k chunks | ||
| // Instantiate and prepare the wasm for parsing | ||
| const ready = await parser.prepareWasm(new Uint8Array(saxWasmbuffer)); | ||
| const saxWasmResponse = fetch('./path/to/wasm/sax-wasm.wasm'); | ||
| const ready = await parser.prepareWasm(saxWasmResponse); | ||
| if (ready) { | ||
@@ -145,14 +145,14 @@ return parser; | ||
| |Event |Mask |Argument passed to handler | | ||
| |----------------------------------|--------------|------------------------------------------------| | ||
| |SaxEventType.Text |0b000000000001|text: [Text](src/js/saxWasm.ts#L106) | | ||
| |SaxEventType.ProcessingInstruction|0b000000000010|procInst: [Text](src/js/saxWasm.ts#L106) | | ||
| |SaxEventType.SGMLDeclaration |0b000000000100|sgmlDecl: [Text](src/js/saxWasm.ts#L106) | | ||
| |SaxEventType.Doctype |0b000000001000|doctype: [Text](src/js/saxWasm.ts#L106) | | ||
| |SaxEventType.Comment |0b000000010000|comment: [Text](src/js/saxWasm.ts#L106) | | ||
| |SaxEventType.OpenTagStart |0b000000100000|tag: [Tag](src/js/saxWasm.ts#L133) | | ||
| |SaxEventType.Attribute |0b000001000000|attribute: [Attribute](src/js/saxWasm.ts#L49) | | ||
| |SaxEventType.OpenTag |0b000010000000|tag: [Tag](src/js/saxWasm.ts#L133) | | ||
| |SaxEventType.CloseTag |0b000100000000|tag: [Tag](src/js/saxWasm.ts#L133) | | ||
| |SaxEventType.CDATA |0b001000000000|start: [Position](src/js/saxWasm.ts#L39) | | ||
| |Event |Mask | Argument passed to handler | | ||
| |----------------------------------|--------------|-----------------------------------------------| | ||
| |SaxEventType.Text |0b000000000001| text: [Text](src/js/saxWasm.ts#L114) | | ||
| |SaxEventType.ProcessingInstruction|0b000000000010| procInst: [Text](src/js/saxWasm.ts#L114) | | ||
| |SaxEventType.SGMLDeclaration |0b000000000100| sgmlDecl: [Text](src/js/saxWasm.ts#L114) | | ||
| |SaxEventType.Doctype |0b000000001000| doctype: [Text](src/js/saxWasm.ts#L114) | | ||
| |SaxEventType.Comment |0b000000010000| comment: [Text](src/js/saxWasm.ts#L114) | | ||
| |SaxEventType.OpenTagStart |0b000000100000| tag: [Tag](src/js/saxWasm.ts#L141) | | ||
| |SaxEventType.Attribute |0b000001000000| attribute: [Attribute](src/js/saxWasm.ts#L59) | | ||
| |SaxEventType.OpenTag |0b000010000000| tag: [Tag](src/js/saxWasm.ts#L141) | | ||
| |SaxEventType.CloseTag |0b000100000000| tag: [Tag](src/js/saxWasm.ts#L141) | | ||
| |SaxEventType.CDATA |0b001000000000| start: [Position](src/js/saxWasm.ts#L39) | | ||
@@ -159,0 +159,0 @@ ## Speeding things up on large documents |
90523
0.95%19
-5%1238
1.73%