xml-to-html-converter 0.3.1 → 0.4.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 +98 -74
- package/dist/index.cjs +31 -12
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +29 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,72 +6,49 @@
|
|
|
6
6
|

|
|
7
7
|

|
|
8
8
|
|
|
9
|
-
A zero-dependency Node.js package for converting XML to HTML.
|
|
9
|
+
A zero-dependency Node.js package for converting XML to HTML.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **`minify(xml)`** strips inter-tag whitespace from prettified XML before parsing. Text content is left untouched
|
|
12
|
+
- **`scaffold(xml)`** reads any XML string and returns a nested node tree
|
|
13
|
+
- **`walk(nodes, visitor)`** traverses the full node tree depth-first, visiting every node
|
|
14
|
+
- **`render(nodes)`** converts a node tree to an HTML string. Every XML element becomes a `<div>` with `data-tag` and `data-attrs-*` attributes
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
---
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## Install
|
|
16
19
|
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
name: string;
|
|
20
|
-
value: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface XmlNode {
|
|
24
|
-
role: XmlNodeRole;
|
|
25
|
-
raw: string;
|
|
26
|
-
xmlTag?: string;
|
|
27
|
-
xmlInner?: string;
|
|
28
|
-
xmlAttributes?: XmlAttribute[];
|
|
29
|
-
globalIndex: number;
|
|
30
|
-
localIndex: number;
|
|
31
|
-
children?: XmlNode[];
|
|
32
|
-
malformed?: true;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type XmlNodeRole =
|
|
36
|
-
| "closeTag"
|
|
37
|
-
| "comment"
|
|
38
|
-
| "doctype"
|
|
39
|
-
| "openTag"
|
|
40
|
-
| "processingInstruction"
|
|
41
|
-
| "selfTag"
|
|
42
|
-
| "textLeaf";
|
|
20
|
+
```bash
|
|
21
|
+
npm install xml-to-html-converter
|
|
43
22
|
```
|
|
44
23
|
|
|
45
|
-
This scaffold is the foundation everything else will be built on. No transformation, no HTML output, no opinions about content, just an accurate, traversable representation of what the XML says.
|
|
46
|
-
|
|
47
24
|
---
|
|
48
25
|
|
|
49
|
-
|
|
50
|
-
>
|
|
51
|
-
> `v0.x` is building the scaffold and the first render pass.
|
|
52
|
-
>
|
|
53
|
-
> - **`minify(xml)`** strips inter-tag whitespace from prettified XML before parsing — text content is left untouched
|
|
54
|
-
> - **`scaffold(xml)`** reads any XML string and returns a nested node tree
|
|
55
|
-
> - Every node knows its `role`, its `raw` source string, its `globalIndex` in the document, and its `localIndex` within its parent
|
|
56
|
-
> - Tag nodes (`openTag`, `selfTag`) also carry `xmlTag`, `xmlInner`, and `xmlAttributes` — the parsed tag name, raw attribute string, and structured attribute array
|
|
57
|
-
> - Broken XML is never thrown — malformed nodes are flagged with `malformed: true` in place and the tree is built regardless
|
|
58
|
-
> - **`render(nodes)`** takes the scaffold output and converts it to an HTML string — every XML element becomes a `<div>` with `data-tag` and `data-attrs-*` attributes
|
|
59
|
-
>
|
|
60
|
-
> `v1.0.0` is when this package becomes what it says it is: a full XML-to-HTML converter. Everything before that is the work to get there.
|
|
26
|
+
## Usage
|
|
61
27
|
|
|
62
|
-
|
|
28
|
+
### minify
|
|
63
29
|
|
|
64
|
-
|
|
30
|
+
When your XML comes from a file or an API it is usually indented and line-broken. `minify` strips the whitespace between tags before parsing. Text content is left completely untouched.
|
|
65
31
|
|
|
66
|
-
```
|
|
67
|
-
|
|
32
|
+
```js
|
|
33
|
+
import { minify } from "xml-to-html-converter";
|
|
34
|
+
|
|
35
|
+
const clean = minify(`
|
|
36
|
+
<bookstore>
|
|
37
|
+
<book category="cooking">
|
|
38
|
+
<title lang="en">Everyday Italian</title>
|
|
39
|
+
</book>
|
|
40
|
+
</bookstore>
|
|
41
|
+
`);
|
|
42
|
+
// <bookstore><book category="cooking"><title lang="en">Everyday Italian</title></book></bookstore>
|
|
68
43
|
```
|
|
69
44
|
|
|
45
|
+
`minify` is opt-in. Skip it if whitespace inside your content is meaningful.
|
|
46
|
+
|
|
70
47
|
---
|
|
71
48
|
|
|
72
|
-
|
|
49
|
+
### scaffold
|
|
73
50
|
|
|
74
|
-
|
|
51
|
+
`scaffold` parses an XML string into a structured tree of `XmlNode` objects. Each node carries its role, its raw source text, and its position in the document both globally across the full document and locally within its parent.
|
|
75
52
|
|
|
76
53
|
```js
|
|
77
54
|
import { scaffold } from "xml-to-html-converter";
|
|
@@ -135,7 +112,43 @@ const tree = scaffold(`
|
|
|
135
112
|
]
|
|
136
113
|
```
|
|
137
114
|
|
|
138
|
-
|
|
115
|
+
`scaffold` never throws. Malformed structures are flagged with `malformed: true` in place and the tree is built regardless. See [Malformed XML](#malformed-xml) for details.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### walk
|
|
120
|
+
|
|
121
|
+
`walk` traverses the full node tree depth-first, calling a visitor function on every node including all descendants. The visitor decides what to collect or do. `walk` has no opinions.
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
import { scaffold, walk } from "xml-to-html-converter";
|
|
125
|
+
|
|
126
|
+
const tree = scaffold(xml);
|
|
127
|
+
|
|
128
|
+
// collect all text content
|
|
129
|
+
const text = [];
|
|
130
|
+
walk(tree, (node) => {
|
|
131
|
+
if (node.role === "textLeaf") text.push(node.raw);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// find all nodes with a specific tag
|
|
135
|
+
const titles = [];
|
|
136
|
+
walk(tree, (node) => {
|
|
137
|
+
if (node.xmlTag === "title") titles.push(node);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// check for malformed nodes anywhere in the tree
|
|
141
|
+
const broken = [];
|
|
142
|
+
walk(tree, (node) => {
|
|
143
|
+
if (node.malformed) broken.push(node);
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### render
|
|
150
|
+
|
|
151
|
+
`render` walks the node tree and converts every XML element to a `<div>`. The original tag name is preserved in `data-tag` and each attribute becomes its own `data-attrs-*` attribute.
|
|
139
152
|
|
|
140
153
|
```js
|
|
141
154
|
import { scaffold, render } from "xml-to-html-converter";
|
|
@@ -151,8 +164,6 @@ const html = render(
|
|
|
151
164
|
);
|
|
152
165
|
```
|
|
153
166
|
|
|
154
|
-
`render` walks the node tree and converts every XML element to a `<div>`. The original tag name is preserved in `data-tag` and each attribute becomes its own `data-attrs-*` attribute:
|
|
155
|
-
|
|
156
167
|
```html
|
|
157
168
|
<div data-tag="bookstore">
|
|
158
169
|
<div data-tag="book" data-attrs-category="cooking">
|
|
@@ -161,21 +172,23 @@ const html = render(
|
|
|
161
172
|
</div>
|
|
162
173
|
```
|
|
163
174
|
|
|
164
|
-
Processing instructions and doctypes are dropped. Comments are passed through unchanged.
|
|
175
|
+
Processing instructions and doctypes are dropped. Comments are passed through unchanged. The output is a raw HTML string — if you are inserting it into a web page, treat it accordingly.
|
|
165
176
|
|
|
166
177
|
---
|
|
167
178
|
|
|
168
|
-
###
|
|
169
|
-
|
|
170
|
-
When your XML comes from a file or an API it is usually indented and line-broken. `minify` strips the whitespace between tags before parsing, leaving text content completely untouched.
|
|
179
|
+
### Full pipeline
|
|
171
180
|
|
|
172
181
|
```js
|
|
173
|
-
import { minify, scaffold, render } from "xml-to-html-converter";
|
|
182
|
+
import { minify, scaffold, walk, render } from "xml-to-html-converter";
|
|
174
183
|
|
|
175
|
-
const
|
|
176
|
-
```
|
|
184
|
+
const tree = scaffold(minify(xml));
|
|
177
185
|
|
|
178
|
-
|
|
186
|
+
walk(tree, (node) => {
|
|
187
|
+
if (node.malformed) console.warn("malformed node", node.raw);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const html = render(tree);
|
|
191
|
+
```
|
|
179
192
|
|
|
180
193
|
---
|
|
181
194
|
|
|
@@ -187,7 +200,7 @@ Every node in the tree has the following fields:
|
|
|
187
200
|
| --------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
188
201
|
| `role` | `XmlNodeRole` | What kind of node this is |
|
|
189
202
|
| `raw` | `string` | The exact source string, untouched |
|
|
190
|
-
| `xmlTag` | `string` | Tag name only, e.g. `"book"` or `"env:Envelope"`. Present on `openTag`, `selfTag`, `closeTag`
|
|
203
|
+
| `xmlTag` | `string` | Tag name only, e.g. `"book"` or `"env:Envelope"`. Present on `openTag`, `selfTag`, and `closeTag` |
|
|
191
204
|
| `xmlInner` | `string` | Everything after the tag name inside the brackets, verbatim. Present on `openTag` and `selfTag` when attributes exist |
|
|
192
205
|
| `xmlAttributes` | `XmlAttribute[]` | Parsed array of `{ name, value }` attribute objects. Present on `openTag` and `selfTag` when attributes exist |
|
|
193
206
|
| `globalIndex` | `number` | Position in the entire document (never resets) |
|
|
@@ -215,11 +228,15 @@ Every node in the tree has the following fields:
|
|
|
215
228
|
|
|
216
229
|
`scaffold` never throws. No matter what the input looks like, it always returns a complete tree. Malformed structures are flagged with `malformed: true` in place and the walk continues.
|
|
217
230
|
|
|
218
|
-
|
|
231
|
+
Eight cases are handled:
|
|
219
232
|
|
|
220
233
|
- **Unclosed tags** - opens but never closes, gets `malformed: true`, children are still collected
|
|
221
234
|
- **Stray closing tags** - a `</tag>` with no matching open surfaces as a `closeTag` token with `malformed: true`
|
|
222
235
|
- **Unclosed brackets** - a `<` with no matching `>` captures the remainder as a malformed token
|
|
236
|
+
- **Unquoted attributes** - `<tag attr=unquoted>` flags the node `malformed: true`, any valid attributes parsed before the error are preserved
|
|
237
|
+
- **Unclosed processing instructions** - `<?xml ...` with no `?>` captures the remainder as a malformed token
|
|
238
|
+
- **Unclosed comments** - `<!-- ...` with no `-->` captures the remainder as a malformed token
|
|
239
|
+
- **Unclosed CDATA** - `<![CDATA[ ...` with no `]]>` captures the remainder as a malformed token
|
|
223
240
|
- **Excessive nesting** - documents nested beyond 500 levels have the deepest open tag flagged `malformed: true` to prevent a stack overflow
|
|
224
241
|
|
|
225
242
|
```js
|
|
@@ -268,7 +285,13 @@ const tree = scaffold("<root><unclosed><valid>text</valid></root>");
|
|
|
268
285
|
## Exports
|
|
269
286
|
|
|
270
287
|
```ts
|
|
271
|
-
import {
|
|
288
|
+
import {
|
|
289
|
+
minify,
|
|
290
|
+
scaffold,
|
|
291
|
+
walk,
|
|
292
|
+
render,
|
|
293
|
+
isMalformed,
|
|
294
|
+
} from "xml-to-html-converter";
|
|
272
295
|
import type {
|
|
273
296
|
XmlNode,
|
|
274
297
|
XmlNodeRole,
|
|
@@ -277,16 +300,17 @@ import type {
|
|
|
277
300
|
} from "xml-to-html-converter";
|
|
278
301
|
```
|
|
279
302
|
|
|
280
|
-
| Export | Kind | Description
|
|
281
|
-
| ------------------ | -------- |
|
|
282
|
-
| `minify` | function | Strips inter-tag whitespace from an XML string
|
|
283
|
-
| `scaffold` | function | Parses an XML string and returns a node tree
|
|
284
|
-
| `
|
|
285
|
-
| `
|
|
286
|
-
| `
|
|
287
|
-
| `
|
|
288
|
-
| `
|
|
289
|
-
| `
|
|
303
|
+
| Export | Kind | Description |
|
|
304
|
+
| ------------------ | -------- | ------------------------------------------------------- |
|
|
305
|
+
| `minify` | function | Strips inter-tag whitespace from an XML string |
|
|
306
|
+
| `scaffold` | function | Parses an XML string and returns a node tree |
|
|
307
|
+
| `walk` | function | Traverses a node tree depth-first with a visitor |
|
|
308
|
+
| `render` | function | Converts a node tree to an HTML string |
|
|
309
|
+
| `isMalformed` | function | Type guard that narrows `XmlNode` to `MalformedXmlNode` |
|
|
310
|
+
| `XmlNode` | type | The shape of every node in the tree |
|
|
311
|
+
| `XmlNodeRole` | type | Union of all valid role strings |
|
|
312
|
+
| `XmlAttribute` | type | Shape of a parsed attribute `{ name, value }` |
|
|
313
|
+
| `MalformedXmlNode` | type | `XmlNode` narrowed to nodes where `malformed` is `true` |
|
|
290
314
|
|
|
291
315
|
---
|
|
292
316
|
|
package/dist/index.cjs
CHANGED
|
@@ -23,13 +23,14 @@ __export(src_exports, {
|
|
|
23
23
|
isMalformed: () => isMalformed,
|
|
24
24
|
minify: () => minify,
|
|
25
25
|
render: () => render,
|
|
26
|
-
scaffold: () => scaffold
|
|
26
|
+
scaffold: () => scaffold,
|
|
27
|
+
walk: () => walk
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(src_exports);
|
|
29
30
|
|
|
30
31
|
// src/modules/minify/minify.ts
|
|
31
32
|
function minify(xml) {
|
|
32
|
-
return xml.replace(/>(\s+)</g,
|
|
33
|
+
return xml.replace(/>(\s+)</g, "><").trim();
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
// src/modules/render/render.ts
|
|
@@ -73,7 +74,12 @@ function parseXmlAttributes(xmlInner) {
|
|
|
73
74
|
i++;
|
|
74
75
|
while (i < s.length && /\s/.test(s[i])) i++;
|
|
75
76
|
const quote = s[i];
|
|
76
|
-
if (quote !== '"' && quote !== "'")
|
|
77
|
+
if (quote !== '"' && quote !== "'") {
|
|
78
|
+
return {
|
|
79
|
+
attributes: attributes.length > 0 ? attributes : void 0,
|
|
80
|
+
malformed: true
|
|
81
|
+
};
|
|
82
|
+
}
|
|
77
83
|
i++;
|
|
78
84
|
const valueStart = i;
|
|
79
85
|
while (i < s.length && s[i] !== quote) i++;
|
|
@@ -81,7 +87,10 @@ function parseXmlAttributes(xmlInner) {
|
|
|
81
87
|
i++;
|
|
82
88
|
attributes.push({ name, value });
|
|
83
89
|
}
|
|
84
|
-
return
|
|
90
|
+
return {
|
|
91
|
+
attributes: attributes.length > 0 ? attributes : void 0,
|
|
92
|
+
malformed: false
|
|
93
|
+
};
|
|
85
94
|
}
|
|
86
95
|
var MAX_DEPTH = 500;
|
|
87
96
|
function scaffold(xml) {
|
|
@@ -184,7 +193,8 @@ function extractXmlNodes(xml, position) {
|
|
|
184
193
|
raw: xml.slice(position),
|
|
185
194
|
role: "processingInstruction",
|
|
186
195
|
tag: "",
|
|
187
|
-
end: xml.length
|
|
196
|
+
end: xml.length,
|
|
197
|
+
malformed: true
|
|
188
198
|
} : {
|
|
189
199
|
raw: xml.slice(position, end2 + 2),
|
|
190
200
|
role: "processingInstruction",
|
|
@@ -194,7 +204,7 @@ function extractXmlNodes(xml, position) {
|
|
|
194
204
|
}
|
|
195
205
|
if (xml[position + 1] === "!" && xml[position + 2] === "[") {
|
|
196
206
|
const end2 = xml.indexOf("]]>", position + 3);
|
|
197
|
-
return end2 === -1 ? { raw: xml.slice(position), role: "textLeaf", tag: "", end: xml.length } : {
|
|
207
|
+
return end2 === -1 ? { raw: xml.slice(position), role: "textLeaf", tag: "", end: xml.length, malformed: true } : {
|
|
198
208
|
raw: xml.slice(position, end2 + 3),
|
|
199
209
|
role: "textLeaf",
|
|
200
210
|
tag: "",
|
|
@@ -203,7 +213,7 @@ function extractXmlNodes(xml, position) {
|
|
|
203
213
|
}
|
|
204
214
|
if (xml[position + 1] === "!" && xml[position + 2] === "-" && xml[position + 3] === "-") {
|
|
205
215
|
const end2 = xml.indexOf("-->", position + 4);
|
|
206
|
-
return end2 === -1 ? { raw: xml.slice(position), role: "comment", tag: "", end: xml.length } : {
|
|
216
|
+
return end2 === -1 ? { raw: xml.slice(position), role: "comment", tag: "", end: xml.length, malformed: true } : {
|
|
207
217
|
raw: xml.slice(position, end2 + 3),
|
|
208
218
|
role: "comment",
|
|
209
219
|
tag: "",
|
|
@@ -243,23 +253,32 @@ function extractXmlNodes(xml, position) {
|
|
|
243
253
|
const trimmed = inner.slice(0, -1).trim();
|
|
244
254
|
const tag2 = trimmed.split(/\s/)[0] ?? "";
|
|
245
255
|
const xmlInner2 = trimmed.slice(tag2.length).trim() || void 0;
|
|
246
|
-
const
|
|
247
|
-
return { raw, role: "selfTag", tag: tag2, xmlInner: xmlInner2, xmlAttributes:
|
|
256
|
+
const parsed2 = xmlInner2 ? parseXmlAttributes(xmlInner2) : void 0;
|
|
257
|
+
return { raw, role: "selfTag", tag: tag2, xmlInner: xmlInner2, xmlAttributes: parsed2?.attributes, end, malformed: parsed2?.malformed ? true : void 0 };
|
|
248
258
|
}
|
|
249
259
|
const tag = inner.split(/\s/)[0] ?? "";
|
|
250
260
|
const xmlInner = inner.slice(tag.length).trim() || void 0;
|
|
251
|
-
const
|
|
252
|
-
return { raw, role: "openTag", tag, xmlInner, xmlAttributes, end };
|
|
261
|
+
const parsed = xmlInner ? parseXmlAttributes(xmlInner) : void 0;
|
|
262
|
+
return { raw, role: "openTag", tag, xmlInner, xmlAttributes: parsed?.attributes, end, malformed: parsed?.malformed ? true : void 0 };
|
|
253
263
|
}
|
|
254
264
|
|
|
255
265
|
// src/modules/scaffold/types.ts
|
|
256
266
|
function isMalformed(node) {
|
|
257
267
|
return node.malformed === true;
|
|
258
268
|
}
|
|
269
|
+
|
|
270
|
+
// src/modules/walk/walk.ts
|
|
271
|
+
function walk(nodes, visitor) {
|
|
272
|
+
for (const node of nodes) {
|
|
273
|
+
visitor(node);
|
|
274
|
+
if (node.children) walk(node.children, visitor);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
259
277
|
// Annotate the CommonJS export names for ESM import in node:
|
|
260
278
|
0 && (module.exports = {
|
|
261
279
|
isMalformed,
|
|
262
280
|
minify,
|
|
263
281
|
render,
|
|
264
|
-
scaffold
|
|
282
|
+
scaffold,
|
|
283
|
+
walk
|
|
265
284
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -25,4 +25,6 @@ declare function render(nodes: XmlNode[]): string;
|
|
|
25
25
|
|
|
26
26
|
declare function scaffold(xml: string): XmlNode[];
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
declare function walk(nodes: XmlNode[], visitor: (node: XmlNode) => void): void;
|
|
29
|
+
|
|
30
|
+
export { type MalformedXmlNode, type XmlAttribute, type XmlNode, type XmlNodeRole, isMalformed, minify, render, scaffold, walk };
|
package/dist/index.d.ts
CHANGED
|
@@ -25,4 +25,6 @@ declare function render(nodes: XmlNode[]): string;
|
|
|
25
25
|
|
|
26
26
|
declare function scaffold(xml: string): XmlNode[];
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
declare function walk(nodes: XmlNode[], visitor: (node: XmlNode) => void): void;
|
|
29
|
+
|
|
30
|
+
export { type MalformedXmlNode, type XmlAttribute, type XmlNode, type XmlNodeRole, isMalformed, minify, render, scaffold, walk };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/modules/minify/minify.ts
|
|
2
2
|
function minify(xml) {
|
|
3
|
-
return xml.replace(/>(\s+)</g,
|
|
3
|
+
return xml.replace(/>(\s+)</g, "><").trim();
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
// src/modules/render/render.ts
|
|
@@ -44,7 +44,12 @@ function parseXmlAttributes(xmlInner) {
|
|
|
44
44
|
i++;
|
|
45
45
|
while (i < s.length && /\s/.test(s[i])) i++;
|
|
46
46
|
const quote = s[i];
|
|
47
|
-
if (quote !== '"' && quote !== "'")
|
|
47
|
+
if (quote !== '"' && quote !== "'") {
|
|
48
|
+
return {
|
|
49
|
+
attributes: attributes.length > 0 ? attributes : void 0,
|
|
50
|
+
malformed: true
|
|
51
|
+
};
|
|
52
|
+
}
|
|
48
53
|
i++;
|
|
49
54
|
const valueStart = i;
|
|
50
55
|
while (i < s.length && s[i] !== quote) i++;
|
|
@@ -52,7 +57,10 @@ function parseXmlAttributes(xmlInner) {
|
|
|
52
57
|
i++;
|
|
53
58
|
attributes.push({ name, value });
|
|
54
59
|
}
|
|
55
|
-
return
|
|
60
|
+
return {
|
|
61
|
+
attributes: attributes.length > 0 ? attributes : void 0,
|
|
62
|
+
malformed: false
|
|
63
|
+
};
|
|
56
64
|
}
|
|
57
65
|
var MAX_DEPTH = 500;
|
|
58
66
|
function scaffold(xml) {
|
|
@@ -155,7 +163,8 @@ function extractXmlNodes(xml, position) {
|
|
|
155
163
|
raw: xml.slice(position),
|
|
156
164
|
role: "processingInstruction",
|
|
157
165
|
tag: "",
|
|
158
|
-
end: xml.length
|
|
166
|
+
end: xml.length,
|
|
167
|
+
malformed: true
|
|
159
168
|
} : {
|
|
160
169
|
raw: xml.slice(position, end2 + 2),
|
|
161
170
|
role: "processingInstruction",
|
|
@@ -165,7 +174,7 @@ function extractXmlNodes(xml, position) {
|
|
|
165
174
|
}
|
|
166
175
|
if (xml[position + 1] === "!" && xml[position + 2] === "[") {
|
|
167
176
|
const end2 = xml.indexOf("]]>", position + 3);
|
|
168
|
-
return end2 === -1 ? { raw: xml.slice(position), role: "textLeaf", tag: "", end: xml.length } : {
|
|
177
|
+
return end2 === -1 ? { raw: xml.slice(position), role: "textLeaf", tag: "", end: xml.length, malformed: true } : {
|
|
169
178
|
raw: xml.slice(position, end2 + 3),
|
|
170
179
|
role: "textLeaf",
|
|
171
180
|
tag: "",
|
|
@@ -174,7 +183,7 @@ function extractXmlNodes(xml, position) {
|
|
|
174
183
|
}
|
|
175
184
|
if (xml[position + 1] === "!" && xml[position + 2] === "-" && xml[position + 3] === "-") {
|
|
176
185
|
const end2 = xml.indexOf("-->", position + 4);
|
|
177
|
-
return end2 === -1 ? { raw: xml.slice(position), role: "comment", tag: "", end: xml.length } : {
|
|
186
|
+
return end2 === -1 ? { raw: xml.slice(position), role: "comment", tag: "", end: xml.length, malformed: true } : {
|
|
178
187
|
raw: xml.slice(position, end2 + 3),
|
|
179
188
|
role: "comment",
|
|
180
189
|
tag: "",
|
|
@@ -214,22 +223,31 @@ function extractXmlNodes(xml, position) {
|
|
|
214
223
|
const trimmed = inner.slice(0, -1).trim();
|
|
215
224
|
const tag2 = trimmed.split(/\s/)[0] ?? "";
|
|
216
225
|
const xmlInner2 = trimmed.slice(tag2.length).trim() || void 0;
|
|
217
|
-
const
|
|
218
|
-
return { raw, role: "selfTag", tag: tag2, xmlInner: xmlInner2, xmlAttributes:
|
|
226
|
+
const parsed2 = xmlInner2 ? parseXmlAttributes(xmlInner2) : void 0;
|
|
227
|
+
return { raw, role: "selfTag", tag: tag2, xmlInner: xmlInner2, xmlAttributes: parsed2?.attributes, end, malformed: parsed2?.malformed ? true : void 0 };
|
|
219
228
|
}
|
|
220
229
|
const tag = inner.split(/\s/)[0] ?? "";
|
|
221
230
|
const xmlInner = inner.slice(tag.length).trim() || void 0;
|
|
222
|
-
const
|
|
223
|
-
return { raw, role: "openTag", tag, xmlInner, xmlAttributes, end };
|
|
231
|
+
const parsed = xmlInner ? parseXmlAttributes(xmlInner) : void 0;
|
|
232
|
+
return { raw, role: "openTag", tag, xmlInner, xmlAttributes: parsed?.attributes, end, malformed: parsed?.malformed ? true : void 0 };
|
|
224
233
|
}
|
|
225
234
|
|
|
226
235
|
// src/modules/scaffold/types.ts
|
|
227
236
|
function isMalformed(node) {
|
|
228
237
|
return node.malformed === true;
|
|
229
238
|
}
|
|
239
|
+
|
|
240
|
+
// src/modules/walk/walk.ts
|
|
241
|
+
function walk(nodes, visitor) {
|
|
242
|
+
for (const node of nodes) {
|
|
243
|
+
visitor(node);
|
|
244
|
+
if (node.children) walk(node.children, visitor);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
230
247
|
export {
|
|
231
248
|
isMalformed,
|
|
232
249
|
minify,
|
|
233
250
|
render,
|
|
234
|
-
scaffold
|
|
251
|
+
scaffold,
|
|
252
|
+
walk
|
|
235
253
|
};
|