@lowlighter/xml 5.3.1 → 5.4.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/README.md CHANGED
@@ -21,6 +21,218 @@
21
21
  - Custom `reviver` and `replacer` functions
22
22
  - Metadata stored into non-enumerable properties for advanced usage
23
23
 
24
+ ## 🕊️ Migrating from `4.x.x` to `5.x.x`
25
+
26
+ Starting from version `5.0.0`, this library use a WASM-compiled binding of the [quick-xml](https://github.com/tafia/quick-xml) rust package. It provides better performances while allowing to support more features.
27
+
28
+ ### Internal API changes
29
+
30
+ The `$XML` internal symbol has been replaced by a set of non-enumerable properties:
31
+
32
+ - Parent node can now be accessed through `"~parent"` property (it'll be `null` for the XML document node)
33
+ - Tag name can now be accessed through `"~name"` property
34
+ - Children nodes can now be accessed through `"~children"` property
35
+ - CDATA can now be tested by checking whether a node has a `"~name": "~cdata"` (if flattened, you'll need to check from the parent node using `~children` property)
36
+
37
+ ```xml
38
+ <root>
39
+ <node><![CDATA[hello <world>]]></node>
40
+ </root>
41
+ ```
42
+
43
+ ```diff
44
+ <ref *1> {
45
+ - [$XML]: { cdata: [ "root", "node" ] },
46
+ + "~parent": null,
47
+ + "~name": "~xml",
48
+ root: {
49
+ node: "hello <world>",
50
+ - [$XML]: { name: "root", parent: null },
51
+ + "~parent": [Circular *1],
52
+ + "~name": "root",
53
+ + "~children": [ { "~name": "~cdata", "#text": "hello <world>" } ],
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### XML document changes
59
+
60
+ XML document properties have been moved directly to top-level rather than being stored in `xml` property.
61
+
62
+ Doctype is now stored in `"#doctype"` property, and attributes values are set to `""` rather than `true`.
63
+
64
+ Processing instructions (like XML stylesheets) are now parsed the same way as regular nodes but have been moved into `"#instructions"` property.
65
+
66
+ ```xml
67
+ <?xml version="1.0" encoding="UTF-8"?>
68
+ <?xml-stylesheet href="styles.xsl" type="text/xsl"?>
69
+ <!DOCTYPE attribute>
70
+ <root/>
71
+ ```
72
+
73
+ ```diff
74
+ {
75
+ - xml: {
76
+ - "@version": "1.0",
77
+ - "@encoding": "UTF-8",
78
+ - },
79
+ - "$stylesheets": [ { "@href": "styles.xsl", "@type": "text/xsl" } ]
80
+ - doctype: { "@attribute": true },
81
+ + "@version": "1.0",
82
+ + "@encoding": "UTF-8",
83
+ + "#instructions": {
84
+ + "xml-stylesheet": { "@href": "styles.xsl", "@type": "text/xsl" }
85
+ + },
86
+ + "#doctype": { "@attribute": "" },
87
+ root: null
88
+ }
89
+ ```
90
+
91
+ ### Mixed content support
92
+
93
+ This breaks any existing code that was expecting mixed content to always be a string. Now mixed content nodes will be parsed as usual, and the `#text` property will contain the "inner text" of the node.
94
+
95
+ Note that `#text` is actually a getter that recursively gets the `#text` of children nodes (ignoring comment nodes) so it'll return the inner text regardless of the node depth.
96
+
97
+ ```xml
98
+ <root>some <b>bold</b> text</root>
99
+ ```
100
+
101
+ ```diff
102
+ {
103
+ - root: "some <b>bold</b> text",
104
+ + root: {
105
+ + "#text": "some bold text",
106
+ + b: "bold",
107
+ }
108
+ ```
109
+
110
+ ### Comments
111
+
112
+ Comments have been moved into `"#comments"` property. Note that this property is now always an array, even if there is only one comment.
113
+
114
+ Additionally, you can find comments into the `~children` property by searching for nodes with `"~name": "~comment"`. If you call the `#text` getter on a parent node containing comments, it will return the inner text without comments.
115
+
116
+ ```xml
117
+ <root><!--some comment--></root>
118
+ ```
119
+
120
+ ```diff
121
+ {
122
+ root: {
123
+ - "#comment": "some comment",
124
+ + "#comments": [ "some comment" ],
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### Parsing
130
+
131
+ #### Options
132
+
133
+ Parse options are categorized into 4 groups:
134
+
135
+ - `clean`, which can remove `attributes`, `comments`, xml `doctype` and `instructions` from the output
136
+ - `flatten`, which can flatten nodes with only a `text` node, `empty` ones or transform `attributes` only nodes into objects without the `@` prefix
137
+ - `revive`, which can `trim` content (unless `xml:space="preserve"`), unescape xml `entities`, revive `booleans` and `numbers`
138
+ - You can also provide a `custom` reviver function (applied after other revivals) that will be called on each attribute and node
139
+ - _Note that signature of the reviver function has changed_
140
+ - `mode`, which can be either `xml` or `html`. Choosing the latter will be more permissive than the former.
141
+
142
+ ```diff
143
+ const options = {
144
+ - reviveBooleans: true,
145
+ - reviveNumbers: true,
146
+ - reviver:() => {},
147
+ + revive: { booleans: true, numbers: true, custom: () => {} },
148
+ - emptyToNull: true,
149
+ - flatten: true,
150
+ + flatten: { text: true, empty: true },
151
+ - debug: false,
152
+ - progress: () => null,
153
+ }
154
+ ```
155
+
156
+ Please refer to the [documentation](https://jsr.io/@libs/xml/doc) for more information.
157
+
158
+ #### Parsing streams
159
+
160
+ The `parse()` function supports any `ReaderSync` interface, which means you can pass directly a file reader for example.
161
+
162
+ ```ts
163
+ import { parse } from "./parse.ts"
164
+ parse(await Deno.readTextFile("example.xml"))
165
+ ```
166
+
167
+ ### Stringifying
168
+
169
+ #### Options
170
+
171
+ Stringify options are now categorized into 2 groups:
172
+
173
+ - `format`, which can configure the `indent` string and automatically `breakline` when a text node is too long
174
+ - `replace`, which can forcefully escape xml `entities`
175
+ - You can also provide a `custom` replacer function that will be called on each attribute and node
176
+ - Note that signature of the replacer function has changed
177
+
178
+ ```diff
179
+ const options = {
180
+ - indentSize: 2,
181
+ + format: { indent: " " },
182
+ - escapeAllEntities: true,
183
+ - replacer: () => {},
184
+ + replace: { entities: true, custom: () => {} },
185
+ - nullToEmpty: false,
186
+ - debug: false,
187
+ - progress: () => null,
188
+ }
189
+ ```
190
+
191
+ Please refer to the [documentation](https://jsr.io/@libs/xml/doc) for more information.
192
+
193
+ ### Stringifying content
194
+
195
+ Please refer to the above section about API changes. If you were handling XML properties, using the `$XML` symbol or `#comment`, you'll most likely need to update your code.
196
+
197
+ The library now provides `comment()` and `cdata()` helpers to respectively create comment and CDATA nodes.
198
+
199
+ ```ts
200
+ import { cdata, comment, stringify } from "./stringify.ts"
201
+ stringify({
202
+ "@version": "1.0",
203
+ "@encoding": "UTF-8",
204
+ root: {
205
+ comment: comment("hello world"),
206
+ cdata: cdata("bonjour <le monde>"),
207
+ text: "hello world",
208
+ node: {
209
+ foo: true,
210
+ bar: 42,
211
+ baz: {
212
+ "@attribute": "value",
213
+ },
214
+ },
215
+ },
216
+ })
217
+ ```
218
+
219
+ ```xml
220
+ <?xml version="1.0" encoding="UTF-8"?>
221
+ <root>
222
+ <comment><!--hello world--></comment>
223
+ <cdata><![CDATA[bonjour <le monde>]]></cdata>
224
+ <text>hello world</text>
225
+ <node>
226
+ <foo>true</foo>
227
+ <bar>42</bar>
228
+ <baz attribute="value"/>
229
+ </node>
230
+ </root>
231
+ ```
232
+
233
+ Note that also you can theorethically use internal properties we strongly advise against it currently. Supporting `~children` might be added in the future ([#57](https://github.com/lowlighter/libs/issues/57)) for mixed content support, but its behavior is not defined yet. Setting
234
+ `~name` manually might lead to unexpected behaviors.
235
+
24
236
  ## 📜 License and credits
25
237
 
26
238
  ```
package/_types.ts CHANGED
@@ -25,11 +25,11 @@ export type xml_node = {
25
25
  /** XML document. */
26
26
  export type xml_document = xml_node & {
27
27
  /** XML version. */
28
- ["@version"]?: `1.${number}`
28
+ ["@version"]?: string
29
29
  /** XML character encoding. */
30
30
  ["@encoding"]?: string
31
31
  /** XML standalone. */
32
- ["@standalone"]?: "yes" | "no"
32
+ ["@standalone"]?: string
33
33
  /** XML doctype. */
34
34
  ["#doctype"]?: xml_node
35
35
  /** XML instructions. */
package/deno.jsonc CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "icon": "📃",
3
3
  "name": "@libs/xml",
4
- "version": "5.3.1",
4
+ "version": "5.4.0",
5
5
  "description": "XML parser/stringifier with no dependencies.",
6
6
  "keywords": [
7
7
  "xml",
@@ -9,7 +9,7 @@
9
9
  "stringifier",
10
10
  "esm"
11
11
  ],
12
- "license": "MIT License",
12
+ "license": "MIT",
13
13
  "author": "lowlighter (Simon Lecoq)",
14
14
  "funding": "https://github.com/sponsors/lowlighter",
15
15
  "homepage": "https://github.com/lowlighter/libs",
@@ -26,6 +26,7 @@
26
26
  "url": "git+https://github.com/lowlighter/libs.git"
27
27
  },
28
28
  "npm": true,
29
+ "deno.land/x": true,
29
30
  "exports": {
30
31
  ".": "./mod.ts",
31
32
  "./parse": "./parse.ts",