@xapi-js/core 1.3.0 → 1.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/dist/index.d.ts CHANGED
@@ -341,6 +341,7 @@ type XmlNode = {
341
341
  declare function arrayBufferToString(buffer: ArrayBuffer): string;
342
342
  /**
343
343
  * Creates an array of entities for parsing XML, including control characters.
344
+ * @deprecated Use PARSE_ENTITIES directly for better performance
344
345
  * @returns An array of objects, each with an `entity` (e.g., "") and its `value` (e.g., "\x01").
345
346
  */
346
347
  declare function makeParseEntities(): {
@@ -468,4 +469,78 @@ declare class XmlStringBuilder {
468
469
  */
469
470
  declare function parseXml(xml: string): XmlNode[];
470
471
  //#endregion
471
- export { Col, Column, ColumnInfo, ColumnType, ColumnTypeError, ConstColumn, Dataset, InvalidXmlError, NexaVersion, Parameter, Row, RowType, Rows, StringWritableStream, XapiOptions, XapiParameters, XapiRoot, XapiValueType, XapiVersion, XmlNode, XmlStringBuilder, XplatformVersion, _unescapeXml, arrayBufferToString, base64ToUint8Array, columnType, convertToColumnType, convertToString, dateToString, encodeControlChars, escapeXml, initXapi, isXapiRoot, makeParseEntities, parse, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write };
472
+ //#region src/schema.d.ts
473
+ type XapiTypeMap = {
474
+ STRING: string;
475
+ INT: number;
476
+ FLOAT: number;
477
+ DECIMAL: number;
478
+ BIGDECIMAL: number;
479
+ DATE: Date;
480
+ DATETIME: Date;
481
+ TIME: Date;
482
+ BLOB: Uint8Array;
483
+ };
484
+ interface XapiColumnSchema<T extends ColumnType = ColumnType, Optional extends boolean = boolean> {
485
+ readonly kind: "xapi-column";
486
+ readonly type: T;
487
+ readonly size: number;
488
+ readonly optional: Optional;
489
+ }
490
+ type XapiColumns = Record<string, XapiColumnSchema>;
491
+ interface XapiDatasetSchema<Columns extends XapiColumns = XapiColumns> {
492
+ readonly kind: "xapi-dataset";
493
+ readonly columns: Columns;
494
+ }
495
+ type XapiDatasets = Record<string, XapiDatasetSchema>;
496
+ interface XapiRootSchema<Datasets extends XapiDatasets = XapiDatasets, Parameters extends XapiColumns = XapiColumns> {
497
+ readonly kind: "xapi-root";
498
+ readonly datasets: Datasets;
499
+ readonly parameters: Parameters;
500
+ }
501
+ interface XapiOperation<Request extends XapiRootSchema = XapiRootSchema, Response extends XapiRootSchema = XapiRootSchema> {
502
+ readonly kind: "xapi-operation";
503
+ readonly request: Request;
504
+ readonly response: Response;
505
+ }
506
+ type RequiredColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? never : Key; }[keyof Columns];
507
+ type OptionalColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? Key : never; }[keyof Columns];
508
+ type InferColumns<Columns extends XapiColumns> = { [Key in RequiredColumnKeys<Columns>]: XapiTypeMap[Columns[Key]["type"]]; } & { [Key in OptionalColumnKeys<Columns>]?: XapiTypeMap[Columns[Key]["type"]]; };
509
+ type InferDataset<Schema extends XapiDatasetSchema> = InferColumns<Schema["columns"]>[];
510
+ type InferRoot<Schema extends XapiRootSchema> = {
511
+ parameters: InferColumns<Schema["parameters"]>;
512
+ datasets: { [Key in keyof Schema["datasets"]]: InferDataset<Schema["datasets"][Key]>; };
513
+ };
514
+ type RequestOf<Operation extends XapiOperation> = InferRoot<Operation["request"]>;
515
+ type ResponseOf<Operation extends XapiOperation> = InferRoot<Operation["response"]>;
516
+ type ColumnOptions<Optional extends boolean> = {
517
+ size?: number;
518
+ optional?: Optional;
519
+ };
520
+ declare function defineDataset<const Columns extends XapiColumns>(columns: Columns): XapiDatasetSchema<Columns>;
521
+ declare function defineRoot<const Datasets extends XapiDatasets, const Parameters extends XapiColumns = Record<never, never>>(definition: {
522
+ datasets: Datasets;
523
+ parameters?: Parameters;
524
+ }): XapiRootSchema<Datasets, Parameters>;
525
+ declare function defineOperation<const Request extends XapiRootSchema, const Response extends XapiRootSchema>(definition: {
526
+ request: Request;
527
+ response: Response;
528
+ }): XapiOperation<Request, Response>;
529
+ declare const xapi: {
530
+ readonly string: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"STRING", Optional>;
531
+ readonly int: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"INT", Optional>;
532
+ readonly float: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"FLOAT", Optional>;
533
+ readonly decimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DECIMAL", Optional>;
534
+ readonly bigdecimal: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BIGDECIMAL", Optional>;
535
+ readonly date: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATE", Optional>;
536
+ readonly datetime: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"DATETIME", Optional>;
537
+ readonly time: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"TIME", Optional>;
538
+ readonly blob: <const Optional extends boolean = false>(options?: ColumnOptions<Optional>) => XapiColumnSchema<"BLOB", Optional>;
539
+ readonly dataset: typeof defineDataset;
540
+ readonly root: typeof defineRoot;
541
+ readonly operation: typeof defineOperation;
542
+ };
543
+ declare function encodeRoot<Schema extends XapiRootSchema>(schema: Schema, value: InferRoot<Schema>): XapiRoot;
544
+ declare function decodeRoot<Schema extends XapiRootSchema>(schema: Schema, root: XapiRoot): InferRoot<Schema>;
545
+ //#endregion
546
+ export { Col, Column, ColumnInfo, ColumnType, ColumnTypeError, ConstColumn, Dataset, InferColumns, InferDataset, InferRoot, InvalidXmlError, NexaVersion, Parameter, RequestOf, ResponseOf, Row, RowType, Rows, StringWritableStream, XapiColumnSchema, XapiColumns, XapiDatasetSchema, XapiDatasets, XapiOperation, XapiOptions, XapiParameters, XapiRoot, XapiRootSchema, XapiTypeMap, XapiValueType, XapiVersion, XmlNode, XmlStringBuilder, XplatformVersion, _unescapeXml, arrayBufferToString, base64ToUint8Array, columnType, convertToColumnType, convertToString, dateToString, decodeRoot, defineDataset, defineOperation, defineRoot, encodeControlChars, encodeRoot, escapeXml, initXapi, isXapiRoot, makeParseEntities, parse, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, xapi };
package/dist/index.js CHANGED
@@ -50,7 +50,6 @@ var InvalidXmlError = class extends Error {
50
50
  this.name = "InvalidXmlError";
51
51
  }
52
52
  };
