-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxml.ts
More file actions
57 lines (51 loc) · 1.74 KB
/
xml.ts
File metadata and controls
57 lines (51 loc) · 1.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
export type Tags = Record<string, XmlFn>;
export type XmlFn = {
(...children: ElementChild[]): Element;
(attrs: Attrs, ...children: ElementChild[]): Element;
};
export type Element = {
tag: string;
attrs: Record<string, string>;
elements: Element[];
} | string;
export type ElementChild = Element | Element[];
export type Attrs = Record<string, string>;
export const tags: Tags = new Proxy({}, {
get(_, tag: string) {
const fn: XmlFn = (
a: Record<string, string> | ElementChild = {},
...c: ElementChild[]
) => {
let attrs: Attrs;
let elements = c.flat();
[attrs, elements] = Array.isArray(a)
? [{}, [...a, ...elements]]
: typeof a === "string"
? [{}, [a, ...elements]]
: typeof a.attrs === "object"
? [{}, [a as Element, ...elements]]
: [a as Attrs, elements];
return { tag, attrs, elements };
};
return fn;
},
});
export function render(
el: Element,
format: boolean = true,
indent: number = 0,
): string {
const dec = indent ? "" : `<?xml version="1.0" encoding="utf8"?>\n`;
const space = format
? Array.from({ length: indent }, () => " ").join("")
: "";
const br = format ? "\n" : "";
if (typeof el === "string") return dec + space + el + br;
const { tag, attrs, elements } = el;
let a = Object.keys(attrs).map((k) => `${k}="${attrs[k]}"`).join(" ");
a = a ? " " + a : a;
if (elements.length === 0) return `${dec}${space}<${tag}${a}/>${br}`;
return `${dec}${space}<${tag}${a}>${br}${
elements.map((e) => render(e, format, indent + 2)).join("")
}${space}</${tag}>${br}`;
}