@xapi-js/core 1.0.0 → 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.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/handler.ts
2
- import { StaxXmlParser, StaxXmlWriter, XmlEventType } from "stax-xml";
2
+ import { StaxXmlWriter } from "stax-xml";
3
+ import * as txml from "txml";
3
4
 
4
5
  // src/types.ts
5
6
  var rowType = ["insert", "update", "delete"];
@@ -18,21 +19,31 @@ var ColumnTypeError = class extends Error {
18
19
  this.name = "ColumnTypeError";
19
20
  }
20
21
  };
22
+ var InvalidXmlError = class extends Error {
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = "InvalidXmlError";
26
+ }
27
+ };
21
28
 
22
29
  // src/utils.ts
30
+ function arrayBufferToString(buffer) {
31
+ const decoder = new TextDecoder();
32
+ return decoder.decode(buffer);
33
+ }
23
34
  function makeParseEntities() {
24
- const entities = [];
35
+ const entities2 = [];
25
36
  for (let i = 1; i <= 32; i++) {
26
- entities.push({ entity: `&#${i};`, value: String.fromCharCode(i) });
37
+ entities2.push({ entity: `&#${i};`, value: String.fromCharCode(i) });
27
38
  }
28
- return entities;
39
+ return entities2;
29
40
  }
30
41
  function makeWriterEntities() {
31
- const entities = [];
42
+ const entities2 = [];
32
43
  for (let i = 1; i <= 32; i++) {
33
- entities.push({ entity: `&#${i};`, value: String.fromCharCode(i) });
44
+ entities2.push({ entity: `&#${i};`, value: String.fromCharCode(i) });
34
45
  }
35
- return entities;
46
+ return entities2;
36
47
  }
37
48
  function base64ToUint8Array(base64String) {
38
49
  const binaryString = atob(base64String);
@@ -110,6 +121,7 @@ function dateToString(date, type) {
110
121
  }
111
122
  }
112
123
  var StringWritableStream = class extends WritableStream {
124
+ result = "";
113
125
  constructor() {
114
126
  const decoder = new TextDecoder();
115
127
  super({
@@ -120,7 +132,6 @@ var StringWritableStream = class extends WritableStream {
120
132
  this.result += decoder.decode();
121
133
  }
122
134
  });
123
- this.result = "";
124
135
  }
125
136
  /**
126
137
  * Returns the collected string result.
@@ -181,23 +192,34 @@ function convertToString(value, type) {
181
192
  return dateToString(value, type);
182
193
  case "BLOB":
183
194
  return uint8ArrayToBase64(value);
195
+ case "STRING":
196
+ return String(value);
184
197
  default:
185
198
  return String(value);
186
199
  }
187
200
  }
201
+ var entities = makeParseEntities();
202
+ function _unescapeXml(str) {
203
+ if (!str) return str;
204
+ const regex = new RegExp(entities.map((e) => e.entity).join("|"), "g");
205
+ return str.replace(regex, (match) => {
206
+ const entity = entities.find((e) => e.entity === match);
207
+ return entity ? entity.value : match;
208
+ });
209
+ }
188
210
 
189
211
  // src/xapi-data.ts
190
212
  var XapiRoot = class {
213
+ /** An array of datasets within the X-API root. */
214
+ datasets = [];
215
+ /** Parameters associated with the X-API root. */
216
+ parameters = { params: [] };
191
217
  /**
192
218
  * Creates an instance of XapiRoot.
193
219
  * @param datasets - Initial array of datasets.
194
220
  * @param parameters - Initial parameters.
195
221
  */
196
222
  constructor(datasets = [], parameters = { params: [] }) {
197
- /** An array of datasets within the X-API root. */
198
- this.datasets = [];
199
- /** Parameters associated with the X-API root. */
200
- this.parameters = { params: [] };
201
223
  this.datasets = datasets;
202
224
  this.parameters = parameters;
203
225
  }
@@ -285,6 +307,13 @@ var XapiRoot = class {
285
307
  }
286
308
  };
