This is an automated email from the ASF dual-hosted git repository. rantunes pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools-temporary-rnd-do-not-use.git
commit e177a6aa2534087e77cab9ec122aff55732b9b45 Author: Yeser Amer <[email protected]> AuthorDate: Mon Nov 6 14:58:31 2023 +0100 kie-issues#665: `xml-parser-ts` Doesn't manage Complex Types with Simple Content (#2039) Co-authored-by: Tiago Bento <[email protected]> --- .../src/parser/VariablesRepository.ts | 6 +- packages/scesim-editor/src/TestScenarioEditor.tsx | 56 ++-- .../tests-data--manual/OldEnoughTest.scesim | 363 +++++++++++++++++++++ .../scesim-marshaller/tests/idempotency.test.ts | 6 +- .../scesim-marshaller/tests/typeSafety.test.ts | 6 +- packages/scesim-marshaller/tests/versions.test.ts | 1 + packages/xml-parser-ts-codegen/src/codegen.ts | 175 +++++----- .../ts-gen/meta.ts | 4 + .../ts-gen/types.d.ts | 19 +- packages/xml-parser-ts-codegen/src/types.d.ts | 9 +- packages/xml-parser-ts/src/index.ts | 60 ++-- 11 files changed, 562 insertions(+), 143 deletions(-) diff --git a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts index 4d514dd051..092d98e5c6 100644 --- a/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts +++ b/packages/dmn-feel-antlr4-parser/src/parser/VariablesRepository.ts @@ -325,7 +325,7 @@ export class VariablesRepository { return { name: itemDefinition["@_name"], properties: new Map<string, DataType>(), - typeRef: itemDefinition["typeRef"] ?? itemDefinition["@_name"], + typeRef: itemDefinition["typeRef"]?.__$$text ?? itemDefinition["@_name"], }; } @@ -333,7 +333,7 @@ export class VariablesRepository { return { name: itemComponent["@_name"], properties: this.buildProperties(itemComponent), - typeRef: itemComponent["typeRef"] ?? itemComponent["@_name"], + typeRef: itemComponent["typeRef"]?.__$$text ?? itemComponent["@_name"], }; } @@ -344,7 +344,7 @@ export class VariablesRepository { const rootProperty = { name: def["@_name"], properties: this.buildProperties(def), - typeRef: def["typeRef"] ?? def["@_name"], + typeRef: def["typeRef"]?.__$$text ?? def["@_name"], }; properties.set(rootProperty.name, rootProperty); diff --git a/packages/scesim-editor/src/TestScenarioEditor.tsx b/packages/scesim-editor/src/TestScenarioEditor.tsx index d3e87731f0..69e69707a0 100644 --- a/packages/scesim-editor/src/TestScenarioEditor.tsx +++ b/packages/scesim-editor/src/TestScenarioEditor.tsx @@ -280,25 +280,25 @@ function TestScenarioMainPanel({ /* The first two FactMapping are related to the "Number" and "Description" columns. If those columns only are present, no Data Objects can be detected in the scesim file */ for (let i = 2; i < factsMappings.length; i++) { - const dataObject = dataObjects.find((value) => value.id === factsMappings[i]["factAlias"]); + const dataObject = dataObjects.find((value) => value.id === factsMappings[i]["factAlias"].__$$text); if (dataObject) { - if (!dataObject.children?.some((value) => value.id === factsMappings[i]["expressionAlias"])) { + if (!dataObject.children?.some((value) => value.id === factsMappings[i]["expressionAlias"]?.__$$text)) { dataObject.children!.push({ - id: factsMappings[i]["expressionAlias"]!, - name: factsMappings[i]["expressionAlias"]!, - customBadgeContent: factsMappings[i]["className"], + id: factsMappings[i]["expressionAlias"]!.__$$text, + name: factsMappings[i]["expressionAlias"]!.__$$text, + customBadgeContent: factsMappings[i]["className"].__$$text, }); } } else { dataObjects.push({ - id: factsMappings[i]["factAlias"], - name: factsMappings[i]["factAlias"], - customBadgeContent: factsMappings[i]["factIdentifier"]!["className"], + id: factsMappings[i]["factAlias"].__$$text, + name: factsMappings[i]["factAlias"].__$$text, + customBadgeContent: factsMappings[i]["factIdentifier"]!["className"]!.__$$text, children: [ { - id: factsMappings[i]["expressionAlias"]!, - name: factsMappings[i]["expressionAlias"]!, - customBadgeContent: factsMappings[i]["className"], + id: factsMappings[i]["expressionAlias"]!.__$$text, + name: factsMappings[i]["expressionAlias"]!.__$$text, + customBadgeContent: factsMappings[i]["className"].__$$text, }, ], }); @@ -310,7 +310,7 @@ function TestScenarioMainPanel({ /** It determines the Alert State */ useEffect(() => { - const assetType = scesimModel.ScenarioSimulationModel["settings"]!["type"]!; + const assetType = scesimModel.ScenarioSimulationModel["settings"]!["type"]!.__$$text; let alertEnabled = false; let alertMessage = ""; @@ -347,13 +347,14 @@ function TestScenarioMainPanel({ onUpdateSettingField={updateSettingField} selectedDock={dockPanel.selected} testScenarioSettings={{ - assetType: scesimModel.ScenarioSimulationModel["settings"]!["type"]!, - dmnName: scesimModel.ScenarioSimulationModel["settings"]!["dmnName"], - dmnNamespace: scesimModel.ScenarioSimulationModel["settings"]!["dmnNamespace"], - isStatelessSessionRule: scesimModel.ScenarioSimulationModel["settings"]!["stateless"] ?? false, - isTestSkipped: scesimModel.ScenarioSimulationModel["settings"]!["skipFromBuild"] ?? false, - kieSessionRule: scesimModel.ScenarioSimulationModel["settings"]!["dmoSession"], - ruleFlowGroup: scesimModel.ScenarioSimulationModel["settings"]!["ruleFlowGroup"], + assetType: scesimModel.ScenarioSimulationModel["settings"]!["type"]!.__$$text, + dmnName: scesimModel.ScenarioSimulationModel["settings"]!["dmnName"]?.__$$text, + dmnNamespace: scesimModel.ScenarioSimulationModel["settings"]!["dmnNamespace"]?.__$$text, + isStatelessSessionRule: + scesimModel.ScenarioSimulationModel["settings"]!["stateless"]?.__$$text ?? false, + isTestSkipped: scesimModel.ScenarioSimulationModel["settings"]!["skipFromBuild"]?.__$$text ?? false, + kieSessionRule: scesimModel.ScenarioSimulationModel["settings"]!["dmoSession"]?.__$$text, + ruleFlowGroup: scesimModel.ScenarioSimulationModel["settings"]!["ruleFlowGroup"]?.__$$text, }} /> } @@ -493,12 +494,17 @@ const TestScenarioEditorInternal = ({ forwardRef }: { forwardRef?: React.Ref<Tes ["settings"]: { ...prevState.ScenarioSimulationModel["settings"], ["dmoSession"]: - assetType === TestScenarioType[TestScenarioType.RULE] && kieSessionRule ? kieSessionRule : undefined, + assetType === TestScenarioType[TestScenarioType.RULE] && kieSessionRule + ? { __$$text: kieSessionRule } + : undefined, ["ruleFlowGroup"]: - assetType === TestScenarioType[TestScenarioType.RULE] && ruleFlowGroup ? ruleFlowGroup : undefined, - ["skipFromBuild"]: isTestSkipped, - ["stateless"]: assetType === TestScenarioType[TestScenarioType.RULE] ? isStatelessSessionRule : undefined, - ["type"]: assetType, + assetType === TestScenarioType[TestScenarioType.RULE] && ruleFlowGroup + ? { __$$text: ruleFlowGroup } + : undefined, + ["skipFromBuild"]: { __$$text: isTestSkipped }, + ["stateless"]: + assetType === TestScenarioType[TestScenarioType.RULE] ? { __$$text: isStatelessSessionRule } : undefined, + ["type"]: { __$$text: assetType }, }, }, })), @@ -512,7 +518,7 @@ const TestScenarioEditorInternal = ({ forwardRef }: { forwardRef?: React.Ref<Tes ...prevState.ScenarioSimulationModel, ["settings"]: { ...prevState.ScenarioSimulationModel["settings"], - [fieldName]: value, + [fieldName]: { __$$text: value }, }, }, })), diff --git a/packages/scesim-marshaller/tests-data--manual/OldEnoughTest.scesim b/packages/scesim-marshaller/tests-data--manual/OldEnoughTest.scesim new file mode 100644 index 0000000000..9645419764 --- /dev/null +++ b/packages/scesim-marshaller/tests-data--manual/OldEnoughTest.scesim @@ -0,0 +1,363 @@ +<ScenarioSimulationModel version="1.8"> + <simulation> + <scesimModelDescriptor> + <factMappings> + <FactMapping> + <expressionElements/> + <expressionIdentifier> + <name>Index</name> + <type>OTHER</type> + </expressionIdentifier> + <factIdentifier> + <name>#</name> + <className>java.lang.Integer</className> + </factIdentifier> + <className>java.lang.Integer</className> + <factAlias>#</factAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>70.0</columnWidth> + </FactMapping> + <FactMapping> + <expressionElements/> + <expressionIdentifier> + <name>Description</name> + <type>OTHER</type> + </expressionIdentifier> + <factIdentifier> + <name>Scenario description</name> + <className>java.lang.String</className> + </factIdentifier> + <className>java.lang.String</className> + <factAlias>Scenario description</factAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>300.0</columnWidth> + </FactMapping> + <FactMapping> + <expressionElements> + <ExpressionElement> + <step>Applicant</step> + </ExpressionElement> + <ExpressionElement> + <step>age</step> + </ExpressionElement> + </expressionElements> + <expressionIdentifier> + <name>1|1</name> + <type>GIVEN</type> + </expressionIdentifier> + <factIdentifier> + <name>1|1</name> + <className>mortgages.mortgages.Applicant</className> + </factIdentifier> + <className>java.lang.Integer</className> + <factAlias>Applicant</factAlias> + <expressionAlias>age</expressionAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>212.60000000000002</columnWidth> + </FactMapping> + <FactMapping> + <expressionElements> + <ExpressionElement> + <step>LoanApplication</step> + </ExpressionElement> + <ExpressionElement> + <step>approved</step> + </ExpressionElement> + </expressionElements> + <expressionIdentifier> + <name>1591876615315</name> + <type>GIVEN</type> + </expressionIdentifier> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <className>java.lang.Boolean</className> + <factAlias>LoanApplication</factAlias> + <expressionAlias>approved</expressionAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>212.60000000000002</columnWidth> + </FactMapping> + <FactMapping> + <expressionElements> + <ExpressionElement> + <step>IncomeSource</step> + </ExpressionElement> + <ExpressionElement> + <step>amount</step> + </ExpressionElement> + </expressionElements> + <expressionIdentifier> + <name>1591622221147</name> + <type>GIVEN</type> + </expressionIdentifier> + <factIdentifier> + <name>1591622221147</name> + <className>mortgages.mortgages.IncomeSource</className> + </factIdentifier> + <className>java.lang.Integer</className> + <factAlias>IncomeSource</factAlias> + <expressionAlias>amount</expressionAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>212.60000000000002</columnWidth> + </FactMapping> + <FactMapping> + <expressionElements> + <ExpressionElement> + <step>LoanApplication</step> + </ExpressionElement> + <ExpressionElement> + <step>approved</step> + </ExpressionElement> + </expressionElements> + <expressionIdentifier> + <name>1|2</name> + <type>EXPECT</type> + </expressionIdentifier> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <className>java.lang.Boolean</className> + <factAlias>LoanApplication</factAlias> + <expressionAlias>approved</expressionAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>212.60000000000002</columnWidth> + </FactMapping> + <FactMapping> + <expressionElements> + <ExpressionElement> + <step>LoanApplication</step> + </ExpressionElement> + <ExpressionElement> + <step>explanation</step> + </ExpressionElement> + </expressionElements> + <expressionIdentifier> + <name>1591874776961</name> + <type>EXPECT</type> + </expressionIdentifier> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <className>java.lang.String</className> + <factAlias>LoanApplication</factAlias> + <expressionAlias>explanation</expressionAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>212.60000000000002</columnWidth> + </FactMapping> + </factMappings> + </scesimModelDescriptor> + <scesimData> + <Scenario> + <factMappingValues> + <FactMappingValue> + <factIdentifier> + <name>Scenario description</name> + <className>java.lang.String</className> + </factIdentifier> + <expressionIdentifier> + <name>Description</name> + <type>OTHER</type> + </expressionIdentifier> + <rawValue class="string">Young Bob want a loan</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>#</name> + <className>java.lang.Integer</className> + </factIdentifier> + <expressionIdentifier> + <name>Index</name> + <type>OTHER</type> + </expressionIdentifier> + <rawValue class="string">1</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1|1</name> + <className>mortgages.mortgages.Applicant</className> + </factIdentifier> + <expressionIdentifier> + <name>1|1</name> + <type>GIVEN</type> + </expressionIdentifier> + <rawValue class="string">17</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622221147</name> + <className>mortgages.mortgages.IncomeSource</className> + </factIdentifier> + <expressionIdentifier> + <name>1591622221147</name> + <type>GIVEN</type> + </expressionIdentifier> + <rawValue class="string">0</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <expressionIdentifier> + <name>1|2</name> + <type>EXPECT</type> + </expressionIdentifier> + <rawValue class="string">false</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <expressionIdentifier> + <name>1591874776961</name> + <type>EXPECT</type> + </expressionIdentifier> + <rawValue class="string">Underage</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <expressionIdentifier> + <name>1591876615315</name> + <type>GIVEN</type> + </expressionIdentifier> + <rawValue class="string">true</rawValue> + </FactMappingValue> + </factMappingValues> + </Scenario> + <Scenario> + <factMappingValues> + <FactMappingValue> + <factIdentifier> + <name>Scenario description</name> + <className>java.lang.String</className> + </factIdentifier> + <expressionIdentifier> + <name>Description</name> + <type>OTHER</type> + </expressionIdentifier> + <rawValue class="string">Adult Anna want a loan</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>#</name> + <className>java.lang.Integer</className> + </factIdentifier> + <expressionIdentifier> + <name>Index</name> + <type>OTHER</type> + </expressionIdentifier> + <rawValue class="string">2</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1|1</name> + <className>mortgages.mortgages.Applicant</className> + </factIdentifier> + <expressionIdentifier> + <name>1|1</name> + <type>GIVEN</type> + </expressionIdentifier> + <rawValue class="string">27</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622221147</name> + <className>mortgages.mortgages.IncomeSource</className> + </factIdentifier> + <expressionIdentifier> + <name>1591622221147</name> + <type>GIVEN</type> + </expressionIdentifier> + <rawValue class="string">0</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <expressionIdentifier> + <name>1|2</name> + <type>EXPECT</type> + </expressionIdentifier> + <rawValue class="string">true</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <expressionIdentifier> + <name>1591874776961</name> + <type>EXPECT</type> + </expressionIdentifier> + <rawValue class="string">null</rawValue> + </FactMappingValue> + <FactMappingValue> + <factIdentifier> + <name>1591622209590</name> + <className>mortgages.mortgages.LoanApplication</className> + </factIdentifier> + <expressionIdentifier> + <name>1591876615315</name> + <type>GIVEN</type> + </expressionIdentifier> + <rawValue class="string">true</rawValue> + </FactMappingValue> + </factMappingValues> + </Scenario> + </scesimData> + </simulation> + <background> + <scesimModelDescriptor> + <factMappings> + <FactMapping> + <expressionElements/> + <expressionIdentifier> + <name>1|1</name> + <type>GIVEN</type> + </expressionIdentifier> + <factIdentifier> + <name>Empty</name> + <className>java.lang.Void</className> + </factIdentifier> + <className>java.lang.Void</className> + <factAlias>INSTANCE 1</factAlias> + <expressionAlias>PROPERTY 1</expressionAlias> + <factMappingValueType>NOT_EXPRESSION</factMappingValueType> + <columnWidth>114.0</columnWidth> + </FactMapping> + </factMappings> + </scesimModelDescriptor> + <scesimData> + <BackgroundData> + <factMappingValues> + <FactMappingValue> + <factIdentifier> + <name>Empty</name> + <className>java.lang.Void</className> + </factIdentifier> + <expressionIdentifier> + <name>1|1</name> + <type>GIVEN</type> + </expressionIdentifier> + </FactMappingValue> + </factMappingValues> + </BackgroundData> + </scesimData> + </background> + <settings> + <type>RULE</type> + <skipFromBuild>false</skipFromBuild> + <stateless>false</stateless> + </settings> + <imports> + <imports/> + </imports> +</ScenarioSimulationModel> \ No newline at end of file diff --git a/packages/scesim-marshaller/tests/idempotency.test.ts b/packages/scesim-marshaller/tests/idempotency.test.ts index caa2bc5861..2ec133a77b 100644 --- a/packages/scesim-marshaller/tests/idempotency.test.ts +++ b/packages/scesim-marshaller/tests/idempotency.test.ts @@ -21,7 +21,11 @@ import * as fs from "fs"; import * as path from "path"; import { getMarshaller } from "@kie-tools/scesim-marshaller"; -const files = ["../tests-data--manual/simple.scesim", "../tests-data--manual/TrafficViolationTest.scesim"]; +const files = [ + "../tests-data--manual/simple.scesim", + "../tests-data--manual/OldEnoughTest.scesim", + "../tests-data--manual/TrafficViolationTest.scesim", +]; describe("idempotency", () => { for (const file of files) { diff --git a/packages/scesim-marshaller/tests/typeSafety.test.ts b/packages/scesim-marshaller/tests/typeSafety.test.ts index b494c131e4..bd4641c2b7 100644 --- a/packages/scesim-marshaller/tests/typeSafety.test.ts +++ b/packages/scesim-marshaller/tests/typeSafety.test.ts @@ -22,7 +22,11 @@ import * as path from "path"; import * as child_process from "child_process"; import { getMarshaller } from "@kie-tools/scesim-marshaller"; -const files = ["../tests-data--manual/TrafficViolationTest.scesim", "../tests-data--manual/simple.scesim"]; +const files = [ + "../tests-data--manual/OldEnoughTest.scesim", + "../tests-data--manual/TrafficViolationTest.scesim", + "../tests-data--manual/simple.scesim", +]; const tmpDir = path.join(__dirname, "..", "dist-tests", "scesim-marshaller-type-safety-tests"); diff --git a/packages/scesim-marshaller/tests/versions.test.ts b/packages/scesim-marshaller/tests/versions.test.ts index 20875d519f..227241ded5 100644 --- a/packages/scesim-marshaller/tests/versions.test.ts +++ b/packages/scesim-marshaller/tests/versions.test.ts @@ -23,6 +23,7 @@ import { getMarshaller } from "@kie-tools/scesim-marshaller"; const files = [ { path: "../tests-data--manual/simple.scesim", version: "1.8" }, + { path: "../tests-data--manual/OldEnoughTest.scesim", version: "1.8" }, { path: "../tests-data--manual/TrafficViolationTest.scesim", version: "1.8" }, ]; diff --git a/packages/xml-parser-ts-codegen/src/codegen.ts b/packages/xml-parser-ts-codegen/src/codegen.ts index 8599a361a5..30feda9b8a 100644 --- a/packages/xml-parser-ts-codegen/src/codegen.ts +++ b/packages/xml-parser-ts-codegen/src/codegen.ts @@ -27,7 +27,6 @@ import { XptcElement, XptcSimpleType, XptcComplexType, - XptcComplexTypeNamed, XptcComplexTypeAnonymous, XptcMetaType, XptcMetaTypeProperty, @@ -57,21 +56,21 @@ const __LOGS = { }; export const XSD__TYPES = new Map<string, XptcTsPrimitiveType>([ - ["xsd:boolean", { type: "primitive", tsEquivalent: "boolean", doc: "xsd:boolean" }], - ["xsd:QName", { type: "primitive", tsEquivalent: "string", doc: "xsd:QName" }], - ["xsd:string", { type: "primitive", tsEquivalent: "string", doc: "xsd:string" }], - ["xsd:int", { type: "primitive", tsEquivalent: "number", doc: "xsd:int" }], - ["xsd:integer", { type: "primitive", tsEquivalent: "number", doc: "xsd:integer" }], - ["xsd:dateTime", { type: "primitive", tsEquivalent: "string", doc: "xsd:dateTime" }], - ["xsd:double", { type: "primitive", tsEquivalent: "number", doc: "xsd:double" }], - ["xsd:long", { type: "primitive", tsEquivalent: "number", doc: "xsd:long" }], - ["xsd:float", { type: "primitive", tsEquivalent: "number", doc: "xsd:float" }], - ["xsd:duration", { type: "primitive", tsEquivalent: "string", doc: "xsd:duration" }], - ["xsd:IDREF", { type: "primitive", tsEquivalent: "string", doc: "xsd:IDREF" }], - ["xsd:anyURI", { type: "primitive", tsEquivalent: "string", doc: "xsd:anyURI" }], - ["xsd:anyType", { type: "primitive", tsEquivalent: "string", doc: "xsd:antType" }], - ["xsd:IDREFS", { type: "primitive", tsEquivalent: "string", doc: "xsd:IDREFS" }], - ["xsd:ID", { type: "primitive", tsEquivalent: "string", doc: "xsd:ID" }], + ["xsd:boolean", { type: "primitive", tsEquivalent: "boolean", annotation: "xsd:boolean" }], + ["xsd:QName", { type: "primitive", tsEquivalent: "string", annotation: "xsd:QName" }], + ["xsd:string", { type: "primitive", tsEquivalent: "string", annotation: "xsd:string" }], + ["xsd:int", { type: "primitive", tsEquivalent: "number", annotation: "xsd:int" }], + ["xsd:integer", { type: "primitive", tsEquivalent: "number", annotation: "xsd:integer" }], + ["xsd:dateTime", { type: "primitive", tsEquivalent: "string", annotation: "xsd:dateTime" }], + ["xsd:double", { type: "primitive", tsEquivalent: "number", annotation: "xsd:double" }], + ["xsd:long", { type: "primitive", tsEquivalent: "number", annotation: "xsd:long" }], + ["xsd:float", { type: "primitive", tsEquivalent: "number", annotation: "xsd:float" }], + ["xsd:duration", { type: "primitive", tsEquivalent: "string", annotation: "xsd:duration" }], + ["xsd:IDREF", { type: "primitive", tsEquivalent: "string", annotation: "xsd:IDREF" }], + ["xsd:anyURI", { type: "primitive", tsEquivalent: "string", annotation: "xsd:anyURI" }], + ["xsd:anyType", { type: "primitive", tsEquivalent: "string", annotation: "xsd:antType" }], + ["xsd:IDREFS", { type: "primitive", tsEquivalent: "string", annotation: "xsd:IDREFS" }], + ["xsd:ID", { type: "primitive", tsEquivalent: "string", annotation: "xsd:ID" }], ]); // TODO: Tiago --> Write unit tests @@ -149,7 +148,7 @@ async function main() { if (s["xsd:union"]["@_memberTypes"] === "xsd:anyURI") { return [ { - doc: "xsd:anyURI", + comment: "xsd:anyURI", type: "simple", kind: "enum", name: s["@_name"] ?? s["@_name"], @@ -172,15 +171,19 @@ async function main() { for (const [location, xsd] of __XSDS.entries()) { for (const xsdCt of xsd["xsd:schema"]["xsd:complexType"] || []) { const isAbstract = xsdCt["@_abstract"] ?? false; + const extensionElement = + xsdCt["xsd:complexContent"]?.["xsd:extension"] ?? xsdCt["xsd:simpleContent"]?.["xsd:extension"]; + __COMPLEX_TYPES.push({ type: "complex", - doc: isAbstract ? "abstract" : "", + comment: isAbstract ? "abstract" : "", isAbstract, isAnonymous: false, name: xsdCt["@_name"]!, + isSimpleContent: !!xsdCt["xsd:simpleContent"], needsExtensionType: !!xsdCt["xsd:anyAttribute"] || !!xsdCt["xsd:sequence"]?.["xsd:any"], declaredAtRelativeLocation: location, - childOf: xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["@_base"], + childOf: extensionElement?.["@_base"], elements: [ ...(xsdCt["xsd:all"]?.["xsd:element"] ?? []).map((s) => xsdElementToXptcElement(xsdCt["@_name"]!, s, location) @@ -188,24 +191,22 @@ async function main() { ...(xsdCt["xsd:sequence"]?.["xsd:element"] ?? []).map((s) => xsdElementToXptcElement(xsdCt["@_name"]!, s, location) ), - ...(xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:sequence"]?.["xsd:element"] ?? []).map((s) => + ...(extensionElement?.["xsd:sequence"]?.["xsd:element"] ?? []).map((s) => xsdElementToXptcElement(xsdCt["@_name"]!, s, location) ), - ...( - xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:sequence"]?.["xsd:choice"]?.["xsd:element"] ?? [] - ).map((s) => xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { forceOptional: true })), - ...(xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:choice"]?.["xsd:element"] ?? []).map((s) => + ...(extensionElement?.["xsd:sequence"]?.["xsd:choice"]?.["xsd:element"] ?? []).map((s) => + xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { forceOptional: true }) + ), + ...(extensionElement?.["xsd:choice"]?.["xsd:element"] ?? []).map((s) => + xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { forceOptional: true }) + ), + ...(extensionElement?.["xsd:choice"]?.["xsd:sequence"]?.["xsd:element"] ?? []).map((s) => xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { forceOptional: true }) ), - ...( - xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:choice"]?.["xsd:sequence"]?.["xsd:element"] ?? [] - ).map((s) => xsdElementToXptcElement(xsdCt["@_name"]!, s, location, { forceOptional: true })), ], attributes: [ ...(xsdCt["xsd:attribute"] ?? []).map((a) => xsdAttributeToXptcAttribute(a)), - ...(xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:attribute"] ?? []).map((a) => - xsdAttributeToXptcAttribute(a) - ), + ...(extensionElement?.["xsd:attribute"] ?? []).map((a) => xsdAttributeToXptcAttribute(a)), ], }); } @@ -307,9 +308,9 @@ async function main() { } const enumName = getTsNameFromNamedType(sp.declaredAtRelativeLocation, sp.name); - if (sp.doc === "xsd:anyURI") { + if (sp.comment === "xsd:anyURI") { ts += ` -export type ${enumName} = string; // ${sp.doc} +export type ${enumName} = string; // ${sp.comment} `; } else if (sp.kind === "enum") { ts += ` @@ -345,13 +346,13 @@ ${sp.values.map((v) => ` '${v}'`).join(" |\n")} ? "number" : p.metaType.name; const ns = getMetaPropertyNs(__RELATIVE_LOCATION, p); - return ` "${ns}${p.name}"${optionalMarker}: ${p.typeBody ?? tsType}${arrayMarker}; // from type ${ + return ` "${ns}${p.name}"${optionalMarker}: ${p.typeBody?.(tsType) ?? tsType}${arrayMarker}; // from type ${ p.fromType } @ ${p.declaredAt}`; }) .join("\n"); - const doc = ct.doc.trim() ? `/* ${ct.doc} */` : ""; + const doc = ct.comment.trim() ? `/* ${ct.comment} */` : ""; const anonymousTypesString = anonymousTypes .map((anonType) => { @@ -518,8 +519,8 @@ function resolveElementRef( }); } -function getMetaTypeName(typeName: string, doc: string) { - return typeName === "number" ? (doc === "xsd:double" || doc === "xsd:float" ? "float" : "integer") : typeName; +function getMetaTypeName({ name, annotation }: { name: string; annotation: string }) { + return name === "number" ? (annotation === "xsd:double" || annotation === "xsd:float" ? "float" : "integer") : name; } function getTypeBodyForElementRef( @@ -590,7 +591,7 @@ function getMetaProperties( fromType: metaTypeName, name: `@_${a.name}`, elem: undefined, - metaType: { name: getMetaTypeName(attributeType.name, attributeType.doc) }, + metaType: { name: getMetaTypeName(attributeType) }, isArray: false, isOptional: a.isOptional, }); @@ -616,7 +617,7 @@ function getMetaProperties( ct.declaredAtRelativeLocation, getAnonymousMetaTypeName(referencedElement.name, "GLOBAL") ), - doc: "Anonymous type from element " + referencedElement.name, + annotation: "Anonymous type from element " + referencedElement.name, }; metaProperties.push({ @@ -624,33 +625,30 @@ function getMetaProperties( fromType: ct.isAnonymous ? "" : ct.name, name: referencedElement.name, elem: referencedElement, - metaType: { - name: getMetaTypeName(tsType.name, tsType.doc), - }, - typeBody: getTypeBodyForElementRef( - __RELATIVE_LOCATION, - __META_TYPE_MAPPING, - __GLOBAL_ELEMENTS, - __SUBSTITUTIONS, - __XSDS, - __NAMED_TYPES_BY_TS_NAME, - ct, - referencedElement - ), + metaType: { name: getMetaTypeName(tsType) }, + typeBody: () => + getTypeBodyForElementRef( + __RELATIVE_LOCATION, + __META_TYPE_MAPPING, + __GLOBAL_ELEMENTS, + __SUBSTITUTIONS, + __XSDS, + __NAMED_TYPES_BY_TS_NAME, + ct, + referencedElement + ), isArray: e.isArray, isOptional: e.isOptional, }); } else if (e.kind === "ofNamedType") { const tsType = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, e.typeName); - metaProperties.push({ declaredAt: ct.declaredAtRelativeLocation, fromType: metaTypeName, name: e.name, elem: undefined, // REALLY? - metaType: { - name: getMetaTypeName(tsType.name, tsType.doc), - }, + metaType: { name: getMetaTypeName(tsType) }, + typeBody: getTsTypeBody(tsType), isArray: e.isArray, isOptional: e.isOptional, }); @@ -686,6 +684,20 @@ function getMetaProperties( } } + if (ct.isSimpleContent && ct.childOf) { + metaProperties.push({ + declaredAt: ct.declaredAtRelativeLocation, + fromType: metaTypeName, + name: `__$$text`, + elem: undefined, + metaType: { + name: getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, ct.childOf).name, + }, + isArray: false, + isOptional: false, + }); + } + const immediateParentType = ct.childOf ? getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, ct.childOf) : undefined; @@ -716,7 +728,7 @@ function getMetaProperties( fromType: curParentCt.name, elem: undefined, name: `@_${a.name}`, - metaType: { name: getMetaTypeName(attributeType.name, attributeType.doc) }, + metaType: { name: getMetaTypeName(attributeType) }, isArray: false, isOptional: a.isOptional, }); @@ -763,9 +775,8 @@ function getMetaProperties( fromType: curParentCt.name, elem: undefined, // REALLY? name: e.name, - metaType: { - name: getMetaTypeName(tsType.name, tsType.doc), - }, + metaType: { name: getMetaTypeName(tsType) }, + typeBody: getTsTypeBody(tsType), isArray: e.isArray, isOptional: e.isOptional, }); @@ -793,7 +804,7 @@ function getMetaProperties( ct.declaredAtRelativeLocation, getAnonymousMetaTypeName(referencedElement.name, "GLOBAL") ), - doc: "Anonymous type from element " + referencedElement.name, + annotation: "Anonymous type from element " + referencedElement.name, }; metaProperties.push({ @@ -801,19 +812,18 @@ function getMetaProperties( fromType: ct.isAnonymous ? "" : ct.name, name: referencedElement.name, elem: referencedElement, - metaType: { - name: getMetaTypeName(tsType.name, tsType.doc), - }, - typeBody: getTypeBodyForElementRef( - __RELATIVE_LOCATION, - __META_TYPE_MAPPING, - __GLOBAL_ELEMENTS, - __SUBSTITUTIONS, - __XSDS, - __NAMED_TYPES_BY_TS_NAME, - ct, - referencedElement - ), + metaType: { name: getMetaTypeName(tsType) }, + typeBody: () => + getTypeBodyForElementRef( + __RELATIVE_LOCATION, + __META_TYPE_MAPPING, + __GLOBAL_ELEMENTS, + __SUBSTITUTIONS, + __XSDS, + __NAMED_TYPES_BY_TS_NAME, + ct, + referencedElement + ), isArray: e.isArray, isOptional: e.isOptional, }); @@ -862,7 +872,7 @@ function getTsTypeFromLocalRef( __NAMED_TYPES_BY_TS_NAME: Map<string, XptcComplexType | XptcSimpleType>, relativeLocation: string, namedTypeLocalRef: string -): { name: string; doc: string } { +): { name: string; annotation: string } { // check if it's a local ref to another namespace if (namedTypeLocalRef.includes(":") && namedTypeLocalRef.split(":").length === 2) { const [localNsName, namedTypeName] = namedTypeLocalRef.split(":"); @@ -875,7 +885,7 @@ function getTsTypeFromLocalRef( if (!xsdType) { throw new Error(`Unknown XSD type '${namedTypeLocalRef}'`); } - return { name: xsdType.tsEquivalent, doc: xsdType.doc }; + return { name: xsdType.tsEquivalent, annotation: xsdType.annotation }; } // find the XSD with matching namespace declaration. @@ -899,13 +909,13 @@ function getTsTypeFromLocalRef( } // found it! - return { name: tsTypeName, doc: `type found from local ref '${localNsName}'.` }; + return { name: tsTypeName, annotation: `type found from local ref '${localNsName}'.` }; } // not a reference to a type in another namespace. simply local name. return { name: getTsNameFromNamedType(relativeLocation, namedTypeLocalRef), - doc: "// local type", + annotation: "// local type", }; } @@ -915,7 +925,7 @@ function xsdSimpleTypeToXptcSimpleType(s: XsdSimpleType, location: string, name: s["xsd:restriction"]["xsd:enumeration"] ) { return { - doc: "enum", + comment: "enum", type: "simple", kind: "enum", name: s["@_name"] ?? name, @@ -924,7 +934,7 @@ function xsdSimpleTypeToXptcSimpleType(s: XsdSimpleType, location: string, name: }; } else if (s["xsd:restriction"]?.["@_base"] === "xsd:int" || s["xsd:restriction"]?.["@_base"] === "xsd:integer") { return { - doc: "int", + comment: "int", type: "simple", kind: "int", restrictionBase: s["xsd:restriction"]["@_base"], @@ -1080,7 +1090,8 @@ function xsdComplexTypeToAnonymousXptcComplexType( ): XptcComplexTypeAnonymous { return { type: "complex", - doc: "", + comment: "", + isSimpleContent: false, // No reason why an anonymous type couldn't be simpleContent... Could be implemented. isAnonymous: true, parentIdentifierForExtensionType, forElementWithName: element, @@ -1103,3 +1114,7 @@ function xsdComplexTypeToAnonymousXptcComplexType( ], }; } + +function getTsTypeBody(tsType: { name: string; annotation: string }): XptcMetaTypeProperty["typeBody"] { + return tsType.annotation.startsWith("xsd:") ? (tsTypeName) => `{ __$$text: ${tsTypeName} }` : undefined; +} diff --git a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts index 646c80f6de..4ae4c3bd27 100644 --- a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts +++ b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/meta.ts @@ -59,6 +59,7 @@ export const meta = { complexType: { "@_abstract": { type: "boolean", isArray: false, isOptional: true }, "xsd:complexContent": { type: "complexContent", isArray: false, isOptional: true }, + "xsd:simpleContent": { type: "simpleContent", isArray: false, isOptional: true }, "xsd:sequence": { type: "sequence", isArray: false, isOptional: true }, "xsd:all": { type: "all", isArray: false, isOptional: true }, "xsd:attribute": { type: "attribute", isArray: true, isOptional: false }, @@ -66,6 +67,9 @@ export const meta = { complexContent: { "xsd:extension": { type: "extension", isArray: false, isOptional: false }, }, + simpleContent: { + "xsd:extension": { type: "extension", isArray: false, isOptional: false }, + }, extension: { "xsd:sequence": { type: "sequence", isArray: false, isOptional: true }, "xsd:choice": { type: "choice", isArray: false, isOptional: true }, diff --git a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts index c1f7f6f061..21d5daa83d 100644 --- a/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts +++ b/packages/xml-parser-ts-codegen/src/schemas/xsd-incomplete--manually-written/ts-gen/types.d.ts @@ -61,6 +61,14 @@ export interface XsdSequence { }; } +export interface XSDExtension { + "xsd:attribute"?: XsdAttribute[]; + "xsd:sequence"?: XsdSequence; + "xsd:all"?: XsdAll; + "xsd:choice"?: XsdChoice; + "@_base": string; +} + export interface XsdComplexType { "@_name"?: string; "@_abstract"?: boolean; @@ -72,13 +80,10 @@ export interface XsdComplexType { "@_processContents": "lax"; }; "xsd:complexContent"?: { - "xsd:extension"?: { - "xsd:attribute"?: XsdAttribute[]; - "xsd:sequence"?: XsdSequence; - "xsd:all"?: XsdAll; - "xsd:choice"?: XsdChoice; - "@_base": string; - }; + "xsd:extension"?: XSDExtension; + }; + "xsd:simpleContent"?: { + "xsd:extension"?: XSDExtension; }; } diff --git a/packages/xml-parser-ts-codegen/src/types.d.ts b/packages/xml-parser-ts-codegen/src/types.d.ts index 7efad208f4..b8a78259d2 100644 --- a/packages/xml-parser-ts-codegen/src/types.d.ts +++ b/packages/xml-parser-ts-codegen/src/types.d.ts @@ -23,8 +23,9 @@ export type XptcComplexTypeBase = { childOf?: string; - doc: string; + comment: string; type: "complex"; + isSimpleContent: boolean; needsExtensionType: boolean; // That's for sequences decalring <xsd:anyAttribute> or <xsd:any> declaredAtRelativeLocation: string; elements: Array< @@ -80,7 +81,7 @@ export type XptcElement = { export type XptcSimpleType = { type: "simple"; - doc: string; + comment: string; name: string; restrictionBase?: string; declaredAtRelativeLocation: string; @@ -102,7 +103,7 @@ export type XptcSimpleType = { ); export type XptcTsPrimitiveType = { - doc: string; + annotation: string; type: "primitive"; tsEquivalent: string; }; @@ -122,7 +123,7 @@ export type XptcMetaTypeProperty = { metaType: { name: string; }; - typeBody?: string; + typeBody?: (type: string) => string | undefined; isArray: boolean; isOptional: boolean; fromType: string; diff --git a/packages/xml-parser-ts/src/index.ts b/packages/xml-parser-ts/src/index.ts index 7a9c15540a..3ac4cec542 100644 --- a/packages/xml-parser-ts/src/index.ts +++ b/packages/xml-parser-ts/src/index.ts @@ -137,7 +137,7 @@ export function parse(args: { for (let ii = 0; ii < children.length; ii++) { const elemNode = children[ii]; - if (elemNode.nodeType === 1 /* element */) { + if (elemNode.nodeType === 1 /* ELEMENT_NODE */) { const { nsedName, subsedName } = resolveElement(elemNode.nodeName, args.nodeType, args); const elemPropType = args.nodeType?.[subsedName ?? nsedName]; @@ -148,15 +148,19 @@ export function parse(args: { ? args.meta[elemPropType.type] // If we can't find this type with the `elements` mapping, we try directly from `meta`. : undefined); // If the current element is not known, we simply ignore its type and go with the defaults. - let elemValue: any; - if (elemPropType?.type === "string") { - elemValue = elemNode.textContent ?? ""; - } else if (elemPropType?.type === "boolean") { - elemValue = parseBoolean(elemNode.textContent ?? ""); - } else if (elemPropType?.type === "float") { - elemValue = parseFloat(elemNode.textContent ?? ""); - } else if (elemPropType?.type === "integer") { - elemValue = parseFloat(elemNode.textContent ?? ""); + // If the elemNode's meta type has a __$$text property, this is the one we use to parse its value. + // All other properties on `elemType` are certainly attributes, which are handlded below. + const t = elemType?.["__$$text"]?.type ?? elemPropType?.type; + + let elemValue: any = {}; + if (t === "string") { + elemValue["__$$text"] = elemNode.textContent ?? ""; + } else if (t === "boolean") { + elemValue["__$$text"] = parseBoolean(elemNode.textContent ?? ""); + } else if (t === "float") { + elemValue["__$$text"] = parseFloat(elemNode.textContent ?? ""); + } else if (t === "integer") { + elemValue["__$$text"] = parseFloat(elemNode.textContent ?? ""); } else { elemValue = parse({ ...args, node: elemNode, nodeType: elemType }); if (subsedName !== nsedName) { @@ -330,11 +334,15 @@ function applyEntities(value: any) { function buildAttrs(json: any) { let isEmpty = true; + let hasText = false; let attrs = " "; for (const propName in json) { if (propName[0] === "@") { attrs += `${propName.substring(2)}="${applyEntities(json[propName])}" `; + } else if (propName === "__$$text") { + hasText = true; + isEmpty = false; } else if (propName !== "__$$element") { isEmpty = false; } @@ -344,7 +352,7 @@ function buildAttrs(json: any) { isEmpty = false; } - return { attrs: attrs.substring(0, attrs.length - 1), isEmpty }; + return { attrs: attrs.substring(0, attrs.length - 1), isEmpty, hasText }; } export function build(args: { @@ -373,6 +381,10 @@ export function build(args: { else if (propName === "__$$element") { continue; } + // ignore this. text content is treated inside the "array" and "nested element" sections. + else if (propName === "__$$text") { + continue; + } // pi tag else if (propName[0] === "?") { xml += `${indent}<${propName}${buildAttrs(propValue).attrs} ?>\n`; @@ -391,15 +403,17 @@ export function build(args: { else if (Array.isArray(propValue)) { for (const item of propValue) { const elementName = applyInstanceNs({ ns, instanceNs, propName: item["__$$element"] ?? propName }); - const { attrs, isEmpty } = buildAttrs(item); + const { attrs, isEmpty, hasText } = buildAttrs(item); xml += `${indent}<${elementName}${attrs}`; if (isEmpty) { xml += " />\n"; } else if (typeof item === "object") { - xml += `>\n${build({ ...args, json: item, indent: `${indent} ` })}`; - xml += `${indent}</${elementName}>\n`; - } else { - xml += `>${applyEntities(item)}</${elementName}>\n`; + if (hasText) { + xml += `>${applyEntities(item["__$$text"])}</${elementName}>\n`; + } else { + xml += `>\n${build({ ...args, json: item, indent: `${indent} ` })}`; + xml += `${indent}</${elementName}>\n`; + } } } } @@ -407,15 +421,17 @@ export function build(args: { else { const item = propValue; const elementName = applyInstanceNs({ ns, instanceNs, propName: item["__$$element"] ?? propName }); - const { attrs, isEmpty } = buildAttrs(item); + const { attrs, isEmpty, hasText } = buildAttrs(item); xml += `${indent}<${elementName}${attrs}`; if (isEmpty) { xml += " />\n"; } else if (typeof item === "object") { - xml += `>\n${build({ ...args, json: item, indent: `${indent} ` })}`; - xml += `${indent}</${elementName}>\n`; - } else { - xml += `>${applyEntities(item)}</${elementName}>\n`; + if (hasText) { + xml += `>${applyEntities(item["__$$text"])}</${elementName}>\n`; + } else { + xml += `>\n${build({ ...args, json: item, indent: `${indent} ` })}`; + xml += `${indent}</${elementName}>\n`; + } } } } @@ -451,7 +467,7 @@ function applyInstanceNs({ ////////////////// export type NamespacedProperty<P extends string, K> = K extends string - ? K extends `@_${string}` | `${string}:${string}` // @_xxx are attributes, xxx:xxx are elements referencing other namespaces; + ? K extends `@_${string}` | `${string}:${string}` | "__$$text" | "__$$element" // @_xxx are attributes, xxx:xxx are elements referencing other namespaces; __$$element and __$$text are special properties with no domain-related characteristcs. Therefore, not namespace-able. ? K : `${P}:${K}` : never; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
