@xapi-js/core 1.4.1 → 1.6.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.cjs +301 -162
- package/dist/index.d.cts +49 -2
- package/dist/index.d.ts +49 -2
- package/dist/index.js +299 -163
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -522,9 +522,7 @@ function _unescapeXml(str) {
|
|
|
522
522
|
if (!str) return str;
|
|
523
523
|
if (str.indexOf("&") === -1) return str;
|
|
524
524
|
let result = str.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'").replace(/&/g, "&");
|
|
525
|
-
result = result.replace(CONTROL_CHAR_ENTITY_REGEX, (match) =>
|
|
526
|
-
return ENTITY_MAP.get(match) || match;
|
|
527
|
-
});
|
|
525
|
+
result = result.replace(CONTROL_CHAR_ENTITY_REGEX, (match) => ENTITY_MAP.get(match));
|
|
528
526
|
return result;
|
|
529
527
|
}
|
|
530
528
|
function isXapiRoot(value) {
|
|
@@ -630,7 +628,7 @@ var XmlStringBuilder = class {
|
|
|
630
628
|
* @returns An array of parsed XML nodes.
|
|
631
629
|
*/
|
|
632
630
|
function parseXml(xml) {
|
|
633
|
-
if (!xml
|
|
631
|
+
if (!xml) return [];
|
|
634
632
|
return new XapiXmlParser(xml).parse();
|
|
635
633
|
}
|
|
636
634
|
/**
|
|
@@ -645,6 +643,50 @@ const CHAR_SLASH = 47;
|
|
|
645
643
|
const CHAR_EQUALS = 61;
|
|
646
644
|
const CHAR_QUOTE = 34;
|
|
647
645
|
const CHAR_APOS = 39;
|
|
646
|
+
/** Reuse the small, fixed X-API vocabulary instead of allocating a name per node. */
|
|
647
|
+
function xapiXmlName(xml, start, end) {
|
|
648
|
+
switch (end - start) {
|
|
649
|
+
case 2:
|
|
650
|
+
if (xml.startsWith("id", start)) return "id";
|
|
651
|
+
break;
|
|
652
|
+
case 3:
|
|
653
|
+
if (xml.startsWith("Col", start)) return "Col";
|
|
654
|
+
if (xml.startsWith("Row", start)) return "Row";
|
|
655
|
+
break;
|
|
656
|
+
case 4:
|
|
657
|
+
if (xml.startsWith("Root", start)) return "Root";
|
|
658
|
+
if (xml.startsWith("Rows", start)) return "Rows";
|
|
659
|
+
if (xml.startsWith("size", start)) return "size";
|
|
660
|
+
if (xml.startsWith("type", start)) return "type";
|
|
661
|
+
break;
|
|
662
|
+
case 5:
|
|
663
|
+
if (xml.startsWith("value", start)) return "value";
|
|
664
|
+
if (xml.startsWith("xmlns", start)) return "xmlns";
|
|
665
|
+
break;
|
|
666
|
+
case 6:
|
|
667
|
+
if (xml.startsWith("Column", start)) return "Column";
|
|
668
|
+
if (xml.startsWith("OrgRow", start)) return "OrgRow";
|
|
669
|
+
break;
|
|
670
|
+
case 7:
|
|
671
|
+
if (xml.startsWith("Dataset", start)) return "Dataset";
|
|
672
|
+
if (xml.startsWith("version", start)) return "version";
|
|
673
|
+
break;
|
|
674
|
+
case 8:
|
|
675
|
+
if (xml.startsWith("Datasets", start)) return "Datasets";
|
|
676
|
+
break;
|
|
677
|
+
case 9:
|
|
678
|
+
if (xml.startsWith("Parameter", start)) return "Parameter";
|
|
679
|
+
break;
|
|
680
|
+
case 10:
|
|
681
|
+
if (xml.startsWith("ColumnInfo", start)) return "ColumnInfo";
|
|
682
|
+
if (xml.startsWith("Parameters", start)) return "Parameters";
|
|
683
|
+
break;
|
|
684
|
+
case 11:
|
|
685
|
+
if (xml.startsWith("ConstColumn", start)) return "ConstColumn";
|
|
686
|
+
break;
|
|
687
|
+
}
|
|
688
|
+
return xml.substring(start, end);
|
|
689
|
+
}
|
|
648
690
|
/**
|
|
649
691
|
* A lightweight XML parser optimized for X-API structure.
|
|
650
692
|
*/
|
|
@@ -658,20 +700,26 @@ var XapiXmlParser = class {
|
|
|
658
700
|
}
|
|
659
701
|
parse() {
|
|
660
702
|
const nodes = [];
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
this.
|
|
666
|
-
|
|
703
|
+
const xml = this.xml;
|
|
704
|
+
const length = this.length;
|
|
705
|
+
while (this.pos < length) {
|
|
706
|
+
while (this.pos < length) {
|
|
707
|
+
const code = xml.charCodeAt(this.pos);
|
|
708
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
709
|
+
this.pos++;
|
|
710
|
+
}
|
|
711
|
+
if (this.pos >= length) break;
|
|
712
|
+
if (xml.startsWith("<?xml", this.pos)) {
|
|
713
|
+
const end = xml.indexOf("?>", this.pos + 5);
|
|
714
|
+
this.pos = end < 0 ? length : end + 2;
|
|
667
715
|
continue;
|
|
668
716
|
}
|
|
669
|
-
if (
|
|
670
|
-
|
|
671
|
-
this.pos
|
|
717
|
+
if (xml.startsWith("<!--", this.pos)) {
|
|
718
|
+
const end = xml.indexOf("-->", this.pos + 4);
|
|
719
|
+
this.pos = end < 0 ? length : end + 3;
|
|
672
720
|
continue;
|
|
673
721
|
}
|
|
674
|
-
if (this.
|
|
722
|
+
if (xml.charCodeAt(this.pos) === 60) {
|
|
675
723
|
const node = this.parseElement();
|
|
676
724
|
if (node) nodes.push(node);
|
|
677
725
|
} else this.pos++;
|
|
@@ -679,10 +727,17 @@ var XapiXmlParser = class {
|
|
|
679
727
|
return nodes;
|
|
680
728
|
}
|
|
681
729
|
parseElement() {
|
|
682
|
-
|
|
730
|
+
const xml = this.xml;
|
|
731
|
+
const length = this.length;
|
|
683
732
|
this.pos++;
|
|
684
|
-
if (this.
|
|
685
|
-
const
|
|
733
|
+
if (xml.charCodeAt(this.pos) === CHAR_SLASH) return null;
|
|
734
|
+
const nameStart = this.pos;
|
|
735
|
+
while (this.pos < length) {
|
|
736
|
+
const code = xml.charCodeAt(this.pos);
|
|
737
|
+
if (code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
738
|
+
this.pos++;
|
|
739
|
+
}
|
|
740
|
+
const tagName = xapiXmlName(xml, nameStart, this.pos);
|
|
686
741
|
if (!tagName) return null;
|
|
687
742
|
const node = {
|
|
688
743
|
tagName,
|
|
@@ -690,155 +745,110 @@ var XapiXmlParser = class {
|
|
|
690
745
|
children: void 0
|
|
691
746
|
};
|
|
692
747
|
const attributes = this.parseAttributes();
|
|
693
|
-
if (attributes
|
|
694
|
-
this.
|
|
695
|
-
if (this.matches("/>")) {
|
|
748
|
+
if (attributes) node.attributes = attributes;
|
|
749
|
+
if (xml.charCodeAt(this.pos) === CHAR_SLASH && xml.charCodeAt(this.pos + 1) === CHAR_GT) {
|
|
696
750
|
this.pos += 2;
|
|
697
751
|
return node;
|
|
698
752
|
}
|
|
699
|
-
if (this.
|
|
700
|
-
|
|
753
|
+
if (xml.charCodeAt(this.pos) === CHAR_GT) this.pos++;
|
|
754
|
+
let children;
|
|
701
755
|
let textContent = "";
|
|
702
|
-
while (this.pos <
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
756
|
+
while (this.pos < length) {
|
|
757
|
+
const markup = xml.indexOf("<", this.pos);
|
|
758
|
+
if (markup < 0) {
|
|
759
|
+
this.pos = length;
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
if (markup > this.pos) {
|
|
763
|
+
const text = xml.substring(this.pos, markup);
|
|
764
|
+
textContent = textContent ? textContent + text : text;
|
|
765
|
+
this.pos = markup;
|
|
766
|
+
}
|
|
767
|
+
if (xml.startsWith("<![CDATA[", this.pos)) {
|
|
768
|
+
const start = this.pos + 9;
|
|
769
|
+
const end = xml.indexOf("]]>", start);
|
|
770
|
+
if (end < 0) {
|
|
771
|
+
textContent += xml.substring(start);
|
|
772
|
+
this.pos = length;
|
|
773
|
+
break;
|
|
774
|
+
}
|
|
775
|
+
textContent += xml.substring(start, end);
|
|
776
|
+
this.pos = end + 3;
|
|
706
777
|
continue;
|
|
707
778
|
}
|
|
708
|
-
if (this.
|
|
709
|
-
if (textContent) children.push(textContent);
|
|
779
|
+
if (xml.charCodeAt(this.pos + 1) === CHAR_SLASH) {
|
|
780
|
+
if (textContent && (!children || textContent.trim())) (children ??= []).push(textContent);
|
|
710
781
|
this.pos += 2;
|
|
711
|
-
|
|
712
|
-
this.pos
|
|
782
|
+
const end = xml.indexOf(">", this.pos);
|
|
783
|
+
this.pos = end < 0 ? length : end + 1;
|
|
713
784
|
break;
|
|
714
785
|
}
|
|
715
|
-
if (
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
}
|
|
720
|
-
const child = this.parseElement();
|
|
721
|
-
if (child) children.push(child);
|
|
722
|
-
} else {
|
|
723
|
-
textContent += this.current();
|
|
724
|
-
this.pos++;
|
|
786
|
+
if (xml.startsWith("<!--", this.pos)) {
|
|
787
|
+
const end = xml.indexOf("-->", this.pos + 4);
|
|
788
|
+
this.pos = end < 0 ? length : end + 3;
|
|
789
|
+
continue;
|
|
725
790
|
}
|
|
791
|
+
if (textContent && textContent.trim()) (children ??= []).push(textContent);
|
|
792
|
+
textContent = "";
|
|
793
|
+
const child = this.parseElement();
|
|
794
|
+
if (child) (children ??= []).push(child);
|
|
726
795
|
}
|
|
727
|
-
if (children
|
|
796
|
+
if (children) node.children = children;
|
|
728
797
|
return node;
|
|
729
798
|
}
|
|
730
|
-
parseTagName() {
|
|
731
|
-
const start = this.pos;
|
|
732
|
-
while (this.pos < this.length) {
|
|
733
|
-
const code = this.currentCharCode();
|
|
734
|
-
if (this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
735
|
-
this.pos++;
|
|
736
|
-
}
|
|
737
|
-
return this.xml.substring(start, this.pos);
|
|
738
|
-
}
|
|
739
799
|
parseAttributes() {
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
800
|
+
const xml = this.xml;
|
|
801
|
+
const length = this.length;
|
|
802
|
+
let attrs;
|
|
803
|
+
while (this.pos < length) {
|
|
804
|
+
while (this.pos < length) {
|
|
805
|
+
const code = xml.charCodeAt(this.pos);
|
|
806
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
807
|
+
this.pos++;
|
|
808
|
+
}
|
|
809
|
+
const code = xml.charCodeAt(this.pos);
|
|
810
|
+
if (code === CHAR_GT || code === CHAR_SLASH) break;
|
|
811
|
+
const nameStart = this.pos;
|
|
812
|
+
while (this.pos < length) {
|
|
813
|
+
const code = xml.charCodeAt(this.pos);
|
|
814
|
+
if (code === CHAR_EQUALS || code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
815
|
+
this.pos++;
|
|
816
|
+
}
|
|
817
|
+
const attrName = xapiXmlName(xml, nameStart, this.pos);
|
|
746
818
|
if (!attrName) break;
|
|
747
|
-
this.
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
attrs[attrName] = this.parseAttributeValue();
|
|
751
|
-
}
|
|
752
|
-
return Object.keys(attrs).length > 0 ? attrs : void 0;
|
|
753
|
-
}
|
|
754
|
-
parseAttributeName() {
|
|
755
|
-
const start = this.pos;
|
|
756
|
-
while (this.pos < this.length) {
|
|
757
|
-
const code = this.currentCharCode();
|
|
758
|
-
if (code === CHAR_EQUALS || this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
759
|
-
this.pos++;
|
|
760
|
-
}
|
|
761
|
-
return this.xml.substring(start, this.pos);
|
|
762
|
-
}
|
|
763
|
-
parseAttributeValue() {
|
|
764
|
-
const quoteCode = this.currentCharCode();
|
|
765
|
-
if (quoteCode !== CHAR_QUOTE && quoteCode !== CHAR_APOS) {
|
|
766
|
-
const start = this.pos;
|
|
767
|
-
while (this.pos < this.length) {
|
|
768
|
-
const code = this.currentCharCode();
|
|
769
|
-
if (this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
819
|
+
while (this.pos < length) {
|
|
820
|
+
const code = xml.charCodeAt(this.pos);
|
|
821
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
770
822
|
this.pos++;
|
|
771
823
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
while (this.pos < this.length) {
|
|
777
|
-
if (this.currentCharCode() === quoteCode) {
|
|
778
|
-
const value = this.xml.substring(start, this.pos);
|
|
824
|
+
if (xml.charCodeAt(this.pos) === CHAR_EQUALS) this.pos++;
|
|
825
|
+
while (this.pos < length) {
|
|
826
|
+
const code = xml.charCodeAt(this.pos);
|
|
827
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
779
828
|
this.pos++;
|
|
780
|
-
return value;
|
|
781
829
|
}
|
|
782
|
-
this.pos
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
803
|
-
this.pos++;
|
|
830
|
+
const quote = xml.charCodeAt(this.pos);
|
|
831
|
+
let valueStart;
|
|
832
|
+
let valueEnd;
|
|
833
|
+
if (quote === CHAR_QUOTE || quote === CHAR_APOS) {
|
|
834
|
+
valueStart = ++this.pos;
|
|
835
|
+
valueEnd = xml.indexOf(quote === CHAR_QUOTE ? "\"" : "'", valueStart);
|
|
836
|
+
if (valueEnd < 0) {
|
|
837
|
+
valueEnd = length;
|
|
838
|
+
this.pos = length;
|
|
839
|
+
} else this.pos = valueEnd + 1;
|
|
840
|
+
} else {
|
|
841
|
+
valueStart = this.pos;
|
|
842
|
+
while (this.pos < length) {
|
|
843
|
+
const code = xml.charCodeAt(this.pos);
|
|
844
|
+
if (code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
845
|
+
this.pos++;
|
|
846
|
+
}
|
|
847
|
+
valueEnd = this.pos;
|
|
848
|
+
}
|
|
849
|
+
(attrs ??= {})[attrName] = xml.substring(valueStart, valueEnd);
|
|
804
850
|
}
|
|
805
|
-
|
|
806
|
-
isWhitespace(code) {
|
|
807
|
-
return code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR;
|
|
808
|
-
}
|
|
809
|
-
skipUntil(target) {
|
|
810
|
-
const pos = this.findString(target);
|
|
811
|
-
if (pos !== -1) this.pos = pos;
|
|
812
|
-
else this.pos = this.length;
|
|
813
|
-
}
|
|
814
|
-
current() {
|
|
815
|
-
return this.xml[this.pos];
|
|
816
|
-
}
|
|
817
|
-
currentCharCode() {
|
|
818
|
-
return this.xml.charCodeAt(this.pos);
|
|
819
|
-
}
|
|
820
|
-
/**
|
|
821
|
-
* Checks if the string at the given position matches the target string.
|
|
822
|
-
* This avoids creating substring instances for comparison.
|
|
823
|
-
* @param str - The target string to match
|
|
824
|
-
* @param pos - The position to check from (default: current position)
|
|
825
|
-
*/
|
|
826
|
-
matches(str, pos = this.pos) {
|
|
827
|
-
const len = str.length;
|
|
828
|
-
if (pos + len > this.length) return false;
|
|
829
|
-
for (let i = 0; i < len; i++) if (this.xml.charCodeAt(pos + i) !== str.charCodeAt(i)) return false;
|
|
830
|
-
return true;
|
|
831
|
-
}
|
|
832
|
-
/**
|
|
833
|
-
* Finds the position of a target string starting from the given position.
|
|
834
|
-
* @param str - The string to find
|
|
835
|
-
* @param startPos - Starting position (default: current position)
|
|
836
|
-
* @returns The position where the string is found, or -1 if not found
|
|
837
|
-
*/
|
|
838
|
-
findString(str, startPos = this.pos) {
|
|
839
|
-
const maxPos = this.length - str.length;
|
|
840
|
-
for (let pos = startPos; pos <= maxPos; pos++) if (this.matches(str, pos)) return pos;
|
|
841
|
-
return -1;
|
|
851
|
+
return attrs;
|
|
842
852
|
}
|
|
843
853
|
};
|
|
844
854
|
//#endregion
|
|
@@ -934,7 +944,6 @@ function parseColumnInfo(columnInfoElement, dataset) {
|
|
|
934
944
|
}
|
|
935
945
|
}
|
|
936
946
|
function parseRows(rowsElement, dataset) {
|
|
937
|
-
if (typeof rowsElement === "string") return;
|
|
938
947
|
const rows = rowsElement?.children;
|
|
939
948
|
if (!rows) return;
|
|
940
949
|
const datasetRows = dataset.rows;
|
|
@@ -985,8 +994,6 @@ function parseRows(rowsElement, dataset) {
|
|
|
985
994
|
}
|
|
986
995
|
}
|
|
987
996
|
function parseParameters(parametersElement, xapiRoot) {
|
|
988
|
-
if (typeof parametersElement === "string") return;
|
|
989
|
-
if (!parametersElement) return;
|
|
990
997
|
const children = parametersElement.children;
|
|
991
998
|
if (!children) return;
|
|
992
999
|
for (let i = 0; i < children.length; i++) {
|
|
@@ -1021,19 +1028,17 @@ function write(root) {
|
|
|
1021
1028
|
return builder.toString();
|
|
1022
1029
|
}
|
|
1023
1030
|
function writeParameters(builder, parameters) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
builder.writeEndElement("Parameters");
|
|
1036
|
-
}
|
|
1031
|
+
builder.writeStartElement("Parameters");
|
|
1032
|
+
for (const parameter of parameters) {
|
|
1033
|
+
const attrs = { id: parameter.id };
|
|
1034
|
+
if (parameter.type !== void 0) attrs.type = parameter.type;
|
|
1035
|
+
if (parameter.value !== void 0) if (typeof parameter.value === "string") attrs.value = parameter.value;
|
|
1036
|
+
else if (parameter.value instanceof Date) attrs.value = dateToString(parameter.value, parameter.type);
|
|
1037
|
+
else if (parameter.value instanceof Uint8Array) attrs.value = uint8ArrayToBase64(parameter.value);
|
|
1038
|
+
else attrs.value = String(parameter.value);
|
|
1039
|
+
builder.writeStartElement("Parameter", attrs, true);
|
|
1040
|
+
}
|
|
1041
|
+
builder.writeEndElement("Parameters");
|
|
1037
1042
|
}
|
|
1038
1043
|
function writeDataset(builder, dataset) {
|
|
1039
1044
|
builder.writeStartElement("Dataset", { id: dataset.id });
|
|
@@ -1147,7 +1152,12 @@ function encodeRoot(schema, value) {
|
|
|
1147
1152
|
const rows = value.datasets[datasetId];
|
|
1148
1153
|
for (const row of rows) {
|
|
1149
1154
|
const rowIndex = dataset.newRow();
|
|
1155
|
+
dataset.rows[rowIndex].type = row.$rowType;
|
|
1150
1156
|
for (const id of Object.keys(datasetSchema.columns)) dataset.setColumn(rowIndex, id, row[id]);
|
|
1157
|
+
if (row.$orgRow) dataset.rows[rowIndex].orgRow = Object.entries(row.$orgRow).map(([id, value]) => ({
|
|
1158
|
+
id,
|
|
1159
|
+
value
|
|
1160
|
+
}));
|
|
1151
1161
|
}
|
|
1152
1162
|
root.addDataset(dataset);
|
|
1153
1163
|
}
|
|
@@ -1170,6 +1180,8 @@ function decodeRoot(schema, root) {
|
|
|
1170
1180
|
datasets[datasetId] = dataset.getRows().map((row) => {
|
|
1171
1181
|
const value = { ...constants };
|
|
1172
1182
|
for (const column of row.cols) if (column.id in datasetSchema.columns) value[column.id] = column.value;
|
|
1183
|
+
if (row.type) value.$rowType = row.type;
|
|
1184
|
+
if (row.orgRow) value.$orgRow = Object.fromEntries(row.orgRow.map((column) => [column.id, column.value]));
|
|
1173
1185
|
return value;
|
|
1174
1186
|
});
|
|
1175
1187
|
}
|
|
@@ -1179,6 +1191,130 @@ function decodeRoot(schema, root) {
|
|
|
1179
1191
|
};
|
|
1180
1192
|
}
|
|
1181
1193
|
//#endregion
|
|
1194
|
+
//#region src/codec.ts
|
|
1195
|
+
const rowTypes = {
|
|
1196
|
+
N: void 0,
|
|
1197
|
+
I: "insert",
|
|
1198
|
+
U: "update",
|
|
1199
|
+
D: "delete",
|
|
1200
|
+
O: void 0
|
|
1201
|
+
};
|
|
1202
|
+
function sizeOf(size, type) {
|
|
1203
|
+
if (size !== void 0) return Number(size);
|
|
1204
|
+
return type === "STRING" ? 255 : 0;
|
|
1205
|
+
}
|
|
1206
|
+
function jsonValue(value, type) {
|
|
1207
|
+
if (value === null || value === void 0) return void 0;
|
|
1208
|
+
if (type === "DATE" || type === "DATETIME" || type === "TIME") return typeof value === "string" ? convertToColumnType(value, type) : value;
|
|
1209
|
+
if (type === "BLOB" && typeof value === "string") return convertToColumnType(value, type);
|
|
1210
|
+
return value;
|
|
1211
|
+
}
|
|
1212
|
+
function jsonWireValue(value, type) {
|
|
1213
|
+
if (value === void 0) return void 0;
|
|
1214
|
+
if (value instanceof Date) return dateToString(value, type);
|
|
1215
|
+
if (value instanceof Uint8Array) return uint8ArrayToBase64(value);
|
|
1216
|
+
return value;
|
|
1217
|
+
}
|
|
1218
|
+
function columnsToObject(columns) {
|
|
1219
|
+
return Object.fromEntries(columns.map((column) => [column.id, column.value]));
|
|
1220
|
+
}
|
|
1221
|
+
function readRow(dataset, row) {
|
|
1222
|
+
const rowType = rowTypes[row._RowType_ ?? "N"];
|
|
1223
|
+
if (row._RowType_ === "O") {
|
|
1224
|
+
const previous = dataset.rows[dataset.rows.length - 1];
|
|
1225
|
+
if (previous?.type !== "update") return;
|
|
1226
|
+
previous.orgRow = dataset.getColumns().filter((column) => Object.prototype.hasOwnProperty.call(row, column.id)).map((column) => ({
|
|
1227
|
+
id: column.id,
|
|
1228
|
+
value: jsonValue(row[column.id], column.type)
|
|
1229
|
+
}));
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
const index = dataset.newRow();
|
|
1233
|
+
dataset.rows[index].type = rowType;
|
|
1234
|
+
for (const column of dataset.getColumns()) if (Object.prototype.hasOwnProperty.call(row, column.id)) dataset.rows[index].cols.push({
|
|
1235
|
+
id: column.id,
|
|
1236
|
+
value: jsonValue(row[column.id], column.type)
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
function readJson(value) {
|
|
1240
|
+
const root = new XapiRoot();
|
|
1241
|
+
for (const parameter of value.Parameters ?? []) root.addParameter({
|
|
1242
|
+
id: parameter.id,
|
|
1243
|
+
type: parameter.type,
|
|
1244
|
+
value: jsonValue(parameter.value, parameter.type)
|
|
1245
|
+
});
|
|
1246
|
+
for (const source of value.Datasets ?? []) {
|
|
1247
|
+
const dataset = new Dataset(source.id);
|
|
1248
|
+
for (const column of source.ColumnInfo.ConstColumn ?? []) {
|
|
1249
|
+
const type = column.type ?? "STRING";
|
|
1250
|
+
dataset.addConstColumn({
|
|
1251
|
+
id: column.id,
|
|
1252
|
+
type,
|
|
1253
|
+
size: sizeOf(column.size, type),
|
|
1254
|
+
value: jsonValue(column.value, type)
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
for (const column of source.ColumnInfo.Column) {
|
|
1258
|
+
const type = column.type ?? "STRING";
|
|
1259
|
+
dataset.addColumn({
|
|
1260
|
+
id: column.id,
|
|
1261
|
+
type,
|
|
1262
|
+
size: sizeOf(column.size, type)
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
for (const row of source.Rows) readRow(dataset, row);
|
|
1266
|
+
root.addDataset(dataset);
|
|
1267
|
+
}
|
|
1268
|
+
return root;
|
|
1269
|
+
}
|
|
1270
|
+
function writeJson(root) {
|
|
1271
|
+
return {
|
|
1272
|
+
version: "1.0",
|
|
1273
|
+
...root.parameterSize() ? { Parameters: root.getParameters().map((parameter) => ({
|
|
1274
|
+
id: parameter.id,
|
|
1275
|
+
...parameter.type ? { type: parameter.type } : {},
|
|
1276
|
+
...parameter.value !== void 0 ? { value: jsonWireValue(parameter.value, parameter.type ?? "STRING") } : {}
|
|
1277
|
+
})) } : {},
|
|
1278
|
+
...root.datasetSize() ? { Datasets: root.getDatasets().map((dataset) => ({
|
|
1279
|
+
id: dataset.id,
|
|
1280
|
+
ColumnInfo: {
|
|
1281
|
+
...dataset.constColumnSize() ? { ConstColumn: dataset.getConstColumns().map((column) => ({
|
|
1282
|
+
id: column.id,
|
|
1283
|
+
type: column.type,
|
|
1284
|
+
size: column.size,
|
|
1285
|
+
value: jsonWireValue(column.value, column.type)
|
|
1286
|
+
})) } : {},
|
|
1287
|
+
Column: dataset.getColumns().map((column) => ({
|
|
1288
|
+
id: column.id,
|
|
1289
|
+
type: column.type,
|
|
1290
|
+
size: column.size
|
|
1291
|
+
}))
|
|
1292
|
+
},
|
|
1293
|
+
Rows: dataset.getRows().flatMap((row) => {
|
|
1294
|
+
const current = {
|
|
1295
|
+
_RowType_: row.type === "insert" ? "I" : row.type === "update" ? "U" : row.type === "delete" ? "D" : "N",
|
|
1296
|
+
...columnsToObject(row.cols)
|
|
1297
|
+
};
|
|
1298
|
+
if (!row.orgRow) return [current];
|
|
1299
|
+
return [current, {
|
|
1300
|
+
_RowType_: "O",
|
|
1301
|
+
...columnsToObject(row.orgRow)
|
|
1302
|
+
}];
|
|
1303
|
+
})
|
|
1304
|
+
})) } : {}
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
const nexacroJsonCodec = {
|
|
1308
|
+
serialize: writeJson,
|
|
1309
|
+
deserialize: readJson
|
|
1310
|
+
};
|
|
1311
|
+
function parseJson(value) {
|
|
1312
|
+
return nexacroJsonCodec.deserialize(JSON.parse(value));
|
|
1313
|
+
}
|
|
1314
|
+
function writeJsonString(root) {
|
|
1315
|
+
return JSON.stringify(nexacroJsonCodec.serialize(root));
|
|
1316
|
+
}
|
|
1317
|
+
//#endregion
|
|
1182
1318
|
exports.ColumnTypeError = ColumnTypeError;
|
|
1183
1319
|
exports.Dataset = Dataset;
|
|
1184
1320
|
exports.InvalidXmlError = InvalidXmlError;
|
|
@@ -1204,11 +1340,14 @@ exports.escapeXml = escapeXml;
|
|
|
1204
1340
|
exports.initXapi = initXapi;
|
|
1205
1341
|
exports.isXapiRoot = isXapiRoot;
|
|
1206
1342
|
exports.makeParseEntities = makeParseEntities;
|
|
1343
|
+
exports.nexacroJsonCodec = nexacroJsonCodec;
|
|
1207
1344
|
exports.parse = parse;
|
|
1345
|
+
exports.parseJson = parseJson;
|
|
1208
1346
|
exports.parseXml = parseXml;
|
|
1209
1347
|
exports.rowType = rowType;
|
|
1210
1348
|
exports.stringToDate = stringToDate;
|
|
1211
1349
|
exports.stringToReadableStream = stringToReadableStream;
|
|
1212
1350
|
exports.uint8ArrayToBase64 = uint8ArrayToBase64;
|
|
1213
1351
|
exports.write = write;
|
|
1352
|
+
exports.writeJsonString = writeJsonString;
|
|
1214
1353
|
exports.xapi = xapi;
|
package/dist/index.d.cts
CHANGED
|
@@ -506,7 +506,15 @@ interface XapiOperation<Request extends XapiRootSchema = XapiRootSchema, Respons
|
|
|
506
506
|
type RequiredColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? never : Key; }[keyof Columns];
|
|
507
507
|
type OptionalColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? Key : never; }[keyof Columns];
|
|
508
508
|
type InferColumns<Columns extends XapiColumns> = { [Key in RequiredColumnKeys<Columns>]: XapiTypeMap[Columns[Key]["type"]]; } & { [Key in OptionalColumnKeys<Columns>]?: XapiTypeMap[Columns[Key]["type"]]; };
|
|
509
|
-
|
|
509
|
+
/**
|
|
510
|
+
* A schema row remains assignable from the old plain object shape, while
|
|
511
|
+
* retaining the Nexacro row metadata when an operation needs it.
|
|
512
|
+
*/
|
|
513
|
+
type InferDatasetRow<Schema extends XapiDatasetSchema> = InferColumns<Schema["columns"]> & {
|
|
514
|
+
$rowType?: RowType;
|
|
515
|
+
$orgRow?: Partial<InferColumns<Schema["columns"]>>;
|
|
516
|
+
};
|
|
517
|
+
type InferDataset<Schema extends XapiDatasetSchema> = InferDatasetRow<Schema>[];
|
|
510
518
|
type InferRoot<Schema extends XapiRootSchema> = {
|
|
511
519
|
parameters: InferColumns<Schema["parameters"]>;
|
|
512
520
|
datasets: { [Key in keyof Schema["datasets"]]: InferDataset<Schema["datasets"][Key]>; };
|
|
@@ -543,4 +551,43 @@ declare const xapi: {
|
|
|
543
551
|
declare function encodeRoot<Schema extends XapiRootSchema>(schema: Schema, value: InferRoot<Schema>): XapiRoot;
|
|
544
552
|
declare function decodeRoot<Schema extends XapiRootSchema>(schema: Schema, root: XapiRoot): InferRoot<Schema>;
|
|
545
553
|
//#endregion
|
|
546
|
-
|
|
554
|
+
//#region src/codec.d.ts
|
|
555
|
+
/** The wire representation used by Nexacro's Dataset JSON format. */
|
|
556
|
+
interface NexacroJsonParameter {
|
|
557
|
+
id: string;
|
|
558
|
+
type?: ColumnType;
|
|
559
|
+
value?: string | number;
|
|
560
|
+
}
|
|
561
|
+
interface NexacroJsonColumn {
|
|
562
|
+
id: string;
|
|
563
|
+
type?: ColumnType;
|
|
564
|
+
size?: number | string;
|
|
565
|
+
value?: string | number;
|
|
566
|
+
}
|
|
567
|
+
interface NexacroJsonRow {
|
|
568
|
+
_RowType_?: "N" | "I" | "U" | "D" | "O";
|
|
569
|
+
[columnId: string]: unknown;
|
|
570
|
+
}
|
|
571
|
+
interface NexacroJsonDataset {
|
|
572
|
+
id: string;
|
|
573
|
+
ColumnInfo: {
|
|
574
|
+
ConstColumn?: NexacroJsonColumn[];
|
|
575
|
+
Column: NexacroJsonColumn[];
|
|
576
|
+
};
|
|
577
|
+
Rows: NexacroJsonRow[];
|
|
578
|
+
}
|
|
579
|
+
interface NexacroJsonRoot {
|
|
580
|
+
version: "1.0";
|
|
581
|
+
Parameters?: NexacroJsonParameter[];
|
|
582
|
+
Datasets?: NexacroJsonDataset[];
|
|
583
|
+
}
|
|
584
|
+
/** A serializer boundary around the X-API internal model. */
|
|
585
|
+
interface XapiCodec<Serialized> {
|
|
586
|
+
serialize(root: XapiRoot): Serialized;
|
|
587
|
+
deserialize(value: Serialized): XapiRoot;
|
|
588
|
+
}
|
|
589
|
+
declare const nexacroJsonCodec: XapiCodec<NexacroJsonRoot>;
|
|
590
|
+
declare function parseJson(value: string): XapiRoot;
|
|
591
|
+
declare function writeJsonString(root: XapiRoot): string;
|
|
592
|
+
//#endregion
|
|
593
|
+
export { Col, Column, ColumnInfo, ColumnType, ColumnTypeError, ConstColumn, Dataset, InferColumns, InferDataset, InferDatasetRow, InferRoot, InvalidXmlError, NexaVersion, NexacroJsonColumn, NexacroJsonDataset, NexacroJsonParameter, NexacroJsonRoot, NexacroJsonRow, Parameter, RequestOf, ResponseOf, Row, RowType, Rows, StringWritableStream, XapiCodec, 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, nexacroJsonCodec, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
|
package/dist/index.d.ts
CHANGED
|
@@ -506,7 +506,15 @@ interface XapiOperation<Request extends XapiRootSchema = XapiRootSchema, Respons
|
|
|
506
506
|
type RequiredColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? never : Key; }[keyof Columns];
|
|
507
507
|
type OptionalColumnKeys<Columns extends XapiColumns> = { [Key in keyof Columns]-?: Columns[Key]["optional"] extends true ? Key : never; }[keyof Columns];
|
|
508
508
|
type InferColumns<Columns extends XapiColumns> = { [Key in RequiredColumnKeys<Columns>]: XapiTypeMap[Columns[Key]["type"]]; } & { [Key in OptionalColumnKeys<Columns>]?: XapiTypeMap[Columns[Key]["type"]]; };
|
|
509
|
-
|
|
509
|
+
/**
|
|
510
|
+
* A schema row remains assignable from the old plain object shape, while
|
|
511
|
+
* retaining the Nexacro row metadata when an operation needs it.
|
|
512
|
+
*/
|
|
513
|
+
type InferDatasetRow<Schema extends XapiDatasetSchema> = InferColumns<Schema["columns"]> & {
|
|
514
|
+
$rowType?: RowType;
|
|
515
|
+
$orgRow?: Partial<InferColumns<Schema["columns"]>>;
|
|
516
|
+
};
|
|
517
|
+
type InferDataset<Schema extends XapiDatasetSchema> = InferDatasetRow<Schema>[];
|
|
510
518
|
type InferRoot<Schema extends XapiRootSchema> = {
|
|
511
519
|
parameters: InferColumns<Schema["parameters"]>;
|
|
512
520
|
datasets: { [Key in keyof Schema["datasets"]]: InferDataset<Schema["datasets"][Key]>; };
|
|
@@ -543,4 +551,43 @@ declare const xapi: {
|
|
|
543
551
|
declare function encodeRoot<Schema extends XapiRootSchema>(schema: Schema, value: InferRoot<Schema>): XapiRoot;
|
|
544
552
|
declare function decodeRoot<Schema extends XapiRootSchema>(schema: Schema, root: XapiRoot): InferRoot<Schema>;
|
|
545
553
|
//#endregion
|
|
546
|
-
|
|
554
|
+
//#region src/codec.d.ts
|
|
555
|
+
/** The wire representation used by Nexacro's Dataset JSON format. */
|
|
556
|
+
interface NexacroJsonParameter {
|
|
557
|
+
id: string;
|
|
558
|
+
type?: ColumnType;
|
|
559
|
+
value?: string | number;
|
|
560
|
+
}
|
|
561
|
+
interface NexacroJsonColumn {
|
|
562
|
+
id: string;
|
|
563
|
+
type?: ColumnType;
|
|
564
|
+
size?: number | string;
|
|
565
|
+
value?: string | number;
|
|
566
|
+
}
|
|
567
|
+
interface NexacroJsonRow {
|
|
568
|
+
_RowType_?: "N" | "I" | "U" | "D" | "O";
|
|
569
|
+
[columnId: string]: unknown;
|
|
570
|
+
}
|
|
571
|
+
interface NexacroJsonDataset {
|
|
572
|
+
id: string;
|
|
573
|
+
ColumnInfo: {
|
|
574
|
+
ConstColumn?: NexacroJsonColumn[];
|
|
575
|
+
Column: NexacroJsonColumn[];
|
|
576
|
+
};
|
|
577
|
+
Rows: NexacroJsonRow[];
|
|
578
|
+
}
|
|
579
|
+
interface NexacroJsonRoot {
|
|
580
|
+
version: "1.0";
|
|
581
|
+
Parameters?: NexacroJsonParameter[];
|
|
582
|
+
Datasets?: NexacroJsonDataset[];
|
|
583
|
+
}
|
|
584
|
+
/** A serializer boundary around the X-API internal model. */
|
|
585
|
+
interface XapiCodec<Serialized> {
|
|
586
|
+
serialize(root: XapiRoot): Serialized;
|
|
587
|
+
deserialize(value: Serialized): XapiRoot;
|
|
588
|
+
}
|
|
589
|
+
declare const nexacroJsonCodec: XapiCodec<NexacroJsonRoot>;
|
|
590
|
+
declare function parseJson(value: string): XapiRoot;
|
|
591
|
+
declare function writeJsonString(root: XapiRoot): string;
|
|
592
|
+
//#endregion
|
|
593
|
+
export { Col, Column, ColumnInfo, ColumnType, ColumnTypeError, ConstColumn, Dataset, InferColumns, InferDataset, InferDatasetRow, InferRoot, InvalidXmlError, NexaVersion, NexacroJsonColumn, NexacroJsonDataset, NexacroJsonParameter, NexacroJsonRoot, NexacroJsonRow, Parameter, RequestOf, ResponseOf, Row, RowType, Rows, StringWritableStream, XapiCodec, 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, nexacroJsonCodec, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
|
package/dist/index.js
CHANGED
|
@@ -521,9 +521,7 @@ function _unescapeXml(str) {
|
|
|
521
521
|
if (!str) return str;
|
|
522
522
|
if (str.indexOf("&") === -1) return str;
|
|
523
523
|
let result = str.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'").replace(/&/g, "&");
|
|
524
|
-
result = result.replace(CONTROL_CHAR_ENTITY_REGEX, (match) =>
|
|
525
|
-
return ENTITY_MAP.get(match) || match;
|
|
526
|
-
});
|
|
524
|
+
result = result.replace(CONTROL_CHAR_ENTITY_REGEX, (match) => ENTITY_MAP.get(match));
|
|
527
525
|
return result;
|
|
528
526
|
}
|
|
529
527
|
function isXapiRoot(value) {
|
|
@@ -629,7 +627,7 @@ var XmlStringBuilder = class {
|
|
|
629
627
|
* @returns An array of parsed XML nodes.
|
|
630
628
|
*/
|
|
631
629
|
function parseXml(xml) {
|
|
632
|
-
if (!xml
|
|
630
|
+
if (!xml) return [];
|
|
633
631
|
return new XapiXmlParser(xml).parse();
|
|
634
632
|
}
|
|
635
633
|
/**
|
|
@@ -644,6 +642,50 @@ const CHAR_SLASH = 47;
|
|
|
644
642
|
const CHAR_EQUALS = 61;
|
|
645
643
|
const CHAR_QUOTE = 34;
|
|
646
644
|
const CHAR_APOS = 39;
|
|
645
|
+
/** Reuse the small, fixed X-API vocabulary instead of allocating a name per node. */
|
|
646
|
+
function xapiXmlName(xml, start, end) {
|
|
647
|
+
switch (end - start) {
|
|
648
|
+
case 2:
|
|
649
|
+
if (xml.startsWith("id", start)) return "id";
|
|
650
|
+
break;
|
|
651
|
+
case 3:
|
|
652
|
+
if (xml.startsWith("Col", start)) return "Col";
|
|
653
|
+
if (xml.startsWith("Row", start)) return "Row";
|
|
654
|
+
break;
|
|
655
|
+
case 4:
|
|
656
|
+
if (xml.startsWith("Root", start)) return "Root";
|
|
657
|
+
if (xml.startsWith("Rows", start)) return "Rows";
|
|
658
|
+
if (xml.startsWith("size", start)) return "size";
|
|
659
|
+
if (xml.startsWith("type", start)) return "type";
|
|
660
|
+
break;
|
|
661
|
+
case 5:
|
|
662
|
+
if (xml.startsWith("value", start)) return "value";
|
|
663
|
+
if (xml.startsWith("xmlns", start)) return "xmlns";
|
|
664
|
+
break;
|
|
665
|
+
case 6:
|
|
666
|
+
if (xml.startsWith("Column", start)) return "Column";
|
|
667
|
+
if (xml.startsWith("OrgRow", start)) return "OrgRow";
|
|
668
|
+
break;
|
|
669
|
+
case 7:
|
|
670
|
+
if (xml.startsWith("Dataset", start)) return "Dataset";
|
|
671
|
+
if (xml.startsWith("version", start)) return "version";
|
|
672
|
+
break;
|
|
673
|
+
case 8:
|
|
674
|
+
if (xml.startsWith("Datasets", start)) return "Datasets";
|
|
675
|
+
break;
|
|
676
|
+
case 9:
|
|
677
|
+
if (xml.startsWith("Parameter", start)) return "Parameter";
|
|
678
|
+
break;
|
|
679
|
+
case 10:
|
|
680
|
+
if (xml.startsWith("ColumnInfo", start)) return "ColumnInfo";
|
|
681
|
+
if (xml.startsWith("Parameters", start)) return "Parameters";
|
|
682
|
+
break;
|
|
683
|
+
case 11:
|
|
684
|
+
if (xml.startsWith("ConstColumn", start)) return "ConstColumn";
|
|
685
|
+
break;
|
|
686
|
+
}
|
|
687
|
+
return xml.substring(start, end);
|
|
688
|
+
}
|
|
647
689
|
/**
|
|
648
690
|
* A lightweight XML parser optimized for X-API structure.
|
|
649
691
|
*/
|
|
@@ -657,20 +699,26 @@ var XapiXmlParser = class {
|
|
|
657
699
|
}
|
|
658
700
|
parse() {
|
|
659
701
|
const nodes = [];
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
this.
|
|
665
|
-
|
|
702
|
+
const xml = this.xml;
|
|
703
|
+
const length = this.length;
|
|
704
|
+
while (this.pos < length) {
|
|
705
|
+
while (this.pos < length) {
|
|
706
|
+
const code = xml.charCodeAt(this.pos);
|
|
707
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
708
|
+
this.pos++;
|
|
709
|
+
}
|
|
710
|
+
if (this.pos >= length) break;
|
|
711
|
+
if (xml.startsWith("<?xml", this.pos)) {
|
|
712
|
+
const end = xml.indexOf("?>", this.pos + 5);
|
|
713
|
+
this.pos = end < 0 ? length : end + 2;
|
|
666
714
|
continue;
|
|
667
715
|
}
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
this.pos
|
|
716
|
+
if (xml.startsWith("<!--", this.pos)) {
|
|
717
|
+
const end = xml.indexOf("-->", this.pos + 4);
|
|
718
|
+
this.pos = end < 0 ? length : end + 3;
|
|
671
719
|
continue;
|
|
672
720
|
}
|
|
673
|
-
if (this.
|
|
721
|
+
if (xml.charCodeAt(this.pos) === 60) {
|
|
674
722
|
const node = this.parseElement();
|
|
675
723
|
if (node) nodes.push(node);
|
|
676
724
|
} else this.pos++;
|
|
@@ -678,10 +726,17 @@ var XapiXmlParser = class {
|
|
|
678
726
|
return nodes;
|
|
679
727
|
}
|
|
680
728
|
parseElement() {
|
|
681
|
-
|
|
729
|
+
const xml = this.xml;
|
|
730
|
+
const length = this.length;
|
|
682
731
|
this.pos++;
|
|
683
|
-
if (this.
|
|
684
|
-
const
|
|
732
|
+
if (xml.charCodeAt(this.pos) === CHAR_SLASH) return null;
|
|
733
|
+
const nameStart = this.pos;
|
|
734
|
+
while (this.pos < length) {
|
|
735
|
+
const code = xml.charCodeAt(this.pos);
|
|
736
|
+
if (code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
737
|
+
this.pos++;
|
|
738
|
+
}
|
|
739
|
+
const tagName = xapiXmlName(xml, nameStart, this.pos);
|
|
685
740
|
if (!tagName) return null;
|
|
686
741
|
const node = {
|
|
687
742
|
tagName,
|
|
@@ -689,155 +744,110 @@ var XapiXmlParser = class {
|
|
|
689
744
|
children: void 0
|
|
690
745
|
};
|
|
691
746
|
const attributes = this.parseAttributes();
|
|
692
|
-
if (attributes
|
|
693
|
-
this.
|
|
694
|
-
if (this.matches("/>")) {
|
|
747
|
+
if (attributes) node.attributes = attributes;
|
|
748
|
+
if (xml.charCodeAt(this.pos) === CHAR_SLASH && xml.charCodeAt(this.pos + 1) === CHAR_GT) {
|
|
695
749
|
this.pos += 2;
|
|
696
750
|
return node;
|
|
697
751
|
}
|
|
698
|
-
if (this.
|
|
699
|
-
|
|
752
|
+
if (xml.charCodeAt(this.pos) === CHAR_GT) this.pos++;
|
|
753
|
+
let children;
|
|
700
754
|
let textContent = "";
|
|
701
|
-
while (this.pos <
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
755
|
+
while (this.pos < length) {
|
|
756
|
+
const markup = xml.indexOf("<", this.pos);
|
|
757
|
+
if (markup < 0) {
|
|
758
|
+
this.pos = length;
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
if (markup > this.pos) {
|
|
762
|
+
const text = xml.substring(this.pos, markup);
|
|
763
|
+
textContent = textContent ? textContent + text : text;
|
|
764
|
+
this.pos = markup;
|
|
765
|
+
}
|
|
766
|
+
if (xml.startsWith("<![CDATA[", this.pos)) {
|
|
767
|
+
const start = this.pos + 9;
|
|
768
|
+
const end = xml.indexOf("]]>", start);
|
|
769
|
+
if (end < 0) {
|
|
770
|
+
textContent += xml.substring(start);
|
|
771
|
+
this.pos = length;
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
textContent += xml.substring(start, end);
|
|
775
|
+
this.pos = end + 3;
|
|
705
776
|
continue;
|
|
706
777
|
}
|
|
707
|
-
if (this.
|
|
708
|
-
if (textContent) children.push(textContent);
|
|
778
|
+
if (xml.charCodeAt(this.pos + 1) === CHAR_SLASH) {
|
|
779
|
+
if (textContent && (!children || textContent.trim())) (children ??= []).push(textContent);
|
|
709
780
|
this.pos += 2;
|
|
710
|
-
|
|
711
|
-
this.pos
|
|
781
|
+
const end = xml.indexOf(">", this.pos);
|
|
782
|
+
this.pos = end < 0 ? length : end + 1;
|
|
712
783
|
break;
|
|
713
784
|
}
|
|
714
|
-
if (
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
719
|
-
const child = this.parseElement();
|
|
720
|
-
if (child) children.push(child);
|
|
721
|
-
} else {
|
|
722
|
-
textContent += this.current();
|
|
723
|
-
this.pos++;
|
|
785
|
+
if (xml.startsWith("<!--", this.pos)) {
|
|
786
|
+
const end = xml.indexOf("-->", this.pos + 4);
|
|
787
|
+
this.pos = end < 0 ? length : end + 3;
|
|
788
|
+
continue;
|
|
724
789
|
}
|
|
790
|
+
if (textContent && textContent.trim()) (children ??= []).push(textContent);
|
|
791
|
+
textContent = "";
|
|
792
|
+
const child = this.parseElement();
|
|
793
|
+
if (child) (children ??= []).push(child);
|
|
725
794
|
}
|
|
726
|
-
if (children
|
|
795
|
+
if (children) node.children = children;
|
|
727
796
|
return node;
|
|
728
797
|
}
|
|
729
|
-
parseTagName() {
|
|
730
|
-
const start = this.pos;
|
|
731
|
-
while (this.pos < this.length) {
|
|
732
|
-
const code = this.currentCharCode();
|
|
733
|
-
if (this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
734
|
-
this.pos++;
|
|
735
|
-
}
|
|
736
|
-
return this.xml.substring(start, this.pos);
|
|
737
|
-
}
|
|
738
798
|
parseAttributes() {
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
799
|
+
const xml = this.xml;
|
|
800
|
+
const length = this.length;
|
|
801
|
+
let attrs;
|
|
802
|
+
while (this.pos < length) {
|
|
803
|
+
while (this.pos < length) {
|
|
804
|
+
const code = xml.charCodeAt(this.pos);
|
|
805
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
806
|
+
this.pos++;
|
|
807
|
+
}
|
|
808
|
+
const code = xml.charCodeAt(this.pos);
|
|
809
|
+
if (code === CHAR_GT || code === CHAR_SLASH) break;
|
|
810
|
+
const nameStart = this.pos;
|
|
811
|
+
while (this.pos < length) {
|
|
812
|
+
const code = xml.charCodeAt(this.pos);
|
|
813
|
+
if (code === CHAR_EQUALS || code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
814
|
+
this.pos++;
|
|
815
|
+
}
|
|
816
|
+
const attrName = xapiXmlName(xml, nameStart, this.pos);
|
|
745
817
|
if (!attrName) break;
|
|
746
|
-
this.
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
attrs[attrName] = this.parseAttributeValue();
|
|
750
|
-
}
|
|
751
|
-
return Object.keys(attrs).length > 0 ? attrs : void 0;
|
|
752
|
-
}
|
|
753
|
-
parseAttributeName() {
|
|
754
|
-
const start = this.pos;
|
|
755
|
-
while (this.pos < this.length) {
|
|
756
|
-
const code = this.currentCharCode();
|
|
757
|
-
if (code === CHAR_EQUALS || this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
758
|
-
this.pos++;
|
|
759
|
-
}
|
|
760
|
-
return this.xml.substring(start, this.pos);
|
|
761
|
-
}
|
|
762
|
-
parseAttributeValue() {
|
|
763
|
-
const quoteCode = this.currentCharCode();
|
|
764
|
-
if (quoteCode !== CHAR_QUOTE && quoteCode !== CHAR_APOS) {
|
|
765
|
-
const start = this.pos;
|
|
766
|
-
while (this.pos < this.length) {
|
|
767
|
-
const code = this.currentCharCode();
|
|
768
|
-
if (this.isWhitespace(code) || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
818
|
+
while (this.pos < length) {
|
|
819
|
+
const code = xml.charCodeAt(this.pos);
|
|
820
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
769
821
|
this.pos++;
|
|
770
822
|
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
while (this.pos < this.length) {
|
|
776
|
-
if (this.currentCharCode() === quoteCode) {
|
|
777
|
-
const value = this.xml.substring(start, this.pos);
|
|
823
|
+
if (xml.charCodeAt(this.pos) === CHAR_EQUALS) this.pos++;
|
|
824
|
+
while (this.pos < length) {
|
|
825
|
+
const code = xml.charCodeAt(this.pos);
|
|
826
|
+
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
778
827
|
this.pos++;
|
|
779
|
-
return value;
|
|
780
828
|
}
|
|
781
|
-
this.pos
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
if (code !== CHAR_SPACE && code !== CHAR_TAB && code !== CHAR_LF && code !== CHAR_CR) break;
|
|
802
|
-
this.pos++;
|
|
829
|
+
const quote = xml.charCodeAt(this.pos);
|
|
830
|
+
let valueStart;
|
|
831
|
+
let valueEnd;
|
|
832
|
+
if (quote === CHAR_QUOTE || quote === CHAR_APOS) {
|
|
833
|
+
valueStart = ++this.pos;
|
|
834
|
+
valueEnd = xml.indexOf(quote === CHAR_QUOTE ? "\"" : "'", valueStart);
|
|
835
|
+
if (valueEnd < 0) {
|
|
836
|
+
valueEnd = length;
|
|
837
|
+
this.pos = length;
|
|
838
|
+
} else this.pos = valueEnd + 1;
|
|
839
|
+
} else {
|
|
840
|
+
valueStart = this.pos;
|
|
841
|
+
while (this.pos < length) {
|
|
842
|
+
const code = xml.charCodeAt(this.pos);
|
|
843
|
+
if (code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR || code === CHAR_GT || code === CHAR_SLASH) break;
|
|
844
|
+
this.pos++;
|
|
845
|
+
}
|
|
846
|
+
valueEnd = this.pos;
|
|
847
|
+
}
|
|
848
|
+
(attrs ??= {})[attrName] = xml.substring(valueStart, valueEnd);
|
|
803
849
|
}
|
|
804
|
-
|
|
805
|
-
isWhitespace(code) {
|
|
806
|
-
return code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_LF || code === CHAR_CR;
|
|
807
|
-
}
|
|
808
|
-
skipUntil(target) {
|
|
809
|
-
const pos = this.findString(target);
|
|
810
|
-
if (pos !== -1) this.pos = pos;
|
|
811
|
-
else this.pos = this.length;
|
|
812
|
-
}
|
|
813
|
-
current() {
|
|
814
|
-
return this.xml[this.pos];
|
|
815
|
-
}
|
|
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;
|
|
850
|
+
return attrs;
|
|
841
851
|
}
|
|
842
852
|
};
|
|
843
853
|
//#endregion
|
|
@@ -933,7 +943,6 @@ function parseColumnInfo(columnInfoElement, dataset) {
|
|
|
933
943
|
}
|
|
934
944
|
}
|
|
935
945
|
function parseRows(rowsElement, dataset) {
|
|
936
|
-
if (typeof rowsElement === "string") return;
|
|
937
946
|
const rows = rowsElement?.children;
|
|
938
947
|
if (!rows) return;
|
|
939
948
|
const datasetRows = dataset.rows;
|
|
@@ -984,8 +993,6 @@ function parseRows(rowsElement, dataset) {
|
|
|
984
993
|
}
|
|
985
994
|
}
|
|
986
995
|
function parseParameters(parametersElement, xapiRoot) {
|
|
987
|
-
if (typeof parametersElement === "string") return;
|
|
988
|
-
if (!parametersElement) return;
|
|
989
996
|
const children = parametersElement.children;
|
|
990
997
|
if (!children) return;
|
|
991
998
|
for (let i = 0; i < children.length; i++) {
|
|
@@ -1020,19 +1027,17 @@ function write(root) {
|
|
|
1020
1027
|
return builder.toString();
|
|
1021
1028
|
}
|
|
1022
1029
|
function writeParameters(builder, parameters) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
builder.writeEndElement("Parameters");
|
|
1035
|
-
}
|
|
1030
|
+
builder.writeStartElement("Parameters");
|
|
1031
|
+
for (const parameter of parameters) {
|
|
1032
|
+
const attrs = { id: parameter.id };
|
|
1033
|
+
if (parameter.type !== void 0) attrs.type = parameter.type;
|
|
1034
|
+
if (parameter.value !== void 0) if (typeof parameter.value === "string") attrs.value = parameter.value;
|
|
1035
|
+
else if (parameter.value instanceof Date) attrs.value = dateToString(parameter.value, parameter.type);
|
|
1036
|
+
else if (parameter.value instanceof Uint8Array) attrs.value = uint8ArrayToBase64(parameter.value);
|
|
1037
|
+
else attrs.value = String(parameter.value);
|
|
1038
|
+
builder.writeStartElement("Parameter", attrs, true);
|
|
1039
|
+
}
|
|
1040
|
+
builder.writeEndElement("Parameters");
|
|
1036
1041
|
}
|
|
1037
1042
|
function writeDataset(builder, dataset) {
|
|
1038
1043
|
builder.writeStartElement("Dataset", { id: dataset.id });
|
|
@@ -1146,7 +1151,12 @@ function encodeRoot(schema, value) {
|
|
|
1146
1151
|
const rows = value.datasets[datasetId];
|
|
1147
1152
|
for (const row of rows) {
|
|
1148
1153
|
const rowIndex = dataset.newRow();
|
|
1154
|
+
dataset.rows[rowIndex].type = row.$rowType;
|
|
1149
1155
|
for (const id of Object.keys(datasetSchema.columns)) dataset.setColumn(rowIndex, id, row[id]);
|
|
1156
|
+
if (row.$orgRow) dataset.rows[rowIndex].orgRow = Object.entries(row.$orgRow).map(([id, value]) => ({
|
|
1157
|
+
id,
|
|
1158
|
+
value
|
|
1159
|
+
}));
|
|
1150
1160
|
}
|
|
1151
1161
|
root.addDataset(dataset);
|
|
1152
1162
|
}
|
|
@@ -1169,6 +1179,8 @@ function decodeRoot(schema, root) {
|
|
|
1169
1179
|
datasets[datasetId] = dataset.getRows().map((row) => {
|
|
1170
1180
|
const value = { ...constants };
|
|
1171
1181
|
for (const column of row.cols) if (column.id in datasetSchema.columns) value[column.id] = column.value;
|
|
1182
|
+
if (row.type) value.$rowType = row.type;
|
|
1183
|
+
if (row.orgRow) value.$orgRow = Object.fromEntries(row.orgRow.map((column) => [column.id, column.value]));
|
|
1172
1184
|
return value;
|
|
1173
1185
|
});
|
|
1174
1186
|
}
|
|
@@ -1178,4 +1190,128 @@ function decodeRoot(schema, root) {
|
|
|
1178
1190
|
};
|
|
1179
1191
|
}
|
|
1180
1192
|
//#endregion
|
|
1181
|
-
|
|
1193
|
+
//#region src/codec.ts
|
|
1194
|
+
const rowTypes = {
|
|
1195
|
+
N: void 0,
|
|
1196
|
+
I: "insert",
|
|
1197
|
+
U: "update",
|
|
1198
|
+
D: "delete",
|
|
1199
|
+
O: void 0
|
|
1200
|
+
};
|
|
1201
|
+
function sizeOf(size, type) {
|
|
1202
|
+
if (size !== void 0) return Number(size);
|
|
1203
|
+
return type === "STRING" ? 255 : 0;
|
|
1204
|
+
}
|
|
1205
|
+
function jsonValue(value, type) {
|
|
1206
|
+
if (value === null || value === void 0) return void 0;
|
|
1207
|
+
if (type === "DATE" || type === "DATETIME" || type === "TIME") return typeof value === "string" ? convertToColumnType(value, type) : value;
|
|
1208
|
+
if (type === "BLOB" && typeof value === "string") return convertToColumnType(value, type);
|
|
1209
|
+
return value;
|
|
1210
|
+
}
|
|
1211
|
+
function jsonWireValue(value, type) {
|
|
1212
|
+
if (value === void 0) return void 0;
|
|
1213
|
+
if (value instanceof Date) return dateToString(value, type);
|
|
1214
|
+
if (value instanceof Uint8Array) return uint8ArrayToBase64(value);
|
|
1215
|
+
return value;
|
|
1216
|
+
}
|
|
1217
|
+
function columnsToObject(columns) {
|
|
1218
|
+
return Object.fromEntries(columns.map((column) => [column.id, column.value]));
|
|
1219
|
+
}
|
|
1220
|
+
function readRow(dataset, row) {
|
|
1221
|
+
const rowType = rowTypes[row._RowType_ ?? "N"];
|
|
1222
|
+
if (row._RowType_ === "O") {
|
|
1223
|
+
const previous = dataset.rows[dataset.rows.length - 1];
|
|
1224
|
+
if (previous?.type !== "update") return;
|
|
1225
|
+
previous.orgRow = dataset.getColumns().filter((column) => Object.prototype.hasOwnProperty.call(row, column.id)).map((column) => ({
|
|
1226
|
+
id: column.id,
|
|
1227
|
+
value: jsonValue(row[column.id], column.type)
|
|
1228
|
+
}));
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
const index = dataset.newRow();
|
|
1232
|
+
dataset.rows[index].type = rowType;
|
|
1233
|
+
for (const column of dataset.getColumns()) if (Object.prototype.hasOwnProperty.call(row, column.id)) dataset.rows[index].cols.push({
|
|
1234
|
+
id: column.id,
|
|
1235
|
+
value: jsonValue(row[column.id], column.type)
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
function readJson(value) {
|
|
1239
|
+
const root = new XapiRoot();
|
|
1240
|
+
for (const parameter of value.Parameters ?? []) root.addParameter({
|
|
1241
|
+
id: parameter.id,
|
|
1242
|
+
type: parameter.type,
|
|
1243
|
+
value: jsonValue(parameter.value, parameter.type)
|
|
1244
|
+
});
|
|
1245
|
+
for (const source of value.Datasets ?? []) {
|
|
1246
|
+
const dataset = new Dataset(source.id);
|
|
1247
|
+
for (const column of source.ColumnInfo.ConstColumn ?? []) {
|
|
1248
|
+
const type = column.type ?? "STRING";
|
|
1249
|
+
dataset.addConstColumn({
|
|
1250
|
+
id: column.id,
|
|
1251
|
+
type,
|
|
1252
|
+
size: sizeOf(column.size, type),
|
|
1253
|
+
value: jsonValue(column.value, type)
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
for (const column of source.ColumnInfo.Column) {
|
|
1257
|
+
const type = column.type ?? "STRING";
|
|
1258
|
+
dataset.addColumn({
|
|
1259
|
+
id: column.id,
|
|
1260
|
+
type,
|
|
1261
|
+
size: sizeOf(column.size, type)
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
for (const row of source.Rows) readRow(dataset, row);
|
|
1265
|
+
root.addDataset(dataset);
|
|
1266
|
+
}
|
|
1267
|
+
return root;
|
|
1268
|
+
}
|
|
1269
|
+
function writeJson(root) {
|
|
1270
|
+
return {
|
|
1271
|
+
version: "1.0",
|
|
1272
|
+
...root.parameterSize() ? { Parameters: root.getParameters().map((parameter) => ({
|
|
1273
|
+
id: parameter.id,
|
|
1274
|
+
...parameter.type ? { type: parameter.type } : {},
|
|
1275
|
+
...parameter.value !== void 0 ? { value: jsonWireValue(parameter.value, parameter.type ?? "STRING") } : {}
|
|
1276
|
+
})) } : {},
|
|
1277
|
+
...root.datasetSize() ? { Datasets: root.getDatasets().map((dataset) => ({
|
|
1278
|
+
id: dataset.id,
|
|
1279
|
+
ColumnInfo: {
|
|
1280
|
+
...dataset.constColumnSize() ? { ConstColumn: dataset.getConstColumns().map((column) => ({
|
|
1281
|
+
id: column.id,
|
|
1282
|
+
type: column.type,
|
|
1283
|
+
size: column.size,
|
|
1284
|
+
value: jsonWireValue(column.value, column.type)
|
|
1285
|
+
})) } : {},
|
|
1286
|
+
Column: dataset.getColumns().map((column) => ({
|
|
1287
|
+
id: column.id,
|
|
1288
|
+
type: column.type,
|
|
1289
|
+
size: column.size
|
|
1290
|
+
}))
|
|
1291
|
+
},
|
|
1292
|
+
Rows: dataset.getRows().flatMap((row) => {
|
|
1293
|
+
const current = {
|
|
1294
|
+
_RowType_: row.type === "insert" ? "I" : row.type === "update" ? "U" : row.type === "delete" ? "D" : "N",
|
|
1295
|
+
...columnsToObject(row.cols)
|
|
1296
|
+
};
|
|
1297
|
+
if (!row.orgRow) return [current];
|
|
1298
|
+
return [current, {
|
|
1299
|
+
_RowType_: "O",
|
|
1300
|
+
...columnsToObject(row.orgRow)
|
|
1301
|
+
}];
|
|
1302
|
+
})
|
|
1303
|
+
})) } : {}
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
const nexacroJsonCodec = {
|
|
1307
|
+
serialize: writeJson,
|
|
1308
|
+
deserialize: readJson
|
|
1309
|
+
};
|
|
1310
|
+
function parseJson(value) {
|
|
1311
|
+
return nexacroJsonCodec.deserialize(JSON.parse(value));
|
|
1312
|
+
}
|
|
1313
|
+
function writeJsonString(root) {
|
|
1314
|
+
return JSON.stringify(nexacroJsonCodec.serialize(root));
|
|
1315
|
+
}
|
|
1316
|
+
//#endregion
|
|
1317
|
+
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, nexacroJsonCodec, parse, parseJson, parseXml, rowType, stringToDate, stringToReadableStream, uint8ArrayToBase64, write, writeJsonString, xapi };
|