287
309
  var Dataset = class {
310
+ /** The ID of the dataset. */
311
+ id;
312
+ constColumns = [];
313
+ columns = [];
314
+ /** An array of rows in the dataset. */
315
+ rows = [];
316
+ _columnIndexMap = /* @__PURE__ */ new Map();
288
317
  /**
289
318
  * Creates an instance of Dataset.
290
319
  * @param id - The ID of the dataset.
@@ -293,11 +322,6 @@ var Dataset = class {
293
322
  * @param rows - Initial array of rows.
294
323
  */
295
324
  constructor(id, constColumns = [], columns = [], rows = []) {
296
- this.constColumns = [];
297
- this.columns = [];
298
- /** An array of rows in the dataset. */
299
- this.rows = [];
300
- this._columnIndexMap = /* @__PURE__ */ new Map();
301
325
  this.id = id;
302
326
  this.constColumns = constColumns;
303
327
  this.columns = columns;
@@ -478,127 +502,105 @@ function initXapi(options) {
478
502
  ...options
479
503
  };
480
504
  }
481
- async function parse(reader) {
482
- let _stream;
483
- if (typeof reader === "string") {
484
- _stream = new ReadableStream({
485
- start(controller) {
486
- controller.enqueue(new TextEncoder().encode(reader));
487
- controller.close();
488
- }
489
- });
490
- } else {
491
- _stream = reader;
492
- }
493
- const xmlParser = new StaxXmlParser(_stream, {
494
- addEntities: makeParseEntities(),
495
- encoding: "UTF-8"
496
- });
505
+ function parse2(xml) {
506
+ const parsedXml = txml.parse(xml);
497
507
  const xapiRoot = new XapiRoot();
498
- for await (const event of xmlParser) {
499
- if (event.type === XmlEventType.START_ELEMENT) {
500
- const startEvent = event;
501
- switch (startEvent.localName) {
502
- case "Parameter":
503
- let paramValue = void 0;
504
- const charEvent = (await xmlParser.next()).value;
505
- if (charEvent.type === XmlEventType.CHARACTERS) {
506
- paramValue = charEvent.value;
507
- }
508
- xapiRoot.addParameter({
509
- id: startEvent.attributes["id"],
510
- type: startEvent.attributes["type"] || "STRING",
511
- value: _options.parseToTypes ? convertToColumnType(paramValue, startEvent.attributes["type"] || "STRING") : paramValue
512
- });
513
- break;
514
- case "Dataset":
515
- xapiRoot.addDataset(await parseDataset(startEvent, xmlParser));
516
- break;
508
+ const rootElement = parsedXml.find((node) => {
509
+ const rootNode = node;
510
+ return rootNode.tagName === "Root";
511
+ });
512
+ if (rootElement === void 0) return xapiRoot;
513
+ const parametersElement = rootElement.children?.find((node) => node.tagName === "Parameters");
514
+ parseParameters(parametersElement, xapiRoot);
515
+ const datasetsElements = rootElement.children?.filter((node) => node.tagName === "Dataset");
516
+ if (datasetsElements && datasetsElements?.length && datasetsElements.length > 0) {
517
+ for (const datasetsElement of datasetsElements) {
518
+ if (!datasetsElement.attributes || !datasetsElement.attributes.id) {
519
+ throw new InvalidXmlError("Dataset element must have an 'id' attribute");
517
520
  }
521
+ const datasetId = datasetsElement.attributes?.id;
522
+ const dataset = new Dataset(datasetId);
523
+ xapiRoot.addDataset(dataset);
524
+ const columnInfoElement = datasetsElement.children?.find((node) => node.tagName === "ColumnInfo");
525
+ parseColumnInfo(columnInfoElement, dataset);
526
+ const rowsElement = datasetsElement.children?.find((node) => node.tagName === "Rows");
527
+ parseRows(rowsElement, dataset);
518
528
  }
519
529
  }
520
530
  return xapiRoot;
521
531
  }
522
- async function parseDataset(initEvent, xmlParser) {
523
- const dataset = new Dataset(initEvent.attributes["id"]);
524
- let currentRowIndex = -1;
525
- for await (const event of xmlParser) {
526
- if (event.type === XmlEventType.END_ELEMENT && event.localName === "Dataset") {
527
- break;
528
- } else if (event.type === XmlEventType.START_ELEMENT) {
529
- const startEvent = event;
530
- switch (startEvent.localName) {
531
- case "ConstColumn":
532
- dataset.addConstColumn({
533
- id: startEvent.attributes["id"],
534
- size: parseInt(startEvent.attributes["size"] || "0", 10),
535
- type: startEvent.attributes["type"] || "STRING",
536
- value: startEvent.attributes["value"] || void 0
537
- });
538
- break;
539
- case "Column":
540
- dataset.addColumn({
541
- id: startEvent.attributes["id"],
542
- size: parseInt(startEvent.attributes["size"] || "0", 10),
543
- type: startEvent.attributes["type"] || "STRING"
532
+ function parseValue(value, type = "STRING") {
533
+ value = _unescapeXml(value);
534
+ return _options.parseToTypes ? convertToColumnType(value, type) : value;
535
+ }
536
+ function parseColumnInfo(columnInfoElement, dataset) {
537
+ if (!columnInfoElement) throw new InvalidXmlError("ColumnInfo element is missing in the dataset");
538
+ columnInfoElement.children?.forEach((colInfo) => {
539
+ if (colInfo.tagName === "ConstColumn") {
540
+ dataset.addConstColumn({
541
+ id: colInfo.attributes?.id,
542
+ size: parseInt(colInfo.attributes?.size || "0", 10),
543
+ type: colInfo.attributes?.type || "STRING",
544
+ value: parseValue(colInfo.attributes?.value, colInfo.attributes?.type)
545
+ });
546
+ } else if (colInfo.tagName === "Column") {
547
+ dataset.addColumn({
548
+ id: colInfo.attributes?.id,
549
+ size: parseInt(colInfo.attributes?.size || "0", 10),
550
+ type: colInfo.attributes?.type || "STRING"
551
+ });
552
+ }
553
+ });
554
+ }
555
+ function parseRows(rowsElement, dataset) {
556
+ rowsElement?.children?.forEach((r) => {
557
+ if (r.tagName === "Row") {
558
+ const rowIndex = dataset.newRow();
559
+ dataset.rows[rowIndex].type = r.attributes?.type || void 0;
560
+ r.children?.forEach((col) => {
561
+ if (col.tagName === "Col") {
562
+ const colId = col.attributes?.id;
563
+ const value = col.children?.[0];
564
+ const columnInfo = dataset.getColumnInfo(colId);
565
+ if (!columnInfo) throw new InvalidXmlError(`Column with id ${colId} not found in dataset ${dataset.id}`);
566
+ const castedValue = parseValue(value, columnInfo.type);
567
+ dataset.rows[rowIndex].cols.push({ id: colId, value: castedValue });
568
+ } else if (col.tagName === "OrgRow") {
569
+ dataset.rows[rowIndex].orgRow = [];
570
+ col.children?.forEach((orgCol) => {
571
+ if (orgCol.tagName === "Col") {
572
+ const colId = orgCol.attributes?.id;
573
+ const value = orgCol.children?.[0];
574
+ const columnInfo = dataset.getColumnInfo(colId);
575
+ const castedValue = parseValue(value, columnInfo.type);
576
+ if (dataset && dataset.rows && dataset.rows[rowIndex] && dataset.rows[rowIndex].orgRow) {
577
+ dataset.rows[rowIndex].orgRow.push({ id: colId, value: castedValue });
578
+ }
579
+ }
544
580
  });
545
- break;
546
- case "Row":
547
- currentRowIndex = dataset.newRow();
548
- dataset.rows[currentRowIndex].type = startEvent.attributes["type"] || void 0;
549
- break;
550
- case "Col": {
551
- await parseCol(xmlParser, startEvent, dataset, currentRowIndex, false);
552
- break;
553
581
  }
554
- case "OrgRow":
555
- if (currentRowIndex < 0) {
556
- throw new Error("Row must be defined before OrgRow");
557
- }
558
- dataset.rows[currentRowIndex].orgRow = [];
559
- for await (const orgRowEvent of xmlParser) {
560
- if (orgRowEvent.type === XmlEventType.END_ELEMENT && orgRowEvent.localName === "OrgRow") {
561
- break;
562
- }
563
- if (orgRowEvent.type === XmlEventType.START_ELEMENT && orgRowEvent.localName === "Col") {
564
- const orgColEvent = orgRowEvent;
565
- await parseCol(xmlParser, orgColEvent, dataset, currentRowIndex, true);
566
- }
567
- }
568
- }
582
+ });
583
+ } else if (r.tagName === "Col") {
584
+ throw new InvalidXmlError("Row must be defined before Col");
585
+ } else if (r.tagName === "OrgRow") {
586
+ throw new InvalidXmlError("Row must be defined before OrgRow");
569
587
  }
570
- }
571
- return dataset;
588
+ });
572
589
  }
573
- async function parseCol(xmlParser, startEvent, dataset, currentRowIndex, isOrgRow) {
574
- if (currentRowIndex < 0) {
575
- throw new Error("Row must be defined before Col");
576
- }
577
- const colId = startEvent.attributes["id"];
578
- const colIndex = dataset.getColumnIndex(colId);
579
- if (colIndex === void 0 || colIndex < 0) {
580
- throw new Error(`Column with id ${colId} not found in dataset ${dataset.id}`);
581
- }
582
- const colCharEvent = (await xmlParser.next()).value;
583
- let value;
584
- if (colCharEvent.type === XmlEventType.CDATA) {
585
- value = colCharEvent.value;
586
- } else if (colCharEvent.type === XmlEventType.CHARACTERS) {
587
- value = colCharEvent.value;
588
- }
589
- let castedValue = value;
590
- if (_options.parseToTypes) {
591
- const columnInfo = dataset.getColumnInfo(colId);
592
- if (!columnInfo || columnType.includes(columnInfo.type) === false) {
593
- throw new Error(`Column type for ${colId} not found in dataset ${dataset.id}`);
590
+ function parseParameters(parametersElement, xapiRoot) {
591
+ if (!parametersElement) return;
592
+ parametersElement.children?.forEach((p) => {
593
+ if (p.tagName === "Parameter") {
594
+ const id = p.attributes?.id;
595
+ const type = p.attributes?.type || "STRING";
596
+ const value = p.children?.[0];
597
+ xapiRoot.addParameter({
598
+ id,
599
+ type,
600
+ value: parseValue(value, type)
601
+ });
594
602
  }
595
- castedValue = convertToColumnType(value, columnInfo.type);
596
- }
597
- if (!isOrgRow) {
598
- dataset.rows[currentRowIndex].cols.push({ id: colId, value: castedValue });
599
- } else {
600
- dataset.rows[currentRowIndex].orgRow.push({ id: colId, value: castedValue });
601
- }
603
+ });
602
604
  }
603
605
  async function writeString(root) {
604
606
  const stringStream = new StringWritableStream();
@@ -718,10 +720,13 @@ async function writeColumn(writer, dataset, col) {
718
720
  export {
719
721
  ColumnTypeError,
720
722
  Dataset,
723
+ InvalidXmlError,
721
724
  NexaVersion,
722
725
  StringWritableStream,
723
726
  XapiRoot,
724
727
  XplatformVersion,
728
+ _unescapeXml,
729
+ arrayBufferToString,
725
730
  base64ToUint8Array,
726
731
  columnType,
727
732
  convertToColumnType,
@@ -730,7 +735,7 @@ export {
730
735
  initXapi,
731
736
  makeParseEntities,
732
737
  makeWriterEntities,
733
- parse,
738
+ parse2 as parse,
734
739
  rowType,
735
740
  stringToDate,
736
741
  stringToReadableStream,