@lowlighter/xml 5.2.1 → 5.3.0

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/stringify.ts ADDED
@@ -0,0 +1,241 @@
1
+ // Imports
2
+ import type { Nullable, record, rw } from "@libs/typing"
3
+ import type { xml_document, xml_node, xml_text } from "./_types.ts"
4
+
5
+ // Re-exports
6
+ export type { xml_document, xml_node, xml_text }
7
+
8
+ /** XML stringifier options. */
9
+ export type options = {
10
+ /** Format options. */
11
+ format?: {
12
+ /**
13
+ * Indent string (defaults to `" "`).
14
+ * Set to empty string to disable indentation and enable minification.
15
+ */
16
+ indent?: string
17
+ /** Break text node if its length is greater than this value (defaults to `128`). */
18
+ breakline?: number
19
+ }
20
+ /** Replace options. */
21
+ replace?: {
22
+ /**
23
+ * Force escape all XML entities.
24
+ * By default, only the ones that would break the XML structure are escaped.
25
+ */
26
+ entities?: boolean
27
+ /**
28
+ * Custom replacer (this is applied after other revivals).
29
+ * When it is applied on an attribute, `key` and `value` will be given.
30
+ * When it is applied on a node, both `key` and `value` will be `null`.
31
+ * Return `undefined` to delete either the attribute or the tag.
32
+ */
33
+ custom?: (args: { name: string; key: Nullable<string>; value: Nullable<string>; node: Readonly<xml_node> }) => unknown
34
+ }
35
+ }
36
+
37
+ /** XML stringifier options (with non-nullable format options). */
38
+ type _options = options & { format: NonNullable<options["format"]> }
39
+
40
+ //* - `readonly ["~children"]: Array<xml_node|xml_text>`: node children
41
+
42
+ /**
43
+ * Stringify an {@link xml_document} object into a XML string.
44
+ *
45
+ * Output can be customized using the {@link options} parameter.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { stringify } from "./stringify.ts"
50
+ *
51
+ * console.log(stringify({
52
+ * root: {
53
+ * text: "hello",
54
+ * array: ["world", "monde", "世界", "🌏"],
55
+ * number: 42,
56
+ * boolean: true,
57
+ * complex: {
58
+ * "@attribute": "value",
59
+ * "#text": "content",
60
+ * },
61
+ * }
62
+ * }))
63
+ * ```
64
+ */
65
+ export function stringify(document: Partial<xml_document>, options?: options): string {
66
+ options ??= {}
67
+ options.format ??= {}
68
+ options.format.indent ??= " "
69
+ options.format.breakline ??= 128
70
+ const _options = options as _options
71
+ let text = ""
72
+ // Add prolog
73
+ text += xml_prolog(document as xml_document, _options)
74
+ // Add processing instructions
75
+ if (document["#instructions"]) {
76
+ for (const nodes of Object.values(document["#instructions"])) {
77
+ for (const node of [nodes].flat()) {
78
+ text += xml_instruction(node, _options)
79
+ }
80
+ }
81
+ }
82
+ // Add doctype
83
+ if (document["#doctype"]) {
84
+ text += xml_doctype(document["#doctype"] as xml_node, _options)
85
+ }
86
+
87
+ // Add root node
88
+ const [root, ...garbage] = xml_children(document as xml_document, _options)
89
+ if (garbage.length) {
90
+ throw new SyntaxError("Multiple root node detected")
91
+ }
92
+ text += xml_node(root, { ..._options, depth: 0 })
93
+
94
+ return text.trim()
95
+ }
96
+
97
+ /** Create XML prolog. */
98
+ function xml_prolog(document: xml_document, options: _options): string {
99
+ ;(document as rw)["~name"] ??= "xml"
100
+ return xml_instruction(document, options)
101
+ }
102
+
103
+ /** Create XML instruction. */
104
+ function xml_instruction(node: xml_node, { format: { indent } }: _options): string {
105
+ let text = ""
106
+ const attributes = xml_attributes(node as xml_node, arguments[1])
107
+ if (attributes.length) {
108
+ text += `<?${node["~name"].replace(/^~/, "")}`
109
+ for (const [name, value] of attributes) {
110
+ text += ` ${name}="${value}"`
111
+ }
112
+ text += `?>${indent ? "\n" : ""}`
113
+ }
114
+ return text
115
+ }
116
+
117
+ /** Create XML doctype. */
118
+ function xml_doctype(node: xml_node, { format: { indent } }: _options): string {
119
+ let text = ""
120
+ const attributes = xml_attributes(node, arguments[1])
121
+ const elements = xml_children(node, arguments[1])
122
+ if (attributes.length + elements.length) {
123
+ text += `<!DOCTYPE`
124
+ for (const [name] of attributes) {
125
+ text += ` ${!/^[A-Za-z0-9_]+$/.test(name) ? `"${name}"` : name}`
126
+ }
127
+ if (elements.length) {
128
+ text += `${indent ? `\n${indent}` : " "}[${indent ? "\n" : ""}`
129
+ for (const element of elements) {
130
+ text += `${indent}<!ELEMENT ${element["~name"]} (${element["#text"]})>${indent ? "\n" : ""}`
131
+ }
132
+ text += `${indent ? indent : ""}]${indent ? "\n" : ""}`
133
+ }
134
+ text += `>${indent ? "\n" : ""}`
135
+ }
136
+ return text
137
+ }
138
+
139
+ /** Create XML node. */
140
+ function xml_node(node: xml_node, { format: { breakline = 0, indent = "" }, replace, depth = 0 }: _options & { depth?: number }): string {
141
+ if (replace?.custom) {
142
+ if (replace.custom({ name: node["~name"], key: null, value: null, node }) === undefined) {
143
+ return ""
144
+ }
145
+ }
146
+ let text = `${indent.repeat(depth)}<${node["~name"]}`
147
+ const attributes = xml_attributes(node, arguments[1])
148
+ const children = xml_children(node, arguments[1])
149
+ const preserve = node["@xml:space"] === "preserve"
150
+ for (const [name, value] of attributes) {
151
+ text += ` ${name}="${value}"`
152
+ }
153
+ if ((children.length) || (("#text" in node) && (node["#text"].length))) {
154
+ const inline = indent && (!preserve) && ((children.length) || (node["#text"].length > breakline - indent.length * depth))
155
+ text += `>${indent && (!preserve) && (children.length) ? "\n" : ""}`
156
+ if ("#text" in node) {
157
+ if (inline) {
158
+ text += `\n${indent.repeat(depth + 1)}`
159
+ }
160
+ text += node["#text"]
161
+ if (inline) {
162
+ text += "\n"
163
+ }
164
+ }
165
+ for (const child of children) {
166
+ text += xml_node(child, { ...arguments[1], depth: depth + 1 })
167
+ }
168
+ if (inline) {
169
+ text += indent.repeat(depth)
170
+ }
171
+ text += `</${node["~name"]}>${indent ? "\n" : ""}`
172
+ } else {
173
+ text += `/>${indent ? "\n" : ""}`
174
+ }
175
+ return text
176
+ }
177
+
178
+ /** Extract children from node. */
179
+ function xml_children(node: xml_node, options: options): Array<xml_node> {
180
+ const children = Object.keys(node)
181
+ .filter((key) => /^[A-Za-z_]/.test(key))
182
+ .flatMap((key) =>
183
+ [node![key]].flat().map((value) => {
184
+ switch (true) {
185
+ case value === null:
186
+ return ({ ["~name"]: key, ["#text"]: "" })
187
+ case typeof value === "object":
188
+ return ({ ["~name"]: key, ...value as record })
189
+ default:
190
+ return ({ ["~name"]: key, ["#text"]: `${value}` })
191
+ }
192
+ })
193
+ )
194
+ .map((node) => {
195
+ if ("#text" in node) {
196
+ node["#text"] = replace(node as xml_node, "#text", { ...options, escape: ["<", ">"] }) as string
197
+ if (node["#text"] === undefined) {
198
+ delete node["#text"]
199
+ } else {
200
+ node["#text"] = `${node["#text"]}`
201
+ }
202
+ }
203
+ return node
204
+ }) as ReturnType<typeof xml_children>
205
+ //TODO(@lowlighter): Eventually add node["~children"] support for ordering and possibly bypass the children search
206
+ return children
207
+ }
208
+
209
+ /** Extract attributes from node. */
210
+ function xml_attributes(node: xml_node, options: options): Array<[string, string]> {
211
+ return Object.entries(node!)
212
+ .filter(([key]) => key.startsWith("@"))
213
+ .map(([key]) => [key.slice(1), replace(node!, key, { ...options, escape: ['"', "'"] })])
214
+ .filter(([_, value]) => value !== undefined) as ReturnType<typeof xml_attributes>
215
+ }
216
+
217
+ /** Entities */
218
+ const entities = {
219
+ "&": "&amp;", //Keep first
220
+ '"': "&quot;",
221
+ "<": "&lt;",
222
+ ">": "&gt;",
223
+ "'": "&apos;",
224
+ } as const
225
+
226
+ /** Replace value. */
227
+ function replace(node: xml_node | xml_text, key: string, options: options & { escape?: Array<keyof typeof entities> }) {
228
+ let value = `${(node as xml_node)[key]}` as string
229
+ if (options?.escape) {
230
+ if (options?.replace?.entities) {
231
+ options.escape = Object.keys(entities) as Array<keyof typeof entities>
232
+ }
233
+ for (const char of options?.escape) {
234
+ value = `${value}`.replaceAll(char, entities[char])
235
+ }
236
+ }
237
+ if (options?.replace?.custom) {
238
+ return options.replace.custom({ name: node["~name"], key, value, node: node as xml_node })
239
+ }
240
+ return value
241
+ }
@@ -0,0 +1,284 @@
1
+ import { type options as parse_options, parse } from "./parse.ts"
2
+ import { type options as stringify_options, stringify } from "./stringify.ts"
3
+ import { expect, test } from "@libs/testing"
4
+
5
+ // This operation ensure that reforming a parsed XML will still yield same data
6
+ const check = (xml: string, options?: parse_options & stringify_options) => {
7
+ expect(stringify(parse(xml, options), options), xml)
8
+ return parse(stringify(parse(xml, options), options), options)
9
+ }
10
+
11
+ test("all")("stringify(): xml syntax xml prolog", () =>
12
+ expect(
13
+ check(
14
+ `<?xml version="1.0" encoding="UTF-8"?>
15
+ <root/>`,
16
+ ),
17
+ ).toEqual(
18
+ {
19
+ "@version": "1.0",
20
+ "@encoding": "UTF-8",
21
+ root: null,
22
+ },
23
+ ))
24
+
25
+ test("all")("stringify(): xml syntax xml stylesheet", () =>
26
+ expect(
27
+ check(
28
+ `<?xml version="1.0" encoding="UTF-8"?>
29
+ <?xml-stylesheet href="styles.xsl" type="text/xsl"?>
30
+ <root/>`,
31
+ ),
32
+ ).toEqual(
33
+ {
34
+ "@version": "1.0",
35
+ "@encoding": "UTF-8",
36
+ "#instructions": {
37
+ "xml-stylesheet": {
38
+ "@href": "styles.xsl",
39
+ "@type": "text/xsl",
40
+ },
41
+ },
42
+ root: null,
43
+ },
44
+ ))
45
+
46
+ test("all")("stringify(): xml syntax doctype", () =>
47
+ expect(
48
+ check(
49
+ `<!DOCTYPE type "quoted attribute" [
50
+ <!ELEMENT element (value)>
51
+ ]>
52
+ <root/>`,
53
+ ),
54
+ ).toEqual(
55
+ {
56
+ "#doctype": {
57
+ "@type": "",
58
+ "@quoted attribute": "",
59
+ element: "value",
60
+ },
61
+ root: null,
62
+ },
63
+ ))
64
+
65
+ for (const indent of [" ", ""]) {
66
+ test("all")(`stringify(): xml example w3schools.com#3 (indent = "${indent}")`, () =>
67
+ expect(
68
+ check(
69
+ `
70
+ <?xml version="1.0" encoding="UTF-8"?>
71
+ <?xml-stylesheet href="styles.xsl" type="text/xsl"?>
72
+ <!DOCTYPE type "quoted attribute" [
73
+ <!ELEMENT element (value)>
74
+ ]>
75
+ <bookstore>
76
+ <notebook/>
77
+ <book category="cooking">
78
+ <!-- Comment Node -->
79
+ <title lang="en">Everyday Italian</title>
80
+ <author>Giada De Laurentiis</author>
81
+ <year>2005</year>
82
+ <price>30</price>
83
+ </book>
84
+ <book category="children">
85
+ <!-- First Comment Node -->
86
+ <!-- Second Comment Node -->
87
+ <title lang="en">Harry Potter</title>
88
+ <author>J K. Rowling</author>
89
+ <year>2005</year>
90
+ <price>29.99</price>
91
+ </book>
92
+ <book category="web">
93
+ <title lang="en">XQuery Kick Start</title>
94
+ <author>James McGovern</author>
95
+ <author>Per Bothner</author>
96
+ <author>Kurt Cagle</author>
97
+ <author>James Linn</author>
98
+ <author>Vaidyanathan Nagarajan</author>
99
+ <year>2003</year>
100
+ <price>49.99</price>
101
+ </book>
102
+ <book category="web" cover="paperback">
103
+ <title lang="en">Learning XML</title>
104
+ <author>Erik T. Ray</author>
105
+ <year>2003</year>
106
+ <price>39.95</price>
107
+ </book>
108
+ </bookstore>`,
109
+ { revive: { booleans: true, numbers: true }, format: { indent } },
110
+ ),
111
+ ).toEqual(
112
+ {
113
+ "@version": "1.0",
114
+ "@encoding": "UTF-8",
115
+ "#instructions": {
116
+ "xml-stylesheet": {
117
+ "@href": "styles.xsl",
118
+ "@type": "text/xsl",
119
+ },
120
+ },
121
+ "#doctype": {
122
+ "@type": "",
123
+ "@quoted attribute": "",
124
+ element: "value",
125
+ },
126
+ bookstore: {
127
+ notebook: null,
128
+ book: [
129
+ {
130
+ "@category": "cooking",
131
+ title: { "@lang": "en", "#text": "Everyday Italian" },
132
+ author: "Giada De Laurentiis",
133
+ year: 2005,
134
+ price: 30,
135
+ },
136
+ {
137
+ "@category": "children",
138
+ title: { "@lang": "en", "#text": "Harry Potter" },
139
+ author: "J K. Rowling",
140
+ year: 2005,
141
+ price: 29.99,
142
+ },
143
+ {
144
+ "@category": "web",
145
+ title: { "@lang": "en", "#text": "XQuery Kick Start" },
146
+ author: [
147
+ "James McGovern",
148
+ "Per Bothner",
149
+ "Kurt Cagle",
150
+ "James Linn",
151
+ "Vaidyanathan Nagarajan",
152
+ ],
153
+ year: 2003,
154
+ price: 49.99,
155
+ },
156
+ {
157
+ "@category": "web",
158
+ "@cover": "paperback",
159
+ title: { "@lang": "en", "#text": "Learning XML" },
160
+ author: "Erik T. Ray",
161
+ year: 2003,
162
+ price: 39.95,
163
+ },
164
+ ],
165
+ },
166
+ },
167
+ ))
168
+ }
169
+
170
+ test("all")("stringify(): xml types", () =>
171
+ expect(
172
+ check(
173
+ `<types>
174
+ <boolean>true</boolean>
175
+ <null/>
176
+ <string>hello</string>
177
+ </types>`,
178
+ { revive: { booleans: true } },
179
+ ),
180
+ ).toEqual(
181
+ {
182
+ types: {
183
+ boolean: true,
184
+ null: null,
185
+ string: "hello",
186
+ },
187
+ },
188
+ ))
189
+
190
+ test("all")("stringify(): xml entities", () =>
191
+ expect(
192
+ check(`<string>&quot; &lt; &gt; &amp; &apos;</string>`),
193
+ ).toEqual(
194
+ {
195
+ string: `" < > & '`,
196
+ },
197
+ ))
198
+
199
+ test("all")(
200
+ "stringify(): xml entities are escaped only where needed",
201
+ () =>
202
+ expect(stringify({
203
+ root: {
204
+ "@attribute": `<text with escaped quotes (',")>`,
205
+ text: `only < and > should be escaped, not &, ", '`,
206
+ },
207
+ }, { format: { breakline: 0 } })).toEqual(
208
+ `
209
+ <root attribute="<text with escaped quotes (&apos;,&quot;)>">
210
+ <text>
211
+ only &lt; and &gt; should be escaped, not &, ", '
212
+ </text>
213
+ </root>`.trim(),
214
+ ),
215
+ )
216
+
217
+ test("all")(
218
+ "stringify(): xml entiries are always escaped when escapeAllEntities is true",
219
+ () =>
220
+ expect(stringify({
221
+ root: {
222
+ "@attribute": `< > &, ", '`,
223
+ text: `< > &, ", '`,
224
+ },
225
+ }, { replace: { entities: true }, format: { breakline: 0 } })).toEqual(
226
+ `
227
+ <root attribute="&lt; &gt; &amp;, &quot;, &apos;">
228
+ <text>
229
+ &lt; &gt; &amp;, &quot;, &apos;
230
+ </text>
231
+ </root>`.trim(),
232
+ ),
233
+ )
234
+
235
+ test("all")("stringify(): xml space preserve", () =>
236
+ expect(
237
+ check(`<text xml:space="preserve"> hello world </text>`),
238
+ ).toEqual(
239
+ {
240
+ text: {
241
+ "#text": " hello world ",
242
+ "@xml:space": "preserve",
243
+ },
244
+ },
245
+ ))
246
+
247
+ test("all")("stringify(): cdata is preserved", () =>
248
+ expect(
249
+ check(`<string><![CDATA[hello <world>]]></string>`),
250
+ ).toEqual(
251
+ {
252
+ string: `hello <world>`,
253
+ },
254
+ ))
255
+
256
+ // Custom replacer
257
+
258
+ test("all")("stringify(): xml replacer", () =>
259
+ expect(
260
+ stringify({ root: { not: true, yes: true, delete: true, attribute: { "@delete": true } } }, {
261
+ replace: {
262
+ custom: ({ name, key, value }) => {
263
+ if ((name === "delete") || (key === "@delete")) {
264
+ return undefined
265
+ }
266
+ if ((name === "not") && (key === "#text")) {
267
+ return !value
268
+ }
269
+ return value
270
+ },
271
+ },
272
+ }),
273
+ ).toBe(
274
+ `
275
+ <root>
276
+ <not>false</not>
277
+ <yes>true</yes>
278
+ <attribute/>
279
+ </root>`.trim(),
280
+ ))
281
+
282
+ //Errors checks
283
+
284
+ test("all")("stringify(): xml syntax unique root", () => expect(() => stringify({ root: null, garbage: null })).toThrow(SyntaxError))
@@ -0,0 +1,159 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 3
4
+
5
+ [[package]]
6
+ name = "bumpalo"
7
+ version = "3.16.0"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
10
+
11
+ [[package]]
12
+ name = "cfg-if"
13
+ version = "1.0.0"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
16
+
17
+ [[package]]
18
+ name = "js-sys"
19
+ version = "0.3.69"
20
+ source = "registry+https://github.com/rust-lang/crates.io-index"
21
+ checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
22
+ dependencies = [
23
+ "wasm-bindgen",
24
+ ]
25
+
26
+ [[package]]
27
+ name = "log"
28
+ version = "0.4.21"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
31
+
32
+ [[package]]
33
+ name = "memchr"
34
+ version = "2.7.2"
35
+ source = "registry+https://github.com/rust-lang/crates.io-index"
36
+ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
37
+
38
+ [[package]]
39
+ name = "once_cell"
40
+ version = "1.19.0"
41
+ source = "registry+https://github.com/rust-lang/crates.io-index"
42
+ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
43
+
44
+ [[package]]
45
+ name = "proc-macro2"
46
+ version = "1.0.82"
47
+ source = "registry+https://github.com/rust-lang/crates.io-index"
48
+ checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
49
+ dependencies = [
50
+ "unicode-ident",
51
+ ]
52
+
53
+ [[package]]
54
+ name = "quick-xml"
55
+ version = "0.31.0"
56
+ source = "registry+https://github.com/rust-lang/crates.io-index"
57
+ checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
58
+ dependencies = [
59
+ "memchr",
60
+ ]
61
+
62
+ [[package]]
63
+ name = "quote"
64
+ version = "1.0.36"
65
+ source = "registry+https://github.com/rust-lang/crates.io-index"
66
+ checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
67
+ dependencies = [
68
+ "proc-macro2",
69
+ ]
70
+
71
+ [[package]]
72
+ name = "syn"
73
+ version = "2.0.64"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
76
+ dependencies = [
77
+ "proc-macro2",
78
+ "quote",
79
+ "unicode-ident",
80
+ ]
81
+
82
+ [[package]]
83
+ name = "unicode-ident"
84
+ version = "1.0.12"
85
+ source = "registry+https://github.com/rust-lang/crates.io-index"
86
+ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
87
+
88
+ [[package]]
89
+ name = "wasm-bindgen"
90
+ version = "0.2.92"
91
+ source = "registry+https://github.com/rust-lang/crates.io-index"
92
+ checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
93
+ dependencies = [
94
+ "cfg-if",
95
+ "wasm-bindgen-macro",
96
+ ]
97
+
98
+ [[package]]
99
+ name = "wasm-bindgen-backend"
100
+ version = "0.2.92"
101
+ source = "registry+https://github.com/rust-lang/crates.io-index"
102
+ checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
103
+ dependencies = [
104
+ "bumpalo",
105
+ "log",
106
+ "once_cell",
107
+ "proc-macro2",
108
+ "quote",
109
+ "syn",
110
+ "wasm-bindgen-shared",
111
+ ]
112
+
113
+ [[package]]
114
+ name = "wasm-bindgen-macro"
115
+ version = "0.2.92"
116
+ source = "registry+https://github.com/rust-lang/crates.io-index"
117
+ checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
118
+ dependencies = [
119
+ "quote",
120
+ "wasm-bindgen-macro-support",
121
+ ]
122
+
123
+ [[package]]
124
+ name = "wasm-bindgen-macro-support"
125
+ version = "0.2.92"
126
+ source = "registry+https://github.com/rust-lang/crates.io-index"
127
+ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
128
+ dependencies = [
129
+ "proc-macro2",
130
+ "quote",
131
+ "syn",
132
+ "wasm-bindgen-backend",
133
+ "wasm-bindgen-shared",
134
+ ]
135
+
136
+ [[package]]
137
+ name = "wasm-bindgen-shared"
138
+ version = "0.2.92"
139
+ source = "registry+https://github.com/rust-lang/crates.io-index"
140
+ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
141
+
142
+ [[package]]
143
+ name = "wasm_xml_parser"
144
+ version = "0.1.0"
145
+ dependencies = [
146
+ "quick-xml",
147
+ "wasm-bindgen",
148
+ "web-sys",
149
+ ]
150
+
151
+ [[package]]
152
+ name = "web-sys"
153
+ version = "0.3.69"
154
+ source = "registry+https://github.com/rust-lang/crates.io-index"
155
+ checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
156
+ dependencies = [
157
+ "js-sys",
158
+ "wasm-bindgen",
159
+ ]
@@ -0,0 +1,16 @@
1
+ [package]
2
+ name = "wasm_xml_parser"
3
+ version = "0.1.0"
4
+ authors = ["lowlighter"]
5
+ edition = "2021"
6
+ description = "WASM XML parser"
7
+ repository = "https://github.com/lowlighter/libs"
8
+ license = "MIT"
9
+
10
+ [dependencies]
11
+ quick-xml = "0.31"
12
+ wasm-bindgen = "0.2"
13
+ web-sys = { version = "0.3" }
14
+
15
+ [lib]
16
+ crate-type = ["cdylib", "rlib"]