All files / src/web/flowable/roundTrip extractDocumentState.ts

95.83% Statements 46/48
80.48% Branches 33/41
100% Functions 6/6
95.74% Lines 45/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131                                    4x         63x 63x 63x 4x   59x       496x                               21x   496x 5x     6971x 496x       496x 63x 63x 42x     21x 21x 21x           390x 2481x 1387x       390x   390x 908x 908x 127x 127x 127x             127x     781x 98x 98x 98x                       390x 390x 390x 390x       390x   390x 408x     390x 12014x     390x 390x  
import { parseXmlDocument } from '../xmlParser';
import type { Element as XmlElement } from '@xmldom/xmldom';
import { ACTIVITI_NAMESPACE, XSI_NAMESPACE } from './constants';
import {
	cloneFlowableState,
	createEmptyFlowableState,
	type FlowableDocumentState,
} from '../types';
import {
	buildXmlIdentity,
	getActivitiAttribute,
	getElementChildren,
	getElementsByLocalName,
	getLocalName,
} from './xmlUtils';
import { extractElementState } from './elementStateExtraction';
import { extractProcessLevelState } from './processStateExtraction';
 
const KNOWN_QNAME_PREFIX_NAMESPACES: Record<string, string> = {
	xsd: 'http://www.w3.org/2001/XMLSchema',
};
 
function getQNamePrefix(value: string): string {
	const trimmedValue = value.trim();
	const separatorIndex = trimmedValue.indexOf(':');
	if (separatorIndex <= 0) {
		return '';
	}
	return trimmedValue.slice(0, separatorIndex);
}
 
export function ensureActivitiNamespace(documentState: FlowableDocumentState): void {
	const needsActivitiNamespace = Object.values(documentState.elements).some((elementState) => {
		return (
			Object.keys(elementState.activitiAttributes).length > 0 ||
			elementState.fieldExtensions.length > 0 ||
			elementState.taskListeners.length > 0 ||
			elementState.executionListeners.length > 0 ||
			elementState.formProperties.length > 0 ||
			elementState.inputParameters.length > 0 ||
			elementState.outputParameters.length > 0 ||
			Boolean(elementState.failedJobRetryTimeCycle) ||
			elementState.exceptionMaps.length > 0 ||
			(elementState.multiInstance !== null && (elementState.multiInstance.collection || elementState.multiInstance.elementVariable))
		);
	}) || documentState.signalDefinitions.some((signal) => Boolean(signal.scope))
		|| documentState.eventListeners.length > 0
		|| documentState.localizations.length > 0
		|| documentState.dataObjects.some((dataObject) => Boolean(dataObject.defaultValue));
 
	if (needsActivitiNamespace && !documentState.namespaces.activiti) {
		documentState.namespaces.activiti = ACTIVITI_NAMESPACE;
	}
 
	const needsXsiNamespace = Object.values(documentState.elements).some((elementState) => Boolean(elementState.conditionExpression));
	Iif (needsXsiNamespace && !documentState.namespaces.xsi) {
		documentState.namespaces.xsi = XSI_NAMESPACE;
	}
 
	for (const dataObject of documentState.dataObjects) {
		const prefix = getQNamePrefix(dataObject.itemSubjectRef);
		if (!prefix || documentState.namespaces[prefix]) {
			continue;
		}
 
		const namespaceUri = KNOWN_QNAME_PREFIX_NAMESPACES[prefix];
		Eif (namespaceUri) {
			documentState.namespaces[prefix] = namespaceUri;
		}
	}
}
 
function extractDefinitionLevelState(definitions: XmlElement, documentState: FlowableDocumentState): void {
	for (const attribute of Array.from(definitions.attributes)) {
		if (attribute.name.startsWith('xmlns:')) {
			documentState.namespaces[attribute.name.slice(6)] = attribute.value;
		}
	}
 
	documentState.targetNamespace = definitions.getAttribute('targetNamespace') || '';
 
	for (const child of getElementChildren(definitions)) {
		const localName = getLocalName(child);
		if (localName === 'signal') {
			const id = child.getAttribute('id');
			Eif (id) {
				documentState.signalDefinitions.push({
					id,
					name: child.getAttribute('name') || '',
					scope: getActivitiAttribute(child, 'scope') || '',
					xmlIdentity: buildXmlIdentity('signalDefinition', child),
				});
			}
			continue;
		}
 
		if (localName === 'message') {
			const id = child.getAttribute('id');
			Eif (id) {
				documentState.messageDefinitions.push({
					id,
					name: child.getAttribute('name') || '',
					xmlIdentity: buildXmlIdentity('messageDefinition', child),
				});
			}
		}
	}
}
 
 
export function extractFlowableDocumentState(xml: string): FlowableDocumentState {
	const documentState = createEmptyFlowableState();
	const document = parseXmlDocument(xml);
	const definitions = document.documentElement;
	Iif (!definitions) {
		return documentState;
	}
 
	extractDefinitionLevelState(definitions, documentState);
 
	for (const processElement of getElementsByLocalName(document, 'process')) {
		extractProcessLevelState(processElement, documentState);
	}
 
	for (const node of getElementsByLocalName(document, '*')) {
		extractElementState(node, documentState);
	}
 
	ensureActivitiNamespace(documentState);
	return cloneFlowableState(documentState);
}