Skip to content

Commit

Permalink
kie-issues#1051: @kie-tools/dmn-marshaller not respecting `xsd:sequ…
Browse files Browse the repository at this point in the history
…ence` declaration order when an XSD Element extends another Element (apache#2222)
  • Loading branch information
tiagobento authored Apr 1, 2024
1 parent 928ede5 commit f829ef2
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 18 deletions.
65 changes: 59 additions & 6 deletions packages/dmn-marshaller/tests/xsdSequence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,68 @@

import * as fs from "fs";
import * as path from "path";
import { getMarshaller } from "@kie-tools/dmn-marshaller";
import { DmnLatestModel, getMarshaller } from "@kie-tools/dmn-marshaller";

const files = [
{ path: "../tests-data--manual/other/decisionAndInput.dmn" },
{ path: "../tests-data--manual/other/decisionAndInput_wrongSequenceOrder.dmn" },
];
describe("build produces elements respecting the hierarchy of the element type", () => {
test("businessKnowledgeSource element", () => {
const json: DmnLatestModel = {
definitions: {
"@_name": "myDmn",
"@_namespace": "myDmnNamespace",
drgElement: [
{
__$$element: "businessKnowledgeModel",
authorityRequirement: [],
"@_name": "myBkm",
encapsulatedLogic: {
expression: {
__$$element: "literalExpression",
text: { __$$text: "myBkm literal expression" },
extensionElements: {},
},
},
variable: {
"@_name": "myBkm var",
extensionElements: {},
description: { __$$text: "myBkm var description" },
},
extensionElements: {},
description: { __$$text: "myBkm description" },
},
],
},
};
expect(
getMarshaller(
`<?xml version="1.0" encoding="UTF-8" ?><definitions name="" namespace="" xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/"/>`,
{ upgradeTo: "latest" }
).builder.build(json)
).toStrictEqual(`<?xml version="1.0" encoding="UTF-8" ?>
<definitions name="myDmn" namespace="myDmnNamespace" xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/" xmlns:dmndi="https://www.omg.org/spec/DMN/20230324/DMNDI/" xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" xmlns:di="http://www.omg.org/spec/DMN/20180521/DI/" xmlns:kie="https://kie.org/dmn/extensions/1.0">
<businessKnowledgeModel name="myBkm">
<description>myBkm description</description>
<extensionElements />
<variable name="myBkm var">
<description>myBkm var description</description>
<extensionElements />
</variable>
<encapsulatedLogic>
<literalExpression>
<extensionElements />
<text>myBkm literal expression</text>
</literalExpression>
</encapsulatedLogic>
</businessKnowledgeModel>
</definitions>
`);
});
});

