@svta/cml-xml 1.0.1 → 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
@@ -2,8 +2,7 @@
2
2
  /**
3
3
  * XML node
4
4
  *
5
- *
6
- * @beta
5
+ * @public
7
6
  */
8
7
  type XmlNode = {
9
8
  nodeName: string;
@@ -12,6 +11,7 @@ type XmlNode = {
12
11
  childNodes: XmlNode[];
13
12
  prefix?: string | null;
14
13
  localName?: string;
14
+ parentElement?: XmlNode | null;
15
15
  };
16
16
  //#endregion
17
17
  //#region src/getElementsByName.d.ts
@@ -23,8 +23,7 @@ type XmlNode = {
23
23
  * @param found - An array to collect matching nodes.
24
24
  * @returns An array of all matching XmlNodes.
25
25
  *
26
- *
27
- * @beta
26
+ * @public
28
27
  *
29
28
  */
30
29
  declare function getElementsByName(node: XmlNode, name: string, found?: XmlNode[]): XmlNode[];
@@ -33,13 +32,13 @@ declare function getElementsByName(node: XmlNode, name: string, found?: XmlNode[
33
32
  /**
34
33
  * XML parsing options
35
34
  *
36
- *
37
- * @beta
35
+ * @public
38
36
  */
39
37
  type XmlParseOptions = {
40
38
  pos?: number;
41
39
  keepWhitespace?: boolean;
42
40
  keepComments?: boolean;
41
+ includeParentElement?: boolean;
43
42
  };
44
43
  //#endregion
45
44
  //#region src/parseXml.d.ts
@@ -50,10 +49,10 @@ type XmlParseOptions = {
50
49
  * @param options - Optional parsing options
51
50
  * @returns The parsed XML
52
51
  *
53
- * @beta
52
+ * @public
54
53
  *
55
54
  * @example
56
- * {@includeCode ../test/decodeXml.test.ts#example}
55
+ * {@includeCode ../test/parseXml.test.ts#example}
57
56
  */
58
57
  declare function parseXml(input: string, options?: XmlParseOptions): XmlNode;
59
58
  //#endregion
@@ -64,7 +63,7 @@ declare function parseXml(input: string, options?: XmlParseOptions): XmlNode;
64
63
  * @param xml - The XML node to encode
65
64
  * @returns The parsed XML
66
65
  *
67
- * @beta
66
+ * @public
68
67
  *
69
68
  * @example
70
69
  * {@includeCode ../test/serializeXml.test.ts#example}
@@ -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":";;AAOA;;;;ACOA;AAAwC,KDP5B,OAAA,GCO4B;EAA8B,QAAA,EAAA,MAAA;EAAiB,SAAA,EAAA,MAAA,GAAA,IAAA;EAAA,UAAA,EDJ1E,MCI0E,CAAA,MAAA,EAAA,MAAA,CAAA;cDH1E;;;AELb,CAAA;;;AFCA;;;;ACOA;;;;;;;;ACRY,iBDQI,iBAAA,CCRJ,IAAA,EDQ4B,OCR5B,EAAA,IAAA,EAAA,MAAA,EAAA,KAAA,CAAA,EDQ0D,OCR1D,EAAA,CAAA,EDQ2E,OCR3E,EAAA;;;;AFCZ;;;;ACOA;AAAwC,KCR5B,eAAA,GDQ4B;EAA8B,GAAA,CAAA,EAAA,MAAA;EAAiB,cAAA,CAAA,EAAA,OAAA;EAAA,YAAA,CAAA,EAAA,OAAA;;;;;;;AAAvF;;;;;;;;ACRA;iBCUgB,QAAA,0BAAiC,kBAAuB;;;AHTxE;;;;ACOA;;;;;;;iBGDgB,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
@@ -9,8 +9,7 @@ import { unescapeHtml } from "@svta/cml-utils";
9
9
  * @param found - An array to collect matching nodes.
10
10
  * @returns An array of all matching XmlNodes.
11
11
  *
12
- *
13
- * @beta
12
+ * @public
14
13
  *
15
14
  */
16
15
  function getElementsByName(node, name, found = []) {
@@ -22,6 +21,25 @@ function getElementsByName(node, name, found = []) {
22
21
 
23
22
  //#endregion
24
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
+ ]);
25
43
  /**
26
44
  * Parse XML into a JS object with no validation and some failure tolerance
27
45
  *
@@ -29,29 +47,20 @@ function getElementsByName(node, name, found = []) {
29
47
  * @param options - Optional parsing options
30
48
  * @returns The parsed XML
31
49
  *
32
- * @beta
50
+ * @public
33
51
  *
34
52
  * @example
35
- * {@includeCode ../test/decodeXml.test.ts#example}
53
+ * {@includeCode ../test/parseXml.test.ts#example}
36
54
  */
37
55
  function parseXml(input, options = {}) {
38
56
  let pos = options.pos || 0;
39
57
  const length = input.length;
40
58
  const keepComments = !!options.keepComments;
41
59
  const keepWhitespace = !!options.keepWhitespace;
42
- const openBracket = "<";
43
- const openBracketCC = "<".charCodeAt(0);
44
- const closeBracket = ">";
45
- const closeBracketCC = ">".charCodeAt(0);
46
- const minusCC = "-".charCodeAt(0);
47
- const slashCC = "/".charCodeAt(0);
48
- const questionCC = "?".charCodeAt(0);
49
- const exclamationCC = "!".charCodeAt(0);
50
- const singleQuoteCC = "'".charCodeAt(0);
51
- const doubleQuoteCC = "\"".charCodeAt(0);
52
- const openCornerBracketCC = "[".charCodeAt(0);
53
- const closeCornerBracketCC = "]".charCodeAt(0);
54
- const nameSpacer = "\r\n >/= ";
60
+ const includeParentElement = !!options.includeParentElement;
61
+ /**
62
+ * Creates a text node
63
+ */
55
64
  function createTextNode(value, nodeName = "#text") {
56
65
  return {
57
66
  nodeName,
@@ -61,33 +70,35 @@ function parseXml(input, options = {}) {
61
70
  };
62
71
  }
63
72
  /**
64
- * parsing a list of entries
73
+ * Parses a list of entries
65
74
  */
66
75
  function parseChildren(tagName = "") {
67
76
  const children = [];
68
- while (input[pos]) if (input.charCodeAt(pos) == openBracketCC) {
69
- 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) {
70
80
  const closeStart = pos + 2;
71
- pos = input.indexOf(closeBracket, pos);
81
+ pos = input.indexOf(">", pos);
72
82
  if (!input.startsWith(tagName, closeStart)) {
73
83
  const parsedText = input.substring(0, pos).split("\n");
74
84
  throw new Error("Unexpected close tag\nLine: " + (parsedText.length - 1) + "\nColumn: " + (parsedText[parsedText.length - 1].length + 1) + "\nChar: " + input[pos]);
75
85
  }
76
86
  if (pos + 1) pos += 1;
77
87
  return children;
78
- } else if (input.charCodeAt(pos + 1) === questionCC) {
79
- pos = input.indexOf(closeBracket, pos);
88
+ } else if (next === QUESTION_CC) {
89
+ pos = input.indexOf(">", pos);
80
90
  pos++;
81
91
  continue;
82
- } else if (input.charCodeAt(pos + 1) === exclamationCC) {
83
- if (input.charCodeAt(pos + 2) == minusCC) {
92
+ } else if (next === EXCLAMATION_CC) {
93
+ const third = input.charCodeAt(pos + 2);
94
+ if (third === MINUS_CC) {
84
95
  const startCommentPos = pos;
85
- 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);
86
97
  if (pos === -1) pos = length;
87
98
  if (keepComments) children.push(createTextNode(input.substring(startCommentPos, pos + 1), "#comment"));
88
- } 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)) {
89
100
  const cdataEndIndex = input.indexOf("]]>", pos);
90
- if (cdataEndIndex == -1) {
101
+ if (cdataEndIndex === -1) {
91
102
  children.push(createTextNode(input.substr(pos + 9), "#cdata"));
92
103
  pos = length;
93
104
  } else {
@@ -99,9 +110,10 @@ function parseXml(input, options = {}) {
99
110
  const startDoctype = pos + 1;
100
111
  pos += 2;
101
112
  let encapsuled = false;
102
- while ((input.charCodeAt(pos) !== closeBracketCC || encapsuled === true) && input[pos]) {
103
- if (input.charCodeAt(pos) === openCornerBracketCC) encapsuled = true;
104
- 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;
105
117
  pos++;
106
118
  }
107
119
  children.push(createTextNode(input.substring(startDoctype, pos), "#doctype"));
@@ -124,38 +136,38 @@ function parseXml(input, options = {}) {
124
136
  return children;
125
137
  }
126
138
  /**
127
- * returns the text outside of texts until the first '&lt;'
139
+ * Returns the text outside of texts until the first '&lt;'
128
140
  */
129
141
  function parseText() {
130
142
  const start = pos;
131
- pos = input.indexOf(openBracket, pos) - 1;
143
+ pos = input.indexOf("<", pos) - 1;
132
144
  if (pos === -2) pos = length;
133
145
  return unescapeHtml(input.slice(start, pos + 1));
134
146
  }
135
147
  /**
136
- * returns text until the first nonAlphabetic letter
148
+ * Returns text until the first nonAlphabetic letter
137
149
  */
138
150
  function parseName() {
139
151
  const start = pos;
140
- while (nameSpacer.indexOf(input[pos]) === -1 && input[pos]) pos++;
152
+ while (pos < length && !NAME_SPACER_SET.has(input.charCodeAt(pos))) pos++;
141
153
  return input.slice(start, pos);
142
154
  }
143
155
  /**
144
- * parses the attributes of a node
156
+ * Parses the attributes of a node
145
157
  */
146
158
  function parseAttributes() {
147
159
  const attributes = {};
148
- while (input.charCodeAt(pos) !== closeBracketCC && input[pos]) {
160
+ while (pos < length && input.charCodeAt(pos) !== CLOSE_BRACKET_CC) {
149
161
  const c = input.charCodeAt(pos);
150
162
  if (c > 64 && c < 91 || c > 96 && c < 123) {
151
163
  const name = parseName();
152
164
  let value = "";
153
165
  let code = input.charCodeAt(pos);
154
- while (code !== singleQuoteCC && code !== doubleQuoteCC) {
166
+ while (code !== SINGLE_QUOTE_CC && code !== DOUBLE_QUOTE_CC) {
155
167
  pos++;
156
168
  code = input.charCodeAt(pos);
157
169
  }
158
- if (code === singleQuoteCC || code === doubleQuoteCC) {
170
+ if (code === SINGLE_QUOTE_CC || code === DOUBLE_QUOTE_CC) {
159
171
  value = parseString();
160
172
  if (pos === -1) throw new Error("Missing closing quote");
161
173
  } else pos--;
@@ -166,7 +178,7 @@ function parseXml(input, options = {}) {
166
178
  return attributes;
167
179
  }
168
180
  /**
169
- * parses a node
181
+ * Parses a node
170
182
  */
171
183
  function parseNode() {
172
184
  pos++;
@@ -182,7 +194,7 @@ function parseXml(input, options = {}) {
182
194
  let childNodes = [];
183
195
  const prev = input.charCodeAt(pos - 1);
184
196
  pos++;
185
- if (prev !== slashCC) childNodes = parseChildren(nodeName);
197
+ if (prev !== SLASH_CC) childNodes = parseChildren(nodeName);
186
198
  return {
187
199
  nodeName,
188
200
  nodeValue: null,
@@ -193,7 +205,7 @@ function parseXml(input, options = {}) {
193
205
  };
194
206
  }
195
207
  /**
196
- * 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 "
197
209
  */
198
210
  function parseString() {
199
211
  const startChar = input[pos];
@@ -201,12 +213,21 @@ function parseXml(input, options = {}) {
201
213
  pos = input.indexOf(startChar, startpos);
202
214
  return input.slice(startpos, pos);
203
215
  }
204
- 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 = {
205
224
  nodeName: "#document",
206
225
  nodeValue: null,
207
226
  childNodes: parseChildren(""),
208
227
  attributes: {}
209
228
  };
229
+ if (includeParentElement) setParentElements(document, null);
230
+ return document;
210
231
  }
211
232
 
212
233
  //#endregion
@@ -217,7 +238,7 @@ function parseXml(input, options = {}) {
217
238
  * @param xml - The XML node to encode
218
239
  * @returns The parsed XML
219
240
  *
220
- * @beta
241
+ * @public
221
242
  *
222
243
  * @example
223
244
  * {@includeCode ../test/serializeXml.test.ts#example}
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 *\n * @beta\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 * @beta\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 * @beta\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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"}
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.1",
3
+ "version": "1.1.0",
4
4
  "description": "XML parsing utilities",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -50,6 +50,6 @@
50
50
  }
51
51
  },
52
52
  "peerDependencies": {
53
- "@svta/cml-utils": "1.0.1"
53
+ "@svta/cml-utils": "1.1.0"
54
54
  }
55
55
  }