@svta/cml-xml 1.0.2 → 1.1.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/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ type XmlNode = {
11
11
  childNodes: XmlNode[];
12
12
  prefix?: string | null;
13
13
  localName?: string;
14
+ parentElement?: XmlNode | null;
14
15
  };
15
16
  //#endregion
16
17
  //#region src/getElementsByName.d.ts
@@ -37,6 +38,7 @@ type XmlParseOptions = {
37
38
  pos?: number;
38
39
  keepWhitespace?: boolean;
39
40
  keepComments?: boolean;
41
+ includeParentElement?: boolean;
40
42
  };
41
43
  //#endregion
42
44
  //#region src/parseXml.d.ts
@@ -50,7 +52,7 @@ type XmlParseOptions = {
50
52
  * @public
51
53
  *
52
54
  * @example
53
- * {@includeCode ../test/decodeXml.test.ts#example}
55
+ * {@includeCode ../test/parseXml.test.ts#example}
54
56
  */
55
57
  declare function parseXml(input: string, options?: XmlParseOptions): XmlNode;
56
58
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/XmlNode.ts","../src/getElementsByName.ts","../src/XmlParseOptions.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":[],"mappings":";;AAMA;;;;ACOgB,KDPJ,OAAA,GCOI;EAAwB,QAAA,EAAA,MAAA;EAA8B,SAAA,EAAA,MAAA,GAAA,IAAA;EAAiB,UAAA,EDJ1E,MCI0E,CAAA,MAAA,EAAA,MAAA,CAAA;EAAA,UAAA,EDH1E,OCG0E,EAAA;;;;;;ADPvF;;;;ACOA;;;;;;;iBAAgB,iBAAA,OAAwB,+BAA8B,YAAiB;;;;ADPvF;;;;ACOgB,KCRJ,eAAA,GDQI;EAAwB,GAAA,CAAA,EAAA,MAAA;EAA8B,cAAA,CAAA,EAAA,OAAA;EAAiB,YAAA,CAAA,EAAA,OAAA;CAAA;;;;;;AAAvF;;;;;;;;ACRA;iBCWgB,QAAA,0BAAiC,kBAAuB;;;AHVxE;;;;ACOA;;;;;;;iBGAgB,YAAA,MAAkB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/XmlNode.ts","../src/getElementsByName.ts","../src/XmlParseOptions.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":[],"mappings":";;AAMA;;;;AAOiB,KAPL,OAAA,GAOK;;;cAJJ;ECIb,UAAgB,EDHH,OCGG,EAAA;EAAwB,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAA8B,SAAA,CAAA,EAAA,MAAA;EAAiB,aAAA,CAAA,EDAtE,OCAsE,GAAA,IAAA;CAAA;;;ADPvF;;;;;;;;ACOA;;;AAAuF,iBAAvE,iBAAA,CAAuE,IAAA,EAA/C,OAA+C,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EAAjB,OAAiB,EAAA,CAAA,EAAA,OAAA,EAAA;;;;ADPvF;;;;AAOiB,KERL,eAAA,GFQK;;;;ECAjB,oBAAgB,CAAA,EAAA,OAAA;CAAwB;;;;;;;;;;AAAxC;;;;;iBEkBgB,QAAA,0BAAiC,kBAAuB;;;AHzBxE;;;;;;;;ACOA;;;AAAuF,iBGAvE,YAAA,CHAuE,GAAA,EGArD,OHAqD,CAAA,EAAA,MAAA"}
package/dist/index.js CHANGED
@@ -21,6 +21,25 @@ function getElementsByName(node, name, found = []) {
21
21
 
22
22
  //#endregion
23
23
  //#region src/parseXml.ts
24
+ const OPEN_BRACKET_CC = 60;
25
+ const CLOSE_BRACKET_CC = 62;
26
+ const MINUS_CC = 45;
27
+ const SLASH_CC = 47;
28
+ const QUESTION_CC = 63;
29
+ const EXCLAMATION_CC = 33;
30
+ const SINGLE_QUOTE_CC = 39;
31
+ const DOUBLE_QUOTE_CC = 34;
32
+ const OPEN_CORNER_BRACKET_CC = 91;
33
+ const CLOSE_CORNER_BRACKET_CC = 93;
34
+ const NAME_SPACER_SET = new Set([
35
+ 13,
36
+ 10,
37
+ 9,
38
+ 62,
39
+ 47,
40
+ 61,
41
+ 32
42
+ ]);
24
43
  /**
25
44
  * Parse XML into a JS object with no validation and some failure tolerance
26
45
  *
@@ -31,26 +50,17 @@ function getElementsByName(node, name, found = []) {
31
50
  * @public
32
51
  *
33
52
  * @example
34
- * {@includeCode ../test/decodeXml.test.ts#example}
53
+ * {@includeCode ../test/parseXml.test.ts#example}
35
54
  */
36
55
  function parseXml(input, options = {}) {
37
56
  let pos = options.pos || 0;
38
57
  const length = input.length;
39
58
  const keepComments = !!options.keepComments;
40
59
  const keepWhitespace = !!options.keepWhitespace;
41
- const openBracket = "<";
42
- const openBracketCC = "<".charCodeAt(0);
43
- const closeBracket = ">";
44
- const closeBracketCC = ">".charCodeAt(0);
45
- const minusCC = "-".charCodeAt(0);
46
- const slashCC = "/".charCodeAt(0);
47
- const questionCC = "?".charCodeAt(0);
48
- const exclamationCC = "!".charCodeAt(0);
49
- const singleQuoteCC = "'".charCodeAt(0);
50
- const doubleQuoteCC = "\"".charCodeAt(0);
51
- const openCornerBracketCC = "[".charCodeAt(0);
52
- const closeCornerBracketCC = "]".charCodeAt(0);
53
- const nameSpacer = "\r\n >/= ";
60
+ const includeParentElement = !!options.includeParentElement;
61
+ /**
62
+ * Creates a text node
63
+ */
54
64
  function createTextNode(value, nodeName = "#text") {
55
65
  return {
56
66
  nodeName,
@@ -60,33 +70,35 @@ function parseXml(input, options = {}) {
60
70
  };
61
71
  }
62
72
  /**
63
- * parsing a list of entries
73
+ * Parses a list of entries
64
74
  */
65
75
  function parseChildren(tagName = "") {
66
76
  const children = [];
67
- while (input[pos]) if (input.charCodeAt(pos) == openBracketCC) {
68
- if (input.charCodeAt(pos + 1) === slashCC) {
77
+ while (pos < length) if (input.charCodeAt(pos) === OPEN_BRACKET_CC) {
78
+ const next = input.charCodeAt(pos + 1);
79
+ if (next === SLASH_CC) {
69
80
  const closeStart = pos + 2;
70
- pos = input.indexOf(closeBracket, pos);
81
+ pos = input.indexOf(">", pos);
71
82
  if (!input.startsWith(tagName, closeStart)) {
72
83
  const parsedText = input.substring(0, pos).split("\n");
73
84
  throw new Error("Unexpected close tag\nLine: " + (parsedText.length - 1) + "\nColumn: " + (parsedText[parsedText.length - 1].length + 1) + "\nChar: " + input[pos]);
74
85
  }
75
86
  if (pos + 1) pos += 1;
76
87
  return children;
77
- } else if (input.charCodeAt(pos + 1) === questionCC) {
78
- pos = input.indexOf(closeBracket, pos);
88
+ } else if (next === QUESTION_CC) {
89
+ pos = input.indexOf(">", pos);
79
90
  pos++;
80
91
  continue;
81
- } else if (input.charCodeAt(pos + 1) === exclamationCC) {
82
- if (input.charCodeAt(pos + 2) == minusCC) {
92
+ } else if (next === EXCLAMATION_CC) {
93
+ const third = input.charCodeAt(pos + 2);
94
+ if (third === MINUS_CC) {
83
95
  const startCommentPos = pos;
84
- while (pos !== -1 && !(input.charCodeAt(pos) === closeBracketCC && input.charCodeAt(pos - 1) == minusCC && input.charCodeAt(pos - 2) == minusCC && pos != -1)) pos = input.indexOf(closeBracket, pos + 1);
96
+ while (pos !== -1 && !(input.charCodeAt(pos) === CLOSE_BRACKET_CC && input.charCodeAt(pos - 1) === MINUS_CC && input.charCodeAt(pos - 2) === MINUS_CC)) pos = input.indexOf(">", pos + 1);
85
97
  if (pos === -1) pos = length;
86
98
  if (keepComments) children.push(createTextNode(input.substring(startCommentPos, pos + 1), "#comment"));
87
- } else if (input.charCodeAt(pos + 2) === openCornerBracketCC && input.charCodeAt(pos + 8) === openCornerBracketCC && input.startsWith("CDATA", pos + 3)) {
99
+ } else if (third === OPEN_CORNER_BRACKET_CC && input.charCodeAt(pos + 8) === OPEN_CORNER_BRACKET_CC && input.startsWith("CDATA", pos + 3)) {
88
100
  const cdataEndIndex = input.indexOf("]]>", pos);
89
- if (cdataEndIndex == -1) {
101
+ if (cdataEndIndex === -1) {
90
102
  children.push(createTextNode(input.substr(pos + 9), "#cdata"));
91
103
  pos = length;
92
104
  } else {
@@ -98,9 +110,10 @@ function parseXml(input, options = {}) {
98
110
  const startDoctype = pos + 1;
99
111
  pos += 2;
100
112
  let encapsuled = false;
101
- while ((input.charCodeAt(pos) !== closeBracketCC || encapsuled === true) && input[pos]) {
102
- if (input.charCodeAt(pos) === openCornerBracketCC) encapsuled = true;
103
- else if (encapsuled === true && input.charCodeAt(pos) === closeCornerBracketCC) encapsuled = false;
113
+ while (pos < length && (input.charCodeAt(pos) !== CLOSE_BRACKET_CC || encapsuled)) {
114
+ const cc = input.charCodeAt(pos);
115
+ if (cc === OPEN_CORNER_BRACKET_CC) encapsuled = true;
116
+ else if (encapsuled && cc === CLOSE_CORNER_BRACKET_CC) encapsuled = false;
104
117
  pos++;
105
118
  }
106
119
  children.push(createTextNode(input.substring(startDoctype, pos), "#doctype"));
@@ -123,38 +136,38 @@ function parseXml(input, options = {}) {
123
136
  return children;
124
137
  }
125
138
  /**
126
- * returns the text outside of texts until the first '&lt;'
139
+ * Returns the text outside of texts until the first '&lt;'
127
140
  */
128
141
  function parseText() {
129
142
  const start = pos;
130
- pos = input.indexOf(openBracket, pos) - 1;
143
+ pos = input.indexOf("<", pos) - 1;
131
144
  if (pos === -2) pos = length;
132
145
  return unescapeHtml(input.slice(start, pos + 1));
133
146
  }
134
147
  /**
135
- * returns text until the first nonAlphabetic letter
148
+ * Returns text until the first nonAlphabetic letter
136
149
  */
137
150
  function parseName() {
138
151
  const start = pos;
139
- while (nameSpacer.indexOf(input[pos]) === -1 && input[pos]) pos++;
152
+ while (pos < length && !NAME_SPACER_SET.has(input.charCodeAt(pos))) pos++;
140
153
  return input.slice(start, pos);
141
154
  }
142
155
  /**
143
- * parses the attributes of a node
156
+ * Parses the attributes of a node
144
157
  */
145
158
  function parseAttributes() {
146
159
  const attributes = {};
147
- while (input.charCodeAt(pos) !== closeBracketCC && input[pos]) {
160
+ while (pos < length && input.charCodeAt(pos) !== CLOSE_BRACKET_CC) {
148
161
  const c = input.charCodeAt(pos);
149
162
  if (c > 64 && c < 91 || c > 96 && c < 123) {
150
163
  const name = parseName();
151
164
  let value = "";
152
165
  let code = input.charCodeAt(pos);
153
- while (code !== singleQuoteCC && code !== doubleQuoteCC) {
166
+ while (code !== SINGLE_QUOTE_CC && code !== DOUBLE_QUOTE_CC) {
154
167
  pos++;
155
168
  code = input.charCodeAt(pos);
156
169
  }
157
- if (code === singleQuoteCC || code === doubleQuoteCC) {
170
+ if (code === SINGLE_QUOTE_CC || code === DOUBLE_QUOTE_CC) {
158
171
  value = parseString();
159
172
  if (pos === -1) throw new Error("Missing closing quote");
160
173
  } else pos--;
@@ -165,7 +178,7 @@ function parseXml(input, options = {}) {
165
178
  return attributes;
166
179
  }
167
180
  /**
168
- * parses a node
181
+ * Parses a node
169
182
  */
170
183
  function parseNode() {
171
184
  pos++;
@@ -181,7 +194,7 @@ function parseXml(input, options = {}) {
181
194
  let childNodes = [];
182
195
  const prev = input.charCodeAt(pos - 1);
183
196
  pos++;
184
- if (prev !== slashCC) childNodes = parseChildren(nodeName);
197
+ if (prev !== SLASH_CC) childNodes = parseChildren(nodeName);
185
198
  return {
186
199
  nodeName,
187
200
  nodeValue: null,
@@ -192,7 +205,7 @@ function parseXml(input, options = {}) {
192
205
  };
193
206
  }
194
207
  /**
195
- * is parsing a string, that starts with a char and with the same usually ' or "
208
+ * Parses a string, that starts with a char and with the same usually ' or "
196
209
  */
197
210
  function parseString() {
198
211
  const startChar = input[pos];
@@ -200,12 +213,21 @@ function parseXml(input, options = {}) {
200
213
  pos = input.indexOf(startChar, startpos);
201
214
  return input.slice(startpos, pos);
202
215
  }
203
- return {
216
+ /**
217
+ * Recursively sets parentElement on all nodes in the tree
218
+ */
219
+ function setParentElements(node, parent) {
220
+ node.parentElement = parent?.nodeName.startsWith("#") ? null : parent;
221
+ for (const child of node.childNodes) setParentElements(child, node);
222
+ }
223
+ const document = {
204
224
  nodeName: "#document",
205
225
  nodeValue: null,
206
226
  childNodes: parseChildren(""),
207
227
  attributes: {}
208
228
  };
229
+ if (includeParentElement) setParentElements(document, null);
230
+ return document;
209
231
  }
210
232
 
211
233
  //#endregion
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["children: any[]","attributes: Record<string, string>","value: string","childNodes: any[]"],"sources":["../src/getElementsByName.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":["import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Recursively finds all elements by name within an XML structure.\n *\n * @param node - The current XML node to search within.\n * @param name - The name of the target nodes to find.\n * @param found - An array to collect matching nodes.\n * @returns An array of all matching XmlNodes.\n *\n * @public\n *\n */\nexport function getElementsByName(node: XmlNode, name: string, found: XmlNode[] = []): XmlNode[] {\n\tif (!node) {\n\t\treturn found\n\t}\n\n\tif (node.nodeName === name) {\n\t\tfound.push(node)\n\t}\n\n\tif (node.childNodes) {\n\t\tfor (const child of node.childNodes) {\n\t\t\tgetElementsByName(child, name, found)\n\t\t}\n\t}\n\n\treturn found\n}\n","import { unescapeHtml } from '@svta/cml-utils'\nimport type { XmlNode } from './XmlNode.ts'\nimport type { XmlParseOptions } from './XmlParseOptions.ts'\n\n/**\n * Parse XML into a JS object with no validation and some failure tolerance\n *\n * @param input - The input XML string\n * @param options - Optional parsing options\n * @returns The parsed XML\n *\n * @public\n *\n * @example\n * {@includeCode ../test/decodeXml.test.ts#example}\n */\nexport function parseXml(input: string, options: XmlParseOptions = {}): XmlNode {\n\tlet pos = options.pos || 0\n\n\tconst length = input.length\n\tconst keepComments = !!options.keepComments\n\tconst keepWhitespace = !!options.keepWhitespace\n\n\tconst openBracket = '<'\n\tconst openBracketCC = '<'.charCodeAt(0)\n\tconst closeBracket = '>'\n\tconst closeBracketCC = '>'.charCodeAt(0)\n\tconst minusCC = '-'.charCodeAt(0)\n\tconst slashCC = '/'.charCodeAt(0)\n\tconst questionCC = '?'.charCodeAt(0)\n\tconst exclamationCC = '!'.charCodeAt(0)\n\tconst singleQuoteCC = \"'\".charCodeAt(0)\n\tconst doubleQuoteCC = '\"'.charCodeAt(0)\n\tconst openCornerBracketCC = '['.charCodeAt(0)\n\tconst closeCornerBracketCC = ']'.charCodeAt(0)\n\tconst nameSpacer = '\\r\\n\\t>/= '\n\n\tfunction createTextNode(value: string, nodeName = '#text'): XmlNode {\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: value,\n\t\t\tattributes: {},\n\t\t\tchildNodes: [],\n\t\t}\n\t}\n\n\t/**\n\t * parsing a list of entries\n\t */\n\tfunction parseChildren(tagName: string = ''): XmlNode[] {\n\t\tconst children: any[] = []\n\t\twhile (input[pos]) {\n\t\t\tif (input.charCodeAt(pos) == openBracketCC) {\n\t\t\t\tif (input.charCodeAt(pos + 1) === slashCC) {\n\t\t\t\t\tconst closeStart = pos + 2\n\t\t\t\t\tpos = input.indexOf(closeBracket, pos)\n\t\t\t\t\tif (!input.startsWith(tagName, closeStart)) {\n\t\t\t\t\t\tconst parsedText = input.substring(0, pos).split('\\n')\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'Unexpected close tag\\nLine: ' + (parsedText.length - 1) +\n\t\t\t\t\t\t\t'\\nColumn: ' + (parsedText[parsedText.length - 1].length + 1) +\n\t\t\t\t\t\t\t'\\nChar: ' + input[pos],\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pos + 1) {\n\t\t\t\t\t\tpos += 1\n\t\t\t\t\t}\n\n\t\t\t\t\treturn children\n\t\t\t\t}\n\t\t\t\telse if (input.charCodeAt(pos + 1) === questionCC) {\n\t\t\t\t\t// xml declaration\n\t\t\t\t\tpos = input.indexOf(closeBracket, pos)\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\telse if (input.charCodeAt(pos + 1) === exclamationCC) {\n\t\t\t\t\tif (input.charCodeAt(pos + 2) == minusCC) {\n\t\t\t\t\t\t// comment support\n\t\t\t\t\t\tconst startCommentPos = pos\n\t\t\t\t\t\twhile (pos !== -1 && !(input.charCodeAt(pos) === closeBracketCC && input.charCodeAt(pos - 1) == minusCC && input.charCodeAt(pos - 2) == minusCC && pos != -1)) {\n\t\t\t\t\t\t\tpos = input.indexOf(closeBracket, pos + 1)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (keepComments) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startCommentPos, pos + 1), '#comment'))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (\n\t\t\t\t\t\tinput.charCodeAt(pos + 2) === openCornerBracketCC &&\n\t\t\t\t\t\tinput.charCodeAt(pos + 8) === openCornerBracketCC &&\n\t\t\t\t\t\tinput.startsWith('CDATA', pos + 3)\n\t\t\t\t\t) {\n\t\t\t\t\t\t// cdata\n\t\t\t\t\t\tconst cdataEndIndex = input.indexOf(']]>', pos)\n\t\t\t\t\t\tif (cdataEndIndex == -1) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substr(pos + 9), '#cdata'))\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(pos + 9, cdataEndIndex), '#cdata'))\n\t\t\t\t\t\t\tpos = cdataEndIndex + 3\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// doctypesupport\n\t\t\t\t\t\tconst startDoctype = pos + 1\n\t\t\t\t\t\tpos += 2\n\t\t\t\t\t\tlet encapsuled = false\n\t\t\t\t\t\twhile ((input.charCodeAt(pos) !== closeBracketCC || encapsuled === true) && input[pos]) {\n\t\t\t\t\t\t\tif (input.charCodeAt(pos) === openCornerBracketCC) {\n\t\t\t\t\t\t\t\tencapsuled = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (encapsuled === true && input.charCodeAt(pos) === closeCornerBracketCC) {\n\t\t\t\t\t\t\t\tencapsuled = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpos++\n\t\t\t\t\t\t}\n\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startDoctype, pos), '#doctype'))\n\t\t\t\t\t}\n\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst node = parseNode()\n\t\t\t\tchildren.push(node)\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst text = parseText()\n\t\t\t\tif (keepWhitespace) {\n\t\t\t\t\tif (text.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(text))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconst trimmed = text.trim()\n\t\t\t\t\tif (trimmed.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(trimmed))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpos++\n\t\t\t}\n\t\t}\n\t\treturn children\n\t}\n\n\t/**\n\t * returns the text outside of texts until the first '&lt;'\n\t */\n\tfunction parseText(): string {\n\t\tconst start = pos\n\t\tpos = input.indexOf(openBracket, pos) - 1\n\t\tif (pos === -2) {\n\t\t\tpos = length\n\t\t}\n\n\t\treturn unescapeHtml(input.slice(start, pos + 1))\n\t}\n\n\t/**\n\t * returns text until the first nonAlphabetic letter\n\t */\n\tfunction parseName(): string {\n\t\tconst start = pos\n\t\twhile (nameSpacer.indexOf(input[pos]) === -1 && input[pos]) {\n\t\t\tpos++\n\t\t}\n\t\treturn input.slice(start, pos)\n\t}\n\n\t/**\n\t * parses the attributes of a node\n\t */\n\tfunction parseAttributes(): Record<string, string> {\n\t\tconst attributes: Record<string, string> = {}\n\n\t\t// parsing attributes\n\t\twhile (input.charCodeAt(pos) !== closeBracketCC && input[pos]) {\n\t\t\tconst c = input.charCodeAt(pos)\n\t\t\tif ((c > 64 && c < 91) || (c > 96 && c < 123)) {\n\t\t\t\tconst name = parseName()\n\t\t\t\tlet value: string = ''\n\t\t\t\t// search beginning of the string\n\t\t\t\tlet code = input.charCodeAt(pos)\n\t\t\t\twhile (code !== singleQuoteCC && code !== doubleQuoteCC) {\n\t\t\t\t\tpos++\n\t\t\t\t\tcode = input.charCodeAt(pos)\n\t\t\t\t}\n\n\t\t\t\tif (code === singleQuoteCC || code === doubleQuoteCC) {\n\t\t\t\t\tvalue = parseString()\n\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\tthrow new Error('Missing closing quote')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpos--\n\t\t\t\t}\n\n\t\t\t\tattributes[name] = unescapeHtml(value)\n\t\t\t}\n\t\t\tpos++\n\t\t}\n\n\t\treturn attributes\n\t}\n\n\t/**\n\t * parses a node\n\t */\n\tfunction parseNode(): XmlNode {\n\t\tpos++\n\t\tconst nodeName = parseName()\n\t\tlet localName = nodeName\n\t\tlet prefix = null\n\n\t\tconst nsIndex = nodeName.indexOf(':')\n\t\tif (nsIndex !== -1) {\n\t\t\tprefix = nodeName.slice(0, nsIndex)\n\t\t\tlocalName = nodeName.slice(nsIndex + 1)\n\t\t}\n\n\t\tconst attributes = parseAttributes()\n\n\t\tlet childNodes: any[] = []\n\n\t\t// optional parsing of children\n\t\tconst prev = input.charCodeAt(pos - 1)\n\t\tpos++\n\n\t\tif (prev !== slashCC) {\n\t\t\tchildNodes = parseChildren(nodeName)\n\t\t}\n\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: null,\n\t\t\tattributes,\n\t\t\tchildNodes,\n\t\t\tprefix,\n\t\t\tlocalName,\n\t\t}\n\t}\n\n\t/**\n\t * is parsing a string, that starts with a char and with the same usually ' or \"\n\t */\n\tfunction parseString(): string {\n\t\tconst startChar = input[pos]\n\t\tconst startpos = pos + 1\n\t\tpos = input.indexOf(startChar, startpos)\n\t\treturn input.slice(startpos, pos)\n\t}\n\n\treturn {\n\t\tnodeName: '#document',\n\t\tnodeValue: null,\n\t\tchildNodes: parseChildren(''),\n\t\tattributes: {},\n\t}\n}\n","import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Basic xml encoding utility. Encodes XML into a string.\n *\n * @param xml - The XML node to encode\n * @returns The parsed XML\n *\n * @public\n *\n * @example\n * {@includeCode ../test/serializeXml.test.ts#example}\n */\nexport function serializeXml(xml: XmlNode): string {\n\tconst { nodeName, attributes, childNodes } = xml\n\n\tif (nodeName === '#document') {\n\t\treturn `<?xml version=\"1.0\" encoding=\"UTF-8\"?>${serializeXml(childNodes[0])}`\n\t}\n\n\tif (nodeName === '#text') {\n\t\treturn xml.nodeValue || ''\n\t}\n\n\tlet result = `<${nodeName}`\n\n\tif (attributes) {\n\t\tfor (const key in attributes) {\n\t\t\tresult += ` ${key}=${JSON.stringify(attributes[key])}`\n\t\t}\n\t}\n\n\tlet children = ''\n\n\tconst childCount = childNodes?.length\n\n\tif (childCount) {\n\t\tfor (let i = 0; i < childCount; i++) {\n\t\t\tchildren += serializeXml(childNodes[i])\n\t\t}\n\t}\n\n\tconst close = (!children) ? ' />' : `>${children}</${nodeName}>`\n\tresult += close\n\n\treturn result\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,SAAgB,kBAAkB,MAAe,MAAc,QAAmB,EAAE,EAAa;AAChG,KAAI,CAAC,KACJ,QAAO;AAGR,KAAI,KAAK,aAAa,KACrB,OAAM,KAAK,KAAK;AAGjB,KAAI,KAAK,WACR,MAAK,MAAM,SAAS,KAAK,WACxB,mBAAkB,OAAO,MAAM,MAAM;AAIvC,QAAO;;;;;;;;;;;;;;;;;ACZR,SAAgB,SAAS,OAAe,UAA2B,EAAE,EAAW;CAC/E,IAAI,MAAM,QAAQ,OAAO;CAEzB,MAAM,SAAS,MAAM;CACrB,MAAM,eAAe,CAAC,CAAC,QAAQ;CAC/B,MAAM,iBAAiB,CAAC,CAAC,QAAQ;CAEjC,MAAM,cAAc;CACpB,MAAM,gBAAgB,IAAI,WAAW,EAAE;CACvC,MAAM,eAAe;CACrB,MAAM,iBAAiB,IAAI,WAAW,EAAE;CACxC,MAAM,UAAU,IAAI,WAAW,EAAE;CACjC,MAAM,UAAU,IAAI,WAAW,EAAE;CACjC,MAAM,aAAa,IAAI,WAAW,EAAE;CACpC,MAAM,gBAAgB,IAAI,WAAW,EAAE;CACvC,MAAM,gBAAgB,IAAI,WAAW,EAAE;CACvC,MAAM,gBAAgB,KAAI,WAAW,EAAE;CACvC,MAAM,sBAAsB,IAAI,WAAW,EAAE;CAC7C,MAAM,uBAAuB,IAAI,WAAW,EAAE;CAC9C,MAAM,aAAa;CAEnB,SAAS,eAAe,OAAe,WAAW,SAAkB;AACnE,SAAO;GACN;GACA,WAAW;GACX,YAAY,EAAE;GACd,YAAY,EAAE;GACd;;;;;CAMF,SAAS,cAAc,UAAkB,IAAe;EACvD,MAAMA,WAAkB,EAAE;AAC1B,SAAO,MAAM,KACZ,KAAI,MAAM,WAAW,IAAI,IAAI,eAAe;AAC3C,OAAI,MAAM,WAAW,MAAM,EAAE,KAAK,SAAS;IAC1C,MAAM,aAAa,MAAM;AACzB,UAAM,MAAM,QAAQ,cAAc,IAAI;AACtC,QAAI,CAAC,MAAM,WAAW,SAAS,WAAW,EAAE;KAC3C,MAAM,aAAa,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,KAAK;AACtD,WAAM,IAAI,MACT,kCAAkC,WAAW,SAAS,KACtD,gBAAgB,WAAW,WAAW,SAAS,GAAG,SAAS,KAC3D,aAAa,MAAM,KACnB;;AAGF,QAAI,MAAM,EACT,QAAO;AAGR,WAAO;cAEC,MAAM,WAAW,MAAM,EAAE,KAAK,YAAY;AAElD,UAAM,MAAM,QAAQ,cAAc,IAAI;AACtC;AACA;cAEQ,MAAM,WAAW,MAAM,EAAE,KAAK,eAAe;AACrD,QAAI,MAAM,WAAW,MAAM,EAAE,IAAI,SAAS;KAEzC,MAAM,kBAAkB;AACxB,YAAO,QAAQ,MAAM,EAAE,MAAM,WAAW,IAAI,KAAK,kBAAkB,MAAM,WAAW,MAAM,EAAE,IAAI,WAAW,MAAM,WAAW,MAAM,EAAE,IAAI,WAAW,OAAO,IACzJ,OAAM,MAAM,QAAQ,cAAc,MAAM,EAAE;AAE3C,SAAI,QAAQ,GACX,OAAM;AAEP,SAAI,aACH,UAAS,KAAK,eAAe,MAAM,UAAU,iBAAiB,MAAM,EAAE,EAAE,WAAW,CAAC;eAIrF,MAAM,WAAW,MAAM,EAAE,KAAK,uBAC9B,MAAM,WAAW,MAAM,EAAE,KAAK,uBAC9B,MAAM,WAAW,SAAS,MAAM,EAAE,EACjC;KAED,MAAM,gBAAgB,MAAM,QAAQ,OAAO,IAAI;AAC/C,SAAI,iBAAiB,IAAI;AACxB,eAAS,KAAK,eAAe,MAAM,OAAO,MAAM,EAAE,EAAE,SAAS,CAAC;AAC9D,YAAM;YAEF;AACJ,eAAS,KAAK,eAAe,MAAM,UAAU,MAAM,GAAG,cAAc,EAAE,SAAS,CAAC;AAChF,YAAM,gBAAgB;;AAEvB;WAEI;KAEJ,MAAM,eAAe,MAAM;AAC3B,YAAO;KACP,IAAI,aAAa;AACjB,aAAQ,MAAM,WAAW,IAAI,KAAK,kBAAkB,eAAe,SAAS,MAAM,MAAM;AACvF,UAAI,MAAM,WAAW,IAAI,KAAK,oBAC7B,cAAa;eAEL,eAAe,QAAQ,MAAM,WAAW,IAAI,KAAK,qBACzD,cAAa;AAEd;;AAED,cAAS,KAAK,eAAe,MAAM,UAAU,cAAc,IAAI,EAAE,WAAW,CAAC;;AAG9E;AACA;;GAGD,MAAM,OAAO,WAAW;AACxB,YAAS,KAAK,KAAK;SAEf;GACJ,MAAM,OAAO,WAAW;AACxB,OAAI,gBACH;QAAI,KAAK,SAAS,EACjB,UAAS,KAAK,eAAe,KAAK,CAAC;UAGhC;IACJ,MAAM,UAAU,KAAK,MAAM;AAC3B,QAAI,QAAQ,SAAS,EACpB,UAAS,KAAK,eAAe,QAAQ,CAAC;;AAGxC;;AAGF,SAAO;;;;;CAMR,SAAS,YAAoB;EAC5B,MAAM,QAAQ;AACd,QAAM,MAAM,QAAQ,aAAa,IAAI,GAAG;AACxC,MAAI,QAAQ,GACX,OAAM;AAGP,SAAO,aAAa,MAAM,MAAM,OAAO,MAAM,EAAE,CAAC;;;;;CAMjD,SAAS,YAAoB;EAC5B,MAAM,QAAQ;AACd,SAAO,WAAW,QAAQ,MAAM,KAAK,KAAK,MAAM,MAAM,KACrD;AAED,SAAO,MAAM,MAAM,OAAO,IAAI;;;;;CAM/B,SAAS,kBAA0C;EAClD,MAAMC,aAAqC,EAAE;AAG7C,SAAO,MAAM,WAAW,IAAI,KAAK,kBAAkB,MAAM,MAAM;GAC9D,MAAM,IAAI,MAAM,WAAW,IAAI;AAC/B,OAAK,IAAI,MAAM,IAAI,MAAQ,IAAI,MAAM,IAAI,KAAM;IAC9C,MAAM,OAAO,WAAW;IACxB,IAAIC,QAAgB;IAEpB,IAAI,OAAO,MAAM,WAAW,IAAI;AAChC,WAAO,SAAS,iBAAiB,SAAS,eAAe;AACxD;AACA,YAAO,MAAM,WAAW,IAAI;;AAG7B,QAAI,SAAS,iBAAiB,SAAS,eAAe;AACrD,aAAQ,aAAa;AACrB,SAAI,QAAQ,GACX,OAAM,IAAI,MAAM,wBAAwB;UAIzC;AAGD,eAAW,QAAQ,aAAa,MAAM;;AAEvC;;AAGD,SAAO;;;;;CAMR,SAAS,YAAqB;AAC7B;EACA,MAAM,WAAW,WAAW;EAC5B,IAAI,YAAY;EAChB,IAAI,SAAS;EAEb,MAAM,UAAU,SAAS,QAAQ,IAAI;AACrC,MAAI,YAAY,IAAI;AACnB,YAAS,SAAS,MAAM,GAAG,QAAQ;AACnC,eAAY,SAAS,MAAM,UAAU,EAAE;;EAGxC,MAAM,aAAa,iBAAiB;EAEpC,IAAIC,aAAoB,EAAE;EAG1B,MAAM,OAAO,MAAM,WAAW,MAAM,EAAE;AACtC;AAEA,MAAI,SAAS,QACZ,cAAa,cAAc,SAAS;AAGrC,SAAO;GACN;GACA,WAAW;GACX;GACA;GACA;GACA;GACA;;;;;CAMF,SAAS,cAAsB;EAC9B,MAAM,YAAY,MAAM;EACxB,MAAM,WAAW,MAAM;AACvB,QAAM,MAAM,QAAQ,WAAW,SAAS;AACxC,SAAO,MAAM,MAAM,UAAU,IAAI;;AAGlC,QAAO;EACN,UAAU;EACV,WAAW;EACX,YAAY,cAAc,GAAG;EAC7B,YAAY,EAAE;EACd;;;;;;;;;;;;;;;;AC3PF,SAAgB,aAAa,KAAsB;CAClD,MAAM,EAAE,UAAU,YAAY,eAAe;AAE7C,KAAI,aAAa,YAChB,QAAO,yCAAyC,aAAa,WAAW,GAAG;AAG5E,KAAI,aAAa,QAChB,QAAO,IAAI,aAAa;CAGzB,IAAI,SAAS,IAAI;AAEjB,KAAI,WACH,MAAK,MAAM,OAAO,WACjB,WAAU,IAAI,IAAI,GAAG,KAAK,UAAU,WAAW,KAAK;CAItD,IAAI,WAAW;CAEf,MAAM,aAAa,YAAY;AAE/B,KAAI,WACH,MAAK,IAAI,IAAI,GAAG,IAAI,YAAY,IAC/B,aAAY,aAAa,WAAW,GAAG;CAIzC,MAAM,QAAS,CAAC,WAAY,QAAQ,IAAI,SAAS,IAAI,SAAS;AAC9D,WAAU;AAEV,QAAO"}
1
+ {"version":3,"file":"index.js","names":["children: XmlNode[]","attributes: Record<string, string>","value: string","childNodes: any[]","document: XmlNode"],"sources":["../src/getElementsByName.ts","../src/parseXml.ts","../src/serializeXml.ts"],"sourcesContent":["import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Recursively finds all elements by name within an XML structure.\n *\n * @param node - The current XML node to search within.\n * @param name - The name of the target nodes to find.\n * @param found - An array to collect matching nodes.\n * @returns An array of all matching XmlNodes.\n *\n * @public\n *\n */\nexport function getElementsByName(node: XmlNode, name: string, found: XmlNode[] = []): XmlNode[] {\n\tif (!node) {\n\t\treturn found\n\t}\n\n\tif (node.nodeName === name) {\n\t\tfound.push(node)\n\t}\n\n\tif (node.childNodes) {\n\t\tfor (const child of node.childNodes) {\n\t\t\tgetElementsByName(child, name, found)\n\t\t}\n\t}\n\n\treturn found\n}\n","import { unescapeHtml } from '@svta/cml-utils'\nimport type { XmlNode } from './XmlNode.ts'\nimport type { XmlParseOptions } from './XmlParseOptions.ts'\n\n// Character code constants (computed once at module load)\nconst OPEN_BRACKET_CC = 60 // '<'\nconst CLOSE_BRACKET_CC = 62 // '>'\nconst MINUS_CC = 45 // '-'\nconst SLASH_CC = 47 // '/'\nconst QUESTION_CC = 63 // '?'\nconst EXCLAMATION_CC = 33 // '!'\nconst SINGLE_QUOTE_CC = 39 // \"'\"\nconst DOUBLE_QUOTE_CC = 34 // '\"'\nconst OPEN_CORNER_BRACKET_CC = 91 // '['\nconst CLOSE_CORNER_BRACKET_CC = 93 // ']'\n\n// Set for fast name delimiter lookup: \\r \\n \\t > / = space\nconst NAME_SPACER_SET = new Set([13, 10, 9, 62, 47, 61, 32])\n\n/**\n * Parse XML into a JS object with no validation and some failure tolerance\n *\n * @param input - The input XML string\n * @param options - Optional parsing options\n * @returns The parsed XML\n *\n * @public\n *\n * @example\n * {@includeCode ../test/parseXml.test.ts#example}\n */\nexport function parseXml(input: string, options: XmlParseOptions = {}): XmlNode {\n\tlet pos = options.pos || 0\n\n\tconst length = input.length\n\tconst keepComments = !!options.keepComments\n\tconst keepWhitespace = !!options.keepWhitespace\n\tconst includeParentElement = !!options.includeParentElement\n\n\t/**\n\t * Creates a text node\n\t */\n\tfunction createTextNode(value: string, nodeName = '#text'): XmlNode {\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: value,\n\t\t\tattributes: {},\n\t\t\tchildNodes: [],\n\t\t}\n\t}\n\n\t/**\n\t * Parses a list of entries\n\t */\n\tfunction parseChildren(tagName: string = ''): XmlNode[] {\n\t\tconst children: XmlNode[] = []\n\t\twhile (pos < length) {\n\t\t\tconst c = input.charCodeAt(pos)\n\t\t\tif (c === OPEN_BRACKET_CC) {\n\t\t\t\tconst next = input.charCodeAt(pos + 1)\n\t\t\t\tif (next === SLASH_CC) {\n\t\t\t\t\tconst closeStart = pos + 2\n\t\t\t\t\tpos = input.indexOf('>', pos)\n\t\t\t\t\tif (!input.startsWith(tagName, closeStart)) {\n\t\t\t\t\t\tconst parsedText = input.substring(0, pos).split('\\n')\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t'Unexpected close tag\\nLine: ' + (parsedText.length - 1) +\n\t\t\t\t\t\t\t'\\nColumn: ' + (parsedText[parsedText.length - 1].length + 1) +\n\t\t\t\t\t\t\t'\\nChar: ' + input[pos],\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tif (pos + 1) {\n\t\t\t\t\t\tpos += 1\n\t\t\t\t\t}\n\n\t\t\t\t\treturn children\n\t\t\t\t}\n\t\t\t\telse if (next === QUESTION_CC) {\n\t\t\t\t\t// xml declaration\n\t\t\t\t\tpos = input.indexOf('>', pos)\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\telse if (next === EXCLAMATION_CC) {\n\t\t\t\t\tconst third = input.charCodeAt(pos + 2)\n\t\t\t\t\tif (third === MINUS_CC) {\n\t\t\t\t\t\t// comment support\n\t\t\t\t\t\tconst startCommentPos = pos\n\t\t\t\t\t\twhile (pos !== -1 && !(input.charCodeAt(pos) === CLOSE_BRACKET_CC && input.charCodeAt(pos - 1) === MINUS_CC && input.charCodeAt(pos - 2) === MINUS_CC)) {\n\t\t\t\t\t\t\tpos = input.indexOf('>', pos + 1)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (keepComments) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startCommentPos, pos + 1), '#comment'))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (\n\t\t\t\t\t\tthird === OPEN_CORNER_BRACKET_CC &&\n\t\t\t\t\t\tinput.charCodeAt(pos + 8) === OPEN_CORNER_BRACKET_CC &&\n\t\t\t\t\t\tinput.startsWith('CDATA', pos + 3)\n\t\t\t\t\t) {\n\t\t\t\t\t\t// cdata\n\t\t\t\t\t\tconst cdataEndIndex = input.indexOf(']]>', pos)\n\t\t\t\t\t\tif (cdataEndIndex === -1) {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substr(pos + 9), '#cdata'))\n\t\t\t\t\t\t\tpos = length\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tchildren.push(createTextNode(input.substring(pos + 9, cdataEndIndex), '#cdata'))\n\t\t\t\t\t\t\tpos = cdataEndIndex + 3\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// doctypesupport\n\t\t\t\t\t\tconst startDoctype = pos + 1\n\t\t\t\t\t\tpos += 2\n\t\t\t\t\t\tlet encapsuled = false\n\t\t\t\t\t\twhile (pos < length && (input.charCodeAt(pos) !== CLOSE_BRACKET_CC || encapsuled)) {\n\t\t\t\t\t\t\tconst cc = input.charCodeAt(pos)\n\t\t\t\t\t\t\tif (cc === OPEN_CORNER_BRACKET_CC) {\n\t\t\t\t\t\t\t\tencapsuled = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (encapsuled && cc === CLOSE_CORNER_BRACKET_CC) {\n\t\t\t\t\t\t\t\tencapsuled = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpos++\n\t\t\t\t\t\t}\n\t\t\t\t\t\tchildren.push(createTextNode(input.substring(startDoctype, pos), '#doctype'))\n\t\t\t\t\t}\n\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst node = parseNode()\n\t\t\t\tchildren.push(node)\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst text = parseText()\n\t\t\t\tif (keepWhitespace) {\n\t\t\t\t\tif (text.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(text))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconst trimmed = text.trim()\n\t\t\t\t\tif (trimmed.length > 0) {\n\t\t\t\t\t\tchildren.push(createTextNode(trimmed))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpos++\n\t\t\t}\n\t\t}\n\t\treturn children\n\t}\n\n\t/**\n\t * Returns the text outside of texts until the first '&lt;'\n\t */\n\tfunction parseText(): string {\n\t\tconst start = pos\n\t\tpos = input.indexOf('<', pos) - 1\n\t\tif (pos === -2) {\n\t\t\tpos = length\n\t\t}\n\n\t\treturn unescapeHtml(input.slice(start, pos + 1))\n\t}\n\n\t/**\n\t * Returns text until the first nonAlphabetic letter\n\t */\n\tfunction parseName(): string {\n\t\tconst start = pos\n\t\twhile (pos < length && !NAME_SPACER_SET.has(input.charCodeAt(pos))) {\n\t\t\tpos++\n\t\t}\n\t\treturn input.slice(start, pos)\n\t}\n\n\t/**\n\t * Parses the attributes of a node\n\t */\n\tfunction parseAttributes(): Record<string, string> {\n\t\tconst attributes: Record<string, string> = {}\n\n\t\t// parsing attributes\n\t\twhile (pos < length && input.charCodeAt(pos) !== CLOSE_BRACKET_CC) {\n\t\t\tconst c = input.charCodeAt(pos)\n\t\t\tif ((c > 64 && c < 91) || (c > 96 && c < 123)) {\n\t\t\t\tconst name = parseName()\n\t\t\t\tlet value: string = ''\n\t\t\t\t// search beginning of the string\n\t\t\t\tlet code = input.charCodeAt(pos)\n\t\t\t\twhile (code !== SINGLE_QUOTE_CC && code !== DOUBLE_QUOTE_CC) {\n\t\t\t\t\tpos++\n\t\t\t\t\tcode = input.charCodeAt(pos)\n\t\t\t\t}\n\n\t\t\t\tif (code === SINGLE_QUOTE_CC || code === DOUBLE_QUOTE_CC) {\n\t\t\t\t\tvalue = parseString()\n\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\tthrow new Error('Missing closing quote')\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpos--\n\t\t\t\t}\n\n\t\t\t\tattributes[name] = unescapeHtml(value)\n\t\t\t}\n\t\t\tpos++\n\t\t}\n\n\t\treturn attributes\n\t}\n\n\t/**\n\t * Parses a node\n\t */\n\tfunction parseNode(): XmlNode {\n\t\tpos++\n\t\tconst nodeName = parseName()\n\t\tlet localName = nodeName\n\t\tlet prefix = null\n\n\t\tconst nsIndex = nodeName.indexOf(':')\n\t\tif (nsIndex !== -1) {\n\t\t\tprefix = nodeName.slice(0, nsIndex)\n\t\t\tlocalName = nodeName.slice(nsIndex + 1)\n\t\t}\n\n\t\tconst attributes = parseAttributes()\n\n\t\tlet childNodes: any[] = []\n\n\t\t// optional parsing of children\n\t\tconst prev = input.charCodeAt(pos - 1)\n\t\tpos++\n\n\t\tif (prev !== SLASH_CC) {\n\t\t\tchildNodes = parseChildren(nodeName)\n\t\t}\n\n\t\treturn {\n\t\t\tnodeName,\n\t\t\tnodeValue: null,\n\t\t\tattributes,\n\t\t\tchildNodes,\n\t\t\tprefix,\n\t\t\tlocalName,\n\t\t}\n\t}\n\n\t/**\n\t * Parses a string, that starts with a char and with the same usually ' or \"\n\t */\n\tfunction parseString(): string {\n\t\tconst startChar = input[pos]\n\t\tconst startpos = pos + 1\n\t\tpos = input.indexOf(startChar, startpos)\n\t\treturn input.slice(startpos, pos)\n\t}\n\n\t/**\n\t * Recursively sets parentElement on all nodes in the tree\n\t */\n\tfunction setParentElements(node: XmlNode, parent: XmlNode | null): void {\n\t\tnode.parentElement = parent?.nodeName.startsWith('#') ? null : parent\n\t\tfor (const child of node.childNodes) {\n\t\t\tsetParentElements(child, node)\n\t\t}\n\t}\n\n\tconst document: XmlNode = {\n\t\tnodeName: '#document',\n\t\tnodeValue: null,\n\t\tchildNodes: parseChildren(''),\n\t\tattributes: {},\n\t}\n\n\tif (includeParentElement) {\n\t\tsetParentElements(document, null)\n\t}\n\n\treturn document\n}\n","import type { XmlNode } from './XmlNode.ts'\n\n/**\n * Basic xml encoding utility. Encodes XML into a string.\n *\n * @param xml - The XML node to encode\n * @returns The parsed XML\n *\n * @public\n *\n * @example\n * {@includeCode ../test/serializeXml.test.ts#example}\n */\nexport function serializeXml(xml: XmlNode): string {\n\tconst { nodeName, attributes, childNodes } = xml\n\n\tif (nodeName === '#document') {\n\t\treturn `<?xml version=\"1.0\" encoding=\"UTF-8\"?>${serializeXml(childNodes[0])}`\n\t}\n\n\tif (nodeName === '#text') {\n\t\treturn xml.nodeValue || ''\n\t}\n\n\tlet result = `<${nodeName}`\n\n\tif (attributes) {\n\t\tfor (const key in attributes) {\n\t\t\tresult += ` ${key}=${JSON.stringify(attributes[key])}`\n\t\t}\n\t}\n\n\tlet children = ''\n\n\tconst childCount = childNodes?.length\n\n\tif (childCount) {\n\t\tfor (let i = 0; i < childCount; i++) {\n\t\t\tchildren += serializeXml(childNodes[i])\n\t\t}\n\t}\n\n\tconst close = (!children) ? ' />' : `>${children}</${nodeName}>`\n\tresult += close\n\n\treturn result\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svta/cml-xml",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "XML parsing utilities",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",