53
-
54
53
  //#endregion
55
54
  //#region src/xapi-data.ts
56
55
  /**
@@ -316,23 +315,30 @@ var Dataset = class {
316
315
  return this.rows.length;
317
316
  }
318
317
  };
319
-
320
318
  //#endregion
321
319
  //#region src/utils.ts
322
320
  function arrayBufferToString(buffer) {
323
321
  return new TextDecoder().decode(buffer);
324
322
  }
325
323
  /**
326
- * Creates an array of entities for parsing XML, including control characters.
327
- * @returns An array of objects, each with an `entity` (e.g., "&#1;") and its `value` (e.g., "\x01").
324
+ * Pre-defined XML entities for parsing, including control characters.
325
+ * Static array to avoid repeated allocation.
328
326
  */
329
- function makeParseEntities() {
330
- const entities$1 = [];
331
- for (let i = 1; i <= 32; i++) entities$1.push({
327
+ const PARSE_ENTITIES = (() => {
328
+ const entities = [];
329
+ for (let i = 1; i <= 32; i++) entities.push({
332
330
  entity: `&#${i};`,
333
331
  value: String.fromCharCode(i)
334
332
  });
335
- return entities$1;
333
+ return entities;
334
+ })();
335
+ /**
336
+ * Creates an array of entities for parsing XML, including control characters.
337
+ * @deprecated Use PARSE_ENTITIES directly for better performance
338
+ * @returns An array of objects, each with an `entity` (e.g., "&#1;") and its `value` (e.g., "\x01").
339
+ */
340
+ function makeParseEntities() {
341
+ return PARSE_ENTITIES.slice();
336
342
  }
337
343
  /**
338
344
  * Converts a Base64 string to a Uint8Array.
@@ -461,10 +467,10 @@ function stringToReadableStream(str) {
461
467
  function convertToColumnType(value, type) {
462
468
  switch (type) {
463
469
  case "INT":
464
- case "BIGDECIMAL":
465
470
  const intValue = parseInt(value, 10);
466
471
  return isNaN(intValue) ? value : intValue;
467
472
  case "FLOAT":
473
+ case "BIGDECIMAL":
468
474
  const floatValue = parseFloat(value);
469
475
  return isNaN(floatValue) ? value : floatValue;
470
476
  case "DECIMAL":
@@ -502,14 +508,21 @@ function convertToString(value, type) {
502
508
  default: return String(value);
503
509
  }
504
510
  }
505
- const entities = makeParseEntities();
511
+ /**
512
+ * Pre-compiled regex for control character entities.
513
+ * Created once to avoid repeated compilation.
514
+ */
515
+ const CONTROL_CHAR_ENTITY_REGEX = new RegExp(PARSE_ENTITIES.map((e) => e.entity.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "g");
516
+ /**
517
+ * Map for fast entity lookup during decoding.
518
+ */
519
+ const ENTITY_MAP = new Map(PARSE_ENTITIES.map((e) => [e.entity, e.value]));
506
520
  function _unescapeXml(str) {
507
521
  if (!str) return str;
522
+ if (str.indexOf("&") === -1) return str;
508
523
  let result = str.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"").replace(/&apos;/g, "'").replace(/&amp;/g, "&");
509
- const regex = new RegExp(entities.map((e) => e.entity).join("|"), "g");
510
- result = result.replace(regex, (match) => {
511
- const entity = entities.find((e) => e.entity === match);
512
- return entity ? entity.value : match;
524
+ result = result.replace(CONTROL_CHAR_ENTITY_REGEX, (match) => {
525
+ return ENTITY_MAP.get(match) || match;
513
526
  });
514
527
  return result;
515
528
  }
@@ -620,6 +633,18 @@ function parseXml(xml) {
620
633
  return new XapiXmlParser(xml).parse();
621
634
  }
622
635
  /**
636
+ * Character codes for fast comparison
637
+ */
638
+ const CHAR_SPACE = 32;
639
+ const CHAR_TAB = 9;
640
+ const CHAR_LF = 10;
641
+ const CHAR_CR = 13;
642
+ const CHAR_GT = 62;
643
+ const CHAR_SLASH = 47;
644
+ const CHAR_EQUALS = 61;
645
+ const CHAR_QUOTE = 34;
646
+ const CHAR_APOS = 39;
647
+ /**
623
648
  * A lightweight XML parser optimized for X-API structure.
624
649
  */
625
650
  var XapiXmlParser = class {
@@ -635,12 +660,12 @@ var XapiXmlParser = class {
635
660
  while (this.pos < this.length) {
636
661
  this.skipWhitespace();
637
662
  if (this.pos >= this.length) break;
638
- if (this.peek(5) === "<?xml") {
663
+ if (this.matches("<?xml")) {
639
664
  this.skipUntil("?>");
640
665
  this.pos += 2;
641
666
  continue;
642
667
  }
643
- if (this.peek(4) === "<!--") {
668
+ if (this.matches("<!--")) {
644
669
  this.skipUntil("-->");
645
670
  this.pos += 3;
646
671
  continue;
@@ -658,11 +683,15 @@ var XapiXmlParser = class {
658
683
  if (this.current() === "/") return null;
659
684
  const tagName = this.parseTagName();
660
685
  if (!tagName) return null;
661
- const node = { tagName };
686
+ const node = {
687
+ tagName,
688
+ attributes: void 0,
689
+ children: void 0
690
+ };
662
691
  const attributes = this.parseAttributes();
663
692
  if (attributes && Object.keys(attributes).length > 0) node.attributes = attributes;
664
693
  this.skipWhitespace();
665
- if (this.peek(2) === "/>") {
694
+ if (this.matches("/>")) {
666
695
  this.pos += 2;
667
696
  return node;
668
697
  }
@@ -670,12 +699,12 @@ var XapiXmlParser = class {
670
699
  const children = [];
671
700
  let textContent = "";
672
701
  while (this.pos < this.length) {
673
- if (this.peek(9) === "<![CDATA[") {
702
+ if (this.matches("<![CDATA[")) {
674
703
  const cdataText = this.parseCDATA();
675
704
  if (cdataText !== null) textContent += cdataText;
676
705
  continue;
677
706
  }
678
- if (this.peek(2) === "</") {
707
+ if (this.matches("</")) {
679
708
  if (textContent) children.push(textContent);
680
709
  this.pos += 2;
681
710
  this.skipUntil(">");
@@ -698,21 +727,20 @@ var XapiXmlParser = class {
698
727
  return node;
699
728
  }
700
729
  parseTagName() {
701
- let name = "";
730
+ const start = this.pos;
702
731
  while (this.pos < this.length) {
703
- const ch = this.current();
704
- if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === ">" || ch === "/") break;
705
- name += ch;
732
+ const code = this.currentCharCode();
733
+ if (this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
706
734
  this.pos++;
707
735
  }
708
- return name;
736
+ return this.xml.substring(start, this.pos);
709
737
  }
710
738
  parseAttributes() {
711
739
  const attrs = {};
712
740
  while (this.pos < this.length) {
713
741
  this.skipWhitespace();
714
742
  const ch = this.current();
715
- if (ch === ">" || ch === "/" || this.peek(2) === "/>") break;
743
+ if (ch === ">" || ch === "/" || this.matches("/>")) break;
716
744
  const attrName = this.parseAttributeName();
717
745
  if (!attrName) break;
718
746
  this.skipWhitespace();
@@ -723,74 +751,95 @@ var XapiXmlParser = class {
723
751
  return Object.keys(attrs).length > 0 ? attrs : void 0;
724
752
  }
725
753
  parseAttributeName() {
726
- let name = "";
754
+ const start = this.pos;
727
755
  while (this.pos < this.length) {
728
- const ch = this.current();
729
- if (ch === "=" || ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === ">" || ch === "/") break;
730
- name += ch;
756
+ const code = this.currentCharCode();
757
+ if (code === CHAR_EQUALS || this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
731
758
  this.pos++;
732
759
  }
733
- return name;
760
+ return this.xml.substring(start, this.pos);
734
761
  }
735
762
  parseAttributeValue() {
736
- let value = "";
737
- const quote = this.current();
738
- if (quote !== "\"" && quote !== "'") {
763
+ const quoteCode = this.currentCharCode();
764
+ if (quoteCode !== CHAR_QUOTE && quoteCode !== CHAR_APOS) {
765
+ const start = this.pos;
739
766
  while (this.pos < this.length) {
740
- const ch = this.current();
741
- if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === ">" || ch === "/") break;
742
- value += ch;
767
+ const code = this.currentCharCode();
768
+ if (this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
743
769
  this.pos++;
744
770
  }
745
- return value;
771
+ return this.xml.substring(start, this.pos);
746
772
  }
747
773
  this.pos++;
774
+ const start = this.pos;
748
775
  while (this.pos < this.length) {
749
- const ch = this.current();
750
- if (ch === quote) {
776
+ if (this.currentCharCode() === quoteCode) {
777
+ const value = this.xml.substring(start, this.pos);
751
778
  this.pos++;
752
- break;
779
+ return value;
753
780
  }
754
- value += ch;
755
781
  this.pos++;
756
782
  }
757
- return value;
783
+ return this.xml.substring(start, this.pos);
758
784
  }
759
785
  parseCDATA() {
760
- if (this.peek(9) !== "<![CDATA[") return null;
786
+ if (!this.matches("<![CDATA[")) return null;
761
787
  this.pos += 9;
762
- let content = "";
763
- while (this.pos < this.length) {
764
- if (this.peek(3) === "]]>") {
765
- this.pos += 3;
766
- break;
767
- }
768
- content += this.current();
769
- this.pos++;
788
+ const endPos = this.findString("]]>");
789
+ if (endPos === -1) {
790
+ const content = this.xml.substring(this.pos);
791
+ this.pos = this.length;
792
+ return content;
770
793
  }
794
+ const content = this.xml.substring(this.pos, endPos);
795
+ this.pos = endPos + 3;
771
796
  return content;
772
797
  }
773
798
  skipWhitespace() {
774
799
  while (this.pos < this.length) {
775
- const ch = this.current();
776
- if (ch !== " " && ch !== " " && ch !== "\n" && ch !== "\r") break;
800
+ const code = this.currentCharCode();
801
+ if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
777
802
  this.pos++;
778
803
  }
779
804
  }
805
+ isWhitespace(code) {
806
+ return code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR;
807
+ }
780
808
  skipUntil(target) {
781
- while (this.pos < this.length) {
782
- if (this.peek(target.length) === target) break;
783
- this.pos++;
784
- }
809
+ const pos = this.findString(target);
810
+ if (pos !== -1) this.pos = pos;
811
+ else this.pos = this.length;
785
812
  }
786
813
  current() {
787
814
  return this.xml[this.pos];
788
815
  }
789
- peek(length) {
790
- return this.xml.substring(this.pos, this.pos + length);
816
+ currentCharCode() {
817
+ return this.xml.charCodeAt(this.pos);
818
+ }
819
+ /**
820
+ * Checks if the string at the given position matches the target string.
821
+ * This avoids creating substring instances for comparison.
822
+ * @param str - The target string to match
823
+ * @param pos - The position to check from (default: current position)
824
+ */
825
+ matches(str, pos = this.pos) {
826
+ const len = str.length;
827
+ if (pos + len > this.length) return false;
828
+ for (let i = 0; i < len; i++) if (this.xml.charCodeAt(pos + i) !== str.charCodeAt(i)) return false;
829
+ return true;
830
+ }
831
+ /**
832
+ * Finds the position of a target string starting from the given position.
833
+ * @param str - The string to find
834
+ * @param startPos - Starting position (default: current position)
835
+ * @returns The position where the string is found, or -1 if not found
836
+ */
837
+ findString(str, startPos = this.pos) {
838
+ const maxPos = this.length - str.length;
839
+ for (let pos = startPos; pos <= maxPos; pos++) if (this.matches(str, pos)) return pos;
840
+ return -1;
791
841
  }
792
842
  };
793
-
794
843
  //#endregion
795
844
  //#region src/handler.ts
796
845
  let _options = {
@@ -825,28 +874,31 @@ function parse(xml) {
825
874
  if (typeof child === "string") continue;
826
875
  const tagName = child.tagName;
827
876
  if (tagName === "Parameters") parseParameters(child, xapiRoot);
828
- else if (tagName === "Dataset") {
829
- if (!child.attributes || !child.attributes.id) throw new InvalidXmlError("Dataset element must have an 'id' attribute");
830
- const datasetId = child.attributes.id;
831
- const dataset = new Dataset(datasetId);
832
- xapiRoot.addDataset(dataset);
833
- const datasetChildren = child.children;
834
- let columnInfoElement;
835
- let rowsElement;
836
- if (datasetChildren) for (let j = 0; j < datasetChildren.length; j++) {
837
- const datasetChild = datasetChildren[j];
838
- if (typeof datasetChild === "string") continue;
839
- const childTagName = datasetChild.tagName;
840
- if (childTagName === "ColumnInfo") columnInfoElement = datasetChild;
841
- else if (childTagName === "Rows") rowsElement = datasetChild;
842
- if (columnInfoElement && rowsElement) break;
843
- }
844
- parseColumnInfo(columnInfoElement, dataset);
845
- parseRows(rowsElement, dataset);
846
- }
877
+ else if (tagName === "Datasets") {
878
+ for (const datasetElement of child.children ?? []) if (typeof datasetElement !== "string" && datasetElement.tagName === "Dataset") parseDataset(datasetElement, xapiRoot);
879
+ } else if (tagName === "Dataset") parseDataset(child, xapiRoot);
847
880
  }
848
881
  return xapiRoot;
849
882
  }
883
+ function parseDataset(child, xapiRoot) {
884
+ if (!child.attributes || !child.attributes.id) throw new InvalidXmlError("Dataset element must have an 'id' attribute");
885
+ const datasetId = child.attributes.id;
886
+ const dataset = new Dataset(datasetId);
887
+ xapiRoot.addDataset(dataset);
888
+ const datasetChildren = child.children;
889
+ let columnInfoElement;
890
+ let rowsElement;
891
+ if (datasetChildren) for (let j = 0; j < datasetChildren.length; j++) {
892
+ const datasetChild = datasetChildren[j];
893
+ if (typeof datasetChild === "string") continue;
894
+ const childTagName = datasetChild.tagName;
895
+ if (childTagName === "ColumnInfo") columnInfoElement = datasetChild;
896
+ else if (childTagName === "Rows") rowsElement = datasetChild;
897
+ if (columnInfoElement && rowsElement) break;
898
+ }
899
+ parseColumnInfo(columnInfoElement, dataset);
900
+ parseRows(rowsElement, dataset);
901
+ }
850
902
  function parseValue(value, type = "STRING") {
851
903
  value = _unescapeXml(value);
852
904
  return _options.parseToTypes ? convertToColumnType(value, type) : value;
@@ -942,7 +994,7 @@ function parseParameters(parametersElement, xapiRoot) {
942
994
  const attrs = p.attributes;
943
995
  const id = attrs?.id;
944
996
  const type = attrs?.type || "STRING";
945
- const value = p.children?.[0];
997
+ const value = p.children?.[0] ?? attrs?.value;
946
998
  xapiRoot.addParameter({
947
999
  id,
948
1000
  type,
@@ -1020,6 +1072,110 @@ function writeColumn(builder, dataset, col) {
1020
1072
  builder.writeElementWithText("Col", { id: col.id }, convertToString(col.value, colInfo.type));
1021
1073
  } else builder.writeStartElement("Col", { id: col.id }, true);
1022
1074
  }
1023
-
1024
1075
  //#endregion
1025
- export { ColumnTypeError, Dataset, InvalidXmlError, NexaVersion, StringWritableStream, XapiRoot, XmlStringBuilder, XplatformVersion, _unescapeXml, arrayBufferToString, base64ToUint8Array, columnType, convertToColumnType, convertToString, dateToString, encodeControlChars, escapeXml, initXapi, isXapiRoot, makeParseEntities, parse, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write };
1076
+ //#region src/schema.ts
1077
+ const defaultSizes = {
1078
+ STRING: 256,
1079
+ INT: 10,
1080
+ FLOAT: 20,
1081
+ DECIMAL: 20,
1082
+ BIGDECIMAL: 30,
1083
+ DATE: 8,
1084
+ DATETIME: 17,
1085
+ TIME: 6,
1086
+ BLOB: 1e3
1087
+ };
1088
+ function column(type, options = {}) {
1089
+ return {
1090
+ kind: "xapi-column",
1091
+ type,
1092
+ size: options.size ?? defaultSizes[type],
1093
+ optional: options.optional ?? false
1094
+ };
1095
+ }
1096
+ function defineDataset(columns) {
1097
+ return {
1098
+ kind: "xapi-dataset",
1099
+ columns
1100
+ };
1101
+ }
1102
+ function defineRoot(definition) {
1103
+ return {
1104
+ kind: "xapi-root",
1105
+ datasets: definition.datasets,
1106
+ parameters: definition.parameters ?? {}
1107
+ };
1108
+ }
1109
+ function defineOperation(definition) {
1110
+ return {
1111
+ kind: "xapi-operation",
1112
+ ...definition
1113
+ };
1114
+ }
1115
+ const xapi = {
1116
+ string: (options) => column("STRING", options),
1117
+ int: (options) => column("INT", options),
1118
+ float: (options) => column("FLOAT", options),
1119
+ decimal: (options) => column("DECIMAL", options),
1120
+ bigdecimal: (options) => column("BIGDECIMAL", options),
1121
+ date: (options) => column("DATE", options),
1122
+ datetime: (options) => column("DATETIME", options),
1123
+ time: (options) => column("TIME", options),
1124
+ blob: (options) => column("BLOB", options),
1125
+ dataset: defineDataset,
1126
+ root: defineRoot,
1127
+ operation: defineOperation
1128
+ };
1129
+ function encodeRoot(schema, value) {
1130
+ const root = new XapiRoot();
1131
+ for (const [id, parameterSchema] of Object.entries(schema.parameters)) {
1132
+ const parameterValue = value.parameters[id];
1133
+ if (parameterValue !== void 0 || !parameterSchema.optional) root.addParameter({
1134
+ id,
1135
+ type: parameterSchema.type,
1136
+ value: parameterValue
1137
+ });
1138
+ }
1139
+ for (const [datasetId, datasetSchema] of Object.entries(schema.datasets)) {
1140
+ const dataset = new Dataset(datasetId);
1141
+ for (const [id, columnSchema] of Object.entries(datasetSchema.columns)) dataset.addColumn({
1142
+ id,
1143
+ type: columnSchema.type,
1144
+ size: columnSchema.size
1145
+ });
1146
+ const rows = value.datasets[datasetId];
1147
+ for (const row of rows) {
1148
+ const rowIndex = dataset.newRow();
1149
+ for (const id of Object.keys(datasetSchema.columns)) dataset.setColumn(rowIndex, id, row[id]);
1150
+ }
1151
+ root.addDataset(dataset);
1152
+ }
1153
+ return root;
1154
+ }
1155
+ function decodeRoot(schema, root) {
1156
+ const parameters = {};
1157
+ for (const id of Object.keys(schema.parameters)) {
1158
+ const value = root.getParameter(id)?.value;
1159
+ if (value !== void 0) parameters[id] = value;
1160
+ }
1161
+ const datasets = {};
1162
+ for (const [datasetId, datasetSchema] of Object.entries(schema.datasets)) {
1163
+ const dataset = root.getDataset(datasetId);
1164
+ if (!dataset) {
1165
+ datasets[datasetId] = [];
1166
+ continue;
1167
+ }
1168
+ const constants = Object.fromEntries(dataset.getConstColumns().map(({ id, value }) => [id, value]));
1169
+ datasets[datasetId] = dataset.getRows().map((row) => {
1170
+ const value = { ...constants };
1171
+ for (const column of row.cols) if (column.id in datasetSchema.columns) value[column.id] = column.value;
1172
+ return value;
1173
+ });
1174
+ }
1175
+ return {
1176
+ parameters,
1177
+ datasets
1178
+ };
1179
+ }
1180
+ //#endregion
1181
+ export { ColumnTypeError, Dataset, InvalidXmlError, NexaVersion, StringWritableStream, XapiRoot, XmlStringBuilder, XplatformVersion, _unescapeXml, arrayBufferToString, base64ToUint8Array, columnType, convertToColumnType, convertToString, dateToString, decodeRoot, defineDataset, defineOperation, defineRoot, encodeControlChars, encodeRoot, escapeXml, initXapi, isXapiRoot, makeParseEntities, parse, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, xapi };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xapi-js/core",
3
3
  "type": "module",
4
- "version": "1.3.0",
4
+ "version": "1.4.1",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "author": "Clickin <josh87786@gmail.com>",
30
30
  "devDependencies": {
31
31
  "@types/node": "^20.11.24",
32
- "typescript": "^5.3.3"
32
+ "typescript": "^7.0.2"
33
33
  },
34
34
  "scripts": {
35
35
  "build": "tsdown",