@thi.ng/sax 2.2.62 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -41
- package/index.d.ts +36 -0
- package/index.js +28 -6
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
[@thi.ng/transducers](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers)-based,
|
|
36
36
|
[SAX](https://en.wikipedia.org/wiki/Simple_API_for_XML)-like,
|
|
37
37
|
non-validating, [configurable](#parser-options), speedy & tiny XML
|
|
38
|
-
parser (~1.
|
|
38
|
+
parser (~1.4KB brotli).
|
|
39
39
|
|
|
40
40
|
Unlike the classic event-driven approach of SAX, this parser is
|
|
41
41
|
implemented as a transducer function, transforming an XML input into a
|
|
@@ -88,7 +88,7 @@ For Node.js REPL:
|
|
|
88
88
|
const sax = await import("@thi.ng/sax");
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 1.
|
|
91
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 1.65 KB
|
|
92
92
|
|
|
93
93
|
## Dependencies
|
|
94
94
|
|
|
@@ -132,12 +132,12 @@ src=`<?xml version="1.0" encoding="utf-8"?>
|
|
|
132
132
|
<b2 foo="bar" />
|
|
133
133
|
</a>`
|
|
134
134
|
|
|
135
|
-
// sax.parse() returns
|
|
136
|
-
doc = [...tx.iterator(sax.parse(), src)]
|
|
137
|
-
|
|
138
|
-
// ...or returns iterator if input is given
|
|
135
|
+
// sax.parse() returns iterator if input is given
|
|
139
136
|
doc = [...sax.parse(src)]
|
|
140
137
|
|
|
138
|
+
// ...or returns a transducer to be used with thi.ng/transducers
|
|
139
|
+
doc = [...tx.iterator(sax.parse(), src)]
|
|
140
|
+
|
|
141
141
|
// (see description of `type` values and parse options further below)
|
|
142
142
|
|
|
143
143
|
// [ { type: 0,
|
|
@@ -188,11 +188,8 @@ first `<g>` element is complete. This is because the `matchFirst()`
|
|
|
188
188
|
transducer will cause early termination once that element has been
|
|
189
189
|
processed.
|
|
190
190
|
|
|
191
|
-
```ts
|
|
192
|
-
|
|
193
|
-
import * as tx from "@thi.ng/transducers";
|
|
194
|
-
|
|
195
|
-
svg=`
|
|
191
|
+
```ts id:svgdoc
|
|
192
|
+
const svg = `
|
|
196
193
|
<?xml version="1.0"?>
|
|
197
194
|
<svg version="1.1" height="300" width="300" xmlns="http://www.w3.org/2000/svg">
|
|
198
195
|
<g fill="yellow">
|
|
@@ -206,27 +203,37 @@ svg=`
|
|
|
206
203
|
<circle cx="150.00" cy="150.00" r="25.00" />
|
|
207
204
|
</g>
|
|
208
205
|
</svg>`;
|
|
206
|
+
```
|
|
209
207
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
tx.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
)
|
|
208
|
+
```ts tangle:export/readme-parse-svg.ts
|
|
209
|
+
import { parse, Type } from "@thi.ng/sax";
|
|
210
|
+
import * as tx from "@thi.ng/transducers";
|
|
211
|
+
|
|
212
|
+
// using the SVG example doc defined above
|
|
213
|
+
<<svgdoc>>
|
|
214
|
+
|
|
215
|
+
console.log(
|
|
216
|
+
[...tx.iterator(
|
|
217
|
+
tx.comp(
|
|
218
|
+
// transform into parse events (see parser options below)
|
|
219
|
+
parse({ children: true }),
|
|
220
|
+
// match 1st group end
|
|
221
|
+
tx.matchFirst((e) => e.type == Type.ELEM_END && e.tag == "g"),
|
|
222
|
+
// extract group's children
|
|
223
|
+
tx.mapcat((e) => e.children),
|
|
224
|
+
// select circles only
|
|
225
|
+
tx.filter((e) => e.tag == "circle"),
|
|
226
|
+
// transform attributes
|
|
227
|
+
tx.map((e)=> [e.tag, {
|
|
228
|
+
...e.attribs,
|
|
229
|
+
cx: parseFloat(e.attribs.cx),
|
|
230
|
+
cy: parseFloat(e.attribs.cy),
|
|
231
|
+
r: parseFloat(e.attribs.r),
|
|
232
|
+
}])
|
|
233
|
+
),
|
|
234
|
+
svg
|
|
235
|
+
)]
|
|
236
|
+
);
|
|
230
237
|
// [ [ 'circle', { cx: 50, cy: 150, r: 50 } ],
|
|
231
238
|
// [ 'circle', { cx: 250, cy: 150, r: 50 } ],
|
|
232
239
|
// [ 'circle', { cx: 150, cy: 150, fill: 'rgba(0,255,255,0.25)', r: 100, stroke: '#ff0000' } ] ]
|
|
@@ -238,22 +245,25 @@ This example shows how SVG can be parsed into
|
|
|
238
245
|
[@thi.ng/hiccup](https://github.com/thi-ng/umbrella/tree/develop/packages/hiccup)
|
|
239
246
|
format.
|
|
240
247
|
|
|
241
|
-
```ts
|
|
248
|
+
```ts tangle:export/readme-parse-elements.ts
|
|
242
249
|
import { defmulti, DEFAULT } from "@thi.ng/defmulti";
|
|
243
|
-
import { parse } from "@thi.ng/sax";
|
|
250
|
+
import { parse, type ParseElement } from "@thi.ng/sax";
|
|
244
251
|
import * as tx from "@thi.ng/transducers";
|
|
245
252
|
|
|
253
|
+
// using the SVG example doc defined above
|
|
254
|
+
<<svgdoc>>
|
|
255
|
+
|
|
246
256
|
// coerces given attribute IDs into numeric values and
|
|
247
257
|
// keeps all other attribs
|
|
248
|
-
const numericAttribs = (e, ...ids: string[]) =>
|
|
258
|
+
const numericAttribs = (e: ParseElement, ...ids: string[]) =>
|
|
249
259
|
ids.reduce(
|
|
250
260
|
(acc, id) => (acc[id] = parseFloat(e.attribs[id]), acc),
|
|
251
|
-
{ ...e.attribs }
|
|
261
|
+
<Record<string,any>>{ ...e.attribs }
|
|
252
262
|
);
|
|
253
263
|
|
|
254
264
|
// returns iterator of parsed & filtered children of given element
|
|
255
265
|
// (iterator is used to avoid extraneous copying at call sites)
|
|
256
|
-
const parsedChildren = (e) =>
|
|
266
|
+
const parsedChildren = (e: ParseElement) =>
|
|
257
267
|
tx.iterator(
|
|
258
268
|
tx.comp(
|
|
259
269
|
tx.map(parseElement),
|
|
@@ -281,11 +291,13 @@ parseElement.add("svg", (e) =>
|
|
|
281
291
|
// implementation for unhandled elements
|
|
282
292
|
parseElement.add(DEFAULT, () => null);
|
|
283
293
|
|
|
284
|
-
//
|
|
294
|
+
// finally parse & transform results:
|
|
285
295
|
// the `last()` reducer just returns the ultimate value
|
|
286
296
|
// which in this case is the SVG root element's ELEM_END parse event
|
|
287
297
|
// this also contains all children (by default)
|
|
288
|
-
|
|
298
|
+
console.log(
|
|
299
|
+
parseElement(tx.transduce(parse(), tx.last(), svg))
|
|
300
|
+
);
|
|
289
301
|
|
|
290
302
|
// ["svg",
|
|
291
303
|
// {
|
|
@@ -327,14 +339,14 @@ If the parser encounters a syntax error, an error event value incl. a
|
|
|
327
339
|
description and input position will be produced (but no JS error will be
|
|
328
340
|
thrown) and the entire transducer pipeline stopped.
|
|
329
341
|
|
|
330
|
-
```ts
|
|
342
|
+
```ts tangle:export/readme-error-handling.ts
|
|
331
343
|
import { parse } from "@thi.ng/sax";
|
|
332
344
|
import { iterator } from "@thi.ng/transducers";
|
|
333
345
|
|
|
334
|
-
[...iterator(parse(), `a`)]
|
|
346
|
+
console.log([...iterator(parse(), `a`)]);
|
|
335
347
|
// [ { type: 7, body: 'unexpected char: \'a\' @ pos 1' } ]
|
|
336
348
|
|
|
337
|
-
[...iterator(parse(), `<a><b></c></a>`)]
|
|
349
|
+
console.log([...iterator(parse(), `<a><b></c></a>`)]);
|
|
338
350
|
// [ { type: 4, tag: 'a', attribs: {} },
|
|
339
351
|
// { type: 4, tag: 'b', attribs: {} },
|
|
340
352
|
// { type: 7, body: 'unmatched tag: c @ pos 7' } ]
|
package/index.d.ts
CHANGED
|
@@ -84,4 +84,40 @@ export declare enum Type {
|
|
|
84
84
|
export declare function parse(opts?: Partial<ParseOpts>): Transducer<string, ParseEvent>;
|
|
85
85
|
export declare function parse(src: string): IterableIterator<ParseEvent>;
|
|
86
86
|
export declare function parse(opts: Partial<ParseOpts>, src: string): IterableIterator<ParseEvent>;
|
|
87
|
+
/**
|
|
88
|
+
* Convenience helper for certain applications of {@link parse} to produce a
|
|
89
|
+
* tree of the parsed document.
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* This functions always enables the {@link ParseOpts.children} option, only
|
|
93
|
+
* keeps {@link Type.ELEM_END} events and only returns the last one, i.e that of
|
|
94
|
+
* the root element (including all children).
|
|
95
|
+
*
|
|
96
|
+
* Also see {@link parseAsHiccup}.
|
|
97
|
+
*
|
|
98
|
+
* @param src
|
|
99
|
+
* @param opts
|
|
100
|
+
*/
|
|
101
|
+
export declare const parseAsTree: (src: string, opts?: Partial<ParseOpts>) => ParseEvent;
|
|
102
|
+
/**
|
|
103
|
+
* Convenience helper for certain applications of {@link parse} to produce a
|
|
104
|
+
* tree of the parsed document in thi.ng/hiccup format.
|
|
105
|
+
*
|
|
106
|
+
* @remarks
|
|
107
|
+
* Uses {@link parseAsTree} and then transforms result.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts tangle:../export/parse-as-hiccup.ts
|
|
111
|
+
* import { parseAsHiccup } from "@thi.ng/sax";
|
|
112
|
+
*
|
|
113
|
+
* const doc = `<svg><g id="foo"><circle x="0" y="0" r="100"/></g></svg>`;
|
|
114
|
+
*
|
|
115
|
+
* console.log(parseAsHiccup(doc));
|
|
116
|
+
* // ["svg", {}, ["g", { id: "foo" }, ["circle", { x: "0", y: "0", r: "100" }]]]
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @param src
|
|
120
|
+
* @param opts
|
|
121
|
+
*/
|
|
122
|
+
export declare const parseAsHiccup: (src: string, opts?: Partial<ParseOpts>) => [string, IObjectOf<string>, ...any[]];
|
|
87
123
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { NO_OP } from "@thi.ng/api/api";
|
|
2
2
|
import { unescapeEntities } from "@thi.ng/strings/entities";
|
|
3
3
|
import { ESCAPES } from "@thi.ng/strings/escape";
|
|
4
|
+
import { transduce } from "@thi.ng/transducers/transduce";
|
|
5
|
+
import { comp } from "@thi.ng/transducers/comp";
|
|
6
|
+
import { filter } from "@thi.ng/transducers/filter";
|
|
7
|
+
import { last } from "@thi.ng/transducers/last";
|
|
4
8
|
import { fsm } from "@thi.ng/transducers-fsm";
|
|
5
9
|
import { __iter, iterator } from "@thi.ng/transducers/iterator";
|
|
6
10
|
const VOID_TAGS = new Set(
|
|
@@ -61,6 +65,20 @@ function parse(...args) {
|
|
|
61
65
|
terminate: 1 /* ERROR */
|
|
62
66
|
});
|
|
63
67
|
}
|
|
68
|
+
const parseAsTree = (src, opts) => transduce(
|
|
69
|
+
comp(
|
|
70
|
+
parse({ ...opts, children: true }),
|
|
71
|
+
filter((x) => x.type === 5 /* ELEM_END */)
|
|
72
|
+
),
|
|
73
|
+
last(),
|
|
74
|
+
src
|
|
75
|
+
);
|
|
76
|
+
const parseAsHiccup = (src, opts) => __toHiccup(parseAsTree(src, opts));
|
|
77
|
+
const __toHiccup = (root) => [
|
|
78
|
+
root.tag,
|
|
79
|
+
root.attribs ?? {},
|
|
80
|
+
...root.children?.length ? root.children.map(__toHiccup) : root.body ? [root.body] : []
|
|
81
|
+
];
|
|
64
82
|
const __isWS = (x) => {
|
|
65
83
|
const c = x.charCodeAt(0);
|
|
66
84
|
return c === 32 || // space
|
|
@@ -70,12 +88,14 @@ const __isWS = (x) => {
|
|
|
70
88
|
};
|
|
71
89
|
const __isTagChar = (x) => {
|
|
72
90
|
const c = x.charCodeAt(0);
|
|
73
|
-
return c >=
|
|
74
|
-
c >= 97 && c <= 122 || // a-z
|
|
91
|
+
return c >= 97 && c <= 122 || // a-z
|
|
75
92
|
c >= 48 && c <= 57 || // 0-9
|
|
76
|
-
c
|
|
77
|
-
c
|
|
78
|
-
c
|
|
93
|
+
c >= 65 && c <= 90 || // A-Z
|
|
94
|
+
c === 58 || // :
|
|
95
|
+
c === 45 || // -
|
|
96
|
+
c === 95 || // _
|
|
97
|
+
c === 46 || // .
|
|
98
|
+
c === 183 || c >= 192 && c <= 214 || c >= 248 && c <= 767 || c >= 768 && c <= 879 || c >= 880 && c <= 893 || c >= 895 && c <= 8191 || c >= 895 && c <= 8191 || c === 8204 || c === 8205 || c === 8255 || c === 8256 || c >= 8304 && c <= 8591 || c >= 11264 && c <= 12271 || c >= 12289 && c <= 55295 || c >= 63744 && c <= 64975 || c >= 65008 && c <= 65533;
|
|
79
99
|
};
|
|
80
100
|
const __error = (s, body) => {
|
|
81
101
|
s.state = 1 /* ERROR */;
|
|
@@ -411,5 +431,7 @@ const __beginElementBody = (state) => {
|
|
|
411
431
|
export {
|
|
412
432
|
Type,
|
|
413
433
|
VOID_TAGS,
|
|
414
|
-
parse
|
|
434
|
+
parse,
|
|
435
|
+
parseAsHiccup,
|
|
436
|
+
parseAsTree
|
|
415
437
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/sax",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Transducer-based, SAX-like, non-validating, speedy & tiny XML parser",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@thi.ng/api": "^8.12.
|
|
43
|
-
"@thi.ng/strings": "^3.9.
|
|
44
|
-
"@thi.ng/transducers": "^9.6.
|
|
45
|
-
"@thi.ng/transducers-fsm": "^2.2.
|
|
42
|
+
"@thi.ng/api": "^8.12.8",
|
|
43
|
+
"@thi.ng/strings": "^3.9.29",
|
|
44
|
+
"@thi.ng/transducers": "^9.6.17",
|
|
45
|
+
"@thi.ng/transducers-fsm": "^2.2.150"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"esbuild": "^0.
|
|
48
|
+
"esbuild": "^0.27.0",
|
|
49
49
|
"typedoc": "^0.28.14",
|
|
50
50
|
"typescript": "^5.9.3"
|
|
51
51
|
},
|
|
@@ -82,5 +82,5 @@
|
|
|
82
82
|
],
|
|
83
83
|
"year": 2018
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "be6e7657b1e5c54d7d648d1b52888a7297e95a17\n"
|
|
86
86
|
}
|