This is an automated email from the ASF dual-hosted git repository.
tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new 8b917008e91 kie-issues#1933: Preliminary changes before the new BPMN
Editor (#3161)
8b917008e91 is described below
commit 8b917008e91e1d8a6cd745b9d200434591c11ad2
Author: Tiago Bento <[email protected]>
AuthorDate: Thu May 29 19:27:19 2025 -0400
kie-issues#1933: Preliminary changes before the new BPMN Editor (#3161)
---
packages/bpmn-marshaller/package.json | 3 +-
.../src/drools-extension-metaData.ts | 165 ++++++++
packages/bpmn-marshaller/src/drools-extension.ts | 418 +++++++++++++++++++++
packages/bpmn-marshaller/src/index.ts | 120 ++++--
.../src/schemas/bpmn-2_0/Bpmn20Spec.ts} | 23 +-
.../src/schemas/bpmn-2_0/Semantic.xsd | 53 ++-
.../src/schemas/drools-1_0/README.txt | 5 +
.../src/schemas/drools-1_0/drools.xsd | 148 ++++++++
packages/bpmn-marshaller/tests/idempotency.test.ts | 4 +-
.../bpmn-marshaller/tests/namespacedAttributes.ts | 113 ++++++
packages/bpmn-marshaller/tests/typeSafety.test.ts | 2 +-
packages/bpmn-marshaller/tests/versions.test.ts | 2 +-
.../tests-e2e/__fixtures__/files/can-drive.dmn | 8 +-
.../__fixtures__/files/find-employees.dmn | 70 ++--
.../__fixtures__/files/loan-pre-qualification.dmn | 66 ++--
.../dmn-marshaller/src/schemas/kie-1_0/KIE.xsd | 2 +-
packages/dmn-marshaller/tests/xsdSequence.test.ts | 6 +-
packages/react-hooks/src/usePreviousRef.ts | 1 +
packages/xml-parser-ts-codegen/README.md | 2 +-
packages/xml-parser-ts-codegen/src/codegen.ts | 293 +++++++++++----
.../ts-gen/meta.ts | 16 +-
.../ts-gen/types.d.ts | 22 +-
packages/xml-parser-ts-codegen/src/types.d.ts | 23 +-
.../src/elementFilter.ts} | 22 +-
packages/xml-parser-ts/src/index.ts | 71 +++-
25 files changed, 1417 insertions(+), 241 deletions(-)
diff --git a/packages/bpmn-marshaller/package.json
b/packages/bpmn-marshaller/package.json
index 7462146eed8..dc1de6d4aa5 100644
--- a/packages/bpmn-marshaller/package.json
+++ b/packages/bpmn-marshaller/package.json
@@ -19,8 +19,9 @@
"src"
],
"scripts": {
- "build:codegen": "pnpm build:codegen:bpmn20",
+ "build:codegen": "pnpm build:codegen:bpmn20 && pnpm
build:codegen:drools10",
"build:codegen:bpmn20": "xml-parser-ts-codegen
./src/schemas/bpmn-2_0/BPMN20.xsd definitions",
+ "build:codegen:drools10": "xml-parser-ts-codegen
./src/schemas/drools-1_0/drools.xsd global",
"build:dev": "rimraf dist && pnpm build:codegen && tsc -p tsconfig.json",
"build:prod": "pnpm lint && rimraf dist && pnpm build:codegen && tsc -p
tsconfig.json && pnpm test",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then
\"kie-tools--eslint ./src\"",
diff --git a/packages/bpmn-marshaller/src/drools-extension-metaData.ts
b/packages/bpmn-marshaller/src/drools-extension-metaData.ts
new file mode 100644
index 00000000000..c2f84083c1a
--- /dev/null
+++ b/packages/bpmn-marshaller/src/drools-extension-metaData.ts
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import "./drools-extension";
+import { WithMetaData } from "./schemas/bpmn-2_0/ts-gen/types";
+
+export type Bpmn20KnownMetaDataKey =
+ | "elementname" // Used for any Flow Element.
+ | "customTags" // Used for Process Variables.
+ | "customDescription" // Used for "Process Instance Description" as a global
property.
+ | "customSLADueDate" // Used for "SLA Due date" as a global property.
+ | "customAbortParent" // Used for "Abort parent" flag on Call Activities.
+ | "customAsync" // Used for "Async" flag on Call Activities.
+ | "customActivationCondition" // Used for "Activation condition" expression
on Ad-hoc sub-processes.
+ | "customAutoStart" // Used for "Ad-hoc auto-start" flag on Ad-hoc
sub-processes.
+ | "customScope"; // Used for "Signal Scope" flag on intermediateThrowEvent
and endEvent Signal nodes
+
+export type Bpmn20ProcessVariableTags =
+ | "internal" // TODO: Tiago --> Used for?
+ | "required" // TODO: Tiago --> Used for?
+ | "readonly" // TODO: Tiago --> Used for?
+ | "input" // TODO: Tiago --> Used for?
+ | "output" // TODO: Tiago --> Used for?
+ | "business_relevant" // TODO: Tiago --> Used for?
+ | "tracked"; // TODO: Tiago --> Used for?
+
+/**
+ * Helps reading drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @returns A map containing the metaData entries indexed by their name
attribute.
+ */
+export function parseBpmn20Drools10MetaData(
+ obj: undefined | { extensionElements?: WithMetaData }
+): Map<Bpmn20KnownMetaDataKey, string> {
+ const metadata = new Map<Bpmn20KnownMetaDataKey, string>();
+
+ for (let i = 0; i < (obj?.extensionElements?.["drools:metaData"] ??
[]).length; i++) {
+ const entry = obj!.extensionElements!["drools:metaData"]![i];
+ if (entry["@_name"] !== undefined) {
+ metadata.set(entry["@_name"] as Bpmn20KnownMetaDataKey,
entry["drools:metaValue"].__$$text);
+ }
+ }
+
+ return metadata;
+}
+
+/**
+ * Helps changing drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param keyOrIndex The drools:metaData entry name or entry index.
+ * @param value The drools:metaData entry value.
+ */
+export function setBpmn20Drools10MetaData(
+ obj: undefined | { extensionElements?: WithMetaData },
+ keyOrIndex: Bpmn20KnownMetaDataKey | number,
+ value: string
+): void {
+ if (obj) {
+ obj.extensionElements ??= { "drools:metaData": [] };
+ obj.extensionElements["drools:metaData"] ??= [];
+ }
+
+ if (typeof keyOrIndex === "number") {
+ if (obj?.extensionElements?.["drools:metaData"]?.[keyOrIndex]) {
+ obj.extensionElements["drools:metaData"][keyOrIndex]["drools:metaValue"]
= { __$$text: value };
+ } else {
+ // nothing to do.
+ }
+ } else {
+ let updated = false;
+ for (let i = 0; i < (obj?.extensionElements?.["drools:metaData"]?.length
?? 0); i++) {
+ const entry = obj!.extensionElements!["drools:metaData"]![i]!;
+ if (entry["@_name"] === keyOrIndex) {
+ if (updated) {
+ break;
+ }
+ entry["drools:metaValue"] = { __$$text: value };
+ updated = true;
+ }
+ }
+
+ if (!updated) {
+ obj?.extensionElements?.["drools:metaData"]?.push({
+ "@_name": keyOrIndex,
+ "drools:metaValue": { __$$text: value },
+ });
+ }
+ }
+}
+
+/**
+ * Helps adding drools:metaData entries to objects.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param key The drools:metaData entry name.
+ * @param value The drools:metaData entry value.
+ */
+export function addBpmn20Drools10MetaData(
+ obj: undefined | { extensionElements?: WithMetaData },
+ key: Bpmn20KnownMetaDataKey,
+ value: string
+): void {
+ if (obj) {
+ obj.extensionElements ??= { "drools:metaData": [] };
+ obj.extensionElements["drools:metaData"] ??= [];
+ obj.extensionElements["drools:metaData"]?.push({
+ "@_name": key,
+ "drools:metaValue": { __$$text: value },
+ });
+ }
+}
+
+/**
+ * Helps renaming drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param index The drools:metaData entry index.
+ * @param newKeyName The new drools:metaData entry name.
+ */
+export function renameBpmn20Drools10MetaDataEntry(
+ obj: undefined | { extensionElements?: WithMetaData },
+ index: number,
+ newKeyName: string
+): void {
+ if (obj?.extensionElements?.["drools:metaData"]?.[index]) {
+ obj.extensionElements["drools:metaData"][index]["@_name"] = newKeyName;
+ }
+}
+
+/**
+ * Helps deleting drools:metaData entries.
+ *
+ * @param obj The object to extract drools:metaData from. No-op if undefined.
+ * @param index The drools:metaData entry name.
+ */
+export function deleteBpmn20Drools10MetaDataEntry(
+ obj: undefined | { extensionElements?: WithMetaData },
+ keyOrIndex: string | number
+): void {
+ if (typeof keyOrIndex === "number") {
+ obj?.extensionElements?.["drools:metaData"]?.splice(keyOrIndex, 1);
+ } else if (obj?.extensionElements?.["drools:metaData"]) {
+ obj.extensionElements!["drools:metaData"] =
obj.extensionElements["drools:metaData"].filter(
+ (m) => m["@_name"] !== keyOrIndex
+ );
+ }
+}
diff --git a/packages/bpmn-marshaller/src/drools-extension.ts
b/packages/bpmn-marshaller/src/drools-extension.ts
new file mode 100644
index 00000000000..57fb49c18b2
--- /dev/null
+++ b/packages/bpmn-marshaller/src/drools-extension.ts
@@ -0,0 +1,418 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Namespaced, mergeMetas } from "@kie-tools/xml-parser-ts";
+
+import { meta as bpmn20meta, ns as bpmn20ns } from
"./schemas/bpmn-2_0/ts-gen/meta";
+import "./schemas/bpmn-2_0/ts-gen/types";
+
+import { meta as drools10meta, ns as drools10ns } from
"./schemas/drools-1_0/ts-gen/meta";
+import {
+ drools__GLOBAL__global,
+ drools__GLOBAL__import,
+ drools__GLOBAL__metaData,
+ drools__GLOBAL__onEntry_script,
+ drools__GLOBAL__onExit_script,
+} from "./schemas/drools-1_0/ts-gen/types";
+
+export const DROOLS_NS__PRE_GWT_REMOVAL = "http://www.jboss.org/drools";
+export const DROOLS_NS = "drools:";
+export type DROOLS = "drools";
+
+export { Namespaced };
+
+export const BUSINESS_RULE_TASK_IMPLEMENTATIONS = {
+ drools: "http://www.jboss.org/drools/rule",
+ dmn: "http://www.jboss.org/drools/dmn",
+};
+
+export const
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING = {
+ FILE_PATH: "fileName",
+ NAMESPACE: "namespace",
+ MODEL_NAME: "model",
+};
+
+export const USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING
= {
+ TASK_NAME: "TaskName",
+ SKIPPABLE: "Skippable",
+ GROUP_ID: "GroupId",
+ COMMENT: "Comment",
+ DESCRIPTION: "Description",
+ PRIORITY: "Priority",
+ CREATED_BY: "CreatedBy",
+ CONTENT: "Content",
+ NOT_STARTED_REASSIGN: "NotStartedReassign",
+ NOT_COMPLETED_REASSIGN: "NotCompletedReassign",
+ NOT_STARTED_NOTIFY: "NotStartedNotify",
+ NOT_COMPLETELY_NOTIFY: "NotCompletedNotify",
+ MULTI_INSTANCE_ITEM_TYPE: "multiInstanceItemType",
+};
+
+export const DATA_INPUT_RESERVED_NAMES = new Set([
+
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.FILE_PATH,
+
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NAMESPACE,
+
BUSINESS_RULE_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.MODEL_NAME,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.TASK_NAME,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.SKIPPABLE,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.GROUP_ID,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.COMMENT,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.DESCRIPTION,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.PRIORITY,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.CREATED_BY,
+ USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.CONTENT,
+
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_STARTED_REASSIGN,
+
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_COMPLETED_REASSIGN,
+
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_STARTED_NOTIFY,
+
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.NOT_COMPLETELY_NOTIFY,
+
USER_TASK_IO_SPECIFICATION_DATA_INPUTS_CONSTANTS_FOR_DMN_BINDING.MULTI_INSTANCE_ITEM_TYPE,
+]);
+
+export const SERVICE_TASK_IMPLEMENTATIONS = {
+ java: "Java",
+ webService: "WebService",
+};
+
+///////////////////////////
+/// BPMN 2.0 ///
+///////////////////////////
+
+declare module "./schemas/bpmn-2_0/ts-gen/types" {
+ type WithMetaData = {
+ "drools:metaData"?: Namespaced<DROOLS, drools__GLOBAL__metaData>[];
+ };
+
+ export interface BPMN20__tProcess {
+ "@_drools:packageName"?: Namespaced<DROOLS, string>;
+ "@_drools:version"?: Namespaced<DROOLS, string>;
+ "@_drools:adHoc"?: Namespaced<DROOLS, boolean>;
+ }
+
+ export interface BPMN20__tProcess__extensionElements extends WithMetaData,
WithEntryAndExitScripts {
+ "drools:import"?: Namespaced<DROOLS, drools__GLOBAL__import>[];
+ "drools:global"?: Namespaced<DROOLS, drools__GLOBAL__global>[];
+ }
+
+ type WithEntryAndExitScripts = {
+ "drools:onEntry-script"?: Namespaced<DROOLS,
drools__GLOBAL__onEntry_script>;
+ "drools:onExit-script"?: Namespaced<DROOLS, drools__GLOBAL__onExit_script>;
+ };
+
+ // *************************************************** NOTE
******************************************************
+ //
+ // Some sequenceFlow elements are commented on purpose. They're here for
completeness, but they're not currently
+ // relevant by this BPMN marshaller, since none of those
are executable.
+ //
+ //
***************************************************************************************************************
+
+ export interface BPMN20__tAdHocSubProcess__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tBoundaryEvent__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tBusinessRuleTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tCallActivity__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tCallChoreography__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tChoreographyTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tComplexGateway__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tDataObject__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tDataObjectReference__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tDataStoreReference__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tEndEvent__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tEvent__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tEventBasedGateway__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tExclusiveGateway__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tImplicitThrowEvent__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tInclusiveGateway__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tIntermediateCatchEvent__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tIntermediateThrowEvent__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tManualTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tParallelGateway__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tReceiveTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tScriptTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tSendTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tSequenceFlow__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tServiceTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tStartEvent__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ // export interface BPMN20__tSubChoreography__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tSubProcess__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tTransaction__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tUserTask__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tAssociation__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tGroup__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+ export interface BPMN20__tTextAnnotation__extensionElements extends
WithEntryAndExitScripts, WithMetaData {}
+
+ // Other
+ export interface BPMN20__tProperty__extensionElements extends WithMetaData {}
+ export interface BPMN20__tLane__extensionElements extends WithMetaData {}
+
+ // Call activity
+ export interface BPMN20__tCallActivity {
+ "@_drools:independent"?: Namespaced<DROOLS, boolean>;
+ "@_drools:waitForCompletion"?: Namespaced<DROOLS, boolean>;
+ }
+
+ // Service task
+ export interface BPMN20__tServiceTask {
+ "@_drools:serviceimplementation"?: Namespaced<DROOLS, string>;
+ "@_drools:serviceinterface"?: Namespaced<DROOLS, string>;
+ "@_drools:serviceoperation"?: Namespaced<DROOLS, string>;
+ }
+
+ // Business Rule task
+ export interface BPMN20__tBusinessRuleTask {
+ "@_drools:ruleFlowGroup"?: Namespaced<DROOLS, string>;
+ }
+
+ // Data Input
+ export interface BPMN20__tDataInput {
+ "@_drools:dtype"?: Namespaced<DROOLS, string>;
+ }
+
+ // Data Output
+ export interface BPMN20__tDataOutput {
+ "@_drools:dtype"?: Namespaced<DROOLS, string>;
+ }
+
+ // Message Event Definition
+ export interface BPMN20__tMessageEventDefinition {
+ "@_drools:msgref"?: Namespaced<DROOLS, string>;
+ }
+
+ // Escalation Event Definition
+ export interface BPMN20__tEscalationEventDefinition {
+ "@_drools:esccode"?: Namespaced<DROOLS, string>;
+ }
+
+ // Error Event Definition
+ export interface BPMN20__tErrorEventDefinition {
+ "@_drools:erefname"?: Namespaced<DROOLS, string>;
+ }
+
+ // Sequence Flow Definition
+ export interface BPMN20__tSequenceFlow {
+ "@_drools:priority"?: Namespaced<DROOLS, string>;
+ }
+}
+
+bpmn20ns.set(DROOLS_NS, drools10ns.get("")!);
+bpmn20ns.set(drools10ns.get("")!, DROOLS_NS);
+
+mergeMetas(bpmn20meta, [[DROOLS_NS, drools10meta]]);
+
+// Process attrs
+(bpmn20meta["BPMN20__tProcess"] as any)["@_drools:packageName"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tProcess",
+};
+(bpmn20meta["BPMN20__tProcess"] as any)["@_drools:version"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tProcess",
+};
+(bpmn20meta["BPMN20__tProcess"] as any)["@_drools:adHoc"] = {
+ type: "boolean",
+ isArray: false,
+ xsdType: "xsd:boolean",
+ fromType: "BPMN20__tProcess",
+};
+
+// Process elements
+(bpmn20meta["BPMN20__tProcess__extensionElements"] as any)["drools:import"] = {
+ type: "drools__GLOBAL__import",
+ isArray: true,
+ xsdType: "// local type",
+ fromType: "BPMN20__tProcess__extensionElements",
+};
+(bpmn20meta["BPMN20__tProcess__extensionElements"] as any)["drools:global"] = {
+ type: "drools__GLOBAL__global",
+ isArray: true,
+ xsdType: "// local type",
+ fromType: "BPMN20__tProcess__extensionElements",
+};
+
+// Business Rule Task attrs
+(bpmn20meta["BPMN20__tBusinessRuleTask"] as any)["@_drools:ruleFlowGroup"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tBusinessRuleTask",
+};
+
+// Call Activity attrs
+(bpmn20meta["BPMN20__tCallActivity"] as any)["@_drools:independent"] = {
+ type: "boolean",
+ isArray: false,
+ xsdType: "xsd:boolean",
+ fromType: "BPMN20__tCallActivity",
+};
+(bpmn20meta["BPMN20__tCallActivity"] as any)["@_drools:waitForCompletion"] = {
+ type: "boolean",
+ isArray: false,
+ xsdType: "xsd:boolean",
+ fromType: "BPMN20__tCallActivity",
+};
+
+// Service Task attrs
+(bpmn20meta["BPMN20__tServiceTask"] as any)["@_drools:serviceimplementation"]
= {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tServiceTask",
+};
+(bpmn20meta["BPMN20__tServiceTask"] as any)["@_drools:serviceinterface"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tServiceTask",
+};
+(bpmn20meta["BPMN20__tServiceTask"] as any)["@_drools:serviceoperation"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tServiceTask",
+};
+
+// Data Input
+(bpmn20meta["BPMN20__tDataInput"] as any)["@_drools:dtype"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tDataInput",
+};
+// Data Output
+(bpmn20meta["BPMN20__tDataOutput"] as any)["@_drools:dtype"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tDataOutput",
+};
+
+// Message Event Definition
+(bpmn20meta["BPMN20__tMessageEventDefinition"] as any)["@_drools:msgref"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tMessageEventDefinition",
+};
+
+// Escalation Event Definition
+(bpmn20meta["BPMN20__tEscalationEventDefinition"] as any)["@_drools:esccode"]
= {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tEscalationEventDefinition",
+};
+
+// Error Event Definition
+(bpmn20meta["BPMN20__tErrorEventDefinition"] as any)["@_drools:erefname"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tErrorEventDefinition",
+};
+
+// Error Event Definition
+(bpmn20meta["BPMN20__tSequenceFlow"] as any)["@_drools:priority"] = {
+ type: "string",
+ isArray: false,
+ xsdType: "xsd:string",
+ fromType: "BPMN20__tSequenceFlow",
+};
+
+class MetaType {
+ public static of(typeName: keyof typeof bpmn20meta) {
+ return new MetaType(typeName);
+ }
+
+ private constructor(private readonly typeName: keyof typeof bpmn20meta) {}
+
+ public hasMetadata() {
+ (bpmn20meta[this.typeName] as any)["drools:metaData"] = {
+ type: "drools__GLOBAL__metaData",
+ isArray: true,
+ xsdType: "// local type",
+ fromType: this.typeName,
+ };
+ return this;
+ }
+
+ public hasEntryAndExitScripts() {
+ (bpmn20meta[this.typeName] as any)["drools:onEntry-script"] = {
+ type: "drools__GLOBAL__onEntry_script",
+ isArray: false,
+ xsdType: "// local type",
+ fromType: this.typeName,
+ };
+ (bpmn20meta[this.typeName] as any)["drools:onExit-script"] = {
+ type: "drools__GLOBAL__onExit_script",
+ isArray: false,
+ xsdType: "// local type",
+ fromType: this.typeName,
+ };
+ return this;
+ }
+}
+
+//
+// See some of those are commented above too.
+//
+MetaType.of("BPMN20__tAdHocSubProcess__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tBoundaryEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tBusinessRuleTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tCallActivity__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tCallChoreography__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tChoreographyTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tComplexGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tDataObject__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tDataObjectReference__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tDataStoreReference__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tEndEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tEventBasedGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tExclusiveGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tImplicitThrowEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tInclusiveGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tIntermediateCatchEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tIntermediateThrowEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tManualTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tParallelGateway__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tReceiveTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tScriptTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tSendTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tSequenceFlow__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tServiceTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tStartEvent__extensionElements").hasEntryAndExitScripts().hasMetadata();
+//
MetaType.of("BPMN20__tSubChoreography__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tSubProcess__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tTransaction__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tUserTask__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tAssociation__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tGroup__extensionElements").hasEntryAndExitScripts().hasMetadata();
+MetaType.of("BPMN20__tTextAnnotation__extensionElements").hasEntryAndExitScripts().hasMetadata();
+
+// Process
+MetaType.of("BPMN20__tProcess__extensionElements").hasMetadata();
+
+// Property
+MetaType.of("BPMN20__tProperty__extensionElements").hasMetadata();
+
+// Lane
+MetaType.of("BPMN20__tLane__extensionElements").hasMetadata();
diff --git a/packages/bpmn-marshaller/src/index.ts
b/packages/bpmn-marshaller/src/index.ts
index 434642fda7f..df373603d2b 100644
--- a/packages/bpmn-marshaller/src/index.ts
+++ b/packages/bpmn-marshaller/src/index.ts
@@ -17,46 +17,122 @@
* under the License.
*/
-import { Meta, getInstanceNs, domParser, getParser } from
"@kie-tools/xml-parser-ts";
+import { Meta, XmlParserTs, domParser, getInstanceNs, getParser } from
"@kie-tools/xml-parser-ts";
import {
- meta as bpmn20meta,
- elements as bpmn20elements,
subs as bpmn20subs,
+ elements as bpmn20elements,
+ meta as bpmn20meta,
root as bpmn20root,
ns as bpmn20ns,
} from "./schemas/bpmn-2_0/ts-gen/meta";
-
import { BPMN20__tDefinitions } from "./schemas/bpmn-2_0/ts-gen/types";
-type BpmnDefinitions = { definitions: BPMN20__tDefinitions };
+export type BpmnMarshaller<V extends BpmnMarshallerVersions = "latest"> =
InternalBpmnMarshaller<V> & {
+ originalVersion: BpmnVersions;
+ isLatest: boolean;
+};
+
+export type InternalBpmnMarshaller<V extends BpmnMarshallerVersions =
"latest"> = V extends "2.0"
+ ? BpmnMarshaller20
+ : V extends "latest"
+ ? BpmnLatestMarshaller
+ : never;
-type BpmnMarshaller = {
- parser: { parse(): BpmnDefinitions };
- builder: { build(json: BpmnDefinitions): string };
+export type BpmnMarshallerBase = {
instanceNs: Map<string, string>;
root: { element: string; type: string };
meta: Meta;
- version: "2.0";
};
-export function getMarshaller(xml: string): BpmnMarshaller {
- const domdoc = domParser.getDomDocument(xml);
- const instanceNs = getInstanceNs(domdoc);
+export type AllBpmnMarshallers = BpmnMarshaller20;
+
+export type KieExtensionVersions = "0.0" | "1.0";
+export type BpmnVersions = AllBpmnMarshallers["version"];
+export type BpmnMarshallerVersions = AllBpmnMarshallers["version"] | "latest";
+
+export type BpmnMarshaller20 = BpmnMarshallerBase & {
+ parser: { parse(): { definitions: BPMN20__tDefinitions } };
+ builder: { build(json: { definitions: BPMN20__tDefinitions }): string };
+ version: "2.0";
+};
- const p = getParser<BpmnDefinitions>({
+export const BPMN_PARSERS: Record<BpmnVersions, XmlParserTs<any>> = {
+ "2.0": getParser<{ [bpmn20root.element]: BPMN20__tDefinitions }>({
ns: bpmn20ns,
meta: bpmn20meta,
subs: bpmn20subs,
elements: bpmn20elements,
root: bpmn20root,
- });
+ }),
+};
- return {
- instanceNs,
- version: "2.0",
- root: bpmn20root,
- meta: bpmn20meta,
- parser: { parse: () => p.parse({ type: "domdoc", domdoc, instanceNs
}).json },
- builder: { build: (json: BpmnDefinitions) => p.build({ json, instanceNs })
},
- };
+export const BPMN_VERSIONS_TIMELINE: BpmnVersions[] = ["2.0"];
+export const BPMN_LATEST_VERSION = "2.0" as const;
+export type BpmnLatestMarshaller = BpmnMarshaller20;
+export type BpmnLatestModel = { [bpmn20root.element]: BPMN20__tDefinitions };
+
+export type BpmnMarshallerOpts<V extends BpmnMarshallerVersions> = {
upgradeTo?: V };
+
+export function getMarshaller<V extends BpmnMarshallerVersions>(
+ xml: string,
+ opts?: BpmnMarshallerOpts<V>
+): BpmnMarshaller<V> {
+ const originalDomdoc = domParser.getDomDocument(xml);
+ const originalInstanceNs = getInstanceNs(originalDomdoc);
+
+ const originalMarshaller = getMarshallerForFixedVersion(originalDomdoc,
originalInstanceNs);
+
+ // `opts.upgradeTo` is optional. It defaults to not upgrading at all.
"latest" is an alias to whatever the `BPMN_LATEST_VERSION` constante declares.
+ const targetVersion: BpmnVersions =
+ opts?.upgradeTo === "latest" ? BPMN_LATEST_VERSION : opts?.upgradeTo ??
originalMarshaller.version;
+
+ // If the XML is already on the latest version, we don't do anything else
and just return the marshaller.
+ if (originalMarshaller.version === targetVersion) {
+ return {
+ ...(originalMarshaller as InternalBpmnMarshaller<V>),
+ originalVersion: originalMarshaller.version,
+ isLatest: true,
+ };
+ } else {
+ throw new Error(
+ `BPMN MARSHALLER: Cannot build BPMN ${targetVersion} marshaller from a
model that's already in version '${originalMarshaller.version}'. Downgrading
BPMN models is not possible.`
+ );
+ }
+}
+
+export function getBpmnVersion(instanceNs: Map<string, string>): BpmnVersions {
+ // Do not remove this '!== undefined', as "" is a valid namespace on the
instanceNs map, although it is a falsy value.
+ if (instanceNs.get(bpmn20ns.get("")!) !== undefined) {
+ return "2.0";
+ }
+ // None.. throw error
+ else {
+ throw new Error(
+ `BPMN MARSHALLER: Unknown version declared for BPMN. Instance NS -->
'${JSON.stringify([
+ ...instanceNs.entries(),
+ ])}'.`
+ );
+ }
+}
+
+export function getMarshallerForFixedVersion(domdoc: Document, instanceNs:
Map<string, string>): AllBpmnMarshallers {
+ const version = getBpmnVersion(instanceNs);
+
+ switch (version) {
+ case "2.0":
+ return {
+ instanceNs,
+ version: "2.0",
+ root: bpmn20root,
+ meta: bpmn20meta,
+ parser: { parse: () => BPMN_PARSERS["2.0"].parse({ type: "domdoc",
domdoc, instanceNs }).json },
+ builder: { build: (json) => BPMN_PARSERS["2.0"].build({ json,
instanceNs }) },
+ };
+ default:
+ throw new Error(
+ `BPMN MARSHALLER: Unknown version declared for BPMN. Instance NS -->
'${JSON.stringify([
+ ...instanceNs.entries(),
+ ])}'.`
+ );
+ }
}
diff --git a/packages/react-hooks/src/usePreviousRef.ts
b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Bpmn20Spec.ts
similarity index 56%
copy from packages/react-hooks/src/usePreviousRef.ts
copy to packages/bpmn-marshaller/src/schemas/bpmn-2_0/Bpmn20Spec.ts
index b5855874e6a..995efdfeb55 100644
--- a/packages/react-hooks/src/usePreviousRef.ts
+++ b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Bpmn20Spec.ts
@@ -17,16 +17,19 @@
* under the License.
*/
-import { useEffect, useRef } from "react";
+import { ns as bpmn20ns } from "../bpmn-2_0/ts-gen/meta";
-export function usePreviousRef<T>(value: T): React.MutableRefObject<T> {
- const ref = useRef<T>(value);
+export type UniqueNameIndex = Map<string, string>;
- useEffect(() => {
- if (ref.current !== value) {
- ref.current = value;
- }
- }, [value]);
+export const BPMN20_SPEC = {
+ isValidName: (id: string, name: string | undefined, allUniqueNames:
UniqueNameIndex): boolean => {
+ return true; // FIXME: Tiago: Implement (valid name)
+ },
+};
- return ref;
-}
+export const allBpmnImportNamespaces = new Set([bpmn20ns.get("")!]);
+
+export const KIE_BPMN_UNKNOWN_NAMESPACE =
"https://kie.apache.org/bpmn/unknown";
+
+export const BOUNDARY_EVENT_CANCEL_ACTIVITY_DEFAULT_VALUE = true;
+export const
START_EVENT_NODE_ON_EVENT_SUB_PROCESSES_IS_INTERRUPTING_DEFAULT_VALUE = true;
diff --git a/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd
b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd
index 83ffee85c33..71850dec2cd 100644
--- a/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd
+++ b/packages/bpmn-marshaller/src/schemas/bpmn-2_0/Semantic.xsd
@@ -58,8 +58,14 @@
<xsd:complexContent>
<xsd:extension base="tBaseElement">
<xsd:sequence>
- <xsd:element name="from" type="tExpression" minOccurs="1"
maxOccurs="1" />
- <xsd:element name="to" type="tExpression" minOccurs="1"
maxOccurs="1" />
+ <xsd:element name="from" type="tFormalExpression" minOccurs="1"
maxOccurs="1" />
+ <xsd:element name="to" type="tFormalExpression" minOccurs="1"
maxOccurs="1" />
+ <xsd:element name="inputName" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" />
+ <xsd:element name="inputDataType" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" />
+ <xsd:element name="inputSource" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" />
+ <xsd:element name="outputName" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" />
+ <xsd:element name="outputDataType" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" />
+ <xsd:element name="outputTarget" type="xsd:string" minOccurs="0"
maxOccurs="unbounded" />
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
@@ -95,7 +101,15 @@
<xsd:complexType name="tBaseElement" abstract="true">
<xsd:sequence>
<xsd:element ref="documentation" minOccurs="0" maxOccurs="unbounded" />
- <xsd:element ref="extensionElements" minOccurs="0" maxOccurs="1" />
+ <!-- (begin) Manually edited. Inlined `tExtensionElements` for type-safe
extensibility. -->
+ <xsd:element name="extensionElements" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- (end) -->
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID" use="optional" />
<xsd:anyAttribute namespace="##other" processContents="lax" />
@@ -105,7 +119,15 @@
<xsd:complexType name="tBaseElementWithMixedContent" abstract="true"
mixed="true">
<xsd:sequence>
<xsd:element ref="documentation" minOccurs="0" maxOccurs="unbounded" />
- <xsd:element ref="extensionElements" minOccurs="0" maxOccurs="1" />
+ <!-- (begin) Manually edited. Inlined `tExtensionElements` for type-safe
extensibility. -->
+ <xsd:element name="extensionElements" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- (end) -->
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID" use="optional" />
<xsd:anyAttribute namespace="##other" processContents="lax" />
@@ -177,13 +199,6 @@
</xsd:complexContent>
</xsd:complexType>
- <xsd:element name="cancelEventDefinition" type="tCancelEventDefinition"
substitutionGroup="eventDefinition" />
- <xsd:complexType name="tCancelEventDefinition">
- <xsd:complexContent>
- <xsd:extension base="tEventDefinition" />
- </xsd:complexContent>
- </xsd:complexType>
-
<xsd:element name="catchEvent" type="tCatchEvent" />
<xsd:complexType name="tCatchEvent" abstract="true">
<xsd:complexContent>
@@ -682,12 +697,13 @@
<xsd:attribute name="mustUnderstand" type="xsd:boolean" use="optional"
default="false" />
</xsd:complexType>
- <xsd:element name="extensionElements" type="tExtensionElements" />
+ <!-- Manually edited. This is inlined in baseElement and
baseElementWithMixedContent, for type-safe extensibility. -->
+ <!-- <xsd:element name="extensionElements" type="tExtensionElements" />
<xsd:complexType name="tExtensionElements">
<xsd:sequence>
<xsd:any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded" />
</xsd:sequence>
- </xsd:complexType>
+ </xsd:complexType> -->
<xsd:element name="flowElement" type="tFlowElement" />
<xsd:complexType name="tFlowElement" abstract="true">
@@ -802,8 +818,14 @@
<xsd:complexContent>
<xsd:extension base="tGlobalTask">
<xsd:sequence>
+ <xsd:element name="taskName" type="xsd:string" minOccurs="0"
maxOccurs="1" />
+ <xsd:element name="subject" type="xsd:string" minOccurs="0"
maxOccurs="1" />
+ <xsd:element name="content" type="xsd:string" minOccurs="0"
maxOccurs="1" />
+ <xsd:element name="priority" type="xsd:string" minOccurs="0"
maxOccurs="1" />
<xsd:element ref="rendering" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
+ <xsd:attribute name="description" type="xsd:string" use="optional" />
+ <xsd:attribute name="skippable" type="xsd:boolean" default="false" />
<xsd:attribute name="implementation" type="tImplementation"
default="##unspecified" />
</xsd:extension>
</xsd:complexContent>
@@ -1498,19 +1520,22 @@
<xsd:complexContent>
<xsd:extension base="tArtifact">
<xsd:sequence>
- <xsd:element ref="text" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="text" type="xsd:string" minOccurs="0"
maxOccurs="1" />
</xsd:sequence>
<xsd:attribute name="textFormat" type="xsd:string"
default="text/plain" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
+ <!-- Manually edited to make this type-safe -->
+ <!--
<xsd:element name="text" type="tText" />
<xsd:complexType name="tText" mixed="true">
<xsd:sequence>
<xsd:any namespace="##any" processContents="lax" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
+ -->
<xsd:element name="throwEvent" type="tThrowEvent" />
<xsd:complexType name="tThrowEvent" abstract="true">
diff --git a/packages/bpmn-marshaller/src/schemas/drools-1_0/README.txt
b/packages/bpmn-marshaller/src/schemas/drools-1_0/README.txt
new file mode 100644
index 00000000000..0467ea8cada
--- /dev/null
+++ b/packages/bpmn-marshaller/src/schemas/drools-1_0/README.txt
@@ -0,0 +1,5 @@
+This extension for BPMN 2.0 has been in place since before migrating to Apache
KIE, back when KIE was managed by Red Hat.
+
+To ensure retro-compatibility, this is being kept as is.
+
+In the future we can migrate to a "KIE" extension, instead of "Drools".
diff --git a/packages/bpmn-marshaller/src/schemas/drools-1_0/drools.xsd
b/packages/bpmn-marshaller/src/schemas/drools-1_0/drools.xsd
new file mode 100644
index 00000000000..941be9e96a4
--- /dev/null
+++ b/packages/bpmn-marshaller/src/schemas/drools-1_0/drools.xsd
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:drools="http://www.jboss.org/drools"
+ targetNamespace="http://www.jboss.org/drools"
+ elementFormDefault="qualified"
+>
+ <xsd:attribute name="packageName">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attribute name="version">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attribute name="ruleFlowGroup">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attribute name="taskName">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attribute name="priority">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="1" />
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attribute name="msgref">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attribute name="esccode">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attribute name="erefname">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string" />
+ </xsd:simpleType>
+ </xsd:attribute>
+
+ <xsd:attributeGroup name="onxscriptattributes">
+ <xsd:attribute name="scriptFormat" type="xsd:string" use="required" />
+ </xsd:attributeGroup>
+
+ <xsd:attributeGroup name="importattributes">
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:attributeGroup>
+
+ <xsd:attributeGroup name="globalattributes">
+ <xsd:attribute name="identifier" type="xsd:string" use="required" />
+ <xsd:attribute name="type" type="xsd:string" use="required" />
+ </xsd:attributeGroup>
+
+ <xsd:element name="onEntry-script">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="script" minOccurs="1" maxOccurs="1"
type="xsd:string" />
+ </xsd:sequence>
+ <xsd:attributeGroup ref="drools:onxscriptattributes" />
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="onExit-script">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="script" minOccurs="1" maxOccurs="1"
type="xsd:string" />
+ </xsd:sequence>
+ <xsd:attributeGroup ref="drools:onxscriptattributes" />
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="import">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="drools:importattributes" />
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="global">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="drools:globalattributes" />
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- Manually written to reflect what's actually happening on BPMN Editor
(classic) -->
+ <xsd:element name="metaData">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="metaValue" minOccurs="1" maxOccurs="1"
type="xsd:string" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- Manually edited to reflect what's actually happening on BPMN Editor
(classic) -->
+ <!--
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element maxOccurs="unbounded" ref="drools:metaentry" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="metaentry">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1"
/>
+ <xsd:element name="value" type="xsd:string" minOccurs="1"
maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ -->
+</xsd:schema>
diff --git a/packages/bpmn-marshaller/tests/idempotency.test.ts
b/packages/bpmn-marshaller/tests/idempotency.test.ts
index 8b08bec2e0d..6156f8baeae 100644
--- a/packages/bpmn-marshaller/tests/idempotency.test.ts
+++ b/packages/bpmn-marshaller/tests/idempotency.test.ts
@@ -28,11 +28,11 @@ describe("idempotency", () => {
test(path.basename(file), () => {
const xml_original = fs.readFileSync(path.join(__dirname, file),
"utf-8");
- const { parser, builder } = getMarshaller(xml_original);
+ const { parser, builder } = getMarshaller(xml_original, { upgradeTo:
"latest" });
const json = parser.parse();
const xml_firstPass = builder.build(json);
- const xml_secondPass =
builder.build(getMarshaller(xml_firstPass).parser.parse());
+ const xml_secondPass = builder.build(getMarshaller(xml_firstPass, {
upgradeTo: "latest" }).parser.parse());
expect(xml_firstPass).toStrictEqual(xml_secondPass);
});
diff --git a/packages/bpmn-marshaller/tests/namespacedAttributes.ts
b/packages/bpmn-marshaller/tests/namespacedAttributes.ts
new file mode 100644
index 00000000000..465b806941e
--- /dev/null
+++ b/packages/bpmn-marshaller/tests/namespacedAttributes.ts
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { getMarshaller } from "@kie-tools/bpmn-marshaller";
+import { DROOLS_NS__PRE_GWT_REMOVAL } from
"@kie-tools/bpmn-marshaller/dist/drools-extension";
+import { BPMN20__tProcess } from "../dist/schemas/bpmn-2_0/ts-gen/types";
+import "@kie-tools/bpmn-marshaller/dist/drools-extension";
+
+const defaultXmlns = `targetNamespace=""
+ xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
+ xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
+ xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
+ xmlns:di="http://www.omg.org/spec/DD/20100524/DI"`;
+
+// Baseline case, happy path.
+describe("namespaced attributes from drools.xsd extension", () => {
+ test("normal", () => {
+ const normal = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+ ${defaultXmlns}
+ xmlns:drools="http://www.jboss.org/drools"
+>
+ <bpmn2:process drools:version="1.0.0" />
+</bpmn2:definitions>`;
+
+ const marshaller = getMarshaller(normal, { upgradeTo: "latest" });
+ const json = marshaller.parser.parse();
+
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+ expect((json.definitions.rootElement?.[0] as
BPMN20__tProcess)["@_drools:version"]).toStrictEqual("1.0.0");
+
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(normal));
+ });
+
+ // Maps the `drools` namespace as the default.
+ // Since attributes are unnamespaced by default, having a default namespace
mapped doesn't mean unqualified attributes will all be
+ // assigned to the default namespace.
+ test("defaultNs", () => {
+ const defaultNs = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+ ${defaultXmlns}
+ xmlns="http://www.jboss.org/drools"
+>
+ <bpmn2:process version="1.0.0" />
+</bpmn2:definitions>`;
+
+ const marshaller = getMarshaller(defaultNs, { upgradeTo: "latest" });
+ const json = marshaller.parser.parse();
+
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+
expect(json.definitions["@_xmlns"]).toStrictEqual(DROOLS_NS__PRE_GWT_REMOVAL);
+ expect(json.definitions["@_xmlns:drools"]).toStrictEqual(undefined);
+ expect((json.definitions.rootElement?.[0] as
BPMN20__tProcess)["@_drools:version"]).toStrictEqual(undefined);
+ expect((json.definitions.rootElement?.[0] as
any)["@_version"]).toStrictEqual("1.0.0");
+
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(defaultNs));
+ });
+
+ // Uses a different declaration name for the `drools` namespace.
+ test("renamed", () => {
+ const renamed = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+ ${defaultXmlns}
+ xmlns:droolz="http://www.jboss.org/drools"
+>
+ <bpmn2:process droolz:version="1.0.0" />
+</bpmn2:definitions>`;
+
+ const marshaller = getMarshaller(renamed, { upgradeTo: "latest" });
+ const json = marshaller.parser.parse();
+
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+ expect((json.definitions.rootElement?.[0] as
BPMN20__tProcess)["@_drools:version"]).toStrictEqual("1.0.0");
+ expect((json.definitions.rootElement?.[0] as
any)["@_droolz:version"]).toStrictEqual(undefined);
+
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(renamed));
+ });
+
+ // Uses a generic attribute called "version", not tied to the `drools`
namespace.
+ test("wrong", () => {
+ const wrong = `<?xml version="1.0" encoding="UTF-8" ?>
+<bpmn2:definitions
+ ${defaultXmlns}
+ xmlns:drools="http://www.jboss.org/drools"
+>
+ <bpmn2:process version="1.0.0" />
+</bpmn2:definitions>`;
+
+ const marshaller = getMarshaller(wrong, { upgradeTo: "latest" });
+ const json = marshaller.parser.parse();
+
expect(json.definitions.rootElement?.[0].__$$element).toStrictEqual("process");
+ expect((json.definitions.rootElement?.[0] as
BPMN20__tProcess)["@_drools:version"]).not.toStrictEqual("1.0.0");
+ expect((json.definitions.rootElement?.[0] as
any)["@_version"]).toStrictEqual("1.0.0");
+
expect(poorlyFormatted(marshaller.builder.build(json))).toStrictEqual(poorlyFormatted(wrong));
+ });
+});
+
+// Just enough for these tests.
+function poorlyFormatted(s: string) {
+ return s
+ .replace(/\n+/g, "") // remove new lines
+ .replace(/ /g, " "); // replace double spaces by single space
+}
diff --git a/packages/bpmn-marshaller/tests/typeSafety.test.ts
b/packages/bpmn-marshaller/tests/typeSafety.test.ts
index d5cec6a5a68..8e1c212eba4 100644
--- a/packages/bpmn-marshaller/tests/typeSafety.test.ts
+++ b/packages/bpmn-marshaller/tests/typeSafety.test.ts
@@ -45,7 +45,7 @@ describe("type safety", () => {
test(path.basename(file), () => {
const xml = fs.readFileSync(path.join(__dirname, file), "utf-8");
- const { parser, version } = getMarshaller(xml);
+ const { parser, version } = getMarshaller(xml, { upgradeTo: "latest" });
const json = parser.parse();
const minorVersion = version.split(".")[1];
diff --git a/packages/bpmn-marshaller/tests/versions.test.ts
b/packages/bpmn-marshaller/tests/versions.test.ts
index 93aa3aaeca4..0f1e0bf2437 100644
--- a/packages/bpmn-marshaller/tests/versions.test.ts
+++ b/packages/bpmn-marshaller/tests/versions.test.ts
@@ -27,7 +27,7 @@ describe("versions", () => {
for (const file of files) {
test(path.basename(file.path), () => {
const xml = fs.readFileSync(path.join(__dirname, file.path), "utf-8");
- const { version } = getMarshaller(xml);
+ const { version } = getMarshaller(xml, { upgradeTo: "latest" });
expect(version).toStrictEqual(file.version);
});
}
diff --git
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn
index a1c669473f2..8acb1df4842 100644
--- a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn
+++ b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/can-drive.dmn
@@ -47,10 +47,6 @@
<dmn:typeRef>number</dmn:typeRef>
</dmn:itemComponent>
</dmn:itemDefinition>
- <dmn:inputData id="_66B82652-6454-4792-A989-7C97C4DF4672" name="Person">
- <dmn:extensionElements />
- <dmn:variable id="_6866698D-4B5B-44C2-952F-98EB982F16B6" name="Person"
typeRef="tPerson" />
- </dmn:inputData>
<dmn:decision id="_753802DC-87F4-4485-81AE-E5393C61B1AC" name="Can drive?">
<dmn:extensionElements />
<dmn:variable id="_F1CBDD9A-1300-469A-A478-7A2D1C00C5B6" name="Can drive?"
typeRef="boolean" />
@@ -159,6 +155,10 @@
</dmn:rule>
</dmn:decisionTable>
</dmn:decision>
+ <dmn:inputData id="_66B82652-6454-4792-A989-7C97C4DF4672" name="Person">
+ <dmn:extensionElements />
+ <dmn:variable id="_6866698D-4B5B-44C2-952F-98EB982F16B6" name="Person"
typeRef="tPerson" />
+ </dmn:inputData>
<dmndi:DMNDI>
<dmndi:DMNDiagram id="_1ED795B9-32EE-417C-8D14-C48D140B6ED5" name="DRG">
<di:extension>
diff --git
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
index 669fee27cbd..da32534b1e0 100644
---
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
+++
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/find-employees.dmn
@@ -66,41 +66,6 @@
<dmn:itemDefinition id="_8F50694C-1210-42B7-AB93-C839B8DA61CF"
name="tKnowledges" isCollection="true">
<dmn:typeRef>tKnowledge</dmn:typeRef>
</dmn:itemDefinition>
- <dmn:businessKnowledgeModel id="_F08537C6-DD4C-46F2-9709-61B43DF7AB0C"
name="Find employee by knowledge">
- <dmn:extensionElements />
- <dmn:variable id="_87CC2587-114D-41AE-9D69-35DC313B8A47" name="Find
employee by knowledge" typeRef="tEmployees" />
- <dmn:encapsulatedLogic id="_243056C9-28EA-4EF2-8510-6F3BC6A5E5DC"
kind="FEEL">
- <dmn:formalParameter id="_FC4939B4-6414-4F17-8D8C-FE339EA9AC5D"
name="employees" typeRef="tEmployees" />
- <dmn:formalParameter id="_2B8160CE-1F54-42D7-B111-706FE3BF2012"
name="knowledge" typeRef="tKnowledge" />
- <dmn:formalParameter id="_810CD0CE-7F46-4827-B19B-BFBD543BB3D9"
name="dept" typeRef="tDept" />
- <dmn:context id="_1B96445B-523F-49B3-99BE-308A2F3CFBA5">
- <dmn:contextEntry>
- <dmn:variable id="_A762CB8E-56C3-45AE-B59F-731E4A0CA73F"
name="Employees by" typeRef="tEmployees" />
- <dmn:literalExpression id="_BC626016-B599-47A1-ABD6-67A2C7F761CE">
- <dmn:text>employees[item.Dept = dept]</dmn:text>
- </dmn:literalExpression>
- </dmn:contextEntry>
- <dmn:contextEntry>
- <dmn:variable
- id="_C772ADED-2499-4AF1-9C99-63AA17901EBB"
- name="Employees with Knowledge"
- typeRef="tEmployees"
- />
- <dmn:literalExpression id="_3543AF00-0F90-47C4-BCBF-6E3B28A08BD7">
- <dmn:text>for e in Employees by return
-if (list contains(e.Knowledges, knowledge))
-then e
-else null</dmn:text>
- </dmn:literalExpression>
- </dmn:contextEntry>
- <dmn:contextEntry>
- <dmn:literalExpression id="_049ECA86-1971-48B7-86FF-7E89B399074A">
- <dmn:text>for e in Employees with Knowledge[item != null] return
e</dmn:text>
- </dmn:literalExpression>
- </dmn:contextEntry>
- </dmn:context>
- </dmn:encapsulatedLogic>
- </dmn:businessKnowledgeModel>
<dmn:decision id="_7E27D2CF-13CA-4EF5-945C-0E7EB26E89CF" name="Employees">
<dmn:extensionElements />
<dmn:variable id="_C732DAF4-F690-42BF-BB38-5994AF7D4193" name="Employees"
typeRef="tEmployees" />
@@ -206,6 +171,41 @@ else null</dmn:text>
</dmn:binding>
</dmn:invocation>
</dmn:decision>
+ <dmn:businessKnowledgeModel id="_F08537C6-DD4C-46F2-9709-61B43DF7AB0C"
name="Find employee by knowledge">
+ <dmn:extensionElements />
+ <dmn:variable id="_87CC2587-114D-41AE-9D69-35DC313B8A47" name="Find
employee by knowledge" typeRef="tEmployees" />
+ <dmn:encapsulatedLogic id="_243056C9-28EA-4EF2-8510-6F3BC6A5E5DC"
kind="FEEL">
+ <dmn:formalParameter id="_FC4939B4-6414-4F17-8D8C-FE339EA9AC5D"
name="employees" typeRef="tEmployees" />
+ <dmn:formalParameter id="_2B8160CE-1F54-42D7-B111-706FE3BF2012"
name="knowledge" typeRef="tKnowledge" />
+ <dmn:formalParameter id="_810CD0CE-7F46-4827-B19B-BFBD543BB3D9"
name="dept" typeRef="tDept" />
+ <dmn:context id="_1B96445B-523F-49B3-99BE-308A2F3CFBA5">
+ <dmn:contextEntry>
+ <dmn:variable id="_A762CB8E-56C3-45AE-B59F-731E4A0CA73F"
name="Employees by" typeRef="tEmployees" />
+ <dmn:literalExpression id="_BC626016-B599-47A1-ABD6-67A2C7F761CE">
+ <dmn:text>employees[item.Dept = dept]</dmn:text>
+ </dmn:literalExpression>
+ </dmn:contextEntry>
+ <dmn:contextEntry>
+ <dmn:variable
+ id="_C772ADED-2499-4AF1-9C99-63AA17901EBB"
+ name="Employees with Knowledge"
+ typeRef="tEmployees"
+ />
+ <dmn:literalExpression id="_3543AF00-0F90-47C4-BCBF-6E3B28A08BD7">
+ <dmn:text>for e in Employees by return
+if (list contains(e.Knowledges, knowledge))
+then e
+else null</dmn:text>
+ </dmn:literalExpression>
+ </dmn:contextEntry>
+ <dmn:contextEntry>
+ <dmn:literalExpression id="_049ECA86-1971-48B7-86FF-7E89B399074A">
+ <dmn:text>for e in Employees with Knowledge[item != null] return
e</dmn:text>
+ </dmn:literalExpression>
+ </dmn:contextEntry>
+ </dmn:context>
+ </dmn:encapsulatedLogic>
+ </dmn:businessKnowledgeModel>
<dmn:inputData id="_FC002A20-9A6F-4461-A568-01946BE5CD6C" name="Dept">
<dmn:extensionElements />
<dmn:variable id="_7B025B6B-40F4-4E77-BEC6-712D72ED3A82" name="Dept"
typeRef="tDept" />
diff --git
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
index 85b41de564b..0b7d8fca8a5 100644
---
a/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
+++
b/packages/dmn-editor-standalone/tests-e2e/__fixtures__/files/loan-pre-qualification.dmn
@@ -157,19 +157,6 @@
<dmn:typeRef>string</dmn:typeRef>
</dmn:itemComponent>
</dmn:itemDefinition>
- <dmn:inputData id="_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" name="Credit
Score">
- <dmn:extensionElements />
- <dmn:variable id="_A97019FC-EE01-451F-A7AA-5A97ED005FB9" name="Credit
Score" typeRef="Credit_Score" />
- </dmn:inputData>
- <dmn:businessKnowledgeModel id="_4C788DBD-C672-4F41-9AFE-9C7D2C145734"
name="Lender Acceptable DTI">
- <dmn:extensionElements />
- <dmn:variable id="_85508943-7AD2-4AA0-80E5-20923CA2308D" name="Lender
Acceptable DTI" typeRef="number" />
- <dmn:encapsulatedLogic id="_9F0257EE-CF82-49FD-AEDD-3155890864FF"
kind="FEEL">
- <dmn:literalExpression id="_21E8FA38-C947-4733-9E52-CF81A97ADF91">
- <dmn:text>0.36</dmn:text>
- </dmn:literalExpression>
- </dmn:encapsulatedLogic>
- </dmn:businessKnowledgeModel>
<dmn:decision id="_F0DC8923-5FC7-4200-8BD1-461D5F3714BE" name="Front End
Ratio">
<dmn:extensionElements />
<dmn:variable id="_A0B0B032-F63F-491F-A65E-72E68A86B8FD" name="Front End
Ratio" typeRef="Front_End_Ratio" />
@@ -228,23 +215,6 @@
</dmn:contextEntry>
</dmn:context>
</dmn:decision>
- <dmn:businessKnowledgeModel id="_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA"
name="PITI">
- <dmn:extensionElements />
- <dmn:variable id="_994F490E-10AC-4704-BFDA-14A3B98A981E" name="PITI"
typeRef="number" />
- <dmn:encapsulatedLogic id="_D33D9AEA-49DF-489F-98EC-4B42FF8C2027"
kind="FEEL">
- <dmn:formalParameter id="_664280C1-D5E0-47BE-82EF-0A6579975A62"
name="pmt" typeRef="number" />
- <dmn:formalParameter id="_3E7DF0B3-C48B-481D-B092-FC82EC2F6E37"
name="tax" typeRef="number" />
- <dmn:formalParameter id="_DF691F86-AD12-46BA-B149-AC875836A116"
name="insurance" typeRef="number" />
- <dmn:formalParameter id="_9E2E257F-90EB-4FC4-8DD9-089784E7579E"
name="income" typeRef="number" />
- <dmn:literalExpression id="_A32ED4A5-7B89-40F7-BE25-CDB636FE071C">
- <dmn:text>(pmt+tax+insurance) / income</dmn:text>
- </dmn:literalExpression>
- </dmn:encapsulatedLogic>
- </dmn:businessKnowledgeModel>
- <dmn:inputData id="_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" name="Applicant
Data">
- <dmn:extensionElements />
- <dmn:variable id="_2BBF28D2-DF09-4201-8D7A-5820E260592B" name="Applicant
Data" typeRef="Applicant_Data" />
- </dmn:inputData>
<dmn:decision id="_D6F4234F-15B3-4F5B-B814-5F6FF29D2907" name="Back End
Ratio">
<dmn:extensionElements />
<dmn:variable id="_5AF571F7-AD41-43DC-ABFD-26672585042F" name="Back End
Ratio" typeRef="Back_End_Ratio" />
@@ -496,10 +466,28 @@
</dmn:rule>
</dmn:decisionTable>
</dmn:decision>
- <dmn:inputData id="_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" name="Requested
Product">
+ <dmn:businessKnowledgeModel id="_4C788DBD-C672-4F41-9AFE-9C7D2C145734"
name="Lender Acceptable DTI">
<dmn:extensionElements />
- <dmn:variable id="_EE05E1C7-67ED-4A71-BDEE-8005259351E8" name="Requested
Product" typeRef="Requested_Product" />
- </dmn:inputData>
+ <dmn:variable id="_85508943-7AD2-4AA0-80E5-20923CA2308D" name="Lender
Acceptable DTI" typeRef="number" />
+ <dmn:encapsulatedLogic id="_9F0257EE-CF82-49FD-AEDD-3155890864FF"
kind="FEEL">
+ <dmn:literalExpression id="_21E8FA38-C947-4733-9E52-CF81A97ADF91">
+ <dmn:text>0.36</dmn:text>
+ </dmn:literalExpression>
+ </dmn:encapsulatedLogic>
+ </dmn:businessKnowledgeModel>
+ <dmn:businessKnowledgeModel id="_FAF9080E-F4EF-49F7-AEFD-0D2990D8FFDA"
name="PITI">
+ <dmn:extensionElements />
+ <dmn:variable id="_994F490E-10AC-4704-BFDA-14A3B98A981E" name="PITI"
typeRef="number" />
+ <dmn:encapsulatedLogic id="_D33D9AEA-49DF-489F-98EC-4B42FF8C2027"
kind="FEEL">
+ <dmn:formalParameter id="_664280C1-D5E0-47BE-82EF-0A6579975A62"
name="pmt" typeRef="number" />
+ <dmn:formalParameter id="_3E7DF0B3-C48B-481D-B092-FC82EC2F6E37"
name="tax" typeRef="number" />
+ <dmn:formalParameter id="_DF691F86-AD12-46BA-B149-AC875836A116"
name="insurance" typeRef="number" />
+ <dmn:formalParameter id="_9E2E257F-90EB-4FC4-8DD9-089784E7579E"
name="income" typeRef="number" />
+ <dmn:literalExpression id="_A32ED4A5-7B89-40F7-BE25-CDB636FE071C">
+ <dmn:text>(pmt+tax+insurance) / income</dmn:text>
+ </dmn:literalExpression>
+ </dmn:encapsulatedLogic>
+ </dmn:businessKnowledgeModel>
<dmn:businessKnowledgeModel id="_DA5CCF62-90A8-4CFC-A137-98B528522588"
name="DTI">
<dmn:extensionElements />
<dmn:variable id="_2F8921D1-6384-4ECB-848E-CE84A20B2573" name="DTI"
typeRef="number" />
@@ -520,6 +508,18 @@
</dmn:literalExpression>
</dmn:encapsulatedLogic>
</dmn:businessKnowledgeModel>
+ <dmn:inputData id="_4C89E59C-FDDA-438C-8D1F-0B1194EF6DAE" name="Credit
Score">
+ <dmn:extensionElements />
+ <dmn:variable id="_A97019FC-EE01-451F-A7AA-5A97ED005FB9" name="Credit
Score" typeRef="Credit_Score" />
+ </dmn:inputData>
+ <dmn:inputData id="_1CF5CEFA-AF97-46F9-9CD5-9A8AEBB20B4E" name="Applicant
Data">
+ <dmn:extensionElements />
+ <dmn:variable id="_2BBF28D2-DF09-4201-8D7A-5820E260592B" name="Applicant
Data" typeRef="Applicant_Data" />
+ </dmn:inputData>
+ <dmn:inputData id="_6E3205AF-7E3D-4ABE-A367-96F3F6E8210E" name="Requested
Product">
+ <dmn:extensionElements />
+ <dmn:variable id="_EE05E1C7-67ED-4A71-BDEE-8005259351E8" name="Requested
Product" typeRef="Requested_Product" />
+ </dmn:inputData>
<dmndi:DMNDI>
<dmndi:DMNDiagram id="_1608585F-01C8-4A66-B3E5-F4422D4DD2CA" name="DRG"
useAlternativeInputDataShape="false">
<di:extension>
diff --git a/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd
b/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd
index 1a813d8a67c..f8d2ac66143 100644
--- a/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd
+++ b/packages/dmn-marshaller/src/schemas/kie-1_0/KIE.xsd
@@ -9,7 +9,7 @@
<xsd:element name="ComponentsWidthsExtension"
type="kie:tComponentsWidthsExtension" />
<xsd:element name="ComponentWidths" type="kie:tComponentWidths" />
<xsd:element name="attachment" type="kie:tAttachment" />
- <xsd:attribute name="constraintType" type="tConstraintType" use="optional" />
+ <xsd:attribute name="constraintType" type="kie:tConstraintType"
use="optional" />
<xsd:complexType name="tComponentsWidthsExtension">
<xsd:sequence>
diff --git a/packages/dmn-marshaller/tests/xsdSequence.test.ts
b/packages/dmn-marshaller/tests/xsdSequence.test.ts
index c2aefe113b9..fc71f8c0964 100644
--- a/packages/dmn-marshaller/tests/xsdSequence.test.ts
+++ b/packages/dmn-marshaller/tests/xsdSequence.test.ts
@@ -106,9 +106,6 @@ describe("build always produces elements in the same
order", () => {
expect(marshaller.builder.build(json)).toStrictEqual(`<?xml
version="1.0" encoding="UTF-8" ?>
<definitions xmlns="https://www.omg.org/spec/DMN/20230324/MODEL/"
expressionLanguage="https://www.omg.org/spec/DMN/20230324/FEEL/"
namespace="https://kie.org/dmn/_D19C1092-7677-427F-A493-BCED38F74A9B"
id="_11655DE3-BEA5-45B1-B54E-8AD84FBBED25"
name="DMN_1E889EDB-B967-4508-8DB1-E0DF5986E62F"
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/extens [...]
<import name="some-import" namespace="some-namespace"
importType="some-import-type" />
- <inputData name="New Input Data" id="_154F9E03-B180-4C87-B7D3-8745DA4336F4">
- <variable name="New Input Data" id="_A28401DD-9A87-4251-A1E4-C63FC3A7C729"
typeRef="string" />
- </inputData>
<decision name="New Decision" id="_392BEF3D-44B5-47DC-8A06-C36F15DB2984">
<variable id="_C2C9C21A-E708-46D9-876A-52BB25692B66" typeRef="string"
name="New Decision" />
<informationRequirement id="_E781E253-D97E-4A1D-BE51-037B012B30F0">
@@ -118,6 +115,9 @@ describe("build always produces elements in the same
order", () => {
<text>"New Decision"</text>
</literalExpression>
</decision>
+ <inputData name="New Input Data" id="_154F9E03-B180-4C87-B7D3-8745DA4336F4">
+ <variable name="New Input Data" id="_A28401DD-9A87-4251-A1E4-C63FC3A7C729"
typeRef="string" />
+ </inputData>
<group name="some-group" />
<dmndi:DMNDI>
<dmndi:DMNDiagram id="_0D2FD42B-91FF-4795-B71F-E501CE115389" name="Default
DRD" useAlternativeInputDataShape="false">
diff --git a/packages/react-hooks/src/usePreviousRef.ts
b/packages/react-hooks/src/usePreviousRef.ts
index b5855874e6a..4504479fa9a 100644
--- a/packages/react-hooks/src/usePreviousRef.ts
+++ b/packages/react-hooks/src/usePreviousRef.ts
@@ -17,6 +17,7 @@
* under the License.
*/
+import * as React from "react";
import { useEffect, useRef } from "react";
export function usePreviousRef<T>(value: T): React.MutableRefObject<T> {
diff --git a/packages/xml-parser-ts-codegen/README.md
b/packages/xml-parser-ts-codegen/README.md
index e2c36fd49c0..c972f54006b 100644
--- a/packages/xml-parser-ts-codegen/README.md
+++ b/packages/xml-parser-ts-codegen/README.md
@@ -21,7 +21,7 @@ This package provides a Node.js script that generates
TypeScript types and metad
For more information about `@kie-tools/xml-parser-ts`, go to
[../packages/xml-parser-ts](../xml-parser-ts/README.md)
-It was created to provide a way to marshall/unmarshall DMN, SceSim, BPMN, and
PMML files, so it is only tested against those formats XSDs.
+It was created to provide a way to marshall/unmarshall BPMN, DMN, Test
Scenario, and PMML files, so it is only tested against those formats XSDs.
> NOTE: This package is probably not suited for your use-case, as it is
> incomplete and was not tested with a large number of XSD files, but it
> should work for simple XSDs. If you want to use it, please go ahead! Let us
> know if you tried and it worked! Feel free to contribute too with issues and
> PRs too.
diff --git a/packages/xml-parser-ts-codegen/src/codegen.ts
b/packages/xml-parser-ts-codegen/src/codegen.ts
index c5054aebc12..f1c927f3cac 100644
--- a/packages/xml-parser-ts-codegen/src/codegen.ts
+++ b/packages/xml-parser-ts-codegen/src/codegen.ts
@@ -30,6 +30,8 @@ import {
XptcComplexTypeAnonymous,
XptcMetaType,
XptcMetaTypeProperty,
+ XptcAttribute,
+ XptcTopLevelAttributeGroup,
} from "./types";
import {
XsdAttribute,
@@ -143,29 +145,58 @@ async function main() {
// // process <xsd:simpleType>'s
const __SIMPLE_TYPES: XptcSimpleType[] =
Array.from(__XSDS.entries()).flatMap(([location, schema]) =>
- (schema["xsd:schema"]["xsd:simpleType"] || []).flatMap((s) => {
- if (s["xsd:union"]) {
- if (s["xsd:union"]["@_memberTypes"] === "xsd:anyURI") {
+ (schema["xsd:schema"]["xsd:simpleType"] || []).flatMap((xsdSimpleType) => {
+ if (xsdSimpleType["xsd:union"]) {
+ if (xsdSimpleType["xsd:union"]["@_memberTypes"] === "xsd:anyURI") {
return [
{
comment: "xsd:anyURI",
type: "simple",
kind: "enum",
- name: s["@_name"] ?? s["@_name"],
+ name: xsdSimpleType["@_name"]!,
declaredAtRelativeLocation: location,
values: [],
},
];
}
- return (s["xsd:union"]["xsd:simpleType"] ?? []).flatMap((ss) =>
- xsdSimpleTypeToXptcSimpleType(ss, location, s["@_name"])
+ return (xsdSimpleType["xsd:union"]["xsd:simpleType"] ??
[]).flatMap((ss) =>
+ xsdSimpleTypeToXptcSimpleType(ss, location, xsdSimpleType["@_name"]!)
);
} else {
- return xsdSimpleTypeToXptcSimpleType(s, location, s["@_name"]);
+ return xsdSimpleTypeToXptcSimpleType(xsdSimpleType, location,
xsdSimpleType["@_name"]!);
}
})
);
+ const __ATTRIBUTE_GROUPS_BY_QNAME: Map<string, XptcTopLevelAttributeGroup> =
new Map(
+ Array.from(__XSDS.entries()).flatMap(([location, schema]) =>
+ (schema["xsd:schema"]["xsd:attributeGroup"] ||
[]).flatMap((xsdAttrGroup) => {
+ const qNamePrefix = Object.keys(schema["xsd:schema"])
+ .find(
+ (key: keyof (typeof schema)["xsd:schema"]) =>
+ key.startsWith("@_xmlns:") && // is a xml namespace declaration
+ schema["xsd:schema"][key] ===
schema["xsd:schema"]["@_targetNamespace"]
+ )
+ ?.split(":")[1];
+ if (!qNamePrefix) {
+ return [];
+ }
+
+ return [
+ [
+ `${qNamePrefix}:${xsdAttrGroup["@_name"]}`,
+ {
+ name: xsdAttrGroup["@_name"],
+ attributes: (xsdAttrGroup["xsd:attribute"] ?? []).map((xsdAttr)
=>
+ xsdAttributeToXptcAttribute(xsdAttr, location)
+ ),
+ },
+ ],
+ ];
+ })
+ )
+ );
+
// // process <xsd:complexType>'s
const __COMPLEX_TYPES: XptcComplexType[] = [];
for (const [location, xsd] of __XSDS.entries()) {
@@ -177,6 +208,7 @@ async function main() {
__COMPLEX_TYPES.push({
type: "complex",
comment: isAbstract ? "abstract" : "",
+ isMixed: xsdCt["@_mixed"] ?? false,
isAbstract,
isAnonymous: false,
name: xsdCt["@_name"]!,
@@ -186,27 +218,30 @@ async function main() {
childOf: extensionElement?.["@_base"],
elements: [
...(xsdCt["xsd:all"]?.["xsd:element"] ?? []).map((s) =>
- xsdElementToXptcElement(xsdCt["@_name"]!, s, location)
+ xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME,
xsdCt["@_name"]!, s, location)
),
...(xsdCt["xsd:sequence"]?.["xsd:element"] ?? []).map((s) =>
- xsdElementToXptcElement(xsdCt["@_name"]!, s, location)
+ xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME,
xsdCt["@_name"]!, s, location)
),
...(extensionElement?.["xsd:sequence"]?.["xsd:element"] ??
[]).map((s) =>
- xsdElementToXptcElement(xsdCt["@_name"]!, s, location)
+ xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME,
xsdCt["@_name"]!, s, location)
),
...(extensionElement?.["xsd:sequence"]?.["xsd:choice"]?.["xsd:element"] ??
[]).map((s) =>
- xsdElementToXptcElement(xsdCt["@_name"]!, s, location, {
forceOptional: true })
+ xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME,
xsdCt["@_name"]!, s, location, { forceOptional: true })
),
...(extensionElement?.["xsd:choice"]?.["xsd:element"] ?? []).map((s)
=>
- xsdElementToXptcElement(xsdCt["@_name"]!, s, location, {
forceOptional: true })
+ xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME,
xsdCt["@_name"]!, s, location, { forceOptional: true })
),
...(extensionElement?.["xsd:choice"]?.["xsd:sequence"]?.["xsd:element"] ??
[]).map((s) =>
- xsdElementToXptcElement(xsdCt["@_name"]!, s, location, {
forceOptional: true })
+ xsdElementToXptcElement(__ATTRIBUTE_GROUPS_BY_QNAME,
xsdCt["@_name"]!, s, location, { forceOptional: true })
),
],
attributes: [
- ...(xsdCt["xsd:attribute"] ?? []).map((a) =>
xsdAttributeToXptcAttribute(a)),
- ...(extensionElement?.["xsd:attribute"] ?? []).map((a) =>
xsdAttributeToXptcAttribute(a)),
+ ...(xsdCt["xsd:attribute"] ?? []).map((a) =>
xsdAttributeToXptcAttribute(a, location)),
+ ...(extensionElement?.["xsd:attribute"] ?? []).map((a) =>
xsdAttributeToXptcAttribute(a, location)),
+ ...(xsdCt["xsd:attributeGroup"] ?? []).flatMap(
+ (attrGroup) =>
__ATTRIBUTE_GROUPS_BY_QNAME.get(attrGroup["@_ref"])?.attributes ?? []
+ ),
],
});
}
@@ -216,13 +251,42 @@ async function main() {
const __GLOBAL_ELEMENTS = new Map<string, XptcElement>();
for (const [location, xsd] of __XSDS.entries()) {
for (const e of xsd["xsd:schema"]["xsd:element"] || []) {
- const a = xsdElementToXptcElement("GLOBAL", { ...e, "@_minOccurs": 0,
"@_maxOccurs": "unbounded" }, location, {
- forceOptional: false,
- });
+ const a = xsdElementToXptcElement(
+ __ATTRIBUTE_GROUPS_BY_QNAME,
+ "GLOBAL",
+ { ...e, "@_minOccurs": 0, "@_maxOccurs": "unbounded" },
+ location,
+ {
+ forceOptional: false,
+ }
+ );
+
+ let isAbstract = e["@_abstract"];
+ if (a.kind === "ofNamedType") {
+ const split = a.typeName?.split(":") ?? [];
+ const qNamePrefix = split.length === 2 ? split[0] : undefined;
+ const typeName = split.length === 2 ? split[1] : split[0];
+ const namespace = xsd["xsd:schema"][`@_xmlns:${qNamePrefix}`];
+ const [typeXsdLocation, typeXsd] =
+ [...__XSDS.entries()].find(([location, xsd]) =>
xsd["xsd:schema"]["@_targetNamespace"] === namespace) ?? [];
+
+ const type = __COMPLEX_TYPES
+ .filter((s) => !s.isAnonymous)
+ .filter((s) => (qNamePrefix ? s.declaredAtRelativeLocation ===
typeXsdLocation : true))
+ .find((s) => s.name === typeName);
+
+ if (!type) {
+ throw new Error(`Can't find type '${typeName}' for element
${e["@_name"]}`);
+ }
+
+ isAbstract ??= type?.isAbstract;
+ }
+
+ isAbstract ??= false;
__GLOBAL_ELEMENTS.set(`${location}__${e["@_name"]}`, {
name: e["@_name"],
- isAbstract: e["@_abstract"] ?? false,
+ isAbstract,
substitutionGroup: e["@_substitutionGroup"],
type: e["@_type"],
declaredAtRelativeLocation: location,
@@ -242,7 +306,7 @@ async function main() {
__SUBSTITUTIONS.set(xLocation, localizedSubstitutions);
for (const e of xsd["xsd:schema"]["xsd:element"] || []) {
if (e["@_substitutionGroup"]) {
- const subsGroup = getXptcElementFromLocalElementRef(
+ const subsGroup = getXptcElementFromElementQName(
__XSDS,
__GLOBAL_ELEMENTS,
xLocation,
@@ -251,7 +315,7 @@ async function main() {
if (!subsGroup) {
throw new Error(`Invalid subsitution group for element
'${e["@_name"]}'`);
}
- const elem = getXptcElementFromLocalElementRef(__XSDS,
__GLOBAL_ELEMENTS, xLocation, e["@_name"]);
+ const elem = getXptcElementFromElementQName(__XSDS,
__GLOBAL_ELEMENTS, xLocation, e["@_name"]);
if (!elem) {
throw new Error(`Invalid element '${e["@_name"]}'`);
}
@@ -262,6 +326,7 @@ async function main() {
const accumulatedSubstitutionElements = new Set([
...(localizedSubstitutions.get(localizedElementName) ?? []),
`${xLocation}__${elem.name}`,
+ ...(subsGroup.isAbstract ? [] : [localizedElementName]), //
Include itself if not abstract
]);
localizedSubstitutions.set(localizedElementName,
[...accumulatedSubstitutionElements]);
@@ -435,10 +500,14 @@ ${Array.from(subs.entries())
.map(
([head, elements]) =>
`${elements
- .map((e) => {
+ .flatMap((e) => {
const elementName = `${getRealtiveLocationNs(__RELATIVE_LOCATION,
e.split("__")[0]) + e.split("__")[1]}`;
const headName = `${getRealtiveLocationNs(__RELATIVE_LOCATION,
head.split("__")[0]) + head.split("__")[1]}`;
- return ` "${elementName}": "${headName}",`;
+ if (elementName === headName) {
+ return []; // Do not serialize itself as a substitution.
+ } else {
+ return ` "${elementName}": "${headName}",`;
+ }
})
.join("\n")}`
)
@@ -510,12 +579,36 @@ function resolveElementRef(
return [referencedElement];
}
- return
substitutionNamesForReferencedElement.flatMap((substitutionElementName) => {
+ const substitutionsWithoutSelfReferences = new Map(
+ [...substitutions.entries()].map(([key, value]) => [key, value.filter((v)
=> v !== key)] as const)
+ );
+
+ const resolved =
substitutionNamesForReferencedElement.flatMap((substitutionElementName) => {
const substitutionElement = __GLOBAL_ELEMENTS.get(substitutionElementName);
if (!substitutionElement) {
throw new Error(`Can't find element '${substitutionElementName}' for
substitution ${key}`);
}
- return resolveElementRef(__GLOBAL_ELEMENTS, __XSDS, substitutions,
substitutionElement);
+
+ if (substitutionElement.isAbstract) {
+ return resolveElementRef(__GLOBAL_ELEMENTS, __XSDS,
substitutionsWithoutSelfReferences, substitutionElement);
+ }
+
+ // Include itself if not abstract.
+ return [
+ substitutionElement,
+ ...resolveElementRef(__GLOBAL_ELEMENTS, __XSDS,
substitutionsWithoutSelfReferences, substitutionElement),
+ ];
+ });
+
+ const seen = new Set<string>();
+ return resolved.filter((s) => {
+ const key = `${s.declaredAtRelativeLocation}__${s.name}`;
+ if (seen.has(key)) {
+ return false;
+ } else {
+ seen.add(key);
+ return true;
+ }
});
}
@@ -552,7 +645,7 @@ ${resolutions
const elementName = `${elementNs}${element.name}`;
return [
` ({ __$$element: "${elementName}" } & ${
- getTsTypeFromLocalRef(
+ getTsTypeFromQName(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation,
@@ -582,13 +675,15 @@ function getMetaProperties(
const anonymousTypes: XptcMetaType[] = [];
const immediateParentType = ct.childOf
- ? getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, ct.childOf)
+ ? getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, ct.childOf)
: undefined;
let curParentCt = immediateParentType ?
__NAMED_TYPES_BY_TS_NAME.get(immediateParentType.name) : undefined;
let needsExtensionType = ct.needsExtensionType;
+ let isMixed = ct.isMixed;
+
while (curParentCt) {
const curParentCtMetaProperties: XptcMetaTypeProperty[] = [];
if (curParentCt?.type === "complex") {
@@ -601,8 +696,10 @@ function getMetaProperties(
throw new Error("Anonymous types are never parent types.");
}
+ isMixed ||= curParentCt.isMixed;
+
for (const a of curParentCt.attributes) {
- const attributeType = getTsTypeFromLocalRef(
+ const attributeType = getTsTypeFromQName(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
curParentCt.declaredAtRelativeLocation,
@@ -652,7 +749,7 @@ function getMetaProperties(
isOptional: e.isOptional,
});
} else if (e.kind === "ofNamedType") {
- const tsType = getTsTypeFromLocalRef(
+ const tsType = getTsTypeFromQName(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation,
@@ -670,7 +767,7 @@ function getMetaProperties(
isOptional: e.isOptional,
});
} else if (e.kind === "ofRef") {
- const referencedElement = getXptcElementFromLocalElementRef(
+ const referencedElement = getXptcElementFromElementQName(
__XSDS,
__GLOBAL_ELEMENTS,
ct.declaredAtRelativeLocation,
@@ -682,7 +779,7 @@ function getMetaProperties(
}
const tsType = referencedElement.type
- ? getTsTypeFromLocalRef(
+ ? getTsTypeFromQName(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation,
@@ -722,7 +819,7 @@ function getMetaProperties(
}
const nextParentType = curParentCt.childOf
- ? getTsTypeFromLocalRef(
+ ? getTsTypeFromQName(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
curParentCt.declaredAtRelativeLocation,
@@ -744,7 +841,7 @@ function getMetaProperties(
// Own properties are parsed later to ensure xsd:sequence order.
for (const a of ct.attributes) {
- const attributeType = getTsTypeFromLocalRef(
+ const attributeType = getTsTypeFromQName(
__XSDS,
__NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation,
@@ -764,7 +861,7 @@ function getMetaProperties(
for (const e of ct.elements) {
if (e.kind === "ofRef") {
- const referencedElement = getXptcElementFromLocalElementRef(
+ const referencedElement = getXptcElementFromElementQName(
__XSDS,
__GLOBAL_ELEMENTS,
ct.declaredAtRelativeLocation,
@@ -776,7 +873,7 @@ function getMetaProperties(
}
const tsType = referencedElement.type
- ? getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, referencedElement.type)
+ ? getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, referencedElement.type)
: {
name: getTsNameFromNamedType(
ct.declaredAtRelativeLocation,
@@ -806,7 +903,7 @@ function getMetaProperties(
isOptional: e.isOptional,
});
} else if (e.kind === "ofNamedType") {
- const tsType = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, e.typeName);
+ const tsType = getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, e.typeName);
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
@@ -850,7 +947,7 @@ function getMetaProperties(
}
if (ct.isSimpleContent && ct.childOf) {
- const t = getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, ct.childOf);
+ const t = getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME,
ct.declaredAtRelativeLocation, ct.childOf);
ctMetaProperties.push({
declaredAt: ct.declaredAtRelativeLocation,
fromType: metaTypeName,
@@ -865,6 +962,21 @@ function getMetaProperties(
});
}
+ if (isMixed) {
+ ctMetaProperties.push({
+ declaredAt: ct.declaredAtRelativeLocation,
+ fromType: metaTypeName,
+ name: `__$$text`,
+ elem: undefined,
+ metaType: {
+ name: "string",
+ xsdType: "xsd:string",
+ },
+ isArray: false,
+ isOptional: true,
+ });
+ }
+
if (!(ct.type === "complex" && !ct.isAnonymous && ct.isAbstract)) {
__META_TYPE_MAPPING.set(metaTypeName, {
name: metaTypeName,
@@ -884,23 +996,23 @@ function getTsNameFromNamedType(relativeLocation: string,
namedTypeName: string)
return `${filenameWithoutExtension}__${namedTypeName}`.replaceAll(/[ -.]/g,
"_");
}
-function getTsTypeFromLocalRef(
+function getTsTypeFromQName(
__XSDS: Map<string, XsdSchema>,
__NAMED_TYPES_BY_TS_NAME: Map<string, XptcComplexType | XptcSimpleType>,
relativeLocation: string,
- namedTypeLocalRef: string
+ namedTypeQName: 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(":");
+ if (namedTypeQName.includes(":") && namedTypeQName.split(":").length === 2) {
+ const [localNsName, namedTypeName] = namedTypeQName.split(":");
const xmlnsKey = `@_xmlns:${localNsName}`;
const namespace = (__XSDS.get(relativeLocation)?.["xsd:schema"] as
any)[xmlnsKey];
// short circuit here. we don't parse XSD's XSD.
if (namespace === "http://www.w3.org/2001/XMLSchema") {
- const xsdType = XSD__TYPES.get(namedTypeLocalRef);
+ const xsdType = XSD__TYPES.get(namedTypeQName);
if (!xsdType) {
- throw new Error(`Unknown XSD type '${namedTypeLocalRef}'`);
+ throw new Error(`Unknown XSD type '${namedTypeQName}'`);
}
return { name: xsdType.tsEquivalent, annotation: xsdType.annotation };
}
@@ -922,7 +1034,7 @@ function getTsTypeFromLocalRef(
// some simple types are declared just because of the restrictions it has,
they're not interesting for the generated structure.
if (namedType.type === "simple" && namedType.kind === "int" &&
namedType.restrictionBase) {
- return getTsTypeFromLocalRef(__XSDS, __NAMED_TYPES_BY_TS_NAME,
relativeLocation, namedType.restrictionBase);
+ return getTsTypeFromQName(__XSDS, __NAMED_TYPES_BY_TS_NAME,
relativeLocation, namedType.restrictionBase);
}
// found it!
@@ -931,49 +1043,66 @@ function getTsTypeFromLocalRef(
// not a reference to a type in another namespace. simply local name.
return {
- name: getTsNameFromNamedType(relativeLocation, namedTypeLocalRef),
+ name: getTsNameFromNamedType(relativeLocation, namedTypeQName),
annotation: "// local type",
};
}
-function xsdSimpleTypeToXptcSimpleType(s: XsdSimpleType, location: string,
name: string): XptcSimpleType {
+function xsdSimpleTypeToXptcSimpleType(
+ xsdSimpleType: XsdSimpleType,
+ location: string,
+ nameIfUnnamed: string
+): XptcSimpleType {
if (
- (s["xsd:restriction"]?.["@_base"] === "xsd:string" ||
s["xsd:restriction"]?.["@_base"] === "xsd:token") &&
- s["xsd:restriction"]["xsd:enumeration"]
+ xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:string" ||
+ xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:token"
+ ) {
+ if (xsdSimpleType["xsd:restriction"]["xsd:enumeration"]) {
+ return {
+ comment: "enum",
+ type: "simple",
+ kind: "enum",
+ name: xsdSimpleType["@_name"] ?? nameIfUnnamed,
+ declaredAtRelativeLocation: location,
+ values: xsdSimpleType["xsd:restriction"]["xsd:enumeration"].map((e) =>
e["@_value"]),
+ };
+ } else {
+ return {
+ comment: "string",
+ type: "simple",
+ kind: "string",
+ name: xsdSimpleType["@_name"] ?? nameIfUnnamed,
+ declaredAtRelativeLocation: location,
+ };
+ }
+ } else if (
+ xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:int" ||
+ xsdSimpleType["xsd:restriction"]?.["@_base"] === "xsd:integer"
) {
- return {
- comment: "enum",
- type: "simple",
- kind: "enum",
- name: s["@_name"] ?? name,
- declaredAtRelativeLocation: location,
- values: s["xsd:restriction"]["xsd:enumeration"].map((e) => e["@_value"]),
- };
- } else if (s["xsd:restriction"]?.["@_base"] === "xsd:int" ||
s["xsd:restriction"]?.["@_base"] === "xsd:integer") {
return {
comment: "int",
type: "simple",
kind: "int",
- restrictionBase: s["xsd:restriction"]["@_base"],
- name: s["@_name"] ?? name,
+ restrictionBase: xsdSimpleType["xsd:restriction"]["@_base"],
+ name: xsdSimpleType["@_name"] ?? nameIfUnnamed,
declaredAtRelativeLocation: location,
- minInclusive: s["xsd:restriction"]["xsd:minInclusive"]?.["@_value"],
- maxInclusive: s["xsd:restriction"]["xsd:maxInclusive"]?.["@_value"],
+ minInclusive:
xsdSimpleType["xsd:restriction"]["xsd:minInclusive"]?.["@_value"],
+ maxInclusive:
xsdSimpleType["xsd:restriction"]["xsd:maxInclusive"]?.["@_value"],
};
} else {
- throw new Error(`Unknown xsd:simpleType --> ${JSON.stringify(s, undefined,
2)}`);
+ throw new Error(`Unknown xsd:simpleType -->
${JSON.stringify(xsdSimpleType, undefined, 2)}`);
}
}
-function getXptcElementFromLocalElementRef(
+function getXptcElementFromElementQName(
__XSDS: Map<string, XsdSchema>,
__GLOBAL_ELEMENTS: Map<string, XptcElement>,
relativeLocation: string,
- localElementRef: string
+ elementQName: string
): XptcElement | undefined {
// check if it's a QName to another namespace
- if (localElementRef.includes(":") && localElementRef.split(":").length ===
2) {
- const [localNsName, referencedElementName] = localElementRef.split(":");
+ if (elementQName.includes(":") && elementQName.split(":").length === 2) {
+ const [localNsName, referencedElementName] = elementQName.split(":");
const xmlnsKey = `@_xmlns:${localNsName}`;
const namespace = (__XSDS.get(relativeLocation)?.["xsd:schema"] as
any)[xmlnsKey];
@@ -988,10 +1117,11 @@ function getXptcElementFromLocalElementRef(
return
__GLOBAL_ELEMENTS.get(`${referencedXsdRelativeLocation}__${referencedElementName}`);
}
- return __GLOBAL_ELEMENTS.get(`${relativeLocation}__${localElementRef}`);
+ return __GLOBAL_ELEMENTS.get(`${relativeLocation}__${elementQName}`);
}
function xsdElementToXptcElement(
+ __ATTRIBUTE_GROUPS_BY_QNAME: Map<string, XptcTopLevelAttributeGroup>,
parentIdentifierForExtensionType: string,
xsdElement: NonNullable<Unpacked<XsdSequence["xsd:element"]>>,
location: string,
@@ -1067,6 +1197,7 @@ function xsdElementToXptcElement(
isArray,
isOptional,
anonymousType: xsdComplexTypeToAnonymousXptcComplexType(
+ __ATTRIBUTE_GROUPS_BY_QNAME,
parentIdentifierForExtensionType,
xsdElement["xsd:complexType"],
location,
@@ -1091,15 +1222,19 @@ function xsdElementToXptcElement(
throw new Error(`Unknown xsd:element structure.
${JSON.stringify(xsdElement)}`);
}
-function xsdAttributeToXptcAttribute(xsdAttribute: XsdAttribute):
Unpacked<XptcComplexType["attributes"]> {
+function xsdAttributeToXptcAttribute(xsdAttribute: XsdAttribute, location:
string): XptcAttribute {
return {
name: xsdAttribute["@_name"],
localTypeRef: xsdAttribute["@_type"],
isOptional: xsdAttribute["@_use"] === undefined || xsdAttribute["@_use"]
=== "optional",
+ simpleType: xsdAttribute["xsd:simpleType"]
+ ? xsdSimpleTypeToXptcSimpleType(xsdAttribute["xsd:simpleType"],
location, `${xsdAttribute["@_name"]}simpleType`)
+ : undefined,
};
}
function xsdComplexTypeToAnonymousXptcComplexType(
+ __ATTRIBUTE_GROUPS_BY_QNAME: Map<string, XptcTopLevelAttributeGroup>,
parentIdentifierForExtensionType: string,
xsdCt: XsdComplexType,
location: string,
@@ -1108,6 +1243,7 @@ function xsdComplexTypeToAnonymousXptcComplexType(
return {
type: "complex",
comment: "",
+ isMixed: xsdCt["@_mixed"] ?? false,
isSimpleContent: false, // No reason why an anonymous type couldn't be
simpleContent... Could be implemented.
isAnonymous: true,
parentIdentifierForExtensionType,
@@ -1117,16 +1253,29 @@ function xsdComplexTypeToAnonymousXptcComplexType(
childOf: xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["@_base"],
elements: [
...(xsdCt["xsd:sequence"]?.["xsd:element"] ?? []).map((s) =>
-
xsdElementToXptcElement(`${parentIdentifierForExtensionType}__${element}`, s,
location)
+ xsdElementToXptcElement(
+ __ATTRIBUTE_GROUPS_BY_QNAME,
+ `${parentIdentifierForExtensionType}__${element}`,
+ s,
+ location
+ )
),
...(xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:sequence"]?.["xsd:element"]
?? []).map((s) =>
-
xsdElementToXptcElement(`${parentIdentifierForExtensionType}__${element}`, s,
location)
+ xsdElementToXptcElement(
+ __ATTRIBUTE_GROUPS_BY_QNAME,
+ `${parentIdentifierForExtensionType}__${element}`,
+ s,
+ location
+ )
),
],
attributes: [
- ...(xsdCt["xsd:attribute"] ?? []).map((a) =>
xsdAttributeToXptcAttribute(a)),
+ ...(xsdCt["xsd:attribute"] ?? []).map((a) =>
xsdAttributeToXptcAttribute(a, location)),
...(xsdCt["xsd:complexContent"]?.["xsd:extension"]?.["xsd:attribute"] ??
[]).map((a) =>
- xsdAttributeToXptcAttribute(a)
+ xsdAttributeToXptcAttribute(a, location)
+ ),
+ ...(xsdCt["xsd:attributeGroup"] ?? []).flatMap(
+ (attrGroup) =>
__ATTRIBUTE_GROUPS_BY_QNAME.get(attrGroup["@_ref"])?.attributes ?? []
),
],
};
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 7cce79edc45..9e42df5e336 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
@@ -34,6 +34,8 @@ export const meta = {
"xsd:annotation": { type: "annotation", isArray: true, fromType: "",
xsdType: "" },
"xsd:simpleType": { type: "simpleType", isArray: true, fromType: "",
xsdType: "" },
"xsd:complexType": { type: "complexType", isArray: true, fromType: "",
xsdType: "" },
+ "xsd:attributeGroup": { type: "topLevelAttributeGroup", isArray: true,
fromType: "", xsdType: "" },
+ "xsd:attribute": { type: "attribute", isArray: true, fromType: "",
xsdType: "" },
},
all: {
"@_minOccurs": { type: "integer", isArray: false, fromType: "", xsdType:
"" },
@@ -49,7 +51,17 @@ export const meta = {
union: {
"xsd:simpleType": { type: "simpleType", isArray: true, fromType: "",
xsdType: "" },
},
- attribute: {},
+ attribute: {
+ "@_name": { type: "string", isArray: false, fromType: "", xsdType: "" },
+ "xsd:simpleType": { type: "simpleType", isArray: false, fromType: "",
xsdType: "" },
+ },
+ topLevelAttributeGroup: {
+ "@_name": { type: "string", isArray: false, fromType: "", xsdType: "" },
+ "xsd:attribute": { type: "attribute", isArray: true, fromType: "",
xsdType: "" },
+ },
+ attributeGroup: {
+ "@_ref": { type: "string", isArray: false, fromType: "", xsdType: "" },
+ },
element: {
"@_abstract": { type: "boolean", isArray: false, fromType: "", xsdType: ""
},
"@_minOccurs": { type: "integer", isArray: false, fromType: "", xsdType:
"" },
@@ -58,11 +70,13 @@ export const meta = {
},
complexType: {
"@_abstract": { type: "boolean", isArray: false, fromType: "", xsdType: ""
},
+ "@_mixed": { type: "boolean", isArray: false, fromType: "", xsdType: "" },
"xsd:complexContent": { type: "complexContent", isArray: false, fromType:
"", xsdType: "" },
"xsd:simpleContent": { type: "simpleContent", isArray: false, fromType:
"", xsdType: "" },
"xsd:sequence": { type: "sequence", isArray: false, fromType: "", xsdType:
"" },
"xsd:all": { type: "all", isArray: false, fromType: "", xsdType: "" },
"xsd:attribute": { type: "attribute", isArray: true, fromType: "",
xsdType: "" },
+ "xsd:attributeGroup": { type: "attributeGroup", isArray: true, fromType:
"", xsdType: "" },
},
complexContent: {
"xsd:extension": { type: "extension", isArray: false, fromType: "",
xsdType: "" },
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 21d5daa83d9..98552a69d6a 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
@@ -17,6 +17,8 @@
* under the License.
*/
+import { XmlParserTsRootElementBaseType } from "@kie-tools/xml-parser-ts";
+
export type XsdPrimitives = "xsd:int" | "xsd:string" | "xsd:token" |
"xsd:integer" | "xsd:anyURI";
export interface XsdImport {
@@ -28,7 +30,7 @@ export interface XsdImport {
}
export interface XsdSimpleType {
- "@_name": string;
+ "@_name"?: string;
"xsd:union"?: {
"@_memberTypes": XsdPrimitives;
"xsd:simpleType"?: XsdSimpleType[];
@@ -47,6 +49,12 @@ export interface XsdAttribute {
"@_type": string;
"@_use"?: "required" | "optional";
"@_default": string;
+ "xsd:simpleType"?: XsdSimpleType;
+}
+
+export interface XsdTopLevelAttributeGroup {
+ "xsd:attribute": XsdAttribute[];
+ "@_name": string;
}
export interface XsdSequence {
@@ -61,7 +69,7 @@ export interface XsdSequence {
};
}
-export interface XSDExtension {
+export interface XsdExtension {
"xsd:attribute"?: XsdAttribute[];
"xsd:sequence"?: XsdSequence;
"xsd:all"?: XsdAll;
@@ -72,7 +80,9 @@ export interface XSDExtension {
export interface XsdComplexType {
"@_name"?: string;
"@_abstract"?: boolean;
+ "@_mixed"?: boolean;
"xsd:attribute"?: XsdAttribute[];
+ "xsd:attributeGroup"?: Array<{ "@_ref": string }>;
"xsd:sequence"?: XsdSequence;
"xsd:all"?: XsdAll;
"xsd:anyAttribute"?: {
@@ -80,10 +90,10 @@ export interface XsdComplexType {
"@_processContents": "lax";
};
"xsd:complexContent"?: {
- "xsd:extension"?: XSDExtension;
+ "xsd:extension"?: XsdExtension;
};
"xsd:simpleContent"?: {
- "xsd:extension"?: XSDExtension;
+ "xsd:extension"?: XsdExtension;
};
}
@@ -121,7 +131,7 @@ export interface XsdTopLevelElement {
}
export interface XsdSchema {
- "xsd:schema": {
+ "xsd:schema": XmlParserTsRootElementBaseType & {
"@_targetNamespace": string;
"@_elementFormDefault": "qualified";
"@_attributeFormDefault": "unqualified";
@@ -130,5 +140,7 @@ export interface XsdSchema {
"xsd:simpleType"?: XsdSimpleType[];
"xsd:complexType"?: XsdComplexType[];
"xsd:element"?: XsdTopLevelElement[];
+ "xsd:attribute"?: XsdAttribute[];
+ "xsd:attributeGroup"?: XsdTopLevelAttributeGroup[];
};
}
diff --git a/packages/xml-parser-ts-codegen/src/types.d.ts
b/packages/xml-parser-ts-codegen/src/types.d.ts
index 669ff403f33..3375daf6c76 100644
--- a/packages/xml-parser-ts-codegen/src/types.d.ts
+++ b/packages/xml-parser-ts-codegen/src/types.d.ts
@@ -28,6 +28,7 @@ export type XptcComplexTypeBase = {
isSimpleContent: boolean;
needsExtensionType: boolean; // That's for sequences decalring
<xsd:anyAttribute> or <xsd:any>
declaredAtRelativeLocation: string;
+ attributes: XptcAttribute[];
elements: Array<
{
isArray: boolean;
@@ -49,15 +50,11 @@ export type XptcComplexTypeBase = {
}
)
>;
- attributes: Array<{
- name: string;
- localTypeRef: string;
- isOptional: boolean;
- }>;
};
export type XptcComplexTypeAnonymous = XptcComplexTypeBase & {
isAnonymous: true; // Declared directly inside elements.
+ isMixed: boolean;
forElementWithName: string;
parentIdentifierForExtensionType: string;
};
@@ -65,11 +62,24 @@ export type XptcComplexTypeAnonymous = XptcComplexTypeBase
& {
export type XptcComplexTypeNamed = XptcComplexTypeBase & {
name: string;
isAbstract: boolean;
+ isMixed: boolean;
isAnonymous: false;
};
export type XptcComplexType = XptcComplexTypeNamed | XptcComplexTypeAnonymous;
+export type XptcAttribute = {
+ name: string;
+ localTypeRef: string;
+ isOptional: boolean;
+ simpleType?: XptcSimpleType;
+};
+
+export type XptcTopLevelAttributeGroup = {
+ name: string;
+ attributes: XptcAttribute[];
+};
+
export type XptcElement = {
name: string;
type?: string;
@@ -86,6 +96,9 @@ export type XptcSimpleType = {
restrictionBase?: string;
declaredAtRelativeLocation: string;
} & (
+ | {
+ kind: "string";
+ }
| {
kind: "enum";
values: string[];
diff --git a/packages/react-hooks/src/usePreviousRef.ts
b/packages/xml-parser-ts/src/elementFilter.ts
similarity index 70%
copy from packages/react-hooks/src/usePreviousRef.ts
copy to packages/xml-parser-ts/src/elementFilter.ts
index b5855874e6a..1118a3e8ecb 100644
--- a/packages/react-hooks/src/usePreviousRef.ts
+++ b/packages/xml-parser-ts/src/elementFilter.ts
@@ -17,16 +17,14 @@
* under the License.
*/
-import { useEffect, useRef } from "react";
+export type ElementFilter<E extends { __$$element: string }, Filter extends
string> = E extends any
+ ? E["__$$element"] extends Filter
+ ? E
+ : never
+ : never;
-export function usePreviousRef<T>(value: T): React.MutableRefObject<T> {
- const ref = useRef<T>(value);
-
- useEffect(() => {
- if (ref.current !== value) {
- ref.current = value;
- }
- }, [value]);
-
- return ref;
-}
+export type ElementExclusion<E extends { __$$element: string }, Filter extends
string> = E extends any
+ ? E["__$$element"] extends Filter
+ ? never
+ : E
+ : never;
diff --git a/packages/xml-parser-ts/src/index.ts
b/packages/xml-parser-ts/src/index.ts
index 8ade30121a3..76ca0fc0970 100644
--- a/packages/xml-parser-ts/src/index.ts
+++ b/packages/xml-parser-ts/src/index.ts
@@ -162,7 +162,7 @@ export function getParser<T extends object>(args: {
if (k.endsWith(":") || k === "" /* Filters only `xmlns --> URL`
mappings, since `ns` is bi-directional.*/) {
const instanceNsKey = instanceNs.get(v)?.slice(0, -1);
const originalXmlnsPropName = instanceNsKey ?
`@_xmlns:${instanceNsKey}` : `@_xmlns`;
- if (!instanceNsKey ||
!__json[args.root.element][originalXmlnsPropName]) {
+ if (instanceNsKey === undefined ||
!__json[args.root.element][originalXmlnsPropName]) {
const nsName = k.slice(0, -1);
const newXmlnsPropName = nsName ? `@_xmlns:${nsName}` : `@_xmlns`;
console.warn(`Adding NS mapping to XML: ${newXmlnsPropName} -->
${v}`);
@@ -181,6 +181,11 @@ export function getParser<T extends object>(args: {
[args.root.element]: { type: args.root.type, fromType: "root",
isArray: false, xsdType: "// root" },
};
+ const declaredElementsOrder = [];
+ for (const e in args.elements ?? {}) {
+ declaredElementsOrder.push(e);
+ }
+
const xml = build({
json: __json,
ns: args.ns,
@@ -188,6 +193,7 @@ export function getParser<T extends object>(args: {
elements: args.elements,
meta: args.meta,
metaType: rootMetaType,
+ declaredElementsOrder,
indent: "",
});
// console.timeEnd("building took");
@@ -216,7 +222,7 @@ export function parse(args: {
const elemNode = children[ii];
if (elemNode.nodeType === 1 /* ELEMENT_NODE */) {
- const { nsedName, subsedName } = resolveElement(elemNode.nodeName,
args.nodeMetaType, args);
+ const { nsedName, subsedName } = resolveQName(elemNode.nodeName,
args.nodeMetaType, args);
const elemMetaProp = args.nodeMetaType?.[subsedName ?? nsedName];
@@ -227,7 +233,8 @@ export function parse(args: {
: undefined); // If the current element is not known, we simply
ignore its type and go with the defaults.
// 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.
+ // All other properties (except `__$$element`) on `elemType` are
certainly attributes, which are handled below.
+ // The `__$$element` property is also processed below, since there can
be an element with both `__$$text` and `__$$element` properties.
const t = elemMetaType?.["__$$text"]?.type ?? elemMetaProp?.type;
let elemValue: any = {};
@@ -241,16 +248,27 @@ export function parse(args: {
elemValue["__$$text"] = parseFloat(elemNode.textContent ?? "");
} else {
elemValue = parse({ ...args, node: elemNode, nodeMetaType:
elemMetaType });
- if (subsedName !== nsedName) {
- // substitution occurred, need to save the original, normalized
element name
- elemValue["__$$element"] = nsedName;
- }
}
+ if (subsedName !== nsedName) {
+ // substitution occurred, need to save the original, normalized
element name
+ elemValue["__$$element"] = nsedName;
+ }
+
+ const argsForAttrs = { ns: args.ns, instanceNs: args.instanceNs, subs:
{} }; // Attributes can't use substitution groups.
const attrs = (elemNode as Element).attributes;
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i];
- const attrPropType = elemMetaType?.[`@_${attr.name}`];
+ const resolvedAttrQName = resolveQName(attr.name, args.nodeMetaType,
argsForAttrs);
+
+ // If the attribute's name is not qualified, we don't mess
+ // with it. We treat it as having no namespace, instead of
+ // potentially using the default namespace mapped with `xmlns=`.
+ const attrName = resolvedAttrQName.isQualified
+ ? resolvedAttrQName.subsedName ?? resolvedAttrQName.nsedName
+ : attr.name;
+
+ const attrPropType = elemMetaType?.[`@_${attrName}`];
let attrValue: any;
if (attrPropType?.type === "string") {
@@ -267,7 +285,7 @@ export function parse(args: {
attrValue = attr.value; // Unknown type, default to the text from
the XML.
}
- elemValue[`@_${attr.name}`] = attrValue;
+ elemValue[`@_${attrName}`] = attrValue;
}
const currentValue = json[subsedName ?? nsedName];
@@ -296,7 +314,7 @@ export function parse(args: {
return json;
}
-export function resolveElement(
+export function resolveQName(
name: string,
parentMetaType: MetaType | undefined,
{
@@ -311,14 +329,17 @@ export function resolveElement(
) {
let nameNs = undefined;
let nameName = undefined;
+ let isQualified: boolean;
const s = name.split(":");
if (s.length === 1) {
nameNs = ns.get(instanceNs.get("")!) ?? "";
nameName = s[0];
+ isQualified = false;
} else if (s.length === 2) {
nameNs = ns.get(instanceNs.get(`${s[0]}:`)!) ?? `${s[0]}:`;
nameName = s[1];
+ isQualified = true;
} else {
throw new Error(name);
}
@@ -339,7 +360,7 @@ export function resolveElement(
subsedName = nsedSubs[subsedName];
}
- return { nsedName, subsedName };
+ return { nsedName, subsedName, isQualified };
}
function parseInt(attrValue: string) {
@@ -410,7 +431,7 @@ function applyEntities(value: any) {
.replace(quotEntity.regex, quotEntity.replacement);
}
-function buildAttrs(json: any) {
+function buildAttrs(json: any, { ns, instanceNs }: { ns: Map<string, string>;
instanceNs: Map<string, string> }) {
let isEmpty = true;
let hasText = false;
let attrs = " ";
@@ -418,7 +439,12 @@ function buildAttrs(json: any) {
// Attributes don't ever need to be serialized in a particular order.
for (const propName in json) {
if (propName[0] === "@") {
- attrs += `${propName.substring(2)}="${applyEntities(json[propName])}" `;
+ const attrName =
+ propName.split(":").length === 2 // only apply namespace if it's
qualified name. attributes are unnamespaced by default.
+ ? applyInstanceNs({ propName: propName.substring(2), instanceNs, ns
})
+ : propName.substring(2);
+
+ attrs += `${attrName}="${applyEntities(json[propName])}" `;
} else if (propName === "__$$text") {
hasText = true;
isEmpty = false;
@@ -441,6 +467,7 @@ export function build(args: {
elements: Elements;
meta: Meta;
metaType: MetaType | undefined;
+ declaredElementsOrder: string[];
indent: string;
}): string {
const { json, ns, instanceNs, indent, metaType } = args;
@@ -451,7 +478,7 @@ export function build(args: {
let xml = "";
- // We want to respect a certain order here given xsd:sequence declarations.
+ // We want to respect a certain order here given xsd:sequence, xsd:choice,
and xsd:all declarations
const sortedJsonProps: string[] = [];
for (const p in json) {
sortedJsonProps.push(p);
@@ -483,7 +510,7 @@ export function build(args: {
}
// pi tag
else if (jsonPropName[0] === "?") {
- xml = `${indent}<${jsonPropName}${buildAttrs(jsonPropValue).attrs} ?>\n`
+ xml; // PI Tags should always go at the top of the XML
+ xml = `${indent}<${jsonPropName}${buildAttrs(jsonPropValue, args).attrs}
?>\n` + xml; // PI Tags should always go at the top of the XML
}
// empty tag
else if (jsonPropValue === undefined || jsonPropValue === null ||
jsonPropValue === "") {
@@ -497,9 +524,17 @@ export function build(args: {
}
// array
else if (Array.isArray(jsonPropValue)) {
- for (const item of jsonPropValue) {
+ // In order to keep the order of elements of xsd:sequences in a
`substituionGroup`
+ // we need to sort elements by their declaration order.
+ const elemOrder = args.declaredElementsOrder;
+ const arr =
+ jsonPropValue?.[0]?.__$$element === undefined
+ ? jsonPropValue
+ : jsonPropValue.toSorted((a, b) => elemOrder.indexOf(a.__$$element)
- elemOrder.indexOf(b.__$$element));
+
+ for (const item of arr) {
const elementName = applyInstanceNs({ ns, instanceNs, propName:
item?.["__$$element"] ?? jsonPropName });
- const { attrs, isEmpty, hasText } = buildAttrs(item);
+ const { attrs, isEmpty, hasText } = buildAttrs(item, args);
xml += `${indent}<${elementName}${attrs}`;
if (isEmpty) {
xml += " />\n";
@@ -522,7 +557,7 @@ export function build(args: {
else {
const item = jsonPropValue;
const elementName = applyInstanceNs({ ns, instanceNs, propName:
item["__$$element"] ?? jsonPropName });
- const { attrs, isEmpty, hasText } = buildAttrs(item);
+ const { attrs, isEmpty, hasText } = buildAttrs(item, args);
xml += `${indent}<${elementName}${attrs}`;
if (isEmpty) {
xml += " />\n";
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]