describe("build always produces elements in the same order", () => {
for (const file of files) {
for (const file of [
{ path: "../tests-data--manual/other/decisionAndInput.dmn" },
{ path: "../tests-data--manual/other/decisionAndInput_wrongSequenceOrder.dmn" },
]) {
test(path.basename(file.path), () => {
const xml = fs.readFileSync(path.join(__dirname, file.path), "utf-8");
const marshaller = getMarshaller(xml, { upgradeTo: "1.5" });
Expand Down
32 changes: 20 additions & 12 deletions packages/xml-parser-ts-codegen/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,10 @@ function getMetaProperties(
ct: XptcComplexType,
metaTypeName: string
): { anonymousTypes: XptcMetaType[]; needsExtensionType: boolean; metaProperties: XptcMetaTypeProperty[] } {
const metaProperties: XptcMetaTypeProperty[] = [];
/** Accumulates all properties of this complex type (ct). Attributes and elements. */
let ctMetaProperties: XptcMetaTypeProperty[] = [];

/** Accumulates all anonymous types instantiated on this complex type's hierarchy */
const anonymousTypes: XptcMetaType[] = [];

const immediateParentType = ct.childOf
Expand All @@ -587,6 +590,7 @@ function getMetaProperties(
let needsExtensionType = ct.needsExtensionType;

while (curParentCt) {
const curParentCtMetaProperties: XptcMetaTypeProperty[] = [];
if (curParentCt?.type === "complex") {
const curParentCtMetaTypeName = getTsNameFromNamedType(
curParentCt.declaredAtRelativeLocation,
Expand All @@ -608,7 +612,7 @@ function getMetaProperties(
throw new Error(`Can't resolve local type ref ${a.localTypeRef}`);
}

metaProperties.push({
curParentCtMetaProperties.push({
declaredAt: curParentCt.declaredAtRelativeLocation,
fromType: curParentCtMetaTypeName,
elem: undefined,
Expand Down Expand Up @@ -638,7 +642,7 @@ function getMetaProperties(
name: anonymousTypeName,
properties: mp.metaProperties,
});
metaProperties.push({
curParentCtMetaProperties.push({
elem: undefined, // REALLY?
declaredAt: curParentCt.declaredAtRelativeLocation,
fromType: curParentCtMetaTypeName,
Expand All @@ -655,7 +659,7 @@ function getMetaProperties(
e.typeName
);

metaProperties.push({
curParentCtMetaProperties.push({
declaredAt: curParentCt.declaredAtRelativeLocation,
fromType: curParentCtMetaTypeName,
elem: undefined, // REALLY?
Expand Down Expand Up @@ -692,7 +696,7 @@ function getMetaProperties(
annotation: "Anonymous type from element " + referencedElement.name,
};

metaProperties.push({
curParentCtMetaProperties.push({
declaredAt: referencedElement?.declaredAtRelativeLocation,
fromType: ct.isAnonymous ? "" : curParentCtMetaTypeName,
name: referencedElement.name,
Expand Down Expand Up @@ -725,6 +729,10 @@ function getMetaProperties(
curParentCt.childOf
)
: undefined;

// Make sure the inheritance order is respected. Elements should be listed always from the most generic to the most specific type.
// Since we're iterating upwards in the hierarchy, we need to invert prepend the array with the props we find on each step of the hierarchy.
ctMetaProperties = [...curParentCtMetaProperties, ...ctMetaProperties];
curParentCt = nextParentType ? __NAMED_TYPES_BY_TS_NAME.get(nextParentType.name) : undefined;
} else if (curParentCt?.type === "simple") {
throw new Error("Can't have a non-complex type as parent of another.");
Expand All @@ -743,7 +751,7 @@ function getMetaProperties(
a.localTypeRef
);

metaProperties.push({
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: `@_${a.name}`,
Expand Down Expand Up @@ -777,7 +785,7 @@ function getMetaProperties(
annotation: "Anonymous type from element " + referencedElement.name,
};

metaProperties.push({
ctMetaProperties.push({
declaredAt: referencedElement?.declaredAtRelativeLocation,
fromType: ct.isAnonymous ? "" : metaTypeName,
name: referencedElement.name,
Expand All @@ -799,7 +807,7 @@ function getMetaProperties(
});
} else if (e.kind === "ofNamedType") {
const tsType = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, e.typeName);
metaProperties.push({
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: e.name,
Expand Down Expand Up @@ -827,7 +835,7 @@ function getMetaProperties(
name: anonymousTypeName,
properties: mp.metaProperties,
});
metaProperties.push({
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: e.name,
Expand All @@ -843,7 +851,7 @@ function getMetaProperties(

if (ct.isSimpleContent && ct.childOf) {
const t = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME, ct.declaredAtRelativeLocation, ct.childOf);
metaProperties.push({
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
name: `__$$text`,
Expand All @@ -860,11 +868,11 @@ function getMetaProperties(
if (!(ct.type === "complex" && !ct.isAnonymous && ct.isAbstract)) {
__META_TYPE_MAPPING.set(metaTypeName, {
name: metaTypeName,
properties: [...metaProperties.reduce((acc, p) => acc.set(p.name, p), new Map()).values()], // Removing duplicates.
properties: [...ctMetaProperties.reduce((acc, p) => acc.set(p.name, p), new Map()).values()], // Removing duplicates.
});
}

return { metaProperties, needsExtensionType, anonymousTypes };
return { metaProperties: ctMetaProperties, needsExtensionType, anonymousTypes };
}

function getAnonymousMetaTypeName(elementName: string, metaTypeName: string) {
Expand Down

0 comments on commit f829ef2

Please sign in to comment.