diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml
index 1d94a4fe3..c7996f749 100644
--- a/.github/workflows/build-lint-test.yml
+++ b/.github/workflows/build-lint-test.yml
@@ -36,6 +36,10 @@ jobs:
- name: ๐
Run stylelint
run: yarn workspace @kaoto/kaoto run lint:style
+ # Build packages excluding @kaoto/camel-catalog since it was build during installing dependencies
+ - name: Build packages
+ run: yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog --exclude @kaoto/xml-schema-ts run build
+
# Run tests
- name: ๐งช Run tests
run: yarn workspaces foreach --verbose --all --topological-dev run test
@@ -45,10 +49,6 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}
- # Build packages excluding @kaoto/camel-catalog since it was build during installing dependencies
- - name: Build packages
- run: yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog run build
-
# Build lib
- name: Build @kaoto/kaoto package in lib mode
run: yarn workspace @kaoto/kaoto run build:lib
diff --git a/.github/workflows/deploy-main.yml b/.github/workflows/deploy-main.yml
index 1b7f603de..bd030572d 100644
--- a/.github/workflows/deploy-main.yml
+++ b/.github/workflows/deploy-main.yml
@@ -44,7 +44,7 @@ jobs:
# Build packages excluding @kaoto/camel-catalog since it was build during installing dependencies
- name: '๐ง Build packages'
run: |
- yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog run build
+ yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog --exclude @kaoto/xml-schema-ts run build
- name: '๐ง Tar UI Dist'
shell: bash
diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index bdcbc8018..b1eb09c44 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -45,7 +45,7 @@ jobs:
# Build packages excluding @kaoto/camel-catalog since it was build during installing dependencies
- name: Build packages
- run: yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog run build
+ run: yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog --exclude @kaoto/xml-schema-ts run build
# Build lib
- name: Build @kaoto/kaoto package in lib mode
diff --git a/.github/workflows/release-pipeline.yml b/.github/workflows/release-pipeline.yml
index e24b217ff..f9e844958 100644
--- a/.github/workflows/release-pipeline.yml
+++ b/.github/workflows/release-pipeline.yml
@@ -105,7 +105,7 @@ jobs:
- name: '๐ง Build packages'
run: |
- yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog run build
+ yarn workspaces foreach --verbose --all --topological-dev --exclude @kaoto/camel-catalog --exclude @kaoto/xml-schema-ts run build
- name: '๐ฐ๏ธ Login to Container Registry'
uses: docker/login-action@v3
diff --git a/package.json b/package.json
index 9724d9246..a4c516973 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
"typescript": "5.5.4"
},
"scripts": {
- "postinstall": "yarn workspace @kaoto/camel-catalog run build",
+ "postinstall": "yarn workspace @kaoto/camel-catalog run build && yarn workspace @kaoto/xml-schema-ts run build",
"version": "lerna version",
"publish": "lerna publish from-package"
},
diff --git a/packages/ui-tests/stories/datamapper/DataMapperDebugger.stories.tsx b/packages/ui-tests/stories/datamapper/DataMapperDebugger.stories.tsx
new file mode 100644
index 000000000..c3293ce19
--- /dev/null
+++ b/packages/ui-tests/stories/datamapper/DataMapperDebugger.stories.tsx
@@ -0,0 +1,18 @@
+import { DataMapperDebugger } from '@kaoto/kaoto/testing';
+import { Meta, StoryFn } from '@storybook/react';
+import { fn } from '@storybook/test';
+
+export default {
+ title: 'DataMapper/Debugger',
+ component: DataMapperDebugger,
+} as Meta;
+
+const Template: StoryFn = (args) => {
+ return ;
+};
+
+export const Debugger = Template.bind({});
+Debugger.args = {
+ onUpdateDocument: fn(),
+ onUpdateMappings: fn(),
+};
diff --git a/packages/ui/jest-setup.ts b/packages/ui/jest-setup.ts
index 99fc973fc..6fc4f2ace 100644
--- a/packages/ui/jest-setup.ts
+++ b/packages/ui/jest-setup.ts
@@ -17,6 +17,20 @@ Object.defineProperty(window, 'fetch', {
value: jest.fn(),
});
+Object.defineProperty(window, 'matchMedia', {
+ writable: true,
+ value: jest.fn().mockImplementation((query) => ({
+ matches: false,
+ media: query,
+ onchange: null,
+ addListener: jest.fn(), // Deprecated
+ removeListener: jest.fn(), // Deprecated
+ addEventListener: jest.fn(),
+ removeEventListener: jest.fn(),
+ dispatchEvent: jest.fn(),
+ })),
+});
+
jest
.spyOn(global, 'crypto', 'get')
.mockImplementation(() => ({ getRandomValues: () => [12345678], subtle }) as unknown as Crypto);
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 56ab2e9ff..50f4ea8ac 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -51,12 +51,17 @@
"lint:style:fix": "yarn lint:style --fix"
},
"dependencies": {
+ "@dnd-kit/core": "^6.1.0",
"@kaoto-next/uniforms-patternfly": "^0.7.14",
+ "@kaoto/xml-schema-ts": "workspace:*",
"@kie-tools-core/editor": "0.32.0",
"@kie-tools-core/notifications": "0.32.0",
"@types/uuid": "^10.0.0",
+ "@types/xml-name-validator": "^4.0.3",
+ "@visx/shape": "^3.12.0",
"ajv": "^8.12.0",
"ajv-formats": "^3.0.0",
+ "chevrotain": "10.5.0",
"clsx": "^2.1.0",
"html-to-image": "^1.11.11",
"lodash": "^4.17.21",
@@ -67,6 +72,8 @@
"uniforms-bridge-json-schema": "4.0.0-alpha.6",
"usehooks-ts": "^3.0.0",
"uuid": "^10.0.0",
+ "xml-formatter": "^3.6.2",
+ "xml-name-validator": "^5.0.0",
"yaml": "^2.3.2",
"zustand": "^4.3.9"
},
diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx
index 20995b843..7a4ff7892 100644
--- a/packages/ui/src/App.tsx
+++ b/packages/ui/src/App.tsx
@@ -1,4 +1,11 @@
+import { VisualizationProvider } from '@patternfly/react-topology';
+import { useMemo } from 'react';
import { Outlet } from 'react-router-dom';
+import { RenderingProvider } from './components/RenderingAnchor/rendering.provider';
+import { ControllerService } from './components/Visualization/Canvas/controller.service';
+import { RegisterComponents } from './components/registers/RegisterComponents';
+import { RegisterNodeInteractionAddons } from './components/registers/RegisterNodeInteractionAddons';
+import { NodeInteractionAddonProvider } from './components/registers/interactions/node-interaction-addon.provider';
import { useReload } from './hooks/reload.hook';
import { Shell } from './layout/Shell';
import { LocalStorageSettingsAdapter } from './models/settings/localstorage-settings-adapter';
@@ -17,6 +24,7 @@ import { CatalogSchemaLoader } from './utils/catalog-schema-loader';
function App() {
const ReloadProvider = useReload();
+ const controller = useMemo(() => ControllerService.createController(), []);
const settingsAdapter = new LocalStorageSettingsAdapter();
let catalogUrl = CatalogSchemaLoader.DEFAULT_CATALOG_PATH;
const settingsCatalogUrl = settingsAdapter.getSettings().catalogUrl;
@@ -35,9 +43,19 @@ function App() {
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/assets/components/datamapper.png b/packages/ui/src/assets/components/datamapper.png
new file mode 100644
index 000000000..57472858c
Binary files /dev/null and b/packages/ui/src/assets/components/datamapper.png differ
diff --git a/packages/ui/src/assets/data-mapper/add-parameter.png b/packages/ui/src/assets/data-mapper/add-parameter.png
new file mode 100644
index 000000000..104295fda
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/add-parameter.png differ
diff --git a/packages/ui/src/assets/data-mapper/add_parameter_confirm.png b/packages/ui/src/assets/data-mapper/add_parameter_confirm.png
new file mode 100644
index 000000000..cfc2a6a10
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/add_parameter_confirm.png differ
diff --git a/packages/ui/src/assets/data-mapper/attach-schema-parameter.png b/packages/ui/src/assets/data-mapper/attach-schema-parameter.png
new file mode 100644
index 000000000..38b38a69d
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/attach-schema-parameter.png differ
diff --git a/packages/ui/src/assets/data-mapper/attach-schema-source-body.png b/packages/ui/src/assets/data-mapper/attach-schema-source-body.png
new file mode 100644
index 000000000..973be1a40
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/attach-schema-source-body.png differ
diff --git a/packages/ui/src/assets/data-mapper/attach-schema-target-body.png b/packages/ui/src/assets/data-mapper/attach-schema-target-body.png
new file mode 100644
index 000000000..0d9818df2
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/attach-schema-target-body.png differ
diff --git a/packages/ui/src/assets/data-mapper/configure-button.png b/packages/ui/src/assets/data-mapper/configure-button.png
new file mode 100644
index 000000000..f2a77bde3
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/configure-button.png differ
diff --git a/packages/ui/src/assets/data-mapper/data-mapping.png b/packages/ui/src/assets/data-mapper/data-mapping.png
new file mode 100644
index 000000000..58449c875
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/data-mapping.png differ
diff --git a/packages/ui/src/assets/data-mapper/datamapper-step.png b/packages/ui/src/assets/data-mapper/datamapper-step.png
new file mode 100644
index 000000000..b38b2b53e
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/datamapper-step.png differ
diff --git a/packages/ui/src/assets/data-mapper/kaoto-datamapper-catalog.png b/packages/ui/src/assets/data-mapper/kaoto-datamapper-catalog.png
new file mode 100644
index 000000000..604c4eaea
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/kaoto-datamapper-catalog.png differ
diff --git a/packages/ui/src/assets/data-mapper/kaoto-design.png b/packages/ui/src/assets/data-mapper/kaoto-design.png
new file mode 100644
index 000000000..46e5aa5fd
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/kaoto-design.png differ
diff --git a/packages/ui/src/assets/data-mapper/source-target.png b/packages/ui/src/assets/data-mapper/source-target.png
new file mode 100644
index 000000000..59a287564
Binary files /dev/null and b/packages/ui/src/assets/data-mapper/source-target.png differ
diff --git a/packages/ui/src/assets/kaoto-patterns/kaoto-patterns.json b/packages/ui/src/assets/kaoto-patterns/kaoto-patterns.json
new file mode 100644
index 000000000..0ff8ac0a8
--- /dev/null
+++ b/packages/ui/src/assets/kaoto-patterns/kaoto-patterns.json
@@ -0,0 +1,97 @@
+{
+ "kaoto-datamapper" : {
+ "model" : {
+ "kind" : "model",
+ "name" : "kaoto-datamapper",
+ "title" : "Kaoto DataMapper",
+ "description" : "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
+ "deprecated" : false,
+ "label" : "transformation",
+ "javaType" : "org.apache.camel.model.StepDefinition",
+ "supportLevel" : "Stable",
+ "abstract" : false,
+ "input" : true,
+ "output" : true
+ },
+ "properties" : {
+ "description" : {
+ "index" : 0,
+ "kind" : "attribute",
+ "displayName" : "Description",
+ "group" : "common",
+ "required" : false,
+ "type" : "string",
+ "javaType" : "java.lang.String",
+ "deprecated" : false,
+ "autowired" : false,
+ "secret" : false,
+ "description" : "Sets the description of this node"
+ },
+ "disabled" : {
+ "index" : 1,
+ "kind" : "attribute",
+ "displayName" : "Disabled",
+ "group" : "advanced",
+ "label" : "advanced",
+ "required" : false,
+ "type" : "boolean",
+ "javaType" : "java.lang.Boolean",
+ "deprecated" : false,
+ "autowired" : false,
+ "secret" : false,
+ "defaultValue" : false,
+ "description" : "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime."
+ },
+ "outputs" : {
+ "index" : 2,
+ "kind" : "element",
+ "displayName" : "Outputs",
+ "group" : "common",
+ "required" : true,
+ "type" : "array",
+ "javaType" : "java.util.List",
+ "oneOf" : [ "aggregate", "bean", "choice", "circuitBreaker", "claimCheck", "convertBodyTo", "convertHeaderTo", "convertVariableTo", "delay", "doCatch", "doFinally", "doTry", "dynamicRouter", "enrich", "filter", "idempotentConsumer", "intercept", "interceptFrom", "interceptSendToEndpoint", "kamelet", "loadBalance", "log", "loop", "marshal", "multicast", "onCompletion", "onException", "onFallback", "otherwise", "pausable", "pipeline", "policy", "pollEnrich", "process", "recipientList", "removeHeader", "removeHeaders", "removeProperties", "removeProperty", "removeVariable", "resequence", "resumable", "rollback", "routingSlip", "saga", "sample", "script", "serviceCall", "setBody", "setExchangePattern", "setHeader", "setHeaders", "setProperty", "setVariable", "setVariables", "sort", "split", "step", "stop", "threads", "throttle", "throwException", "to", "toD", "transacted", "transform", "unmarshal", "validate", "when", "whenSkipSendToEndpoint", "wireTap" ],
+ "deprecated" : false,
+ "autowired" : false,
+ "secret" : false
+ }
+ },
+ "exchangeProperties" : {
+ "CamelStepId" : {
+ "index" : 0,
+ "kind" : "exchangeProperty",
+ "displayName" : "Step Id",
+ "label" : "producer",
+ "required" : false,
+ "javaType" : "String",
+ "deprecated" : false,
+ "autowired" : false,
+ "secret" : false,
+ "description" : "The id of the Step EIP"
+ }
+ },
+ "propertiesSchema" : {
+ "title" : "Kaoto DataMapper",
+ "description" : "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
+ "type" : "object",
+ "additionalProperties" : false,
+ "properties" : {
+ "description" : {
+ "type" : "string",
+ "title" : "Description",
+ "description" : "Sets the description of this node",
+ "group" : "common"
+ },
+ "disabled" : {
+ "type" : "boolean",
+ "title" : "Disabled",
+ "description" : "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.",
+ "group" : "advanced"
+ }
+ },
+ "$comment" : "steps",
+ "$schema" : "http://json-schema.org/draft-07/schema#",
+ "required" : [ ]
+ }
+ }
+}
diff --git a/packages/ui/src/camel-utils/camel-random-id.test.ts b/packages/ui/src/camel-utils/camel-random-id.test.ts
index 2fa43aa75..bb9f0a720 100644
--- a/packages/ui/src/camel-utils/camel-random-id.test.ts
+++ b/packages/ui/src/camel-utils/camel-random-id.test.ts
@@ -1,4 +1,4 @@
-import { getCamelRandomId } from './camel-random-id';
+import { getCamelRandomId, getHexaDecimalRandomId } from './camel-random-id';
describe('camel-random-id', () => {
it('should return a random number', () => {
@@ -35,4 +35,19 @@ describe('camel-random-id', () => {
expect(getCamelRandomId('route')).toEqual(expect.any(String));
});
+
+ describe('getHexaDecimalRandomId()', () => {
+ it('should return a random number with Hexadecimal format', async () => {
+ // crypto.getRandomValues() in Jest returns a fixed number 12345678. Replacing with Date.now()
+ jest
+ .spyOn(global, 'crypto', 'get')
+ .mockImplementation(() => ({ getRandomValues: () => [Date.now()] }) as unknown as Crypto);
+ const one = getHexaDecimalRandomId('test');
+ expect(one).toMatch(/test-[0-9a-f]{1,8}/);
+ await new Promise((f) => setTimeout(f, 1));
+ const two = getHexaDecimalRandomId('test');
+ expect(two).toMatch(/test-[0-9a-f]{1,8}/);
+ expect(one).not.toEqual(two);
+ });
+ });
});
diff --git a/packages/ui/src/camel-utils/camel-random-id.ts b/packages/ui/src/camel-utils/camel-random-id.ts
index d6c51b168..651a7635e 100644
--- a/packages/ui/src/camel-utils/camel-random-id.ts
+++ b/packages/ui/src/camel-utils/camel-random-id.ts
@@ -1,6 +1,14 @@
+const getCryptoObj = () => {
+ return window.crypto || (window as Window & { msCrypto?: Crypto }).msCrypto;
+};
+
export const getCamelRandomId = (kind: string, length = 4): string => {
- const cryptoObj = window.crypto || (window as Window & { msCrypto?: Crypto }).msCrypto;
- const randomNumber = Math.floor(cryptoObj?.getRandomValues(new Uint32Array(1))[0] ?? Date.now());
+ const randomNumber = Math.floor(getCryptoObj()?.getRandomValues(new Uint32Array(1))[0] ?? Date.now());
return `${kind}-${randomNumber.toString(10).slice(0, length)}`;
};
+
+export const getHexaDecimalRandomId = (prefix: string) => {
+ const randomNumber = getCryptoObj()?.getRandomValues(new Uint32Array(1))[0] ?? Date.now();
+ return `${prefix}-${randomNumber.toString(16)}`;
+};
diff --git a/packages/ui/src/components/DataMapper/DataMapper.test.tsx b/packages/ui/src/components/DataMapper/DataMapper.test.tsx
new file mode 100644
index 000000000..e713e1061
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/DataMapper.test.tsx
@@ -0,0 +1,113 @@
+import { render, screen } from '@testing-library/react';
+import { IVisualizationNode } from '../../models';
+import { DocumentDefinitionType } from '../../models/datamapper/document';
+import { IDataMapperMetadata } from '../../models/datamapper/metadata';
+import { IMetadataApi, MetadataProvider } from '../../providers';
+import { shipOrderToShipOrderXslt, shipOrderXsd } from '../../stubs/data-mapper';
+import { DataMapper } from './DataMapper';
+
+describe('DataMapperPage', () => {
+ const vizNode = {
+ getId: () => 'route-1234',
+ getComponentSchema: () => {
+ return {
+ definition: { id: 'kaoto-datamapper-1234' },
+ };
+ },
+ } as unknown as IVisualizationNode;
+ const defaultMetadata: IDataMapperMetadata = {
+ sourceBody: {
+ type: DocumentDefinitionType.Primitive,
+ filePath: [],
+ },
+ sourceParameters: {},
+ targetBody: {
+ type: DocumentDefinitionType.Primitive,
+ filePath: [],
+ },
+ xsltPath: `kaoto-datamapper-1234.xsl`,
+ };
+
+ let metadata: IDataMapperMetadata;
+ let fileContents: Record;
+ const api = {
+ getMetadata: (_key: string) => {
+ return Promise.resolve(metadata);
+ },
+ setMetadata: (_key: string, meta: IDataMapperMetadata) => {
+ Object.assign(metadata, meta);
+ return Promise.resolve();
+ },
+ getResourceContent: (path: string) => {
+ return Promise.resolve(fileContents[path]);
+ },
+ saveResourceContent: (path: string, content: string) => {
+ fileContents[path] = content;
+ return Promise.resolve();
+ },
+ } as IMetadataApi;
+
+ beforeEach(() => {
+ metadata = defaultMetadata;
+ fileContents = {};
+ });
+
+ it('should render initial XSLT mappings', async () => {
+ fileContents[metadata.xsltPath] = shipOrderToShipOrderXslt;
+ render(
+
+
+ ,
+ );
+ await screen.findByTestId('card-source-parameters-header');
+ // TODO assert mappings are restored even without loading schema... But how? Lines are not drawn...
+ });
+
+ it('should render initial XSLT mappings with initial documents', async () => {
+ fileContents['ShipOrder.xsd'] = shipOrderXsd;
+ metadata.sourceBody = {
+ filePath: ['ShipOrder.xsd'],
+ type: DocumentDefinitionType.XML_SCHEMA,
+ };
+ metadata.targetBody = {
+ filePath: ['ShipOrder.xsd'],
+ type: DocumentDefinitionType.XML_SCHEMA,
+ };
+ metadata.sourceParameters['testparam1'] = {
+ filePath: [],
+ type: DocumentDefinitionType.Primitive,
+ };
+ render(
+
+
+ ,
+ );
+ await screen.findByTestId('card-source-parameters-header');
+ expect(screen.getByTestId('node-source-doc-param-testparam1')).toBeInTheDocument();
+ expect(screen.getByTestId('node-source-doc-sourceBody-Body')).toBeInTheDocument();
+ expect(screen.getByTestId('node-target-doc-targetBody-Body')).toBeInTheDocument();
+ expect(screen.getByTestId(/node-source-field-OrderId-\n*/)).toBeInTheDocument();
+ expect(screen.getByTestId(/node-target-field-OrderId-\n*/)).toBeInTheDocument();
+ // TODO assert mappings are restored even without loading schema... But how? Lines are not drawn...
+ });
+
+ it('should not render toolbar menu in embedded mode', async () => {
+ render(
+
+
+ ,
+ );
+ try {
+ await screen.findByTestId('main-menu-button');
+ fail();
+ } catch (e) {
+ expect(e).toBeTruthy();
+ }
+ });
+
+ it('should show an error message if vizNode is not provided', async () => {
+ render( );
+ const error = await screen.findByText('No associated DataMapper step was provided.');
+ expect(error).toBeInTheDocument();
+ });
+});
diff --git a/packages/ui/src/components/DataMapper/DataMapper.tsx b/packages/ui/src/components/DataMapper/DataMapper.tsx
new file mode 100644
index 000000000..b7d7a5547
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/DataMapper.tsx
@@ -0,0 +1,116 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { FunctionComponent, useCallback, useContext, useEffect, useState } from 'react';
+import { DataMapperControl } from '../../components/DataMapper/DataMapperControl';
+import { DataMapperProvider } from '../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../providers/datamapper-canvas.provider';
+import { DocumentDefinition, DocumentInitializationModel } from '../../models/datamapper/document';
+import { IVisualizationNode } from '../../models';
+import { EntitiesContext, MetadataContext } from '../../providers';
+import { DataMapperMetadataService } from '../../services/datamapper-metadata.service';
+import { DocumentType } from '../../models/datamapper/path';
+import { IDataMapperMetadata } from '../../models/datamapper/metadata';
+import { Loading } from '../../components/Loading';
+
+export interface IDataMapperProps {
+ vizNode?: IVisualizationNode;
+}
+
+export const DataMapper: FunctionComponent = ({ vizNode }) => {
+ const entitiesContext = useContext(EntitiesContext)!;
+ const ctx = useContext(MetadataContext)!;
+ const metadataId = vizNode && DataMapperMetadataService.getDataMapperMetadataId(vizNode);
+ const [metadata, setMetadata] = useState();
+ const [documentInitializationModel, setDocumentInitializationModel] = useState();
+ const [initialXsltFile, setInitialXsltFile] = useState();
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ if (!metadataId) return;
+ const initialize = async () => {
+ let meta = await ctx.getMetadata(metadataId);
+ if (!meta) {
+ meta = await DataMapperMetadataService.initializeDataMapperMetadata(entitiesContext, vizNode, ctx, metadataId);
+ }
+ setMetadata(meta);
+ const initModel = await DataMapperMetadataService.loadDocuments(ctx, meta);
+ setDocumentInitializationModel(initModel);
+ const mappingFile = await DataMapperMetadataService.loadMappingFile(ctx, meta);
+ setInitialXsltFile(mappingFile);
+ };
+ initialize().then(() => setIsLoading(false));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const onUpdateDocument = useCallback(
+ (definition: DocumentDefinition) => {
+ if (!metadataId || !metadata) return;
+ switch (definition.documentType) {
+ case DocumentType.SOURCE_BODY:
+ DataMapperMetadataService.updateSourceBodyMetadata(ctx, metadataId, metadata, definition);
+ break;
+ case DocumentType.TARGET_BODY:
+ DataMapperMetadataService.updateTargetBodyMetadata(ctx, metadataId, metadata, definition);
+ break;
+ case DocumentType.PARAM:
+ DataMapperMetadataService.updateSourceParameterMetadata(
+ ctx,
+ metadataId,
+ metadata,
+ definition.name!,
+ definition,
+ );
+ }
+ },
+ [ctx, metadata, metadataId],
+ );
+
+ const onDeleteParameter = useCallback(
+ (name: string) => {
+ if (!metadataId || !metadata) return;
+ DataMapperMetadataService.deleteSourceParameterMetadata(ctx, metadataId, metadata, name);
+ },
+ [ctx, metadata, metadataId],
+ );
+
+ const onUpdateMappings = useCallback(
+ (xsltFile: string) => {
+ if (!metadata) return;
+ DataMapperMetadataService.updateMappingFile(ctx, metadata, xsltFile);
+ },
+ [ctx, metadata],
+ );
+
+ return !metadataId ? (
+ <>No associated DataMapper step was provided.>
+ ) : isLoading ? (
+
+ ) : (
+
+
+
+
+
+ );
+};
+
+export default DataMapper;
diff --git a/packages/ui/src/components/DataMapper/DataMapperControl.tsx b/packages/ui/src/components/DataMapper/DataMapperControl.tsx
new file mode 100644
index 000000000..4579f3a1b
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/DataMapperControl.tsx
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { FunctionComponent, useMemo } from 'react';
+import { useDataMapper } from '../../hooks/useDataMapper';
+import { CanvasView } from '../../models/datamapper/view';
+import { SourceTargetView } from '../View/SourceTargetView';
+
+export const DataMapperControl: FunctionComponent = () => {
+ const { activeView } = useDataMapper();
+ const currentView = useMemo(() => {
+ switch (activeView) {
+ case CanvasView.SOURCE_TARGET:
+ return ;
+ default:
+ return <>View {activeView} is not supported>;
+ }
+ }, [activeView]);
+
+ return <>{currentView}>;
+};
diff --git a/packages/ui/src/components/DataMapper/DataMapperLauncher.scss b/packages/ui/src/components/DataMapper/DataMapperLauncher.scss
new file mode 100644
index 000000000..aecd3e85c
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/DataMapperLauncher.scss
@@ -0,0 +1,5 @@
+.data-mapper-launcher {
+ button {
+ margin-top: var(--pf-v5-global--spacer--md);
+ }
+}
diff --git a/packages/ui/src/components/DataMapper/DataMapperLauncher.tsx b/packages/ui/src/components/DataMapper/DataMapperLauncher.tsx
new file mode 100644
index 000000000..afd68bb1a
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/DataMapperLauncher.tsx
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 {
+ Alert,
+ Button,
+ Form,
+ FormGroup,
+ HelperText,
+ HelperTextItem,
+ Popover,
+ TextInput,
+ ValidatedOptions,
+} from '@patternfly/react-core';
+import { HelpIcon, WrenchIcon } from '@patternfly/react-icons';
+import { FunctionComponent, useCallback, useContext, useMemo } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { IVisualizationNode } from '../../models';
+import { MetadataContext } from '../../providers/metadata.provider';
+import { Links } from '../../router/links.models';
+import { DataMapperMetadataService } from '../../services/datamapper-metadata.service';
+import { isDefined, isXSLTComponent } from '../../utils';
+import type { XsltComponentDef } from '../../utils/is-xslt-component';
+import './DataMapperLauncher.scss';
+
+export const DataMapperLauncher: FunctionComponent<{ vizNode?: IVisualizationNode }> = ({ vizNode }) => {
+ const navigate = useNavigate();
+ const metadata = useContext(MetadataContext);
+ const xsltDocument = useMemo(() => {
+ const xsltComponent = vizNode?.getComponentSchema()?.definition?.steps?.find(isXSLTComponent) as XsltComponentDef;
+ return DataMapperMetadataService.getXSLTDocumentName(xsltComponent);
+ }, [vizNode]);
+ const isXsltDocumentDefined = useMemo(() => {
+ return isDefined(xsltDocument);
+ }, [xsltDocument]);
+
+ const onClick = useCallback(() => {
+ navigate(`${Links.DataMapper}/${vizNode?.getComponentSchema()?.definition?.id}`);
+ }, [navigate, vizNode]);
+
+ if (!isDefined(metadata)) {
+ return (
+
+
+ At the moment, the Kaoto DataMapper cannot be configured using the browser directly. Please use the VS Code
+ extension for an enhanced experience. The Kaoto extension is bundled in the
+
+ Extension Pack for Apache Camel
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ }
+ >
+ Configure
+
+
+ );
+};
+
+export default DataMapperLauncher;
diff --git a/packages/ui/src/components/DataMapper/debug/CanvasMonitor.tsx b/packages/ui/src/components/DataMapper/debug/CanvasMonitor.tsx
new file mode 100644
index 000000000..1380d5ff7
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/CanvasMonitor.tsx
@@ -0,0 +1,18 @@
+import { FunctionComponent, useEffect } from 'react';
+import { useCanvas } from '../../../hooks/useCanvas';
+
+export const CanvasMonitor: FunctionComponent = () => {
+ const { getAllNodePaths, reloadNodeReferences } = useCanvas();
+
+ useEffect(() => {
+ console.log(
+ 'Node References: [' +
+ getAllNodePaths()
+ .map((p) => p + '\n')
+ .toString() +
+ ']',
+ );
+ }, [getAllNodePaths, reloadNodeReferences]);
+
+ return <>>;
+};
diff --git a/packages/ui/src/components/DataMapper/debug/ContextToolbar.tsx b/packages/ui/src/components/DataMapper/debug/ContextToolbar.tsx
new file mode 100644
index 000000000..f5d63665b
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/ContextToolbar.tsx
@@ -0,0 +1,34 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { FunctionComponent } from 'react';
+import { Toolbar, ToolbarContent, ToolbarGroup } from '@patternfly/react-core';
+import { MainMenuToolbarItem } from './MainMenuToolbarItem';
+import { ToggleDebugToolbarItem } from './ToggleDebugToolbarItem';
+
+export const ContextToolbar: FunctionComponent = () => {
+ return (
+
+
+ {
+
+
+
+
+ }
+
+
+ );
+};
diff --git a/packages/ui/src/components/DataMapper/debug/DataMapperDebugger.test.tsx b/packages/ui/src/components/DataMapper/debug/DataMapperDebugger.test.tsx
new file mode 100644
index 000000000..583461424
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/DataMapperDebugger.test.tsx
@@ -0,0 +1,13 @@
+import { DataMapperDebugger } from './DataMapperDebugger';
+import { render, screen } from '@testing-library/react';
+
+describe('Debug', () => {
+ it('should render', async () => {
+ const mockLog = jest.fn();
+ console.log = mockLog;
+ render( );
+ await screen.findByTestId('main-menu-button');
+ const nodeRefsLog = mockLog.mock.calls.filter((call) => call[0].startsWith('Node References: ['));
+ expect(nodeRefsLog.length).toBeGreaterThan(0);
+ });
+});
diff --git a/packages/ui/src/components/DataMapper/debug/DataMapperDebugger.tsx b/packages/ui/src/components/DataMapper/debug/DataMapperDebugger.tsx
new file mode 100644
index 000000000..c9552cdd4
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/DataMapperDebugger.tsx
@@ -0,0 +1,32 @@
+import { FunctionComponent } from 'react';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { DebugLayout } from './DebugLayout';
+import { DocumentDefinition, DocumentInitializationModel } from '../../../models/datamapper';
+
+type DataMapperDebuggerProps = {
+ documentInitializationModel?: DocumentInitializationModel;
+ onUpdateDocument?: (definition: DocumentDefinition) => void;
+ initialXsltFile?: string;
+ onUpdateMappings?: (xsltFile: string) => void;
+};
+
+export const DataMapperDebugger: FunctionComponent = ({
+ documentInitializationModel,
+ onUpdateDocument,
+ initialXsltFile,
+ onUpdateMappings,
+}) => {
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/DataMapper/debug/DataMapperMonitor.tsx b/packages/ui/src/components/DataMapper/debug/DataMapperMonitor.tsx
new file mode 100644
index 000000000..3e69f48df
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/DataMapperMonitor.tsx
@@ -0,0 +1,15 @@
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { useEffect } from 'react';
+import { MappingService } from '../../../services/mapping.service';
+
+export const DataMapperMonitor = () => {
+ const { mappingTree, sourceParameterMap, sourceBodyDocument, targetBodyDocument } = useDataMapper();
+
+ useEffect(() => {
+ MappingService.extractMappingLinks(mappingTree, sourceParameterMap, sourceBodyDocument).forEach((mapping) => {
+ console.log(`Mapping: [source={${mapping.sourceNodePath}}, target={${mapping.targetNodePath}}]`);
+ });
+ }, [mappingTree, sourceBodyDocument, sourceParameterMap, targetBodyDocument]);
+
+ return <>>;
+};
diff --git a/packages/ui/src/components/DataMapper/debug/DebugLayout.scss b/packages/ui/src/components/DataMapper/debug/DebugLayout.scss
new file mode 100644
index 000000000..5f7ee499d
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/DebugLayout.scss
@@ -0,0 +1,11 @@
+.debug-layout {
+ height: 100%;
+
+ &__drawer-content {
+ height: 100%;
+ }
+
+ &__drawer-content-body {
+ height: 100%;
+ }
+}
diff --git a/packages/ui/src/components/DataMapper/debug/DebugLayout.test.tsx b/packages/ui/src/components/DataMapper/debug/DebugLayout.test.tsx
new file mode 100644
index 000000000..af80c3213
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/DebugLayout.test.tsx
@@ -0,0 +1,177 @@
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
+import { DebugLayout } from './DebugLayout';
+import { FunctionComponent, PropsWithChildren, useEffect } from 'react';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { useCanvas } from '../../../hooks/useCanvas';
+import { MappingSerializerService } from '../../../services/mapping-serializer.service';
+import { MappingTree } from '../../../models/datamapper/mapping';
+import { shipOrderToShipOrderXslt, TestUtil } from '../../../stubs/data-mapper';
+import { IMappingLink } from '../../../models/datamapper/visualization';
+import { MappingService } from '../../../services/mapping.service';
+
+describe('DebugLayout', () => {
+ afterAll(() => {
+ jest.resetModules();
+ jest.resetAllMocks();
+ });
+
+ it('should render Documents and mappings', async () => {
+ let mappingLinks: IMappingLink[] = [];
+ const LoadMappings: FunctionComponent = ({ children }) => {
+ const {
+ mappingTree,
+ setMappingTree,
+ sourceParameterMap,
+ setSourceBodyDocument,
+ setTargetBodyDocument,
+ sourceBodyDocument,
+ } = useDataMapper();
+ const { getAllNodePaths, reloadNodeReferences } = useCanvas();
+ useEffect(() => {
+ const sourceDoc = TestUtil.createSourceOrderDoc();
+ setSourceBodyDocument(sourceDoc);
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ setTargetBodyDocument(targetDoc);
+ MappingSerializerService.deserialize(shipOrderToShipOrderXslt, targetDoc, mappingTree, sourceParameterMap);
+ setMappingTree(mappingTree);
+ reloadNodeReferences();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ useEffect(() => {
+ mappingLinks = MappingService.extractMappingLinks(mappingTree, sourceParameterMap, sourceBodyDocument);
+ }, [getAllNodePaths, mappingTree, sourceBodyDocument, sourceParameterMap]);
+ return <>{children}>;
+ };
+ const mockLog = jest.fn();
+ console.log = mockLog;
+ render(
+
+
+
+
+
+
+ ,
+ );
+ await screen.findAllByText('ShipOrder');
+ const targetNodes = screen.getAllByTestId(/node-target-.*/);
+ expect(targetNodes.length).toEqual(20);
+ expect(mappingLinks.length).toEqual(11);
+ const nodeRefsLog = mockLog.mock.calls.filter((call) => call[0].startsWith('Node References: ['));
+ expect(nodeRefsLog.length).toBeGreaterThan(0);
+ });
+
+ describe('Main Menu', () => {
+ it('should import and export mappings', async () => {
+ let spyOnMappingTree: MappingTree;
+ const TestLoader: FunctionComponent = ({ children }) => {
+ const { mappingTree, setSourceBodyDocument, setTargetBodyDocument } = useDataMapper();
+ const { reloadNodeReferences } = useCanvas();
+ useEffect(() => {
+ const sourceDoc = TestUtil.createSourceOrderDoc();
+ setSourceBodyDocument(sourceDoc);
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ setTargetBodyDocument(targetDoc);
+ reloadNodeReferences();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ useEffect(() => {
+ spyOnMappingTree = mappingTree;
+ }, [mappingTree]);
+ return <>{children}>;
+ };
+ const mockLog = jest.fn();
+ console.log = mockLog;
+ render(
+
+
+
+
+
+
+ ,
+ );
+ let mainMenuButton = await screen.findByTestId('main-menu-button');
+ act(() => {
+ fireEvent.click(mainMenuButton);
+ });
+ const importButton = screen.getByTestId('import-mappings-button');
+ act(() => {
+ fireEvent.click(importButton);
+ });
+ const fileContent = new File([new Blob([shipOrderToShipOrderXslt])], 'ShipOrderToShipOrder.xsl', {
+ type: 'text/plain',
+ });
+ const fileInput = screen.getByTestId('import-mappings-file-input');
+ expect(spyOnMappingTree!.children.length).toBe(0);
+ act(() => {
+ fireEvent.change(fileInput, { target: { files: { item: () => fileContent, length: 1, 0: fileContent } } });
+ });
+ await waitFor(() => expect(spyOnMappingTree!.children.length).toBe(1));
+
+ mainMenuButton = screen.getByTestId('main-menu-button');
+ act(() => {
+ fireEvent.click(mainMenuButton);
+ });
+ const exportButton = screen.getByTestId('export-mappings-button');
+ act(() => {
+ fireEvent.click(exportButton.getElementsByTagName('button')[0]);
+ });
+ const modal = await screen.findAllByTestId('export-mappings-modal');
+ expect(modal).toBeTruthy();
+ const closeModalButton = screen.getByTestId('export-mappings-modal-close-btn');
+ act(() => {
+ fireEvent.click(closeModalButton);
+ });
+ expect(screen.queryByTestId('export-mappings-modal')).toBeFalsy();
+ const nodeRefsLog = mockLog.mock.calls.filter((call) => call[0].startsWith('Node References: ['));
+ expect(nodeRefsLog.length).toBeGreaterThan(0);
+ }, 15000);
+ });
+
+ describe('debug', () => {
+ it('should output debug info to console', async () => {
+ const TestLoader: FunctionComponent = ({ children }) => {
+ const {
+ setDebug,
+ mappingTree,
+ setMappingTree,
+ sourceParameterMap,
+ setSourceBodyDocument,
+ setTargetBodyDocument,
+ } = useDataMapper();
+ const { reloadNodeReferences } = useCanvas();
+ useEffect(() => {
+ setDebug(true);
+ const sourceDoc = TestUtil.createSourceOrderDoc();
+ setSourceBodyDocument(sourceDoc);
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ setTargetBodyDocument(targetDoc);
+ MappingSerializerService.deserialize(shipOrderToShipOrderXslt, targetDoc, mappingTree, sourceParameterMap);
+ setMappingTree(mappingTree);
+ reloadNodeReferences();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ return <>{children}>;
+ };
+ const mockLog = jest.fn();
+ console.log = mockLog;
+ render(
+
+
+
+
+
+
+ ,
+ );
+ await screen.findByTestId('main-menu-button');
+ const nodeRefsLog = mockLog.mock.calls.filter((call) => call[0].startsWith('Node References: ['));
+ expect(nodeRefsLog.length).toBeGreaterThan(0);
+ const mappingsLog = mockLog.mock.calls.filter((call) => call[0].startsWith('Mapping: ['));
+ expect(mappingsLog.length).toBeGreaterThan(0);
+ });
+ });
+});
diff --git a/packages/ui/src/components/DataMapper/debug/DebugLayout.tsx b/packages/ui/src/components/DataMapper/debug/DebugLayout.tsx
new file mode 100644
index 000000000..ddcabe979
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/DebugLayout.tsx
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { FunctionComponent, memo, useEffect } from 'react';
+import { Masthead, MastheadContent, Page, PageSection, PageSectionVariants } from '@patternfly/react-core';
+import { ContextToolbar } from './ContextToolbar';
+import './DebugLayout.scss';
+import { DataMapperControl } from '../DataMapperControl';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { CanvasMonitor } from './CanvasMonitor';
+import { DataMapperMonitor } from './DataMapperMonitor';
+import { BrowserFilePickerMetadataProvider } from '../../../stubs/BrowserFilePickerMetadataProvider';
+
+export const DebugLayout: FunctionComponent = memo(function DebugLayout() {
+ const { setDebug } = useDataMapper()!;
+ useEffect(() => {
+ setDebug(true);
+ }, [setDebug]);
+
+ const header = (
+
+
+
+
+
+ );
+
+ return (
+
+
+
+
+
+
+
+
+
+ );
+});
diff --git a/packages/ui/src/components/DataMapper/debug/ExportMappingFileDropdownItem.tsx b/packages/ui/src/components/DataMapper/debug/ExportMappingFileDropdownItem.tsx
new file mode 100644
index 000000000..c6da3777f
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/ExportMappingFileDropdownItem.tsx
@@ -0,0 +1,75 @@
+import { Button, DropdownItem, Modal } from '@patternfly/react-core';
+import { CodeEditor, Language } from '@patternfly/react-code-editor';
+import { FunctionComponent, useCallback, useMemo, useState } from 'react';
+import { ExportIcon } from '@patternfly/react-icons';
+import { MappingSerializerService } from '../../../services/mapping-serializer.service';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { Monaco } from '@monaco-editor/react';
+import { editor } from 'monaco-editor/esm/vs/editor/editor.api';
+import IStandaloneEditorConstructionOptions = editor.IStandaloneEditorConstructionOptions;
+
+export const ExportMappingFileDropdownItem: FunctionComponent<{
+ onComplete: () => void;
+}> = ({ onComplete }) => {
+ const { mappingTree, sourceParameterMap } = useDataMapper();
+ const [isModalOpen, setIsModalOpen] = useState();
+ const [serializedMappings, setSerializedMappings] = useState();
+
+ const handleMenuClick = useCallback(() => {
+ const serialized = MappingSerializerService.serialize(mappingTree, sourceParameterMap);
+ setSerializedMappings(serialized);
+ setIsModalOpen(true);
+ }, [mappingTree, sourceParameterMap]);
+
+ const handleModalClose = useCallback(() => {
+ setSerializedMappings('');
+ setIsModalOpen(false);
+ onComplete();
+ }, [onComplete]);
+
+ const onEditorDidMount = useCallback((editor: editor.IStandaloneCodeEditor, monaco: Monaco) => {
+ editor.layout();
+ editor.focus();
+ monaco.editor.getModels()[0].updateOptions({ tabSize: 2 });
+ }, []);
+
+ const modalActions = useMemo(() => {
+ return [
+
+ Close
+ ,
+ ];
+ }, [handleModalClose]);
+
+ const editorOptions: IStandaloneEditorConstructionOptions = useMemo(() => {
+ return { wordWrap: 'on' };
+ }, []);
+
+ return (
+ <>
+ } onClick={handleMenuClick} data-testid="export-mappings-button">
+ Export current mappings (.xsl)
+
+ handleModalClose()}
+ actions={modalActions}
+ data-testid="export-mappings-modal"
+ >
+
+
+ >
+ );
+};
diff --git a/packages/ui/src/components/DataMapper/debug/ImportMappingFileDropdownItem.tsx b/packages/ui/src/components/DataMapper/debug/ImportMappingFileDropdownItem.tsx
new file mode 100644
index 000000000..9b7ed9f84
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/ImportMappingFileDropdownItem.tsx
@@ -0,0 +1,50 @@
+import { DropdownItem } from '@patternfly/react-core';
+import { ChangeEvent, createRef, FunctionComponent, useCallback } from 'react';
+import { ImportIcon } from '@patternfly/react-icons';
+import { MappingSerializerService } from '../../../services/mapping-serializer.service';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { readFileAsString } from '../../../stubs/read-file-as-string';
+
+type ImportMappingFileDropdownItemProps = {
+ onComplete: () => void;
+};
+
+export const ImportMappingFileDropdownItem: FunctionComponent = ({
+ onComplete,
+}) => {
+ const { mappingTree, sourceParameterMap, targetBodyDocument, refreshMappingTree } = useDataMapper();
+ const fileInputRef = createRef();
+
+ const onClick = useCallback(() => {
+ fileInputRef.current?.click();
+ }, [fileInputRef]);
+
+ const onImport = useCallback(
+ (event: ChangeEvent) => {
+ const file = event.target.files?.item(0);
+ if (!file) return;
+ readFileAsString(file).then((content) => {
+ MappingSerializerService.deserialize(content, targetBodyDocument, mappingTree, sourceParameterMap);
+ refreshMappingTree();
+ onComplete();
+ });
+ },
+ [mappingTree, onComplete, refreshMappingTree, sourceParameterMap, targetBodyDocument],
+ );
+
+ return (
+ <>
+ } onClick={onClick} data-testid="import-mappings-button">
+ Import mappings (.xsl)
+
+
+ >
+ );
+};
diff --git a/packages/ui/src/components/DataMapper/debug/MainMenuToolbarItem.tsx b/packages/ui/src/components/DataMapper/debug/MainMenuToolbarItem.tsx
new file mode 100644
index 000000000..4f0757164
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/MainMenuToolbarItem.tsx
@@ -0,0 +1,27 @@
+import { FunctionComponent } from 'react';
+import { useToggle } from '../../../hooks/useToggle';
+import { Dropdown, DropdownList, MenuToggle, ToolbarItem } from '@patternfly/react-core';
+import { ExportMappingFileDropdownItem } from './ExportMappingFileDropdownItem';
+import { ImportMappingFileDropdownItem } from './ImportMappingFileDropdownItem';
+
+export const MainMenuToolbarItem: FunctionComponent = () => {
+ const { state: isOpen, toggle: onToggle, toggleOff } = useToggle(false);
+ return (
+
+ (
+
+ DataMapper
+
+ )}
+ isOpen={isOpen}
+ isPlain={true}
+ >
+
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/DataMapper/debug/README.md b/packages/ui/src/components/DataMapper/debug/README.md
new file mode 100644
index 000000000..94e76b66e
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/README.md
@@ -0,0 +1,7 @@
+### How to use
+
+#### In this directory
+`yarn vite .`
+
+#### Or from Kaoto `packages/ui` directory
+`yarn vite src/components/DataMapper/debug`
diff --git a/packages/ui/src/components/DataMapper/debug/ToggleDebugToolbarItem.tsx b/packages/ui/src/components/DataMapper/debug/ToggleDebugToolbarItem.tsx
new file mode 100644
index 000000000..4ae9b96d8
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/ToggleDebugToolbarItem.tsx
@@ -0,0 +1,23 @@
+import { FunctionComponent } from 'react';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { ToggleGroup, ToggleGroupItem, ToolbarItem } from '@patternfly/react-core';
+import { BugIcon } from '@patternfly/react-icons';
+
+export const ToggleDebugToolbarItem: FunctionComponent = () => {
+ const { debug, setDebug } = useDataMapper();
+
+ return (
+
+
+ }
+ aria-label="Enable debug mode"
+ buttonId="enable-debug-mode"
+ data-testid="enable-debug-mode-btn"
+ isSelected={debug}
+ onChange={() => setDebug(!debug)}
+ >
+
+
+ );
+};
diff --git a/packages/ui/src/components/DataMapper/debug/index.html b/packages/ui/src/components/DataMapper/debug/index.html
new file mode 100644
index 000000000..0c7f1cd4d
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+ DataMapper Debugger
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/DataMapper/debug/index.ts b/packages/ui/src/components/DataMapper/debug/index.ts
new file mode 100644
index 000000000..5c87e44e1
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/index.ts
@@ -0,0 +1 @@
+export * from './DataMapperDebugger';
diff --git a/packages/ui/src/components/DataMapper/debug/main.tsx b/packages/ui/src/components/DataMapper/debug/main.tsx
new file mode 100644
index 000000000..5d753db29
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/debug/main.tsx
@@ -0,0 +1,15 @@
+import '@patternfly/react-core/dist/styles/base.css'; // This import needs to be first
+import { createRoot } from 'react-dom/client';
+import { DataMapperDebugger } from './DataMapperDebugger';
+import { DocumentDefinition } from '../../../models/datamapper/document';
+
+const onUpdateMappings = (xsltFile: string) => {
+ console.log('onUpdateMappings() >>>>> ' + xsltFile);
+};
+const onUpdateDocument = (definition: DocumentDefinition) => {
+ console.log('onUpdateDocument() >>>>>', JSON.stringify(definition));
+};
+
+const container = document.getElementById('root');
+const root = createRoot(container!);
+root.render( );
diff --git a/packages/ui/src/components/DataMapper/on-delete-datamapper.ts b/packages/ui/src/components/DataMapper/on-delete-datamapper.ts
new file mode 100644
index 000000000..88d7d7e5b
--- /dev/null
+++ b/packages/ui/src/components/DataMapper/on-delete-datamapper.ts
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { DataMapperMetadataService } from '../../services/datamapper-metadata.service';
+import { IMetadataApi } from '../../providers';
+import { IVisualizationNode } from '../../models';
+
+export const ACTION_ID_DELETE_STEP_AND_FILE = 'del-step-and-file';
+export const ACTION_ID_DELETE_STEP_ONLY = 'del-step-only';
+
+export const onDeleteDataMapper = async (
+ api: IMetadataApi,
+ vizNode: IVisualizationNode,
+ modalAnswer: string | undefined,
+) => {
+ const metadataId = DataMapperMetadataService.getDataMapperMetadataId(vizNode);
+ if (modalAnswer === ACTION_ID_DELETE_STEP_AND_FILE) {
+ await DataMapperMetadataService.deleteXsltFile(api, metadataId);
+ }
+ await DataMapperMetadataService.deleteMetadata(api, metadataId);
+};
diff --git a/packages/ui/src/components/Document/Document.scss b/packages/ui/src/components/Document/Document.scss
new file mode 100644
index 000000000..120fd6c13
--- /dev/null
+++ b/packages/ui/src/components/Document/Document.scss
@@ -0,0 +1,95 @@
+@use '../../styles/dnd';
+
+.node {
+ &__row {
+ display: flex;
+ flex-flow: row nowrap;
+ align-items: center;
+
+ &[data-draggable='false'] [data-drag-handler] {
+ display: none;
+ }
+
+ &[data-draggable='true'] {
+ @include dnd.cursor-grab;
+ }
+ }
+
+ &__container {
+ padding: 5px;
+ padding-left: var(--pf-v5-global--spacer--md);
+ }
+
+ &__header,
+ &__children {
+ border-bottom: 1px solid var(--pf-v5-global--palette--black-300);
+ border-left: 1px solid var(--pf-v5-global--palette--black-300);
+ padding-left: var(--pf-v5-global--spacer--md);
+ }
+
+ &__children {
+ padding: var(--pf-v5-global--spacer--xs) var(--pf-v5-global--spacer--md);
+ }
+
+ &__spacer {
+ margin: var(--pf-v5-global--spacer--sm) 0 var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--sm);
+ }
+
+ &__target__actions {
+ flex-grow: 1;
+ justify-content: end;
+ }
+}
+
+img {
+ transition: transform 0.5s ease-in-out;
+}
+
+.toggle-icon {
+ cursor: pointer;
+
+ &--collapsed {
+ transform: rotate(-90deg);
+ }
+}
+
+.truncate {
+ --pf-v5-c-truncate--MinWidth: 0;
+}
+
+/* stylelint-disable-next-line selector-class-pattern */
+.pf-v5-c-action-list__group {
+ padding-left: 0.5rem;
+ padding-right: 0.5rem;
+
+ .pf-v5-c-button {
+ --pf-v5-c-button--PaddingLeft: 0.5rem;
+ --pf-v5-c-button--PaddingRight: 0.5rem;
+ }
+
+ .pf-v5-c-menu-toggle.pf-m-plain:not(.pf-m-text) {
+ --pf-v5-c-menu-toggle--PaddingLeft: 0.5rem;
+ --pf-v5-c-menu-toggle--PaddingRight: 0.5rem;
+ }
+}
+
+.parameter-card {
+ /* stylelint-disable-next-line selector-class-pattern */
+ .pf-v5-c-card__header {
+ padding-block: 0;
+ padding-inline: 0;
+ }
+}
+
+.parameter-actions {
+ padding-left: 0.5rem;
+ padding-right: 0.5rem;
+
+ --pf-v5-c-action-list--child--spacer-base: 0.5rem;
+ --pf-v5-c-action-list--group--spacer-base: 0.5rem;
+
+ .pf-v5-c-button {
+ --pf-v5-c-button--PaddingLeft: 0.5rem;
+ --pf-v5-c-button--PaddingRight: 0.5rem;
+ }
+}
diff --git a/packages/ui/src/components/Document/NodeContainer.scss b/packages/ui/src/components/Document/NodeContainer.scss
new file mode 100644
index 000000000..93bd17fe9
--- /dev/null
+++ b/packages/ui/src/components/Document/NodeContainer.scss
@@ -0,0 +1,20 @@
+@use '../../styles/dnd';
+
+.droppable-container {
+ color: var(--pf-v5-global--primary-color--200);
+ border-width: thin;
+ border-style: dashed;
+ border-color: var(--pf-v5-global--primary-color--200);
+ background-color: var(--pf-v5-global--palette--blue-50);
+}
+
+.draggable-container {
+ font-weight: bold;
+ color: var(--pf-v5-global--primary-color--100);
+ border-width: thin;
+ border-style: solid;
+ border-color: var(--pf-v5-global--primary-color--200);
+ background-color: var(--pf-v5-global--palette--black-200);
+
+ @include dnd.cursor-grab;
+}
diff --git a/packages/ui/src/components/Document/NodeContainer.tsx b/packages/ui/src/components/Document/NodeContainer.tsx
new file mode 100644
index 000000000..2ebed9fdd
--- /dev/null
+++ b/packages/ui/src/components/Document/NodeContainer.tsx
@@ -0,0 +1,83 @@
+import { useDraggable, useDroppable } from '@dnd-kit/core';
+import clsx from 'clsx';
+import { forwardRef, FunctionComponent, PropsWithChildren } from 'react';
+import { DocumentNodeData, NodeData } from '../../models/datamapper/visualization';
+import { isDefined } from '../../utils';
+import './NodeContainer.scss';
+import { VisualizationService } from '../../services/visualization.service';
+
+type DnDContainerProps = PropsWithChildren & {
+ nodeData: NodeData;
+};
+
+type BaseContainerProps = PropsWithChildren & {
+ className?: string;
+ id: string;
+ nodeData: NodeData;
+};
+
+export const DroppableContainer: FunctionComponent = ({ className, id, nodeData, children }) => {
+ const { isOver, setNodeRef: setDroppableNodeRef } = useDroppable({
+ id: `droppable-${id}`,
+ data: nodeData,
+ });
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const DraggableContainer: FunctionComponent = ({ id, nodeData, children }) => {
+ const {
+ attributes,
+ listeners,
+ setNodeRef: setDraggableNodeRef,
+ transform,
+ } = useDraggable({
+ id: `draggable-${id}`,
+ data: nodeData,
+ });
+
+ return (
+
+ {children}
+
+ );
+};
+
+const DnDContainer: FunctionComponent = ({ nodeData, children }) => {
+ const dndId = VisualizationService.generateDndId(nodeData);
+ return (
+
+
+ {children}
+
+
+ );
+};
+
+type NodeContainerProps = PropsWithChildren & {
+ nodeData?: NodeData;
+};
+
+export const NodeContainer = forwardRef(({ children, nodeData }, forwardedRef) => {
+ return nodeData && !(nodeData instanceof DocumentNodeData && !nodeData.isPrimitive) ? (
+
+ {children}
+
+ ) : (
+ {children}
+ );
+});
diff --git a/packages/ui/src/components/Document/NodeTitle.tsx b/packages/ui/src/components/Document/NodeTitle.tsx
new file mode 100644
index 000000000..3a3cc1fbf
--- /dev/null
+++ b/packages/ui/src/components/Document/NodeTitle.tsx
@@ -0,0 +1,31 @@
+import { Label, Title, Truncate } from '@patternfly/react-core';
+import clsx from 'clsx';
+import { FunctionComponent } from 'react';
+import { MappingNodeData, NodeData } from '../../models/datamapper/visualization';
+import './Document.scss';
+
+interface INodeTitle {
+ className?: string;
+ nodeData: NodeData;
+ isDocument: boolean;
+}
+
+export const NodeTitle: FunctionComponent = ({ className, nodeData, isDocument }) => {
+ if (nodeData instanceof MappingNodeData) {
+ return (
+
+
+
+ );
+ }
+
+ if (isDocument) {
+ return (
+
+
+
+ );
+ }
+
+ return ;
+};
diff --git a/packages/ui/src/components/Document/Parameters.test.tsx b/packages/ui/src/components/Document/Parameters.test.tsx
new file mode 100644
index 000000000..7649beff5
--- /dev/null
+++ b/packages/ui/src/components/Document/Parameters.test.tsx
@@ -0,0 +1,143 @@
+import { Parameters } from './Parameters';
+import { DataMapperProvider } from '../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../providers/datamapper-canvas.provider';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { shipOrderXsd } from '../../stubs/data-mapper';
+import { BrowserFilePickerMetadataProvider } from '../../stubs/BrowserFilePickerMetadataProvider';
+
+describe('Parameters', () => {
+ it('should add and remove a parameter', async () => {
+ const mockUpdateDocument = jest.fn();
+ const mockDeleteParameter = jest.fn();
+ render(
+
+
+
+
+
+
+ ,
+ );
+ expect(mockUpdateDocument.mock.calls.length).toEqual(0);
+ expect(mockDeleteParameter.mock.calls.length).toEqual(0);
+ const addButton = await screen.findByTestId('add-parameter-button');
+ act(() => {
+ fireEvent.click(addButton);
+ });
+ const paramNameInput = screen.getByTestId('add-new-parameter-name-input');
+ act(() => {
+ fireEvent.change(paramNameInput, { target: { value: 'testparam1' } });
+ });
+ const submitButton = screen.getByTestId('add-new-parameter-submit-btn');
+ act(() => {
+ fireEvent.click(submitButton);
+ });
+ expect(mockUpdateDocument.mock.calls.length).toEqual(1);
+ expect(mockDeleteParameter.mock.calls.length).toEqual(0);
+ expect(mockUpdateDocument.mock.calls[0][0]['name']).toEqual('testparam1');
+ const deleteButton = screen.getByTestId('delete-parameter-testparam1-button');
+ act(() => {
+ fireEvent.click(deleteButton);
+ });
+ const confirmButton = screen.getByTestId('delete-parameter-modal-confirm-btn');
+ act(() => {
+ fireEvent.click(confirmButton);
+ });
+ expect(mockUpdateDocument.mock.calls.length).toEqual(1);
+ expect(mockDeleteParameter.mock.calls.length).toEqual(1);
+ expect(mockDeleteParameter.mock.calls[0][0]).toEqual('testparam1');
+ await screen.findByTestId('add-parameter-button');
+ const notexist = screen.queryByTestId('delete-parameter-testparam1-button');
+ expect(notexist).toBeFalsy();
+ });
+
+ it('should show validation error for invalid parameter name', async () => {
+ const mockUpdateDocument = jest.fn();
+ const mockDeleteParameter = jest.fn();
+ render(
+
+
+
+
+
+
+ ,
+ );
+ expect(mockUpdateDocument.mock.calls.length).toEqual(0);
+ expect(mockDeleteParameter.mock.calls.length).toEqual(0);
+ const addButton = await screen.findByTestId('add-parameter-button');
+ act(() => {
+ fireEvent.click(addButton);
+ });
+ let paramNameInput = screen.getByTestId('add-new-parameter-name-input');
+ act(() => {
+ fireEvent.change(paramNameInput, { target: { value: 'testparam1::' } });
+ });
+ expect(screen.getByTestId('new-parameter-helper-text-invalid')).toBeInTheDocument();
+ let submitButton = screen.getByTestId('add-new-parameter-submit-btn') as HTMLButtonElement;
+ expect(submitButton.disabled).toBeTruthy();
+ act(() => {
+ fireEvent.change(paramNameInput, { target: { value: 'testparam1' } });
+ });
+ expect(submitButton.disabled).toBeFalsy();
+ act(() => {
+ fireEvent.click(submitButton);
+ });
+ act(() => {
+ fireEvent.click(addButton);
+ });
+ paramNameInput = screen.getByTestId('add-new-parameter-name-input');
+ act(() => {
+ fireEvent.change(paramNameInput, { target: { value: 'testparam1' } });
+ });
+ expect(screen.getByTestId('new-parameter-helper-text-duplicate')).toBeInTheDocument();
+ submitButton = screen.getByTestId('add-new-parameter-submit-btn') as HTMLButtonElement;
+ expect(submitButton.disabled).toBeTruthy();
+ });
+
+ it('should attach and detach a schema', async () => {
+ render(
+
+
+
+
+
+
+ ,
+ );
+ const addButton = await screen.findByTestId('add-parameter-button');
+ act(() => {
+ fireEvent.click(addButton);
+ });
+ const paramNameInput = screen.getByTestId('add-new-parameter-name-input');
+ act(() => {
+ fireEvent.change(paramNameInput, { target: { value: 'testparam1' } });
+ });
+ const submitButton = screen.getByTestId('add-new-parameter-submit-btn');
+ act(() => {
+ fireEvent.click(submitButton);
+ });
+ const attachButton = screen.getByTestId('attach-schema-param-testparam1-button');
+ const fileContent = new File([new Blob([shipOrderXsd])], 'ShipOrder.xsd', { type: 'text/plain' });
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileInput = screen.getByTestId('attach-schema-file-input');
+ act(() => {
+ fireEvent.change(fileInput, { target: { files: { item: () => fileContent, length: 1, 0: fileContent } } });
+ });
+ const shipTo = await screen.findByText('ShipTo');
+ expect(shipTo).toBeTruthy();
+
+ const detachButton = screen.getByTestId('detach-schema-param-testparam1-button');
+ act(() => {
+ fireEvent.click(detachButton);
+ });
+ const detachConfirmButton = screen.getByTestId('detach-schema-modal-confirm-btn');
+ act(() => {
+ fireEvent.click(detachConfirmButton);
+ });
+ await screen.findByTestId('add-parameter-button');
+ expect(screen.queryByTestId('ShipTo')).toBeFalsy();
+ });
+});
diff --git a/packages/ui/src/components/Document/Parameters.tsx b/packages/ui/src/components/Document/Parameters.tsx
new file mode 100644
index 000000000..b596dcc10
--- /dev/null
+++ b/packages/ui/src/components/Document/Parameters.tsx
@@ -0,0 +1,231 @@
+import {
+ ActionList,
+ ActionListGroup,
+ ActionListItem,
+ Button,
+ Card,
+ CardBody,
+ CardExpandableContent,
+ CardHeader,
+ CardTitle,
+ HelperText,
+ HelperTextItem,
+ Stack,
+ StackItem,
+ TextInput,
+} from '@patternfly/react-core';
+import { CheckIcon, PlusIcon, TimesIcon } from '@patternfly/react-icons';
+import { FunctionComponent, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
+import { qname } from 'xml-name-validator';
+import { useCanvas } from '../../hooks/useCanvas';
+import { useDataMapper } from '../../hooks/useDataMapper';
+import { useToggle } from '../../hooks/useToggle';
+import { DocumentDefinition, DocumentDefinitionType } from '../../models/datamapper/document';
+import { DocumentType } from '../../models/datamapper/path';
+import { NodeReference } from '../../providers/datamapper-canvas.provider';
+import './Document.scss';
+import { NodeContainer } from './NodeContainer';
+import { SourceDocument } from './SourceDocument';
+
+enum ParameterNameValidation {
+ EMPTY,
+ OK,
+ DUPLICATE,
+ INVALID,
+}
+
+type AddNewParameterPlaceholderProps = {
+ onComplete: () => void;
+};
+
+const AddNewParameterPlaceholder: FunctionComponent = ({ onComplete }) => {
+ const { sourceParameterMap, updateDocumentDefinition } = useDataMapper();
+ const [newParameterName, setNewParameterName] = useState('');
+
+ const submitNewParameter = useCallback(() => {
+ if (!sourceParameterMap.has(newParameterName)) {
+ const definition = new DocumentDefinition(DocumentType.PARAM, DocumentDefinitionType.Primitive, newParameterName);
+ updateDocumentDefinition(definition);
+ }
+ setNewParameterName('');
+ onComplete();
+ }, [sourceParameterMap, newParameterName, onComplete, updateDocumentDefinition]);
+
+ const cancelNewParameter = useCallback(() => {
+ setNewParameterName('');
+ onComplete();
+ }, [onComplete]);
+
+ const newParameterNameValidation: ParameterNameValidation = useMemo(() => {
+ if (newParameterName === '') return ParameterNameValidation.EMPTY;
+ if (sourceParameterMap.has(newParameterName)) return ParameterNameValidation.DUPLICATE;
+ if (!qname(newParameterName)) return ParameterNameValidation.INVALID;
+ return ParameterNameValidation.OK;
+ }, [newParameterName, sourceParameterMap]);
+
+ const textInputValidatedProp = useMemo(() => {
+ switch (newParameterNameValidation) {
+ case ParameterNameValidation.OK:
+ return 'success';
+ case ParameterNameValidation.EMPTY:
+ return 'default';
+ case ParameterNameValidation.DUPLICATE:
+ case ParameterNameValidation.INVALID:
+ return 'error';
+ }
+ }, [newParameterNameValidation]);
+
+ const inputRef = useRef(null);
+
+ useEffect(() => {
+ inputRef.current?.focus();
+ }, []);
+
+ return (
+
+
+
+ setNewParameterName(text)}
+ placeholder="parameter name"
+ validated={textInputValidatedProp}
+ />
+
+ {newParameterNameValidation === ParameterNameValidation.DUPLICATE && (
+
+ Parameter '{newParameterName}' already exists
+
+ )}
+ {newParameterNameValidation === ParameterNameValidation.INVALID && (
+
+ Invalid parameter name '{newParameterName}': it must be a valid QName
+
+ )}
+
+
+
+
+
+ submitNewParameter()}
+ variant="link"
+ isDisabled={newParameterNameValidation !== ParameterNameValidation.OK}
+ id="add-new-parameter-submit-btn"
+ data-testid="add-new-parameter-submit-btn"
+ aria-label="Submit new parameter"
+ >
+
+
+
+
+ cancelNewParameter()}
+ variant="plain"
+ id="add-new-parameter-cancel-btn"
+ data-testid="add-new-parameter-cancel-btn"
+ aria-label={'Cancel new parameter'}
+ >
+
+
+
+
+
+ );
+};
+
+type ParametersProps = {
+ isReadOnly: boolean;
+};
+
+export const Parameters: FunctionComponent = ({ isReadOnly }) => {
+ const { sourceParameterMap, isSourceParametersExpanded, setSourceParametersExpanded } = useDataMapper();
+ const { reloadNodeReferences } = useCanvas();
+ const {
+ state: isAddingNewParameter,
+ toggleOff: toggleOffAddNewParameter,
+ toggleOn: toggleOnAddNewParameter,
+ } = useToggle(false);
+
+ const { getNodeReference, setNodeReference } = useCanvas();
+ const nodeReference = useRef({ headerRef: null, containerRef: null });
+ const headerRef = useRef(null);
+ useImperativeHandle(nodeReference, () => ({
+ get headerRef() {
+ return headerRef.current;
+ },
+ get containerRef() {
+ return headerRef.current;
+ },
+ }));
+ const nodeRefId = 'param';
+ getNodeReference(nodeRefId) !== nodeReference && setNodeReference(nodeRefId, nodeReference);
+
+ const handleAddNewParameter = useCallback(() => {
+ setSourceParametersExpanded(true);
+ toggleOnAddNewParameter();
+ }, [setSourceParametersExpanded, toggleOnAddNewParameter]);
+
+ const handleOnExpand = useCallback(() => {
+ setSourceParametersExpanded(!isSourceParametersExpanded);
+ reloadNodeReferences();
+ }, [isSourceParametersExpanded, reloadNodeReferences, setSourceParametersExpanded]);
+
+ const parametersHeaderActions = useMemo(() => {
+ return (
+
+ {!isReadOnly && (
+
+ handleAddNewParameter()}
+ >
+
+
+
+ )}
+
+ );
+ }, [handleAddNewParameter, isReadOnly]);
+
+ return (
+
+
+
+ Parameters
+
+
+
+
+
+ {isAddingNewParameter && (
+
+ toggleOffAddNewParameter()} />
+
+ )}
+ {Array.from(sourceParameterMap.entries()).map(([documentId, doc]) => (
+
+
+
+ ))}
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/Document/SourceDocument.test.tsx b/packages/ui/src/components/Document/SourceDocument.test.tsx
new file mode 100644
index 000000000..0f4649a58
--- /dev/null
+++ b/packages/ui/src/components/Document/SourceDocument.test.tsx
@@ -0,0 +1,50 @@
+import { SourceDocument } from './SourceDocument';
+import { render, screen, waitFor } from '@testing-library/react';
+import { DataMapperProvider } from '../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../providers/datamapper-canvas.provider';
+import { BODY_DOCUMENT_ID, PrimitiveDocument } from '../../models/datamapper/document';
+import { DocumentType } from '../../models/datamapper/path';
+import { TestUtil } from '../../stubs/data-mapper';
+
+describe('SourceDocument', () => {
+ it('should render primitive document', async () => {
+ const document = new PrimitiveDocument(DocumentType.SOURCE_BODY, BODY_DOCUMENT_ID);
+ render(
+
+
+
+
+ ,
+ );
+ expect(await screen.findByText('Body')).toBeTruthy();
+ });
+
+ it('should render ShipOrder doc', async () => {
+ const document = TestUtil.createSourceOrderDoc();
+ render(
+
+
+
+
+ ,
+ );
+ expect(await screen.findByText('OrderPerson')).toBeTruthy();
+ expect(await screen.findByText('Country')).toBeInTheDocument();
+ });
+
+ it('should render camel-spring.xsd doc till 2nd level', async () => {
+ const document = TestUtil.createCamelSpringXsdSourceDoc();
+ render(
+
+
+
+
+ ,
+ );
+ await waitFor(async () => {
+ const aggregates = await screen.findAllByText('aggregate');
+ expect(aggregates.length).toEqual(2);
+ });
+ expect(await screen.findByText('correlationExpression')).toBeTruthy();
+ }, 10000);
+});
diff --git a/packages/ui/src/components/Document/SourceDocument.tsx b/packages/ui/src/components/Document/SourceDocument.tsx
new file mode 100644
index 000000000..9244a451f
--- /dev/null
+++ b/packages/ui/src/components/Document/SourceDocument.tsx
@@ -0,0 +1,133 @@
+import { Icon } from '@patternfly/react-core';
+import { AngleDownIcon, AtIcon, GripVerticalIcon, LayerGroupIcon } from '@patternfly/react-icons';
+import clsx from 'clsx';
+import { FunctionComponent, useCallback, useRef, useState } from 'react';
+import { useCanvas } from '../../hooks/useCanvas';
+import { useDataMapper } from '../../hooks/useDataMapper';
+import { IDocument } from '../../models/datamapper/document';
+import { DocumentNodeData, NodeData } from '../../models/datamapper/visualization';
+import { NodeReference } from '../../providers/datamapper-canvas.provider';
+import { VisualizationService } from '../../services/visualization.service';
+import { DocumentActions } from './actions/DocumentActions';
+import './Document.scss';
+import { NodeContainer } from './NodeContainer';
+import { NodeTitle } from './NodeTitle';
+
+type DocumentProps = {
+ document: IDocument;
+ isReadOnly: boolean;
+};
+
+export const SourceDocument: FunctionComponent = ({ document, isReadOnly }) => {
+ const { initialExpandedFieldRank, maxTotalFieldCountToExpandAll } = useDataMapper();
+ const nodeData = new DocumentNodeData(document);
+ return (
+
+ );
+};
+
+type DocumentNodeProps = {
+ nodeData: NodeData;
+ isReadOnly: boolean;
+ expandAll: boolean;
+ initialExpandedRank: number;
+ rank: number;
+};
+
+export const SourceDocumentNode: FunctionComponent = ({
+ nodeData,
+ isReadOnly,
+ expandAll,
+ initialExpandedRank,
+ rank,
+}) => {
+ const { getNodeReference, reloadNodeReferences, setNodeReference } = useCanvas();
+ const shouldCollapseByDefault =
+ !expandAll && VisualizationService.shouldCollapseByDefault(nodeData, initialExpandedRank, rank);
+ const [collapsed, setCollapsed] = useState(shouldCollapseByDefault);
+
+ const onClick = useCallback(() => {
+ setCollapsed(!collapsed);
+ reloadNodeReferences();
+ }, [collapsed, reloadNodeReferences]);
+
+ const isDocument = nodeData instanceof DocumentNodeData;
+ const hasChildren = VisualizationService.hasChildren(nodeData);
+ const children = collapsed ? [] : VisualizationService.generateNodeDataChildren(nodeData);
+ const isCollectionField = VisualizationService.isCollectionField(nodeData);
+ const isAttributeField = VisualizationService.isAttributeField(nodeData);
+ const isDraggable = !isDocument || VisualizationService.isPrimitiveDocumentNode(nodeData);
+ const headerRef = useRef(null);
+ const containerRef = useRef(null);
+ const nodeReference = useRef({
+ get headerRef() {
+ return headerRef.current;
+ },
+ get containerRef() {
+ return containerRef.current;
+ },
+ });
+ const nodeRefId = nodeData.path.toString();
+ getNodeReference(nodeRefId) !== nodeReference && setNodeReference(nodeRefId, nodeReference);
+
+ return (
+
+
+
+
+
+ {hasChildren && (
+
+ )}
+
+
+
+
+
+ {isCollectionField && (
+
+
+
+ )}
+
+ {isAttributeField && (
+
+
+
+ )}
+
+
+
+ {!isReadOnly && isDocument ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {hasChildren && !collapsed && (
+
+ {children.map((child) => (
+
+ ))}
+
+ )}
+
+
+ );
+};
diff --git a/packages/ui/src/components/Document/TargetDocument.tsx b/packages/ui/src/components/Document/TargetDocument.tsx
new file mode 100644
index 000000000..ea2d9fd7f
--- /dev/null
+++ b/packages/ui/src/components/Document/TargetDocument.tsx
@@ -0,0 +1,144 @@
+import { Icon } from '@patternfly/react-core';
+import { AngleDownIcon, AtIcon, GripVerticalIcon, LayerGroupIcon } from '@patternfly/react-icons';
+import clsx from 'clsx';
+import { FunctionComponent, useCallback, useRef, useState } from 'react';
+import { useCanvas } from '../../hooks/useCanvas';
+import { useDataMapper } from '../../hooks/useDataMapper';
+import { IDocument } from '../../models/datamapper/document';
+import { TargetDocumentNodeData, TargetNodeData } from '../../models/datamapper/visualization';
+import { NodeReference } from '../../providers/datamapper-canvas.provider';
+import { VisualizationService } from '../../services/visualization.service';
+import { DocumentActions } from './actions/DocumentActions';
+import { TargetNodeActions } from './actions/TargetNodeActions';
+import './Document.scss';
+import { NodeContainer } from './NodeContainer';
+import { NodeTitle } from './NodeTitle';
+
+type DocumentProps = {
+ document: IDocument;
+};
+
+export const TargetDocument: FunctionComponent = ({ document }) => {
+ const { initialExpandedFieldRank, mappingTree, maxTotalFieldCountToExpandAll } = useDataMapper();
+ const nodeData = new TargetDocumentNodeData(document, mappingTree);
+
+ return (
+
+ );
+};
+
+type DocumentNodeProps = {
+ nodeData: TargetNodeData;
+ expandAll: boolean;
+ initialExpandedRank: number;
+ rank: number;
+};
+
+const TargetDocumentNode: FunctionComponent = ({
+ nodeData,
+ expandAll,
+ initialExpandedRank,
+ rank,
+}) => {
+ const { getNodeReference, reloadNodeReferences, setNodeReference } = useCanvas();
+ const shouldCollapseByDefault =
+ !expandAll && VisualizationService.shouldCollapseByDefault(nodeData, initialExpandedRank, rank);
+ const [collapsed, setCollapsed] = useState(shouldCollapseByDefault);
+
+ const isDocument = VisualizationService.isDocumentNode(nodeData);
+ const isPrimitive = VisualizationService.isPrimitiveDocumentNode(nodeData);
+ const hasChildren = VisualizationService.hasChildren(nodeData);
+
+ const onClick = useCallback(() => {
+ if (!hasChildren) return;
+
+ setCollapsed(!collapsed);
+ reloadNodeReferences();
+ }, [collapsed, hasChildren, reloadNodeReferences]);
+
+ const children = VisualizationService.generateNodeDataChildren(nodeData) as TargetNodeData[];
+ const isCollectionField = VisualizationService.isCollectionField(nodeData);
+ const isAttributeField = VisualizationService.isAttributeField(nodeData);
+ const isDraggable = !isDocument || VisualizationService.isPrimitiveDocumentNode(nodeData);
+ const headerRef = useRef(null);
+ const containerRef = useRef(null);
+ const nodeReference = useRef({
+ get headerRef() {
+ return headerRef.current;
+ },
+ get containerRef() {
+ return containerRef.current;
+ },
+ });
+ const nodeRefId = nodeData.path.toString();
+ getNodeReference(nodeRefId) !== nodeReference && setNodeReference(nodeRefId, nodeReference);
+
+ const showNodeActions = (isDocument && isPrimitive) || !isDocument;
+ const { refreshMappingTree } = useDataMapper();
+ const handleUpdate = useCallback(() => {
+ refreshMappingTree();
+ }, [refreshMappingTree]);
+
+ return (
+
+
+
+
+
+
+ {hasChildren && (
+
+ )}
+
+
+
+
+
+ {isCollectionField && (
+
+
+
+ )}
+
+ {isAttributeField && (
+
+
+
+ )}
+
+
+
+
+ {showNodeActions ? (
+
+ ) : (
+
+ )}
+
+ {isDocument && }
+
+
+
+
+ {hasChildren && !collapsed && (
+
+ {children.map((child) => (
+
+ ))}
+
+ )}
+
+
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/AttachSchemaButton.test.tsx b/packages/ui/src/components/Document/actions/AttachSchemaButton.test.tsx
new file mode 100644
index 000000000..83e703e10
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/AttachSchemaButton.test.tsx
@@ -0,0 +1,130 @@
+import { AttachSchemaButton } from './AttachSchemaButton';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { DocumentType } from '../../../models/datamapper/path';
+import { BODY_DOCUMENT_ID } from '../../../models/datamapper/document';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { readFileAsString } from '../../../stubs/read-file-as-string';
+
+import { noTopElementXsd, shipOrderEmptyFirstLineXsd, shipOrderXsd } from '../../../stubs/data-mapper';
+import { BrowserFilePickerMetadataProvider } from '../../../stubs/BrowserFilePickerMetadataProvider';
+import { FunctionComponent, PropsWithChildren, useEffect } from 'react';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { AlertProps } from '@patternfly/react-core';
+
+jest.mock('../../../stubs/read-file-as-string');
+const mockReadFileAsString = readFileAsString as jest.MockedFunction;
+
+describe('AttachSchemaButton', () => {
+ afterAll(() => {
+ mockReadFileAsString.mockReset();
+ });
+
+ it('should invoke onClick()', async () => {
+ const spyOnClick = jest.spyOn(HTMLInputElement.prototype, 'click');
+ render(
+
+
+
+
+
+
+ ,
+ );
+ const attachButton = await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ expect(spyOnClick.mock.calls.length).toEqual(0);
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ expect(spyOnClick.mock.calls.length).toBeGreaterThan(0);
+ });
+
+ it('should invoke onImport()', async () => {
+ mockReadFileAsString.mockResolvedValue(shipOrderXsd);
+ render(
+
+
+
+
+
+
+ ,
+ );
+ const attachButton = await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileInput = await screen.findByTestId('attach-schema-file-input');
+ const fileContent = new File([new Blob([shipOrderXsd])], 'ShipOrder.xsd', { type: 'text/plain' });
+ act(() => {
+ fireEvent.change(fileInput, { target: { files: { item: () => fileContent, length: 1, 0: fileContent } } });
+ });
+ await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ expect(mockReadFileAsString.mock.calls.length).toEqual(1);
+ });
+
+ let capturedAlerts: Partial[] = [];
+ const TestAlertCapture: FunctionComponent = ({ children }) => {
+ const { alerts } = useDataMapper();
+ useEffect(() => {
+ capturedAlerts = alerts;
+ }, [alerts]);
+ return <>{children}>;
+ };
+
+ it('should show a toast alert for invalid schema', async () => {
+ mockReadFileAsString.mockResolvedValue(noTopElementXsd);
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+ const attachButton = await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileInput = await screen.findByTestId('attach-schema-file-input');
+ const fileContent = new File([new Blob([noTopElementXsd])], 'NoTopElement.xsd', { type: 'text/plain' });
+ act(() => {
+ fireEvent.change(fileInput, { target: { files: { item: () => fileContent, length: 1, 0: fileContent } } });
+ });
+ await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ expect(capturedAlerts.length).toEqual(1);
+ expect(capturedAlerts[0].title).toContain('no top level Element');
+ });
+
+ it('should show a toast alert for XML parse error', async () => {
+ mockReadFileAsString.mockResolvedValue(shipOrderEmptyFirstLineXsd);
+ render(
+
+
+
+
+
+
+
+
+ ,
+ );
+ const attachButton = await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileInput = await screen.findByTestId('attach-schema-file-input');
+ const fileContent = new File([new Blob([shipOrderEmptyFirstLineXsd])], 'ShipOrderEmptyFirstLine.xsd', {
+ type: 'text/plain',
+ });
+ act(() => {
+ fireEvent.change(fileInput, { target: { files: { item: () => fileContent, length: 1, 0: fileContent } } });
+ });
+ await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ expect(capturedAlerts.length).toEqual(1);
+ expect(capturedAlerts[0].title).toContain('an XML declaration must be at the start of the document');
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/AttachSchemaButton.tsx b/packages/ui/src/components/Document/actions/AttachSchemaButton.tsx
new file mode 100644
index 000000000..e414e4eaf
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/AttachSchemaButton.tsx
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { AlertVariant, Button } from '@patternfly/react-core';
+import { FunctionComponent, useCallback, useContext } from 'react';
+
+import { ImportIcon } from '@patternfly/react-icons';
+import { useCanvas } from '../../../hooks/useCanvas';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { DocumentDefinitionType } from '../../../models/datamapper/document';
+import { DocumentType } from '../../../models/datamapper/path';
+import { MetadataContext } from '../../../providers';
+import { DataMapperMetadataService } from '../../../services/datamapper-metadata.service';
+import { DocumentService } from '../../../services/document.service';
+
+type AttachSchemaProps = {
+ documentType: DocumentType;
+ documentId: string;
+ hasSchema?: boolean;
+};
+
+export const AttachSchemaButton: FunctionComponent = ({
+ documentType,
+ documentId,
+ hasSchema = false,
+}) => {
+ const api = useContext(MetadataContext)!;
+ const { addAlert, setIsLoading, updateDocumentDefinition } = useDataMapper();
+ const { clearNodeReferencesForDocument, reloadNodeReferences } = useCanvas();
+
+ const onClick = useCallback(async () => {
+ const paths = await DataMapperMetadataService.selectDocumentSchema(api);
+ if (!paths || (Array.isArray(paths) && paths.length === 0)) return;
+ setIsLoading(true);
+ try {
+ const definition = await DocumentService.createDocumentDefinition(
+ api,
+ documentType,
+ DocumentDefinitionType.XML_SCHEMA,
+ documentId,
+ Array.isArray(paths) ? paths : [paths],
+ );
+ if (!definition) return;
+ await updateDocumentDefinition(definition);
+ clearNodeReferencesForDocument(documentType, documentId);
+ reloadNodeReferences();
+ /* eslint-disable @typescript-eslint/no-explicit-any */
+ } catch (error: any) {
+ const cause = error['message'] ? ': ' + error['message'] : '';
+ addAlert({ variant: AlertVariant.danger, title: `Cannot read the schema file ${cause}` });
+ } finally {
+ setIsLoading(false);
+ }
+ }, [
+ addAlert,
+ api,
+ clearNodeReferencesForDocument,
+ documentId,
+ documentType,
+ reloadNodeReferences,
+ setIsLoading,
+ updateDocumentDefinition,
+ ]);
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/ConditionMenuAction.test.tsx b/packages/ui/src/components/Document/actions/ConditionMenuAction.test.tsx
new file mode 100644
index 000000000..869baec08
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/ConditionMenuAction.test.tsx
@@ -0,0 +1,182 @@
+import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
+import { BODY_DOCUMENT_ID } from '../../../models/datamapper/document';
+import { ChooseItem, FieldItem, MappingTree } from '../../../models/datamapper/mapping';
+import { DocumentType } from '../../../models/datamapper/path';
+import { MappingNodeData, TargetDocumentNodeData, TargetFieldNodeData } from '../../../models/datamapper/visualization';
+import { MappingService } from '../../../services/mapping.service';
+import { VisualizationService } from '../../../services/visualization.service';
+import { TestUtil } from '../../../stubs/data-mapper';
+import { ConditionMenuAction } from './ConditionMenuAction';
+
+describe('ConditionMenuAction', () => {
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ const mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ const documentNodeData = new TargetDocumentNodeData(targetDoc, mappingTree);
+
+ it('should apply ValueSelector', () => {
+ const nodeData = new TargetFieldNodeData(
+ documentNodeData,
+ targetDoc.fields[0],
+ new FieldItem(mappingTree, targetDoc.fields[0]),
+ );
+ const onUpdateMock = jest.fn();
+ const spyOnApply = jest.spyOn(VisualizationService, 'applyValueSelector');
+ render( );
+ const actionToggle = screen.getByTestId('transformation-actions-menu-toggle');
+ act(() => {
+ fireEvent.click(actionToggle);
+ });
+ const selectorItem = screen.getByTestId('transformation-actions-selector');
+ act(() => {
+ fireEvent.click(selectorItem.getElementsByTagName('button')[0]);
+ });
+ waitFor(() => screen.getByTestId('transformation-actions-menu-toggle').getAttribute('aria-expanded') === 'false');
+ expect(onUpdateMock.mock.calls.length).toEqual(1);
+ expect(spyOnApply.mock.calls.length).toEqual(1);
+ });
+
+ it('should apply If', () => {
+ const nodeData = new TargetFieldNodeData(
+ documentNodeData,
+ targetDoc.fields[0],
+ new FieldItem(mappingTree, targetDoc.fields[0]),
+ );
+ const onUpdateMock = jest.fn();
+ const spyOnApply = jest.spyOn(VisualizationService, 'applyIf');
+ render( );
+ const actionToggle = screen.getByTestId('transformation-actions-menu-toggle');
+ act(() => {
+ fireEvent.click(actionToggle);
+ });
+ const ifItem = screen.getByTestId('transformation-actions-if');
+ act(() => {
+ fireEvent.click(ifItem.getElementsByTagName('button')[0]);
+ });
+ waitFor(() => screen.getByTestId('transformation-actions-menu-toggle').getAttribute('aria-expanded') === 'false');
+ expect(onUpdateMock.mock.calls.length).toEqual(1);
+ expect(spyOnApply.mock.calls.length).toEqual(1);
+ });
+
+ it('should apply choose', () => {
+ const nodeData = new TargetFieldNodeData(
+ documentNodeData,
+ targetDoc.fields[0],
+ new FieldItem(mappingTree, targetDoc.fields[0]),
+ );
+ const onUpdateMock = jest.fn();
+ const spyOnApply = jest.spyOn(VisualizationService, 'applyChooseWhenOtherwise');
+ render( );
+ const actionToggle = screen.getByTestId('transformation-actions-menu-toggle');
+ act(() => {
+ fireEvent.click(actionToggle);
+ });
+ const chooseItem = screen.getByTestId('transformation-actions-choose');
+ act(() => {
+ fireEvent.click(chooseItem.getElementsByTagName('button')[0]);
+ });
+ waitFor(() => screen.getByTestId('transformation-actions-menu-toggle').getAttribute('aria-expanded') === 'false');
+ expect(onUpdateMock.mock.calls.length).toEqual(1);
+ expect(spyOnApply.mock.calls.length).toEqual(1);
+ });
+
+ it('should apply when', () => {
+ const nodeData = new MappingNodeData(documentNodeData, new ChooseItem(mappingTree, targetDoc.fields[0]));
+ const onUpdateMock = jest.fn();
+ const spyOnApply = jest.spyOn(MappingService, 'addWhen');
+ render( );
+ const actionToggle = screen.getByTestId('transformation-actions-menu-toggle');
+ act(() => {
+ fireEvent.click(actionToggle);
+ });
+ const whenItem = screen.getByTestId('transformation-actions-when');
+ act(() => {
+ fireEvent.click(whenItem.getElementsByTagName('button')[0]);
+ });
+ waitFor(() => screen.getByTestId('transformation-actions-menu-toggle').getAttribute('aria-expanded') === 'false');
+
+ expect(onUpdateMock.mock.calls.length).toEqual(1);
+ expect(spyOnApply.mock.calls.length).toEqual(1);
+ });
+
+ it('should apply otherwise', () => {
+ const nodeData = new MappingNodeData(documentNodeData, new ChooseItem(mappingTree, targetDoc.fields[0]));
+ const onUpdateMock = jest.fn();
+ const spyOnApply = jest.spyOn(MappingService, 'addOtherwise');
+ render( );
+ const actionToggle = screen.getByTestId('transformation-actions-menu-toggle');
+ act(() => {
+ fireEvent.click(actionToggle);
+ });
+ const otherwiseItem = screen.getByTestId('transformation-actions-otherwise');
+ act(() => {
+ fireEvent.click(otherwiseItem.getElementsByTagName('button')[0]);
+ });
+ waitFor(() => screen.getByTestId('transformation-actions-menu-toggle').getAttribute('aria-expanded') === 'false');
+
+ expect(onUpdateMock.mock.calls.length).toEqual(1);
+ expect(spyOnApply.mock.calls.length).toEqual(1);
+ });
+
+ it('should apply for-each', () => {
+ const nodeData = new TargetFieldNodeData(
+ documentNodeData,
+ targetDoc.fields[0].fields[3],
+ new FieldItem(mappingTree, targetDoc.fields[0].fields[3]),
+ );
+ const onUpdateMock = jest.fn();
+ const spyOnApply = jest.spyOn(VisualizationService, 'applyForEach');
+ render( );
+ const actionToggle = screen.getByTestId('transformation-actions-menu-toggle');
+ act(() => {
+ fireEvent.click(actionToggle);
+ });
+ const foreachItem = screen.getByTestId('transformation-actions-foreach');
+ act(() => {
+ fireEvent.click(foreachItem.getElementsByTagName('button')[0]);
+ });
+ waitFor(() => screen.getByTestId('transformation-actions-menu-toggle').getAttribute('aria-expanded') === 'false');
+ expect(onUpdateMock.mock.calls.length).toEqual(1);
+ expect(spyOnApply.mock.calls.length).toEqual(1);
+ });
+
+ it('should stop event propagation upon context menu toggle', () => {
+ const stopPropagationSpy = jest.fn();
+ const nodeData = new TargetFieldNodeData(
+ documentNodeData,
+ targetDoc.fields[0].fields[3],
+ new FieldItem(mappingTree, targetDoc.fields[0].fields[3]),
+ );
+
+ const wrapper = render( {}} />);
+
+ act(() => {
+ const actionToggle = wrapper.getByTestId('transformation-actions-menu-toggle');
+ fireEvent.click(actionToggle, { stopPropagation: stopPropagationSpy });
+ });
+
+ waitFor(() => expect(stopPropagationSpy).toHaveBeenCalled());
+ });
+
+ it('should stop event propagation upon selecting a menu option', () => {
+ const stopPropagationSpy = jest.fn();
+ const nodeData = new TargetFieldNodeData(
+ documentNodeData,
+ targetDoc.fields[0].fields[3],
+ new FieldItem(mappingTree, targetDoc.fields[0].fields[3]),
+ );
+
+ const wrapper = render( {}} />);
+
+ act(() => {
+ const actionToggle = wrapper.getByTestId('transformation-actions-menu-toggle');
+ fireEvent.click(actionToggle, { stopPropagation: jest.fn() });
+ });
+
+ act(() => {
+ const selectorOption = wrapper.getByTestId('transformation-actions-selector');
+ fireEvent.click(selectorOption, { stopPropagation: stopPropagationSpy });
+ });
+
+ waitFor(() => expect(stopPropagationSpy).toHaveBeenCalled());
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/ConditionMenuAction.tsx b/packages/ui/src/components/Document/actions/ConditionMenuAction.tsx
new file mode 100644
index 000000000..43286e7c0
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/ConditionMenuAction.tsx
@@ -0,0 +1,142 @@
+import { FunctionComponent, Ref, MouseEvent, useCallback, useState } from 'react';
+import { MappingNodeData, TargetFieldNodeData, TargetNodeData } from '../../../models/datamapper/visualization';
+import { VisualizationService } from '../../../services/visualization.service';
+import {
+ ActionListItem,
+ Dropdown,
+ DropdownItem,
+ DropdownList,
+ MenuToggle,
+ MenuToggleElement,
+} from '@patternfly/react-core';
+import { EllipsisVIcon } from '@patternfly/react-icons';
+import { ChooseItem } from '../../../models/datamapper/mapping';
+
+type ConditionMenuProps = {
+ nodeData: TargetNodeData;
+ onUpdate: () => void;
+};
+
+const DEFAULT_POPPER_PROPS = {
+ position: 'end',
+ preventOverflow: true,
+} as const;
+
+export const ConditionMenuAction: FunctionComponent = ({ nodeData, onUpdate }) => {
+ const [isActionMenuOpen, setIsActionMenuOpen] = useState(false);
+ const allowIfChoose = VisualizationService.allowIfChoose(nodeData);
+ const allowForEach = VisualizationService.allowForEach(nodeData);
+ const isChooseNode = nodeData instanceof MappingNodeData && nodeData.mapping instanceof ChooseItem;
+ const otherwiseItem = isChooseNode && (nodeData.mapping as ChooseItem).otherwise;
+ const allowValueSelector = VisualizationService.allowValueSelector(nodeData);
+ const hasValueSelector = VisualizationService.hasValueSelector(nodeData);
+ const isValueSelectorNode = VisualizationService.isValueSelectorNode(nodeData);
+
+ const onToggleActionMenu = useCallback(
+ (_event: MouseEvent | undefined) => {
+ setIsActionMenuOpen(!isActionMenuOpen);
+ },
+ [isActionMenuOpen],
+ );
+
+ const onSelectAction = useCallback(
+ (event: MouseEvent | undefined, value: string | number | undefined) => {
+ event?.stopPropagation();
+ switch (value) {
+ case 'selector':
+ VisualizationService.applyValueSelector(nodeData);
+ break;
+ case 'if':
+ VisualizationService.applyIf(nodeData);
+ break;
+ case 'choose':
+ VisualizationService.applyChooseWhenOtherwise(nodeData);
+ break;
+ case 'foreach':
+ VisualizationService.applyForEach(nodeData as TargetFieldNodeData);
+ break;
+ case 'when':
+ VisualizationService.applyWhen(nodeData);
+ break;
+ case 'otherwise':
+ VisualizationService.applyOtherwise(nodeData);
+ break;
+ }
+ onUpdate();
+ setIsActionMenuOpen(false);
+ },
+ [nodeData, onUpdate],
+ );
+
+ return (
+ !isValueSelectorNode && (
+
+ ) => (
+
+
+
+ )}
+ isOpen={isActionMenuOpen}
+ onOpenChange={(isOpen: boolean) => setIsActionMenuOpen(isOpen)}
+ popperProps={DEFAULT_POPPER_PROPS}
+ zIndex={100}
+ >
+
+ {allowValueSelector && (
+
+ Add selector expression
+
+ )}
+ {isChooseNode ? (
+ <>
+
+ Add when
+
+
+ Add otherwise
+
+ >
+ ) : (
+ <>
+ {allowForEach && (
+
+ Wrap with for-each
+
+ )}
+ {allowIfChoose && (
+ <>
+
+ Wrap with if
+
+
+ Wrap with choose-when-otherwise
+
+ >
+ )}
+ >
+ )}
+
+
+
+ )
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/DeleteMappingItemAction.test.tsx b/packages/ui/src/components/Document/actions/DeleteMappingItemAction.test.tsx
new file mode 100644
index 000000000..5612993f2
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DeleteMappingItemAction.test.tsx
@@ -0,0 +1,43 @@
+import { DeleteMappingItemAction } from './DeleteMappingItemAction';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { MappingNodeData, TargetDocumentNodeData } from '../../../models/datamapper/visualization';
+import { MappingTree, ValueSelector } from '../../../models/datamapper/mapping';
+import { DocumentType } from '../../../models/datamapper/path';
+import { BODY_DOCUMENT_ID } from '../../../models/datamapper/document';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { TestUtil } from '../../../stubs/data-mapper';
+
+describe('DeleteMappingItemAction', () => {
+ it('should invoke onDelete()', async () => {
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ const mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ const docData = new TargetDocumentNodeData(targetDoc, mappingTree);
+ const nodeData = new MappingNodeData(docData, new ValueSelector(mappingTree));
+ const onDeleteMock = jest.fn();
+ render(
+
+
+
+
+ ,
+ );
+ const deleteBtn = await screen.findByTestId('delete-mapping-btn');
+ act(() => {
+ fireEvent.click(deleteBtn);
+ });
+ const cancelBtn = screen.getByTestId('delete-mapping-cancel-btn');
+ act(() => {
+ fireEvent.click(cancelBtn);
+ });
+ expect(onDeleteMock.mock.calls.length).toBe(0);
+ act(() => {
+ fireEvent.click(deleteBtn);
+ });
+ const confirmBtn = screen.getByTestId('delete-mapping-confirm-btn');
+ act(() => {
+ fireEvent.click(confirmBtn);
+ });
+ expect(onDeleteMock.mock.calls.length).toBe(1);
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/DeleteMappingItemAction.tsx b/packages/ui/src/components/Document/actions/DeleteMappingItemAction.tsx
new file mode 100644
index 000000000..e094bd1a8
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DeleteMappingItemAction.tsx
@@ -0,0 +1,54 @@
+import { ActionListItem, Button, Modal, ModalVariant } from '@patternfly/react-core';
+import { TrashIcon } from '@patternfly/react-icons';
+import { FunctionComponent, useCallback } from 'react';
+import { useCanvas } from '../../../hooks/useCanvas';
+import { useToggle } from '../../../hooks/useToggle';
+import { ConditionItem } from '../../../models/datamapper/mapping';
+import { TargetNodeData } from '../../../models/datamapper/visualization';
+import { VisualizationService } from '../../../services/visualization.service';
+
+type DeleteItemProps = {
+ nodeData: TargetNodeData;
+ onDelete: () => void;
+};
+
+export const DeleteMappingItemAction: FunctionComponent = ({ nodeData, onDelete }) => {
+ const { state: isModalOpen, toggleOn: openModal, toggleOff: closeModal } = useToggle(false);
+ const { clearNodeReferencesForPath, reloadNodeReferences } = useCanvas();
+
+ const onConfirmDelete = useCallback(() => {
+ if (nodeData.mapping && nodeData.mapping instanceof ConditionItem) {
+ clearNodeReferencesForPath(nodeData.mapping.nodePath.toString());
+ reloadNodeReferences();
+ }
+ VisualizationService.deleteMappingItem(nodeData);
+ onDelete();
+ closeModal();
+ }, [clearNodeReferencesForPath, closeModal, nodeData, onDelete, reloadNodeReferences]);
+ const title = `Delete ${nodeData.title} mapping`;
+
+ return (
+
+
+
+
+
+ Confirm
+ ,
+
+ Cancel
+ ,
+ ]}
+ >
+ {title}?
+
+
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/DeleteParameterButton.test.tsx b/packages/ui/src/components/Document/actions/DeleteParameterButton.test.tsx
new file mode 100644
index 000000000..63e636798
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DeleteParameterButton.test.tsx
@@ -0,0 +1,44 @@
+import { FunctionComponent, PropsWithChildren, useEffect } from 'react';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { DeleteParameterButton } from './DeleteParameterButton';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { IDocument, PrimitiveDocument } from '../../../models/datamapper/document';
+import { DocumentType } from '../../../models/datamapper/path';
+
+describe('DeleteParameterButton', () => {
+ it('should delete a parameter', async () => {
+ let parameterMap: Map;
+ const ParamTest: FunctionComponent = ({ children }) => {
+ const { sourceParameterMap } = useDataMapper();
+ useEffect(() => {
+ sourceParameterMap.set('testparam1', new PrimitiveDocument(DocumentType.PARAM, 'testparam1'));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ useEffect(() => {
+ parameterMap = sourceParameterMap;
+ }, [sourceParameterMap]);
+ return <>{children}>;
+ };
+ render(
+
+
+
+
+
+
+ ,
+ );
+ const deleteBtn = await screen.findByTestId('delete-parameter-testparam1-button');
+ expect(parameterMap!.size).toEqual(1);
+ act(() => {
+ fireEvent.click(deleteBtn);
+ });
+ const confirmBtn = screen.getByTestId('delete-parameter-modal-confirm-btn');
+ act(() => {
+ fireEvent.click(confirmBtn);
+ });
+ expect(parameterMap!.size).toEqual(0);
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/DeleteParameterButton.tsx b/packages/ui/src/components/Document/actions/DeleteParameterButton.tsx
new file mode 100644
index 000000000..4ae92dd40
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DeleteParameterButton.tsx
@@ -0,0 +1,73 @@
+import { Button, Modal, ModalVariant } from '@patternfly/react-core';
+import { TrashIcon } from '@patternfly/react-icons';
+import { FunctionComponent, useCallback } from 'react';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { useToggle } from '../../../hooks/useToggle';
+import { MappingService } from '../../../services/mapping.service';
+
+import { useCanvas } from '../../../hooks/useCanvas';
+import { DocumentType } from '../../../models/datamapper/path';
+
+type DeleteParameterProps = {
+ parameterName: string;
+};
+
+export const DeleteParameterButton: FunctionComponent = ({ parameterName }) => {
+ const { mappingTree, setMappingTree, deleteSourceParameter } = useDataMapper();
+ const { clearNodeReferencesForDocument, reloadNodeReferences } = useCanvas();
+ const { state: isModalOpen, toggleOn: openModal, toggleOff: closeModal } = useToggle(false);
+
+ const onConfirmDelete = useCallback(() => {
+ const cleaned = MappingService.removeAllMappingsForDocument(mappingTree, DocumentType.PARAM, parameterName);
+ setMappingTree(cleaned);
+ deleteSourceParameter(parameterName);
+ clearNodeReferencesForDocument(DocumentType.PARAM, parameterName);
+ reloadNodeReferences();
+ closeModal();
+ }, [
+ clearNodeReferencesForDocument,
+ closeModal,
+ deleteSourceParameter,
+ mappingTree,
+ parameterName,
+ reloadNodeReferences,
+ setMappingTree,
+ ]);
+
+ return (
+ <>
+
+
+
+
+
+ Confirm
+ ,
+
+ Cancel
+ ,
+ ]}
+ >
+ Delete parameter "{parameterName}"? Related mappings will be also removed.
+
+ >
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/DetachSchemaButton.test.tsx b/packages/ui/src/components/Document/actions/DetachSchemaButton.test.tsx
new file mode 100644
index 000000000..79d8316d4
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DetachSchemaButton.test.tsx
@@ -0,0 +1,51 @@
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { DetachSchemaButton } from './DetachSchemaButton';
+import { BODY_DOCUMENT_ID, IDocument, PrimitiveDocument } from '../../../models/datamapper/document';
+import { DocumentType } from '../../../models/datamapper/path';
+import { FunctionComponent, PropsWithChildren, useEffect } from 'react';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+
+import { TestUtil } from '../../../stubs/data-mapper';
+
+describe('DetachSchemaButton', () => {
+ it('should detach the schema', async () => {
+ let sourceDoc: IDocument;
+ let setInitialDoc = true;
+ const DetachTest: FunctionComponent = ({ children }) => {
+ const { sourceBodyDocument, setSourceBodyDocument } = useDataMapper();
+ useEffect(() => {
+ if (setInitialDoc) {
+ setSourceBodyDocument(TestUtil.createSourceOrderDoc());
+ setInitialDoc = false;
+ }
+ });
+ useEffect(() => {
+ sourceDoc = sourceBodyDocument;
+ }, [sourceBodyDocument]);
+ return {children}
;
+ };
+ render(
+
+
+
+
+
+
+ ,
+ );
+ const detachBtn = await screen.findByTestId('detach-schema-sourceBody-Body-button');
+ expect(sourceDoc!.fields.length).toBe(1);
+ act(() => {
+ fireEvent.click(detachBtn);
+ });
+ const confirmBtn = screen.getByTestId('detach-schema-modal-confirm-btn');
+ act(() => {
+ fireEvent.click(confirmBtn);
+ });
+ await screen.findByTestId('detachtest');
+ expect(sourceDoc!.fields.length).toBe(0);
+ expect(sourceDoc! instanceof PrimitiveDocument);
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/DetachSchemaButton.tsx b/packages/ui/src/components/Document/actions/DetachSchemaButton.tsx
new file mode 100644
index 000000000..33b014481
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DetachSchemaButton.tsx
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { Button, Modal, ModalVariant } from '@patternfly/react-core';
+import { FunctionComponent, useCallback } from 'react';
+
+import { ExportIcon } from '@patternfly/react-icons';
+import { useCanvas } from '../../../hooks/useCanvas';
+import { useDataMapper } from '../../../hooks/useDataMapper';
+import { useToggle } from '../../../hooks/useToggle';
+import { DocumentDefinition, DocumentDefinitionType } from '../../../models/datamapper/document';
+import { DocumentType } from '../../../models/datamapper/path';
+
+type DeleteSchemaProps = {
+ documentType: DocumentType;
+ documentId: string;
+};
+
+export const DetachSchemaButton: FunctionComponent = ({ documentType, documentId }) => {
+ const { updateDocumentDefinition } = useDataMapper();
+ const { clearNodeReferencesForDocument, reloadNodeReferences } = useCanvas();
+ const { state: isModalOpen, toggleOn: openModal, toggleOff: closeModal } = useToggle(false);
+
+ const onConfirmDelete = useCallback(() => {
+ const definition = new DocumentDefinition(documentType, DocumentDefinitionType.Primitive, documentId);
+ updateDocumentDefinition(definition);
+ clearNodeReferencesForDocument(documentType, documentId);
+ reloadNodeReferences();
+ closeModal();
+ }, [
+ documentType,
+ documentId,
+ updateDocumentDefinition,
+ clearNodeReferencesForDocument,
+ reloadNodeReferences,
+ closeModal,
+ ]);
+
+ return (
+ <>
+
+
+
+
+
+ Confirm
+ ,
+
+ Cancel
+ ,
+ ]}
+ >
+ Detach correlated schema and make it back to be a primitive value? Related mappings will be also removed.
+
+ >
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/DocumentActions.test.tsx b/packages/ui/src/components/Document/actions/DocumentActions.test.tsx
new file mode 100644
index 000000000..9ce632f0f
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DocumentActions.test.tsx
@@ -0,0 +1,20 @@
+import { DocumentActions } from './DocumentActions';
+import { render, screen } from '@testing-library/react';
+import { DocumentNodeData } from '../../../models/datamapper/visualization';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { TestUtil } from '../../../stubs/data-mapper';
+
+describe('DocumentActions', () => {
+ it('should render', async () => {
+ const docData = new DocumentNodeData(TestUtil.createSourceOrderDoc());
+ render(
+
+
+
+
+ ,
+ );
+ expect(await screen.findByTestId('attach-schema-sourceBody-ShipOrder.xsd-button'));
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/DocumentActions.tsx b/packages/ui/src/components/Document/actions/DocumentActions.tsx
new file mode 100644
index 000000000..7a965073a
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/DocumentActions.tsx
@@ -0,0 +1,45 @@
+import { ActionListGroup, ActionListItem } from '@patternfly/react-core';
+import { AttachSchemaButton } from './AttachSchemaButton';
+import { DetachSchemaButton } from './DetachSchemaButton';
+import { DocumentType } from '../../../models/datamapper/path';
+import { DocumentNodeData } from '../../../models/datamapper/visualization';
+import { DeleteParameterButton } from './DeleteParameterButton';
+import { FunctionComponent, MouseEvent, useCallback } from 'react';
+import '../Document.scss';
+
+type DocumentActionsProps = {
+ className?: string;
+ nodeData: DocumentNodeData;
+};
+
+export const DocumentActions: FunctionComponent = ({ className, nodeData }) => {
+ const documentType = nodeData.document.documentType;
+ const documentId = nodeData.document.documentId;
+ const handleStopPropagation = useCallback((event: MouseEvent) => {
+ event.stopPropagation();
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+ {documentType === DocumentType.PARAM && (
+
+
+
+ )}
+
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/TargetNodeActions.test.tsx b/packages/ui/src/components/Document/actions/TargetNodeActions.test.tsx
new file mode 100644
index 000000000..57704858a
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/TargetNodeActions.test.tsx
@@ -0,0 +1,35 @@
+import { TargetNodeActions } from './TargetNodeActions';
+import { render, screen } from '@testing-library/react';
+import { MappingNodeData, TargetDocumentNodeData } from '../../../models/datamapper/visualization';
+import { MappingTree, ValueSelector } from '../../../models/datamapper/mapping';
+import { DocumentType } from '../../../models/datamapper/path';
+import { BODY_DOCUMENT_ID } from '../../../models/datamapper/document';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { TestUtil } from '../../../stubs/data-mapper';
+
+describe('TargetNodeActions', () => {
+ it('should render', async () => {
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ const tree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ const nodeData = new TargetDocumentNodeData(targetDoc, tree);
+ render( );
+ expect(await screen.findByTestId('transformation-actions-menu-toggle')).toBeTruthy();
+ });
+
+ it('should render expression action', async () => {
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ const tree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ const docData = new TargetDocumentNodeData(targetDoc, tree);
+ const mappingData = new MappingNodeData(docData, new ValueSelector(tree));
+ render(
+
+
+
+
+ ,
+ );
+ expect(await screen.findByTestId('transformation-xpath-input')).toBeTruthy();
+ expect(screen.getByTestId(`edit-xpath-button-${mappingData.id}`)).toBeTruthy();
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/TargetNodeActions.tsx b/packages/ui/src/components/Document/actions/TargetNodeActions.tsx
new file mode 100644
index 000000000..e41ec7939
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/TargetNodeActions.tsx
@@ -0,0 +1,37 @@
+import { ActionListGroup } from '@patternfly/react-core';
+import { FunctionComponent, MouseEvent, KeyboardEvent, useCallback } from 'react';
+import { XPathInputAction } from './XPathInputAction';
+import { DeleteMappingItemAction } from './DeleteMappingItemAction';
+import { ConditionMenuAction } from './ConditionMenuAction';
+import { XPathEditorAction } from './XPathEditorAction';
+import { TargetNodeData } from '../../../models/datamapper/visualization';
+import { VisualizationService } from '../../../services/visualization.service';
+import '../Document.scss';
+
+type TargetNodeActionsProps = {
+ className?: string;
+ nodeData: TargetNodeData;
+ onUpdate: () => void;
+};
+
+export const TargetNodeActions: FunctionComponent = ({ className, nodeData, onUpdate }) => {
+ const expressionItem = VisualizationService.getExpressionItemForNode(nodeData);
+ const allowConditionMenu = VisualizationService.allowConditionMenu(nodeData);
+ const isDeletable = VisualizationService.isDeletableNode(nodeData);
+ const handleStopPropagation = useCallback((event: MouseEvent | KeyboardEvent) => {
+ event.stopPropagation();
+ }, []);
+
+ return (
+
+ {expressionItem && (
+ <>
+
+
+ >
+ )}
+ {allowConditionMenu && }
+ {isDeletable && }
+
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/XPathEditorAction.test.tsx b/packages/ui/src/components/Document/actions/XPathEditorAction.test.tsx
new file mode 100644
index 000000000..b4bc9f292
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/XPathEditorAction.test.tsx
@@ -0,0 +1,39 @@
+import { XPathEditorAction } from './XPathEditorAction';
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { MappingTree, ValueSelector } from '../../../models/datamapper/mapping';
+import { DocumentType } from '../../../models/datamapper/path';
+import { BODY_DOCUMENT_ID } from '../../../models/datamapper/document';
+import { TargetDocumentNodeData } from '../../../models/datamapper/visualization';
+import { DataMapperProvider } from '../../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../../providers/datamapper-canvas.provider';
+import { TestUtil } from '../../../stubs/data-mapper';
+
+describe('XPathEditorAction', () => {
+ it('should open xpath editor modal', async () => {
+ window.ResizeObserver = jest.fn().mockImplementation(() => ({
+ observe: jest.fn(),
+ unobserve: jest.fn(),
+ disconnect: jest.fn(),
+ }));
+ const doc = TestUtil.createTargetOrderDoc();
+ const tree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ const docData = new TargetDocumentNodeData(doc, tree);
+ render(
+
+
+
+
+ ,
+ );
+ const editBtn = await screen.findByTestId(`edit-xpath-button-${docData.id}`);
+ act(() => {
+ fireEvent.click(editBtn);
+ });
+ const modal = await screen.findByTestId('xpath-editor-modal');
+ expect(modal).toBeInTheDocument();
+ const monaco = await screen.findByTestId('xpath-editor');
+ expect(monaco).toBeInTheDocument();
+ const textbox = await screen.findByRole('textbox');
+ expect(textbox).toBeInTheDocument();
+ }, 30000);
+});
diff --git a/packages/ui/src/components/Document/actions/XPathEditorAction.tsx b/packages/ui/src/components/Document/actions/XPathEditorAction.tsx
new file mode 100644
index 000000000..3be40d656
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/XPathEditorAction.tsx
@@ -0,0 +1,43 @@
+import { TargetNodeData } from '../../../models/datamapper/visualization';
+import { ExpressionItem } from '../../../models/datamapper/mapping';
+import { FunctionComponent, useCallback, useState } from 'react';
+import { ActionListItem, Button } from '@patternfly/react-core';
+import { PencilAltIcon } from '@patternfly/react-icons';
+import { XPathEditorModal } from '../../XPath/XPathEditorModal';
+import { useCanvas } from '../../../hooks/useCanvas';
+
+type XPathEditorProps = {
+ nodeData: TargetNodeData;
+ mapping: ExpressionItem;
+ onUpdate: () => void;
+};
+export const XPathEditorAction: FunctionComponent = ({ nodeData, mapping, onUpdate }) => {
+ const { reloadNodeReferences } = useCanvas();
+ const [isEditorOpen, setIsEditorOpen] = useState(false);
+ const launchXPathEditor = useCallback(() => setIsEditorOpen(true), []);
+ const closeXPathEditor = useCallback(() => {
+ setIsEditorOpen(false);
+ reloadNodeReferences();
+ }, [reloadNodeReferences]);
+
+ return (
+
+ }
+ />
+
+
+ );
+};
diff --git a/packages/ui/src/components/Document/actions/XPathInputAction.scss b/packages/ui/src/components/Document/actions/XPathInputAction.scss
new file mode 100644
index 000000000..97763a73d
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/XPathInputAction.scss
@@ -0,0 +1,7 @@
+.input-group {
+ flex-grow: 1;
+
+ &__text {
+ width: 100%;
+ }
+}
diff --git a/packages/ui/src/components/Document/actions/XPathInputAction.test.tsx b/packages/ui/src/components/Document/actions/XPathInputAction.test.tsx
new file mode 100644
index 000000000..52182a0fa
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/XPathInputAction.test.tsx
@@ -0,0 +1,47 @@
+import { XPathInputAction } from './XPathInputAction';
+import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
+import { MappingTree, ValueSelector } from '../../../models/datamapper/mapping';
+import { BODY_DOCUMENT_ID } from '../../../models/datamapper/document';
+import { DocumentType } from '../../../models/datamapper/path';
+
+describe('XPathInputAction', () => {
+ let tree: MappingTree;
+ let mapping: ValueSelector;
+
+ beforeEach(() => {
+ tree = new MappingTree(DocumentType.SOURCE_BODY, BODY_DOCUMENT_ID);
+ mapping = new ValueSelector(tree);
+ });
+
+ it('should update xpath', () => {
+ const onUpdateMock = jest.fn();
+ render( );
+ expect(mapping.expression).toBeFalsy();
+ const input = screen.getByTestId('transformation-xpath-input');
+ act(() => {
+ fireEvent.change(input, { target: { value: '/ShipOrder' } });
+ });
+ expect(mapping.expression).toEqual('/ShipOrder');
+ expect(onUpdateMock.mock.calls.length).toEqual(1);
+ });
+
+ it('should show error popover button if xpath has a parse error', async () => {
+ mapping.expression = '{{';
+ const onUpdateMock = jest.fn();
+ render( );
+ const btn = await screen.findByTestId('xpath-input-error-btn');
+ expect(btn).toBeInTheDocument();
+ });
+
+ it('should stop event propagation on handleXPathChange', () => {
+ const stopPropagationSpy = jest.fn();
+ const wrapper = render( );
+
+ act(() => {
+ const input = wrapper.getByTestId('transformation-xpath-input');
+ fireEvent.change(input, { target: { value: '/ShipOrder' }, stopPropagation: stopPropagationSpy });
+ });
+
+ waitFor(() => expect(stopPropagationSpy).toHaveBeenCalled());
+ });
+});
diff --git a/packages/ui/src/components/Document/actions/XPathInputAction.tsx b/packages/ui/src/components/Document/actions/XPathInputAction.tsx
new file mode 100644
index 000000000..d5de0cc0e
--- /dev/null
+++ b/packages/ui/src/components/Document/actions/XPathInputAction.tsx
@@ -0,0 +1,101 @@
+import { ExpressionItem } from '../../../models/datamapper/mapping';
+import { FormEvent, FunctionComponent, MouseEvent, useCallback, useEffect, useMemo, useState } from 'react';
+import {
+ ActionListItem,
+ Button,
+ ButtonVariant,
+ Icon,
+ InputGroup,
+ InputGroupItem,
+ List,
+ ListItem,
+ Popover,
+ TextInput,
+} from '@patternfly/react-core';
+import { ExclamationCircleIcon, ExclamationTriangleIcon } from '@patternfly/react-icons';
+import { ValidatedXPathParseResult, XPathService } from '../../../services/xpath/xpath.service';
+import './XPathInputAction.scss';
+
+type XPathInputProps = {
+ mapping: ExpressionItem;
+ onUpdate: () => void;
+};
+export const XPathInputAction: FunctionComponent = ({ mapping, onUpdate }) => {
+ const [validationResult, setValidationResult] = useState();
+
+ const validateXPath = useCallback(() => {
+ const result = XPathService.validate(mapping.expression);
+ setValidationResult(result);
+ }, [mapping.expression]);
+
+ useEffect(() => {
+ validateXPath();
+ }, [validateXPath]);
+
+ const handleXPathChange = useCallback(
+ (event: FormEvent, value: string) => {
+ event.stopPropagation();
+ if (mapping) {
+ mapping.expression = value;
+ onUpdate();
+ }
+ },
+ [mapping, onUpdate],
+ );
+
+ const stopPropagation = useCallback((event: MouseEvent) => {
+ event.stopPropagation();
+ }, []);
+
+ const errorContent = useMemo(() => {
+ return (
+
+ {validationResult?.getErrors().map((e) => {e} )}
+ {validationResult?.getWarnings().map((w) => {w} )}
+
+ );
+ }, [validationResult]);
+
+ return (
+
+
+
+
+
+ {validationResult &&
+ (!validationResult.getCst() ||
+ validationResult.dataMapperErrors.length > 0 ||
+ validationResult.hasWarnings()) && (
+
+
+
+
+
+ ) : (
+
+
+
+ )
+ }
+ >
+
+
+ )}
+
+
+ );
+};
diff --git a/packages/ui/src/components/RenderingAnchor/RenderingAnchor.test.tsx b/packages/ui/src/components/RenderingAnchor/RenderingAnchor.test.tsx
new file mode 100644
index 000000000..b5fcfe74e
--- /dev/null
+++ b/packages/ui/src/components/RenderingAnchor/RenderingAnchor.test.tsx
@@ -0,0 +1,61 @@
+import { render } from '@testing-library/react';
+import { createVisualizationNode, IVisualizationNode } from '../../models';
+import { RenderingAnchor } from './RenderingAnchor';
+import { RenderingAnchorContext } from './rendering.provider';
+import { IRegisteredValidatedComponent, IRenderingAnchorContext } from './rendering.provider.model';
+
+describe('RenderingAnchor', () => {
+ const anchorTag = 'example-anchor';
+ const vizNode: IVisualizationNode = createVisualizationNode('example-node', {});
+ let renderingAnchorContext: IRenderingAnchorContext;
+
+ beforeEach(() => {
+ renderingAnchorContext = {
+ getRegisteredComponents: jest.fn().mockReturnValue([]),
+ registerComponent: jest.fn(),
+ };
+ });
+
+ it('should not render the `RenderingAnchor` when the `vizNode` prop is undefined', () => {
+ const wrapper = render( );
+
+ expect(wrapper.container).toBeEmptyDOMElement();
+ });
+
+ it('should not render anything if there is no registered components for a given anchor', () => {
+ const wrapper = render(
+
+
+ ,
+ );
+
+ expect(wrapper.container).toBeEmptyDOMElement();
+ });
+
+ it('should query the registered components by `anchorTag` and `vizNode`', () => {
+ render(
+
+
+ ,
+ );
+
+ expect(renderingAnchorContext.getRegisteredComponents).toHaveBeenCalledWith(anchorTag, vizNode);
+ });
+
+ it('should render the registered components', () => {
+ const registeredComponents: IRegisteredValidatedComponent[] = [
+ { key: '1', Component: () => Component 1
},
+ { key: '2', Component: () => Component 2
},
+ ];
+ renderingAnchorContext.getRegisteredComponents = jest.fn().mockReturnValue(registeredComponents);
+
+ const wrapper = render(
+
+
+ ,
+ );
+
+ expect(wrapper.getByText('Component 1')).toBeInTheDocument();
+ expect(wrapper.getByText('Component 2')).toBeInTheDocument();
+ });
+});
diff --git a/packages/ui/src/components/RenderingAnchor/RenderingAnchor.tsx b/packages/ui/src/components/RenderingAnchor/RenderingAnchor.tsx
new file mode 100644
index 000000000..3a84cc3f5
--- /dev/null
+++ b/packages/ui/src/components/RenderingAnchor/RenderingAnchor.tsx
@@ -0,0 +1,21 @@
+import { FunctionComponent, useContext } from 'react';
+import { IVisualizationNode } from '../../models';
+import { isDefined } from '../../utils';
+import { RenderingAnchorContext } from './rendering.provider';
+
+interface IRenderingAnchor {
+ anchorTag: string;
+ vizNode: IVisualizationNode | undefined;
+}
+
+export const RenderingAnchor: FunctionComponent = ({ anchorTag, vizNode }) => {
+ const renderingAnchorContext = useContext(RenderingAnchorContext);
+
+ if (!isDefined(vizNode)) {
+ return null;
+ }
+
+ const registeredChildren = renderingAnchorContext.getRegisteredComponents(anchorTag, vizNode);
+
+ return registeredChildren.map(({ key, Component }) => );
+};
diff --git a/packages/ui/src/components/RenderingAnchor/rendering.provider.model.ts b/packages/ui/src/components/RenderingAnchor/rendering.provider.model.ts
new file mode 100644
index 000000000..668fb3b75
--- /dev/null
+++ b/packages/ui/src/components/RenderingAnchor/rendering.provider.model.ts
@@ -0,0 +1,56 @@
+import { FunctionComponent } from 'react';
+import { IVisualizationNode } from '../../models';
+
+export interface IRegisteredComponent {
+ anchor: string;
+ activationFn: (vizNode: IVisualizationNode) => boolean;
+ component: FunctionComponent<{ vizNode?: IVisualizationNode }>;
+}
+
+export interface IRegisteredValidatedComponent {
+ key: string;
+ Component: IRegisteredComponent['component'];
+}
+
+export interface IRenderingAnchorContext {
+ /**
+ * Register a component to be rendered in the given anchor
+ *
+ * @example
+ * ```tsx
+ * const renderingAnchorContext = useContext(RenderingAnchorContext);
+ *
+ * renderingAnchorContext.registerComponent({
+ * anchor: 'form-header',
+ * activationFn: () => true,
+ * component: ({ vizNode }) => {vizNode.getId()} ,
+ * });
+ * ```
+ * @param props Registered component definition
+ * @returns void
+ */
+ registerComponent: (props: IRegisteredComponent) => void;
+
+ /**
+ * Get components registered to the given anchor and pass the validation function
+ *
+ * @example
+ * ```tsx
+ * const renderingAnchorContext = useContext(RenderingAnchorContext);
+ *
+ * const components = renderingAnchorContext.getRegisteredComponents('form-header', vizNode);
+ *
+ * return (
+ *
+ * {components.map(({ key, Component }) => (
+ *
+ * ))}
+ *
+ * );
+ * ```
+ * @param anchorTag The anchor tag to register the component to
+ * @param vizNode The visualization node to pass to the component
+ * @returns `IRegisteredValidatedComponent[]` An array of registered and validated components
+ */
+ getRegisteredComponents: (anchorTag: string, vizNode: IVisualizationNode) => IRegisteredValidatedComponent[];
+}
diff --git a/packages/ui/src/components/RenderingAnchor/rendering.provider.test.tsx b/packages/ui/src/components/RenderingAnchor/rendering.provider.test.tsx
new file mode 100644
index 000000000..d6c0c26d8
--- /dev/null
+++ b/packages/ui/src/components/RenderingAnchor/rendering.provider.test.tsx
@@ -0,0 +1,118 @@
+import { render } from '@testing-library/react';
+import { useContext } from 'react';
+import { IVisualizationNode } from '../../models/visualization/base-visual-entity';
+import { createVisualizationNode } from '../../models/visualization/visualization-node';
+import { RenderingAnchorContext, RenderingProvider } from './rendering.provider';
+import { IRegisteredComponent } from './rendering.provider.model';
+
+describe('RenderingProvider', () => {
+ const anchorExample = 'form-header';
+ const vizNode: IVisualizationNode = createVisualizationNode('example-node', {});
+
+ describe('RenderingAnchorContext', () => {
+ it('should provide a default implementation', () => {
+ expect(() => {
+ render( );
+ }).not.toThrow();
+ });
+ });
+
+ it('should render the child component', () => {
+ const { getByText } = render(
+
+ Child component
+ ,
+ );
+
+ expect(getByText('Child component')).toBeInTheDocument();
+ });
+
+ it('should allow consumers to register and render components', () => {
+ const { getByText } = render(
+
+ true,
+ component: () => Registered component
,
+ },
+ ]}
+ />
+ ,
+ );
+
+ expect(getByText('Registered component')).toBeInTheDocument();
+ });
+
+ it('should filter components by anchorTag', async () => {
+ const { getByText, queryByText } = render(
+
+ true,
+ component: () => Registered component
,
+ },
+ {
+ anchor: 'another-anchor',
+ activationFn: () => true,
+ component: () => Another component
,
+ },
+ ]}
+ />
+ ,
+ );
+
+ expect(getByText('Registered component')).toBeInTheDocument();
+
+ const anotherComponent = queryByText('Another component');
+ expect(anotherComponent).toBeNull();
+ });
+
+ it('should filter components by activationFn', async () => {
+ const { getByText, queryByText } = render(
+
+ true,
+ component: () => Registered component
,
+ },
+ {
+ anchor: anchorExample,
+ activationFn: () => false,
+ component: () => Another component
,
+ },
+ ]}
+ />
+ ,
+ );
+
+ expect(getByText('Registered component')).toBeInTheDocument();
+
+ const anotherComponent = queryByText('Another component');
+ expect(anotherComponent).toBeNull();
+ });
+
+ function ProviderConsumer(props: { anchorTag: string; registerComponents: IRegisteredComponent[] }) {
+ const { registerComponent, getRegisteredComponents } = useContext(RenderingAnchorContext);
+
+ props.registerComponents.forEach((regComponent) => registerComponent(regComponent));
+
+ const components = getRegisteredComponents('form-header', vizNode);
+
+ return (
+
+ {components.map(({ key, Component }) => (
+
+ ))}
+
+ );
+ }
+});
diff --git a/packages/ui/src/components/RenderingAnchor/rendering.provider.tsx b/packages/ui/src/components/RenderingAnchor/rendering.provider.tsx
new file mode 100644
index 000000000..1ce101b44
--- /dev/null
+++ b/packages/ui/src/components/RenderingAnchor/rendering.provider.tsx
@@ -0,0 +1,44 @@
+import { createContext, FunctionComponent, PropsWithChildren, Suspense, useCallback, useMemo, useRef } from 'react';
+import { getCamelRandomId } from '../../camel-utils/camel-random-id';
+import { IVisualizationNode } from '../../models';
+import { Loading } from '../Loading';
+import { IRegisteredComponent, IRenderingAnchorContext } from './rendering.provider.model';
+
+export const RenderingAnchorContext = createContext({
+ registerComponent: () => {},
+ getRegisteredComponents: () => [],
+});
+
+export const RenderingProvider: FunctionComponent = ({ children }) => {
+ const registeredComponents = useRef<({ key: string } & IRegisteredComponent)[]>([]);
+
+ const registerComponent = useCallback((props: IRegisteredComponent) => {
+ const key = getCamelRandomId(props.anchor, 6);
+ registeredComponents.current.push({ key, ...props });
+ }, []);
+
+ const getRegisteredComponents = useCallback((anchorTag: string, vizNode: IVisualizationNode) => {
+ return registeredComponents.current
+ .filter(
+ (registeredComponent) => registeredComponent.anchor === anchorTag && registeredComponent.activationFn(vizNode),
+ )
+ .map(({ key, component }) => ({ key, Component: component }));
+ }, []);
+
+ const value = useMemo(
+ () => ({ registerComponent, getRegisteredComponents }),
+ [getRegisteredComponents, registerComponent],
+ );
+
+ return (
+
+ Loading dynamic components...
+
+ }
+ >
+ {children}
+
+ );
+};
diff --git a/packages/ui/src/components/View/MappingLink.tsx b/packages/ui/src/components/View/MappingLink.tsx
new file mode 100644
index 000000000..c59b45d6e
--- /dev/null
+++ b/packages/ui/src/components/View/MappingLink.tsx
@@ -0,0 +1,196 @@
+import {
+ CSSProperties,
+ FunctionComponent,
+ MutableRefObject,
+ RefObject,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+} from 'react';
+import { useCanvas } from '../../hooks/useCanvas';
+import { useDataMapper } from '../../hooks/useDataMapper';
+import { NodeReference } from '../../providers/datamapper-canvas.provider';
+import { MappingService } from '../../services/mapping.service';
+import { Circle, LinePath } from '@visx/shape';
+import { curveMonotoneX } from '@visx/curve';
+
+type LineCoord = {
+ x1: number;
+ y1: number;
+ x2: number;
+ y2: number;
+};
+
+type LineProps = LineCoord & {
+ sourceNodePath: string;
+ targetNodePath: string;
+ svgRef?: RefObject;
+};
+
+const MappingLink: FunctionComponent = ({ x1, y1, x2, y2, sourceNodePath, targetNodePath, svgRef }) => {
+ const { mappingLinkCanvasRef } = useCanvas();
+ const [isOver, setIsOver] = useState(false);
+ const lineStyle = {
+ stroke: 'gray',
+ strokeWidth: isOver ? 6 : 3,
+ pointerEvents: 'auto' as CSSProperties['pointerEvents'],
+ };
+ const dotRadius = isOver ? 6 : 3;
+ const svgRect = svgRef?.current?.getBoundingClientRect();
+ const canvasRect = mappingLinkCanvasRef?.current?.getBoundingClientRect();
+ const canvasLeft = canvasRect ? canvasRect.left - (svgRect ? svgRect.left : 0) : undefined;
+ const canvasRight = canvasRect ? canvasRect.right - (svgRect ? svgRect.left : 0) : undefined;
+
+ const onMouseEnter = useCallback(() => {
+ setIsOver(true);
+ }, []);
+
+ const onMouseLeave = useCallback(() => {
+ setIsOver(false);
+ }, []);
+
+ return (
+ <>
+
+
+ data={[
+ [x1, y1],
+ [canvasLeft ? canvasLeft : x1, y1],
+ [canvasRight ? canvasRight : x2, y2],
+ [x2, y2],
+ ]}
+ x={(d) => d[0]}
+ y={(d) => d[1]}
+ curve={curveMonotoneX}
+ style={lineStyle}
+ onClick={() => {}}
+ onMouseEnter={onMouseEnter}
+ onMouseLeave={onMouseLeave}
+ data-testid={`mapping-link-${x1}-${y1}-${x2}-${y2}`}
+ xlinkTitle={`Source: ${sourceNodePath}, Target: ${targetNodePath}`}
+ />
+
+ >
+ );
+};
+
+export const MappingLinksContainer: FunctionComponent = () => {
+ const { mappingTree, sourceBodyDocument, sourceParameterMap } = useDataMapper();
+ const [lineCoordList, setLineCoordList] = useState([]);
+ const { getNodeReference } = useCanvas();
+ const svgRef = useRef(null);
+
+ const getCoordFromFieldRef = useCallback(
+ (sourceRef: MutableRefObject, targetRef: MutableRefObject) => {
+ const svgRect = svgRef.current?.getBoundingClientRect();
+ const sourceRect = sourceRef.current?.headerRef?.getBoundingClientRect();
+ const targetRect = targetRef.current?.headerRef?.getBoundingClientRect();
+ if (!sourceRect || !targetRect) {
+ return;
+ }
+
+ return {
+ x1: sourceRect.right - (svgRect ? svgRect.left : 0),
+ y1: sourceRect.top + (sourceRect.bottom - sourceRect.top) / 2 - (svgRect ? svgRect.top : 0),
+ x2: targetRect.left - (svgRect ? svgRect.left : 0),
+ y2: targetRect.top + (targetRect.bottom - targetRect.top) / 2 - (svgRect ? svgRect.top : 0),
+ };
+ },
+ [],
+ );
+
+ const getParentPath = useCallback((path: string) => {
+ if (path.endsWith('://')) return path.substring(0, path.indexOf(':'));
+
+ const lastSeparatorIndex = path.lastIndexOf('/');
+ const endIndex =
+ lastSeparatorIndex !== -1 && path.charAt(lastSeparatorIndex - 1) === '/'
+ ? lastSeparatorIndex + 1
+ : lastSeparatorIndex;
+ return endIndex !== -1 ? path.substring(0, endIndex) : null;
+ }, []);
+
+ const getClosestExpandedPath = useCallback(
+ (path: string) => {
+ let tracedPath: string | null = path;
+ while (
+ !!tracedPath &&
+ (getNodeReference(tracedPath)?.current == null ||
+ getNodeReference(tracedPath)?.current.headerRef == null ||
+ getNodeReference(tracedPath)?.current.headerRef?.getClientRects().length === 0)
+ ) {
+ const parentPath = getParentPath(tracedPath);
+ if (parentPath === tracedPath) break;
+ tracedPath = parentPath;
+ }
+ return tracedPath;
+ },
+ [getNodeReference, getParentPath],
+ );
+
+ const refreshLinks = useCallback(() => {
+ const links = MappingService.extractMappingLinks(mappingTree, sourceParameterMap, sourceBodyDocument);
+ const answer: LineProps[] = links.reduce((acc, { sourceNodePath, targetNodePath }) => {
+ const sourceClosestPath = getClosestExpandedPath(sourceNodePath);
+ const targetClosestPath = getClosestExpandedPath(targetNodePath);
+ if (sourceClosestPath && targetClosestPath) {
+ const sourceFieldRef = getNodeReference(sourceClosestPath);
+ const targetFieldRef = getNodeReference(targetClosestPath);
+ if (sourceFieldRef && !!targetFieldRef) {
+ const coord = getCoordFromFieldRef(sourceFieldRef, targetFieldRef);
+ if (coord) acc.push({ ...coord, sourceNodePath: sourceNodePath, targetNodePath: targetNodePath });
+ }
+ }
+ return acc;
+ }, [] as LineProps[]);
+ setLineCoordList(answer);
+ }, [
+ mappingTree,
+ sourceParameterMap,
+ sourceBodyDocument,
+ getClosestExpandedPath,
+ getNodeReference,
+ getCoordFromFieldRef,
+ ]);
+
+ useEffect(() => {
+ refreshLinks();
+ window.addEventListener('resize', refreshLinks);
+ window.addEventListener('scroll', refreshLinks);
+ return () => {
+ window.removeEventListener('resize', refreshLinks);
+ window.removeEventListener('scroll', refreshLinks);
+ };
+ }, [refreshLinks]);
+
+ return (
+
+
+ {lineCoordList.map((lineProps, index) => (
+
+ ))}
+
+
+ );
+};
diff --git a/packages/ui/src/components/View/SourcePanel.test.tsx b/packages/ui/src/components/View/SourcePanel.test.tsx
new file mode 100644
index 000000000..f435d4558
--- /dev/null
+++ b/packages/ui/src/components/View/SourcePanel.test.tsx
@@ -0,0 +1,31 @@
+import { DataMapperProvider } from '../../providers/datamapper.provider';
+import { SourcePanel } from './SourcePanel';
+import { render, screen } from '@testing-library/react';
+import { DataMapperCanvasProvider } from '../../providers/datamapper-canvas.provider';
+
+describe('SourcePanel', () => {
+ it('should render action buttons by default', () => {
+ render(
+
+
+
+
+ ,
+ );
+ expect(screen.getByTestId('add-parameter-button')).toBeInTheDocument();
+ expect(screen.getByTestId('attach-schema-sourceBody-Body-button')).toBeInTheDocument();
+ expect(screen.getByTestId('detach-schema-sourceBody-Body-button')).toBeInTheDocument();
+ });
+ it('should not render action buttons if isReadOnly=true', () => {
+ render(
+
+
+
+
+ ,
+ );
+ expect(screen.queryByTestId('add-parameter-button')).toBeFalsy();
+ expect(screen.queryByTestId('attach-schema-sourceBody-Body-button')).toBeFalsy();
+ expect(screen.queryByTestId('detach-schema-sourceBody-Body-button')).toBeFalsy();
+ });
+});
diff --git a/packages/ui/src/components/View/SourcePanel.tsx b/packages/ui/src/components/View/SourcePanel.tsx
new file mode 100644
index 000000000..9ce10180c
--- /dev/null
+++ b/packages/ui/src/components/View/SourcePanel.tsx
@@ -0,0 +1,55 @@
+import { FunctionComponent } from 'react';
+import {
+ Divider,
+ Panel,
+ PanelHeader,
+ PanelMain,
+ Stack,
+ StackItem,
+ Text,
+ TextContent,
+ TextVariants,
+ Truncate,
+} from '@patternfly/react-core';
+import { Parameters } from '../Document/Parameters';
+import { useDataMapper } from '../../hooks/useDataMapper';
+import { useCanvas } from '../../hooks/useCanvas';
+import { SourceDocument } from '../Document/SourceDocument';
+import './SourceTargetView.scss';
+
+type SourcePanelProps = {
+ isReadOnly?: boolean;
+};
+
+export const SourcePanel: FunctionComponent = ({ isReadOnly = false }) => {
+ const { sourceBodyDocument } = useDataMapper();
+ const { reloadNodeReferences } = useCanvas();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/View/SourceTargetView.scss b/packages/ui/src/components/View/SourceTargetView.scss
new file mode 100644
index 000000000..e50918f50
--- /dev/null
+++ b/packages/ui/src/components/View/SourceTargetView.scss
@@ -0,0 +1,50 @@
+.source-target-view {
+ height: 100%;
+ overflow-x: auto;
+
+ &__source-split {
+ width: 30%;
+ min-width: 300px;
+ }
+
+ &__source-panel {
+ height: 100%;
+ }
+
+ &__source-panel-main {
+ height: 100%;
+ max-height: 100%;
+ overflow: clip auto;
+ }
+
+ &__line-blank {
+ width: 10%;
+ min-width: 1px;
+ overflow-x: clip;
+ }
+
+ &__target-split {
+ width: 60%;
+ min-width: 300px;
+ }
+
+ &__target-panel {
+ display: flex;
+ flex-flow: column;
+ height: 100%;
+ min-width: 400px;
+ }
+
+ &__target-panel-main {
+ height: 100%;
+ max-height: 100%;
+ }
+
+ &__truncate {
+ --pf-v5-c-truncate--MinWidth: 0;
+ }
+
+ &__divider {
+ padding-bottom: 0.5rem;
+ }
+}
diff --git a/packages/ui/src/components/View/SourceTargetView.test.tsx b/packages/ui/src/components/View/SourceTargetView.test.tsx
new file mode 100644
index 000000000..466b35b40
--- /dev/null
+++ b/packages/ui/src/components/View/SourceTargetView.test.tsx
@@ -0,0 +1,85 @@
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import { DataMapperProvider } from '../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../providers/datamapper-canvas.provider';
+import { SourceTargetView } from './SourceTargetView';
+
+import { shipOrderXsd } from '../../stubs/data-mapper';
+import { BrowserFilePickerMetadataProvider } from '../../stubs/BrowserFilePickerMetadataProvider';
+
+describe('SourceTargetView', () => {
+ describe('Source Body Document', () => {
+ it('should attach and detach schema', async () => {
+ render(
+
+
+
+
+
+
+ ,
+ );
+ const attachButton = await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileContent = new File([new Blob([shipOrderXsd])], 'ShipOrder.xsd', { type: 'text/plain' });
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileInput = screen.getByTestId('attach-schema-file-input');
+ act(() => {
+ fireEvent.change(fileInput, { target: { files: { item: () => fileContent, length: 1, 0: fileContent } } });
+ });
+ const shipTo = await screen.findByText('ShipTo');
+ expect(shipTo).toBeTruthy();
+ const detachButton = screen.getByTestId('detach-schema-sourceBody-Body-button');
+ act(() => {
+ fireEvent.click(detachButton);
+ });
+ const detachConfirmButton = screen.getByTestId('detach-schema-modal-confirm-btn');
+ act(() => {
+ fireEvent.click(detachConfirmButton);
+ });
+ await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ expect(screen.queryByTestId('ShipTo')).toBeFalsy();
+ });
+ });
+
+ describe('Target Body Document', () => {
+ it('should attach and detach schema', async () => {
+ render(
+
+
+
+
+
+
+ ,
+ );
+ const attachButton = await screen.findByTestId('attach-schema-targetBody-Body-button');
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileContent = new File([new Blob([shipOrderXsd])], 'ShipOrder.xsd', { type: 'text/plain' });
+ act(() => {
+ fireEvent.click(attachButton);
+ });
+ const fileInput = screen.getByTestId('attach-schema-file-input');
+ act(() => {
+ fireEvent.change(fileInput, { target: { files: { item: () => fileContent, length: 1, 0: fileContent } } });
+ });
+ const shipTo = await screen.findByText('ShipTo');
+ expect(shipTo).toBeTruthy();
+ const detachButton = screen.getByTestId('detach-schema-targetBody-Body-button');
+ act(() => {
+ fireEvent.click(detachButton);
+ });
+ const detachConfirmButton = screen.getByTestId('detach-schema-modal-confirm-btn');
+ act(() => {
+ fireEvent.click(detachConfirmButton);
+ });
+ await screen.findByTestId('attach-schema-sourceBody-Body-button');
+ expect(screen.queryByTestId('ShipTo')).toBeFalsy();
+ });
+ });
+});
diff --git a/packages/ui/src/components/View/SourceTargetView.tsx b/packages/ui/src/components/View/SourceTargetView.tsx
new file mode 100644
index 000000000..bbfc50dfc
--- /dev/null
+++ b/packages/ui/src/components/View/SourceTargetView.tsx
@@ -0,0 +1,66 @@
+import {
+ Divider,
+ Panel,
+ PanelHeader,
+ PanelMain,
+ Split,
+ SplitItem,
+ Stack,
+ StackItem,
+ Text,
+ TextContent,
+ TextVariants,
+ Truncate,
+} from '@patternfly/react-core';
+import { FunctionComponent, useEffect, useRef } from 'react';
+import { useDataMapper } from '../../hooks/useDataMapper';
+import { MappingLinksContainer } from './MappingLink';
+import './SourceTargetView.scss';
+import { useCanvas } from '../../hooks/useCanvas';
+import { SourcePanel } from './SourcePanel';
+import { SourceTargetDnDHandler } from '../../providers/dnd/SourceTargetDnDHandler';
+import { TargetDocument } from '../Document/TargetDocument';
+
+export const SourceTargetView: FunctionComponent = () => {
+ const { targetBodyDocument } = useDataMapper();
+ const { reloadNodeReferences, setDefaultHandler, setMappingLinkCanvasRef } = useCanvas();
+ const mappingLinkCanvasRef = useRef(null);
+ setMappingLinkCanvasRef(mappingLinkCanvasRef);
+
+ useEffect(() => {
+ setDefaultHandler(new SourceTargetDnDHandler());
+ }, [setDefaultHandler]);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/Visualization/Canvas/Form/CanvasForm.tsx b/packages/ui/src/components/Visualization/Canvas/Form/CanvasForm.tsx
index 1bb12d4f3..1b2c2cdb8 100644
--- a/packages/ui/src/components/Visualization/Canvas/Form/CanvasForm.tsx
+++ b/packages/ui/src/components/Visualization/Canvas/Form/CanvasForm.tsx
@@ -2,6 +2,8 @@ import { Card, CardBody, CardHeader } from '@patternfly/react-core';
import { FunctionComponent, useCallback, useContext, useEffect, useRef } from 'react';
import { VisibleFlowsContext } from '../../../../providers';
import { ErrorBoundary } from '../../../ErrorBoundary';
+import { Anchors } from '../../../registers/anchors';
+import { RenderingAnchor } from '../../../RenderingAnchor/RenderingAnchor';
import { CanvasNode } from '../canvas.models';
import './CanvasForm.scss';
import { CanvasFormBody } from './CanvasFormBody';
@@ -37,6 +39,7 @@ export const CanvasForm: FunctionComponent = ({ selectedNode, o
+
diff --git a/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteGroup.test.tsx b/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteGroup.test.tsx
index 83270ecab..8e2cb2fef 100644
--- a/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteGroup.test.tsx
+++ b/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteGroup.test.tsx
@@ -5,6 +5,8 @@ import {
ActionConfirmationModalContext,
} from '../../../../providers/action-confirmation-modal.provider';
import { ItemDeleteGroup } from './ItemDeleteGroup';
+import { NodeInteractionAddonContext } from '../../../registers/interactions/node-interaction-addon.provider';
+import { IInteractionAddonType } from '../../../registers/interactions/node-interaction-addon.model';
import { EntityType } from '../../../../models/camel/entities';
import { TestProvidersWrapper } from '../../../../stubs';
import { CamelRouteResource } from '../../../../models/camel/camel-route-resource';
@@ -72,4 +74,32 @@ describe('ItemDeleteGroup', () => {
expect(removeEntitySpy).toHaveBeenCalledWith(entityId);
});
});
+
+ it('should process addon when deleting', async () => {
+ const mockDeleteModalContext = {
+ actionConfirmation: () => Promise.resolve(ACTION_ID_CONFIRM),
+ };
+ const mockAddon = jest.fn();
+ const mockNodeInteractionAddonContext = {
+ registerInteractionAddon: jest.fn(),
+ getRegisteredInteractionAddons: (_interaction: IInteractionAddonType, _vizNode: IVisualizationNode) => [
+ { type: IInteractionAddonType.ON_DELETE, activationFn: () => true, callback: mockAddon },
+ ],
+ };
+
+ const wrapper = render(
+
+
+
+
+ ,
+ );
+ act(() => {
+ fireEvent.click(wrapper.getByText('Delete'));
+ });
+
+ await waitFor(() => {
+ expect(mockAddon).toHaveBeenCalled();
+ });
+ });
});
diff --git a/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteStep.test.tsx b/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteStep.test.tsx
index 8e4b5993c..b12a27fb3 100644
--- a/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteStep.test.tsx
+++ b/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemDeleteStep.test.tsx
@@ -1,10 +1,12 @@
-import { fireEvent, render, waitFor } from '@testing-library/react';
+import { act, fireEvent, render, waitFor } from '@testing-library/react';
import { createVisualizationNode, IVisualizationNode } from '../../../../models';
import { ItemDeleteStep } from './ItemDeleteStep';
import {
ACTION_ID_CONFIRM,
ActionConfirmationModalContext,
} from '../../../../providers/action-confirmation-modal.provider';
+import { IInteractionAddonType } from '../../../registers/interactions/node-interaction-addon.model';
+import { NodeInteractionAddonContext } from '../../../registers/interactions/node-interaction-addon.provider';
describe('ItemDeleteStep', () => {
let vizNode: IVisualizationNode;
@@ -58,4 +60,30 @@ describe('ItemDeleteStep', () => {
expect(removeChildSpy).toHaveBeenCalled();
});
});
+
+ it('should process addon when deleting', async () => {
+ const mockDeleteModalContext = {
+ actionConfirmation: () => Promise.resolve(ACTION_ID_CONFIRM),
+ };
+ const mockAddon = jest.fn();
+ const mockNodeInteractionAddonContext = {
+ registerInteractionAddon: jest.fn(),
+ getRegisteredInteractionAddons: (_interaction: IInteractionAddonType, _vizNode: IVisualizationNode) => [
+ { type: IInteractionAddonType.ON_DELETE, activationFn: () => true, callback: mockAddon },
+ ],
+ };
+ const wrapper = render(
+
+
+
+
+ ,
+ );
+ act(() => {
+ fireEvent.click(wrapper.getByText('Delete'));
+ });
+ await waitFor(() => {
+ expect(mockAddon).toHaveBeenCalled();
+ });
+ });
});
diff --git a/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemReplaceStep.test.tsx b/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemReplaceStep.test.tsx
index 4fd40cb9e..3fb570d7b 100644
--- a/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemReplaceStep.test.tsx
+++ b/packages/ui/src/components/Visualization/Custom/ContextMenu/ItemReplaceStep.test.tsx
@@ -1,7 +1,13 @@
-import { fireEvent, render } from '@testing-library/react';
-import { createVisualizationNode } from '../../../../models';
+import { act, fireEvent, render, waitFor } from '@testing-library/react';
+import { createVisualizationNode, DefinedComponent, IVisualizationNode } from '../../../../models';
import { CamelRouteResource } from '../../../../models/camel/camel-route-resource';
-import { ActionConfirmationModalContext } from '../../../../providers/action-confirmation-modal.provider';
+import { NodeInteractionAddonContext } from '../../../registers/interactions/node-interaction-addon.provider';
+import { IInteractionAddonType } from '../../../registers/interactions/node-interaction-addon.model';
+import { CatalogModalContext } from '../../../../providers';
+import {
+ ACTION_ID_CONFIRM,
+ ActionConfirmationModalContext,
+} from '../../../../providers/action-confirmation-modal.provider';
import { EntitiesContext } from '../../../../providers/entities.provider';
import { ItemReplaceStep } from './ItemReplaceStep';
@@ -52,4 +58,38 @@ describe('ItemReplaceStep', () => {
text: 'Step and its children will be lost.',
});
});
+
+ it('should process addon when replacing', async () => {
+ const mockCatalogModalContext = {
+ setIsModalOpen: jest.fn(),
+ getNewComponent: () => Promise.resolve({} as DefinedComponent),
+ };
+ const mockReplaceModalContext = {
+ actionConfirmation: () => Promise.resolve(ACTION_ID_CONFIRM),
+ };
+ const mockAddon = jest.fn();
+ const mockNodeInteractionAddonContext = {
+ registerInteractionAddon: jest.fn(),
+ getRegisteredInteractionAddons: (_interaction: IInteractionAddonType, _vizNode: IVisualizationNode) => [
+ { type: IInteractionAddonType.ON_DELETE, activationFn: () => true, callback: mockAddon },
+ ],
+ };
+ const wrapper = render(
+
+
+
+
+
+
+
+
+ ,
+ );
+ act(() => {
+ fireEvent.click(wrapper.getByText('Replace'));
+ });
+ await waitFor(() => {
+ expect(mockAddon).toHaveBeenCalled();
+ });
+ });
});
diff --git a/packages/ui/src/components/Visualization/Custom/ContextMenu/item-delete-helper.test.ts b/packages/ui/src/components/Visualization/Custom/ContextMenu/item-delete-helper.test.ts
new file mode 100644
index 000000000..b122f4f70
--- /dev/null
+++ b/packages/ui/src/components/Visualization/Custom/ContextMenu/item-delete-helper.test.ts
@@ -0,0 +1,26 @@
+import { processNodeInteractionAddonRecursively } from './item-delete-helper';
+import { createVisualizationNode } from '../../../../models';
+import {
+ IInteractionAddonType,
+ IRegisteredInteractionAddon,
+} from '../../../registers/interactions/node-interaction-addon.model';
+import { ACTION_ID_CONFIRM } from '../../../../providers';
+
+describe('item-delete-helper', () => {
+ describe('processNodeInteractionAddonRecursively', () => {
+ it('should process children', () => {
+ const addons: Record = {};
+ const vizNode = createVisualizationNode('test', {});
+ const childVn = createVisualizationNode('child', {});
+ const mockAddon: IRegisteredInteractionAddon = {
+ type: IInteractionAddonType.ON_DELETE,
+ activationFn: () => true,
+ callback: jest.fn(),
+ };
+ addons[childVn.id] = [mockAddon];
+ vizNode.addChild(childVn);
+ processNodeInteractionAddonRecursively(vizNode, ACTION_ID_CONFIRM, (vn) => addons[vn.id] ?? []);
+ expect(mockAddon.callback).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/packages/ui/src/components/Visualization/Custom/ContextMenu/item-delete-helper.ts b/packages/ui/src/components/Visualization/Custom/ContextMenu/item-delete-helper.ts
new file mode 100644
index 000000000..72149a567
--- /dev/null
+++ b/packages/ui/src/components/Visualization/Custom/ContextMenu/item-delete-helper.ts
@@ -0,0 +1,39 @@
+import { IVisualizationNode } from '../../../../models';
+import {
+ IModalCustomization,
+ IRegisteredInteractionAddon,
+} from '../../../registers/interactions/node-interaction-addon.model';
+
+export const processNodeInteractionAddonRecursively = (
+ parentVizNode: IVisualizationNode,
+ modalAnswer: string | undefined,
+ getAddons: (vizNode: IVisualizationNode) => IRegisteredInteractionAddon[],
+) => {
+ parentVizNode.getChildren()?.forEach((child) => {
+ processNodeInteractionAddonRecursively(child, modalAnswer, getAddons);
+ });
+ getAddons(parentVizNode).forEach((addon) => {
+ addon.callback(parentVizNode, modalAnswer);
+ });
+};
+
+export const findModalCustomizationRecursively = (
+ parentVizNode: IVisualizationNode,
+ getAddons: (vizNode: IVisualizationNode) => IRegisteredInteractionAddon[],
+) => {
+ const modalCustomizations: IModalCustomization[] = [];
+ // going breadth-first while addon processes depth-first... do we want?
+ getAddons(parentVizNode).forEach((addon) => {
+ if (addon.modalCustomization && !modalCustomizations.includes(addon.modalCustomization)) {
+ modalCustomizations.push(addon.modalCustomization);
+ }
+ });
+ parentVizNode.getChildren()?.forEach((child) => {
+ findModalCustomizationRecursively(child, getAddons).forEach((custom) => {
+ if (!modalCustomizations.includes(custom)) {
+ modalCustomizations.push(custom);
+ }
+ });
+ });
+ return modalCustomizations;
+};
diff --git a/packages/ui/src/components/Visualization/Custom/hooks/delete-group.hook.tsx b/packages/ui/src/components/Visualization/Custom/hooks/delete-group.hook.tsx
index 2df9aa4c8..c86152a2f 100644
--- a/packages/ui/src/components/Visualization/Custom/hooks/delete-group.hook.tsx
+++ b/packages/ui/src/components/Visualization/Custom/hooks/delete-group.hook.tsx
@@ -1,25 +1,44 @@
import { useCallback, useContext, useMemo } from 'react';
import { IVisualizationNode } from '../../../../models/visualization/base-visual-entity';
-import { ACTION_ID_CONFIRM, ActionConfirmationModalContext } from '../../../../providers';
+import { ACTION_ID_CANCEL, ActionConfirmationModalContext } from '../../../../providers';
import { EntitiesContext } from '../../../../providers/entities.provider';
+import { NodeInteractionAddonContext } from '../../../registers/interactions/node-interaction-addon.provider';
+import { IInteractionAddonType } from '../../../registers/interactions/node-interaction-addon.model';
+import {
+ findModalCustomizationRecursively,
+ processNodeInteractionAddonRecursively,
+} from '../ContextMenu/item-delete-helper';
export const useDeleteGroup = (vizNode: IVisualizationNode) => {
const entitiesContext = useContext(EntitiesContext);
const deleteModalContext = useContext(ActionConfirmationModalContext);
const flowId = vizNode?.getId();
+ const { getRegisteredInteractionAddons } = useContext(NodeInteractionAddonContext);
+
const onDeleteGroup = useCallback(async () => {
+ const modalCustoms = findModalCustomizationRecursively(vizNode, (vn) =>
+ getRegisteredInteractionAddons(IInteractionAddonType.ON_DELETE, vn),
+ );
+ const additionalModalText = modalCustoms.length > 0 ? modalCustoms[0].additionalText : undefined;
+ const buttonOptions = modalCustoms.length > 0 ? modalCustoms[0].buttonOptions : undefined;
/** Open delete confirm modal, get the confirmation */
- const isDeleteConfirmed = await deleteModalContext?.actionConfirmation({
+ const modalAnswer = await deleteModalContext?.actionConfirmation({
title: "Do you want to delete the '" + vizNode.getId() + "' " + vizNode.getTitle() + '?',
text: 'All steps will be lost.',
+ additionalModalText,
+ buttonOptions,
});
- if (isDeleteConfirmed !== ACTION_ID_CONFIRM) return;
+ if (!modalAnswer || modalAnswer === ACTION_ID_CANCEL) return;
+
+ processNodeInteractionAddonRecursively(vizNode, modalAnswer, (vn) =>
+ getRegisteredInteractionAddons(IInteractionAddonType.ON_DELETE, vn),
+ );
entitiesContext?.camelResource.removeEntity(flowId);
entitiesContext?.updateEntitiesFromCamelResource();
- }, [deleteModalContext, entitiesContext, flowId]);
+ }, [deleteModalContext, entitiesContext, flowId, getRegisteredInteractionAddons, vizNode]);
const value = useMemo(
() => ({
diff --git a/packages/ui/src/components/Visualization/Custom/hooks/delete-step.hook.tsx b/packages/ui/src/components/Visualization/Custom/hooks/delete-step.hook.tsx
index e5b9434fa..71074047e 100644
--- a/packages/ui/src/components/Visualization/Custom/hooks/delete-step.hook.tsx
+++ b/packages/ui/src/components/Visualization/Custom/hooks/delete-step.hook.tsx
@@ -1,28 +1,48 @@
import { useCallback, useContext, useMemo } from 'react';
import { IVisualizationNode } from '../../../../models/visualization/base-visual-entity';
-import { ACTION_ID_CONFIRM, ActionConfirmationModalContext } from '../../../../providers';
+import { ACTION_ID_CANCEL, ACTION_ID_CONFIRM, ActionConfirmationModalContext } from '../../../../providers';
import { EntitiesContext } from '../../../../providers/entities.provider';
+import { NodeInteractionAddonContext } from '../../../registers/interactions/node-interaction-addon.provider';
+import { IInteractionAddonType } from '../../../registers/interactions/node-interaction-addon.model';
+import {
+ findModalCustomizationRecursively,
+ processNodeInteractionAddonRecursively,
+} from '../ContextMenu/item-delete-helper';
export const useDeleteStep = (vizNode: IVisualizationNode) => {
const entitiesContext = useContext(EntitiesContext);
const deleteModalContext = useContext(ActionConfirmationModalContext);
const childrenNodes = vizNode.getChildren();
const hasChildren = childrenNodes !== undefined && childrenNodes.length > 0;
+ const { getRegisteredInteractionAddons } = useContext(NodeInteractionAddonContext);
const onDeleteStep = useCallback(async () => {
- if (hasChildren) {
+ const modalCustoms = findModalCustomizationRecursively(vizNode, (vn) =>
+ getRegisteredInteractionAddons(IInteractionAddonType.ON_DELETE, vn),
+ );
+
+ let modalAnswer: string | undefined = ACTION_ID_CONFIRM;
+ if (hasChildren || modalCustoms.length > 0) {
+ const additionalModalText = modalCustoms.length > 0 ? modalCustoms[0].additionalText : undefined;
+ const buttonOptions = modalCustoms.length > 0 ? modalCustoms[0].buttonOptions : undefined;
/** Open delete confirm modal, get the confirmation */
- const isDeleteConfirmed = await deleteModalContext?.actionConfirmation({
+ modalAnswer = await deleteModalContext?.actionConfirmation({
title: 'Permanently delete step?',
text: 'Step and its children will be lost.',
+ additionalModalText,
+ buttonOptions,
});
- if (isDeleteConfirmed !== ACTION_ID_CONFIRM) return;
+ if (!modalAnswer || modalAnswer === ACTION_ID_CANCEL) return;
}
+ processNodeInteractionAddonRecursively(vizNode, modalAnswer, (vn) =>
+ getRegisteredInteractionAddons(IInteractionAddonType.ON_DELETE, vn),
+ );
+
vizNode.removeChild();
entitiesContext?.updateEntitiesFromCamelResource();
- }, [deleteModalContext, entitiesContext, hasChildren, vizNode]);
+ }, [deleteModalContext, entitiesContext, getRegisteredInteractionAddons, hasChildren, vizNode]);
const value = useMemo(
() => ({
diff --git a/packages/ui/src/components/Visualization/Custom/hooks/replace-step.hook.tsx b/packages/ui/src/components/Visualization/Custom/hooks/replace-step.hook.tsx
index a2424500f..d3d083d29 100644
--- a/packages/ui/src/components/Visualization/Custom/hooks/replace-step.hook.tsx
+++ b/packages/ui/src/components/Visualization/Custom/hooks/replace-step.hook.tsx
@@ -1,7 +1,18 @@
import { useCallback, useContext, useMemo } from 'react';
import { AddStepMode, IVisualizationNode } from '../../../../models/visualization/base-visual-entity';
-import { ACTION_ID_CONFIRM, ActionConfirmationModalContext, CatalogModalContext } from '../../../../providers';
+import {
+ ACTION_ID_CANCEL,
+ ACTION_ID_CONFIRM,
+ ActionConfirmationModalContext,
+ CatalogModalContext,
+} from '../../../../providers';
import { EntitiesContext } from '../../../../providers/entities.provider';
+import { NodeInteractionAddonContext } from '../../../registers/interactions/node-interaction-addon.provider';
+import { IInteractionAddonType } from '../../../registers/interactions/node-interaction-addon.model';
+import {
+ findModalCustomizationRecursively,
+ processNodeInteractionAddonRecursively,
+} from '../ContextMenu/item-delete-helper';
export const useReplaceStep = (vizNode: IVisualizationNode) => {
const entitiesContext = useContext(EntitiesContext);
@@ -9,18 +20,27 @@ export const useReplaceStep = (vizNode: IVisualizationNode) => {
const replaceModalContext = useContext(ActionConfirmationModalContext);
const childrenNodes = vizNode.getChildren();
const hasChildren = childrenNodes !== undefined && childrenNodes.length > 0;
+ const { getRegisteredInteractionAddons } = useContext(NodeInteractionAddonContext);
const onReplaceNode = useCallback(async () => {
if (!vizNode || !entitiesContext) return;
+ const modalCustoms = findModalCustomizationRecursively(vizNode, (vn) =>
+ getRegisteredInteractionAddons(IInteractionAddonType.ON_DELETE, vn),
+ );
+ let modalAnswer: string | undefined = ACTION_ID_CONFIRM;
if (hasChildren) {
+ const additionalModalText = modalCustoms.length > 0 ? modalCustoms[0].additionalText : undefined;
+ const buttonOptions = modalCustoms.length > 0 ? modalCustoms[0].buttonOptions : undefined;
/** Open delete confirm modal, get the confirmation */
- const isReplaceConfirmed = await replaceModalContext?.actionConfirmation({
+ modalAnswer = await replaceModalContext?.actionConfirmation({
title: 'Replace step?',
text: 'Step and its children will be lost.',
+ additionalModalText,
+ buttonOptions,
});
- if (isReplaceConfirmed !== ACTION_ID_CONFIRM) return;
+ if (!modalAnswer || modalAnswer === ACTION_ID_CANCEL) return;
}
/** Find compatible components */
@@ -30,12 +50,16 @@ export const useReplaceStep = (vizNode: IVisualizationNode) => {
const definedComponent = await catalogModalContext?.getNewComponent(catalogFilter);
if (!definedComponent) return;
+ processNodeInteractionAddonRecursively(vizNode, modalAnswer, (vn) =>
+ getRegisteredInteractionAddons(IInteractionAddonType.ON_DELETE, vn),
+ );
+
/** Add new node to the entities */
vizNode.addBaseEntityStep(definedComponent, AddStepMode.ReplaceStep);
/** Update entity */
entitiesContext.updateEntitiesFromCamelResource();
- }, [catalogModalContext, entitiesContext, hasChildren, replaceModalContext, vizNode]);
+ }, [catalogModalContext, entitiesContext, getRegisteredInteractionAddons, hasChildren, replaceModalContext, vizNode]);
const value = useMemo(
() => ({
diff --git a/packages/ui/src/components/Visualization/Visualization.tsx b/packages/ui/src/components/Visualization/Visualization.tsx
index a95d905c1..8c9fb7ff8 100644
--- a/packages/ui/src/components/Visualization/Visualization.tsx
+++ b/packages/ui/src/components/Visualization/Visualization.tsx
@@ -1,10 +1,8 @@
-import { VisualizationProvider } from '@patternfly/react-topology';
-import { FunctionComponent, PropsWithChildren, ReactNode, useMemo } from 'react';
+import { FunctionComponent, PropsWithChildren, ReactNode } from 'react';
import { BaseVisualCamelEntity } from '../../models/visualization/base-visual-entity';
import { CanvasFormTabsProvider } from '../../providers';
import { ErrorBoundary } from '../ErrorBoundary';
import { Canvas } from './Canvas';
-import { ControllerService } from './Canvas/controller.service';
import { CanvasFallback } from './CanvasFallback';
import { ContextToolbar } from './ContextToolbar/ContextToolbar';
import './Visualization.scss';
@@ -16,17 +14,13 @@ interface CanvasProps {
}
export const Visualization: FunctionComponent> = (props) => {
- const controller = useMemo(() => ControllerService.createController(), []);
-
return (
-
-
-
- }>
- } entities={props.entities} />
-
-
-
-
+
+
+ }>
+ } entities={props.entities} />
+
+
+
);
};
diff --git a/packages/ui/src/components/XPath/FunctionIcon.scss b/packages/ui/src/components/XPath/FunctionIcon.scss
new file mode 100644
index 000000000..49714290b
--- /dev/null
+++ b/packages/ui/src/components/XPath/FunctionIcon.scss
@@ -0,0 +1,4 @@
+.function-icon {
+ position: relative;
+ bottom: -3px;
+}
diff --git a/packages/ui/src/components/XPath/FunctionIcon.test.tsx b/packages/ui/src/components/XPath/FunctionIcon.test.tsx
new file mode 100644
index 000000000..761fe9f32
--- /dev/null
+++ b/packages/ui/src/components/XPath/FunctionIcon.test.tsx
@@ -0,0 +1,9 @@
+import { FunctionIcon } from './FunctionIcon';
+import { render, screen } from '@testing-library/react';
+
+describe('FunctionIcon', () => {
+ it('should render', () => {
+ render( );
+ expect(screen.getByText('(x)')).toBeTruthy();
+ });
+});
diff --git a/packages/ui/src/components/XPath/FunctionIcon.tsx b/packages/ui/src/components/XPath/FunctionIcon.tsx
new file mode 100644
index 000000000..65e552d5a
--- /dev/null
+++ b/packages/ui/src/components/XPath/FunctionIcon.tsx
@@ -0,0 +1,12 @@
+import { FunctionComponent } from 'react';
+import './FunctionIcon.scss';
+
+export const FunctionIcon: FunctionComponent = () => {
+ return (
+
+
+ f(x)
+
+
+ );
+};
diff --git a/packages/ui/src/components/XPath/XPathEditor.scss b/packages/ui/src/components/XPath/XPathEditor.scss
new file mode 100644
index 000000000..047daa884
--- /dev/null
+++ b/packages/ui/src/components/XPath/XPathEditor.scss
@@ -0,0 +1,4 @@
+.xpath-editor {
+ width: 100%;
+ height: 100%;
+}
diff --git a/packages/ui/src/components/XPath/XPathEditor.tsx b/packages/ui/src/components/XPath/XPathEditor.tsx
new file mode 100644
index 000000000..33aa36a21
--- /dev/null
+++ b/packages/ui/src/components/XPath/XPathEditor.tsx
@@ -0,0 +1,71 @@
+import { FunctionComponent, useEffect, useRef, useState } from 'react';
+import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
+import './XPathEditor.scss';
+import { xpathEditorConstrufctionOption, xpathEditorTheme } from './monaco-options';
+import { XPathService } from '../../services/xpath/xpath.service';
+import { ExpressionItem } from '../../models/datamapper';
+
+type XPathEditorProps = {
+ mapping: ExpressionItem;
+ onChange: (expression: string | undefined) => void;
+};
+
+export const XPathEditor: FunctionComponent = ({ mapping, onChange }) => {
+ const [editor, setEditor] = useState(null);
+ const monacoEl = useRef(null);
+ const xpathLanguage = XPathService.getMonacoXPathLanguageMetadata();
+
+ useEffect(() => {
+ const previousExpression = editor?.getModel()?.getValue();
+ if (previousExpression !== mapping.expression) editor?.getModel()?.setValue(mapping.expression);
+ }, [editor, mapping.expression]);
+
+ useEffect(() => {
+ if (monacoEl) {
+ setEditor((editor) => {
+ if (editor) return editor;
+
+ monaco.languages.register({ id: xpathLanguage.id });
+ monaco.languages.setMonarchTokensProvider(xpathLanguage.id, xpathLanguage.tokensProvider);
+ monaco.languages.setLanguageConfiguration(xpathLanguage.id, xpathLanguage.languageConfiguration);
+ monaco.languages.registerCompletionItemProvider(xpathLanguage.id, xpathLanguage.completionItemProvider);
+ monaco.languages.registerHoverProvider(xpathLanguage.id, {
+ provideHover: (model, position, token, context) => {
+ console.log(`#### ${model}, ${position}, ${token}, ${context}`);
+ return { contents: [{ value: 'test' }] };
+ },
+ });
+ const themeName = 'datamapperTheme';
+ monaco.editor.defineTheme(themeName, xpathEditorTheme);
+
+ const newEditor = monaco.editor.create(monacoEl.current!, {
+ ...xpathEditorConstrufctionOption,
+ theme: themeName,
+ value: mapping.expression,
+ minimap: {
+ enabled: false,
+ },
+ });
+ newEditor.onDidChangeModelContent((_e) => onChange(newEditor.getModel()?.getValue()));
+ return newEditor;
+ });
+ }
+
+ return () => {
+ if (!monacoEl) {
+ editor?.dispose();
+ setEditor(null);
+ }
+ };
+ }, [
+ editor,
+ mapping.expression,
+ onChange,
+ xpathLanguage.completionItemProvider,
+ xpathLanguage.id,
+ xpathLanguage.languageConfiguration,
+ xpathLanguage.tokensProvider,
+ ]);
+
+ return
;
+};
diff --git a/packages/ui/src/components/XPath/XPathEditorLayout.scss b/packages/ui/src/components/XPath/XPathEditorLayout.scss
new file mode 100644
index 000000000..d840018df
--- /dev/null
+++ b/packages/ui/src/components/XPath/XPathEditorLayout.scss
@@ -0,0 +1,14 @@
+@use '../../styles/dnd';
+
+.menu-item-drag {
+ @include dnd.cursor-grab;
+}
+
+.xpath-editor-layout-grid {
+ height: 90%;
+}
+
+.xpath-editor-layout-tab-content {
+ position: relative;
+ height: 100%;
+}
diff --git a/packages/ui/src/components/XPath/XPathEditorLayout.tsx b/packages/ui/src/components/XPath/XPathEditorLayout.tsx
new file mode 100644
index 000000000..1242541e1
--- /dev/null
+++ b/packages/ui/src/components/XPath/XPathEditorLayout.tsx
@@ -0,0 +1,117 @@
+import {
+ Grid,
+ GridItem,
+ Menu,
+ MenuContent,
+ MenuGroup,
+ MenuItem,
+ Tab,
+ TabContent,
+ Tabs,
+ TabTitleText,
+} from '@patternfly/react-core';
+import { FunctionComponent, MouseEvent, useCallback, useMemo, useState } from 'react';
+import { EditorNodeData, FunctionNodeData } from '../../models/datamapper';
+import { ExpressionItem } from '../../models/datamapper/mapping';
+import { DatamapperDndProvider } from '../../providers/datamapper-dnd.provider';
+import { DataMapperDnDMonitor } from '../../providers/dnd/DataMapperDndMonitor';
+import { ExpressionEditorDnDHandler } from '../../providers/dnd/ExpressionEditorDnDHandler';
+import { FunctionGroup } from '../../services/xpath/xpath-parser';
+import { XPathService } from '../../services/xpath/xpath.service';
+import { DraggableContainer, DroppableContainer } from '../Document/NodeContainer';
+import { SourcePanel } from '../View/SourcePanel';
+import { XPathEditor } from './XPathEditor';
+import './XPathEditorLayout.scss';
+
+type XPathEditorLayoutProps = {
+ mapping: ExpressionItem;
+ onUpdate: () => void;
+};
+
+export const XPathEditorLayout: FunctionComponent = ({ mapping, onUpdate }) => {
+ const dndHandler = useMemo(() => new ExpressionEditorDnDHandler(), []);
+
+ const handleExpressionChange = useCallback(
+ (expression?: string) => {
+ mapping.expression = expression ?? '';
+ onUpdate();
+ },
+ [mapping, onUpdate],
+ );
+ const functionDefinitions = XPathService.getXPathFunctionDefinitions();
+
+ const [activeTabKey, setActiveTabKey] = useState(0);
+ const handleTabClick = (_event: MouseEvent, tabIndex: string | number) => {
+ setActiveTabKey(tabIndex);
+ };
+
+ return (
+
+
+
+
+ Field}
+ className="xpath-editor-layout-tab-content"
+ >
+
+
+
+
+ Function}
+ className="xpath-editor-layout-tab-content"
+ >
+
+
+
+ {Object.keys(functionDefinitions).map((value) => (
+
+ {functionDefinitions[value as FunctionGroup].map((func, index) => (
+
+
+ {func.displayName}
+
+
+ ))}
+
+ ))}
+
+
+
+
+
+
+
+ {/* TODO: non-DnD operation as an alternative
+
+ } />
+
+ */}
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/components/XPath/XPathEditorModal.scss b/packages/ui/src/components/XPath/XPathEditorModal.scss
new file mode 100644
index 000000000..ebf14ee7d
--- /dev/null
+++ b/packages/ui/src/components/XPath/XPathEditorModal.scss
@@ -0,0 +1,9 @@
+.xpath-editor-modal {
+ height: 90%;
+
+ &__header {
+ display: flex;
+ flex-flow: row nowrap;
+ align-items: center;
+ }
+}
diff --git a/packages/ui/src/components/XPath/XPathEditorModal.test.tsx b/packages/ui/src/components/XPath/XPathEditorModal.test.tsx
new file mode 100644
index 000000000..0087c716f
--- /dev/null
+++ b/packages/ui/src/components/XPath/XPathEditorModal.test.tsx
@@ -0,0 +1,42 @@
+import { XPathEditorModal } from './XPathEditorModal';
+import { render, screen } from '@testing-library/react';
+import { BODY_DOCUMENT_ID, ExpressionItem, MappingTree, ValueSelector } from '../../models/datamapper';
+import { DocumentType } from '../../models/datamapper/path';
+import { DataMapperProvider } from '../../providers/datamapper.provider';
+import { DataMapperCanvasProvider } from '../../providers/datamapper-canvas.provider';
+
+describe('XPathEditorModal', () => {
+ it('should render', async () => {
+ window.ResizeObserver = jest.fn().mockImplementation(() => ({
+ observe: jest.fn(),
+ unobserve: jest.fn(),
+ disconnect: jest.fn(),
+ }));
+ const tree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ const mapping: ExpressionItem = new ValueSelector(tree);
+ mapping.expression = '/to/some/field';
+ const onClose = jest.fn();
+ const onUpdate = jest.fn();
+
+ render(
+
+
+
+
+ ,
+ );
+
+ const xpathEditor = screen.getByTestId('xpath-editor');
+ expect(xpathEditor).toBeInTheDocument();
+
+ /* TODO ATM it doesn't render the expression content in Jest
+ const expression = await screen.findByText('/to/some/field');
+ */
+ });
+});
diff --git a/packages/ui/src/components/XPath/XPathEditorModal.tsx b/packages/ui/src/components/XPath/XPathEditorModal.tsx
new file mode 100644
index 000000000..35ad37bca
--- /dev/null
+++ b/packages/ui/src/components/XPath/XPathEditorModal.tsx
@@ -0,0 +1,88 @@
+import { Button, ButtonVariant, List, ListItem, Modal, ModalVariant, Popover } from '@patternfly/react-core';
+import { FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react';
+import { XPathEditorLayout } from './XPathEditorLayout';
+import { ExpressionItem } from '../../models/datamapper';
+import './XPathEditorModal.scss';
+import { ValidatedXPathParseResult, XPathService } from '../../services/xpath/xpath.service';
+import { ExclamationCircleIcon } from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
+import { QuestionCircleIcon } from '@patternfly/react-icons';
+
+type XPathEditorModalProps = {
+ isOpen: boolean;
+ onClose: () => void;
+ title: string;
+ mapping: ExpressionItem;
+ onUpdate: () => void;
+};
+
+export const XPathEditorModal: FunctionComponent = ({
+ isOpen,
+ onClose,
+ title,
+ mapping,
+ onUpdate,
+}) => {
+ const [validationResult, setValidationResult] = useState();
+
+ const validateXPath = useCallback(() => {
+ if (mapping.expression) {
+ const validationResult = XPathService.validate(mapping.expression);
+ setValidationResult(validationResult);
+ } else {
+ setValidationResult(undefined);
+ }
+ }, [mapping.expression]);
+
+ useEffect(() => {
+ validateXPath();
+ }, [validateXPath]);
+
+ const errorContent = useMemo(() => {
+ return {validationResult?.getErrors().map((e) => {e} )}
;
+ }, [validationResult]);
+
+ const header = useMemo(
+ () => (
+
+ XPath Editor: {title}
+
+ Grab a field or a function from the left panel and drag it to the right panel
}>
+ } />
+
+
+ {validationResult && (!validationResult.getCst() || validationResult.dataMapperErrors.length > 0) && (
+
+ }
+ />
+
+ )}
+
+ ),
+ [errorContent, title, validationResult],
+ );
+
+ return (
+
+ Close
+ ,
+ ]}
+ >
+
+
+ );
+};
diff --git a/packages/ui/src/components/XPath/monaco-options.ts b/packages/ui/src/components/XPath/monaco-options.ts
new file mode 100644
index 000000000..4f7df9d0a
--- /dev/null
+++ b/packages/ui/src/components/XPath/monaco-options.ts
@@ -0,0 +1,33 @@
+import * as monaco from 'monaco-editor';
+
+export const xpathEditorTheme: monaco.editor.IStandaloneThemeData = {
+ base: 'vs',
+ inherit: true,
+ rules: [
+ { token: 'identifier', foreground: '0b3c0b', fontStyle: 'bold' },
+ { token: 'action', foreground: '641564', fontStyle: 'italic' },
+ { token: 'number', foreground: '0f2386', fontStyle: 'none' }, // notsecret
+ { token: 'number.float', foreground: '0f2386', fontStyle: 'none' }, // notsecret
+ ],
+ colors: {
+ 'editor.foreground': '#000000',
+ 'editor.background': '#EDF9FA',
+ 'editorCursor.foreground': '#8B0000',
+ 'editor.lineHighlightBackground': '#0000FF20',
+ 'editor.selectionBackground': '#88000030',
+ 'editor.inactiveSelectionBackground': '#88000015',
+ },
+};
+
+export const xpathEditorConstrufctionOption: monaco.editor.IStandaloneEditorConstructionOptions = {
+ language: 'xpath',
+ automaticLayout: true,
+ wordWrap: 'on',
+ scrollBeyondLastColumn: 0,
+ scrollbar: {
+ horizontal: 'hidden',
+ horizontalHasArrows: false,
+ vertical: 'auto',
+ verticalHasArrows: false,
+ },
+};
diff --git a/packages/ui/src/components/registers/RegisterComponents.tsx b/packages/ui/src/components/registers/RegisterComponents.tsx
new file mode 100644
index 000000000..4326fb5b4
--- /dev/null
+++ b/packages/ui/src/components/registers/RegisterComponents.tsx
@@ -0,0 +1,21 @@
+import { FunctionComponent, lazy, PropsWithChildren, useContext, useRef } from 'react';
+import { RenderingAnchorContext } from '../RenderingAnchor/rendering.provider';
+import { IRegisteredComponent } from '../RenderingAnchor/rendering.provider.model';
+import { Anchors } from './anchors';
+import { datamapperActivationFn } from './datamapper.activationfn';
+
+export const RegisterComponents: FunctionComponent = ({ children }) => {
+ const { registerComponent } = useContext(RenderingAnchorContext);
+
+ const componentsToRegister = useRef([
+ {
+ anchor: Anchors.CanvasFormHeader,
+ activationFn: datamapperActivationFn,
+ component: lazy(() => import('../DataMapper/DataMapperLauncher')),
+ },
+ ]);
+
+ componentsToRegister.current.forEach((regComponent) => registerComponent(regComponent));
+
+ return <>{children}>;
+};
diff --git a/packages/ui/src/components/registers/RegisterNodeInteractionAddons.tsx b/packages/ui/src/components/registers/RegisterNodeInteractionAddons.tsx
new file mode 100644
index 000000000..38092632c
--- /dev/null
+++ b/packages/ui/src/components/registers/RegisterNodeInteractionAddons.tsx
@@ -0,0 +1,45 @@
+import { FunctionComponent, PropsWithChildren, useContext, useRef } from 'react';
+import { datamapperActivationFn } from './datamapper.activationfn';
+import { MetadataContext } from '../../providers';
+import {
+ ACTION_ID_DELETE_STEP_AND_FILE,
+ ACTION_ID_DELETE_STEP_ONLY,
+ onDeleteDataMapper,
+} from '../DataMapper/on-delete-datamapper';
+import { NodeInteractionAddonContext } from './interactions/node-interaction-addon.provider';
+import { IInteractionAddonType, IRegisteredInteractionAddon } from './interactions/node-interaction-addon.model';
+import { ButtonVariant } from '@patternfly/react-core';
+
+export const RegisterNodeInteractionAddons: FunctionComponent = ({ children }) => {
+ const metadataApi = useContext(MetadataContext)!;
+ const { registerInteractionAddon } = useContext(NodeInteractionAddonContext);
+ const addonsToRegister = useRef([
+ {
+ type: IInteractionAddonType.ON_DELETE,
+ activationFn: datamapperActivationFn,
+ callback: (vizNode, modalAnswer) => {
+ metadataApi && onDeleteDataMapper(metadataApi, vizNode, modalAnswer);
+ },
+ modalCustomization: {
+ additionalText: 'Do you also want to delete the associated Kaoto DataMapper mapping file (XSLT)?',
+ buttonOptions: {
+ [ACTION_ID_DELETE_STEP_AND_FILE]: {
+ variant: ButtonVariant.danger,
+ buttonText: 'Delete both step and file',
+ },
+ [ACTION_ID_DELETE_STEP_ONLY]: {
+ variant: ButtonVariant.secondary,
+ isDanger: true,
+ buttonText: 'Delete the step, but keep the file',
+ },
+ },
+ },
+ },
+ ]);
+
+ addonsToRegister.current.forEach((interaction) => {
+ registerInteractionAddon(interaction);
+ });
+
+ return <>{children}>;
+};
diff --git a/packages/ui/src/components/registers/anchors.ts b/packages/ui/src/components/registers/anchors.ts
new file mode 100644
index 000000000..ace9fa6cd
--- /dev/null
+++ b/packages/ui/src/components/registers/anchors.ts
@@ -0,0 +1,3 @@
+export const enum Anchors {
+ CanvasFormHeader = 'CanvasFormHeader',
+}
diff --git a/packages/ui/src/components/registers/datamapper.activationfn.test.ts b/packages/ui/src/components/registers/datamapper.activationfn.test.ts
new file mode 100644
index 000000000..e6db9c3e1
--- /dev/null
+++ b/packages/ui/src/components/registers/datamapper.activationfn.test.ts
@@ -0,0 +1,34 @@
+import { Step } from '@kaoto/camel-catalog/types';
+import { IVisualizationNode, KaotoSchemaDefinition } from '../../models';
+import { datamapperRouteDefinitionStub } from '../../stubs/data-mapper';
+import { datamapperActivationFn } from './datamapper.activationfn';
+
+describe('datamapperActivationFn', () => {
+ it('should return false if vizNode is `undefined`', () => {
+ const result = datamapperActivationFn(undefined);
+
+ expect(result).toBe(false);
+ });
+
+ it('should return false if stepDefinition is undefined', () => {
+ const result = datamapperActivationFn({
+ getComponentSchema: () => ({
+ definition: undefined,
+ schema: {} as KaotoSchemaDefinition['schema'],
+ }),
+ } as unknown as IVisualizationNode);
+
+ expect(result).toBe(false);
+ });
+
+ it('should return `true` if stepDefinition is a DataMapper node', () => {
+ const result = datamapperActivationFn({
+ getComponentSchema: () => ({
+ definition: datamapperRouteDefinitionStub.from.steps[0].step as Step,
+ schema: {} as KaotoSchemaDefinition['schema'],
+ }),
+ } as unknown as IVisualizationNode);
+
+ expect(result).toBe(true);
+ });
+});
diff --git a/packages/ui/src/components/registers/datamapper.activationfn.ts b/packages/ui/src/components/registers/datamapper.activationfn.ts
new file mode 100644
index 000000000..352940bad
--- /dev/null
+++ b/packages/ui/src/components/registers/datamapper.activationfn.ts
@@ -0,0 +1,16 @@
+import { IVisualizationNode } from '../../models/visualization/base-visual-entity';
+import { isDataMapperNode } from '../../utils';
+
+export const datamapperActivationFn = (vizNode?: IVisualizationNode): boolean => {
+ if (!vizNode) {
+ return false;
+ }
+
+ const stepDefinition = vizNode.getComponentSchema()?.definition;
+
+ if (!stepDefinition) {
+ return false;
+ }
+
+ return isDataMapperNode(stepDefinition);
+};
diff --git a/packages/ui/src/components/registers/interactions/node-interaction-addon.model.ts b/packages/ui/src/components/registers/interactions/node-interaction-addon.model.ts
new file mode 100644
index 000000000..c24632946
--- /dev/null
+++ b/packages/ui/src/components/registers/interactions/node-interaction-addon.model.ts
@@ -0,0 +1,59 @@
+import { IVisualizationNode } from '../../../models';
+import { ActionConfirmationButtonOption } from '../../../providers';
+
+export enum IInteractionAddonType {
+ ON_DELETE = 'onDelete',
+}
+
+export interface IModalCustomization {
+ buttonOptions: Record;
+ additionalText?: string;
+}
+
+export interface IRegisteredInteractionAddon {
+ type: IInteractionAddonType;
+ activationFn: (vizNode: IVisualizationNode) => boolean;
+ callback: (vizNode: IVisualizationNode, modalAnswer: string | undefined) => void;
+ modalCustomization?: IModalCustomization;
+}
+
+export interface INodeInteractionAddonContext {
+ /**
+ * Register a node interaction addon to be processed on an associated node interaction
+ *
+ * @example
+ * ```tsx
+ * const nodeInteractionAddonContext = useContext(NodeInteractionAddonContext);
+ *
+ * nodeInteractionAddonContext.registerInteractionAddon({
+ * type: IInteractionAddonType.ON_DELETE
+ * activationFn: () => true,
+ * callback: () => { doSomething() }
+ * });
+ * ```
+ * @param addon Registered node interaction addon
+ * @returns void
+ */
+ registerInteractionAddon: (addon: IRegisteredInteractionAddon) => void;
+
+ /**
+ * Get registered interaction addons
+ *
+ * @example
+ * ```tsx
+ * const nodeInteractionAddonContext = useContext(NodeInteractionAddonContext);
+ *
+ * const addons = nodeInteractionAddonContext.getRegisteredInteractionAddons(IInteractionAddonType.ON_DELETE, vizNode);
+ * addons.forEach((addon) => {
+ * addon.callback(vizNode, ACTION_ID_CONFIRM);
+ * });
+ * ```
+ * @param type The interaction addon type enum value
+ * @param vizNode The visualization node to pass to the interaction
+ * @returns `IRegisteredInteraction` An array of registered interactions
+ */
+ getRegisteredInteractionAddons: (
+ type: IInteractionAddonType,
+ vizNode: IVisualizationNode,
+ ) => IRegisteredInteractionAddon[];
+}
diff --git a/packages/ui/src/components/registers/interactions/node-interaction-addon.provider.tsx b/packages/ui/src/components/registers/interactions/node-interaction-addon.provider.tsx
new file mode 100644
index 000000000..fa649bdee
--- /dev/null
+++ b/packages/ui/src/components/registers/interactions/node-interaction-addon.provider.tsx
@@ -0,0 +1,39 @@
+import { createContext, FunctionComponent, PropsWithChildren, useCallback, useMemo, useRef } from 'react';
+import { IVisualizationNode } from '../../../models';
+import {
+ IInteractionAddonType,
+ INodeInteractionAddonContext,
+ IRegisteredInteractionAddon,
+} from './node-interaction-addon.model';
+
+export const NodeInteractionAddonContext = createContext({
+ registerInteractionAddon: () => {},
+ getRegisteredInteractionAddons: () => [],
+});
+
+export const NodeInteractionAddonProvider: FunctionComponent = ({ children }) => {
+ const registeredInteractionAddons = useRef([]);
+
+ const registerInteractionAddon = useCallback((interaction: IRegisteredInteractionAddon) => {
+ registeredInteractionAddons.current.push(interaction);
+ }, []);
+
+ const getRegisteredInteractionAddons = useCallback(
+ (interaction: IInteractionAddonType, vizNode: IVisualizationNode) => {
+ return registeredInteractionAddons.current.filter(
+ (addon) => addon.type === interaction && addon.activationFn(vizNode),
+ );
+ },
+ [],
+ );
+
+ const value = useMemo(
+ () => ({
+ registerInteractionAddon,
+ getRegisteredInteractionAddons,
+ }),
+ [getRegisteredInteractionAddons, registerInteractionAddon],
+ );
+
+ return {children} ;
+};
diff --git a/packages/ui/src/external/RouteVisualization/RouteVisualization.tsx b/packages/ui/src/external/RouteVisualization/RouteVisualization.tsx
index 8cf0c1168..74da71922 100644
--- a/packages/ui/src/external/RouteVisualization/RouteVisualization.tsx
+++ b/packages/ui/src/external/RouteVisualization/RouteVisualization.tsx
@@ -1,4 +1,8 @@
-import React, { useContext, useEffect, useLayoutEffect } from 'react';
+import { VisualizationProvider } from '@patternfly/react-topology';
+import React, { useContext, useEffect, useLayoutEffect, useMemo } from 'react';
+import { Visualization } from '../../components/Visualization';
+import { ControllerService } from '../../components/Visualization/Canvas/controller.service';
+import { useReload } from '../../hooks/reload.hook';
import {
CatalogLoaderProvider,
EntitiesContext,
@@ -8,9 +12,7 @@ import {
VisibleFlowsContext,
VisibleFlowsProvider,
} from '../../providers';
-import { Visualization } from '../../components/Visualization';
import { EventNotifier } from '../../utils';
-import { useReload } from '../../hooks/reload.hook';
const VisibleFlowsVisualization: React.FC<{ className?: string }> = ({ className = '' }) => {
const { visibleFlows, visualFlowsApi } = useContext(VisibleFlowsContext)!;
@@ -26,15 +28,18 @@ const VisibleFlowsVisualization: React.FC<{ className?: string }> = ({ className
const Viz: React.FC<{ catalogUrl: string; className?: string }> = ({ catalogUrl, className = '' }) => {
const ReloadProvider = useReload();
+ const controller = useMemo(() => ControllerService.createController(), []);
return (
-
-
-
+
+
+
+
+
diff --git a/packages/ui/src/hooks/useCanvas.tsx b/packages/ui/src/hooks/useCanvas.tsx
new file mode 100644
index 000000000..8d323556e
--- /dev/null
+++ b/packages/ui/src/hooks/useCanvas.tsx
@@ -0,0 +1,10 @@
+import { CanvasContext, ICanvasContext } from '../providers/datamapper-canvas.provider';
+import { useContext } from 'react';
+
+export const errorMessage = 'useCanvas should be called into CanvasProvider';
+
+export const useCanvas = (): ICanvasContext => {
+ const ctx = useContext(CanvasContext);
+ if (!ctx) throw new Error(errorMessage);
+ return ctx;
+};
diff --git a/packages/ui/src/hooks/useDataMapper.ts b/packages/ui/src/hooks/useDataMapper.ts
new file mode 100644
index 000000000..60393692e
--- /dev/null
+++ b/packages/ui/src/hooks/useDataMapper.ts
@@ -0,0 +1,10 @@
+import { useContext } from 'react';
+import { DataMapperContext, IDataMapperContext } from '../providers/datamapper.provider';
+
+export const errorMessage = 'useDataMapper should be called into DataMapperProvider';
+
+export const useDataMapper = (): IDataMapperContext => {
+ const ctx = useContext(DataMapperContext);
+ if (!ctx) throw new Error(errorMessage);
+ return ctx;
+};
diff --git a/packages/ui/src/hooks/useToggle.ts b/packages/ui/src/hooks/useToggle.ts
new file mode 100644
index 000000000..1a8f27b1c
--- /dev/null
+++ b/packages/ui/src/hooks/useToggle.ts
@@ -0,0 +1,30 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { useCallback, useEffect, useState } from 'react';
+
+type OnToggleReturnType = Promise | boolean;
+
+export function useToggle(initialState: boolean, onToggle?: (toggled: boolean) => OnToggleReturnType) {
+ const [state, setState] = useState(initialState);
+ useEffect(() => setState(initialState), [initialState]);
+ const toggle = useCallback(async () => {
+ const newState = onToggle ? await onToggle(!state) : !state;
+ setState(newState);
+ }, [onToggle, state]);
+ const toggleOff = useCallback(() => setState(false), []);
+ const toggleOn = useCallback(() => setState(true), []);
+ return { state, toggle, toggleOff, toggleOn, setToggle: setState };
+}
diff --git a/packages/ui/src/layout/Navigation.tsx b/packages/ui/src/layout/Navigation.tsx
index e075deedd..80e939e70 100644
--- a/packages/ui/src/layout/Navigation.tsx
+++ b/packages/ui/src/layout/Navigation.tsx
@@ -38,6 +38,11 @@ export const Navigation: FunctionComponent = (props) => {
to: Links.PipeErrorHandler,
hidden: () => !NAVIGATION_ELEMENTS.PipeErrorHandler.includes(currentSchemaType),
},
+ {
+ title: 'DataMapper',
+ to: Links.DataMapper,
+ hidden: () => !NAVIGATION_ELEMENTS.DataMapper.includes(currentSchemaType),
+ },
{ title: 'Catalog', to: Links.Catalog },
],
[currentSchemaType],
@@ -113,4 +118,5 @@ const NAVIGATION_ELEMENTS = {
SourceSchemaType.Pipe,
],
PipeErrorHandler: [SourceSchemaType.KameletBinding, SourceSchemaType.Pipe],
+ DataMapper: [SourceSchemaType.Route, SourceSchemaType.Kamelet],
};
diff --git a/packages/ui/src/layout/__snapshots__/Navigation.test.tsx.snap b/packages/ui/src/layout/__snapshots__/Navigation.test.tsx.snap
index 76987f1d6..aa43ddc6b 100644
--- a/packages/ui/src/layout/__snapshots__/Navigation.test.tsx.snap
+++ b/packages/ui/src/layout/__snapshots__/Navigation.test.tsx.snap
@@ -66,7 +66,7 @@ exports[`Navigation Component navigation sidebar for: Integration 1`] = `
>
@@ -81,7 +81,7 @@ exports[`Navigation Component navigation sidebar for: Integration 1`] = `
@@ -98,7 +98,7 @@ exports[`Navigation Component navigation sidebar for: Integration 1`] = `
@@ -112,7 +112,7 @@ exports[`Navigation Component navigation sidebar for: Integration 1`] = `
@@ -126,7 +126,7 @@ exports[`Navigation Component navigation sidebar for: Integration 1`] = `
@@ -138,9 +138,23 @@ exports[`Navigation Component navigation sidebar for: Integration 1`] = `
Pipe ErrorHandler
+
+
+ DataMapper
+
+
@@ -225,7 +239,7 @@ exports[`Navigation Component navigation sidebar for: Kamelet 1`] = `
>
@@ -240,7 +254,7 @@ exports[`Navigation Component navigation sidebar for: Kamelet 1`] = `
@@ -257,7 +271,7 @@ exports[`Navigation Component navigation sidebar for: Kamelet 1`] = `
@@ -271,7 +285,7 @@ exports[`Navigation Component navigation sidebar for: Kamelet 1`] = `
@@ -285,7 +299,7 @@ exports[`Navigation Component navigation sidebar for: Kamelet 1`] = `
@@ -299,7 +313,21 @@ exports[`Navigation Component navigation sidebar for: Kamelet 1`] = `
+
+ DataMapper
+
+
+
@@ -384,7 +412,7 @@ exports[`Navigation Component navigation sidebar for: KameletBinding 1`] = `
>
@@ -399,7 +427,7 @@ exports[`Navigation Component navigation sidebar for: KameletBinding 1`] = `
@@ -416,7 +444,7 @@ exports[`Navigation Component navigation sidebar for: KameletBinding 1`] = `
@@ -430,7 +458,7 @@ exports[`Navigation Component navigation sidebar for: KameletBinding 1`] = `
@@ -444,7 +472,7 @@ exports[`Navigation Component navigation sidebar for: KameletBinding 1`] = `
@@ -456,9 +484,23 @@ exports[`Navigation Component navigation sidebar for: KameletBinding 1`] = `
Pipe ErrorHandler
+
+
+ DataMapper
+
+
@@ -543,7 +585,7 @@ exports[`Navigation Component navigation sidebar for: Pipe 1`] = `
>
@@ -558,7 +600,7 @@ exports[`Navigation Component navigation sidebar for: Pipe 1`] = `
@@ -575,7 +617,7 @@ exports[`Navigation Component navigation sidebar for: Pipe 1`] = `
@@ -589,7 +631,7 @@ exports[`Navigation Component navigation sidebar for: Pipe 1`] = `
@@ -603,7 +645,7 @@ exports[`Navigation Component navigation sidebar for: Pipe 1`] = `
@@ -615,9 +657,23 @@ exports[`Navigation Component navigation sidebar for: Pipe 1`] = `
Pipe ErrorHandler
+
+
+ DataMapper
+
+
@@ -779,6 +835,20 @@ exports[`Navigation Component navigation sidebar for: Route 1`] = `
data-ouia-component-id="OUIA-Generated-NavItem-6"
data-ouia-component-type="PF5/NavItem"
data-ouia-safe="true"
+ >
+
+ DataMapper
+
+
+
IField;
+}
+
+export interface ITypeFragment {
+ fields: IField[];
+ namedTypeFragmentRefs: string[];
+}
+
+export interface IDocument {
+ documentType: DocumentType;
+ documentId: string;
+ name: string;
+ schemaType: string;
+ fields: IField[];
+ path: NodePath;
+ namedTypeFragments: Record;
+ totalFieldCount: number;
+ isNamespaceAware: boolean;
+}
+
+export abstract class BaseDocument implements IDocument {
+ constructor(
+ public documentType: DocumentType,
+ public documentId: string,
+ ) {
+ this.path = NodePath.fromDocument(documentType, documentId);
+ }
+ fields: IField[] = [];
+ name: string = '';
+ schemaType = '';
+ path: NodePath;
+ namedTypeFragments: Record = {};
+ abstract totalFieldCount: number;
+ abstract isNamespaceAware: boolean;
+}
+
+export class PrimitiveDocument extends BaseDocument implements IField {
+ constructor(documentType: DocumentType, documentId: string) {
+ super(documentType, documentId);
+ this.name = this.documentId;
+ this.id = this.documentId;
+ this.path = NodePath.fromDocument(documentType, documentId);
+ }
+
+ ownerDocument: IDocument = this;
+ defaultValue: string | null = null;
+ isAttribute: boolean = false;
+ maxOccurs: number = 1;
+ minOccurs: number = 0;
+ namespacePrefix: string | null = null;
+ namespaceURI: string | null = null;
+ parent: IParentType = this;
+ type = Types.AnyType;
+ path: NodePath;
+ id: string;
+ namedTypeFragmentRefs = [];
+ totalFieldCount = 1;
+ isNamespaceAware = false;
+ adopt = () => this;
+}
+
+export class BaseField implements IField {
+ constructor(
+ public parent: IParentType,
+ public ownerDocument: IDocument,
+ public name: string,
+ ) {
+ this.id = getCamelRandomId(`field-${this.name}`, 4);
+ this.path = NodePath.childOf(parent.path, this.id);
+ }
+
+ id: string;
+ path: NodePath;
+ fields: IField[] = [];
+ isAttribute: boolean = false;
+ type = Types.AnyType;
+ minOccurs: number = DEFAULT_MIN_OCCURS;
+ maxOccurs: number = DEFAULT_MAX_OCCURS;
+ defaultValue: string | null = null;
+ namespacePrefix: string | null = null;
+ namespaceURI: string | null = null;
+ namedTypeFragmentRefs: string[] = [];
+ adopt = (parent: IField) => {
+ const adopted = new BaseField(parent, parent.ownerDocument, this.name);
+ adopted.isAttribute = this.isAttribute;
+ adopted.type = this.type;
+ adopted.minOccurs = this.minOccurs;
+ adopted.maxOccurs = this.maxOccurs;
+ adopted.defaultValue = this.defaultValue;
+ adopted.namespacePrefix = this.namespacePrefix;
+ adopted.namespaceURI = this.namespaceURI;
+ adopted.namedTypeFragmentRefs = this.namedTypeFragmentRefs;
+ adopted.fields = this.fields.map((child) => child.adopt(adopted));
+ parent.fields.push(adopted);
+ return adopted;
+ };
+}
+
+export enum DocumentDefinitionType {
+ Primitive = 'Primitive',
+ XML_SCHEMA = 'XML Schema',
+}
+
+export class DocumentDefinition {
+ constructor(
+ public documentType: DocumentType,
+ public definitionType: DocumentDefinitionType,
+ public name?: string,
+ public definitionFiles?: Record,
+ ) {
+ if (!definitionFiles) this.definitionFiles = {};
+ }
+}
+
+export class DocumentInitializationModel {
+ constructor(
+ public sourceParameters: Record = {},
+ public sourceBody: DocumentDefinition = {
+ documentType: DocumentType.SOURCE_BODY,
+ definitionType: DocumentDefinitionType.Primitive,
+ },
+ public targetBody: DocumentDefinition = {
+ documentType: DocumentType.TARGET_BODY,
+ definitionType: DocumentDefinitionType.Primitive,
+ },
+ ) {}
+}
diff --git a/packages/ui/src/models/datamapper/index.ts b/packages/ui/src/models/datamapper/index.ts
new file mode 100644
index 000000000..29d39d62d
--- /dev/null
+++ b/packages/ui/src/models/datamapper/index.ts
@@ -0,0 +1,6 @@
+export * from './document';
+export * from './mapping';
+export * from './path';
+export * from './types';
+export * from './view';
+export * from './visualization';
diff --git a/packages/ui/src/models/datamapper/mapping.ts b/packages/ui/src/models/datamapper/mapping.ts
new file mode 100644
index 000000000..ae96b8ab3
--- /dev/null
+++ b/packages/ui/src/models/datamapper/mapping.ts
@@ -0,0 +1,183 @@
+import { IField } from './document';
+import { DocumentType, NodePath, Path } from './path';
+import { Types } from './types';
+import { getCamelRandomId } from '../../camel-utils/camel-random-id';
+
+export type MappingParentType = MappingTree | MappingItem;
+
+export class MappingTree {
+ constructor(documentType: DocumentType, documentId: string) {
+ this.nodePath = NodePath.fromDocument(documentType, documentId);
+ }
+ children: MappingItem[] = [];
+ nodePath: NodePath;
+ contextPath?: Path;
+ namespaceMap: { [prefix: string]: string } = {};
+}
+
+export abstract class MappingItem {
+ constructor(
+ public parent: MappingParentType,
+ public name: string,
+ public id: string,
+ ) {
+ this.mappingTree = parent instanceof MappingTree ? parent : parent.mappingTree;
+ }
+ mappingTree: MappingTree;
+ children: MappingItem[] = [];
+ get nodePath(): NodePath {
+ return NodePath.childOf(this.parent.nodePath, this.id);
+ }
+ get contextPath(): Path | undefined {
+ return this.parent.contextPath;
+ }
+ protected abstract doClone(): MappingItem;
+ clone(): MappingItem {
+ const cloned = this.doClone();
+ cloned.children = this.children.map((c) => c.clone());
+ return cloned;
+ }
+}
+
+export class FieldItem extends MappingItem {
+ constructor(
+ public parent: MappingParentType,
+ public field: IField,
+ ) {
+ super(parent, 'field-' + field.name, field.id);
+ }
+ doClone() {
+ return new FieldItem(this.parent, this.field);
+ }
+}
+
+export abstract class ConditionItem extends MappingItem {
+ constructor(
+ public parent: MappingParentType,
+ public name: string,
+ ) {
+ super(parent, name, getCamelRandomId(name, 4));
+ }
+ readonly isCondition = true;
+}
+
+export abstract class ExpressionItem extends ConditionItem {
+ constructor(
+ public parent: MappingParentType,
+ public name: string,
+ ) {
+ super(parent, name);
+ }
+ expression = '';
+ clone() {
+ const cloned = super.clone() as ExpressionItem;
+ cloned.expression = this.expression;
+ return cloned;
+ }
+}
+
+export class IfItem extends ExpressionItem {
+ constructor(public parent: MappingParentType) {
+ super(parent, 'if');
+ }
+ doClone() {
+ return new IfItem(this.parent);
+ }
+}
+
+export class ChooseItem extends ConditionItem {
+ constructor(
+ public parent: MappingParentType,
+ public field?: IField,
+ ) {
+ super(parent, 'choose');
+ }
+ get when() {
+ return this.children.filter((c) => c instanceof WhenItem) as WhenItem[];
+ }
+ get otherwise() {
+ return this.children.find((c) => c instanceof OtherwiseItem) as OtherwiseItem;
+ }
+ doClone() {
+ return new ChooseItem(this.parent, this.field);
+ }
+}
+
+export class WhenItem extends ExpressionItem {
+ constructor(public parent: MappingParentType) {
+ super(parent, 'when');
+ }
+ doClone() {
+ return new WhenItem(this.parent);
+ }
+}
+
+export class OtherwiseItem extends ConditionItem {
+ constructor(public parent: MappingParentType) {
+ super(parent, 'otherwise');
+ }
+ doClone() {
+ return new OtherwiseItem(this.parent);
+ }
+}
+
+export class ForEachItem extends ExpressionItem {
+ constructor(public parent: MappingParentType) {
+ super(parent, 'for-each');
+ }
+ get contextPath() {
+ return new Path(this.expression, this.parent.contextPath);
+ }
+ sortItems: SortItem[] = [];
+ doClone() {
+ const cloned = new ForEachItem(this.parent);
+ cloned.sortItems = this.sortItems.map((sort) => {
+ return {
+ expression: sort.expression,
+ order: sort.order,
+ } as SortItem;
+ });
+ return cloned;
+ }
+}
+
+export class SortItem {
+ expression: string = '';
+ order: 'ascending' | 'descending' = 'ascending';
+}
+
+export enum ValueType {
+ VALUE = 'value',
+ CONTAINER = 'container',
+ ATTRIBUTE = 'attribute',
+}
+
+export class ValueSelector extends ExpressionItem {
+ constructor(
+ public parent: MappingParentType,
+ public valueType: ValueType = ValueType.VALUE,
+ ) {
+ super(parent, 'value');
+ }
+ doClone() {
+ return new ValueSelector(this.parent, this.valueType);
+ }
+}
+
+export interface IFunctionDefinition {
+ name: string;
+ displayName: string;
+ description: string;
+ returnType: Types;
+ returnCollection?: boolean;
+ arguments: IFunctionArgumentDefinition[];
+}
+
+export interface IFunctionArgumentDefinition {
+ name: string;
+ type: Types;
+ displayName: string;
+ description: string;
+ minOccurs: number;
+ maxOccurs: number;
+}
diff --git a/packages/ui/src/models/datamapper/metadata.ts b/packages/ui/src/models/datamapper/metadata.ts
new file mode 100644
index 000000000..8043b4fea
--- /dev/null
+++ b/packages/ui/src/models/datamapper/metadata.ts
@@ -0,0 +1,13 @@
+import { DocumentDefinitionType } from './document';
+
+export interface IDocumentMetadata {
+ type: DocumentDefinitionType;
+ filePath: string[];
+}
+
+export interface IDataMapperMetadata {
+ xsltPath: string;
+ sourceParameters: Record;
+ sourceBody: IDocumentMetadata;
+ targetBody: IDocumentMetadata;
+}
diff --git a/packages/ui/src/models/datamapper/path.ts b/packages/ui/src/models/datamapper/path.ts
new file mode 100644
index 000000000..9ca600bd9
--- /dev/null
+++ b/packages/ui/src/models/datamapper/path.ts
@@ -0,0 +1,99 @@
+export enum DocumentType {
+ SOURCE_BODY = 'sourceBody',
+ TARGET_BODY = 'targetBody',
+ PARAM = 'param',
+}
+
+export class NodePath {
+ documentType: DocumentType = DocumentType.SOURCE_BODY;
+ documentId: string = '';
+ pathSegments: string[] = [];
+
+ constructor(expression?: string) {
+ if (!expression) return;
+ const parts = expression.split('://');
+ if (parts.length < 2) return;
+ const index = parts[0].indexOf(':');
+ this.documentType = (index !== -1 ? parts[0].substring(0, index) : parts[0]) as DocumentType;
+ this.documentId = index !== -1 ? parts[0].substring(index + 1) : this.documentId;
+ this.pathSegments = parts[1].length > 0 ? parts[1].split('/') : [];
+ }
+
+ toString() {
+ const beforePath = `${this.documentType}:${this.documentId}://`;
+ return this.pathSegments.length > 0 ? `${beforePath}${this.pathSegments.join('/')}` : beforePath;
+ }
+
+ static fromDocument(documentType: DocumentType, documentId: string) {
+ return new NodePath(`${documentType}:${documentId}://`);
+ }
+
+ static childOf(parent: NodePath, childSegment: string) {
+ const answer = new NodePath();
+ answer.documentType = parent.documentType;
+ answer.documentId = parent.documentId;
+ answer.pathSegments = [...parent.pathSegments, childSegment];
+ return answer;
+ }
+}
+
+export class Path {
+ constructor(
+ public readonly expression: string,
+ public readonly parent?: Path,
+ ) {
+ this.isRelative = true;
+ let remainingExpression = this.expression;
+ if (remainingExpression.startsWith('/')) {
+ this.isRelative = false;
+ remainingExpression = remainingExpression.substring(1);
+ }
+ if (remainingExpression.endsWith('/'))
+ remainingExpression = remainingExpression.substring(0, remainingExpression.length - 1);
+ if (remainingExpression.startsWith('$')) {
+ this.isRelative = false;
+ const pos = remainingExpression.indexOf('/');
+ this.parameterName = pos !== -1 ? remainingExpression.substring(1, pos) : remainingExpression.substring(1);
+ remainingExpression = pos !== -1 ? remainingExpression.substring(pos + 1) : '';
+ }
+ this.pathSegments = remainingExpression.split('/').map((segmentString) => new PathSegment(segmentString));
+ }
+
+ toString() {
+ const prefix = this.parameterName ? `$${this.parameterName}/` : this.isRelative ? '' : '/';
+ return this.pathSegments.length > 0 ? `${prefix}${this.pathSegments.join('/')}` : prefix;
+ }
+
+ toAbsolutePathString(): string {
+ return this.isRelative ? this.parent?.toAbsolutePathString() + '/' + this.toString() : this.toString();
+ }
+
+ child(segment: string) {
+ if (segment.startsWith('/')) segment = segment.substring(1);
+ if (segment.endsWith('/')) segment = segment.substring(0, segment.length - 1);
+ return new NodePath(this.toString() + '/' + segment);
+ }
+
+ isRelative: boolean;
+ parameterName?: string;
+ pathSegments: PathSegment[];
+}
+
+export class PathSegment {
+ constructor(public readonly expression: string) {
+ const splitted = expression.split(':');
+ if (splitted.length > 1) {
+ this.prefix = splitted[0];
+ this.name = splitted[1];
+ } else {
+ this.name = splitted[0];
+ }
+ }
+
+ toString() {
+ return this.prefix ? `${this.prefix}:${this.name}` : this.name;
+ }
+
+ prefix?: string;
+ name: string;
+}
diff --git a/packages/ui/src/models/datamapper/types.ts b/packages/ui/src/models/datamapper/types.ts
new file mode 100644
index 000000000..cc47749f5
--- /dev/null
+++ b/packages/ui/src/models/datamapper/types.ts
@@ -0,0 +1,29 @@
+/**
+ * The data types mapped from XML Schema +.
+ */
+export enum Types {
+ AnyAtomicType = 'anyAtomicType',
+ AnyType = 'anyType',
+ AnyURI = 'anyURI',
+ String = 'string',
+ Float = 'float',
+ Double = 'double',
+ Integer = 'integer',
+ Decimal = 'decimal',
+ Boolean = 'boolean',
+ Date = 'date',
+ DateTime = 'dateTime',
+ Time = 'time',
+ QName = 'QName',
+ Duration = 'duration',
+ DayTimeDuration = 'dayTimeDuration',
+ NCName = 'NCName',
+ // not XSD predefined but appear in XPath function signature
+ Numeric = 'numeric',
+ Item = 'item()',
+ Element = 'element()',
+ Node = 'node()',
+ DocumentNode = 'document-node()',
+ // custom types
+ Container = 'Container',
+}
diff --git a/packages/ui/src/models/datamapper/view.ts b/packages/ui/src/models/datamapper/view.ts
new file mode 100644
index 000000000..3305846a8
--- /dev/null
+++ b/packages/ui/src/models/datamapper/view.ts
@@ -0,0 +1,5 @@
+export enum CanvasView {
+ SOURCE_TARGET = 'SourceTarget',
+ MAPPING_TABLE = 'MappingTable',
+ NAMESPACE_TABLE = 'NamespaceTable',
+}
diff --git a/packages/ui/src/models/datamapper/visualization.test.ts b/packages/ui/src/models/datamapper/visualization.test.ts
new file mode 100644
index 000000000..10eb7136b
--- /dev/null
+++ b/packages/ui/src/models/datamapper/visualization.test.ts
@@ -0,0 +1,36 @@
+import { DocumentType, NodePath } from './path';
+
+describe('visualization.ts', () => {
+ describe('NodeIdentifier', () => {
+ it('should represent a document root', () => {
+ const id = new NodePath('sourceBody:docId://');
+ expect(id.documentType).toBe(DocumentType.SOURCE_BODY);
+ expect(id.documentId).toBe('docId');
+ expect(id.pathSegments.length).toBe(0);
+ });
+
+ it('should handle without Document ID', () => {
+ const id = new NodePath('sourceBody://a/b/c');
+ expect(id.documentType).toBe(DocumentType.SOURCE_BODY);
+ expect(id.documentId).toBe('');
+ expect(id.pathSegments.length).toBe(3);
+ const id2 = new NodePath('sourceBody:://a/b/c');
+ expect(id2.documentType).toBe(DocumentType.SOURCE_BODY);
+ expect(id2.documentId).toBe('');
+ expect(id2.pathSegments.length).toBe(3);
+ });
+
+ it('should handle a colon in the Document ID', () => {
+ const id = new NodePath('param:global:someGlobalVariable://d/e/f');
+ expect(id.documentType).toBe(DocumentType.PARAM);
+ expect(id.documentId).toBe('global:someGlobalVariable');
+ expect(id.pathSegments.length).toBe(3);
+ });
+
+ it('should generate a same string', () => {
+ const expression = 'sourceBody:docId://g/h/i';
+ const id = new NodePath(expression);
+ expect(id.toString()).toEqual(expression);
+ });
+ });
+});
diff --git a/packages/ui/src/models/datamapper/visualization.ts b/packages/ui/src/models/datamapper/visualization.ts
new file mode 100644
index 000000000..095915d36
--- /dev/null
+++ b/packages/ui/src/models/datamapper/visualization.ts
@@ -0,0 +1,134 @@
+import { IDocument, IField, PrimitiveDocument } from './document';
+import { ExpressionItem, FieldItem, IFunctionDefinition, MappingItem, MappingParentType, MappingTree } from './mapping';
+import { DocumentType, NodePath } from './path';
+
+export interface NodeData {
+ title: string;
+ id: string;
+ path: NodePath;
+ isSource: boolean;
+ isPrimitive: boolean;
+}
+
+export interface TargetNodeData extends NodeData {
+ mappingTree: MappingTree;
+ mapping?: MappingParentType;
+}
+
+export type SourceNodeDataType = DocumentNodeData | FieldNodeData;
+export type TargetNodeDataType = TargetDocumentNodeData | TargetFieldNodeData;
+
+export class DocumentNodeData implements NodeData {
+ constructor(document: IDocument) {
+ this.title = document.documentId;
+ this.id = `doc-${document.documentType}-${document.documentId}`;
+ this.path = NodePath.fromDocument(document.documentType, document.documentId);
+ this.document = document;
+ this.isSource = document.documentType !== DocumentType.TARGET_BODY;
+ this.isPrimitive = document instanceof PrimitiveDocument;
+ }
+
+ document: IDocument;
+ title: string;
+ id: string;
+ path: NodePath;
+ isSource: boolean;
+ isPrimitive: boolean;
+}
+
+export class TargetDocumentNodeData extends DocumentNodeData implements TargetNodeData {
+ constructor(document: IDocument, mappingTree: MappingTree) {
+ super(document);
+ this.mappingTree = mappingTree;
+ this.mapping = mappingTree;
+ }
+ mappingTree: MappingTree;
+ mapping: MappingTree;
+}
+
+export class FieldNodeData implements NodeData {
+ constructor(
+ public parent: NodeData,
+ public field: IField,
+ ) {
+ this.title = field.name;
+ this.id = field.id;
+ this.path = NodePath.childOf(parent.path, this.id);
+ this.isSource = parent.isSource;
+ this.isPrimitive = parent.isPrimitive;
+ }
+
+ title: string;
+ id: string;
+ path: NodePath;
+ isSource: boolean;
+ isPrimitive: boolean;
+}
+
+export class TargetFieldNodeData extends FieldNodeData implements TargetNodeData {
+ constructor(
+ public parent: TargetNodeData,
+ public field: IField,
+ public mapping?: FieldItem,
+ ) {
+ super(parent, field);
+ this.mappingTree = parent.mappingTree;
+ }
+ mappingTree: MappingTree;
+}
+
+export class MappingNodeData implements TargetNodeData {
+ constructor(
+ public parent: TargetNodeData,
+ public mapping: MappingItem,
+ ) {
+ this.title = mapping.name;
+ this.id = mapping.id;
+ this.path = NodePath.childOf(parent.path, this.id);
+ this.isPrimitive = parent.isPrimitive;
+ this.mappingTree = parent.mappingTree;
+ }
+
+ title: string;
+ id: string;
+ path: NodePath;
+ isSource = false;
+ isPrimitive: boolean;
+ mappingTree: MappingTree;
+}
+
+class SimpleNodePath extends NodePath {
+ constructor(public path: string) {
+ super();
+ }
+ toString() {
+ return this.path;
+ }
+}
+export class EditorNodeData implements NodeData {
+ constructor(public mapping: ExpressionItem) {}
+ id: string = 'editor';
+ isPrimitive: boolean = false;
+ isSource: boolean = false;
+ path: NodePath = new SimpleNodePath('Editor');
+ title: string = 'Editor';
+}
+
+export class FunctionNodeData implements NodeData {
+ constructor(public functionDefinition: IFunctionDefinition) {
+ this.id = functionDefinition.name;
+ this.title = functionDefinition.displayName;
+ this.path = new SimpleNodePath('Func:' + functionDefinition.name);
+ }
+
+ id: string;
+ isPrimitive: boolean = false;
+ isSource: boolean = true;
+ path: NodePath;
+ title: string;
+}
+
+export interface IMappingLink {
+ sourceNodePath: string;
+ targetNodePath: string;
+}
diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/datamapper-node-mapper.test.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/datamapper-node-mapper.test.ts
new file mode 100644
index 000000000..c8821dd78
--- /dev/null
+++ b/packages/ui/src/models/visualization/flows/nodes/mappers/datamapper-node-mapper.test.ts
@@ -0,0 +1,53 @@
+import { Step } from '@kaoto/camel-catalog/types';
+import { datamapperRouteDefinitionStub as datamapperRouteDefinitionStub } from '../../../../../stubs/data-mapper';
+import { RootNodeMapper } from '../root-node-mapper';
+import { DataMapperNodeMapper } from './datamapper-node-mapper';
+import { noopNodeMapper } from './testing/noop-node-mapper';
+
+describe('DataMapperNodeMapper', () => {
+ let mapper: DataMapperNodeMapper;
+ let rootNodeMapper: RootNodeMapper;
+ const routeDefinition = datamapperRouteDefinitionStub;
+ const path = 'from.steps.0.step';
+
+ beforeEach(() => {
+ rootNodeMapper = new RootNodeMapper();
+ rootNodeMapper.registerDefaultMapper(mapper);
+ rootNodeMapper.registerMapper('log', noopNodeMapper);
+
+ mapper = new DataMapperNodeMapper(rootNodeMapper);
+ });
+
+ it('should not return any children', () => {
+ const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'step' }, routeDefinition);
+
+ expect(vizNode.getChildren()).toBeUndefined();
+ });
+
+ describe('isDataMapperNode', () => {
+ it('should return true if it has the right id and a xslt component', () => {
+ const stepDefinition = routeDefinition.from.steps[0].step as Step;
+ const isDataMapperNode = DataMapperNodeMapper.isDataMapperNode(stepDefinition);
+
+ expect(isDataMapperNode).toBe(true);
+ });
+
+ it('should return false if it has the right id but no xslt component', () => {
+ const stepDefinition = routeDefinition.from.steps[0].step as Step;
+ stepDefinition.steps![0].to = { uri: 'direct:log' };
+
+ const isDataMapperNode = DataMapperNodeMapper.isDataMapperNode(stepDefinition);
+
+ expect(isDataMapperNode).toBe(false);
+ });
+
+ it('should return false if it has no id but a xslt component', () => {
+ const stepDefinition = routeDefinition.from.steps[0].step as Step;
+ stepDefinition.id = 'step-1234';
+
+ const isDataMapperNode = DataMapperNodeMapper.isDataMapperNode(stepDefinition);
+
+ expect(isDataMapperNode).toBe(false);
+ });
+ });
+});
diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/datamapper-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/datamapper-node-mapper.ts
new file mode 100644
index 000000000..334a75187
--- /dev/null
+++ b/packages/ui/src/models/visualization/flows/nodes/mappers/datamapper-node-mapper.ts
@@ -0,0 +1,33 @@
+import { Step } from '@kaoto/camel-catalog/types';
+import { DATAMAPPER_ID_PREFIX, isDataMapperNode } from '../../../../../utils';
+import { NodeIconResolver, NodeIconType } from '../../../../../utils/node-icon-resolver';
+import { IVisualizationNode } from '../../../base-visual-entity';
+import { createVisualizationNode } from '../../../visualization-node';
+import { CamelRouteVisualEntityData, ICamelElementLookupResult } from '../../support/camel-component-types';
+import { BaseNodeMapper } from './base-node-mapper';
+
+export class DataMapperNodeMapper extends BaseNodeMapper {
+ getVizNodeFromProcessor(
+ path: string,
+ _componentLookup: ICamelElementLookupResult,
+ _entityDefinition: unknown,
+ ): IVisualizationNode {
+ const processorName = DATAMAPPER_ID_PREFIX;
+
+ const data: CamelRouteVisualEntityData = {
+ path,
+ icon: NodeIconResolver.getIcon(processorName, NodeIconType.EIP),
+ processorName: DATAMAPPER_ID_PREFIX,
+ isGroup: false,
+ };
+
+ const vizNode = createVisualizationNode(processorName, data);
+ vizNode.setTitle('Kaoto data mapper');
+
+ return vizNode;
+ }
+
+ static isDataMapperNode(stepDefinition: Step): boolean {
+ return isDataMapperNode(stepDefinition);
+ }
+}
diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/step-node-mapper.test.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/step-node-mapper.test.ts
new file mode 100644
index 000000000..bcad1f671
--- /dev/null
+++ b/packages/ui/src/models/visualization/flows/nodes/mappers/step-node-mapper.test.ts
@@ -0,0 +1,60 @@
+import { RouteDefinition } from '@kaoto/camel-catalog/types';
+import { parse } from 'yaml';
+import { DATAMAPPER_ID_PREFIX } from '../../../../../utils';
+import { RootNodeMapper } from '../root-node-mapper';
+import { DataMapperNodeMapper } from './datamapper-node-mapper';
+import { StepNodeMapper } from './step-node-mapper';
+import { noopNodeMapper } from './testing/noop-node-mapper';
+
+describe('StepNodeMapper', () => {
+ let mapper: StepNodeMapper;
+ let routeDefinition: RouteDefinition;
+ let rootNodeMapper: RootNodeMapper;
+ const path = 'from.steps.0.step';
+
+ beforeEach(() => {
+ rootNodeMapper = new RootNodeMapper();
+ rootNodeMapper.registerDefaultMapper(mapper);
+ rootNodeMapper.registerMapper('log', noopNodeMapper);
+ rootNodeMapper.registerMapper(DATAMAPPER_ID_PREFIX, noopNodeMapper);
+
+ mapper = new StepNodeMapper(rootNodeMapper);
+
+ routeDefinition = parse(`
+ from:
+ id: from-8888
+ uri: direct:start
+ parameters: {}
+ steps:
+ - step:
+ id: step-1234
+ steps:
+ - log:
+ id: log-1234
+ message: \${body}`);
+ });
+
+ it('should return children', () => {
+ const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'step' }, routeDefinition);
+
+ expect(vizNode.getChildren()).toHaveLength(1);
+ });
+
+ it('should verify if this step node is a Kaoto DataMapper one', () => {
+ const dataMapperNodeSpy = jest.spyOn(DataMapperNodeMapper, 'isDataMapperNode');
+
+ mapper.getVizNodeFromProcessor(path, { processorName: 'step' }, routeDefinition);
+
+ expect(dataMapperNodeSpy).toHaveBeenCalledWith(routeDefinition.from.steps[0].step);
+ });
+
+ it('should delegate to the rootNodeMapper if this step node is a Kaoto DataMapper one', () => {
+ const rootNodeMapperSpy = jest.spyOn(rootNodeMapper, 'getVizNodeFromProcessor');
+ const dataMapperNodeSpy = jest.spyOn(DataMapperNodeMapper, 'isDataMapperNode');
+ dataMapperNodeSpy.mockReturnValue(true);
+
+ mapper.getVizNodeFromProcessor(path, { processorName: 'step' }, routeDefinition);
+
+ expect(rootNodeMapperSpy).toHaveBeenCalledWith(path, { processorName: DATAMAPPER_ID_PREFIX }, routeDefinition);
+ });
+});
diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/step-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/step-node-mapper.ts
new file mode 100644
index 000000000..ddb7dbd31
--- /dev/null
+++ b/packages/ui/src/models/visualization/flows/nodes/mappers/step-node-mapper.ts
@@ -0,0 +1,45 @@
+import { ProcessorDefinition, Step } from '@kaoto/camel-catalog/types';
+import { DATAMAPPER_ID_PREFIX, getValue } from '../../../../../utils';
+import { NodeIconResolver, NodeIconType } from '../../../../../utils/node-icon-resolver';
+import { IVisualizationNode } from '../../../base-visual-entity';
+import { createVisualizationNode } from '../../../visualization-node';
+import { CamelRouteVisualEntityData, ICamelElementLookupResult } from '../../support/camel-component-types';
+import { BaseNodeMapper } from './base-node-mapper';
+import { DataMapperNodeMapper } from './datamapper-node-mapper';
+
+export class StepNodeMapper extends BaseNodeMapper {
+ getVizNodeFromProcessor(
+ path: string,
+ _componentLookup: ICamelElementLookupResult,
+ entityDefinition: unknown,
+ ): IVisualizationNode {
+ const processorName: keyof ProcessorDefinition = 'step';
+
+ const data: CamelRouteVisualEntityData = {
+ path,
+ icon: NodeIconResolver.getIcon(processorName, NodeIconType.EIP),
+ processorName,
+ isGroup: true,
+ };
+
+ const stepDefinition: Step = getValue(entityDefinition, path);
+ if (DataMapperNodeMapper.isDataMapperNode(stepDefinition)) {
+ return this.rootNodeMapper.getVizNodeFromProcessor(
+ path,
+ {
+ processorName: DATAMAPPER_ID_PREFIX,
+ },
+ entityDefinition,
+ );
+ }
+
+ const vizNode = createVisualizationNode(processorName, data);
+
+ const children = this.getChildrenFromBranch(`${path}.steps`, entityDefinition);
+ children.forEach((child) => {
+ vizNode.addChild(child);
+ });
+
+ return vizNode;
+ }
+}
diff --git a/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.test.ts b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.test.ts
index 3ea9ec016..408fdbf4d 100644
--- a/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.test.ts
+++ b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.test.ts
@@ -1,6 +1,9 @@
+import { DATAMAPPER_ID_PREFIX } from '../../../../utils';
import { BaseNodeMapper } from './mappers/base-node-mapper';
import { ChoiceNodeMapper } from './mappers/choice-node-mapper';
+import { DataMapperNodeMapper } from './mappers/datamapper-node-mapper';
import { OtherwiseNodeMapper } from './mappers/otherwise-node-mapper';
+import { StepNodeMapper } from './mappers/step-node-mapper';
import { WhenNodeMapper } from './mappers/when-node-mapper';
import { NodeMapperService } from './node-mapper.service';
import { RootNodeMapper } from './root-node-mapper';
@@ -16,5 +19,7 @@ describe('NodeMapperService', () => {
expect(registerMapperSpy).toHaveBeenCalledWith('choice', expect.any(ChoiceNodeMapper));
expect(registerMapperSpy).toHaveBeenCalledWith('when', expect.any(WhenNodeMapper));
expect(registerMapperSpy).toHaveBeenCalledWith('otherwise', expect.any(OtherwiseNodeMapper));
+ expect(registerMapperSpy).toHaveBeenCalledWith('step', expect.any(StepNodeMapper));
+ expect(registerMapperSpy).toHaveBeenCalledWith(DATAMAPPER_ID_PREFIX, expect.any(DataMapperNodeMapper));
});
});
diff --git a/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.ts b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.ts
index 2f60395d6..50548a542 100644
--- a/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.ts
+++ b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.ts
@@ -1,8 +1,11 @@
+import { DATAMAPPER_ID_PREFIX } from '../../../../utils';
import { IVisualizationNode } from '../../base-visual-entity';
import { ICamelElementLookupResult } from '../support/camel-component-types';
import { BaseNodeMapper } from './mappers/base-node-mapper';
import { ChoiceNodeMapper } from './mappers/choice-node-mapper';
+import { DataMapperNodeMapper } from './mappers/datamapper-node-mapper';
import { OtherwiseNodeMapper } from './mappers/otherwise-node-mapper';
+import { StepNodeMapper } from './mappers/step-node-mapper';
import { WhenNodeMapper } from './mappers/when-node-mapper';
import { MulticastNodeMapper } from './mappers/multicast-node-mapper';
import { LoadBalanceNodeMapper } from './mappers/loadbalance-node-mapper';
@@ -34,6 +37,8 @@ export class NodeMapperService {
this.rootNodeMapper.registerMapper('choice', new ChoiceNodeMapper(this.rootNodeMapper));
this.rootNodeMapper.registerMapper('when', new WhenNodeMapper(this.rootNodeMapper));
this.rootNodeMapper.registerMapper('otherwise', new OtherwiseNodeMapper(this.rootNodeMapper));
+ this.rootNodeMapper.registerMapper('step', new StepNodeMapper(this.rootNodeMapper));
+ this.rootNodeMapper.registerMapper(DATAMAPPER_ID_PREFIX, new DataMapperNodeMapper(this.rootNodeMapper));
this.rootNodeMapper.registerMapper('multicast', new MulticastNodeMapper(this.rootNodeMapper));
this.rootNodeMapper.registerMapper('loadBalance', new LoadBalanceNodeMapper(this.rootNodeMapper));
}
diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts b/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts
index 15131a4c4..b3e8ee1b3 100644
--- a/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts
+++ b/packages/ui/src/models/visualization/flows/support/camel-component-default.service.ts
@@ -1,8 +1,9 @@
import { ProcessorDefinition } from '@kaoto/camel-catalog/types';
import { parse } from 'yaml';
-import { getCamelRandomId } from '../../../../camel-utils/camel-random-id';
+import { getCamelRandomId, getHexaDecimalRandomId } from '../../../../camel-utils/camel-random-id';
import { DefinedComponent } from '../../../camel-catalog-index';
import { CatalogKind } from '../../../catalog-kind';
+import { XSLT_COMPONENT_NAME } from '../../../../utils';
/**
* CamelComponentDefaultService
@@ -170,6 +171,17 @@ export class CamelComponentDefaultService {
simple: {}
`);
+ case 'kaoto-datamapper' as keyof ProcessorDefinition:
+ return parse(`
+ step:
+ id: ${getHexaDecimalRandomId('kaoto-datamapper')}
+ steps:
+ - to:
+ id: ${getCamelRandomId('kaoto-datamapper-xslt')}
+ uri: ${XSLT_COMPONENT_NAME}
+ parameters: {}
+ `);
+
default:
return {
[processorName]: {
diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts
index aa25b5e13..5c146520a 100644
--- a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts
+++ b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts
@@ -1,6 +1,7 @@
import catalogLibrary from '@kaoto/camel-catalog/index.json';
import { CatalogLibrary, ProcessorDefinition } from '@kaoto/camel-catalog/types';
import { getFirstCatalogMap } from '../../../../stubs/test-load-catalog';
+import { DATAMAPPER_ID_PREFIX, XSLT_COMPONENT_NAME } from '../../../../utils';
import { ICamelProcessorDefinition } from '../../../camel-processors-catalog';
import { CatalogKind } from '../../../catalog-kind';
import { NodeLabelType } from '../../../settings/settings.model';
@@ -295,6 +296,19 @@ describe('CamelComponentSchemaService', () => {
['from.steps.3.choice.when.0', {}, { processorName: 'when' }],
['from.steps.3.choice.otherwise', {}, { processorName: 'otherwise' }],
['from.steps.3.choice.otherwise', undefined, { processorName: 'otherwise' }],
+ ['from.steps.0.step', undefined, { processorName: 'step' }],
+ ['from.steps.0.step', { id: 'step-1234' }, { processorName: 'step' }],
+ ['from.steps.0.step', { id: `${DATAMAPPER_ID_PREFIX}-1234`, steps: [] }, { processorName: 'step' }],
+ [
+ 'from.steps.0.step',
+ { id: `modified-${DATAMAPPER_ID_PREFIX}-1234`, steps: [{ to: { uri: `${XSLT_COMPONENT_NAME}:mapping.xsl` } }] },
+ { processorName: 'step' },
+ ],
+ [
+ 'from.steps.0.step',
+ { id: `${DATAMAPPER_ID_PREFIX}-1234`, steps: [{ to: { uri: `${XSLT_COMPONENT_NAME}:mapping.xsl` } }] },
+ { processorName: DATAMAPPER_ID_PREFIX },
+ ],
])('should return the processor and component name for %s', (path, definition, result) => {
const camelElementLookup = CamelComponentSchemaService.getCamelComponentLookup(path, definition);
@@ -392,6 +406,8 @@ describe('CamelComponentSchemaService', () => {
{ id: 'interceptSendToEndpoint-1234' },
'interceptSendToEndpoint-1234',
],
+ [{ processorName: 'step' }, { id: 'kaoto-datamapper-1234' }, 'kaoto-datamapper-1234'],
+ [{ processorName: 'step' }, { id: 'step-1234' }, 'step-1234'],
] as Array<[ICamelElementLookupResult, unknown, string]>)(
'should return the processor name if the component name is not provided: %s [%s]',
(componentLookup, definition, result) => {
diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts
index 4a13a6552..5edebd8ae 100644
--- a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts
+++ b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts
@@ -1,6 +1,13 @@
import { ProcessorDefinition } from '@kaoto/camel-catalog/types';
import { cloneDeep } from 'lodash';
-import { CamelUriHelper, ParsedParameters, getValue, isDefined } from '../../../../utils';
+import {
+ CamelUriHelper,
+ DATAMAPPER_ID_PREFIX,
+ ParsedParameters,
+ getValue,
+ isDataMapperNode,
+ isDefined,
+} from '../../../../utils';
import { ICamelComponentDefinition } from '../../../camel-components-catalog';
import { CatalogKind } from '../../../catalog-kind';
import { IKameletDefinition } from '../../../kamelets-catalog';
@@ -92,6 +99,7 @@ export class CamelComponentSchemaService {
case 'intercept' as keyof ProcessorDefinition:
case 'interceptFrom' as keyof ProcessorDefinition:
case 'interceptSendToEndpoint' as keyof ProcessorDefinition:
+ case 'step':
return id ?? camelElementLookup.processorName;
case 'from' as keyof ProcessorDefinition:
@@ -262,6 +270,12 @@ export class CamelComponentSchemaService {
return { processorName };
}
+ if (processorName === 'step' && isDataMapperNode(definition)) {
+ return {
+ processorName: DATAMAPPER_ID_PREFIX,
+ };
+ }
+
switch (processorName) {
case 'from' as keyof ProcessorDefinition:
return {
diff --git a/packages/ui/src/multiplying-architecture/KaotoBridge.tsx b/packages/ui/src/multiplying-architecture/KaotoBridge.tsx
index b1f3dbe08..736843e85 100644
--- a/packages/ui/src/multiplying-architecture/KaotoBridge.tsx
+++ b/packages/ui/src/multiplying-architecture/KaotoBridge.tsx
@@ -1,14 +1,32 @@
import { ChannelType, EditorApi, StateControlCommand } from '@kie-tools-core/editor/dist/api';
import { Notification } from '@kie-tools-core/notifications/dist/api';
-import { PropsWithChildren, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef } from 'react';
+import { VisualizationProvider } from '@patternfly/react-topology';
+import {
+ PropsWithChildren,
+ forwardRef,
+ useCallback,
+ useContext,
+ useEffect,
+ useImperativeHandle,
+ useMemo,
+ useRef,
+} from 'react';
+import { NodeInteractionAddonProvider } from '../components/registers/interactions/node-interaction-addon.provider';
+import { RegisterComponents } from '../components/registers/RegisterComponents';
+import { RegisterNodeInteractionAddons } from '../components/registers/RegisterNodeInteractionAddons';
+import { RenderingProvider } from '../components/RenderingAnchor/rendering.provider';
+import { ControllerService } from '../components/Visualization/Canvas/controller.service';
import { useReload } from '../hooks/reload.hook';
-import { CatalogTilesProvider } from '../providers/catalog-tiles.provider';
-import { CatalogLoaderProvider } from '../providers/catalog.provider';
-import { RuntimeProvider } from '../providers/runtime.provider';
-import { SchemasLoaderProvider } from '../providers/schemas.provider';
-import { SettingsContext } from '../providers/settings.provider';
-import { SourceCodeApiContext } from '../providers/source-code.provider';
-import { VisibleFlowsProvider } from '../providers/visible-flows.provider';
+import {
+ CatalogLoaderProvider,
+ CatalogTilesProvider,
+ MetadataProvider,
+ RuntimeProvider,
+ SchemasLoaderProvider,
+ SettingsContext,
+ SourceCodeApiContext,
+ VisibleFlowsProvider,
+} from '../providers';
import { EventNotifier } from '../utils';
interface KaotoBridgeProps {
@@ -40,114 +58,196 @@ interface KaotoBridgeProps {
setNotifications: (path: string, notifications: Notification[]) => void;
/**
- * ChannelType where the component is running.
+ * Get metadata querying a Kaoto metadata file using the channel API.
+ * @param key The key to retrieve the metadata from the Kaoto metadata file
*/
- channelType: ChannelType;
-}
+ getMetadata(key: string): Promise;
-export const KaotoBridge = forwardRef>((props, forwardedRef) => {
- const ReloadProvider = useReload();
- const eventNotifier = EventNotifier.getInstance();
- const sourceCodeApiContext = useContext(SourceCodeApiContext);
- const sourceCodeRef = useRef('');
- const settingsAdapter = useContext(SettingsContext);
- const catalogUrl = settingsAdapter.getSettings().catalogUrl;
+ /**
+ * Save metadata to a Kaoto metadata file using the channel API.
+ * @param key The key to set the metadata
+ * @param metadata The metadata to be saved
+ */
+ setMetadata(key: string, metadata: T): Promise;
/**
- * Callback is exposed to the Channel that is called when a new file is opened.
- * It sets the originalContent to the received value.
+ * Retrieve resource content using the channel API.
+ * @param path The path of the resource
*/
- const setContent = useCallback(
- (_path: string, content: string) => {
- /**
- * If the new content is the same as the current one, we don't need to update the Editor,
- * as it will regenerate the Camel Resource, hence disconnecting the configuration form (if open).
- *
- * This happens due to the multiplying architecture lifecycle, where the content is set
- * after saving the file.
- *
- * The lifecycle is:
- * 1. User edits the file either adding a new node or modifying an existing one using the form
- * 2. User saves the file
- * 3. The Envelope uses the `getContent` callback to retrieve the new content
- * 4. The Envelope sets the new content using the `setContent` callback
- *
- * At this point, both the new content and the current content are the same, so the Editor
- * don't need to be updated.
- */
- if (sourceCodeRef.current === content) return;
-
- sourceCodeApiContext.setCodeAndNotify(content);
- sourceCodeRef.current = content;
- },
- [sourceCodeApiContext],
- );
+ getResourceContent(path: string): Promise;
/**
- * Subscribe to the `entities:updated` event to update the File content.
+ * Save resource content using the channel API.
+ * @param path The path of the resource
+ * @param content The content to be saved
*/
- useEffect(() => {
- const unsubscribeFromEntities = eventNotifier.subscribe('entities:updated', (newContent: string) => {
- props.onNewEdit(newContent);
- sourceCodeRef.current = newContent;
- });
+ saveResourceContent(path: string, content: string): Promise;
- const unsubscribeFromSourceCode = eventNotifier.subscribe('code:updated', (newContent: string) => {
- /** Ignore the first change, from an empty string to the file content */
- if (sourceCodeRef.current !== '') {
- props.onNewEdit(newContent);
- }
- sourceCodeRef.current = newContent;
- });
+ /**
+ * Delete resource using the channel API.
+ * @param path The path of the resource
+ */
+ deleteResource(path: string): Promise;
- return () => {
- unsubscribeFromEntities();
- unsubscribeFromSourceCode();
- };
- }, [eventNotifier, props]);
+ /**
+ * Show a Quick Pick widget and ask the user to select one or more files available in the workspace.
+ * @param include The filter expression for the files to include
+ * @param exclude The filter expression for the files to exclude
+ * @param options The options to pass over to VSCode QuickPick
+ */
+ askUserForFileSelection(
+ include: string,
+ exclude?: string,
+ options?: Record,
+ ): Promise;
/**
- * The useImperativeHandler gives the control of the Editor component to who has it's reference,
- * making it possible to communicate with the Editor.
- * It returns all methods that are determined on the EditorApi.
+ * ChannelType where the component is running.
*/
- useImperativeHandle(forwardedRef, () => {
- return {
- /* Callback is exposed to the Channel to set the content of the file into the current Editor. */
- setContent: (path: string, content: string) => Promise.resolve(setContent(path, content)),
- /**
- * Callback is exposed to the Channel to retrieve the current value of the Editor. It returns the value of
- * the editorContent, which is the state that has the kaoto yaml.
- */
- getContent: () => Promise.resolve(sourceCodeRef.current),
- getPreview: () => Promise.resolve(undefined),
- undo: (): Promise => {
- return Promise.resolve();
- },
- redo: (): Promise => {
- return Promise.resolve();
+ channelType: ChannelType;
+}
+
+export const KaotoBridge = forwardRef>(
+ (
+ {
+ onNewEdit,
+ onReady,
+ children,
+ getMetadata,
+ setMetadata,
+ getResourceContent,
+ saveResourceContent,
+ deleteResource,
+ askUserForFileSelection,
+ },
+ forwardedRef,
+ ) => {
+ const ReloadProvider = useReload();
+ const controller = useMemo(() => ControllerService.createController(), []);
+ const eventNotifier = EventNotifier.getInstance();
+ const sourceCodeApiContext = useContext(SourceCodeApiContext);
+ const sourceCodeRef = useRef('');
+ const settingsAdapter = useContext(SettingsContext);
+ const catalogUrl = settingsAdapter.getSettings().catalogUrl;
+ const metadataApi = useMemo(
+ () => ({
+ getMetadata,
+ setMetadata,
+ getResourceContent,
+ saveResourceContent,
+ deleteResource,
+ askUserForFileSelection,
+ shouldSaveSchema: false,
+ }),
+ [getMetadata, setMetadata, getResourceContent, saveResourceContent, deleteResource, askUserForFileSelection],
+ );
+
+ /**
+ * Callback is exposed to the Channel that is called when a new file is opened.
+ * It sets the originalContent to the received value.
+ */
+ const setContent = useCallback(
+ (_path: string, content: string) => {
+ /**
+ * If the new content is the same as the current one, we don't need to update the Editor,
+ * as it will regenerate the Camel Resource, hence disconnecting the configuration form (if open).
+ *
+ * This happens due to the multiplying architecture lifecycle, where the content is set
+ * after saving the file.
+ *
+ * The lifecycle is:
+ * 1. User edits the file either adding a new node or modifying an existing one using the form
+ * 2. User saves the file
+ * 3. The Envelope uses the `getContent` callback to retrieve the new content
+ * 4. The Envelope sets the new content using the `setContent` callback
+ *
+ * At this point, both the new content and the current content are the same, so the Editor
+ * don't need to be updated.
+ */
+ if (sourceCodeRef.current === content) return;
+
+ sourceCodeApiContext.setCodeAndNotify(content);
+ sourceCodeRef.current = content;
},
- validate: () => Promise.resolve([]),
- setTheme: () => Promise.resolve(),
- };
- });
-
- /** Set editor as Ready */
- useEffect(() => {
- props.onReady();
- }, [props]);
-
- return (
-
-
-
-
-
- {props.children}
-
-
-
-
-
- );
-});
+ [sourceCodeApiContext],
+ );
+
+ /**
+ * Subscribe to the `entities:updated` event to update the File content.
+ */
+ useEffect(() => {
+ const unsubscribeFromEntities = eventNotifier.subscribe('entities:updated', (newContent: string) => {
+ onNewEdit(newContent);
+ sourceCodeRef.current = newContent;
+ });
+
+ const unsubscribeFromSourceCode = eventNotifier.subscribe('code:updated', (newContent: string) => {
+ /** Ignore the first change, from an empty string to the file content */
+ if (sourceCodeRef.current !== '') {
+ onNewEdit(newContent);
+ }
+ sourceCodeRef.current = newContent;
+ });
+
+ return () => {
+ unsubscribeFromEntities();
+ unsubscribeFromSourceCode();
+ };
+ }, [eventNotifier, onNewEdit]);
+
+ /**
+ * The useImperativeHandler gives the control of the Editor component to who has it's reference,
+ * making it possible to communicate with the Editor.
+ * It returns all methods that are determined on the EditorApi.
+ */
+ useImperativeHandle(forwardedRef, () => {
+ return {
+ /* Callback is exposed to the Channel to set the content of the file into the current Editor. */
+ setContent: (path: string, content: string) => Promise.resolve(setContent(path, content)),
+ /**
+ * Callback is exposed to the Channel to retrieve the current value of the Editor. It returns the value of
+ * the editorContent, which is the state that has the kaoto yaml.
+ */
+ getContent: () => Promise.resolve(sourceCodeRef.current),
+ getPreview: () => Promise.resolve(undefined),
+ undo: (): Promise => {
+ return Promise.resolve();
+ },
+ redo: (): Promise => {
+ return Promise.resolve();
+ },
+ validate: () => Promise.resolve([]),
+ setTheme: () => Promise.resolve(),
+ };
+ });
+
+ /** Set editor as Ready */
+ useEffect(onReady, [onReady]);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+
+
+
+ );
+ },
+);
diff --git a/packages/ui/src/multiplying-architecture/KaotoEditor.tsx b/packages/ui/src/multiplying-architecture/KaotoEditor.tsx
index 4b64a8043..8e4cff65e 100644
--- a/packages/ui/src/multiplying-architecture/KaotoEditor.tsx
+++ b/packages/ui/src/multiplying-architecture/KaotoEditor.tsx
@@ -3,6 +3,7 @@ import { CodeIcon, ExclamationCircleIcon } from '@patternfly/react-icons';
import clsx from 'clsx';
import { useContext, useMemo, useRef } from 'react';
import { Link, Outlet, useLocation } from 'react-router-dom';
+import icon_component_datamapper from '../assets/components/datamapper.png';
import bean from '../assets/eip/bean.png';
import camelIcon from '../assets/logo-kaoto.svg';
import { SourceSchemaType } from '../models/camel/source-schema-type';
@@ -15,11 +16,12 @@ const enum TabList {
Beans,
Metadata,
ErrorHandler,
+ KaotoDataMapper,
}
const SCHEMA_TABS: Record = {
- [SourceSchemaType.Route]: [TabList.Design, TabList.Beans],
- [SourceSchemaType.Kamelet]: [TabList.Design, TabList.Beans, TabList.Metadata],
+ [SourceSchemaType.Route]: [TabList.Design, TabList.Beans, TabList.KaotoDataMapper],
+ [SourceSchemaType.Kamelet]: [TabList.Design, TabList.Beans, TabList.Metadata, TabList.KaotoDataMapper],
[SourceSchemaType.Integration]: [],
[SourceSchemaType.KameletBinding]: [TabList.Design, TabList.Metadata, TabList.ErrorHandler],
[SourceSchemaType.Pipe]: [TabList.Design, TabList.Metadata, TabList.ErrorHandler],
@@ -30,6 +32,11 @@ export const KaotoEditor = () => {
const resource = entitiesContext?.camelResource;
const inset = useRef({ default: 'insetSm' });
const currentLocation = useLocation();
+ const secondSlashIndex = currentLocation.pathname.indexOf('/', 1);
+ const currentPath = currentLocation.pathname.substring(0, secondSlashIndex !== -1 ? secondSlashIndex : undefined);
+ const dataMapperLink = currentLocation.pathname.startsWith(Links.DataMapper)
+ ? currentLocation.pathname
+ : Links.DataMapper;
const availableTabs = useMemo(() => {
if (!resource) {
@@ -38,6 +45,7 @@ export const KaotoEditor = () => {
beans: false,
metadata: false,
errorHandler: false,
+ kaotoDataMapper: false,
};
}
@@ -46,6 +54,7 @@ export const KaotoEditor = () => {
beans: SCHEMA_TABS[resource.getType()].indexOf(TabList.Beans) >= 0,
metadata: SCHEMA_TABS[resource.getType()].indexOf(TabList.Metadata) >= 0,
errorHandler: SCHEMA_TABS[resource.getType()].indexOf(TabList.ErrorHandler) >= 0,
+ kaotoDataMapper: SCHEMA_TABS[resource.getType()].indexOf(TabList.KaotoDataMapper) >= 0,
};
}, [resource]);
@@ -55,13 +64,14 @@ export const KaotoEditor = () => {
inset={inset.current}
isBox
unmountOnExit
- activeKey={currentLocation.pathname}
+ activeKey={currentPath}
aria-label="Tabs in the Kaoto editor"
role="region"
>
{availableTabs.design && (
@@ -81,6 +91,7 @@ export const KaotoEditor = () => {
{availableTabs.beans && (
@@ -100,6 +111,7 @@ export const KaotoEditor = () => {
{availableTabs.metadata && (
@@ -117,6 +129,7 @@ export const KaotoEditor = () => {
{availableTabs.errorHandler && (
@@ -130,6 +143,26 @@ export const KaotoEditor = () => {
/>
)}
+
+ {availableTabs.kaotoDataMapper && (
+
+
+
+
+
+
+
+ DataMapper
+ >
+ }
+ aria-label="DataMapper"
+ />
+
+ )}
{
kogitoWorkspace_newEdit: getNotificationMock(),
kogitoWorkspace_openFile: getNotificationMock(),
},
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- requests: {} as any,
+ requests: {
+ getMetadata: jest.fn(),
+ setMetadata: jest.fn(),
+ getResourceContent: jest.fn(),
+ saveResourceContent: jest.fn(),
+ } as unknown as ApiRequests
,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
shared: {} as any,
},
@@ -194,6 +199,30 @@ describe('KaotoEditorApp', () => {
StateControlCommand.REDO,
);
});
+
+ it('should delegate to the channelApi getting metadata from the Kaoto metadata file', async () => {
+ await kaotoEditorApp.getMetadata('path');
+
+ expect(envelopeContext.channelApi.requests.getMetadata).toHaveBeenCalledWith('path');
+ });
+
+ it('should delegate to the channelApi setting metadata from the Kaoto metadata file', async () => {
+ await kaotoEditorApp.setMetadata('key', 'value');
+
+ expect(envelopeContext.channelApi.requests.setMetadata).toHaveBeenCalledWith('key', 'value');
+ });
+
+ it('should delegate to the channelApi getting a file resource content', async () => {
+ await kaotoEditorApp.getResourceContent('path');
+
+ expect(envelopeContext.channelApi.requests.getResourceContent).toHaveBeenCalledWith('path');
+ });
+
+ it('should delegate to the channelApi saving file resource content', async () => {
+ await kaotoEditorApp.saveResourceContent('path', 'content');
+
+ expect(envelopeContext.channelApi.requests.saveResourceContent).toHaveBeenCalledWith('path', 'content');
+ });
});
const getNotificationMock = () => ({
diff --git a/packages/ui/src/multiplying-architecture/KaotoEditorApp.tsx b/packages/ui/src/multiplying-architecture/KaotoEditorApp.tsx
index 25a44c358..565c05c08 100644
--- a/packages/ui/src/multiplying-architecture/KaotoEditorApp.tsx
+++ b/packages/ui/src/multiplying-architecture/KaotoEditorApp.tsx
@@ -36,6 +36,12 @@ export class KaotoEditorApp implements Editor {
this.sendNewEdit = this.sendNewEdit.bind(this);
this.sendNotifications = this.sendNotifications.bind(this);
this.sendStateControlCommand = this.sendStateControlCommand.bind(this);
+ this.getMetadata = this.getMetadata.bind(this);
+ this.setMetadata = this.setMetadata.bind(this);
+ this.getResourceContent = this.getResourceContent.bind(this);
+ this.saveResourceContent = this.saveResourceContent.bind(this);
+ this.deleteResource = this.deleteResource.bind(this);
+ this.askUserForFileSelection = this.askUserForFileSelection.bind(this);
}
async setContent(path: string, content: string): Promise {
@@ -94,6 +100,34 @@ export class KaotoEditorApp implements Editor {
this.envelopeContext.channelApi.notifications.kogitoEditor_stateControlCommandUpdate.send(command);
}
+ async getMetadata(key: string): Promise {
+ return this.envelopeContext.channelApi.requests.getMetadata(key);
+ }
+
+ async setMetadata(key: string, preferences: T): Promise {
+ return this.envelopeContext.channelApi.requests.setMetadata(key, preferences);
+ }
+
+ async getResourceContent(path: string): Promise {
+ return this.envelopeContext.channelApi.requests.getResourceContent(path);
+ }
+
+ async saveResourceContent(path: string, content: string): Promise {
+ return this.envelopeContext.channelApi.requests.saveResourceContent(path, content);
+ }
+
+ async deleteResource(path: string): Promise {
+ return this.envelopeContext.channelApi.requests.deleteResource(path);
+ }
+
+ async askUserForFileSelection(
+ include: string,
+ exclude?: string,
+ options?: Record,
+ ): Promise {
+ return this.envelopeContext.channelApi.requests.askUserForFileSelection(include, exclude, options);
+ }
+
af_componentRoot() {
return (
@@ -106,6 +140,12 @@ export class KaotoEditorApp implements Editor {
onNewEdit={this.sendNewEdit}
setNotifications={this.sendNotifications}
onStateControlCommandUpdate={this.sendStateControlCommand}
+ getMetadata={this.getMetadata}
+ setMetadata={this.setMetadata}
+ getResourceContent={this.getResourceContent}
+ saveResourceContent={this.saveResourceContent}
+ deleteResource={this.deleteResource}
+ askUserForFileSelection={this.askUserForFileSelection}
>
diff --git a/packages/ui/src/multiplying-architecture/KaotoEditorRouter.tsx b/packages/ui/src/multiplying-architecture/KaotoEditorRouter.tsx
index 03a24f976..d8fa0fe39 100644
--- a/packages/ui/src/multiplying-architecture/KaotoEditorRouter.tsx
+++ b/packages/ui/src/multiplying-architecture/KaotoEditorRouter.tsx
@@ -25,6 +25,14 @@ export const kaotoEditorRouter = createHashRouter([
path: Links.PipeErrorHandler,
lazy: async () => import('../pages/PipeErrorHandler'),
},
+ {
+ path: Links.DataMapper,
+ lazy: async () => import('../pages/DataMapperHowTo'),
+ },
+ {
+ path: `${Links.DataMapper}/:id`,
+ lazy: async () => import('../pages/DataMapper'),
+ },
],
},
]);
diff --git a/packages/ui/src/pages/DataMapper/DataMapperPage.tsx b/packages/ui/src/pages/DataMapper/DataMapperPage.tsx
new file mode 100644
index 000000000..ef473b980
--- /dev/null
+++ b/packages/ui/src/pages/DataMapper/DataMapperPage.tsx
@@ -0,0 +1,35 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { useVisualizationController } from '@patternfly/react-topology';
+import { FunctionComponent } from 'react';
+import { useParams } from 'react-router-dom';
+import DataMapper from '../../components/DataMapper/DataMapper';
+import { IVisualizationNode } from '../../models';
+import { getVisualizationNodesFromGraph } from '../../utils';
+
+export const DataMapperPage: FunctionComponent = () => {
+ const controller = useVisualizationController();
+ const params = useParams();
+
+ const vizNode = getVisualizationNodesFromGraph(
+ controller.getGraph(),
+ (node: IVisualizationNode) => node.getComponentSchema()?.definition?.id === params.id,
+ )[0];
+
+ return ;
+};
+
+export default DataMapperPage;
diff --git a/packages/ui/src/pages/DataMapper/index.ts b/packages/ui/src/pages/DataMapper/index.ts
new file mode 100644
index 000000000..222b76e07
--- /dev/null
+++ b/packages/ui/src/pages/DataMapper/index.ts
@@ -0,0 +1 @@
+export * from './router-exports';
diff --git a/packages/ui/src/pages/DataMapper/router-exports.tsx b/packages/ui/src/pages/DataMapper/router-exports.tsx
new file mode 100644
index 000000000..c2ea9cf61
--- /dev/null
+++ b/packages/ui/src/pages/DataMapper/router-exports.tsx
@@ -0,0 +1,3 @@
+import { DataMapperPage } from './DataMapperPage';
+
+export const element = ;
diff --git a/packages/ui/src/pages/DataMapperHowTo/DataMapperHowToPage.scss b/packages/ui/src/pages/DataMapperHowTo/DataMapperHowToPage.scss
new file mode 100644
index 000000000..c26c733d8
--- /dev/null
+++ b/packages/ui/src/pages/DataMapperHowTo/DataMapperHowToPage.scss
@@ -0,0 +1,26 @@
+.datamapper-howto {
+ flex-flow: column;
+ justify-content: start;
+ font-size: var(--pf-v5-c-card__body--FontSize);
+ padding: 0 var(--pf-v5-global--spacer--md);
+
+ & ol {
+ margin-bottom: calc(var(--pf-v5-global--spacer--xl) * 2);
+
+ li {
+ margin-bottom: var(--pf-v5-global--spacer--xl);
+ border-bottom: 1px solid var(--pf-v5-global--palette--black-300);
+
+ &::marker {
+ font-weight: bold;
+ }
+ }
+ }
+
+ img {
+ margin: var(--pf-v5-global--spacer--md) 0;
+ border: 1px solid var(--pf-v5-global--palette--black-300);
+ padding: var(--pf-v5-global--spacer--sm);
+ border-radius: calc(var(--pf-v5-global--BorderRadius--sm) * 2);
+ }
+}
diff --git a/packages/ui/src/pages/DataMapperHowTo/DataMapperHowToPage.tsx b/packages/ui/src/pages/DataMapperHowTo/DataMapperHowToPage.tsx
new file mode 100644
index 000000000..a3af5355d
--- /dev/null
+++ b/packages/ui/src/pages/DataMapperHowTo/DataMapperHowToPage.tsx
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { Bullseye, List, ListComponent, ListItem, OrderType, Stack, StackItem, Title } from '@patternfly/react-core';
+import { FunctionComponent } from 'react';
+import icon_component_datamapper from '../../assets/components/datamapper.png';
+import './DataMapperHowToPage.scss';
+import catalog_datamapper from '../../assets/data-mapper/kaoto-datamapper-catalog.png';
+import datamapper_step from '../../assets/data-mapper/datamapper-step.png';
+import configure_button from '../../assets/data-mapper/configure-button.png';
+import kaoto_design from '../../assets/data-mapper/kaoto-design.png';
+import source_target from '../../assets/data-mapper/source-target.png';
+import add_parameter from '../../assets/data-mapper/add-parameter.png';
+import add_parameter_confirm from '../../assets/data-mapper/add_parameter_confirm.png';
+import attach_schema_source_body from '../../assets/data-mapper/attach-schema-source-body.png';
+import attach_schema_target_body from '../../assets/data-mapper/attach-schema-target-body.png';
+import attach_schema_parameter from '../../assets/data-mapper/attach-schema-parameter.png';
+import data_mapping from '../../assets/data-mapper/data-mapping.png';
+
+export const DataMapperHowToPage: FunctionComponent = () => {
+ return (
+
+
+ Looking to configure the Kaoto DataMapper?
+
+
+
+
+
+ The Kaoto DataMapper is a powerful graphical tool that allows you to design data mapping between different
+ formats with Drag and Drop.
+
+
+
+ To get started, follow the steps below:
+
+
+
+ Add a Kaoto DataMapper step in your Camel route. When you Append ,{' '}
+ Prepend or Replace a step in the Kaoto Design view, you can find the{' '}
+ Kaoto DataMapper step in the catalog.
+
+
+
+
+
+ Click the added Kaoto DataMapper step in the Kaoto Design view. It opens up{' '}
+ Kaoto DataMapper config form.
+
+
+
+
+
+ In the Kaoto DataMapper config form, click Configure button. The
+ blank Kaoto DataMapper canvas will launch.
+
+
+
+
+
+ In the DataMapper canvas, you can see Source at the left and Target {' '}
+ at the right.
+
+
+
+ The Source is in an other word input, which the DataMapper step reads the data from.
+ This is mapped to the incoming Camel Message to the DataMapper step, as well as Camel{' '}
+ Variables and Exchange Properties .
+
+
+ The Target is in an other word output, which the DataMapper step writes the data to.
+ This is mapped to the outgoing Camel Message from the DataMapper step.
+
+
+
+
+ Add Parameter(s). The Parameters inside the Source is mapped to any
+ of incoming Camel Variables , Message Headers and{' '}
+ Exchange Properties . For example, if there is an incoming Camel Variable{' '}
+ "orderSequence"
, you can consume it by adding a Parameter{' '}
+ "orderSequence"
in the DataMapper Source section.
+
+
+
+
+
+
+
+
+
+
+ Attach Document schema(s). Attach the schema file of the incoming Camel Message Body {' '}
+ to the Source Body if it's a structured data.
+
+
+
+ Attach the schema file of the outgoing Camel Message Body to the{' '}
+ Target Body if it's a structured data.
+
+
+
+ If any of the Parameter(s) is/are structured data, you can also attach the schema for{' '}
+ Parameters as well.
+
+
+
+
+
+ Now you can start designing your data mappings by drag and drop between Source and{' '}
+ Target
+
+
+
+
+
+ Once you finish designing data mappings, click Design tab to go back to the Kaoto
+ main canvas.
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/pages/DataMapperHowTo/index.ts b/packages/ui/src/pages/DataMapperHowTo/index.ts
new file mode 100644
index 000000000..222b76e07
--- /dev/null
+++ b/packages/ui/src/pages/DataMapperHowTo/index.ts
@@ -0,0 +1 @@
+export * from './router-exports';
diff --git a/packages/ui/src/pages/DataMapperHowTo/router-exports.tsx b/packages/ui/src/pages/DataMapperHowTo/router-exports.tsx
new file mode 100644
index 000000000..e695780d1
--- /dev/null
+++ b/packages/ui/src/pages/DataMapperHowTo/router-exports.tsx
@@ -0,0 +1,3 @@
+import { DataMapperHowToPage } from './DataMapperHowToPage';
+
+export const element = ;
diff --git a/packages/ui/src/pages/DataMapperNotYetInBrowser/DataMapperNotYetInBrowser.tsx b/packages/ui/src/pages/DataMapperNotYetInBrowser/DataMapperNotYetInBrowser.tsx
new file mode 100644
index 000000000..c62a09605
--- /dev/null
+++ b/packages/ui/src/pages/DataMapperNotYetInBrowser/DataMapperNotYetInBrowser.tsx
@@ -0,0 +1,40 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { Brand, Panel, PanelHeader, PanelMain, PanelMainBody, Title } from '@patternfly/react-core';
+import { FunctionComponent } from 'react';
+import icon_component_datamapper from '../../assets/components/datamapper.png';
+
+export const DataMapperNotYetInBrowserPage: FunctionComponent = () => {
+ return (
+
+
+
+ The Kaoto DataMapper cannot be configured
+
+
+
+
+ At the moment, the Kaoto DataMapper cannot be configured using the browser directly. Please use the VS Code
+ extension for an enhanced experience. The Kaoto extension is bundled in the
+
+ Extension Pack for Apache Camel
+
+
+
+
+
+ );
+};
diff --git a/packages/ui/src/pages/DataMapperNotYetInBrowser/index.ts b/packages/ui/src/pages/DataMapperNotYetInBrowser/index.ts
new file mode 100644
index 000000000..222b76e07
--- /dev/null
+++ b/packages/ui/src/pages/DataMapperNotYetInBrowser/index.ts
@@ -0,0 +1 @@
+export * from './router-exports';
diff --git a/packages/ui/src/pages/DataMapperNotYetInBrowser/router-exports.tsx b/packages/ui/src/pages/DataMapperNotYetInBrowser/router-exports.tsx
new file mode 100644
index 000000000..a06b6ee5d
--- /dev/null
+++ b/packages/ui/src/pages/DataMapperNotYetInBrowser/router-exports.tsx
@@ -0,0 +1,3 @@
+import { DataMapperNotYetInBrowserPage } from './DataMapperNotYetInBrowser';
+
+export const element = ;
diff --git a/packages/ui/src/providers/__snapshots__/catalog.provider.test.tsx.snap b/packages/ui/src/providers/__snapshots__/catalog.provider.test.tsx.snap
new file mode 100644
index 000000000..c48b53171
--- /dev/null
+++ b/packages/ui/src/providers/__snapshots__/catalog.provider.test.tsx.snap
@@ -0,0 +1,341 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CatalogLoaderProvider should load the CamelCatalogService 1`] = `
+{
+ "exchangeProperties": {
+ "CamelStepId": {
+ "autowired": false,
+ "deprecated": false,
+ "description": "The id of the Step EIP",
+ "displayName": "Step Id",
+ "index": 0,
+ "javaType": "String",
+ "kind": "exchangeProperty",
+ "label": "producer",
+ "required": false,
+ "secret": false,
+ },
+ },
+ "model": {
+ "abstract": false,
+ "deprecated": false,
+ "description": "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
+ "input": true,
+ "javaType": "org.apache.camel.model.StepDefinition",
+ "kind": "model",
+ "label": "transformation",
+ "name": "kaoto-datamapper",
+ "output": true,
+ "supportLevel": "Stable",
+ "title": "Kaoto DataMapper",
+ },
+ "properties": {
+ "description": {
+ "autowired": false,
+ "deprecated": false,
+ "description": "Sets the description of this node",
+ "displayName": "Description",
+ "group": "common",
+ "index": 0,
+ "javaType": "java.lang.String",
+ "kind": "attribute",
+ "required": false,
+ "secret": false,
+ "type": "string",
+ },
+ "disabled": {
+ "autowired": false,
+ "defaultValue": false,
+ "deprecated": false,
+ "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.",
+ "displayName": "Disabled",
+ "group": "advanced",
+ "index": 1,
+ "javaType": "java.lang.Boolean",
+ "kind": "attribute",
+ "label": "advanced",
+ "required": false,
+ "secret": false,
+ "type": "boolean",
+ },
+ "outputs": {
+ "autowired": false,
+ "deprecated": false,
+ "displayName": "Outputs",
+ "group": "common",
+ "index": 2,
+ "javaType": "java.util.List",
+ "kind": "element",
+ "oneOf": [
+ "aggregate",
+ "bean",
+ "choice",
+ "circuitBreaker",
+ "claimCheck",
+ "convertBodyTo",
+ "convertHeaderTo",
+ "convertVariableTo",
+ "delay",
+ "doCatch",
+ "doFinally",
+ "doTry",
+ "dynamicRouter",
+ "enrich",
+ "filter",
+ "idempotentConsumer",
+ "intercept",
+ "interceptFrom",
+ "interceptSendToEndpoint",
+ "kamelet",
+ "loadBalance",
+ "log",
+ "loop",
+ "marshal",
+ "multicast",
+ "onCompletion",
+ "onException",
+ "onFallback",
+ "otherwise",
+ "pausable",
+ "pipeline",
+ "policy",
+ "pollEnrich",
+ "process",
+ "recipientList",
+ "removeHeader",
+ "removeHeaders",
+ "removeProperties",
+ "removeProperty",
+ "removeVariable",
+ "resequence",
+ "resumable",
+ "rollback",
+ "routingSlip",
+ "saga",
+ "sample",
+ "script",
+ "serviceCall",
+ "setBody",
+ "setExchangePattern",
+ "setHeader",
+ "setHeaders",
+ "setProperty",
+ "setVariable",
+ "setVariables",
+ "sort",
+ "split",
+ "step",
+ "stop",
+ "threads",
+ "throttle",
+ "throwException",
+ "to",
+ "toD",
+ "transacted",
+ "transform",
+ "unmarshal",
+ "validate",
+ "when",
+ "whenSkipSendToEndpoint",
+ "wireTap",
+ ],
+ "required": true,
+ "secret": false,
+ "type": "array",
+ },
+ },
+ "propertiesSchema": {
+ "$comment": "steps",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "additionalProperties": false,
+ "description": "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
+ "properties": {
+ "description": {
+ "description": "Sets the description of this node",
+ "group": "common",
+ "title": "Description",
+ "type": "string",
+ },
+ "disabled": {
+ "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.",
+ "group": "advanced",
+ "title": "Disabled",
+ "type": "boolean",
+ },
+ },
+ "required": [],
+ "title": "Kaoto DataMapper",
+ "type": "object",
+ },
+}
+`;
+
+exports[`CatalogLoaderProvider should load the CamelCatalogService 2`] = `
+{
+ "exchangeProperties": {
+ "CamelStepId": {
+ "autowired": false,
+ "deprecated": false,
+ "description": "The id of the Step EIP",
+ "displayName": "Step Id",
+ "index": 0,
+ "javaType": "String",
+ "kind": "exchangeProperty",
+ "label": "producer",
+ "required": false,
+ "secret": false,
+ },
+ },
+ "model": {
+ "abstract": false,
+ "deprecated": false,
+ "description": "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
+ "input": true,
+ "javaType": "org.apache.camel.model.StepDefinition",
+ "kind": "model",
+ "label": "transformation",
+ "name": "kaoto-datamapper",
+ "output": true,
+ "supportLevel": "Stable",
+ "title": "Kaoto DataMapper",
+ },
+ "properties": {
+ "description": {
+ "autowired": false,
+ "deprecated": false,
+ "description": "Sets the description of this node",
+ "displayName": "Description",
+ "group": "common",
+ "index": 0,
+ "javaType": "java.lang.String",
+ "kind": "attribute",
+ "required": false,
+ "secret": false,
+ "type": "string",
+ },
+ "disabled": {
+ "autowired": false,
+ "defaultValue": false,
+ "deprecated": false,
+ "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.",
+ "displayName": "Disabled",
+ "group": "advanced",
+ "index": 1,
+ "javaType": "java.lang.Boolean",
+ "kind": "attribute",
+ "label": "advanced",
+ "required": false,
+ "secret": false,
+ "type": "boolean",
+ },
+ "outputs": {
+ "autowired": false,
+ "deprecated": false,
+ "displayName": "Outputs",
+ "group": "common",
+ "index": 2,
+ "javaType": "java.util.List",
+ "kind": "element",
+ "oneOf": [
+ "aggregate",
+ "bean",
+ "choice",
+ "circuitBreaker",
+ "claimCheck",
+ "convertBodyTo",
+ "convertHeaderTo",
+ "convertVariableTo",
+ "delay",
+ "doCatch",
+ "doFinally",
+ "doTry",
+ "dynamicRouter",
+ "enrich",
+ "filter",
+ "idempotentConsumer",
+ "intercept",
+ "interceptFrom",
+ "interceptSendToEndpoint",
+ "kamelet",
+ "loadBalance",
+ "log",
+ "loop",
+ "marshal",
+ "multicast",
+ "onCompletion",
+ "onException",
+ "onFallback",
+ "otherwise",
+ "pausable",
+ "pipeline",
+ "policy",
+ "pollEnrich",
+ "process",
+ "recipientList",
+ "removeHeader",
+ "removeHeaders",
+ "removeProperties",
+ "removeProperty",
+ "removeVariable",
+ "resequence",
+ "resumable",
+ "rollback",
+ "routingSlip",
+ "saga",
+ "sample",
+ "script",
+ "serviceCall",
+ "setBody",
+ "setExchangePattern",
+ "setHeader",
+ "setHeaders",
+ "setProperty",
+ "setVariable",
+ "setVariables",
+ "sort",
+ "split",
+ "step",
+ "stop",
+ "threads",
+ "throttle",
+ "throwException",
+ "to",
+ "toD",
+ "transacted",
+ "transform",
+ "unmarshal",
+ "validate",
+ "when",
+ "whenSkipSendToEndpoint",
+ "wireTap",
+ ],
+ "required": true,
+ "secret": false,
+ "type": "array",
+ },
+ },
+ "propertiesSchema": {
+ "$comment": "steps",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "additionalProperties": false,
+ "description": "The Kaoto DataMapper maps and transforms data using a set of Camel processors",
+ "properties": {
+ "description": {
+ "description": "Sets the description of this node",
+ "group": "common",
+ "title": "Description",
+ "type": "string",
+ },
+ "disabled": {
+ "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime.",
+ "group": "advanced",
+ "title": "Disabled",
+ "type": "boolean",
+ },
+ },
+ "required": [],
+ "title": "Kaoto DataMapper",
+ "type": "object",
+ },
+}
+`;
diff --git a/packages/ui/src/providers/catalog.provider.test.tsx b/packages/ui/src/providers/catalog.provider.test.tsx
index 41e31f7ed..936a6b059 100644
--- a/packages/ui/src/providers/catalog.provider.test.tsx
+++ b/packages/ui/src/providers/catalog.provider.test.tsx
@@ -209,6 +209,7 @@ describe('CatalogLoaderProvider', () => {
) {
expect(call[0]).toEqual(CatalogKind.Processor);
expect(Object.values(call[1])[0]).toEqual('dummy-data');
+ expect(Object.values(call[1])[1]).toMatchSnapshot();
count++;
} else if (
Object.keys(call[1])[0].includes(
@@ -217,6 +218,7 @@ describe('CatalogLoaderProvider', () => {
) {
expect(call[0]).toEqual(CatalogKind.Pattern);
expect(Object.values(call[1])[0]).toEqual('dummy-data');
+ expect(Object.values(call[1])[1]).toMatchSnapshot();
count++;
} else if (
Object.keys(call[1])[0].includes(
diff --git a/packages/ui/src/providers/catalog.provider.tsx b/packages/ui/src/providers/catalog.provider.tsx
index e3149f24e..8d94f9b00 100644
--- a/packages/ui/src/providers/catalog.provider.tsx
+++ b/packages/ui/src/providers/catalog.provider.tsx
@@ -1,5 +1,6 @@
import { Text, TextVariants } from '@patternfly/react-core';
import { FunctionComponent, PropsWithChildren, createContext, useEffect, useState } from 'react';
+import kaotoPatterns from '../assets/kaoto-patterns/kaoto-patterns.json';
import { LoadDefaultCatalog } from '../components/LoadDefaultCatalog';
import { Loading } from '../components/Loading';
import { useRuntimeContext } from '../hooks/useRuntimeContext/useRuntimeContext';
@@ -89,8 +90,14 @@ export const CatalogLoaderProvider: FunctionComponent = (prop
]);
CamelCatalogService.setCatalogKey(CatalogKind.Component, camelComponents.body);
- CamelCatalogService.setCatalogKey(CatalogKind.Processor, camelModels.body);
- CamelCatalogService.setCatalogKey(CatalogKind.Pattern, camelPatterns.body);
+ CamelCatalogService.setCatalogKey(CatalogKind.Processor, {
+ ...camelModels.body,
+ ...(kaotoPatterns as unknown as ComponentsCatalog[CatalogKind.Pattern]),
+ });
+ CamelCatalogService.setCatalogKey(CatalogKind.Pattern, {
+ ...camelPatterns.body,
+ ...(kaotoPatterns as unknown as ComponentsCatalog[CatalogKind.Pattern]),
+ });
CamelCatalogService.setCatalogKey(CatalogKind.Entity, camelEntities.body);
CamelCatalogService.setCatalogKey(CatalogKind.Language, camelLanguages.body);
CamelCatalogService.setCatalogKey(CatalogKind.Dataformat, camelDataformats.body);
diff --git a/packages/ui/src/providers/datamapper-canvas.provider.test.tsx b/packages/ui/src/providers/datamapper-canvas.provider.test.tsx
new file mode 100644
index 000000000..d166183d9
--- /dev/null
+++ b/packages/ui/src/providers/datamapper-canvas.provider.test.tsx
@@ -0,0 +1,121 @@
+import { DataMapperCanvasProvider } from './datamapper-canvas.provider';
+import { render } from '@testing-library/react';
+import { DataMapperProvider } from './datamapper.provider';
+import { FunctionComponent, PropsWithChildren, useEffect } from 'react';
+import { SourceTargetView } from '../components/View/SourceTargetView';
+import { useDataMapper } from '../hooks/useDataMapper';
+import { DocumentType } from '../models/datamapper/path';
+import { useCanvas } from '../hooks/useCanvas';
+import { BODY_DOCUMENT_ID } from '../models/datamapper/document';
+import { screen } from '@testing-library/react';
+import { TestUtil } from '../stubs/data-mapper';
+
+describe('CanvasProvider', () => {
+ it('should render', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ expect(await screen.findByTestId('testdiv')).toBeInTheDocument();
+ });
+
+ it('should fail if not within DataMapperProvider', () => {
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ const thrower = () => {
+ render( );
+ };
+ expect(thrower).toThrow();
+ consoleSpy.mockRestore();
+ });
+
+ it('clearNodeReferencesForPath() should clear for the path', async () => {
+ let first = false;
+ let second = false;
+ let beforeNodePaths: string[] = [];
+ let afterNodePaths: string[] = [];
+ const LoadDocuments: FunctionComponent = ({ children }) => {
+ const { setSourceBodyDocument, setTargetBodyDocument } = useDataMapper();
+ const { clearNodeReferencesForPath, getAllNodePaths, reloadNodeReferences } = useCanvas();
+ useEffect(() => {
+ const sourceDoc = TestUtil.createSourceOrderDoc();
+ setSourceBodyDocument(sourceDoc);
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ setTargetBodyDocument(targetDoc);
+ reloadNodeReferences();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ useEffect(() => {
+ if (!first) {
+ first = true;
+ return;
+ }
+ if (!second) {
+ second = true;
+ beforeNodePaths = getAllNodePaths();
+ clearNodeReferencesForPath('sourceBody:ShipOrder.xsd://');
+ afterNodePaths = getAllNodePaths();
+ }
+ }, [clearNodeReferencesForPath, getAllNodePaths, reloadNodeReferences]);
+ return <>{children}>;
+ };
+ render(
+
+
+
+
+
+
+ ,
+ );
+ await screen.findAllByText('ShipOrder');
+ expect(afterNodePaths.length).toEqual(17);
+ expect(beforeNodePaths.length).toBeGreaterThan(afterNodePaths.length);
+ });
+
+ it('clearNodeReferencesForDocument() should clear for the Document', async () => {
+ let first = false;
+ let second = false;
+ let beforeNodePaths: string[] = [];
+ let afterNodePaths: string[] = [];
+ const LoadDocuments: FunctionComponent = ({ children }) => {
+ const { setSourceBodyDocument, setTargetBodyDocument } = useDataMapper();
+ const { clearNodeReferencesForDocument, getAllNodePaths, reloadNodeReferences } = useCanvas();
+ useEffect(() => {
+ const sourceDoc = TestUtil.createSourceOrderDoc();
+ setSourceBodyDocument(sourceDoc);
+ const targetDoc = TestUtil.createTargetOrderDoc();
+ setTargetBodyDocument(targetDoc);
+ reloadNodeReferences();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ useEffect(() => {
+ if (!first) {
+ first = true;
+ return;
+ }
+ if (!second) {
+ second = true;
+ beforeNodePaths = getAllNodePaths();
+ clearNodeReferencesForDocument(DocumentType.SOURCE_BODY, BODY_DOCUMENT_ID);
+ afterNodePaths = getAllNodePaths();
+ }
+ }, [clearNodeReferencesForDocument, getAllNodePaths, reloadNodeReferences]);
+ return <>{children}>;
+ };
+ render(
+
+
+
+
+
+
+ ,
+ );
+ await screen.findAllByText('ShipOrder');
+ expect(afterNodePaths.length).toBeGreaterThan(10);
+ expect(beforeNodePaths.length).toBeGreaterThan(afterNodePaths.length);
+ });
+});
diff --git a/packages/ui/src/providers/datamapper-canvas.provider.tsx b/packages/ui/src/providers/datamapper-canvas.provider.tsx
new file mode 100644
index 000000000..4ff55aa00
--- /dev/null
+++ b/packages/ui/src/providers/datamapper-canvas.provider.tsx
@@ -0,0 +1,141 @@
+import {
+ createContext,
+ FunctionComponent,
+ MutableRefObject,
+ PropsWithChildren,
+ RefObject,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+import { DnDHandler } from './dnd/DnDHandler';
+import { DocumentType, NodePath } from '../models/datamapper/path';
+import { DatamapperDndProvider } from './datamapper-dnd.provider';
+import { useDataMapper } from '../hooks/useDataMapper';
+
+export interface NodeReference {
+ headerRef: HTMLDivElement | null;
+ containerRef: HTMLDivElement | null;
+}
+
+export interface ICanvasContext {
+ setNodeReference: (path: string, ref: MutableRefObject) => void;
+ getNodeReference: (path: string) => MutableRefObject | null;
+ reloadNodeReferences: () => void;
+ clearNodeReferencesForPath: (path: string) => void;
+ clearNodeReferencesForDocument: (documentType: DocumentType, documentId: string) => void;
+ getAllNodePaths: () => string[];
+ setDefaultHandler: (handler: DnDHandler | undefined) => void;
+ getActiveHandler: () => DnDHandler | undefined;
+ setActiveHandler: (handler: DnDHandler | undefined) => void;
+ mappingLinkCanvasRef: RefObject | null;
+ setMappingLinkCanvasRef: (ref: RefObject) => void;
+}
+
+export const CanvasContext = createContext(undefined);
+
+export const DataMapperCanvasProvider: FunctionComponent = (props) => {
+ const { mappingTree } = useDataMapper();
+ const [defaultHandler, setDefaultHandler] = useState();
+ const [activeHandler, setActiveHandler] = useState();
+ const [mappingLinkCanvasRef, setMappingLinkCanvasRef] = useState | null>(null);
+
+ const [nodeReferenceMap, setNodeReferenceMap] = useState>>(
+ new Map>(),
+ );
+
+ const setNodeReference = useCallback(
+ (path: string, ref: MutableRefObject) => {
+ nodeReferenceMap.set(path, ref);
+ },
+ [nodeReferenceMap],
+ );
+
+ const getNodeReference = useCallback(
+ (path: string) => {
+ return nodeReferenceMap.get(path) || null;
+ },
+ [nodeReferenceMap],
+ );
+
+ const reloadNodeReferences = useCallback(() => {
+ setNodeReferenceMap(new Map(nodeReferenceMap));
+ }, [nodeReferenceMap]);
+
+ useEffect(() => {
+ if (mappingTree) reloadNodeReferences();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [mappingTree]);
+
+ const clearNodeReferencesForPath = useCallback(
+ (path: string) => {
+ Array.from(nodeReferenceMap.keys())
+ .filter((key) => key.startsWith(path))
+ .forEach((key) => nodeReferenceMap.delete(key));
+ },
+ [nodeReferenceMap],
+ );
+
+ const clearNodeReferencesForDocument = useCallback(
+ (documentType: DocumentType, documentId: string) => {
+ const pathPrefix = NodePath.fromDocument(documentType, documentId).toString();
+ Array.from(nodeReferenceMap.keys())
+ .filter((key) => key.startsWith(pathPrefix))
+ .forEach((key) => nodeReferenceMap.delete(key));
+ },
+ [nodeReferenceMap],
+ );
+
+ const getAllNodePaths = useCallback(() => {
+ return Array.from(nodeReferenceMap.keys());
+ }, [nodeReferenceMap]);
+
+ const handleSetDefaultHandler = useCallback(
+ (handler: DnDHandler | undefined) => {
+ if (!activeHandler) setActiveHandler(handler);
+ setDefaultHandler(handler);
+ },
+ [activeHandler, setDefaultHandler],
+ );
+
+ const handleSetActiveHandler = useCallback(
+ (handler: DnDHandler | undefined) => {
+ setActiveHandler(handler ? handler : defaultHandler);
+ },
+ [defaultHandler],
+ );
+
+ const value: ICanvasContext = useMemo(() => {
+ return {
+ setNodeReference,
+ getNodeReference,
+ reloadNodeReferences,
+ clearNodeReferencesForPath,
+ clearNodeReferencesForDocument,
+ getAllNodePaths,
+ setDefaultHandler: handleSetDefaultHandler,
+ getActiveHandler: () => activeHandler,
+ setActiveHandler: handleSetActiveHandler,
+ mappingLinkCanvasRef,
+ setMappingLinkCanvasRef: (ref) => setMappingLinkCanvasRef(ref),
+ };
+ }, [
+ setNodeReference,
+ getNodeReference,
+ reloadNodeReferences,
+ clearNodeReferencesForPath,
+ clearNodeReferencesForDocument,
+ getAllNodePaths,
+ handleSetDefaultHandler,
+ handleSetActiveHandler,
+ activeHandler,
+ mappingLinkCanvasRef,
+ ]);
+
+ return (
+
+ {props.children}
+
+ );
+};
diff --git a/packages/ui/src/providers/datamapper-dnd.provider.tsx b/packages/ui/src/providers/datamapper-dnd.provider.tsx
new file mode 100644
index 000000000..f4e247d0d
--- /dev/null
+++ b/packages/ui/src/providers/datamapper-dnd.provider.tsx
@@ -0,0 +1,89 @@
+import { DnDHandler } from './dnd/DnDHandler';
+import { createContext, FunctionComponent, PropsWithChildren, useCallback, useMemo, useState } from 'react';
+import {
+ DataRef,
+ DndContext,
+ DragEndEvent,
+ DragOverlay,
+ DragOverEvent,
+ DragStartEvent,
+ useSensor,
+ MouseSensor,
+ TouchSensor,
+ KeyboardSensor,
+ useSensors,
+} from '@dnd-kit/core';
+import { NodeData } from '../models/datamapper';
+import { Label } from '@patternfly/react-core';
+import { useDataMapper } from '../hooks/useDataMapper';
+import { DataMapperDnDMonitor } from './dnd/DataMapperDndMonitor';
+
+export interface IDataMapperDndContext {
+ handler?: DnDHandler;
+}
+
+export const DataMapperDndContext = createContext({});
+
+type DataMapperDndContextProps = PropsWithChildren & {
+ handler: DnDHandler | undefined;
+};
+
+export const DatamapperDndProvider: FunctionComponent = (props) => {
+ const { mappingTree, refreshMappingTree, debug } = useDataMapper();
+ const [activeData, setActiveData] = useState | null>(null);
+
+ const mouseSensor = useSensor(MouseSensor, {
+ activationConstraint: {
+ distance: 10,
+ },
+ });
+ const touchSensor = useSensor(TouchSensor, {
+ activationConstraint: {
+ delay: 250,
+ tolerance: 5,
+ },
+ });
+ const keyboardSensor = useSensor(KeyboardSensor);
+ const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
+
+ const handleDragStart = useCallback(
+ (event: DragStartEvent) => {
+ props.handler && props.handler.handleDragStart(event);
+ setActiveData(event.active.data as DataRef);
+ },
+ [props.handler],
+ );
+
+ const handleDragOver = useCallback(
+ (event: DragOverEvent) => {
+ props.handler && props.handler.handleDragOver(event);
+ },
+ [props.handler],
+ );
+
+ const handleDragEnd = useCallback(
+ (event: DragEndEvent) => {
+ props.handler && props.handler.handleDragEnd(event, mappingTree, refreshMappingTree);
+ setActiveData(null);
+ },
+ [mappingTree, props.handler, refreshMappingTree],
+ );
+
+ const handler = useMemo(() => {
+ return {
+ handler: props.handler,
+ };
+ }, [props.handler]);
+
+ return (
+
+
+ {props.children}
+
+ {activeData?.current?.title ? activeData.current.title : 'dragging...'}
+
+ {debug && }
+
+
+ );
+};
diff --git a/packages/ui/src/providers/datamapper.provider.test.tsx b/packages/ui/src/providers/datamapper.provider.test.tsx
new file mode 100644
index 000000000..5da08f601
--- /dev/null
+++ b/packages/ui/src/providers/datamapper.provider.test.tsx
@@ -0,0 +1,47 @@
+import { DataMapperProvider } from './datamapper.provider';
+import { render, screen } from '@testing-library/react';
+import { useDataMapper } from '../hooks/useDataMapper';
+import { FieldItem, MappingTree } from '../models/datamapper/mapping';
+import { useEffect } from 'react';
+import { IField } from '../models/datamapper/document';
+
+describe('DataMapperProvider', () => {
+ it('should render', async () => {
+ render(
+
+
+ ,
+ );
+ await screen.findByTestId('testdiv');
+ });
+
+ it('refreshMappingTree should re-create the MappingTree instance', async () => {
+ let prevTree: MappingTree;
+ let nextTree: MappingTree;
+ let done = false;
+ const TestRefreshMappingTree = () => {
+ const { mappingTree, refreshMappingTree } = useDataMapper();
+ useEffect(() => {
+ if (done) {
+ nextTree = mappingTree;
+ } else {
+ prevTree = mappingTree;
+ prevTree.children.push(new FieldItem(prevTree, {} as IField));
+ refreshMappingTree();
+ done = true;
+ }
+ }, [mappingTree, refreshMappingTree]);
+ return
;
+ };
+ render(
+
+
+ ,
+ );
+ await screen.findByTestId('testdiv');
+ expect(prevTree!).toBeDefined();
+ expect(nextTree!).toBeDefined();
+ expect(prevTree! !== nextTree!).toBeTruthy();
+ expect(prevTree!.children[0] === nextTree!.children[0]).toBeTruthy();
+ });
+});
diff --git a/packages/ui/src/providers/datamapper.provider.tsx b/packages/ui/src/providers/datamapper.provider.tsx
new file mode 100644
index 000000000..78f522f4e
--- /dev/null
+++ b/packages/ui/src/providers/datamapper.provider.tsx
@@ -0,0 +1,304 @@
+/*
+ Copyright (C) 2024 Red Hat, Inc.
+
+ Licensed 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 { createContext, FunctionComponent, PropsWithChildren, useCallback, useEffect, useMemo, useState } from 'react';
+
+import { Loading } from '../components/Loading';
+import { MappingTree } from '../models/datamapper/mapping';
+import {
+ BODY_DOCUMENT_ID,
+ DocumentDefinition,
+ DocumentInitializationModel,
+ IDocument,
+ PrimitiveDocument,
+} from '../models/datamapper/document';
+import { CanvasView } from '../models/datamapper/view';
+import { DocumentType } from '../models/datamapper/path';
+import { MappingSerializerService } from '../services/mapping-serializer.service';
+import { MappingService } from '../services/mapping.service';
+import { DocumentService } from '../services/document.service';
+import { Alert, AlertActionCloseButton, AlertGroup, AlertProps, AlertVariant } from '@patternfly/react-core';
+
+export interface IDataMapperContext {
+ isLoading: boolean;
+ setIsLoading(isLoading: boolean): void;
+
+ activeView: CanvasView;
+ setActiveView(view: CanvasView): void;
+
+ initialExpandedFieldRank: number;
+ setInitialExpandedFieldRank: (rank: number) => void;
+ maxTotalFieldCountToExpandAll: number;
+ setMaxTotalFieldCountToExpandAll: (rank: number) => void;
+
+ sourceParameterMap: Map;
+ refreshSourceParameters: () => void;
+ deleteSourceParameter: (name: string) => void;
+ sourceBodyDocument: IDocument;
+ setSourceBodyDocument: (doc: IDocument) => void;
+ targetBodyDocument: IDocument;
+ setTargetBodyDocument: (doc: IDocument) => void;
+ updateDocumentDefinition: (definition: DocumentDefinition) => void;
+
+ isSourceParametersExpanded: boolean;
+ setSourceParametersExpanded: (expanded: boolean) => void;
+
+ mappingTree: MappingTree;
+ refreshMappingTree(): void;
+ setMappingTree(mappings: MappingTree): void;
+
+ alerts: Partial[];
+ addAlert: (alert: Partial) => void;
+
+ debug: boolean;
+ setDebug(debug: boolean): void;
+}
+
+export const DataMapperContext = createContext(null);
+
+type DataMapperProviderProps = PropsWithChildren & {
+ defaultInitialExpandedFieldRank?: number;
+ defaultMaxTotalFieldCountToExpandAll?: number;
+ documentInitializationModel?: DocumentInitializationModel;
+ onUpdateDocument?: (definition: DocumentDefinition) => void;
+ onDeleteParameter?: (name: string) => void;
+ initialXsltFile?: string;
+ onUpdateMappings?: (xsltFile: string) => void;
+};
+
+export const DataMapperProvider: FunctionComponent = ({
+ defaultInitialExpandedFieldRank = 1,
+ defaultMaxTotalFieldCountToExpandAll = 100,
+ documentInitializationModel,
+ onUpdateDocument,
+ onDeleteParameter,
+ initialXsltFile,
+ onUpdateMappings,
+ children,
+}) => {
+ const [debug, setDebug] = useState(false);
+ const [isLoading, setIsLoading] = useState(true);
+ const [activeView, setActiveView] = useState(CanvasView.SOURCE_TARGET);
+ const [initialExpandedFieldRank, setInitialExpandedFieldRank] = useState(defaultInitialExpandedFieldRank);
+ const [maxTotalFieldCountToExpandAll, setMaxTotalFieldCountToExpandAll] = useState(
+ defaultMaxTotalFieldCountToExpandAll,
+ );
+
+ const [sourceParameterMap, setSourceParameterMap] = useState>(new Map());
+ const [isSourceParametersExpanded, setSourceParametersExpanded] = useState(true);
+ const [sourceBodyDocument, setSourceBodyDocument] = useState(
+ new PrimitiveDocument(DocumentType.SOURCE_BODY, BODY_DOCUMENT_ID),
+ );
+ const [targetBodyDocument, setTargetBodyDocument] = useState(
+ new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID),
+ );
+ const [mappingTree, setMappingTree] = useState(
+ new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID),
+ );
+
+ const [alerts, setAlerts] = useState[]>([]);
+
+ useEffect(() => {
+ const documents = DocumentService.createInitialDocuments(documentInitializationModel);
+ let latestSourceParameterMap = sourceParameterMap;
+ let latestTargetBodyDocument = targetBodyDocument;
+ if (documents) {
+ documents.sourceBodyDocument && setSourceBodyDocument(documents.sourceBodyDocument);
+ setSourceParameterMap(documents.sourceParameterMap);
+ latestSourceParameterMap = documents.sourceParameterMap;
+ if (documents.targetBodyDocument) {
+ setTargetBodyDocument(documents.targetBodyDocument);
+ latestTargetBodyDocument = documents.targetBodyDocument;
+ }
+ }
+ if (initialXsltFile) {
+ const loaded = MappingSerializerService.deserialize(
+ initialXsltFile,
+ latestTargetBodyDocument,
+ mappingTree,
+ latestSourceParameterMap,
+ );
+ setMappingTree(loaded);
+ }
+ setIsLoading(false);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const refreshSourceParameters = useCallback(() => {
+ setSourceParameterMap(new Map(sourceParameterMap));
+ }, [sourceParameterMap]);
+
+ const deleteSourceParameter = useCallback(
+ (name: string) => {
+ sourceParameterMap.delete(name);
+ refreshSourceParameters();
+ onDeleteParameter && onDeleteParameter(name);
+ },
+ [onDeleteParameter, refreshSourceParameters, sourceParameterMap],
+ );
+
+ const refreshMappingTree = useCallback(() => {
+ const newMapping = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ newMapping.children = mappingTree.children.map((child) => {
+ child.parent = newMapping;
+ return child;
+ });
+ newMapping.namespaceMap = mappingTree.namespaceMap;
+ setMappingTree(newMapping);
+ onUpdateMappings && onUpdateMappings(MappingSerializerService.serialize(mappingTree, sourceParameterMap!));
+ }, [mappingTree, onUpdateMappings, sourceParameterMap]);
+
+ const removeStaleMappings = useCallback(
+ (documentType: DocumentType, documentId: string, newDocument: IDocument) => {
+ let isFromPrimitive: boolean;
+ switch (documentType) {
+ case DocumentType.SOURCE_BODY:
+ isFromPrimitive = sourceBodyDocument instanceof PrimitiveDocument;
+ break;
+ case DocumentType.TARGET_BODY:
+ isFromPrimitive = targetBodyDocument instanceof PrimitiveDocument;
+ break;
+ case DocumentType.PARAM:
+ isFromPrimitive = sourceParameterMap!.get(documentId) instanceof PrimitiveDocument;
+ }
+ const isToPrimitive = newDocument instanceof PrimitiveDocument;
+ const cleaned =
+ isFromPrimitive || isToPrimitive
+ ? MappingService.removeAllMappingsForDocument(mappingTree, documentType, documentId)
+ : MappingService.removeStaleMappingsForDocument(mappingTree, newDocument);
+ setMappingTree(cleaned);
+ },
+ [mappingTree, sourceBodyDocument, sourceParameterMap, targetBodyDocument],
+ );
+
+ const setNewDocument = useCallback(
+ (documentType: DocumentType, documentId: string, newDocument: IDocument) => {
+ switch (documentType) {
+ case DocumentType.SOURCE_BODY:
+ setSourceBodyDocument(newDocument);
+ break;
+ case DocumentType.TARGET_BODY:
+ setTargetBodyDocument(newDocument);
+ break;
+ case DocumentType.PARAM:
+ sourceParameterMap!.set(documentId, newDocument);
+ refreshSourceParameters();
+ break;
+ }
+ },
+ [refreshSourceParameters, sourceParameterMap],
+ );
+
+ const updateDocumentDefinition = useCallback(
+ (definition: DocumentDefinition) => {
+ const document = DocumentService.createDocument(definition);
+ if (!document) return;
+ removeStaleMappings(document.documentType, document.documentId, document);
+ setNewDocument(document.documentType, document.documentId, document);
+ onUpdateDocument && onUpdateDocument(definition);
+ },
+ [onUpdateDocument, removeStaleMappings, setNewDocument],
+ );
+
+ const addAlert = useCallback(
+ (option: Partial) => {
+ alerts.push(option);
+ setAlerts([...alerts]);
+ },
+ [alerts],
+ );
+
+ const closeAlert = useCallback(
+ (option: Partial) => {
+ const index = alerts.indexOf(option);
+ if (index > -1) {
+ alerts.splice(index, 1);
+ setAlerts([...alerts]);
+ }
+ },
+ [alerts],
+ );
+
+ const value = useMemo(() => {
+ return {
+ isLoading,
+ setIsLoading,
+ activeView,
+ setActiveView,
+ initialExpandedFieldRank,
+ setInitialExpandedFieldRank,
+ maxTotalFieldCountToExpandAll,
+ setMaxTotalFieldCountToExpandAll,
+ sourceParameterMap,
+ isSourceParametersExpanded,
+ setSourceParametersExpanded,
+ refreshSourceParameters,
+ deleteSourceParameter,
+ sourceBodyDocument,
+ setSourceBodyDocument,
+ targetBodyDocument,
+ setTargetBodyDocument,
+ updateDocumentDefinition,
+ mappingTree,
+ refreshMappingTree,
+ setMappingTree,
+ alerts,
+ addAlert,
+ debug,
+ setDebug,
+ };
+ }, [
+ isLoading,
+ activeView,
+ initialExpandedFieldRank,
+ maxTotalFieldCountToExpandAll,
+ sourceParameterMap,
+ isSourceParametersExpanded,
+ refreshSourceParameters,
+ deleteSourceParameter,
+ sourceBodyDocument,
+ targetBodyDocument,
+ updateDocumentDefinition,
+ mappingTree,
+ refreshMappingTree,
+ alerts,
+ addAlert,
+ debug,
+ ]);
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+ <>
+
+ {alerts.map((option, index) => (
+ closeAlert(option)}
+ actionClose={ closeAlert(option)} />}
+ >
+ ))}
+
+ {children}
+ >
+ )}
+
+ );
+};
diff --git a/packages/ui/src/providers/dnd/DataMapperDndMonitor.tsx b/packages/ui/src/providers/dnd/DataMapperDndMonitor.tsx
new file mode 100644
index 000000000..1ee1b5629
--- /dev/null
+++ b/packages/ui/src/providers/dnd/DataMapperDndMonitor.tsx
@@ -0,0 +1,40 @@
+import { FunctionComponent, useContext } from 'react';
+import { DataMapperDndContext } from '../datamapper-dnd.provider';
+import { NodeData } from '../../models/datamapper';
+import { DragOverEvent, useDndMonitor } from '@dnd-kit/core';
+
+export const DataMapperDnDMonitor: FunctionComponent = () => {
+ const { handler } = useContext(DataMapperDndContext);
+
+ useDndMonitor({
+ onDragStart(event) {
+ const fromField = event.active.data.current as NodeData;
+ console.log(`onDragStart: [active: ${fromField?.path.toString()}, handler=${handler?.constructor.name}]`);
+ },
+
+ onDragOver(event: DragOverEvent) {
+ const fromField = event.active?.data.current as NodeData;
+ const toField = event.over?.data.current as NodeData;
+ console.log(
+ `onDragOver: [active: ${fromField?.path.toString()}, over:${toField?.path.toString()}, handler=${handler?.constructor.name}]`,
+ );
+ },
+
+ onDragEnd(event) {
+ const fromField = event.active?.data.current as NodeData;
+ const toField = event.over?.data.current as NodeData;
+ console.log(
+ `onDragEnd: [active: ${fromField?.path.toString()}, over:${toField?.path.toString()}, handler=${handler?.constructor.name}]`,
+ );
+ },
+ onDragCancel(event) {
+ const fromField = event.active?.data.current as NodeData;
+ const toField = event.over?.data.current as NodeData;
+ console.log(
+ `onDragCancel: active: ${fromField?.path.toString()}, over:${toField?.path.toString()}, handler=${handler?.constructor.name}]`,
+ );
+ },
+ });
+
+ return <>>;
+};
diff --git a/packages/ui/src/providers/dnd/DnDHandler.ts b/packages/ui/src/providers/dnd/DnDHandler.ts
new file mode 100644
index 000000000..a00425ea3
--- /dev/null
+++ b/packages/ui/src/providers/dnd/DnDHandler.ts
@@ -0,0 +1,8 @@
+import { DragEndEvent, DragOverEvent, DragStartEvent } from '@dnd-kit/core';
+import { MappingTree } from '../../models/datamapper/mapping';
+
+export interface DnDHandler {
+ handleDragStart(event: DragStartEvent): void;
+ handleDragOver(event: DragOverEvent): void;
+ handleDragEnd(event: DragEndEvent, mappingTree: MappingTree, onUpdate: () => void): void;
+}
diff --git a/packages/ui/src/providers/dnd/ExpressionEditorDnDHandler.ts b/packages/ui/src/providers/dnd/ExpressionEditorDnDHandler.ts
new file mode 100644
index 000000000..70ef01ad9
--- /dev/null
+++ b/packages/ui/src/providers/dnd/ExpressionEditorDnDHandler.ts
@@ -0,0 +1,28 @@
+import { DnDHandler } from './DnDHandler';
+import { DragEndEvent, DragOverEvent, DragStartEvent } from '@dnd-kit/core';
+import { EditorNodeData, FieldNodeData, FunctionNodeData, MappingTree, NodeData } from '../../models/datamapper';
+import { MappingService } from '../../services/mapping.service';
+
+export class ExpressionEditorDnDHandler implements DnDHandler {
+ handleDragEnd(event: DragEndEvent, _mappingTree: MappingTree, onUpdate: () => void): void {
+ const fromNode = event.active.data.current as NodeData;
+ const toNode = event.over?.data.current as NodeData;
+ if (
+ !fromNode ||
+ !toNode ||
+ (!(fromNode instanceof FunctionNodeData) && !(fromNode instanceof FieldNodeData)) ||
+ !(toNode instanceof EditorNodeData)
+ )
+ return;
+ const editorNodeData = toNode as EditorNodeData;
+ if (fromNode instanceof FieldNodeData) {
+ MappingService.mapToCondition(editorNodeData.mapping, fromNode.field);
+ } else {
+ MappingService.wrapWithFunction(editorNodeData.mapping, fromNode.functionDefinition);
+ }
+ onUpdate();
+ }
+
+ handleDragOver(_event: DragOverEvent): void {}
+ handleDragStart(_event: DragStartEvent): void {}
+}
diff --git a/packages/ui/src/providers/dnd/SourceTargetDnDHandler.ts b/packages/ui/src/providers/dnd/SourceTargetDnDHandler.ts
new file mode 100644
index 000000000..12c3256e1
--- /dev/null
+++ b/packages/ui/src/providers/dnd/SourceTargetDnDHandler.ts
@@ -0,0 +1,21 @@
+import { DnDHandler } from './DnDHandler';
+import { DragEndEvent, DragOverEvent, DragStartEvent } from '@dnd-kit/core';
+import { MappingTree } from '../../models/datamapper/mapping';
+import { NodeData } from '../../models/datamapper/visualization';
+import { VisualizationService } from '../../services/visualization.service';
+
+export class SourceTargetDnDHandler implements DnDHandler {
+ handleDragEnd(event: DragEndEvent, mappingTree: MappingTree, onUpdate: () => void): void {
+ const fromNode = event.active.data.current as NodeData;
+ const toNode = event.over?.data.current as NodeData;
+ if (!fromNode || !toNode) return;
+ const { sourceNode, targetNode } = VisualizationService.testNodePair(fromNode, toNode);
+ if (sourceNode && targetNode) {
+ VisualizationService.engageMapping(mappingTree, sourceNode, targetNode);
+ onUpdate();
+ }
+ }
+
+ handleDragOver(_event: DragOverEvent): void {}
+ handleDragStart(_event: DragStartEvent): void {}
+}
diff --git a/packages/ui/src/providers/index.ts b/packages/ui/src/providers/index.ts
index 44019b2a8..0748b8d9f 100644
--- a/packages/ui/src/providers/index.ts
+++ b/packages/ui/src/providers/index.ts
@@ -6,6 +6,7 @@ export * from './action-confirmation-modal.provider';
export * from './entities.provider';
export * from './filtered-field.provider';
export * from './settings.provider';
+export * from './metadata.provider';
export * from './reload.context';
export * from './runtime.provider';
export * from './schema-bridge.provider';
diff --git a/packages/ui/src/providers/metadata.provider.tsx b/packages/ui/src/providers/metadata.provider.tsx
new file mode 100644
index 000000000..69331924d
--- /dev/null
+++ b/packages/ui/src/providers/metadata.provider.tsx
@@ -0,0 +1,68 @@
+import { FunctionComponent, PropsWithChildren, createContext } from 'react';
+
+export interface IMetadataApi {
+ /**
+ * Get metadata querying a Kaoto metadata file.
+ * @param key The key to retrieve the metadata from the Kaoto metadata file
+ */
+ getMetadata(key: string): Promise;
+
+ /**
+ * Save metadata to a Kaoto metadata file.
+ * @param key The key to set the metadata
+ * @param metadata The metadata to be saved
+ */
+ setMetadata(key: string, metadata: T): Promise;
+
+ /**
+ * Retrieve resource content
+ * @param path The path of the resource
+ */
+ getResourceContent(path: string): Promise;
+
+ /**
+ * Save resource content
+ * @param path The path of the resource
+ * @param content The content to be saved
+ */
+ saveResourceContent(path: string, content: string): Promise;
+
+ /**
+ * Delete resource
+ * @param path The path of the resource
+ */
+ deleteResource(path: string): Promise;
+
+ /**
+ * Show a Quick Pick widget and ask the user to select one or more files available in the workspace.
+ * @param include The filter expression for the files to include
+ * @param exclude The filter expression for the files to exclude
+ * @param options The options to pass over to VSCode QuickPick
+ */
+ askUserForFileSelection(
+ include: string,
+ exclude?: string,
+ options?: Record,
+ ): Promise;
+
+ /**
+ * A flag indicates that if the schema file needs to be saved or not. If it's running inside the VS Code,
+ * the schema file is supposed to be read from existing workspace file, therefore it should not save it and overwrite.
+ * On the other hand, if it's running in the browser, the schema file is uploaded directly from the browser, therefore
+ * it needs to be saved to some store.
+ * TODO The file saving in the browser is not implemented yet. If we implement the browser side to be same as what's done
+ * in VS Code, i.e. expecting schema files already in some store and just pick from there, we can remove this.
+ */
+ shouldSaveSchema: boolean;
+}
+
+export const MetadataContext = createContext(undefined);
+
+/**
+ * The goal for this provider is to expose a settings adapter to the SettingsForm component
+ * and its children, so they can be used to render the form fields.
+ * In addition to that, it also provides a mechanism to read/write the settings values.
+ */
+export const MetadataProvider: FunctionComponent> = ({ api, children }) => {
+ return {children} ;
+};
diff --git a/packages/ui/src/router.tsx b/packages/ui/src/router.tsx
index 00237a079..f012bbd3d 100644
--- a/packages/ui/src/router.tsx
+++ b/packages/ui/src/router.tsx
@@ -37,6 +37,14 @@ export const router = createHashRouter([
path: Links.Settings,
lazy: async () => import('./pages/Settings'),
},
+ {
+ path: Links.DataMapper,
+ lazy: async () => import('./pages/DataMapperNotYetInBrowser'),
+ },
+ {
+ path: `${Links.DataMapper}/:id`,
+ lazy: async () => import('./pages/DataMapper'),
+ },
],
},
]);
diff --git a/packages/ui/src/router/links.models.ts b/packages/ui/src/router/links.models.ts
index 369bcb0a4..3a1e7cdcf 100644
--- a/packages/ui/src/router/links.models.ts
+++ b/packages/ui/src/router/links.models.ts
@@ -1,6 +1,7 @@
export const enum Links {
Home = '/', // Flows visualization
SourceCode = '/code', // Flows source code
+ DataMapper = '/datamapper',
Beans = '/beans',
Rest = '/rest',
Metadata = '/metadata',
diff --git a/packages/ui/src/services/datamapper-metadata.service.ts b/packages/ui/src/services/datamapper-metadata.service.ts
new file mode 100644
index 000000000..0d7110f4f
--- /dev/null
+++ b/packages/ui/src/services/datamapper-metadata.service.ts
@@ -0,0 +1,232 @@
+import { ProcessorDefinition } from '@kaoto/camel-catalog/types';
+import { EntitiesContextResult } from '../hooks';
+import { IVisualizationNode } from '../models';
+import {
+ BODY_DOCUMENT_ID,
+ DocumentDefinition,
+ DocumentDefinitionType,
+ DocumentInitializationModel,
+ DocumentType,
+} from '../models/datamapper';
+import { IDataMapperMetadata, IDocumentMetadata } from '../models/datamapper/metadata';
+import { IMetadataApi } from '../providers';
+import { isDefined, isXSLTComponent, XSLT_COMPONENT_NAME } from '../utils';
+import type { XsltComponentDef } from '../utils/is-xslt-component';
+import { EMPTY_XSL } from './mapping-serializer.service';
+
+export class DataMapperMetadataService {
+ static readonly SCHEMA_NAME_PATTERN = '**/*.{xsd,xml,XSD,XML}';
+
+ static getDataMapperMetadataId(vizNode: IVisualizationNode) {
+ const model = vizNode.getComponentSchema()?.definition;
+ return model.id;
+ }
+
+ static async initializeDataMapperMetadata(
+ entitiesContext: EntitiesContextResult,
+ vizNode: IVisualizationNode,
+ api: IMetadataApi,
+ metadataId: string,
+ ): Promise {
+ const model = vizNode.getComponentSchema()?.definition;
+ const xsltStep = (model.steps as ProcessorDefinition[] | undefined)?.find(isXSLTComponent);
+ let documentName = this.getXSLTDocumentName(xsltStep);
+
+ if (isDefined(xsltStep) && !isDefined(documentName)) {
+ /** At this point, the Kaoto DataMapper is not yet configured, hence we create the XSLT mapping document name */
+ documentName = `${metadataId}.xsl`;
+ xsltStep.to.uri = `${XSLT_COMPONENT_NAME}:${documentName}`;
+ vizNode.updateModel(model);
+ entitiesContext.updateSourceCodeFromEntities();
+ }
+
+ const metadata = {
+ sourceBody: {
+ type: DocumentDefinitionType.Primitive,
+ },
+ sourceParameters: {},
+ targetBody: {
+ type: DocumentDefinitionType.Primitive,
+ },
+ xsltPath: documentName,
+ } as IDataMapperMetadata;
+
+ const metadataPromise = api.setMetadata(metadataId, metadata);
+ const contentPromise = api.saveResourceContent(metadata.xsltPath, EMPTY_XSL);
+ await Promise.allSettled([metadataPromise, contentPromise]);
+
+ return metadata;
+ }
+
+ static loadDocuments(api: IMetadataApi, metadata: IDataMapperMetadata): Promise {
+ return new Promise((resolve) => {
+ const answer = new DocumentInitializationModel();
+ const sourceBodyPromise = DataMapperMetadataService.doLoadDocument(
+ api,
+ DocumentType.SOURCE_BODY,
+ BODY_DOCUMENT_ID,
+ metadata.sourceBody,
+ ).then((definition) => (answer.sourceBody = definition));
+ const targetBodyPromise = DataMapperMetadataService.doLoadDocument(
+ api,
+ DocumentType.TARGET_BODY,
+ BODY_DOCUMENT_ID,
+ metadata.targetBody,
+ ).then((definition) => (answer.targetBody = definition));
+ const paramPromises = Object.entries(metadata.sourceParameters).reduce(
+ (acc, [key, meta]) => {
+ acc[key] = DataMapperMetadataService.doLoadDocument(api, DocumentType.PARAM, key, meta).then(
+ (definition) => (answer.sourceParameters[key] = definition),
+ );
+ return acc;
+ },
+ {} as Record>,
+ );
+ Promise.allSettled([sourceBodyPromise, targetBodyPromise, Object.values(paramPromises)]).then(() => {
+ resolve(answer);
+ });
+ });
+ }
+
+ static getXSLTDocumentName(xsltStep?: XsltComponentDef): string | undefined {
+ if (!xsltStep) {
+ return undefined;
+ }
+
+ const [_componentUri, uriFileName] = xsltStep.to.uri.split(':');
+ return uriFileName;
+ }
+
+ private static doLoadDocument(
+ api: IMetadataApi,
+ documentType: DocumentType,
+ name: string,
+ documentMetadata: IDocumentMetadata,
+ ): Promise {
+ return new Promise((resolve) => {
+ const definitionType = documentMetadata.type ? documentMetadata.type : DocumentDefinitionType.Primitive;
+ const definitionFiles: Record = {};
+ const fileReadingPromises = !documentMetadata.filePath
+ ? []
+ : documentMetadata.filePath.map((path) =>
+ api
+ .getResourceContent(path)
+ .then((value) => {
+ if (value) definitionFiles[path] = value;
+ })
+ .catch((reason) => console.log(`Could not read a file "${path}": ${reason}`)),
+ );
+ Promise.allSettled(fileReadingPromises).then(() => {
+ const answer = new DocumentDefinition(documentType, definitionType, name, definitionFiles);
+ resolve(answer);
+ });
+ });
+ }
+
+ static loadMappingFile(api: IMetadataApi, metadata: IDataMapperMetadata): Promise {
+ return api.getResourceContent(metadata.xsltPath);
+ }
+
+ static async updateSourceBodyMetadata(
+ api: IMetadataApi,
+ metadataId: string,
+ metadata: IDataMapperMetadata,
+ definition: DocumentDefinition,
+ ) {
+ metadata.sourceBody = await DataMapperMetadataService.doCreateDocumentMetadata(
+ api,
+ metadataId,
+ metadata,
+ definition,
+ );
+ api.setMetadata(metadataId, metadata);
+ }
+
+ private static doCreateDocumentMetadata(
+ api: IMetadataApi,
+ metadataId: string,
+ metadata: IDataMapperMetadata,
+ definition: DocumentDefinition,
+ ): Promise {
+ const filePaths = definition.definitionFiles ? Object.keys(definition.definitionFiles) : [];
+ const answer = {
+ type: definition.definitionType,
+ filePath: filePaths,
+ };
+ const metadataPromise = api.setMetadata(metadataId, metadata);
+ const filePromises =
+ api.shouldSaveSchema && definition.definitionFiles
+ ? Object.entries(definition.definitionFiles).map(([path, content]) => {
+ api
+ .saveResourceContent(path, content)
+ .catch((error) => console.log(`Could not save a file "${path}": ${error}`));
+ })
+ : [];
+ return new Promise((resolve) => {
+ Promise.allSettled([metadataPromise, ...filePromises]).then(() => resolve(answer));
+ });
+ }
+
+ static async updateTargetBodyMetadata(
+ api: IMetadataApi,
+ metadataId: string,
+ metadata: IDataMapperMetadata,
+ definition: DocumentDefinition,
+ ) {
+ metadata.targetBody = await DataMapperMetadataService.doCreateDocumentMetadata(
+ api,
+ metadataId,
+ metadata,
+ definition,
+ );
+ api.setMetadata(metadataId, metadata);
+ }
+
+ static async updateSourceParameterMetadata(
+ api: IMetadataApi,
+ metadataId: string,
+ metadata: IDataMapperMetadata,
+ name: string,
+ definition: DocumentDefinition,
+ ) {
+ metadata.sourceParameters[name] = await DataMapperMetadataService.doCreateDocumentMetadata(
+ api,
+ metadataId,
+ metadata,
+ definition,
+ );
+ api.setMetadata(metadataId, metadata);
+ }
+
+ static async deleteSourceParameterMetadata(
+ api: IMetadataApi,
+ metadataId: string,
+ metadata: IDataMapperMetadata,
+ name: string,
+ ) {
+ delete metadata.sourceParameters[name];
+ api.setMetadata(metadataId, metadata);
+ }
+
+ static async updateMappingFile(api: IMetadataApi, metadata: IDataMapperMetadata, xsltFile: string) {
+ await api.saveResourceContent(metadata.xsltPath, xsltFile);
+ }
+
+ static async selectDocumentSchema(api: IMetadataApi) {
+ return await api.askUserForFileSelection(this.SCHEMA_NAME_PATTERN, undefined, {
+ canPickMany: false, // TODO set to true once we support xs:include/xs:import, i.e. multiple files
+ placeHolder:
+ 'Choose the schema file to attach. Type a text to narrow down the candidates. The file path is shown as a relative path from the active Camel file opening with Kaoto.',
+ title: 'Attaching document schema file',
+ });
+ }
+
+ static async deleteMetadata(api: IMetadataApi, metadataId: string) {
+ await api.setMetadata(metadataId, undefined);
+ }
+
+ static async deleteXsltFile(api: IMetadataApi, metadataId: string) {
+ const metadata = (await api.getMetadata(metadataId)) as IDataMapperMetadata;
+ await api.deleteResource(metadata.xsltPath);
+ }
+}
diff --git a/packages/ui/src/services/document.service.test.ts b/packages/ui/src/services/document.service.test.ts
new file mode 100644
index 000000000..097626e79
--- /dev/null
+++ b/packages/ui/src/services/document.service.test.ts
@@ -0,0 +1,42 @@
+import { DocumentService } from './document.service';
+
+import { TestUtil } from '../stubs/data-mapper';
+
+describe('DocumentService', () => {
+ const sourceDoc = TestUtil.createSourceOrderDoc();
+ const targetDoc = TestUtil.createTargetOrderDoc();
+
+ describe('getFieldStack()', () => {
+ it('', () => {
+ const stack = DocumentService.getFieldStack(sourceDoc.fields[0].fields[1]);
+ expect(stack.length).toEqual(1);
+ expect(stack[0].name).toEqual('ShipOrder');
+ const stackWithSelf = DocumentService.getFieldStack(sourceDoc.fields[0].fields[1], true);
+ expect(stackWithSelf.length).toEqual(2);
+ expect(stackWithSelf[0].name).toEqual('OrderPerson');
+ });
+ });
+
+ describe('hasField()', () => {
+ it('', () => {
+ expect(DocumentService.hasField(sourceDoc, sourceDoc.fields[0].fields[0])).toBeTruthy();
+ expect(DocumentService.hasField(sourceDoc, targetDoc.fields[0].fields[0])).toBeFalsy();
+ });
+ });
+
+ describe('getFieldFromPathExpression()', () => {
+ it('', () => {
+ const pathExpression = '/ShipOrder/ShipTo';
+ const field = DocumentService.getFieldFromPathExpression(sourceDoc, pathExpression);
+ expect(field?.name).toEqual('ShipTo');
+ });
+ });
+
+ describe('getFieldFromPathSegments()', () => {
+ it('', () => {
+ const pathSegments = ['ShipOrder', 'ShipTo'];
+ const field = DocumentService.getFieldFromPathSegments(sourceDoc, pathSegments);
+ expect(field?.name).toEqual('ShipTo');
+ });
+ });
+});
diff --git a/packages/ui/src/services/document.service.ts b/packages/ui/src/services/document.service.ts
new file mode 100644
index 000000000..0f4523ef2
--- /dev/null
+++ b/packages/ui/src/services/document.service.ts
@@ -0,0 +1,193 @@
+import {
+ BODY_DOCUMENT_ID,
+ DocumentDefinition,
+ DocumentDefinitionType,
+ DocumentInitializationModel,
+ IDocument,
+ IField,
+ IParentType,
+ ITypeFragment,
+ PrimitiveDocument,
+} from '../models/datamapper/document';
+import { DocumentType } from '../models/datamapper/path';
+import { XmlSchemaDocumentService } from './xml-schema-document.service';
+import { IMetadataApi } from '../providers';
+
+interface InitialDocumentsSet {
+ sourceBodyDocument?: IDocument;
+ sourceParameterMap: Map;
+ targetBodyDocument?: IDocument;
+}
+
+export class DocumentService {
+ static async createDocumentDefinition(
+ api: IMetadataApi,
+ documentType: DocumentType,
+ definitionType: DocumentDefinitionType,
+ documentId: string,
+ schemaFilePaths: string[],
+ ): Promise {
+ if (!schemaFilePaths || schemaFilePaths.length === 0) return;
+ const fileContents: Record = {};
+ const fileContentPromises: Promise[] = [];
+ schemaFilePaths.forEach((path: string) => {
+ const promise = api.getResourceContent(path).then((content: string | undefined) => {
+ if (content) fileContents[path] = content;
+ });
+ fileContentPromises.push(promise);
+ });
+ await Promise.allSettled(fileContentPromises);
+ return new DocumentDefinition(documentType, definitionType, documentId, fileContents);
+ }
+
+ static createDocument(definition: DocumentDefinition): IDocument | null {
+ if (definition.definitionType === DocumentDefinitionType.Primitive) {
+ return new PrimitiveDocument(definition.documentType, DocumentType.PARAM ? definition.name! : BODY_DOCUMENT_ID);
+ }
+ if (!definition.definitionFiles || Object.keys(definition.definitionFiles).length === 0) return null;
+ const content = Object.values(definition.definitionFiles)[0];
+ const documentId = definition.documentType === DocumentType.PARAM ? definition.name! : BODY_DOCUMENT_ID;
+ return XmlSchemaDocumentService.createXmlSchemaDocument(definition.documentType, documentId, content);
+ }
+
+ static createInitialDocuments(initModel?: DocumentInitializationModel): InitialDocumentsSet | null {
+ if (!initModel) return null;
+ const answer: InitialDocumentsSet = {
+ sourceParameterMap: new Map(),
+ };
+ if (initModel.sourceBody) {
+ const document = DocumentService.createDocument(initModel.sourceBody);
+ if (document) answer.sourceBodyDocument = document;
+ }
+ if (initModel.sourceParameters) {
+ Object.entries(initModel.sourceParameters).forEach(([key, value]) => {
+ const document = DocumentService.createDocument(value);
+ answer.sourceParameterMap.set(key, document ? document : new PrimitiveDocument(DocumentType.PARAM, key));
+ });
+ }
+ if (initModel.targetBody) {
+ const document = DocumentService.createDocument(initModel.targetBody);
+ if (document) answer.targetBodyDocument = document;
+ }
+ return answer;
+ }
+
+ static getFieldStack(field: IField, includeItself: boolean = false) {
+ if (field instanceof PrimitiveDocument) return [];
+ const fieldStack: IField[] = [];
+ if (includeItself) fieldStack.push(field);
+ for (let next = field.parent; 'parent' in next && next !== next.parent; next = (next as IField).parent) {
+ fieldStack.push(next);
+ }
+ return fieldStack;
+ }
+
+ static hasField(document: IDocument, field: IField) {
+ if (
+ document.documentType !== field.ownerDocument.documentType ||
+ document.documentId !== field.ownerDocument.documentId
+ )
+ return false;
+ if (document instanceof PrimitiveDocument && document === field) return true;
+
+ return DocumentService.isDescendant(document, field);
+ }
+
+ static isDescendant(parent: IField | IDocument, child: IField): boolean {
+ return !!parent.fields.find((f) => f === child || DocumentService.isDescendant(f, child));
+ }
+
+ static getCompatibleField(document: IDocument, field: IField): IField | undefined {
+ if (document instanceof PrimitiveDocument) return field instanceof PrimitiveDocument ? document : undefined;
+ if (field instanceof PrimitiveDocument) return undefined;
+
+ let left: IField | undefined = undefined;
+ const fieldStack = DocumentService.getFieldStack(field, true);
+ for (const right of fieldStack.reverse()) {
+ const parent: IParentType = left ? left : document;
+ left = parent.fields.find((leftTest: IField) => {
+ const isAttributeOrElementMatching = leftTest.isAttribute === right.isAttribute;
+ const isNamespaceMatching =
+ !leftTest.ownerDocument.isNamespaceAware ||
+ !right.ownerDocument.isNamespaceAware ||
+ leftTest.namespaceURI === right.namespaceURI;
+ return isAttributeOrElementMatching && isNamespaceMatching && leftTest.name === right.name;
+ });
+ if (!left) return undefined;
+ }
+ return left;
+ }
+
+ static getFieldFromPathSegments(document: IDocument, pathSegments: string[]) {
+ let parent: IDocument | IField = document;
+ for (const segment of pathSegments) {
+ if (!segment) continue;
+ const child: IField | undefined = parent.fields.find((f) => DocumentService.getFieldExpression(f) === segment);
+ if (!child) {
+ return undefined;
+ }
+ parent = child;
+ }
+ return parent;
+ }
+
+ static getFieldFromPathExpression(document: IDocument, pathExpression: string) {
+ return DocumentService.getFieldFromPathSegments(document, pathExpression.split('/'));
+ }
+
+ static getFieldExpression(field: IField) {
+ return field.isAttribute ? `@${field.name}` : field.name;
+ }
+
+ static getFieldExpressionNS(field: IField, namespaceMap: { [prefix: string]: string }) {
+ let answer = field.isAttribute ? '@' : '';
+ const nsPair =
+ field.namespaceURI &&
+ Object.entries(namespaceMap).find(([prefix, uri]) => prefix && uri && field.namespaceURI === uri);
+ if (nsPair) answer += nsPair[0] + ':';
+ return answer + field.name;
+ }
+
+ static getOwnerDocument(docOrField: IParentType): DocumentType {
+ return ('ownerDocument' in docOrField ? docOrField.ownerDocument : docOrField) as DocumentType;
+ }
+
+ static resolveTypeFragment(field: IField) {
+ if (field.namedTypeFragmentRefs.length === 0) return field;
+ const doc = DocumentService.getOwnerDocument(field);
+ field.namedTypeFragmentRefs.forEach((ref) => {
+ const fragment = doc.namedTypeFragments[ref];
+ DocumentService.adoptTypeFragment(field, fragment);
+ });
+ field.namedTypeFragmentRefs = [];
+ return field;
+ }
+
+ private static adoptTypeFragment(field: IField, fragment: ITypeFragment) {
+ const doc = DocumentService.getOwnerDocument(field);
+ fragment.fields.forEach((f) => f.adopt(field));
+ fragment.namedTypeFragmentRefs.forEach((childRef) => {
+ const childFragment = doc.namedTypeFragments[childRef];
+ DocumentService.adoptTypeFragment(field, childFragment);
+ });
+ }
+
+ static isNonPrimitiveField(parent: IParentType) {
+ return parent && !('documentType' in parent);
+ }
+
+ static isRecursiveField(field: IField) {
+ const name = field.name;
+ const namespace = field.namespaceURI;
+ const stack = DocumentService.getFieldStack(field);
+ return !!stack.find((f) => f.name === name && f.namespaceURI === namespace);
+ }
+
+ static hasFields(document: IDocument) {
+ return !(document instanceof PrimitiveDocument) && document.fields.length > 0;
+ }
+
+ static hasChildren(field: IField) {
+ return field.fields.length > 0 || field.namedTypeFragmentRefs.length > 0;
+ }
+}
diff --git a/packages/ui/src/services/mapping-serializer.service.test.ts b/packages/ui/src/services/mapping-serializer.service.test.ts
new file mode 100644
index 000000000..31c4a4436
--- /dev/null
+++ b/packages/ui/src/services/mapping-serializer.service.test.ts
@@ -0,0 +1,324 @@
+import { EMPTY_XSL, MappingSerializerService, NS_XSL } from './mapping-serializer.service';
+import { BODY_DOCUMENT_ID } from '../models/datamapper/document';
+import {
+ ChooseItem,
+ FieldItem,
+ ForEachItem,
+ IfItem,
+ MappingTree,
+ OtherwiseItem,
+ ValueSelector,
+ WhenItem,
+} from '../models/datamapper/mapping';
+import { DocumentType } from '../models/datamapper/path';
+import { Types } from '../models/datamapper/types';
+
+import { shipOrderToShipOrderXslt, shipOrderToShipOrderInvalidForEachXslt, TestUtil } from '../stubs/data-mapper';
+
+describe('MappingSerializerService', () => {
+ const sourceParameterMap = TestUtil.createParameterMap();
+ const targetDoc = TestUtil.createTargetOrderDoc();
+
+ const domParser = new DOMParser();
+
+ it('createNew() should create am empty XSLT document', () => {
+ const xslt = MappingSerializerService.createNew();
+ const stylesheet = xslt.getElementsByTagNameNS(NS_XSL, 'stylesheet');
+ expect(stylesheet.length).toEqual(1);
+ expect(stylesheet[0].namespaceURI).toBe(NS_XSL);
+ expect(stylesheet[0].localName).toBe('stylesheet');
+ const template = xslt.getElementsByTagNameNS(NS_XSL, 'template');
+ expect(template.length).toEqual(1);
+ expect(template[0].namespaceURI).toBe(NS_XSL);
+ expect(template[0].localName).toBe('template');
+ });
+
+ describe('deserialize()', () => {
+ it('should return an empty MappingTree', () => {
+ let mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ mappingTree = MappingSerializerService.deserialize(EMPTY_XSL, targetDoc, mappingTree, sourceParameterMap);
+ expect(mappingTree.children.length).toEqual(0);
+ mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ mappingTree = MappingSerializerService.deserialize('', targetDoc, mappingTree, sourceParameterMap);
+ expect(mappingTree.children.length).toEqual(0);
+ });
+
+ it('should deserialize XSLT', () => {
+ let mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ expect(Object.keys(mappingTree.namespaceMap).length).toEqual(0);
+ mappingTree = MappingSerializerService.deserialize(
+ shipOrderToShipOrderXslt,
+ targetDoc,
+ mappingTree,
+ sourceParameterMap,
+ );
+ expect(Object.keys(mappingTree.namespaceMap).length).toEqual(1);
+ expect(mappingTree.namespaceMap['ns0']).toEqual('io.kaoto.datamapper.poc.test');
+ expect(mappingTree.children.length).toEqual(1);
+ const shipOrderFieldItem = mappingTree.children[0] as FieldItem;
+ expect(shipOrderFieldItem.field.name).toEqual('ShipOrder');
+ expect(shipOrderFieldItem.field.type).toEqual(Types.Container);
+ expect(shipOrderFieldItem.field.isAttribute).toBeFalsy();
+ expect(shipOrderFieldItem.field.namespaceURI).toEqual('io.kaoto.datamapper.poc.test');
+ expect(shipOrderFieldItem.field.maxOccurs).toEqual(1);
+ expect(shipOrderFieldItem.children.length).toEqual(4);
+
+ const orderIdFieldItem = shipOrderFieldItem.children[0] as FieldItem;
+ expect(orderIdFieldItem.field.name).toEqual('OrderId');
+ expect(orderIdFieldItem.field.type).not.toEqual(Types.Container);
+ expect(orderIdFieldItem.field.isAttribute).toBeTruthy();
+ expect(orderIdFieldItem.field.namespaceURI).toEqual('');
+ expect(orderIdFieldItem.field.maxOccurs).toEqual(1);
+ expect(orderIdFieldItem.children.length).toEqual(1);
+ let selector = orderIdFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('/ns0:ShipOrder/@OrderId');
+
+ const ifItem = shipOrderFieldItem.children[1] as IfItem;
+ expect(ifItem.expression).toEqual("/ns0:ShipOrder/ns0:OrderPerson != ''");
+ expect(ifItem.children.length).toEqual(1);
+ const orderPersonFieldItem = ifItem.children[0] as FieldItem;
+ expect(orderPersonFieldItem.field.name).toEqual('OrderPerson');
+ expect(shipOrderFieldItem.field.type).toEqual(Types.Container);
+ expect(orderPersonFieldItem.field.isAttribute).toBeFalsy();
+ expect(orderPersonFieldItem.field.namespaceURI).toEqual('io.kaoto.datamapper.poc.test');
+ expect(orderPersonFieldItem.field.maxOccurs).toEqual(1);
+ expect(orderPersonFieldItem.children.length).toEqual(1);
+ selector = orderPersonFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('/ns0:ShipOrder/ns0:OrderPerson');
+
+ const shipToFieldItem = shipOrderFieldItem.children[2] as FieldItem;
+ expect(shipToFieldItem.field.name).toEqual('ShipTo');
+ expect(shipToFieldItem.field.isAttribute).toBeFalsy();
+ expect(shipToFieldItem.field.type).toEqual(Types.Container);
+ expect(shipToFieldItem.field.namespaceURI).toEqual('');
+ expect(shipToFieldItem.field.maxOccurs).toEqual(1);
+ expect(shipToFieldItem.children.length).toEqual(1);
+ selector = shipToFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('/ns0:ShipOrder/ShipTo');
+
+ const forEachItem = shipOrderFieldItem.children[3] as ForEachItem;
+ expect(forEachItem.expression).toEqual('/ns0:ShipOrder/Item');
+ expect(forEachItem.children.length).toEqual(1);
+ const itemFieldItem = forEachItem.children[0] as FieldItem;
+ expect(itemFieldItem.field.name).toEqual('Item');
+ expect(itemFieldItem.field.type).toEqual(Types.Container);
+ expect(itemFieldItem.field.isAttribute).toBeFalsy();
+ expect(itemFieldItem.field.namespaceURI).toEqual('');
+ expect(itemFieldItem.field.maxOccurs).toBeGreaterThan(1);
+ expect(itemFieldItem.children.length).toEqual(4);
+
+ const titleFieldItem = itemFieldItem.children[0] as FieldItem;
+ expect(titleFieldItem.field.name).toEqual('Title');
+ expect(titleFieldItem.field.isAttribute).toBeFalsy();
+ expect(titleFieldItem.field.type).not.toEqual(Types.Container);
+ expect(titleFieldItem.field.namespaceURI).toEqual('');
+ expect(titleFieldItem.field.maxOccurs).toEqual(1);
+ expect(titleFieldItem.children.length).toEqual(1);
+ selector = titleFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('Title');
+
+ const chooseItem = itemFieldItem.children[1] as ChooseItem;
+ expect(chooseItem.children.length).toEqual(2);
+
+ const whenItem = chooseItem.children[0] as WhenItem;
+ expect(whenItem.expression).toEqual("Note != ''");
+ expect(whenItem.children.length).toEqual(1);
+ let noteFieldItem = whenItem.children[0] as FieldItem;
+ expect(noteFieldItem.field.name).toEqual('Note');
+ expect(noteFieldItem.field.type).not.toEqual(Types.Container);
+ expect(noteFieldItem.field.isAttribute).toBeFalsy();
+ expect(noteFieldItem.field.namespaceURI).toEqual('');
+ expect(noteFieldItem.field.maxOccurs).toEqual(1);
+ expect(noteFieldItem.children.length).toEqual(1);
+ selector = noteFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('Note');
+
+ const otherwiseItem = chooseItem.children[1] as OtherwiseItem;
+ expect(otherwiseItem.children.length).toEqual(1);
+ noteFieldItem = otherwiseItem.children[0] as FieldItem;
+ expect(noteFieldItem.field.name).toEqual('Note');
+ expect(noteFieldItem.field.type).not.toEqual(Types.Container);
+ expect(noteFieldItem.field.isAttribute).toBeFalsy();
+ expect(noteFieldItem.field.namespaceURI).toEqual('');
+ expect(noteFieldItem.field.maxOccurs).toEqual(1);
+ expect(noteFieldItem.children.length).toEqual(1);
+ selector = noteFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('Title');
+
+ const quantityFieldItem = itemFieldItem.children[2] as FieldItem;
+ expect(quantityFieldItem.field.name).toEqual('Quantity');
+ expect(quantityFieldItem.field.type).not.toEqual(Types.Container);
+ expect(quantityFieldItem.field.isAttribute).toBeFalsy();
+ expect(quantityFieldItem.field.namespaceURI).toEqual('');
+ expect(quantityFieldItem.field.maxOccurs).toEqual(1);
+ expect(quantityFieldItem.children.length).toEqual(1);
+ selector = quantityFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('Quantity');
+
+ const priceFieldItem = itemFieldItem.children[3] as FieldItem;
+ expect(priceFieldItem.field.name).toEqual('Price');
+ expect(priceFieldItem.field.type).not.toEqual(Types.Container);
+ expect(priceFieldItem.field.isAttribute).toBeFalsy();
+ expect(priceFieldItem.field.namespaceURI).toEqual('');
+ expect(priceFieldItem.field.maxOccurs).toEqual(1);
+ expect(priceFieldItem.children.length).toEqual(1);
+ selector = priceFieldItem.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('Price');
+ });
+
+ it('should deserialize incomplete XSLT', () => {
+ let mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ mappingTree = MappingSerializerService.deserialize(
+ shipOrderToShipOrderInvalidForEachXslt,
+ targetDoc,
+ mappingTree,
+ sourceParameterMap,
+ );
+ const forEachItem = mappingTree.children[0].children[0] as ForEachItem;
+ expect(forEachItem.expression).toEqual('');
+ const itemSelector = forEachItem.children[0].children[0] as ValueSelector;
+ expect(itemSelector.expression).toEqual('/ns0:ShipOrder/Item');
+ });
+ });
+
+ describe('serialize()', () => {
+ it('should return an empty XSLT document with empty mappings', () => {
+ const empty = MappingSerializerService.serialize(
+ new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID),
+ sourceParameterMap,
+ );
+ expect(empty).toContain('This file is generated by Kaoto DataMapper. Do not edit');
+ const dom = domParser.parseFromString(empty, 'application/xml');
+ const template = dom
+ .evaluate('/xsl:stylesheet/xsl:template', dom, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE)
+ .iterateNext();
+ expect(template).toBeTruthy();
+ expect(template!.childNodes.length).toEqual(1);
+ expect(template!.childNodes[0].nodeType).toEqual(Node.TEXT_NODE);
+ });
+
+ it('should serialize mappings', () => {
+ let mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ mappingTree = MappingSerializerService.deserialize(
+ shipOrderToShipOrderXslt,
+ targetDoc,
+ mappingTree,
+ sourceParameterMap,
+ );
+ const xslt = MappingSerializerService.serialize(mappingTree, sourceParameterMap);
+ const xsltDocument = domParser.parseFromString(xslt, 'text/xml');
+ expect(xsltDocument.documentElement.getAttribute('xmlns:ns0')).toEqual('io.kaoto.datamapper.poc.test');
+ const orderIdSelect = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:attribute[@name="OrderId"]/xsl:value-of/@select',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(orderIdSelect?.nodeValue).toEqual('/ns0:ShipOrder/@OrderId');
+ const ifTest = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:if/@test',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(ifTest?.nodeValue).toEqual("/ns0:ShipOrder/ns0:OrderPerson != ''");
+ const orderPersonSelect = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:if/OrderPerson/xsl:value-of/@select',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(orderPersonSelect?.nodeValue).toEqual('/ns0:ShipOrder/ns0:OrderPerson');
+ const shipToSelect = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/ShipTo/xsl:copy-of/@select',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(shipToSelect?.nodeValue).toEqual('/ns0:ShipOrder/ShipTo');
+ const forEachSelect = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:for-each/@select',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(forEachSelect?.nodeValue).toEqual('/ns0:ShipOrder/Item');
+ const titleSelect = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:for-each/Item/Title/xsl:value-of/@select',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(titleSelect?.nodeValue).toEqual('Title');
+ const chooseWhenTest = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:for-each/Item/xsl:choose/xsl:when/@test',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(chooseWhenTest?.nodeValue).toEqual("Note != ''");
+ const chooseWhenSelect = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:for-each/Item/xsl:choose/xsl:when/Note/xsl:value-of/@select',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(chooseWhenSelect?.nodeValue).toEqual('Note');
+ const chooseOtherwiseSelect = xsltDocument
+ .evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/xsl:for-each/Item/xsl:choose/xsl:otherwise/Note/xsl:value-of/@select',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ )
+ .iterateNext();
+ expect(chooseOtherwiseSelect?.nodeValue).toEqual('Title');
+ });
+
+ it('should serialize mappings with respecting Document field order', () => {
+ let mappingTree = new MappingTree(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ mappingTree = MappingSerializerService.deserialize(
+ shipOrderToShipOrderXslt,
+ targetDoc,
+ mappingTree,
+ sourceParameterMap,
+ );
+ const shipOrderItem = mappingTree.children[0];
+ shipOrderItem.children = shipOrderItem.children.reverse();
+ const xslt = MappingSerializerService.serialize(mappingTree, sourceParameterMap);
+ const xsltDocument = domParser.parseFromString(xslt, 'text/xml');
+ const shipOrderSelect = xsltDocument.evaluate(
+ '/xsl:stylesheet/xsl:template/ShipOrder/*',
+ xsltDocument,
+ null,
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE,
+ );
+ const xslAttribute = shipOrderSelect.iterateNext() as Element;
+ expect(xslAttribute!.nodeName).toEqual('xsl:attribute');
+ const xslIf = shipOrderSelect.iterateNext() as Element;
+ expect(xslIf!.nodeName).toEqual('xsl:if');
+ expect(xslIf!.getAttribute('test')).toEqual("/ns0:ShipOrder/ns0:OrderPerson != ''");
+ const shipTo = shipOrderSelect.iterateNext() as Element;
+ expect(shipTo!.nodeName).toEqual('ShipTo');
+ const xslForEach = shipOrderSelect.iterateNext() as Element;
+ expect(xslForEach!.nodeName).toEqual('xsl:for-each');
+ expect(xslForEach.getAttribute('select')).toEqual('/ns0:ShipOrder/Item');
+ });
+ });
+});
diff --git a/packages/ui/src/services/mapping-serializer.service.ts b/packages/ui/src/services/mapping-serializer.service.ts
new file mode 100644
index 000000000..1e538c980
--- /dev/null
+++ b/packages/ui/src/services/mapping-serializer.service.ts
@@ -0,0 +1,359 @@
+import { BaseField, IDocument, IField, IParentType, PrimitiveDocument } from '../models/datamapper/document';
+import {
+ ChooseItem,
+ ConditionItem,
+ FieldItem,
+ ForEachItem,
+ IfItem,
+ MappingItem,
+ MappingParentType,
+ MappingTree,
+ OtherwiseItem,
+ ValueSelector,
+ ValueType,
+ WhenItem,
+} from '../models/datamapper/mapping';
+import xmlFormat from 'xml-formatter';
+import { DocumentType } from '../models/datamapper/path';
+import { MappingService } from './mapping.service';
+
+export const DO_NOT_EDIT_COMMENT = '';
+export const NS_XSL = 'http://www.w3.org/1999/XSL/Transform';
+export const EMPTY_XSL = `
+${DO_NOT_EDIT_COMMENT}
+
+
+
+
+
+`;
+
+export class MappingSerializerService {
+ static createNew() {
+ return new DOMParser().parseFromString(EMPTY_XSL, 'application/xml');
+ }
+
+ private static sortFields(left: IField, right: IField) {
+ return left.parent.fields.indexOf(left) - right.parent.fields.indexOf(right);
+ }
+
+ private static sortMappingItem(left: MappingItem, right: MappingItem) {
+ const leftFields =
+ left instanceof FieldItem ? [left.field] : MappingService.getConditionalFields(left as ConditionItem);
+ if (leftFields.length === 0) return 1;
+ if (leftFields.find((f) => f.isAttribute)) return -1;
+ const rightFields =
+ right instanceof FieldItem ? [right.field] : MappingService.getConditionalFields(right as ConditionItem);
+ if (rightFields.length === 0) return -1;
+ if (rightFields.find((f) => f.isAttribute)) return 1;
+ const leftFirst = leftFields.sort(MappingSerializerService.sortFields)[0];
+ const rightFirst = rightFields.sort(MappingSerializerService.sortFields)[0];
+ return leftFirst.parent.fields.indexOf(leftFirst) - rightFirst.parent.fields.indexOf(rightFirst);
+ }
+
+ /**
+ * Serialize the {@link MappingTree} model object into an XSLT mappings document string.
+ * @param mappings {@link MappingTree} object to write
+ * @param sourceParameterMap source paramter map
+ */
+ static serialize(mappings: MappingTree, sourceParameterMap: Map): string {
+ const xslt = MappingSerializerService.createNew();
+ MappingSerializerService.populateNamespaces(xslt, mappings.namespaceMap);
+ MappingSerializerService.populateParam(xslt, sourceParameterMap);
+ const template = MappingSerializerService.getRootTemplate(xslt);
+ mappings.children.sort(MappingSerializerService.sortMappingItem).forEach((mapping) => {
+ MappingSerializerService.populateMapping(template, mapping);
+ });
+ return xmlFormat(new XMLSerializer().serializeToString(xslt));
+ }
+
+ private static populateNamespaces(xslt: Document, namespaceMap: { [prefix: string]: string }) {
+ const rootElement = xslt.documentElement;
+ Object.entries(namespaceMap).forEach(
+ ([prefix, uri]) => prefix && uri && rootElement.setAttribute(`xmlns:${prefix}`, uri),
+ );
+ }
+
+ private static getRootTemplate(xsltDocument: Document) {
+ const prefix = xsltDocument.lookupPrefix(NS_XSL);
+ const nsResolver = xsltDocument.createNSResolver(xsltDocument);
+ return xsltDocument
+ .evaluate(`/${prefix}:stylesheet/${prefix}:template[@match='/']`, xsltDocument, nsResolver, XPathResult.ANY_TYPE)
+ .iterateNext()! as Element;
+ }
+
+ private static populateParam(xsltDocument: Document, sourceParameterMap: Map) {
+ const template = MappingSerializerService.getRootTemplate(xsltDocument);
+ sourceParameterMap.forEach((_doc, paramName) => {
+ const prefix = xsltDocument.lookupPrefix(NS_XSL);
+ const nsResolver = xsltDocument.createNSResolver(xsltDocument);
+ const existing = xsltDocument
+ .evaluate(
+ `/${prefix}:stylesheet/${prefix}:param[@name='${paramName}']`,
+ xsltDocument,
+ nsResolver,
+ XPathResult.ANY_TYPE,
+ )
+ .iterateNext();
+ if (!existing) {
+ const xsltParam = xsltDocument.createElementNS(NS_XSL, 'param');
+ xsltParam.setAttribute('name', paramName);
+ (template.parentNode as Element).insertBefore(xsltParam, template);
+ }
+ });
+ }
+
+ private static populateMapping(parent: Element, mapping: MappingItem) {
+ let child: Element | null = null;
+ if (mapping instanceof ValueSelector) {
+ child = MappingSerializerService.populateValueSelector(parent, mapping);
+ } else if (mapping instanceof FieldItem) {
+ child = MappingSerializerService.populateFieldItem(parent, mapping);
+ } else if (mapping instanceof IfItem) {
+ child = MappingSerializerService.populateIfItem(parent, mapping);
+ } else if (mapping instanceof ChooseItem) {
+ child = MappingSerializerService.populateChooseItem(parent, mapping);
+ } else if (mapping instanceof ForEachItem) {
+ child = MappingSerializerService.populateForEachItem(parent, mapping);
+ } else if (mapping instanceof WhenItem) {
+ child = MappingSerializerService.populateWhenItem(parent, mapping);
+ } else if (mapping instanceof OtherwiseItem) {
+ child = MappingSerializerService.populateOtherwiseItem(parent, mapping);
+ }
+ if (child)
+ mapping.children
+ .sort(MappingSerializerService.sortMappingItem)
+ .forEach((childItem) => MappingSerializerService.populateMapping(child!, childItem));
+ }
+
+ private static populateValueSelector(parent: Element, selector: ValueSelector) {
+ const xsltDocument = parent.ownerDocument;
+ switch (selector.valueType) {
+ case ValueType.CONTAINER: {
+ const copyOf = xsltDocument.createElementNS(NS_XSL, 'copy-of');
+ copyOf.setAttribute('select', selector.expression);
+ parent.appendChild(copyOf);
+ return copyOf;
+ }
+ default: {
+ const valueOf = xsltDocument.createElementNS(NS_XSL, 'value-of');
+ valueOf.setAttribute('select', selector.expression);
+ parent.appendChild(valueOf);
+ return valueOf;
+ }
+ }
+ }
+
+ private static populateFieldItem(parent: Element, mapping: FieldItem) {
+ const xsltDocument = parent.ownerDocument;
+ if (mapping.field.isAttribute) {
+ const xslAttribute = xsltDocument.createElementNS(NS_XSL, 'attribute');
+ xslAttribute.setAttribute('name', mapping.field.name);
+ mapping.field.namespaceURI && xslAttribute.setAttribute('namespace', mapping.field.namespaceURI);
+ parent.appendChild(xslAttribute);
+ return xslAttribute;
+ } else {
+ const element = mapping.field.namespaceURI
+ ? xsltDocument.createElementNS(mapping.field.namespaceURI, mapping.field.name)
+ : xsltDocument.createElement(mapping.field.name);
+ parent.appendChild(element);
+ return element;
+ }
+ }
+
+ private static populateIfItem(parent: Element, mapping: IfItem) {
+ const xsltDocument = parent.ownerDocument;
+ const xslIf = xsltDocument.createElementNS(NS_XSL, 'if');
+ xslIf.setAttribute('test', mapping.expression);
+ parent.appendChild(xslIf);
+ return xslIf;
+ }
+
+ private static populateChooseItem(parent: Element, _mapping: ChooseItem) {
+ const xsltDocument = parent.ownerDocument;
+ const xslChoose = xsltDocument.createElementNS(NS_XSL, 'choose');
+ parent.appendChild(xslChoose);
+ return xslChoose;
+ }
+
+ private static populateForEachItem(parent: Element, mapping: ForEachItem) {
+ const xsltDocument = parent.ownerDocument;
+ const xslForEach = xsltDocument.createElementNS(NS_XSL, 'for-each');
+ xslForEach.setAttribute('select', mapping.expression);
+ parent.appendChild(xslForEach);
+ return xslForEach;
+ }
+
+ private static populateWhenItem(parent: Element, mapping: WhenItem) {
+ const xsltDocument = parent.ownerDocument;
+ const xslWhen = xsltDocument.createElementNS(NS_XSL, 'when');
+ xslWhen.setAttribute('test', mapping.expression);
+ parent.appendChild(xslWhen);
+ return xslWhen;
+ }
+
+ private static populateOtherwiseItem(parent: Element, _mapping: OtherwiseItem) {
+ const xsltDocument = parent.ownerDocument;
+ const xslOtherwise = xsltDocument.createElementNS(NS_XSL, 'otherwise');
+ parent.appendChild(xslOtherwise);
+ return xslOtherwise;
+ }
+
+ /**
+ * Deserialize the XSLT mappings document into a {@link MappingTree} model object.
+ * @param xslt XSLT mappings document in string format
+ * @param targetDocument Target Document
+ * @param mappingTree {@link MappingTree} object to write
+ * @param sourceParameterMap source parameter map
+ */
+ static deserialize(
+ xslt: string,
+ targetDocument: IDocument,
+ mappingTree: MappingTree,
+ sourceParameterMap: Map,
+ ): MappingTree {
+ mappingTree.children = [];
+ const xsltDoc = new DOMParser().parseFromString(xslt, 'application/xml');
+ const template = xsltDoc.getElementsByTagNameNS(NS_XSL, 'template')[0];
+ if (!template?.children) return mappingTree;
+ MappingSerializerService.restoreNamespaces(xsltDoc, mappingTree);
+ MappingSerializerService.restoreParam(xsltDoc, sourceParameterMap);
+ Array.from(template.children).forEach((item) =>
+ MappingSerializerService.restoreMapping(item, targetDocument, mappingTree),
+ );
+ return mappingTree;
+ }
+
+ private static restoreNamespaces(xsltDocument: Document, mappingTree: MappingTree) {
+ mappingTree.namespaceMap = {};
+ const rootElement = xsltDocument.documentElement;
+ Array.from(rootElement.attributes).forEach((attr) => {
+ if (!attr.nodeName.includes(':') || !attr.nodeValue || attr.nodeValue === NS_XSL) return;
+ const splitted = attr.nodeName.split(':');
+ if (splitted[0] === 'xmlns') mappingTree.namespaceMap[splitted[1]] = attr.nodeValue;
+ });
+ }
+
+ private static restoreParam(xsltDocument: Document, sourceParameterMap: Map) {
+ const prefix = xsltDocument.lookupPrefix(NS_XSL);
+ const nsResolver = xsltDocument.createNSResolver(xsltDocument);
+ const params = xsltDocument.evaluate(
+ `/${prefix}:stylesheet/${prefix}:param`,
+ xsltDocument,
+ nsResolver,
+ XPathResult.ANY_TYPE,
+ );
+ let param: Node | null;
+ while ((param = params.iterateNext())) {
+ const paramEl = param as Element;
+ const name = paramEl.getAttribute('name');
+ if (!name || sourceParameterMap.has(name)) continue;
+ sourceParameterMap.set(name, new PrimitiveDocument(DocumentType.PARAM, name));
+ }
+ }
+
+ private static restoreMapping(item: Element, parentField: IParentType, parentMapping: MappingParentType) {
+ let mappingItem: MappingItem | null = null;
+ let fieldItem: IParentType | null = null;
+ if (item.namespaceURI === NS_XSL) {
+ switch (item.localName) {
+ case 'copy-of': {
+ const selector = new ValueSelector(parentMapping, ValueType.CONTAINER);
+ selector.expression = item.getAttribute('select') || '';
+ mappingItem = selector;
+ break;
+ }
+ case 'value-of': {
+ const valueType =
+ 'isAttribute' in parentField && parentField.isAttribute ? ValueType.ATTRIBUTE : ValueType.VALUE;
+ const selector = new ValueSelector(parentMapping, valueType);
+ selector.expression = item.getAttribute('select') || '';
+ mappingItem = selector;
+ break;
+ }
+ case 'if': {
+ const ifItem = new IfItem(parentMapping);
+ ifItem.expression = item.getAttribute('test') || '';
+ mappingItem = ifItem;
+ break;
+ }
+ case 'choose': {
+ mappingItem = new ChooseItem(parentMapping);
+ break;
+ }
+ case 'when': {
+ const whenItem = new WhenItem(parentMapping);
+ whenItem.expression = item.getAttribute('test') || '';
+ mappingItem = whenItem;
+ break;
+ }
+ case 'otherwise': {
+ mappingItem = new OtherwiseItem(parentMapping);
+ break;
+ }
+ case 'for-each': {
+ const forEachItem = new ForEachItem(parentMapping);
+ forEachItem.expression = item.getAttribute('select') || '';
+ mappingItem = forEachItem;
+ break;
+ }
+ case 'attribute': {
+ if (parentField instanceof PrimitiveDocument) return;
+ const field = MappingSerializerService.getOrCreateAttributeField(item, parentField);
+ if (!field) return;
+ fieldItem = field;
+ mappingItem = new FieldItem(parentMapping, field);
+ break;
+ }
+ }
+ } else {
+ if (parentField instanceof PrimitiveDocument) return;
+ const field = MappingSerializerService.getOrCreateElementField(item, parentField);
+ if (!field) return;
+ fieldItem = field;
+ mappingItem = new FieldItem(parentMapping, field);
+ }
+ if (mappingItem) {
+ parentMapping.children.push(mappingItem);
+ Array.from(item.children).forEach((childItem) =>
+ MappingSerializerService.restoreMapping(childItem, fieldItem ? fieldItem : parentField, mappingItem!),
+ );
+ }
+ }
+
+ private static getOrCreateAttributeField(item: Element, parentField: IParentType): IField | null {
+ const namespace = item.getAttribute('namespace');
+ const name = item.getAttribute('name');
+ if (!name) return null;
+ const existing = parentField.fields.find(
+ (child) => child.name === name && ((!namespace && !child.namespaceURI) || child.namespaceURI === namespace),
+ );
+ if (existing) return existing;
+ const field = new BaseField(
+ parentField,
+ 'ownerDocument' in parentField ? parentField.ownerDocument : parentField,
+ name,
+ );
+ field.isAttribute = true;
+ field.namespaceURI = namespace;
+ parentField.fields.push(field);
+ return field;
+ }
+
+ private static getOrCreateElementField(item: Element, parentField: IParentType): IField {
+ const namespace = item.namespaceURI;
+ const name = item.localName;
+ const existing = parentField.fields.find(
+ (child) => child.name === name && ((!namespace && !child.namespaceURI) || child.namespaceURI === namespace),
+ );
+ if (existing) return existing;
+ const field = new BaseField(
+ parentField,
+ 'ownerDocument' in parentField ? parentField.ownerDocument : parentField,
+ name,
+ );
+ field.namespaceURI = namespace;
+ parentField.fields.push(field);
+ return field;
+ }
+}
diff --git a/packages/ui/src/services/mapping.service.test.ts b/packages/ui/src/services/mapping.service.test.ts
new file mode 100644
index 000000000..2d8d157f3
--- /dev/null
+++ b/packages/ui/src/services/mapping.service.test.ts
@@ -0,0 +1,318 @@
+import { MappingService } from './mapping.service';
+import {
+ ChooseItem,
+ FieldItem,
+ IfItem,
+ MappingTree,
+ OtherwiseItem,
+ ValueSelector,
+ ValueType,
+ WhenItem,
+} from '../models/datamapper/mapping';
+import { MappingSerializerService } from './mapping-serializer.service';
+import { DocumentType } from '../models/datamapper/path';
+import { XmlSchemaDocument } from './xml-schema-document.service';
+import { IDocument } from '../models/datamapper/document';
+import { shipOrderToShipOrderXslt, TestUtil } from '../stubs/data-mapper';
+import { XPathService } from './xpath/xpath.service';
+
+describe('MappingService', () => {
+ let sourceDoc: XmlSchemaDocument;
+ let targetDoc: XmlSchemaDocument;
+ let paramsMap: Map;
+ let tree: MappingTree;
+
+ beforeEach(() => {
+ sourceDoc = TestUtil.createSourceOrderDoc();
+ targetDoc = TestUtil.createTargetOrderDoc();
+ paramsMap = TestUtil.createParameterMap();
+ tree = new MappingTree(targetDoc.documentType, targetDoc.documentId);
+ MappingSerializerService.deserialize(shipOrderToShipOrderXslt, targetDoc, tree, paramsMap);
+ });
+
+ describe('filterMappingsForField()', () => {
+ it('should filter mappings', () => {
+ let filtered = MappingService.filterMappingsForField(tree.children, targetDoc.fields[0]);
+ expect(filtered.length).toEqual(1);
+ expect((filtered[0] as FieldItem).field).toEqual(targetDoc.fields[0]);
+ filtered = MappingService.filterMappingsForField(tree.children, targetDoc.fields[0].fields[0]);
+ expect(filtered.length).toEqual(0);
+ });
+ });
+
+ describe('removeAllMappingsForDocument()', () => {
+ it('should remove mappings for target document', () => {
+ expect(tree.children.length).toEqual(1);
+ MappingService.removeAllMappingsForDocument(tree, DocumentType.TARGET_BODY, targetDoc.documentId);
+ expect(tree.children.length).toEqual(0);
+ });
+
+ it('should remove mappings for source document', () => {
+ expect(tree.children.length).toEqual(1);
+ MappingService.removeAllMappingsForDocument(tree, DocumentType.SOURCE_BODY, sourceDoc.documentId);
+ expect(tree.children.length).toEqual(0);
+ });
+
+ it('should not remove mappings unrelated to the removed param', () => {
+ expect(tree.children.length).toEqual(1);
+ MappingService.removeAllMappingsForDocument(tree, DocumentType.PARAM, 'sourceParam1');
+ expect(tree.children.length).toEqual(1);
+ });
+ });
+
+ describe('removeStaleMappingsForDocument()', () => {
+ it('should remove mappings for removed source field', () => {
+ expect(tree.children[0].children.length).toEqual(4);
+ const orderPersonField = sourceDoc.fields[0].fields[1];
+ expect(orderPersonField.name).toEqual('OrderPerson');
+ sourceDoc.fields[0].fields.splice(1, 1);
+ MappingService.removeStaleMappingsForDocument(tree, sourceDoc);
+ expect(tree.children[0].children.length).toEqual(3);
+ });
+
+ it('should remove mappings for removed target field', () => {
+ expect(tree.children[0].children.length).toEqual(4);
+ const orderIdField = targetDoc.fields[0].fields[0];
+ expect(orderIdField.name).toEqual('OrderId');
+ targetDoc.fields[0].fields.splice(0, 1);
+ MappingService.removeStaleMappingsForDocument(tree, targetDoc);
+ expect(tree.children[0].children.length).toEqual(3);
+ });
+
+ it('should not remove mappings when unrelated field is removed', () => {
+ expect(tree.children[0].children.length).toEqual(4);
+ const shipToCountryField = targetDoc.fields[0].fields[2].fields[3];
+ expect(shipToCountryField.name).toEqual('Country');
+ targetDoc.fields[0].fields[2].fields.splice(3, 1);
+ MappingService.removeStaleMappingsForDocument(tree, targetDoc);
+ expect(tree.children[0].children.length).toEqual(4);
+ });
+
+ it('should not remove for-each mapping contents (source)', () => {
+ sourceDoc = TestUtil.createSourceOrderDoc();
+ MappingService.removeStaleMappingsForDocument(tree, sourceDoc);
+ const shipOrderItem = tree.children[0];
+ const forEachItem = shipOrderItem.children[3];
+ expect(forEachItem.parent).toEqual(shipOrderItem);
+ expect(forEachItem.children.length).toEqual(1);
+
+ const itemItem = forEachItem.children[0];
+ expect(itemItem.parent).toEqual(forEachItem);
+ expect(itemItem.children.length).toEqual(4);
+ const titleItem = itemItem.children[0];
+ expect(titleItem.parent).toEqual(itemItem);
+ expect(titleItem.children.length).toEqual(1);
+ expect((titleItem.children[0] as ValueSelector).expression).toEqual('Title');
+
+ const chooseItem = itemItem.children[1];
+ expect(chooseItem.parent).toEqual(itemItem);
+ expect(chooseItem.children.length).toEqual(2);
+ const whenItem = chooseItem.children[0] as WhenItem;
+ expect(whenItem.parent).toEqual(chooseItem);
+ expect(whenItem.expression).toEqual("Note != ''");
+ expect((whenItem.children[0].children[0] as ValueSelector).expression).toEqual('Note');
+ const otherwiseItem = chooseItem.children[1] as OtherwiseItem;
+ expect(otherwiseItem.parent).toEqual(chooseItem);
+ expect((otherwiseItem.children[0].children[0] as ValueSelector).expression).toEqual('Title');
+
+ const quantityItem = itemItem.children[2];
+ expect(quantityItem.parent).toEqual(itemItem);
+ expect(quantityItem.children.length).toEqual(1);
+ expect((quantityItem.children[0] as ValueSelector).expression).toEqual('Quantity');
+
+ const priceItem = itemItem.children[3];
+ expect(priceItem.parent).toEqual(itemItem);
+ expect(priceItem.children.length).toEqual(1);
+ expect((priceItem.children[0] as ValueSelector).expression).toEqual('Price');
+
+ const links = MappingService.extractMappingLinks(tree, paramsMap, sourceDoc);
+ expect(links.length).toEqual(11);
+ links.forEach((link) => expect(link.sourceNodePath.includes(sourceDoc.fields[0].id)).toBeTruthy());
+ });
+
+ it('should not remove for-each mapping contents (target)', () => {
+ targetDoc = TestUtil.createTargetOrderDoc();
+ MappingService.removeStaleMappingsForDocument(tree, targetDoc);
+ const shipOrderItem = tree.children[0];
+ const forEachItem = shipOrderItem.children[3];
+ expect(forEachItem.parent).toEqual(shipOrderItem);
+ expect(forEachItem.children.length).toEqual(1);
+
+ const itemItem = forEachItem.children[0];
+ expect(itemItem.parent).toEqual(forEachItem);
+ expect(itemItem.children.length).toEqual(4);
+ const titleItem = itemItem.children[0];
+ expect(titleItem.parent).toEqual(itemItem);
+ expect(titleItem.children.length).toEqual(1);
+ expect((titleItem.children[0] as ValueSelector).expression).toEqual('Title');
+
+ const chooseItem = itemItem.children[1];
+ expect(chooseItem.parent).toEqual(itemItem);
+ expect(chooseItem.children.length).toEqual(2);
+ const whenItem = chooseItem.children[0] as WhenItem;
+ expect(whenItem.parent).toEqual(chooseItem);
+ expect(whenItem.expression).toEqual("Note != ''");
+ expect((whenItem.children[0].children[0] as ValueSelector).expression).toEqual('Note');
+ const otherwiseItem = chooseItem.children[1] as OtherwiseItem;
+ expect(otherwiseItem.parent).toEqual(chooseItem);
+ expect((otherwiseItem.children[0].children[0] as ValueSelector).expression).toEqual('Title');
+
+ const quantityItem = itemItem.children[2];
+ expect(quantityItem.parent).toEqual(itemItem);
+ expect(quantityItem.children.length).toEqual(1);
+ expect((quantityItem.children[0] as ValueSelector).expression).toEqual('Quantity');
+
+ const priceItem = itemItem.children[3];
+ expect(priceItem.parent).toEqual(itemItem);
+ expect(priceItem.children.length).toEqual(1);
+ expect((priceItem.children[0] as ValueSelector).expression).toEqual('Price');
+
+ const links = MappingService.extractMappingLinks(tree, paramsMap, sourceDoc);
+ expect(links.length).toEqual(11);
+ links.forEach((link) => expect(link.targetNodePath.includes(targetDoc.fields[0].id)).toBeTruthy());
+ });
+
+ it("should not remove for-each targeted field when it doesn't have children (source)", () => {
+ const shipOrderItem = tree.children[0];
+ const forEachItem = shipOrderItem.children[3];
+ shipOrderItem.children = [forEachItem];
+ const itemItem = forEachItem.children[0];
+ itemItem.children = [];
+ MappingService.removeStaleMappingsForDocument(tree, sourceDoc);
+ expect(forEachItem.parent).toEqual(shipOrderItem);
+ expect(forEachItem.children.length).toEqual(1);
+
+ const links = MappingService.extractMappingLinks(tree, paramsMap, sourceDoc);
+ expect(links.length).toEqual(1);
+ expect(links[0].sourceNodePath.includes(sourceDoc.fields[0].id)).toBeTruthy();
+ });
+
+ it("should not remove for-each targeted field when it doesn't have children (target)", () => {
+ const shipOrderItem = tree.children[0];
+ const forEachItem = shipOrderItem.children[3];
+ shipOrderItem.children = [forEachItem];
+ const itemItem = forEachItem.children[0];
+ itemItem.children = [];
+ MappingService.removeStaleMappingsForDocument(tree, targetDoc);
+ expect(forEachItem.parent).toEqual(shipOrderItem);
+ expect(forEachItem.children.length).toEqual(1);
+
+ const links = MappingService.extractMappingLinks(tree, paramsMap, sourceDoc);
+ expect(links.length).toEqual(1);
+ expect(links[0].targetNodePath.includes(targetDoc.fields[0].id)).toBeTruthy();
+ });
+ });
+
+ describe('addChooseWhenOtherwise()', () => {
+ it('should add conditions', () => {
+ const orderIdFieldItem = tree.children[0].children[0];
+ expect(orderIdFieldItem.children.length).toEqual(1);
+ MappingService.addChooseWhenOtherwise(orderIdFieldItem, orderIdFieldItem.children[0]);
+ expect(orderIdFieldItem.children.length).toEqual(1);
+ const chooseItem = orderIdFieldItem.children[0];
+ expect(chooseItem instanceof ChooseItem).toBeTruthy();
+ expect(chooseItem.children[0] instanceof WhenItem).toBeTruthy();
+ expect(chooseItem.children[1] instanceof OtherwiseItem).toBeTruthy();
+ });
+ });
+
+ describe('wrapWithFunction()', () => {
+ it('should wrap with xpath function', () => {
+ const concatFx = XPathService.functions.String.find((f) => f.name === 'concat');
+ const valueSelector = new ValueSelector(tree);
+ valueSelector.expression = '/path/to/field';
+ MappingService.wrapWithFunction(valueSelector, concatFx!);
+ expect(valueSelector.expression).toEqual('concat(/path/to/field)');
+ });
+ });
+
+ describe('mapToCondition()', () => {
+ it('should add to xpath', () => {
+ expect(tree.children[0].children[1] instanceof IfItem).toBeTruthy();
+ const ifItem = tree.children[0].children[1] as IfItem;
+ expect(ifItem.expression).toEqual("/ns0:ShipOrder/ns0:OrderPerson != ''");
+ MappingService.mapToCondition(ifItem, sourceDoc.fields[0].fields[1]);
+ expect(ifItem.expression).toEqual("/ns0:ShipOrder/ns0:OrderPerson != '', /ns0:ShipOrder/ns0:OrderPerson");
+ });
+ });
+
+ describe('mapToDocument()', () => {
+ it('should add ValueSelector', () => {
+ expect(tree.children.length).toEqual(1);
+ MappingService.mapToDocument(tree, sourceDoc.fields[0]);
+ expect(tree.children.length).toEqual(2);
+ expect(tree.children[1] instanceof ValueSelector).toBeTruthy();
+ const selector = tree.children[1] as ValueSelector;
+ expect(selector.expression).toEqual('/ns0:ShipOrder');
+ });
+ });
+
+ describe('mapToField()', () => {
+ it('should add to xpath', () => {
+ const orderIdFieldItem = tree.children[0].children[0];
+ orderIdFieldItem.children = [];
+ MappingService.mapToField(sourceDoc.fields[0].fields[0], orderIdFieldItem);
+ expect(orderIdFieldItem.children[0] instanceof ValueSelector);
+ const orderIdValueSelector = orderIdFieldItem.children[0] as ValueSelector;
+ expect(orderIdValueSelector.expression).toEqual('/ns0:ShipOrder/@OrderId');
+ });
+
+ it('should populate namespace if not exists', () => {
+ tree.namespaceMap = {};
+ const orderIdFieldItem = tree.children[0].children[0];
+ orderIdFieldItem.children = [];
+ MappingService.mapToField(sourceDoc.fields[0].fields[0], orderIdFieldItem);
+ expect(orderIdFieldItem.children[0] instanceof ValueSelector);
+ const orderIdValueSelector = orderIdFieldItem.children[0] as ValueSelector;
+ expect(orderIdValueSelector.expression).toEqual('/ns0:ShipOrder/@OrderId');
+ });
+ });
+
+ describe('createValueSelector()', () => {
+ it('should create ValueSelector', () => {
+ const orderIdFieldItem = tree.children[0].children[0] as FieldItem;
+ expect(orderIdFieldItem.children[0] instanceof ValueSelector).toBeTruthy();
+ orderIdFieldItem.children = [];
+ const valueSelector = MappingService.createValueSelector(orderIdFieldItem);
+ expect(valueSelector.valueType).toEqual(ValueType.ATTRIBUTE);
+ });
+ });
+
+ describe('deleteMappingItem()', () => {
+ it('should delete', () => {
+ expect(tree.children[0].children.length).toEqual(4);
+ const orderIdValueSelector = tree.children[0].children[0].children[0] as ValueSelector;
+ MappingService.deleteMappingItem(orderIdValueSelector);
+ expect(tree.children[0].children.length).toEqual(3);
+ });
+ });
+
+ describe('extractMappingLinks()', () => {
+ it('should return IMappingLink[]', () => {
+ const links = MappingService.extractMappingLinks(tree, paramsMap, sourceDoc);
+ expect(links.length).toEqual(11);
+ expect(links[0].sourceNodePath).toMatch('OrderId');
+ expect(links[0].targetNodePath).toMatch('OrderId');
+ expect(links[1].sourceNodePath).toMatch('OrderPerson');
+ expect(links[1].targetNodePath).toMatch('/if-');
+ expect(links[2].sourceNodePath).toMatch('OrderPerson');
+ expect(links[2].targetNodePath).toMatch(/if-.*field-OrderPerson/);
+ expect(links[3].targetNodePath).toMatch('ShipTo');
+ expect(links[3].targetNodePath).toMatch('ShipTo');
+ expect(links[4].sourceNodePath).toMatch('Item');
+ expect(links[4].targetNodePath).toMatch('/for-each');
+ expect(links[5].sourceNodePath).toMatch('Title');
+ expect(links[5].targetNodePath).toMatch(/for-each-.*field-Item-.*field-Title-.*/);
+ expect(links[6].sourceNodePath).toMatch('Note');
+ expect(links[6].targetNodePath).toMatch(/for-each-.*field-Item-.*choose-.*when-.*/);
+ expect(links[7].sourceNodePath).toMatch('Note');
+ expect(links[7].targetNodePath).toMatch(/for-each-.*field-Item-.*field-Note-.*/);
+ expect(links[8].sourceNodePath).toMatch('Title');
+ expect(links[8].targetNodePath).toMatch(/for-each-.*field-Item-.*choose-.*otherwise-.*field-Note-.*/);
+ expect(links[9].sourceNodePath).toMatch('Quantity');
+ expect(links[9].targetNodePath).toMatch(/for-each-.*field-Item-.*field-Quantity-.*/);
+ expect(links[10].sourceNodePath).toMatch('Price');
+ expect(links[10].targetNodePath).toMatch(/for-each-.*field-Item-.*field-Price-.*/);
+ });
+ });
+});
diff --git a/packages/ui/src/services/mapping.service.ts b/packages/ui/src/services/mapping.service.ts
new file mode 100644
index 000000000..205f1794b
--- /dev/null
+++ b/packages/ui/src/services/mapping.service.ts
@@ -0,0 +1,428 @@
+import {
+ FieldItem,
+ MappingTree,
+ MappingItem,
+ ChooseItem,
+ WhenItem,
+ OtherwiseItem,
+ ConditionItem,
+ IfItem,
+ ValueSelector,
+ MappingParentType,
+ ForEachItem,
+ ExpressionItem,
+ ValueType,
+ IFunctionDefinition,
+} from '../models/datamapper/mapping';
+import { IDocument, IField, PrimitiveDocument } from '../models/datamapper/document';
+import { DocumentService } from './document.service';
+import { XPathService } from './xpath/xpath.service';
+import { IMappingLink } from '../models/datamapper/visualization';
+import { DocumentType, Path } from '../models/datamapper/path';
+
+export class MappingService {
+ static filterMappingsForField(mappings: MappingItem[], field: IField): MappingItem[] {
+ if (!mappings) return [];
+ return mappings.filter((mapping) => {
+ if (mapping instanceof FieldItem) {
+ return mapping.field === field;
+ } else if (mapping instanceof ValueSelector) {
+ return false;
+ } else {
+ return MappingService.getConditionalFields(mapping as ConditionItem).includes(field);
+ }
+ });
+ }
+
+ private static getConditionalFieldItems(mapping: ConditionItem): FieldItem[] {
+ if (mapping instanceof ChooseItem) {
+ return [...mapping.when, mapping.otherwise].reduce((acc, branch) => {
+ branch && acc.push(...MappingService.getConditionalFieldItems(branch));
+ return acc;
+ }, [] as FieldItem[]);
+ } else if (
+ mapping instanceof IfItem ||
+ mapping instanceof WhenItem ||
+ mapping instanceof OtherwiseItem ||
+ mapping instanceof ForEachItem
+ ) {
+ return mapping.children.reduce((acc, child) => {
+ child instanceof FieldItem && acc.push(child);
+ return acc;
+ }, [] as FieldItem[]);
+ }
+ return [];
+ }
+
+ static getConditionalFields(mapping: ConditionItem): IField[] {
+ return MappingService.getConditionalFieldItems(mapping).map((item) => item.field);
+ }
+
+ static removeAllMappingsForDocument(mappingTree: MappingTree, documentType: DocumentType, documentId: string) {
+ if (documentType === DocumentType.TARGET_BODY) {
+ MappingService.doRemoveAllMappingsForTargetDocument(mappingTree);
+ } else {
+ MappingService.doRemoveAllMappingsForSourceDocument(mappingTree, documentType, documentId);
+ }
+ return mappingTree;
+ }
+
+ private static doRemoveAllMappingsForTargetDocument(mappingTree: MappingTree) {
+ mappingTree.children = [];
+ }
+
+ private static doRemoveAllMappingsForSourceDocument(
+ item: MappingTree | MappingItem,
+ documentType: DocumentType,
+ documentId: string,
+ ) {
+ item.children = item.children.reduce((acc, child) => {
+ MappingService.doRemoveAllMappingsForSourceDocument(child, documentType, documentId);
+ if (
+ child instanceof ExpressionItem &&
+ MappingService.hasStaleSourceDocument(child.expression as string, documentType, documentId)
+ ) {
+ return acc;
+ }
+ if (child instanceof FieldItem && child.children.length === 0) return acc;
+ acc.push(child);
+ return acc;
+ }, [] as MappingItem[]);
+ }
+
+ private static hasStaleSourceDocument(expression: string, documentType: DocumentType, documentId: string) {
+ const stalePath = XPathService.extractFieldPaths(expression).find((xpath) => {
+ const parsedPath = new Path(xpath);
+ return (
+ (documentType === DocumentType.SOURCE_BODY && !parsedPath.parameterName) ||
+ (documentType === DocumentType.PARAM && parsedPath.parameterName === documentId)
+ );
+ });
+ return !!stalePath;
+ }
+
+ static removeStaleMappingsForDocument(mappingTree: MappingTree, document: IDocument) {
+ if (document.documentType === DocumentType.TARGET_BODY) {
+ MappingService.doRemoveStaleMappingsForTargetDocument(mappingTree, document);
+ } else {
+ MappingService.doRemoveStaleMappingsForSourceDocument(mappingTree, document);
+ }
+ return mappingTree;
+ }
+
+ private static doRemoveStaleMappingsForTargetDocument(item: MappingTree | MappingItem, document: IDocument) {
+ item.children = item.children.reduce((acc, child) => {
+ MappingService.doRemoveStaleMappingsForTargetDocument(child, document);
+ let compatibleField: IField | undefined = undefined;
+ if (child instanceof FieldItem) {
+ compatibleField = DocumentService.getCompatibleField(document, child.field);
+ if (compatibleField) {
+ child = MappingService.updateFieldItemField(child, compatibleField);
+ }
+ }
+ if (compatibleField && child.children.length > 0) {
+ acc.push(child);
+ } else if (child.parent instanceof ConditionItem || child instanceof ConditionItem) {
+ acc.push(child);
+ }
+ return acc;
+ }, [] as MappingItem[]);
+ }
+
+ private static updateFieldItemField(item: FieldItem, newField: IField): FieldItem {
+ const updated = MappingService.createFieldItem(item.parent, newField);
+ MappingService.adaptChildren(item, updated);
+ item.parent.children = item.parent.children.map((child) => (child === item ? updated : child));
+ return updated;
+ }
+
+ private static adaptChildren(from: MappingItem, to: MappingItem) {
+ to.children = from.children.map((child) => {
+ child.parent = to;
+ return child;
+ });
+ }
+
+ private static doRemoveStaleMappingsForSourceDocument(item: MappingTree | MappingItem, document: IDocument) {
+ item.children = item.children.reduce((acc, child) => {
+ MappingService.doRemoveStaleMappingsForSourceDocument(child, document);
+ if (child instanceof ExpressionItem && MappingService.hasStaleSourceField(child, document)) {
+ return acc;
+ }
+ if (!(child.parent instanceof ConditionItem) && child instanceof FieldItem && child.children.length === 0) {
+ return acc;
+ }
+ acc.push(child);
+ return acc;
+ }, [] as MappingItem[]);
+ }
+
+ private static hasStaleSourceField(expressionItem: ExpressionItem, document: IDocument) {
+ const stalePath = XPathService.extractFieldPaths(expressionItem.expression).find((xpath) => {
+ const absPath = MappingService.getAbsolutePath(expressionItem, xpath);
+ const parsedPath = new Path(absPath);
+ if (
+ (document.documentType === DocumentType.SOURCE_BODY && !parsedPath.parameterName) ||
+ (document.documentType === DocumentType.PARAM && parsedPath.parameterName === document.documentId)
+ ) {
+ return !DocumentService.getFieldFromPathSegments(
+ document,
+ parsedPath.pathSegments.map((seg) => seg.name),
+ );
+ }
+ });
+ return !!stalePath;
+ }
+
+ static wrapWithItem(wrapped: MappingItem, wrapper: MappingItem) {
+ wrapper.children.push(wrapped);
+ wrapped.parent.children = wrapped.parent.children.map((m) => (m !== wrapped ? m : wrapper));
+ wrapped.parent = wrapper;
+ }
+
+ static wrapWithForEach(wrapped: MappingItem) {
+ MappingService.wrapWithItem(wrapped, new ForEachItem(wrapped.parent));
+ }
+
+ static wrapWithIf(wrapped: MappingItem) {
+ MappingService.wrapWithItem(wrapped, new IfItem(wrapped.parent));
+ }
+
+ static wrapWithChooseWhenOtherwise(wrapped: MappingItem) {
+ const parent = wrapped.parent;
+ const chooseItem = new ChooseItem(parent, wrapped && wrapped instanceof FieldItem ? wrapped.field : undefined);
+ const whenItem = MappingService.addWhen(chooseItem);
+ const otherwiseItem = MappingService.addOtherwise(chooseItem);
+ whenItem.children = [wrapped];
+ wrapped.parent = whenItem;
+ const otherwiseWrapped = wrapped.clone();
+ otherwiseWrapped.parent = otherwiseItem;
+ otherwiseItem.children = [otherwiseWrapped];
+ parent.children = parent.children.map((m) => (m !== wrapped ? m : chooseItem));
+ }
+
+ static addIf(parent: MappingParentType, mapping?: MappingItem) {
+ const ifItem = new IfItem(parent);
+ parent.children.push(ifItem);
+ ifItem.children.push(mapping ? mapping : MappingService.createValueSelector(ifItem));
+ }
+
+ static addChooseWhenOtherwise(parent: MappingParentType, mapping?: MappingItem) {
+ const chooseItem = new ChooseItem(parent, mapping && mapping instanceof FieldItem ? mapping.field : undefined);
+ MappingService.addWhen(chooseItem, mapping);
+ MappingService.addOtherwise(chooseItem, mapping?.clone());
+ if (mapping) {
+ parent.children = parent.children.map((m) => (m !== mapping ? m : chooseItem));
+ }
+ if (!parent.children.includes(chooseItem)) parent.children.push(chooseItem);
+ }
+
+ static addWhen(chooseItem: ChooseItem, mapping?: MappingItem, field?: IField) {
+ const whenItem = new WhenItem(chooseItem);
+
+ if (mapping) {
+ whenItem.children.push(mapping);
+ } else {
+ if (field) {
+ MappingService.createFieldItem(whenItem, field);
+ } else {
+ whenItem.children.push(MappingService.createValueSelector(whenItem));
+ }
+ }
+ chooseItem.children.push(whenItem);
+ return whenItem;
+ }
+
+ static addOtherwise(chooseItem: ChooseItem, mapping?: MappingItem, field?: IField) {
+ const newChildren = chooseItem.children.filter((c) => !(c instanceof OtherwiseItem));
+ const otherwiseItem = new OtherwiseItem(chooseItem);
+ if (mapping) {
+ otherwiseItem.children.push(mapping);
+ } else {
+ if (field) {
+ MappingService.createFieldItem(otherwiseItem, field);
+ } else {
+ otherwiseItem.children.push(MappingService.createValueSelector(otherwiseItem));
+ }
+ }
+ newChildren.push(otherwiseItem);
+ chooseItem.children = newChildren;
+ return otherwiseItem;
+ }
+
+ static wrapWithFunction(condition: ExpressionItem, func: IFunctionDefinition) {
+ condition.expression = `${func.name}(${condition.expression})`;
+ }
+
+ static mapToCondition(condition: MappingItem, source: PrimitiveDocument | IField) {
+ MappingService.registerNamespaceFromField(condition.mappingTree, source);
+ const absPath = XPathService.toXPath(source, condition.mappingTree.namespaceMap);
+ const relativePath = MappingService.getRelativePath(condition, absPath);
+ if (condition instanceof ForEachItem) {
+ condition.expression = relativePath;
+ } else if (condition instanceof ExpressionItem) {
+ condition.expression = XPathService.addSource(condition.expression as string, relativePath);
+ }
+ }
+
+ private static getRelativePath(condition: MappingItem, absPath: string): string {
+ const parentPath = condition.parent.contextPath?.toAbsolutePathString();
+ if (!parentPath) return absPath;
+ const index = absPath.indexOf(parentPath);
+ return index == -1 ? absPath : absPath.substring(index + parentPath.length + 1);
+ }
+
+ private static getAbsolutePath(condition: MappingItem, xpath: string): string {
+ return condition.contextPath && !xpath.startsWith('$') && !xpath.startsWith('/')
+ ? condition.contextPath + '/' + xpath
+ : xpath;
+ }
+
+ static mapToDocument(mappingTree: MappingTree, source: PrimitiveDocument | IField) {
+ let valueSelector = mappingTree.children.find((mapping) => mapping instanceof ValueSelector) as ValueSelector;
+ if (!valueSelector) {
+ valueSelector = MappingService.createValueSelector(mappingTree);
+ mappingTree.children.push(valueSelector);
+ }
+ MappingService.registerNamespaceFromField(mappingTree, source);
+ const path = XPathService.toXPath(source, mappingTree.namespaceMap);
+ valueSelector.expression = XPathService.addSource(valueSelector.expression, path);
+ }
+
+ static mapToField(source: PrimitiveDocument | IField, targetFieldItem: MappingItem) {
+ let valueSelector = targetFieldItem?.children.find((child) => child instanceof ValueSelector) as ValueSelector;
+ if (!valueSelector) {
+ valueSelector = MappingService.createValueSelector(targetFieldItem);
+ targetFieldItem.children.push(valueSelector);
+ }
+ MappingService.registerNamespaceFromField(targetFieldItem.mappingTree, source);
+ const absPath = XPathService.toXPath(source, targetFieldItem.mappingTree.namespaceMap);
+ const relativePath = MappingService.getRelativePath(valueSelector, absPath);
+ valueSelector.expression = XPathService.addSource(valueSelector.expression, relativePath);
+ }
+
+ static createFieldItem(parentItem: MappingParentType, field: IField) {
+ const fieldItem = new FieldItem(parentItem, field);
+ parentItem.children.push(fieldItem);
+ return fieldItem;
+ }
+
+ private static registerNamespaceFromField(mappingTree: MappingTree, field: IField) {
+ if (DocumentService.isNonPrimitiveField(field.parent)) {
+ MappingService.registerNamespaceFromField(mappingTree, field.parent as IField);
+ }
+ if (!field.namespaceURI) return;
+ const existingns = Object.entries(mappingTree.namespaceMap).find(
+ ([_prefix, uri]) => field.namespaceURI && uri === field.namespaceURI,
+ );
+ if (!existingns && field.namespaceURI) {
+ const prefix = field.namespacePrefix ?? MappingService.createNSPrefix(mappingTree);
+ mappingTree.namespaceMap[prefix] = field.namespaceURI;
+ }
+ }
+
+ private static createNSPrefix(mappingTree: MappingTree) {
+ for (let index = 0; ; index++) {
+ const prefix = `ns${index}`;
+ if (!mappingTree.namespaceMap[prefix]) return prefix;
+ }
+ }
+
+ static createValueSelector(parent: MappingParentType) {
+ const valueType = parent instanceof MappingTree ? ValueType.VALUE : MappingService.getValueTypeFor(parent);
+ return new ValueSelector(parent, valueType);
+ }
+
+ private static getValueTypeFor(mapping: MappingItem): ValueType {
+ const field = MappingService.getTargetField(mapping);
+ return field?.isAttribute
+ ? ValueType.ATTRIBUTE
+ : field?.fields?.length && field.fields.length > 0
+ ? ValueType.CONTAINER
+ : ValueType.VALUE;
+ }
+
+ private static getTargetField(mapping: MappingItem) {
+ let item = mapping;
+ while (!(item instanceof FieldItem) && !(item.parent instanceof MappingTree)) item = item.parent;
+ if (item instanceof FieldItem) return item.field;
+ }
+
+ static deleteMappingItem(item: MappingParentType) {
+ item.children = item.children.filter((child) => !(child instanceof ValueSelector));
+ const isConditionItem = item instanceof ConditionItem;
+ const isParentFieldItem = 'parent' in item && item.parent instanceof FieldItem;
+ if (isConditionItem || isParentFieldItem) {
+ MappingService.deleteFromParent(item);
+ }
+ }
+
+ private static deleteFromParent(item: MappingItem) {
+ item.parent.children = item.parent.children.filter((child) => child !== item);
+ const isParentFieldItem = item.parent instanceof FieldItem;
+ const isParentParentFieldItem = 'parent' in item.parent && item.parent.parent instanceof FieldItem;
+ const areNoChildren = item.parent.children.length === 0;
+ if (isParentFieldItem && isParentParentFieldItem && areNoChildren) {
+ MappingService.deleteFromParent(item.parent as FieldItem);
+ }
+ }
+
+ static sortMappingItem(left: MappingItem, right: MappingItem) {
+ if (left instanceof ValueSelector) return -1;
+ if (right instanceof ValueSelector) return 1;
+ if (left instanceof WhenItem) return right instanceof OtherwiseItem ? -1 : 0;
+ if (right instanceof WhenItem) return left instanceof OtherwiseItem ? 1 : 0;
+ return 0;
+ }
+
+ static extractMappingLinks(
+ item: MappingTree | MappingItem,
+ sourceParameterMap: Map,
+ sourceBody: IDocument,
+ ): IMappingLink[] {
+ const answer = [] as IMappingLink[];
+ const targetNodePath = item.nodePath.toString();
+ if (item instanceof ExpressionItem) {
+ answer.push(...MappingService.doExtractMappingLinks(item, targetNodePath, sourceParameterMap, sourceBody));
+ }
+ if ('children' in item) {
+ item.children.forEach((child) => {
+ if (
+ item instanceof FieldItem &&
+ !(item.field.ownerDocument instanceof PrimitiveDocument) &&
+ child instanceof ValueSelector
+ ) {
+ answer.push(...MappingService.doExtractMappingLinks(child, targetNodePath, sourceParameterMap, sourceBody));
+ } else {
+ answer.push(...MappingService.extractMappingLinks(child, sourceParameterMap, sourceBody));
+ }
+ });
+ }
+ return answer;
+ }
+
+ private static doExtractMappingLinks(
+ sourceExpressionItem: ExpressionItem,
+ targetNodePath: string,
+ sourceParameterMap: Map,
+ sourceBody: IDocument,
+ ) {
+ const sourceXPath = sourceExpressionItem.expression;
+ const validationResult = XPathService.validate(sourceXPath);
+ if (!validationResult.getCst() || validationResult.dataMapperErrors.length > 0) return [];
+ const fieldPaths = XPathService.extractFieldPaths(sourceXPath);
+ return fieldPaths.reduce((acc, xpath) => {
+ const absolutePath = MappingService.getAbsolutePath(sourceExpressionItem, xpath);
+ const path = new Path(absolutePath);
+ const document = path.parameterName ? sourceParameterMap.get(path.parameterName) : sourceBody;
+ const sourceNodePath =
+ document &&
+ DocumentService.getFieldFromPathSegments(
+ document,
+ path.pathSegments.map((seg) => seg.name),
+ )?.path;
+ sourceNodePath && acc.push({ sourceNodePath: sourceNodePath.toString(), targetNodePath: targetNodePath });
+ return acc;
+ }, [] as IMappingLink[]);
+ }
+}
diff --git a/packages/ui/src/services/visualization.service.test.ts b/packages/ui/src/services/visualization.service.test.ts
new file mode 100644
index 000000000..24849b26a
--- /dev/null
+++ b/packages/ui/src/services/visualization.service.test.ts
@@ -0,0 +1,560 @@
+import { VisualizationService } from './visualization.service';
+import {
+ DocumentNodeData,
+ FieldNodeData,
+ MappingNodeData,
+ TargetDocumentNodeData,
+ TargetFieldNodeData,
+ TargetNodeData,
+} from '../models/datamapper/visualization';
+import {
+ ChooseItem,
+ ExpressionItem,
+ FieldItem,
+ ForEachItem,
+ IfItem,
+ MappingTree,
+ OtherwiseItem,
+ ValueSelector,
+ WhenItem,
+} from '../models/datamapper/mapping';
+import { XmlSchemaDocument } from './xml-schema-document.service';
+import { MappingSerializerService } from './mapping-serializer.service';
+import { BODY_DOCUMENT_ID, IDocument, PrimitiveDocument } from '../models/datamapper/document';
+import { shipOrderToShipOrderInvalidForEachXslt, shipOrderToShipOrderXslt, TestUtil } from '../stubs/data-mapper';
+import { DocumentType } from '../models/datamapper/path';
+
+describe('VisualizationService', () => {
+ let sourceDoc: XmlSchemaDocument;
+ let sourceDocNode: DocumentNodeData;
+ let targetDoc: XmlSchemaDocument;
+ let paramsMap: Map;
+ let tree: MappingTree;
+ let targetDocNode: TargetDocumentNodeData;
+
+ beforeEach(() => {
+ sourceDoc = TestUtil.createSourceOrderDoc();
+ sourceDocNode = new DocumentNodeData(sourceDoc);
+ targetDoc = TestUtil.createTargetOrderDoc();
+ paramsMap = TestUtil.createParameterMap();
+ tree = new MappingTree(targetDoc.documentType, targetDoc.documentId);
+ });
+
+ describe('without pre-populated mappings', () => {
+ beforeEach(() => {
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ });
+
+ describe('testNodePair()', () => {
+ it('should sort source, target', () => {
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ const targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ const { sourceNode, targetNode } = VisualizationService.testNodePair(
+ targetDocChildren[0],
+ sourceDocChildren[0],
+ );
+ expect(sourceNode).toEqual(sourceDocChildren[0]);
+ expect(targetNode).toEqual(targetDocChildren[0]);
+ });
+ });
+
+ describe('applyIf()', () => {
+ it('should add If', () => {
+ let docChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ expect(docChildren.length).toEqual(1);
+ let shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(docChildren[0]);
+ expect(shipOrderChildren.length).toEqual(4);
+ expect(shipOrderChildren[0].title).toEqual('OrderId');
+ VisualizationService.applyIf(shipOrderChildren[0] as TargetNodeData);
+
+ expect(tree.children[0].name).toEqual('field-ShipOrder');
+ expect(tree.children[0].children[0].name).toEqual('if');
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ docChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(docChildren[0]);
+ expect(shipOrderChildren[0].title).toEqual('if');
+ const ifChildren = VisualizationService.generateNonDocumentNodeDataChildren(shipOrderChildren[0]);
+ expect(ifChildren.length).toEqual(1);
+ expect(ifChildren[0].title).toEqual('OrderId');
+ });
+
+ it('should add If on primitive target body', () => {
+ const primitiveTargetDoc = new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ tree = new MappingTree(primitiveTargetDoc.documentType, primitiveTargetDoc.documentId);
+ targetDocNode = new TargetDocumentNodeData(primitiveTargetDoc, tree);
+ VisualizationService.applyIf(targetDocNode);
+
+ expect(VisualizationService.hasChildren(targetDocNode)).toBeTruthy();
+ let targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ expect(targetDocChildren.length).toEqual(1);
+ const ifItem = (targetDocChildren[0] as MappingNodeData).mapping;
+ expect(ifItem instanceof IfItem).toBeTruthy();
+ expect(ifItem.name).toEqual('if');
+
+ targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ const ifChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(ifChildren.length).toEqual(1);
+ expect((ifChildren[0] as MappingNodeData).mapping instanceof ValueSelector).toBeTruthy();
+ });
+ });
+
+ describe('applyChooseWhenOtherwise()', () => {
+ it('should add Choose-When-Otherwise', () => {
+ let docChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ expect(docChildren.length).toEqual(1);
+ let shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(docChildren[0]);
+ expect(shipOrderChildren.length).toEqual(4);
+ expect(shipOrderChildren[1].title).toEqual('OrderPerson');
+ VisualizationService.applyChooseWhenOtherwise(shipOrderChildren[1] as TargetNodeData);
+
+ expect(tree.children[0].name).toEqual('field-ShipOrder');
+ expect(tree.children[0].children[0].name).toEqual('choose');
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ docChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(docChildren[0]);
+
+ expect(shipOrderChildren[1].title).toEqual('choose');
+ const chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(shipOrderChildren[1]);
+ expect(chooseChildren.length).toEqual(2);
+
+ expect(chooseChildren[0].title).toEqual('when');
+ const whenChildren = VisualizationService.generateNonDocumentNodeDataChildren(chooseChildren[0]);
+ expect(whenChildren.length).toEqual(1);
+ const whenOrderPerson = whenChildren[0] as MappingNodeData;
+ expect(whenOrderPerson.title).toEqual('OrderPerson');
+ expect(whenOrderPerson.mapping.parent instanceof WhenItem).toBeTruthy();
+
+ expect(chooseChildren[1].title).toEqual('otherwise');
+ const otherwiseChildren = VisualizationService.generateNonDocumentNodeDataChildren(chooseChildren[1]);
+ expect(otherwiseChildren.length).toEqual(1);
+ const otherwiseOrderPerson = otherwiseChildren[0] as MappingNodeData;
+ expect(otherwiseOrderPerson.title).toEqual('OrderPerson');
+ expect(otherwiseOrderPerson.mapping.parent instanceof OtherwiseItem).toBeTruthy();
+ });
+
+ it('should add Choose-When-Otherwise on primitive target body', () => {
+ const primitiveTargetDoc = new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ tree = new MappingTree(primitiveTargetDoc.documentType, primitiveTargetDoc.documentId);
+ targetDocNode = new TargetDocumentNodeData(primitiveTargetDoc, tree);
+ VisualizationService.applyChooseWhenOtherwise(targetDocNode);
+
+ expect(VisualizationService.hasChildren(targetDocNode)).toBeTruthy();
+ let targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ expect(targetDocChildren.length).toEqual(1);
+ const chooseItem = (targetDocChildren[0] as MappingNodeData).mapping;
+ expect(chooseItem instanceof ChooseItem).toBeTruthy();
+ expect(chooseItem.name).toEqual('choose');
+
+ targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ const chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(chooseChildren.length).toEqual(2);
+ const whenItem = (chooseChildren[0] as MappingNodeData).mapping;
+ expect(whenItem instanceof WhenItem).toBeTruthy();
+ expect(whenItem.children[0] instanceof ValueSelector).toBeTruthy();
+
+ const otherwiseItem = (chooseChildren[1] as MappingNodeData).mapping;
+ expect(otherwiseItem instanceof OtherwiseItem).toBeTruthy();
+ expect(otherwiseItem.children[0] instanceof ValueSelector).toBeTruthy();
+ });
+ });
+
+ describe('applyWhen()', () => {
+ it('should addWhen', () => {
+ let targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ let targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ VisualizationService.applyChooseWhenOtherwise(targetShipOrderChildren[1] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ VisualizationService.applyWhen(targetShipOrderChildren[1] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ const chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetShipOrderChildren[1]);
+ expect(chooseChildren.length).toEqual(3);
+
+ const whenItem1 = (chooseChildren[0] as MappingNodeData).mapping;
+ expect(whenItem1 instanceof WhenItem).toBeTruthy();
+ expect(whenItem1.children.length).toEqual(1);
+ expect(whenItem1.children[0] instanceof FieldItem).toBeTruthy();
+
+ const whenItem2 = (chooseChildren[1] as MappingNodeData).mapping;
+ expect(whenItem2 instanceof WhenItem).toBeTruthy();
+ expect(whenItem2.children.length).toEqual(1);
+ expect(whenItem2.children[0] instanceof FieldItem).toBeTruthy();
+
+ const otherwiseItem = (chooseChildren[2] as MappingNodeData).mapping;
+ expect(otherwiseItem instanceof OtherwiseItem).toBeTruthy();
+ expect(otherwiseItem.children.length).toEqual(1);
+ expect(otherwiseItem.children[0] instanceof FieldItem).toBeTruthy();
+ });
+
+ it('should add When in primitive target body choose', () => {
+ const primitiveTargetDoc = new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ tree = new MappingTree(primitiveTargetDoc.documentType, primitiveTargetDoc.documentId);
+ targetDocNode = new TargetDocumentNodeData(primitiveTargetDoc, tree);
+ VisualizationService.applyChooseWhenOtherwise(targetDocNode);
+
+ let targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ VisualizationService.applyWhen(targetDocChildren[0] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ const chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(chooseChildren.length).toEqual(3);
+
+ const whenItem1 = (chooseChildren[0] as MappingNodeData).mapping;
+ expect(whenItem1 instanceof WhenItem).toBeTruthy();
+ expect(whenItem1.children.length).toEqual(1);
+ expect(whenItem1.children[0] instanceof ValueSelector).toBeTruthy();
+
+ const whenItem2 = (chooseChildren[1] as MappingNodeData).mapping;
+ expect(whenItem2 instanceof WhenItem).toBeTruthy();
+ expect(whenItem2.children.length).toEqual(1);
+ expect(whenItem2.children[0] instanceof ValueSelector).toBeTruthy();
+
+ const otherwiseItem = (chooseChildren[2] as MappingNodeData).mapping;
+ expect(otherwiseItem instanceof OtherwiseItem).toBeTruthy();
+ expect(otherwiseItem.children.length).toEqual(1);
+ expect(otherwiseItem.children[0] instanceof ValueSelector).toBeTruthy();
+ });
+ });
+
+ describe('applyOtherwise()', () => {
+ it('should add Otherwise', () => {
+ let targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ let targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ VisualizationService.applyChooseWhenOtherwise(targetShipOrderChildren[1] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ let chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetShipOrderChildren[1]);
+ VisualizationService.deleteMappingItem(chooseChildren[1] as MappingNodeData);
+ VisualizationService.applyOtherwise(targetShipOrderChildren[1] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetShipOrderChildren[1]);
+ expect(chooseChildren.length).toEqual(2);
+
+ const whenItem = (chooseChildren[0] as MappingNodeData).mapping;
+ expect(whenItem instanceof WhenItem).toBeTruthy();
+ expect(whenItem.children.length).toEqual(1);
+ expect(whenItem.children[0] instanceof FieldItem).toBeTruthy();
+
+ const otherwiseItem = (chooseChildren[1] as MappingNodeData).mapping;
+ expect(otherwiseItem instanceof OtherwiseItem).toBeTruthy();
+ expect(otherwiseItem.children.length).toEqual(1);
+ expect(otherwiseItem.children[0] instanceof FieldItem).toBeTruthy();
+ });
+
+ it('should add Otherwise in primitive target body choose', () => {
+ const primitiveTargetDoc = new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ tree = new MappingTree(primitiveTargetDoc.documentType, primitiveTargetDoc.documentId);
+ targetDocNode = new TargetDocumentNodeData(primitiveTargetDoc, tree);
+ VisualizationService.applyChooseWhenOtherwise(targetDocNode);
+
+ let targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ let chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ VisualizationService.deleteMappingItem(chooseChildren[1] as MappingNodeData);
+ VisualizationService.applyOtherwise(targetDocChildren[0] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ chooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(chooseChildren.length).toEqual(2);
+
+ const whenItem = (chooseChildren[0] as MappingNodeData).mapping;
+ expect(whenItem instanceof WhenItem).toBeTruthy();
+ expect(whenItem.children.length).toEqual(1);
+ expect(whenItem.children[0] instanceof ValueSelector).toBeTruthy();
+
+ const otherwiseItem = (chooseChildren[1] as MappingNodeData).mapping;
+ expect(otherwiseItem instanceof OtherwiseItem).toBeTruthy();
+ expect(otherwiseItem.children.length).toEqual(1);
+ expect(otherwiseItem.children[0] instanceof ValueSelector).toBeTruthy();
+ });
+ });
+
+ describe('applyForEach()', () => {
+ it('should add for-each', () => {
+ let docChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ expect(docChildren.length).toEqual(1);
+ let shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(docChildren[0]);
+ expect(shipOrderChildren.length).toEqual(4);
+ expect(shipOrderChildren[3].title).toEqual('Item');
+ VisualizationService.applyForEach(shipOrderChildren[3] as TargetFieldNodeData);
+
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ docChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(docChildren[0]);
+ expect(shipOrderChildren[3].title).toEqual('for-each');
+ const forEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(shipOrderChildren[3]);
+ expect(forEachChildren.length).toEqual(1);
+ expect(forEachChildren[0].title).toEqual('Item');
+ });
+ });
+
+ describe('applyValueSelector()', () => {
+ it('should apply value selector', () => {
+ expect(tree.children.length).toEqual(0);
+ const docChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ VisualizationService.applyValueSelector(docChildren[0] as TargetNodeData);
+
+ expect(tree.children.length).toEqual(1);
+ expect(tree.children[0].children[0] instanceof ValueSelector).toBeTruthy();
+ });
+
+ it('should apply value selector on primitive target body', () => {
+ const primitiveTargetDoc = new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ tree = new MappingTree(primitiveTargetDoc.documentType, primitiveTargetDoc.documentId);
+ targetDocNode = new TargetDocumentNodeData(primitiveTargetDoc, tree);
+ VisualizationService.applyValueSelector(targetDocNode);
+
+ expect(VisualizationService.hasChildren(targetDocNode)).toBeFalsy();
+ const targetDocChildren = VisualizationService.generatePrimitiveDocumentChildren(targetDocNode);
+ expect(targetDocChildren.length).toEqual(0);
+ });
+ });
+
+ describe('getExpressionItemForNode()', () => {
+ it('should return ValueSelector for primitive target body', () => {
+ const primitiveTargetDoc = new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ tree = new MappingTree(primitiveTargetDoc.documentType, primitiveTargetDoc.documentId);
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ const sourceShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(sourceDocChildren[0]);
+ VisualizationService.engageMapping(tree, sourceShipOrderChildren[1] as FieldNodeData, targetDocNode);
+
+ const expressionItem = VisualizationService.getExpressionItemForNode(targetDocNode);
+ expect(expressionItem?.expression).toEqual('/ns0:ShipOrder/ns0:OrderPerson');
+ });
+ });
+
+ describe('deleteMappingItem()', () => {
+ it('should delete primitive target body mapping', () => {
+ const primitiveTargetDoc = new PrimitiveDocument(DocumentType.TARGET_BODY, BODY_DOCUMENT_ID);
+ tree = new MappingTree(primitiveTargetDoc.documentType, primitiveTargetDoc.documentId);
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ const sourceShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(sourceDocChildren[0]);
+ VisualizationService.engageMapping(tree, sourceShipOrderChildren[1] as FieldNodeData, targetDocNode);
+
+ VisualizationService.deleteMappingItem(targetDocNode);
+ const expressionItem = VisualizationService.getExpressionItemForNode(targetDocNode);
+ expect(expressionItem).toBeUndefined();
+ });
+ });
+
+ describe('engageMapping()', () => {
+ it('should engage mapping to a MappingItem', () => {
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ const sourceShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(sourceDocChildren[0]);
+ let targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ let targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ VisualizationService.applyIf(targetShipOrderChildren[1] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ const ifItem = tree.children[0].children[0] as IfItem;
+ expect(ifItem.expression).toEqual('');
+ VisualizationService.engageMapping(
+ tree,
+ sourceShipOrderChildren[1] as FieldNodeData,
+ targetShipOrderChildren[1] as TargetNodeData,
+ );
+
+ expect(ifItem.expression).toEqual('/ns0:ShipOrder/ns0:OrderPerson');
+ });
+
+ it('should engage mapping to a Document', () => {
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ expect(tree.children.length).toEqual(0);
+ VisualizationService.engageMapping(tree, sourceDocChildren[0] as FieldNodeData, targetDocNode);
+
+ expect(tree.children[0] instanceof ValueSelector).toBeTruthy();
+ const selector = tree.children[0] as ValueSelector;
+ expect(selector.expression).toEqual('/ns0:ShipOrder');
+ });
+
+ it('should engage mapping to a field', () => {
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ const sourceShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(sourceDocChildren[0]);
+ const targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ const targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(tree.children.length).toEqual(0);
+ VisualizationService.engageMapping(
+ tree,
+ sourceShipOrderChildren[1] as FieldNodeData,
+ targetShipOrderChildren[1] as TargetNodeData,
+ );
+
+ expect(tree.children[0] instanceof FieldItem).toBeTruthy();
+ expect(tree.children[0].children[0] instanceof FieldItem).toBeTruthy();
+ expect(tree.children[0].children[0].children[0] instanceof ValueSelector).toBeTruthy();
+ const selector = tree.children[0].children[0].children[0] as ValueSelector;
+ expect(selector.expression).toEqual('/ns0:ShipOrder/ns0:OrderPerson');
+ });
+
+ it("should engage regular mapping even if it's dropped to a for-each wrapped collection field", () => {
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ const sourceShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(sourceDocChildren[0]);
+ const sourceItem = sourceShipOrderChildren[3] as FieldNodeData;
+ let targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ let targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ const targetItem = targetShipOrderChildren[3] as TargetFieldNodeData;
+ VisualizationService.applyForEach(targetItem);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ const forEach = targetShipOrderChildren[3] as MappingNodeData;
+ const forEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(forEach);
+ VisualizationService.engageMapping(tree, sourceItem, forEachChildren[0] as TargetFieldNodeData);
+
+ expect((forEach.mapping as ExpressionItem).expression).toEqual('');
+ expect(((forEachChildren[0] as TargetFieldNodeData).mapping!.children[0] as ValueSelector).expression).toEqual(
+ '/ns0:ShipOrder/Item',
+ );
+ });
+
+ it('should not remove for-each targeted field item when selector is removed', () => {
+ MappingSerializerService.deserialize(shipOrderToShipOrderInvalidForEachXslt, targetDoc, tree, paramsMap);
+
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ let targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ let targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ let forEachItem = (targetShipOrderChildren[3] as MappingNodeData).mapping as ForEachItem;
+ expect(forEachItem.children.length).toEqual(1);
+ expect(forEachItem.expression).toEqual('');
+ let targetForEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(
+ targetShipOrderChildren[3],
+ );
+ let itemItem = targetForEachChildren[0] as TargetFieldNodeData;
+ expect((itemItem.mapping?.children[0] as ValueSelector).expression).toEqual('/ns0:ShipOrder/Item');
+ VisualizationService.deleteMappingItem(targetForEachChildren[0] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ forEachItem = (targetShipOrderChildren[3] as MappingNodeData).mapping as ForEachItem;
+ expect(forEachItem).toBeDefined();
+ expect(forEachItem.children.length).toEqual(1);
+ expect(forEachItem.expression).toEqual('');
+ targetForEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetShipOrderChildren[3]);
+ itemItem = targetForEachChildren[0] as TargetFieldNodeData;
+ expect(itemItem.mapping).toBeDefined();
+ expect(itemItem.mapping?.children.length).toEqual(0);
+ });
+
+ it('should not remove for-each targeted field item when descendent is removed', () => {
+ MappingSerializerService.deserialize(shipOrderToShipOrderInvalidForEachXslt, targetDoc, tree, paramsMap);
+
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ let targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ let targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ let targetForEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(
+ targetShipOrderChildren[3],
+ );
+ let targetItemChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetForEachChildren[0]);
+ const sourceDocChildren = VisualizationService.generateStructuredDocumentChildren(sourceDocNode);
+ const sourceShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(sourceDocChildren[0]);
+ const sourceItemChildren = VisualizationService.generateNonDocumentNodeDataChildren(sourceShipOrderChildren[3]);
+ VisualizationService.deleteMappingItem(targetForEachChildren[0] as TargetNodeData);
+ VisualizationService.engageMapping(
+ tree,
+ sourceItemChildren[0] as FieldNodeData,
+ targetItemChildren[0] as TargetFieldNodeData,
+ );
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ targetForEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetShipOrderChildren[3]);
+ targetItemChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetForEachChildren[0]);
+ expect(
+ ((targetItemChildren[0] as TargetFieldNodeData).mapping?.children[0] as ValueSelector).expression,
+ ).toEqual('/ns0:ShipOrder/Item/Title');
+ VisualizationService.deleteMappingItem(targetItemChildren[0] as TargetNodeData);
+
+ targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ targetShipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ const forEachItem = (targetShipOrderChildren[3] as MappingNodeData).mapping as ForEachItem;
+ expect(forEachItem).toBeDefined();
+ expect(forEachItem.children.length).toEqual(1);
+ expect(forEachItem.expression).toEqual('');
+ targetForEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetShipOrderChildren[3]);
+ targetItemChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetForEachChildren[0]);
+ expect((targetItemChildren[0] as TargetFieldNodeData).mapping?.children[0] as ValueSelector).toBeUndefined();
+ });
+ });
+ });
+
+ describe('with pre-populated mappings', () => {
+ beforeEach(() => {
+ MappingSerializerService.deserialize(shipOrderToShipOrderXslt, targetDoc, tree, paramsMap);
+ targetDocNode = new TargetDocumentNodeData(targetDoc, tree);
+ });
+
+ describe('allowIfChoose()', () => {
+ it('should test if or choose is allowed', () => {
+ const targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ const shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+
+ expect(VisualizationService.allowIfChoose(targetDocNode)).toBeTruthy();
+ expect(VisualizationService.allowIfChoose(targetDocChildren[0] as TargetNodeData)).toBeTruthy();
+ expect(VisualizationService.allowIfChoose(shipOrderChildren[1] as TargetNodeData)).toBeFalsy();
+ });
+ });
+
+ describe('deleteMappingItem()', () => {
+ it('should delete', () => {
+ const targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ let shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(shipOrderChildren[1] instanceof MappingNodeData).toBeTruthy();
+ VisualizationService.deleteMappingItem(shipOrderChildren[1] as TargetNodeData);
+
+ shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(shipOrderChildren[1] instanceof TargetFieldNodeData).toBeTruthy();
+ });
+ });
+
+ describe('allowConditionMenu()', () => {
+ it('should test condition menu is allowed', () => {
+ const targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ const shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ expect(VisualizationService.allowConditionMenu(targetDocNode)).toBeTruthy();
+ expect(VisualizationService.allowConditionMenu(targetDocChildren[0] as TargetNodeData)).toBeTruthy();
+
+ expect(shipOrderChildren.length).toEqual(4);
+ const orderIdNode = shipOrderChildren[0] as TargetFieldNodeData;
+ expect(orderIdNode.title).toEqual('OrderId');
+ expect(VisualizationService.allowConditionMenu(orderIdNode)).toBeFalsy();
+
+ const ifNode = shipOrderChildren[1] as MappingNodeData;
+ expect(ifNode.title).toEqual('if');
+ expect(VisualizationService.allowConditionMenu(ifNode)).toBeTruthy();
+
+ const shipToNode = shipOrderChildren[2] as TargetFieldNodeData;
+ expect(shipToNode.title).toEqual('ShipTo');
+ expect(VisualizationService.allowConditionMenu(shipToNode)).toBeFalsy();
+
+ const forEachNode = shipOrderChildren[3] as MappingNodeData;
+ expect(forEachNode.title).toEqual('for-each');
+ expect(VisualizationService.allowConditionMenu(forEachNode)).toBeFalsy();
+ });
+ });
+
+ describe('generateDndId()', () => {
+ it('should generate unique ID for when and otherwise children', () => {
+ const targetDocChildren = VisualizationService.generateStructuredDocumentChildren(targetDocNode);
+ const shipOrderChildren = VisualizationService.generateNonDocumentNodeDataChildren(targetDocChildren[0]);
+ const forEachChildren = VisualizationService.generateNonDocumentNodeDataChildren(shipOrderChildren[3]);
+ const forEachItemChildren = VisualizationService.generateNonDocumentNodeDataChildren(forEachChildren[0]);
+ const forEachChooseChildren = VisualizationService.generateNonDocumentNodeDataChildren(forEachItemChildren[1]);
+ const whenChildren = VisualizationService.generateNonDocumentNodeDataChildren(forEachChooseChildren[0]);
+ const otherwiseChildren = VisualizationService.generateNonDocumentNodeDataChildren(forEachChooseChildren[1]);
+
+ const whenChildDndId = VisualizationService.generateDndId(whenChildren[0]);
+ expect(whenChildDndId).toContain('when');
+ const otherwiseChildDndId = VisualizationService.generateDndId(otherwiseChildren[0]);
+ expect(otherwiseChildDndId).toContain('otherwise');
+ });
+ });
+ });
+});
diff --git a/packages/ui/src/services/visualization.service.ts b/packages/ui/src/services/visualization.service.ts
new file mode 100644
index 000000000..51e4c996b
--- /dev/null
+++ b/packages/ui/src/services/visualization.service.ts
@@ -0,0 +1,331 @@
+import {
+ MappingNodeData,
+ DocumentNodeData,
+ FieldNodeData,
+ NodeData,
+ SourceNodeDataType,
+ TargetDocumentNodeData,
+ TargetNodeData,
+ TargetFieldNodeData,
+ TargetNodeDataType,
+} from '../models/datamapper/visualization';
+import {
+ ChooseItem,
+ ExpressionItem,
+ FieldItem,
+ ForEachItem,
+ IfItem,
+ MappingItem,
+ MappingTree,
+ OtherwiseItem,
+ ValueSelector,
+ WhenItem,
+} from '../models/datamapper/mapping';
+import { IField, PrimitiveDocument } from '../models/datamapper/document';
+import { MappingService } from './mapping.service';
+import { DocumentService } from './document.service';
+
+type MappingNodePairType = {
+ sourceNode?: SourceNodeDataType;
+ targetNode?: TargetNodeDataType;
+};
+
+export class VisualizationService {
+ static generateNodeDataChildren(nodeData: NodeData) {
+ const isDocument = nodeData instanceof DocumentNodeData;
+ const isPrimitive = nodeData.isPrimitive;
+ return isDocument
+ ? isPrimitive
+ ? VisualizationService.generatePrimitiveDocumentChildren(nodeData as DocumentNodeData)
+ : VisualizationService.generateStructuredDocumentChildren(nodeData as DocumentNodeData)
+ : VisualizationService.generateNonDocumentNodeDataChildren(nodeData);
+ }
+ static generatePrimitiveDocumentChildren(document: DocumentNodeData): NodeData[] {
+ if (!(document instanceof TargetDocumentNodeData) || !document.mapping?.children) return [];
+ return document.mapping.children
+ .filter((child) => !(child instanceof ValueSelector))
+ .map((child) => new MappingNodeData(document, child));
+ }
+
+ static generateStructuredDocumentChildren(document: DocumentNodeData): NodeData[] {
+ return VisualizationService.doGenerateNodeDataFromFields(
+ document,
+ document.document.fields,
+ document instanceof TargetDocumentNodeData ? document.mappingTree.children : undefined,
+ );
+ }
+
+ private static doGenerateNodeDataFromFields(parent: NodeData, fields: IField[], mappings?: MappingItem[]) {
+ const answer: NodeData[] = [];
+ if (parent.isPrimitive && mappings) {
+ mappings
+ .filter((m) => m instanceof ValueSelector)
+ .forEach((m) => answer.push(new MappingNodeData(parent as TargetNodeData, m)));
+ }
+ return fields.reduce((acc, field) => {
+ const mappingsForField = mappings ? MappingService.filterMappingsForField(mappings, field) : [];
+ if (mappingsForField.length === 0) {
+ const fieldNodeData = parent.isSource
+ ? new FieldNodeData(parent, field)
+ : new TargetFieldNodeData(parent as TargetNodeData, field);
+ acc.push(fieldNodeData);
+ return acc;
+ }
+ mappingsForField
+ .filter((mapping) => !VisualizationService.isExistingMapping(acc as TargetNodeData[], mapping))
+ .sort((left, right) => MappingService.sortMappingItem(left, right))
+ .forEach((mapping) => {
+ if (mapping instanceof FieldItem) {
+ const fieldNodeData = new TargetFieldNodeData(parent as TargetNodeData, field, mapping);
+ acc.push(fieldNodeData);
+ } else {
+ acc.push(new MappingNodeData(parent as TargetNodeData, mapping));
+ }
+ });
+ return acc;
+ }, answer);
+ }
+
+ private static isExistingMapping(nodes: TargetNodeData[], mapping: MappingItem) {
+ return nodes.find((node) => 'mapping' in node && node.mapping === mapping);
+ }
+
+ static generateNonDocumentNodeDataChildren(parent: NodeData): NodeData[] {
+ if (parent instanceof MappingNodeData) {
+ return parent.mapping?.children
+ ? parent.mapping.children
+ .sort((left, right) => MappingService.sortMappingItem(left, right))
+ .map((m) => VisualizationService.createNodeDataFromMappingItem(parent, m))
+ : [];
+ } else if (parent instanceof FieldNodeData) {
+ DocumentService.resolveTypeFragment(parent.field);
+ return VisualizationService.doGenerateNodeDataFromFields(
+ parent,
+ parent.field.fields,
+ parent instanceof TargetFieldNodeData ? parent.mapping?.children : undefined,
+ );
+ }
+ return [];
+ }
+
+ private static createNodeDataFromMappingItem(parent: TargetNodeData, item: MappingItem): NodeData {
+ return item instanceof FieldItem
+ ? new TargetFieldNodeData(parent, item.field, item)
+ : new MappingNodeData(parent, item);
+ }
+
+ static testNodePair(fromNode: NodeData, toNode: NodeData): MappingNodePairType {
+ const answer: MappingNodePairType = {};
+ if ((fromNode.isSource && toNode.isSource) || (!fromNode.isSource && !toNode.isSource)) return answer;
+
+ const sourceNode = (fromNode.isSource ? fromNode : toNode) as SourceNodeDataType;
+ const targetNode = (fromNode.isSource ? toNode : fromNode) as TargetNodeDataType;
+ return { sourceNode, targetNode };
+ }
+
+ static isDocumentNode(nodeData: NodeData) {
+ return nodeData instanceof DocumentNodeData;
+ }
+
+ static isPrimitiveDocumentNode(nodeData: NodeData) {
+ return nodeData instanceof DocumentNodeData && nodeData.document instanceof PrimitiveDocument;
+ }
+
+ static isCollectionField(nodeData: NodeData) {
+ return nodeData instanceof FieldNodeData && nodeData.field?.maxOccurs && nodeData.field.maxOccurs > 1;
+ }
+
+ static isAttributeField(nodeData: NodeData) {
+ return nodeData instanceof FieldNodeData && nodeData.field?.isAttribute;
+ }
+
+ static isRecursiveField(nodeData: NodeData) {
+ return nodeData instanceof FieldNodeData && DocumentService.isRecursiveField(nodeData.field);
+ }
+
+ static hasChildren(nodeData: NodeData) {
+ if (nodeData instanceof DocumentNodeData) {
+ if (DocumentService.hasFields(nodeData.document)) return true;
+ const isPrimitiveDocument = nodeData instanceof TargetDocumentNodeData && nodeData.isPrimitive;
+ const isPrimitiveDocumentWithConditionItem =
+ isPrimitiveDocument && !!nodeData.mapping.children.find((m) => !(m instanceof ValueSelector));
+ if (isPrimitiveDocumentWithConditionItem) return true;
+ }
+ if (nodeData instanceof FieldNodeData) return DocumentService.hasChildren(nodeData.field);
+ if (nodeData instanceof MappingNodeData) return nodeData.mapping.children.length > 0;
+ return false;
+ }
+
+ static shouldCollapseByDefault(nodeData: NodeData, initialExpandedRank: number, rank: number) {
+ if (nodeData instanceof DocumentNodeData) return false;
+ const isRecursiveField = VisualizationService.isRecursiveField(nodeData);
+ return isRecursiveField || rank > initialExpandedRank;
+ }
+
+ static allowIfChoose(nodeData: TargetNodeData) {
+ if (nodeData instanceof MappingNodeData) {
+ const mapping = nodeData.mapping;
+ if (
+ mapping instanceof ValueSelector ||
+ mapping instanceof WhenItem ||
+ mapping instanceof OtherwiseItem ||
+ mapping instanceof IfItem ||
+ mapping instanceof ChooseItem
+ )
+ return false;
+ }
+ return true;
+ }
+
+ static allowForEach(nodeData: TargetNodeData) {
+ return nodeData instanceof TargetFieldNodeData && VisualizationService.isCollectionField(nodeData);
+ }
+
+ static isForEachNode(nodeData: TargetNodeData) {
+ return nodeData instanceof MappingNodeData && nodeData.mapping instanceof ForEachItem;
+ }
+
+ static isValueSelectorNode(nodeData: TargetNodeData) {
+ return nodeData instanceof MappingNodeData && nodeData.mapping instanceof ValueSelector;
+ }
+
+ static isChooseNode(nodeData: TargetNodeData) {
+ return nodeData instanceof MappingNodeData && nodeData.mapping instanceof ChooseItem;
+ }
+
+ static isDeletableNode(nodeData: TargetNodeData) {
+ if (nodeData instanceof MappingNodeData) return true;
+ return VisualizationService.getFieldValueSelector(nodeData) !== undefined;
+ }
+
+ static getExpressionItemForNode(nodeData: TargetNodeData) {
+ if (!nodeData.mapping) return;
+ if (nodeData.mapping instanceof ExpressionItem) return nodeData.mapping as ExpressionItem;
+ return VisualizationService.getFieldValueSelector(nodeData);
+ }
+
+ private static getFieldValueSelector(nodeData: TargetNodeData) {
+ if (nodeData.mapping instanceof FieldItem || nodeData.mapping instanceof MappingTree) {
+ return nodeData.mapping.children.find((c) => c instanceof ValueSelector) as ValueSelector;
+ }
+ }
+
+ static allowConditionMenu(nodeData: TargetNodeData) {
+ if (nodeData instanceof TargetFieldNodeData || nodeData instanceof TargetDocumentNodeData) {
+ const isForEachField =
+ 'parent' in nodeData &&
+ nodeData.parent instanceof MappingNodeData &&
+ nodeData.parent.mapping instanceof ForEachItem;
+ return !isForEachField && !VisualizationService.getExpressionItemForNode(nodeData);
+ }
+ const mappingNodeData = nodeData as MappingNodeData;
+ return (
+ !(mappingNodeData.mapping instanceof WhenItem) &&
+ !(mappingNodeData.mapping instanceof OtherwiseItem) &&
+ !(mappingNodeData.mapping instanceof ForEachItem)
+ );
+ }
+
+ static allowValueSelector(nodeData: TargetNodeData) {
+ return (
+ !VisualizationService.isChooseNode(nodeData) &&
+ !VisualizationService.isValueSelectorNode(nodeData) &&
+ !VisualizationService.isForEachNode(nodeData)
+ );
+ }
+
+ static hasValueSelector(nodeData: TargetNodeData) {
+ return !!(nodeData.mapping && nodeData.mapping.children.find((c) => c instanceof ValueSelector));
+ }
+
+ static deleteMappingItem(nodeData: TargetNodeData) {
+ if (nodeData.mapping) {
+ MappingService.deleteMappingItem(nodeData.mapping);
+ }
+ }
+
+ static applyIf(nodeData: TargetNodeData) {
+ if (nodeData instanceof TargetDocumentNodeData) {
+ const valueSelector = nodeData.mappingTree.children.find((c) => c instanceof ValueSelector);
+ MappingService.addIf(nodeData.mappingTree, valueSelector);
+ } else if (nodeData instanceof MappingNodeData || nodeData instanceof TargetFieldNodeData) {
+ const mapping = nodeData.mapping
+ ? nodeData.mapping
+ : nodeData instanceof TargetFieldNodeData
+ ? (VisualizationService.getOrCreateFieldItem(nodeData) as FieldItem)
+ : undefined;
+ if (!mapping) return;
+ MappingService.wrapWithIf(mapping);
+ }
+ }
+
+ static applyChooseWhenOtherwise(nodeData: TargetNodeData) {
+ if (nodeData instanceof TargetDocumentNodeData) {
+ if (nodeData.mappingTree.children.find((c) => c instanceof ChooseItem)) return;
+
+ const valueSelector = nodeData.mappingTree.children.find((c) => c instanceof ValueSelector);
+ MappingService.addChooseWhenOtherwise(nodeData.mappingTree, valueSelector);
+ } else if (nodeData instanceof MappingNodeData || nodeData instanceof TargetFieldNodeData) {
+ if (nodeData.mapping && nodeData.mapping.children.find((c) => c instanceof ChooseItem)) return;
+
+ const mapping = nodeData.mapping
+ ? nodeData.mapping
+ : nodeData instanceof TargetFieldNodeData
+ ? (VisualizationService.getOrCreateFieldItem(nodeData) as FieldItem)
+ : undefined;
+ if (!mapping) return;
+ MappingService.wrapWithChooseWhenOtherwise(mapping);
+ }
+ }
+
+ static applyWhen(nodeData: TargetNodeData) {
+ const chooseItem = nodeData.mapping as ChooseItem;
+ MappingService.addWhen(chooseItem, undefined, chooseItem.field);
+ }
+
+ static applyOtherwise(nodeData: TargetNodeData) {
+ const chooseItem = nodeData.mapping as ChooseItem;
+ MappingService.addOtherwise(chooseItem, undefined, chooseItem.field);
+ }
+
+ static applyForEach(nodeData: TargetFieldNodeData) {
+ const fieldItem = VisualizationService.getOrCreateFieldItem(nodeData);
+ MappingService.wrapWithForEach(fieldItem as MappingItem);
+ }
+
+ static applyValueSelector(nodeData: TargetNodeData) {
+ const mapping =
+ nodeData instanceof TargetFieldNodeData && !nodeData.mapping
+ ? VisualizationService.getOrCreateFieldItem(nodeData)
+ : nodeData.mapping;
+ if (!mapping) return;
+ const existing = mapping.children.find((c: MappingItem) => c instanceof ValueSelector);
+ if (!existing) {
+ const valueSelector = MappingService.createValueSelector(mapping);
+ mapping.children.push(valueSelector);
+ }
+ }
+
+ static engageMapping(mappingTree: MappingTree, sourceNode: SourceNodeDataType, targetNode: TargetNodeData) {
+ const sourceField = 'document' in sourceNode ? (sourceNode.document as PrimitiveDocument) : sourceNode.field;
+ if (targetNode instanceof MappingNodeData) {
+ MappingService.mapToCondition(targetNode.mapping, sourceField);
+ } else if (targetNode instanceof TargetDocumentNodeData) {
+ MappingService.mapToDocument(mappingTree, sourceField);
+ } else if (targetNode instanceof TargetFieldNodeData) {
+ const item = VisualizationService.getOrCreateFieldItem(targetNode);
+ MappingService.mapToField(sourceField, item as MappingItem);
+ }
+ }
+
+ private static getOrCreateFieldItem(nodeData: TargetNodeData): MappingItem {
+ if (nodeData.mapping) return nodeData.mapping as MappingItem;
+ const fieldNodeData = nodeData as TargetFieldNodeData;
+ const parentItem = VisualizationService.getOrCreateFieldItem(fieldNodeData.parent);
+ return MappingService.createFieldItem(parentItem, fieldNodeData.field);
+ }
+
+ static generateDndId(nodeData: NodeData) {
+ return nodeData instanceof DocumentNodeData ? nodeData.id : nodeData.path.pathSegments.join('-');
+ }
+}
diff --git a/packages/ui/src/services/xml-schema-document.service.test.ts b/packages/ui/src/services/xml-schema-document.service.test.ts
new file mode 100644
index 000000000..f4fc397db
--- /dev/null
+++ b/packages/ui/src/services/xml-schema-document.service.test.ts
@@ -0,0 +1,93 @@
+import { XmlSchemaDocumentService, XmlSchemaField } from './xml-schema-document.service';
+import { BODY_DOCUMENT_ID } from '../models/datamapper/document';
+import { DocumentType } from '../models/datamapper/path';
+import { Types } from '../models/datamapper/types';
+import { camelSpringXsd, shipOrderXsd, shipOrderEmptyFirstLineXsd, testDocumentXsd } from '../stubs/data-mapper';
+
+describe('XmlSchemaDocumentService', () => {
+ it('should parse ShipOrder XML schema', () => {
+ const document = XmlSchemaDocumentService.createXmlSchemaDocument(
+ DocumentType.SOURCE_BODY,
+ BODY_DOCUMENT_ID,
+ shipOrderXsd,
+ );
+ expect(document).toBeDefined();
+ const shipOrder = XmlSchemaDocumentService.getFirstElement(document.xmlSchema);
+ const fields: XmlSchemaField[] = [];
+ XmlSchemaDocumentService.populateElement(document, fields, shipOrder);
+ expect(fields.length > 0).toBeTruthy();
+ expect(fields[0].name).toEqual('ShipOrder');
+ expect(fields[0].fields[3].name).toEqual('Item');
+ const itemTitleField = fields[0].fields[3].fields[0];
+ expect(itemTitleField.name).toEqual('Title');
+ expect(itemTitleField.type).not.toEqual(Types.Container);
+ });
+
+ it('should parse TestDocument XML schema', () => {
+ const document = XmlSchemaDocumentService.createXmlSchemaDocument(
+ DocumentType.TARGET_BODY,
+ BODY_DOCUMENT_ID,
+ testDocumentXsd,
+ );
+ expect(document).toBeDefined();
+ const testDoc = XmlSchemaDocumentService.getFirstElement(document.xmlSchema);
+ const fields: XmlSchemaField[] = [];
+ XmlSchemaDocumentService.populateElement(document, fields, testDoc);
+ expect(fields.length > 0).toBeTruthy();
+ });
+
+ it('should parse camel-spring.xsd XML schema', () => {
+ const document = XmlSchemaDocumentService.createXmlSchemaDocument(
+ DocumentType.TARGET_BODY,
+ BODY_DOCUMENT_ID,
+ camelSpringXsd,
+ );
+ expect(document).toBeDefined();
+ expect(document.fields.length).toEqual(1);
+ const aggregate = document.fields[0];
+ expect(aggregate.fields.length).toBe(0);
+ expect(aggregate.namedTypeFragmentRefs.length).toEqual(1);
+ expect(aggregate.namedTypeFragmentRefs[0]).toEqual('{http://camel.apache.org/schema/spring}aggregateDefinition');
+ const aggregateDef = document.namedTypeFragments[aggregate.namedTypeFragmentRefs[0]];
+ expect(aggregateDef.fields.length).toEqual(100);
+ expect(aggregateDef.namedTypeFragmentRefs[0]).toEqual('{http://camel.apache.org/schema/spring}output');
+ const outputDef = document.namedTypeFragments[aggregateDef.namedTypeFragmentRefs[0]];
+ expect(outputDef.fields.length).toEqual(0);
+ expect(outputDef.namedTypeFragmentRefs[0]).toEqual('{http://camel.apache.org/schema/spring}processorDefinition');
+ const processorDef = document.namedTypeFragments[outputDef.namedTypeFragmentRefs[0]];
+ expect(processorDef.fields.length).toEqual(2);
+ expect(processorDef.namedTypeFragmentRefs[0]).toEqual(
+ '{http://camel.apache.org/schema/spring}optionalIdentifiedDefinition',
+ );
+ const optionalIdentifiedDef = document.namedTypeFragments[processorDef.namedTypeFragmentRefs[0]];
+ expect(optionalIdentifiedDef.fields.length).toEqual(3);
+ expect(optionalIdentifiedDef.namedTypeFragmentRefs.length).toEqual(0);
+ });
+
+ it('should create XML Schema Document', () => {
+ const doc = XmlSchemaDocumentService.createXmlSchemaDocument(
+ DocumentType.SOURCE_BODY,
+ 'ShipOrder.xsd',
+ shipOrderXsd,
+ );
+ expect(doc.documentType).toEqual(DocumentType.SOURCE_BODY);
+ expect(doc.documentId).toEqual('ShipOrder.xsd');
+ expect(doc.name).toEqual('ShipOrder.xsd');
+ expect(doc.fields.length).toEqual(1);
+ });
+
+ it('should throw an error if there is a parse error on the XML schema', () => {
+ try {
+ XmlSchemaDocumentService.createXmlSchemaDocument(
+ DocumentType.SOURCE_BODY,
+ 'ShipOrderEmptyFirstLine.xsd',
+ shipOrderEmptyFirstLineXsd,
+ );
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (error: any) {
+ expect(error.message).toContain('an XML declaration must be at the start of the document');
+ return;
+ }
+ expect(true).toBeFalsy();
+ });
+});
diff --git a/packages/ui/src/services/xml-schema-document.service.ts b/packages/ui/src/services/xml-schema-document.service.ts
new file mode 100644
index 000000000..756db00b4
--- /dev/null
+++ b/packages/ui/src/services/xml-schema-document.service.ts
@@ -0,0 +1,415 @@
+import {
+ XmlSchema,
+ XmlSchemaAll,
+ XmlSchemaAllMember,
+ XmlSchemaAny,
+ XmlSchemaAttribute,
+ XmlSchemaAttributeGroup,
+ XmlSchemaAttributeGroupMember,
+ XmlSchemaAttributeGroupRef,
+ XmlSchemaAttributeOrGroupRef,
+ XmlSchemaChoice,
+ XmlSchemaChoiceMember,
+ XmlSchemaCollection,
+ XmlSchemaComplexContentExtension,
+ XmlSchemaComplexContentRestriction,
+ XmlSchemaComplexType,
+ XmlSchemaContentModel,
+ XmlSchemaElement,
+ XmlSchemaGroup,
+ XmlSchemaGroupParticle,
+ XmlSchemaGroupRef,
+ XmlSchemaParticle,
+ XmlSchemaRef,
+ XmlSchemaSequence,
+ XmlSchemaSequenceMember,
+ XmlSchemaSimpleContentExtension,
+ XmlSchemaSimpleContentRestriction,
+ XmlSchemaSimpleType,
+ XmlSchemaType,
+ XmlSchemaUse,
+} from '@kaoto/xml-schema-ts';
+import { BaseDocument, BaseField, ITypeFragment } from '../models/datamapper/document';
+import { Types } from '../models/datamapper/types';
+import { DocumentType } from '../models/datamapper/path';
+import { DocumentService } from './document.service';
+
+export interface XmlSchemaTypeFragment extends ITypeFragment {
+ fields: XmlSchemaField[];
+}
+
+export class XmlSchemaDocument extends BaseDocument {
+ rootElement: XmlSchemaElement;
+ fields: XmlSchemaField[] = [];
+ namedTypeFragments: Record = {};
+ totalFieldCount = 0;
+ isNamespaceAware = true;
+
+ constructor(
+ public xmlSchema: XmlSchema,
+ documentType: DocumentType,
+ documentId: string,
+ ) {
+ super(documentType, documentId);
+ this.name = documentId;
+ if (this.xmlSchema.getElements().size == 0) {
+ throw Error("There's no top level Element in the schema");
+ }
+ // TODO let user choose the root element from top level elements if there're multiple
+ this.rootElement = XmlSchemaDocumentService.getFirstElement(this.xmlSchema);
+ XmlSchemaDocumentService.populateElement(this, this.fields, this.rootElement);
+ this.schemaType = 'XML';
+ }
+}
+
+type XmlSchemaParentType = XmlSchemaDocument | XmlSchemaField;
+
+export class XmlSchemaField extends BaseField {
+ fields: XmlSchemaField[] = [];
+ namespaceURI: string | null = null;
+ namespacePrefix: string | null = null;
+
+ constructor(
+ public parent: XmlSchemaParentType,
+ public name: string,
+ public isAttribute: boolean,
+ ) {
+ super(parent, DocumentService.getOwnerDocument(parent), name);
+ }
+}
+
+export class XmlSchemaDocumentService {
+ static parseXmlSchema(content: string): XmlSchema {
+ const collection = new XmlSchemaCollection();
+ return collection.read(content, () => {});
+ }
+
+ static createXmlSchemaDocument(documentType: DocumentType, documentId: string, content: string) {
+ const schema = XmlSchemaDocumentService.parseXmlSchema(content);
+ return new XmlSchemaDocument(schema, documentType, documentId);
+ }
+
+ static getFirstElement(xmlSchema: XmlSchema) {
+ return xmlSchema.getElements().values().next().value;
+ }
+
+ /**
+ * Populate XML Element as a field into {@link fields} array passed in as an argument.
+ * @param parent
+ * @param fields
+ * @param element
+ */
+ static populateElement(parent: XmlSchemaParentType, fields: XmlSchemaField[], element: XmlSchemaElement) {
+ const name = element.getWireName()!.getLocalPart()!;
+ const refTarget = element.getRef().getTarget();
+ const resolvedElement = refTarget ? refTarget : element;
+ const field: XmlSchemaField = new XmlSchemaField(parent, name, false);
+ field.namespaceURI = resolvedElement.getWireName()!.getNamespaceURI();
+ field.namespacePrefix = resolvedElement.getWireName()!.getPrefix();
+ field.defaultValue = resolvedElement.defaultValue || resolvedElement.fixedValue;
+ field.minOccurs = resolvedElement.getMinOccurs();
+ field.maxOccurs = resolvedElement.getMaxOccurs();
+ fields.push(field);
+
+ const ownerDoc = DocumentService.getOwnerDocument(parent);
+ const cachedTypeFragments = ownerDoc.namedTypeFragments;
+ ownerDoc.totalFieldCount++;
+ XmlSchemaDocumentService.populateSchemaType(cachedTypeFragments, field, resolvedElement.getSchemaType());
+ }
+
+ private static populateSchemaType(
+ cachedTypeFragments: Record,
+ field: XmlSchemaField,
+ schemaType: XmlSchemaType | null,
+ parentTypeFragment?: XmlSchemaTypeFragment,
+ ) {
+ if (!schemaType) return;
+ if (schemaType instanceof XmlSchemaSimpleType) {
+ const simple = schemaType as XmlSchemaSimpleType;
+ field.type = Types[simple.getName() as keyof typeof Types] || Types.AnyType;
+ return;
+ }
+ field.type = Types.Container;
+ if (schemaType instanceof XmlSchemaComplexType) {
+ const complex = schemaType as XmlSchemaComplexType;
+ const typeQName = complex.getQName();
+ const children: XmlSchemaField[] = [];
+ const typeFragment: XmlSchemaTypeFragment = { fields: children, namedTypeFragmentRefs: [] };
+ if (typeQName) {
+ parentTypeFragment
+ ? parentTypeFragment.namedTypeFragmentRefs.push(typeQName.toString())
+ : field.namedTypeFragmentRefs.push(typeQName.toString());
+ const cached = typeQName && cachedTypeFragments[typeQName.toString()];
+ if (cached) return;
+ cachedTypeFragments[typeQName.toString()] = typeFragment;
+ } else {
+ field.fields = children;
+ }
+
+ XmlSchemaDocumentService.populateContentModel(
+ cachedTypeFragments,
+ field,
+ children,
+ complex.getContentModel(),
+ typeFragment,
+ );
+ const attributes: XmlSchemaAttributeOrGroupRef[] = complex.getAttributes();
+ attributes.forEach((attr) => {
+ XmlSchemaDocumentService.populateAttributeOrGroupRef(field, children, attr);
+ });
+ XmlSchemaDocumentService.populateParticle(field, children, complex.getParticle());
+ }
+ }
+
+ private static populateAttributeOrGroupRef(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ attr: XmlSchemaAttributeOrGroupRef,
+ ) {
+ if (attr instanceof XmlSchemaAttribute) {
+ XmlSchemaDocumentService.populateAttribute(parent, fields, attr);
+ } else if (attr instanceof XmlSchemaAttributeGroupRef) {
+ XmlSchemaDocumentService.populateAttributeGroupRef(parent, fields, attr);
+ }
+ }
+
+ /**
+ * Populate XML Attribute as a field into {@link fields} array passed in as an argument.
+ * @param parent
+ * @param fields
+ * @param attr
+ */
+ static populateAttribute(parent: XmlSchemaParentType, fields: XmlSchemaField[], attr: XmlSchemaAttribute) {
+ const name = attr.getWireName()!.getLocalPart()!;
+ const field = new XmlSchemaField(parent, name, true);
+ field.namespaceURI = attr.getWireName()!.getNamespaceURI();
+ field.namespacePrefix = attr.getWireName()!.getPrefix();
+ field.defaultValue = attr.getDefaultValue() || attr.getFixedValue();
+ fields.push(field);
+
+ const ownerDoc = DocumentService.getOwnerDocument(parent);
+ ownerDoc.totalFieldCount++;
+
+ const use = attr.getUse();
+ switch (use) {
+ case XmlSchemaUse.PROHIBITED:
+ field.maxOccurs = 0;
+ field.minOccurs = 0;
+ break;
+ case XmlSchemaUse.REQUIRED:
+ field.minOccurs = 1;
+ field.maxOccurs = 1;
+ break;
+ default: // OPTIONAL, NONE or not specified
+ field.minOccurs = 0;
+ field.maxOccurs = 1;
+ break;
+ }
+ }
+
+ private static populateAttributeGroupRef(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ groupRef: XmlSchemaAttributeGroupRef,
+ ) {
+ const ref: XmlSchemaRef = groupRef.getRef();
+ XmlSchemaDocumentService.populateAttributeGroup(parent, fields, ref.getTarget());
+ }
+
+ private static populateAttributeGroupMember(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ member: XmlSchemaAttributeGroupMember,
+ ) {
+ if (member instanceof XmlSchemaAttribute) {
+ XmlSchemaDocumentService.populateAttribute(parent, fields, member);
+ } else if (member instanceof XmlSchemaAttributeGroup) {
+ XmlSchemaDocumentService.populateAttributeGroup(parent, fields, member);
+ } else if (member instanceof XmlSchemaAttributeGroupRef) {
+ XmlSchemaDocumentService.populateAttributeGroupRef(parent, fields, member);
+ }
+ }
+
+ private static populateAttributeGroup(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ group: XmlSchemaAttributeGroup | null,
+ ) {
+ if (group == null) {
+ return;
+ }
+ group
+ .getAttributes()
+ .forEach((member: XmlSchemaAttributeGroupMember) =>
+ XmlSchemaDocumentService.populateAttributeGroupMember(parent, fields, member),
+ );
+ }
+
+ private static populateParticle(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ particle: XmlSchemaParticle | null,
+ ) {
+ if (particle == null) {
+ return;
+ }
+ if (particle instanceof XmlSchemaAny) {
+ XmlSchemaDocumentService.populateAny(fields, particle);
+ } else if (particle instanceof XmlSchemaElement) {
+ XmlSchemaDocumentService.populateElement(parent, fields, particle);
+ } else if (particle instanceof XmlSchemaGroupParticle) {
+ XmlSchemaDocumentService.populateGroupParticle(parent, fields, particle);
+ } else if (particle instanceof XmlSchemaGroupRef) {
+ XmlSchemaDocumentService.populateGroupRef(parent, fields, particle);
+ }
+ }
+
+ private static populateAny(_fields: XmlSchemaField[], _schemaAny: XmlSchemaAny) {
+ /* TODO - xs:any allows arbitrary elements */
+ }
+
+ private static populateGroupParticle(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ groupParticle: XmlSchemaGroupParticle | null,
+ ) {
+ if (groupParticle == null) {
+ return;
+ }
+ if (groupParticle instanceof XmlSchemaChoice) {
+ const choice = groupParticle as XmlSchemaChoice;
+ choice
+ .getItems()
+ .forEach((member: XmlSchemaChoiceMember) =>
+ XmlSchemaDocumentService.populateChoiceMember(parent, fields, member),
+ );
+ } else if (groupParticle instanceof XmlSchemaSequence) {
+ const sequence = groupParticle as XmlSchemaSequence;
+ sequence
+ .getItems()
+ .forEach((member: XmlSchemaSequenceMember) =>
+ XmlSchemaDocumentService.populateSequenceMember(parent, fields, member),
+ );
+ } else if (groupParticle instanceof XmlSchemaAll) {
+ const all = groupParticle as XmlSchemaAll;
+ all
+ .getItems()
+ .forEach((member: XmlSchemaAllMember) => XmlSchemaDocumentService.populateAllMember(parent, fields, member));
+ }
+ }
+
+ private static populateGroupRef(parent: XmlSchemaParentType, fields: XmlSchemaField[], groupRef: XmlSchemaGroupRef) {
+ XmlSchemaDocumentService.populateGroupParticle(parent, fields, groupRef.getParticle());
+ }
+
+ private static populateChoiceMember(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ member: XmlSchemaChoiceMember,
+ ) {
+ if (member instanceof XmlSchemaGroupRef) {
+ XmlSchemaDocumentService.populateGroupRef(parent, fields, member);
+ } else if (member instanceof XmlSchemaGroup) {
+ XmlSchemaDocumentService.populateGroup(parent, fields, member);
+ } else if (member instanceof XmlSchemaParticle) {
+ XmlSchemaDocumentService.populateParticle(parent, fields, member);
+ }
+ }
+
+ private static populateSequenceMember(
+ parent: XmlSchemaParentType,
+ fields: XmlSchemaField[],
+ member: XmlSchemaSequenceMember,
+ ) {
+ if (member instanceof XmlSchemaGroupRef) {
+ XmlSchemaDocumentService.populateGroupRef(parent, fields, member);
+ } else if (member instanceof XmlSchemaGroup) {
+ XmlSchemaDocumentService.populateGroup(parent, fields, member);
+ } else if (member instanceof XmlSchemaParticle) {
+ XmlSchemaDocumentService.populateParticle(parent, fields, member);
+ }
+ }
+
+ private static populateAllMember(parent: XmlSchemaParentType, fields: XmlSchemaField[], member: XmlSchemaAllMember) {
+ if (member instanceof XmlSchemaParticle) {
+ XmlSchemaDocumentService.populateParticle(parent, fields, member);
+ }
+ }
+
+ private static populateGroup(parent: XmlSchemaParentType, fields: XmlSchemaField[], group: XmlSchemaGroup) {
+ XmlSchemaDocumentService.populateParticle(parent, fields, group.getParticle());
+ }
+
+ private static populateContentModel(
+ cachedTypeFragments: Record,
+ parent: XmlSchemaField,
+ fields: XmlSchemaField[],
+ contentModel: XmlSchemaContentModel | null,
+ parentTypeFragment?: XmlSchemaTypeFragment,
+ ) {
+ if (!contentModel) return;
+ const content = contentModel.getContent();
+ if (content instanceof XmlSchemaSimpleContentExtension) {
+ XmlSchemaDocumentService.populateSimpleContentExtension(parent, fields, content);
+ } else if (content instanceof XmlSchemaSimpleContentRestriction) {
+ XmlSchemaDocumentService.populateSimpleContentRestriction(parent, fields, content);
+ } else if (content instanceof XmlSchemaComplexContentExtension) {
+ XmlSchemaDocumentService.populateComplexContentExtension(
+ cachedTypeFragments,
+ parent,
+ fields,
+ content,
+ parentTypeFragment,
+ );
+ } else if (content instanceof XmlSchemaComplexContentRestriction) {
+ XmlSchemaDocumentService.populateComplexContentRestriction(parent, fields, content);
+ }
+ }
+
+ private static populateSimpleContentExtension(
+ parent: XmlSchemaField,
+ fields: XmlSchemaField[],
+ extension: XmlSchemaSimpleContentExtension,
+ ) {
+ const attributes = extension.getAttributes();
+ attributes.forEach((attr) => {
+ XmlSchemaDocumentService.populateAttributeOrGroupRef(parent, fields, attr);
+ });
+ }
+
+ private static populateSimpleContentRestriction(
+ _parent: XmlSchemaField,
+ _fields: XmlSchemaField[],
+ _restriction: XmlSchemaSimpleContentRestriction,
+ ) {
+ // TODO restriction support
+ }
+
+ private static populateComplexContentExtension(
+ cachedTypeFragments: Record,
+ parent: XmlSchemaField,
+ fields: XmlSchemaField[],
+ extension: XmlSchemaComplexContentExtension,
+ parentTypeFragment?: XmlSchemaTypeFragment,
+ ) {
+ const baseTypeName = extension.getBaseTypeName();
+ const doc = DocumentService.getOwnerDocument(parent);
+ const baseType = baseTypeName ? doc.xmlSchema.getSchemaTypes().get(baseTypeName) : undefined;
+ if (baseType) {
+ XmlSchemaDocumentService.populateSchemaType(cachedTypeFragments, parent, baseType, parentTypeFragment);
+ }
+ const attributes = extension.getAttributes();
+ attributes.forEach((attr) => {
+ XmlSchemaDocumentService.populateAttributeOrGroupRef(parent, fields, attr);
+ });
+ XmlSchemaDocumentService.populateParticle(parent, fields, extension.getParticle());
+ }
+
+ private static populateComplexContentRestriction(
+ _parent: XmlSchemaField,
+ _fields: XmlSchemaField[],
+ _restriction: XmlSchemaComplexContentRestriction,
+ ) {
+ // TODO restriction support
+ }
+}
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-boolean.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-boolean.ts
new file mode 100644
index 000000000..2682b99a4
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-boolean.ts
@@ -0,0 +1,24 @@
+import { Types } from '../../../models/datamapper/types';
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+
+/**
+ * 9.3 Boolean - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#boolean-value-functions
+ */
+export const booleanFunctions = [
+ {
+ name: 'not',
+ displayName: 'Not',
+ description: 'Inverts the xs:boolean value of the argument.',
+ returnType: Types.Boolean,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+] as IFunctionDefinition[];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-context.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-context.ts
new file mode 100644
index 000000000..31fc0a45c
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-context.ts
@@ -0,0 +1,64 @@
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+import { Types } from '../../../models/datamapper/types';
+
+/**
+ * 16 Context - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#context
+ */
+export const contextFunctions = [
+ {
+ name: 'position',
+ displayName: 'Position',
+ description: 'Returns the position of the context item within the sequence of items currently being processed.',
+ returnType: Types.Integer,
+ arguments: [],
+ },
+ {
+ name: 'last',
+ displayName: 'Last',
+ description: 'Returns the number of items in the sequence of items currently being processed.',
+ returnType: Types.Integer,
+ arguments: [],
+ },
+ {
+ name: 'current-dateTime',
+ displayName: 'Current DateTime',
+ description: 'Returns the current xs:dateTime.',
+ returnType: Types.DateTime,
+ arguments: [],
+ },
+ {
+ name: 'current-date',
+ displayName: 'Current Date',
+ description: 'Returns the current xs:date.',
+ returnType: Types.Date,
+ arguments: [],
+ },
+ {
+ name: 'current-time',
+ displayName: 'Current Time',
+ description: 'Returns the current xs:time.',
+ returnType: Types.Time,
+ arguments: [],
+ },
+ {
+ name: 'implicit-timezone',
+ displayName: 'Implicit Timezone',
+ description: 'Returns the value of the implicit timezone property from the dynamic context.',
+ returnType: Types.DayTimeDuration,
+ arguments: [],
+ },
+ {
+ name: 'default-collation',
+ displayName: 'Default Collation',
+ description: 'Returns the value of the default collation property from the static context.',
+ returnType: Types.String,
+ arguments: [],
+ },
+ {
+ name: 'static-base-uri',
+ displayName: 'Static Base URI',
+ description: 'Returns the value of the Base URI property from the static context.',
+ returnType: Types.AnyURI,
+ arguments: [],
+ },
+] as IFunctionDefinition[];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-datetime.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-datetime.ts
new file mode 100644
index 000000000..869f7a8fd
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-datetime.ts
@@ -0,0 +1,248 @@
+import { Types } from '../../../models/datamapper/types';
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+
+/**
+ * 10. Date and Time - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#durations-dates-times
+ */
+export const dateAndTimeFunctions = [
+ {
+ name: 'years-from-duration',
+ displayName: 'Years From Duration',
+ description: 'Returns the year component of an xs:duration value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Duration, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'months-from-duration',
+ displayName: 'Months From Duration',
+ description: 'Returns the months component of an xs:duration value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Duration, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'days-from-duration',
+ displayName: 'Days From Duration',
+ description: 'Returns the days component of an xs:duration value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Duration, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'hours-from-duration',
+ displayName: 'Hours From Duration',
+ description: 'Returns the hours component of an xs:duration value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Duration, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'minutes-from-duration',
+ displayName: 'Minutes From Duration',
+ description: 'Returns the minutes component of an xs:duration value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Duration, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'seconds-from-duration',
+ displayName: 'Seconds From Duration',
+ description: 'Returns the seconds component of an xs:duration value.',
+ returnType: Types.Decimal,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Duration, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'year-from-dateTime',
+ displayName: 'Year From Date Time',
+ description: 'Returns the year from an xs:dateTime value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.DateTime, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'month-from-dateTime',
+ displayName: 'Month From Date Time',
+ description: 'Returns the month from an xs:dateTime value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.DateTime, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'day-from-dateTime',
+ displayName: 'Day From Date Time',
+ description: 'Returns the day from an xs:dateTime value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.DateTime, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'hours-from-dateTime',
+ displayName: 'Hours From Date Time',
+ description: 'Returns the hours from an xs:dateTime value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.DateTime, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'minutes-from-dateTime',
+ displayName: 'Minutes From Date Time',
+ description: 'Returns the minutes from an xs:dateTime value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.DateTime, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'seconds-from-dateTime',
+ displayName: 'Seconds From Date Time',
+ description: 'Returns the seconds from an xs:dateTime value.',
+ returnType: Types.Decimal,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Decimal, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'timezone-from-dateTime',
+ displayName: 'Timezone From Date Time',
+ description: 'Returns the timezone from an xs:dateTime value.',
+ returnType: Types.DayTimeDuration,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.DateTime, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'year-from-date',
+ displayName: 'Year From Date',
+ description: 'Returns the year from an xs:date value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Date, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'month-from-date',
+ displayName: 'Month From Date',
+ description: 'Returns the month from an xs:date value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Date, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'day-from-date',
+ displayName: 'Day From Date',
+ description: 'Returns the day from an xs:date value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Date, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'timezone-from-date',
+ displayName: 'Timezone From Date',
+ description: 'Returns the timezone from an xs:date value.',
+ returnType: Types.DayTimeDuration,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Date, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'hours-from-time',
+ displayName: 'Hours From Time',
+ description: 'Returns the hours from an xs:time value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Time, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'minutes-from-time',
+ displayName: 'Minutes From Time',
+ description: 'Returns the minutes from an xs:time value.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Time, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'seconds-from-time',
+ displayName: 'Seconds From Time',
+ description: 'Returns the seconds from an xs:time value.',
+ returnType: Types.Decimal,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Time, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'timezone-from-time',
+ displayName: 'Timezone From Time',
+ description: 'Returns the timezone from an xs:time value.',
+ returnType: Types.DayTimeDuration,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Time, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'adjust-dateTime-to-timezone',
+ displayName: 'Adjust DateTime to Timezone',
+ description: 'Adjusts an xs:dateTime value to a specific timezone, or to no timezone at all.',
+ returnType: Types.DateTime,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.DateTime, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'timezone',
+ displayName: '$timezone',
+ description: '$timezone',
+ type: Types.DayTimeDuration,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'adjust-date-to-timezone',
+ displayName: 'Adjust Date to Timezone',
+ description: 'Adjusts an xs:date value to a specific timezone, or to no timezone at all.',
+ returnType: Types.Date,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Date, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'timezone',
+ displayName: '$timezone',
+ description: '$timezone',
+ type: Types.DayTimeDuration,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'adjust-time-to-timezone',
+ displayName: 'Adjust Time to Timezone',
+ description: 'Adjusts an xs:time value to a specific timezone, or to no timezone at all.',
+ returnType: Types.Time,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Time, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'timezone',
+ displayName: '$timezone',
+ description: '$timezone',
+ type: Types.DayTimeDuration,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+] as IFunctionDefinition[];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-node.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-node.ts
new file mode 100644
index 000000000..d5e7c1e16
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-node.ts
@@ -0,0 +1,79 @@
+import { Types } from '../../../models/datamapper/types';
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+
+/**
+ * 14 Node - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#node-functions
+ */
+export const nodeFunctions = [
+ {
+ name: 'name',
+ displayName: 'Name',
+ description: 'Returns the name of the context node or the specified node as an xs:string.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Node, minOccurs: 0, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'local-name',
+ displayName: 'Local Name',
+ description: 'Returns the local name of the context node or the specified node as an xs:NCName.',
+ },
+ {
+ name: 'namespace-uri',
+ displayName: 'Namespace URI',
+ description:
+ 'Returns the namespace URI as an xs:anyURI for the xs:QName of the argument node or the context node if' +
+ ' the argument is omitted. This may be the URI corresponding to the zero-length string if the xs:QName' +
+ ' is in no namespace.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Node, minOccurs: 0, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'number',
+ displayName: 'Number',
+ description:
+ 'Returns the value of the context item after atomization or the specified argument converted to an xs:double.',
+ returnType: Types.Double,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.AnyAtomicType, minOccurs: 0, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'lang',
+ displayName: 'Lang',
+ description:
+ 'Returns true or false, depending on whether the language of the given node or the context node, as defined' +
+ ' using the xml:lang attribute, is the same as, or a sublanguage of, the language specified by the argument.',
+ returnType: Types.Boolean,
+ arguments: [
+ {
+ name: 'testlarg',
+ displayName: '$testlang',
+ description: '$testlang',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'node',
+ displayName: '$node',
+ description: '$node',
+ type: Types.Node,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'root',
+ displayName: 'Root',
+ description: 'Returns the root of the tree to which the node argument belongs.',
+ returnType: Types.Node,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.Node, minOccurs: 0, maxOccurs: 1 },
+ ],
+ },
+] as IFunctionDefinition[];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-numeric.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-numeric.ts
new file mode 100644
index 000000000..19a21c9f7
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-numeric.ts
@@ -0,0 +1,63 @@
+import { Types } from '../../../models/datamapper/types';
+
+/**
+ * 6.4 Numeric - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#numeric-value-functions
+ */
+export const numericFunctions = [
+ {
+ name: 'abs',
+ displayName: 'Absolute',
+ description: 'Returns the absolute value of the argument.',
+ returnType: Types.Numeric,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.Numeric, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'ceiling',
+ displayName: 'Ceiling',
+ description: 'Returns the smallest number with no fractional part that is greater than or equal to the argument.',
+ returnType: Types.Numeric,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.Numeric, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'floor',
+ displayName: 'Floor',
+ group: 'Numeric',
+ description: 'Returns the largest number with no fractional part that is less than or equal to the argument.',
+ returnType: Types.Numeric,
+ arguments: [
+ { name: 'arg', displayName: 'arg', description: 'Argument', type: Types.Numeric, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'round',
+ displayName: 'Round',
+ description: 'Rounds to the nearest number with no fractional part.',
+ returnType: Types.Numeric,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.Numeric, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'round-half-to-even',
+ displayName: 'Round Half To Even',
+ description:
+ 'Takes a number and a precision and returns a number rounded to the given precision. If the fractional part' +
+ ' is exactly half, the result is the number whose least significant digit is even.',
+ returnType: Types.Numeric,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.Numeric, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'precision',
+ displayName: 'Precision',
+ description: 'Precision',
+ type: Types.Integer,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-qname.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-qname.ts
new file mode 100644
index 000000000..74a15930b
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-qname.ts
@@ -0,0 +1,117 @@
+import { Types } from '../../../models/datamapper/types';
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+
+/**
+ * 11 QName - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#QName-funcs
+ */
+export const qnameFunctions = [
+ {
+ name: 'resolve-QName',
+ displayName: 'Resolve QName',
+ description:
+ 'Returns an xs:QName with the lexical form given in the first argument. The prefix is resolved using the' +
+ ' in-scope namespaces for a given element.',
+ returnType: Types.QName,
+ arguments: [
+ { name: 'qname', displayName: '$qname', description: '$qname', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'QName',
+ displayName: 'QName',
+ description:
+ 'Returns an xs:QName with the namespace URI given in the first argument and the local name and prefix in' +
+ ' the second argument.',
+ returnType: Types.QName,
+ arguments: [
+ {
+ name: 'paramURI',
+ displayName: '$paramURI',
+ description: '$paramURI',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'paramQName',
+ displayName: '$paramQName',
+ description: '$paramQName',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'prefix-from-QName',
+ displayName: 'Prefix From QName',
+ description: 'Returns an xs:NCName representing the prefix of the xs:QName argument.',
+ returnType: Types.NCName,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.QName, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'local-name-from-QName',
+ displayName: 'Local Name From QName',
+ description: 'Returns an xs:NCName representing the local name of the xs:QName argument.',
+ returnType: Types.NCName,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.QName, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'namespace-uri--from-QName',
+ displayName: 'Namespace URI From QName',
+ description:
+ 'Returns the namespace URI for the xs:QName argument. If the xs:QName is in no namespace, the zero-length' +
+ ' string is returned.',
+ returnType: Types.AnyURI,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: '$arg', type: Types.QName, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'namespace-uri-for-prefix',
+ displayName: 'Namespace URI For Prefix',
+ description:
+ 'Returns the namespace URI of one of the in-scope namespaces for the given element,' +
+ ' identified by its namespace prefix.',
+ returnType: Types.AnyURI,
+ arguments: [
+ {
+ name: 'prefix',
+ displayName: '$prefix',
+ description: '$prefix',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'element',
+ displayName: '$element',
+ description: '$element',
+ type: Types.Element,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'in-scope-prefixes',
+ displayName: 'In Scope Prefixes',
+ description: 'Returns the prefixes of the in-scope namespaces for the given element.',
+ returnType: Types.String,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'element',
+ displayName: '$element',
+ description: '$element',
+ type: Types.Element,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ ],
+ },
+] as IFunctionDefinition[];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-sequence.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-sequence.ts
new file mode 100644
index 000000000..a265c5888
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-sequence.ts
@@ -0,0 +1,518 @@
+import { Types } from '../../../models/datamapper/types';
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+
+/**
+ * 15 Sequence - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#sequence-functions
+ */
+export const sequenceFunctions = [
+ {
+ name: 'boolean',
+ displayName: 'Boolean',
+ description: 'Computes the effective boolean value of the argument sequence.',
+ returnType: Types.Boolean,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'index-of',
+ displayName: 'Index Of',
+ description:
+ 'Returns a sequence of xs:integers, each of which is the index of a member of the sequence specified as' +
+ ' the first argument that is equal to the value of the second argument. If no members of the specified' +
+ ' sequence are equal to the value of the second argument, the empty sequence is returned.',
+ returnType: Types.Integer,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'seqParam',
+ displayName: '$seqParam',
+ description: '$seqParam',
+ type: Types.AnyAtomicType,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'srchParam',
+ displayName: '$srchParam',
+ description: '$srchParam',
+ type: Types.AnyAtomicType,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: '$collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'empty',
+ displayName: 'Empty',
+ description: 'Indicates whether or not the provided sequence is empty.',
+ returnType: Types.Boolean,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'exists',
+ displayName: 'Exists',
+ description: 'Indicates whether or not the provided sequence is not empty.',
+ returnType: Types.Boolean,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'distinct-values',
+ displayName: 'Distinct Values',
+ description:
+ 'Returns a sequence in which all but one of a set of duplicate values, based on value equality, have been' +
+ ' deleted. The order in which the distinct values are returned is implementation dependent.',
+ returnType: Types.AnyAtomicType,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.AnyAtomicType,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: '$collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'insert-before',
+ displayName: 'Insert Before',
+ description: 'Inserts an item or sequence of items at a specified position in a sequence.',
+ returnType: Types.Item,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'target',
+ displayName: '$target',
+ description: '$target',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'position',
+ displayName: '$position',
+ description: '$position',
+ type: Types.Integer,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'inserts',
+ displayName: '$inserts',
+ description: '$inserts',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'remove',
+ displayName: 'Remove',
+ description: 'Removes an item from a specified position in a sequence.',
+ returnType: Types.Item,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'target',
+ displayName: '$target',
+ description: '$target',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'position',
+ displayName: '$position',
+ description: '$position',
+ type: Types.Integer,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'reverse',
+ displayName: 'Reverse',
+ description: 'Reverses the order of items in a sequence.',
+ returnType: Types.Item,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'subsequence',
+ displayName: 'Subsequence',
+ description: 'Returns the subsequence of a given sequence, identified by location.',
+ returnType: Types.Item,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'sourceSeq',
+ displayName: '$sourceSeq',
+ description: '$sourceSeq',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'startingLoc',
+ displayName: '$startingLoc',
+ description: '$startingLoc',
+ type: Types.Double,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'length',
+ displayName: '$length',
+ description: '$length',
+ type: Types.Double,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'unordered',
+ displayName: 'Unordered',
+ description: 'Returns the items in the given sequence in a non-deterministic order.',
+ returnType: Types.Item,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'sourceSeq',
+ displayName: '$sourceSeq',
+ description: '$sourceSeq',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'zero-or-one',
+ displayName: 'Zero Or One',
+ description: 'Returns the input sequence if it contains zero or one items. Raises an error otherwise.',
+ returnType: Types.Item,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'one-or-more',
+ displayName: 'One Or More',
+ description: 'Returns the input sequence if it contains one or more items. Raises an error otherwise.',
+ returnType: Types.Item,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'exactly-one',
+ displayName: 'Exactly One',
+ description: 'Returns the input sequence if it contains exactly one item. Raises an error otherwise.',
+ returnType: Types.Item,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'deep-equal',
+ displayName: 'Deep Equal',
+ description: 'Returns true if the two arguments have items that compare equal in corresponding positions.',
+ returnType: Types.Boolean,
+ arguments: [
+ {
+ name: 'parameter1',
+ displayName: '$parameter1',
+ description: 'parameter1',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'parameter2',
+ displayName: '$parameter2',
+ description: 'parameter2',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: 'collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'count',
+ displayName: 'Count',
+ description: 'Returns the number of items in a sequence.',
+ returnType: Types.Integer,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.Item,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'avg',
+ displayName: 'Average',
+ description: 'Returns the average of a sequence of values.',
+ returnType: Types.AnyAtomicType,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.AnyAtomicType,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'max',
+ displayName: 'Maximum',
+ description: 'Returns the maximum value from a sequence of comparable values.',
+ returnType: Types.AnyAtomicType,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.AnyAtomicType,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: 'collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'min',
+ displayName: 'Minimum',
+ description: 'Returns the minimum value from a sequence of comparable values.',
+ returnType: Types.AnyAtomicType,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.AnyAtomicType,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: 'collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'sum',
+ displayName: 'Sum',
+ description: 'Returns the sum of a sequence of values.',
+ returnType: Types.AnyAtomicType,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.AnyAtomicType,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'zero',
+ displayName: '$zero',
+ description: 'zero',
+ type: Types.AnyAtomicType,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'id',
+ displayName: 'ID',
+ description:
+ 'Returns the sequence of element nodes having an ID value matching the one or more of the supplied IDREF values.',
+ returnType: Types.Element,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'node',
+ displayName: '$node',
+ description: '$node',
+ type: Types.Node,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'idref',
+ displayName: 'IDREF',
+ description:
+ 'Returns the sequence of element or attribute nodes with an IDREF value matching one or more of the' +
+ ' supplied ID values.',
+ returnType: Types.Node,
+ returnCollection: true,
+ arguments: [
+ {
+ name: 'arg',
+ displayName: '$arg',
+ description: '$arg',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'node',
+ displayName: '$node',
+ description: '$node',
+ type: Types.Node,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'doc',
+ displayName: 'DOC',
+ description: 'Returns a document node retrieved using the specified URI.',
+ returnType: Types.DocumentNode,
+ arguments: [{ name: 'uri', displayName: '$uri', type: Types.String, minOccurs: 1, maxOccurs: 1 }],
+ },
+ {
+ name: 'doc-available',
+ displayName: 'DOC available',
+ description: 'Returns true if a document node can be retrieved using the specified URI.',
+ returnType: Types.Boolean,
+ arguments: [{ name: 'uri', displayName: '$uri', type: Types.String, minOccurs: 1, maxOccurs: 1 }],
+ },
+ {
+ name: 'collection',
+ displayName: 'Collection',
+ description:
+ 'Returns a sequence of nodes retrieved using the specified URI or the nodes in the default collection.',
+ returnType: Types.Node,
+ returnCollection: true,
+ arguments: [{ name: 'arg', displayName: '$arg', type: Types.String, minOccurs: 0, maxOccurs: 1 }],
+ },
+ {
+ name: 'element-with-id',
+ displayName: 'Element With ID',
+ description:
+ 'Returns the sequence of element nodes that have an ID value matching the value of one or more of the' +
+ ' IDREF values supplied in $arg.',
+ returnType: Types.Element,
+ returnCollection: true,
+ arguments: [
+ { name: 'arg', displayName: '$arg', type: Types.String, minOccurs: 1, maxOccurs: Number.MAX_VALUE },
+ { name: 'node', displayName: '$node', type: Types.Node, minOccurs: 0, maxOccurs: 1 },
+ ],
+ },
+] as IFunctionDefinition[];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-string.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-string.ts
new file mode 100644
index 000000000..ade04ea0e
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions-string.ts
@@ -0,0 +1,402 @@
+import { Types } from '../../../models/datamapper/types';
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+
+/**
+ * 7.4 String - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#string-value-functions
+ */
+export const stringFunctions = [
+ {
+ name: 'concat',
+ displayName: 'Concatenate',
+ description: 'Concatenates two or more xs:anyAtomicType arguments cast to xs:string.',
+ returnType: Types.String,
+ arguments: [
+ {
+ name: 'args',
+ displayName: '$args',
+ description: 'Arguments',
+ type: Types.AnyAtomicType,
+ minOccurs: 2,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ ],
+ },
+ {
+ name: 'string-join',
+ displayName: 'Concatenate with Delimiter',
+ description:
+ 'Returns the xs:string produced by concatenating a sequence of xs:strings using an optional separator.',
+ returnType: Types.String,
+ arguments: [
+ {
+ name: 'arg1',
+ displayName: '$arg1',
+ description: 'Arguments',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: Number.MAX_SAFE_INTEGER,
+ },
+ {
+ name: 'arg2',
+ displayName: '$arg2',
+ description: 'Separator',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'substring',
+ displayName: 'Substring',
+ description: 'Returns the xs:string located at a specified place within an argument xs:string.',
+ returnType: Types.String,
+ arguments: [
+ {
+ name: 'sourceString',
+ displayName: '$sourceString',
+ description: 'Source String',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'startingLoc',
+ displayName: '$startingLoc',
+ description: 'Starting Location',
+ type: Types.Double,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'length',
+ displayName: '$length',
+ description: 'Length',
+ type: Types.Double,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'string-length',
+ displayName: 'String Length',
+ description: 'Returns the length of the argument.',
+ returnType: Types.Integer,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.String, minOccurs: 0, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'normalize-space',
+ displayName: 'Normalize Space',
+ description: 'Returns the whitespace-normalized value of the argument.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.String, minOccurs: 0, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'normalize-unicode',
+ displayName: 'Normalize Unicode',
+ description:
+ 'Returns the normalized value of the first argument in the normalization form specified by the second argument.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'normalizationForm',
+ displayName: '$normalizationForm',
+ description: 'Normalization Form',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'upper-case',
+ displayName: 'Uppercase',
+ description: 'Returns the upper-cased value of the argument.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'lower-case',
+ displayName: 'Lowercase',
+ description: 'Returns the lower-cased value of the argument.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'translate',
+ displayName: 'Translate',
+ description:
+ 'Returns the first xs:string argument with occurrences of characters contained in the second argument' +
+ ' replaced by the character at the corresponding position in the third argument.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg', displayName: '$arg', description: 'Argument', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'mapString',
+ displayName: '$mapString',
+ description: 'Map String',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'transString',
+ displayName: '$transString',
+ description: 'Translate String',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'encode-for-uri',
+ displayName: 'Encode for URI',
+ description:
+ 'Returns the xs:string argument with certain characters escaped to enable the resulting string to be used' +
+ ' as a path segment in a URI.',
+ returnType: Types.String,
+ arguments: [
+ {
+ name: 'uri-part',
+ displayName: '$uri-part',
+ description: 'An URI part',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'iri-to-uri',
+ displayName: 'IRI to URI',
+ description:
+ 'Returns the xs:string argument with certain characters escaped to enable the resulting string to be used' +
+ ' as (part of) a URI.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'iri', displayName: '$iri', description: 'IRI string', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+ {
+ name: 'escape-html-uri',
+ displayName: 'Escape HTML URI',
+ description:
+ 'Returns the xs:string argument with certain characters escaped in the manner that html user agents handle' +
+ ' attribute values that expect URIs.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'uri', displayName: '$uri', description: 'URI string', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ ],
+ },
+] as IFunctionDefinition[];
+
+/**
+ * 7.5 Substring Matching - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#substring.functions
+ */
+export const substringMatchingFunctions = [
+ {
+ name: 'contains',
+ displayName: 'Contains',
+ description: 'Indicates whether one xs:string contains another xs:string. A collation may be specified.',
+ returnType: Types.Boolean,
+ arguments: [
+ { name: 'arg1', displayName: '$arg1', description: '$arg1', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ { name: 'arg2', displayName: '$arg2', description: '$arg2', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: '$collation',
+ type: 'xs:string',
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'starts-with',
+ displayName: 'Starts With',
+ description:
+ 'Indicates whether the value of one xs:string begins with the collation units of another xs:string.' +
+ ' A collation may be specified.',
+ returnType: Types.Boolean,
+ arguments: [
+ { name: 'arg1', displayName: '$arg1', description: '$arg1', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ { name: 'arg2', displayName: '$arg2', description: '$arg2', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: '$collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'ends-with',
+ displayName: 'Ends With',
+ description:
+ 'Indicates whether the value of one xs:string ends with the collation units of another xs:string.' +
+ ' A collation may be specified.',
+ returnType: Types.Boolean,
+ arguments: [
+ { name: 'arg1', displayName: '$arg1', description: '$arg1', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ { name: 'arg2', displayName: '$arg2', description: '$arg2', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: '$collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'substring-before',
+ displayName: 'Substring Before',
+ description:
+ 'Returns the collation units of one xs:string that precede in that xs:string the collation units of another' +
+ ' xs:string. A collation may be specified.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg1', displayName: '$arg1', description: '$arg1', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ { name: 'arg2', displayName: '$arg2', description: '$arg2', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: '$collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'substring-after',
+ displayName: 'Substring After',
+ description:
+ 'Returns the collation units of xs:string that follow in that xs:string the collation units of another' +
+ ' xs:string. A collation may be specified.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'arg1', displayName: '$arg1', description: '$arg1', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ { name: 'arg2', displayName: '$arg2', description: '$arg2', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'collation',
+ displayName: '$collation',
+ description: '$collation',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+] as IFunctionDefinition[];
+
+/**
+ * 7.6 Pattern Matching - https://www.w3.org/TR/2010/REC-xpath-functions-20101214/#string.match
+ */
+export const patternMatchingFunctions = [
+ {
+ name: 'matches',
+ displayName: 'Matches',
+ description:
+ 'Returns an xs:boolean value that indicates whether the value of the first argument is matched by the' +
+ ' regular expression that is the value of the second argument.',
+ returnType: Types.Boolean,
+ arguments: [
+ { name: 'input', displayName: '$input', description: '$input', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'pattern',
+ displayName: '$pattern',
+ description: '$pattern',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'flags',
+ displayName: '$flags',
+ description: '$flags',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'replace',
+ displayName: 'Replace',
+ description:
+ 'Returns the value of the first argument with every substring matched by the regular expression that is' +
+ ' the value of the second argument replaced by the replacement string that is the value of the third argument.',
+ returnType: Types.String,
+ arguments: [
+ { name: 'input', displayName: '$input', description: '$input', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'pattern',
+ displayName: '$pattern',
+ description: '$pattern',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'replacement',
+ displayName: '$replacement',
+ description: '$replacement',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'flags',
+ displayName: '$flags',
+ description: '$flags',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+ {
+ name: 'tokenize',
+ displayName: 'Tokenize',
+ description:
+ 'Returns a sequence of one or more xs:strings whose values are substrings of the value of the first argument' +
+ ' separated by substrings that match the regular expression that is the value of the second argument.',
+ returnType: Types.String,
+ returnCollection: true,
+ arguments: [
+ { name: 'input', displayName: '$input', description: '$input', type: Types.String, minOccurs: 1, maxOccurs: 1 },
+ {
+ name: 'pattern',
+ displayName: '$pattern',
+ description: '$pattern',
+ type: Types.String,
+ minOccurs: 1,
+ maxOccurs: 1,
+ },
+ {
+ name: 'flags',
+ displayName: '$flags',
+ description: '$flags',
+ type: Types.String,
+ minOccurs: 0,
+ maxOccurs: 1,
+ },
+ ],
+ },
+] as IFunctionDefinition[];
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-functions.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions.ts
new file mode 100644
index 000000000..802b7fb23
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-functions.ts
@@ -0,0 +1,28 @@
+import { IFunctionDefinition } from '../../../models/datamapper/mapping';
+import { FunctionGroup } from '../xpath-parser';
+import { numericFunctions } from './xpath-2.0-functions-numeric';
+import { patternMatchingFunctions, stringFunctions, substringMatchingFunctions } from './xpath-2.0-functions-string';
+import { dateAndTimeFunctions } from './xpath-2.0-functions-datetime';
+import { booleanFunctions } from './xpath-2.0-functions-boolean';
+import { qnameFunctions } from './xpath-2.0-functions-qname';
+import { nodeFunctions } from './xpath-2.0-functions-node';
+import { sequenceFunctions } from './xpath-2.0-functions-sequence';
+import { contextFunctions } from './xpath-2.0-functions-context';
+
+/**
+ * The XPath 2.0 functions catalog.
+ * https://www.w3.org/TR/2010/REC-xpath-functions-20101214/
+ */
+
+export const XPATH_2_0_FUNCTIONS: Record = {
+ [FunctionGroup.String]: stringFunctions,
+ [FunctionGroup.SubstringMatching]: substringMatchingFunctions,
+ [FunctionGroup.PatternMatching]: patternMatchingFunctions,
+ [FunctionGroup.Numeric]: numericFunctions,
+ [FunctionGroup.DateAndTime]: dateAndTimeFunctions,
+ [FunctionGroup.Boolean]: booleanFunctions,
+ [FunctionGroup.QName]: qnameFunctions,
+ [FunctionGroup.Node]: nodeFunctions,
+ [FunctionGroup.Sequence]: sequenceFunctions,
+ [FunctionGroup.Context]: contextFunctions,
+};
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-parser.test.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-parser.test.ts
new file mode 100644
index 000000000..381971843
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-parser.test.ts
@@ -0,0 +1,32 @@
+import { XPath2Parser } from './xpath-2.0-parser';
+
+describe('XPath 2.0 parser', () => {
+ describe('Lexer', () => {
+ it('should tokenize', () => {
+ let tokens = XPath2Parser.lexer.tokenize('/shiporder/orderperson');
+ expect(tokens.errors.length).toEqual(0);
+ expect(tokens.tokens.length).toEqual(4);
+ tokens = XPath2Parser.lexer.tokenize('/shiporder/orderperson/');
+ expect(tokens.errors.length).toEqual(0);
+ expect(tokens.tokens.length).toEqual(5);
+ tokens = XPath2Parser.lexer.tokenize('/from/me/to/you');
+ expect(tokens.errors.length).toEqual(0);
+ expect(tokens.tokens.length).toEqual(8);
+ });
+ });
+
+ describe('Parser', () => {
+ it('should parse', () => {
+ const parser = new XPath2Parser();
+ let result = parser.parseXPath('/shiporder/orderperson');
+ expect(result.lexErrors.length).toEqual(0);
+ expect(result.parseErrors.length).toEqual(0);
+ result = parser.parseXPath('/shiporder/orderperson/');
+ expect(result.lexErrors.length).toEqual(0);
+ expect(result.parseErrors.length).toEqual(0);
+ result = parser.parseXPath('/from/me/to/you');
+ expect(result.lexErrors.length).toEqual(0);
+ expect(result.parseErrors.length).toEqual(0);
+ });
+ });
+});
diff --git a/packages/ui/src/services/xpath/2.0/xpath-2.0-parser.ts b/packages/ui/src/services/xpath/2.0/xpath-2.0-parser.ts
new file mode 100644
index 000000000..4c78bd67c
--- /dev/null
+++ b/packages/ui/src/services/xpath/2.0/xpath-2.0-parser.ts
@@ -0,0 +1,730 @@
+import { defaultParserErrorProvider, IParserConfig, ITokenConfig, TokenType } from 'chevrotain';
+import { createToken as orgCreateToken, CstParser, Lexer } from 'chevrotain';
+import { XPathParser, XPathParserResult } from '../xpath-parser';
+
+const fragments: Record = {};
+const f = fragments;
+
+fragments['NameStartChar'] = /[a-zA-Z]|\\u2070-\\u218F|\\u2C00-\\u2FEF|\\u3001-\\uD7FF|\\uF900-\\uFDCF|\\uFDF0-\\uFFFD/;
+fragments['NameChar'] = new RegExp(
+ `(${f.NameStartChar.source})|-|_|\\.|\\d|\\u00B7|[\\u0300-\\u036F]|[\\u203F-\\u2040]`,
+);
+fragments['Name'] = new RegExp(`(${f.NameStartChar.source})(${f.NameChar.source})*`);
+fragments['StringLiteral'] = /("(""|[^"])*")|('(''|[^'])*')/;
+fragments['Digits'] = /[0-9]+/;
+fragments['DecimalLiteral'] = /(\.[0-9]+)|([0-9]+\.[0-9]*)/;
+fragments['DoubleLiteral'] = /((\.[0-9]+)|([0-9]+(\.[0-9]*)?))[eE][+-]?[0-9]+/;
+
+const allTokens: TokenType[] = [];
+
+function createToken(options: ITokenConfig) {
+ const newToken = orgCreateToken(options);
+ allTokens.push(newToken);
+ return newToken;
+}
+
+createToken({
+ name: 'WhiteSpace',
+ pattern: /\s+/,
+ group: Lexer.SKIPPED,
+});
+
+/* In order to refer NCName from keywords for longer_alt, declare earlier here, but push as a last one later */
+const NCName = orgCreateToken({ name: 'NCName', pattern: fragments['Name'] });
+
+const Comma = createToken({ name: 'Comma', pattern: /,/ });
+const Return = createToken({ name: 'Returns', pattern: /return/, longer_alt: NCName });
+const For = createToken({ name: 'For', pattern: /for/, longer_alt: NCName });
+const Dollar = createToken({ name: 'Dollar', pattern: /\$/ });
+const Intersect = createToken({ name: 'Intersect', pattern: /intersect/, longer_alt: NCName });
+const Instance = createToken({ name: 'Instance', pattern: /instance/, longer_alt: NCName });
+const In = createToken({ name: 'In', pattern: /in/, longer_alt: NCName });
+const Some = createToken({ name: 'Some', pattern: /some/, longer_alt: NCName });
+const Every = createToken({ name: 'Every', pattern: /every/, longer_alt: NCName });
+const Satisfies = createToken({ name: 'Satisfies', pattern: /satisfies/, longer_alt: NCName });
+const If = createToken({ name: 'If', pattern: /if/, longer_alt: NCName });
+const Then = createToken({ name: 'Then', pattern: /then/, longer_alt: NCName });
+const Else = createToken({ name: 'Else', pattern: /else/, longer_alt: NCName });
+const LParen = createToken({ name: 'LParen', pattern: /\(/ });
+const RParen = createToken({ name: 'RParen', pattern: /\)/ });
+const Or = createToken({ name: 'Or', pattern: /or/, longer_alt: NCName });
+const And = createToken({ name: 'And', pattern: /and/, longer_alt: NCName });
+const To = createToken({ name: 'To', pattern: /to/, longer_alt: NCName });
+const Plus = createToken({ name: 'Plus', pattern: /\+/ });
+const Minus = createToken({ name: 'Minus', pattern: /-/ });
+const Asterisk = createToken({ name: 'Asterisk', pattern: /\*/ });
+const Div = createToken({ name: 'Div', pattern: /div/, longer_alt: NCName });
+const Idiv = createToken({ name: 'Tdiv', pattern: /idiv/, longer_alt: NCName });
+const Mod = createToken({ name: 'Mod', pattern: /mod/, longer_alt: NCName });
+const Union = createToken({ name: 'Union', pattern: /union/, longer_alt: NCName });
+const Pipe = createToken({ name: 'Pipe', pattern: /\|/ });
+const Except = createToken({ name: 'Except', pattern: /except/, longer_alt: NCName });
+const Of = createToken({ name: 'Of', pattern: /of/, longer_alt: NCName });
+const Treat = createToken({ name: 'Treat', pattern: /treat/, longer_alt: NCName });
+const Castable = createToken({ name: 'Castable', pattern: /castable/, longer_alt: NCName });
+const As = createToken({ name: 'As', pattern: /as/, longer_alt: NCName });
+const Cast = createToken({ name: 'Cast', pattern: /cast/, longer_alt: NCName });
+const Equal = createToken({ name: 'Equal', pattern: /=/ });
+const NotEqual = createToken({ name: 'NotEqual', pattern: /!=/ });
+const Precede = createToken({ name: 'Precede', pattern: /< });
+const LessThanEqual = createToken({ name: 'LessThanEqual', pattern: /<=/ });
+const LessThan = createToken({ name: 'LessThan', pattern: / });
+const Follow = createToken({ name: 'Precede', pattern: />>/ });
+const GreaterThanEqual = createToken({ name: 'GreaterThanEqual', pattern: />=/ });
+const GreaterThan = createToken({ name: 'GreaterThan', pattern: />/ });
+const Eq = createToken({ name: 'Eq', pattern: /eq/, longer_alt: NCName });
+const Ne = createToken({ name: 'Ne', pattern: /ne/, longer_alt: NCName });
+const Lt = createToken({ name: 'Lt', pattern: /lt/, longer_alt: NCName });
+const Le = createToken({ name: 'Le', pattern: /le/, longer_alt: NCName });
+const Gt = createToken({ name: 'Gt', pattern: /gt/, longer_alt: NCName });
+const Ge = createToken({ name: 'Ge', pattern: /ge/, longer_alt: NCName });
+const Is = createToken({ name: 'Is', pattern: /is/, longer_alt: NCName });
+const DoubleSlash = createToken({ name: 'DoubleSlash', pattern: /\/\// });
+const Slash = createToken({ name: 'Slash', pattern: /\// });
+const DoubleColon = createToken({ name: 'DoubleColon', pattern: /::/ });
+const Colon = createToken({ name: 'Colon', pattern: /:/ });
+const Child = createToken({ name: 'Child', pattern: /child/, longer_alt: NCName });
+const DescendantOrSelf = createToken({ name: 'DescendantOrSelf', pattern: /descendant-or-self/, longer_alt: NCName });
+const Descendant = createToken({ name: 'Descendant', pattern: /descendant/, longer_alt: NCName });
+const Attribute = createToken({ name: 'Attribute', pattern: /attribute/, longer_alt: NCName });
+const Self = createToken({ name: 'Self', pattern: /self/, longer_alt: NCName });
+const FollowingSibling = createToken({ name: 'FollowingSibling', pattern: /following-sibling/, longer_alt: NCName });
+const Following = createToken({ name: 'Following', pattern: /followed-sibling/, longer_alt: NCName });
+const Namespace = createToken({ name: 'Namespace', pattern: /namespace/, longer_alt: NCName });
+const Parent = createToken({ name: 'Parent', pattern: /parent/, longer_alt: NCName });
+const AncestorOrSelf = createToken({ name: 'AncestorOrSelf', pattern: /ancestor-or-self/, longer_alt: NCName });
+const Ancestor = createToken({ name: 'Ancestor', pattern: /ancestor/, longer_alt: NCName });
+const PrecedingSibling = createToken({ name: 'PrecedingSibling', pattern: /preceding-sibling/, longer_alt: NCName });
+const Preceding = createToken({ name: 'Preceding', pattern: /preceding/, longer_alt: NCName });
+const ContextItemExpr = createToken({ name: 'ContextItemExpr', pattern: /\./ });
+const AbbrevReverseStep = createToken({ name: 'AbbrevReverseStep', pattern: /\.\./ });
+const At = createToken({ name: 'At', pattern: /@/ });
+const LSquare = createToken({ name: 'LSquare', pattern: /\[/ });
+const RSquare = createToken({ name: 'RSquare', pattern: /]/ });
+const Question = createToken({ name: 'Question', pattern: /\?/ });
+const Item = createToken({ name: 'Item', pattern: /item/, longer_alt: NCName });
+const Node = createToken({ name: 'Node', pattern: /node/, longer_alt: NCName });
+const DocumentNode = createToken({ name: 'DocumentNode', pattern: /document-node/, longer_alt: NCName });
+const Text = createToken({ name: 'Text', pattern: /text/, longer_alt: NCName });
+const Comment = createToken({ name: 'Comment', pattern: /comment/, longer_alt: NCName });
+const ProcessingInstruction = createToken({
+ name: 'ProcessingInstruction',
+ pattern: /processing-instruction/,
+ longer_alt: NCName,
+});
+const SchemaAttribute = createToken({ name: 'SchemaAttribute', pattern: /schema-attribute/, longer_alt: NCName });
+const Element = createToken({ name: 'Element', pattern: /element/, longer_alt: NCName });
+const SchemaElement = createToken({ name: 'SchemaElement', pattern: /schema-element/, longer_alt: NCName });
+const EmptySequence = createToken({ name: 'EmptySequence', pattern: /empty-sequence/, longer_alt: NCName });
+
+const StringLiteral = createToken({ name: 'StringLiteral', pattern: fragments['StringLiteral'] });
+const IntegerLiteral = createToken({ name: 'IntegerLiteral', pattern: fragments['Digits'] });
+const DecimalLiteral = createToken({ name: 'DecimalLiteral', pattern: fragments['DecimalLiteral'] });
+const DoubleLiteral = createToken({ name: 'DoubleLiteral', pattern: fragments['DoubleLiteral'] });
+
+/** DO NOT CHANGE @see {@link NCName} */
+allTokens.push(NCName);
+
+/**
+ * XPath 2.0 Parser which implements the EBNF defined in the W3C specification
+ * - https://www.w3.org/TR/xpath20/#id-grammar
+ */
+export class XPath2Parser extends CstParser implements XPathParser {
+ static lexer = new Lexer(allTokens);
+
+ constructor() {
+ super(allTokens, {
+ recoveryEnabled: false,
+ maxLookahead: 5,
+ dynamicTokensEnabled: false,
+ outputCst: true,
+ errorMessageProvider: defaultParserErrorProvider,
+ nodeLocationTracking: 'none',
+ traceInitPerf: false,
+ skipValidations: false,
+ } as IParserConfig & { outputCst: boolean });
+ this.performSelfAnalysis();
+ }
+
+ parseXPath(xpath: string): XPathParserResult {
+ const lexResult = XPath2Parser.lexer.tokenize(xpath);
+ this.input = lexResult.tokens;
+ const cst = this.Expr();
+
+ return {
+ cst: cst,
+ lexErrors: lexResult.errors,
+ parseErrors: this.errors,
+ };
+ }
+
+ private Expr = this.RULE('Expr', () => {
+ this.SUBRULE(this.ExprSingle);
+ this.MANY(() => {
+ this.CONSUME(Comma);
+ this.SUBRULE2(this.ExprSingle);
+ });
+ });
+
+ private ExprSingle = this.RULE('ExprSingle', () => {
+ this.OR([
+ { ALT: () => this.SUBRULE(this.ForExpr) },
+ { ALT: () => this.SUBRULE(this.QuantifiedExpr) },
+ { ALT: () => this.SUBRULE(this.IfExpr) },
+ { ALT: () => this.SUBRULE(this.OrExpr) },
+ ]);
+ });
+
+ private ForExpr = this.RULE('ForExpr', () => {
+ this.CONSUME(For);
+ this.SUBRULE(this.VarRef);
+ this.CONSUME(In);
+ this.SUBRULE(this.ExprSingle);
+ this.MANY(() => {
+ this.CONSUME(Comma);
+ this.SUBRULE2(this.VarRef);
+ this.CONSUME2(In);
+ this.SUBRULE2(this.ExprSingle);
+ });
+ this.CONSUME(Return);
+ this.SUBRULE3(this.ExprSingle);
+ });
+
+ private QuantifiedExpr = this.RULE('QuantifiedExpr', () => {
+ this.OR([{ ALT: () => this.CONSUME(Some) }, { ALT: () => this.CONSUME(Every) }]);
+ this.SUBRULE(this.VarRef);
+ this.CONSUME(In);
+ this.SUBRULE(this.ExprSingle);
+ this.MANY(() => {
+ this.CONSUME(Comma);
+ this.SUBRULE2(this.VarRef);
+ this.CONSUME2(In);
+ this.SUBRULE2(this.ExprSingle);
+ });
+ this.CONSUME(Satisfies);
+ this.SUBRULE3(this.ExprSingle);
+ });
+
+ private IfExpr = this.RULE('IfExpr', () => {
+ this.CONSUME(If);
+ this.CONSUME(LParen);
+ this.SUBRULE(this.Expr);
+ this.CONSUME(RParen);
+ this.CONSUME(Then);
+ this.SUBRULE(this.ExprSingle);
+ this.CONSUME(Else);
+ this.SUBRULE2(this.ExprSingle);
+ });
+
+ private OrExpr = this.RULE('OrExpr', () => {
+ this.SUBRULE(this.AndExpr);
+ this.MANY(() => {
+ this.CONSUME(Or);
+ this.SUBRULE2(this.AndExpr);
+ });
+ });
+
+ private AndExpr = this.RULE('AndExpr', () => {
+ this.SUBRULE(this.ComparisonExpr);
+ this.MANY(() => {
+ this.CONSUME(And);
+ this.SUBRULE2(this.ComparisonExpr);
+ });
+ });
+
+ private ComparisonExpr = this.RULE('ComparisonExpr', () => {
+ this.SUBRULE(this.RangeExpr);
+ this.OPTION(() => {
+ this.OR([
+ // ValueComp
+ { ALT: () => this.CONSUME(Eq) },
+ { ALT: () => this.CONSUME(Ne) },
+ { ALT: () => this.CONSUME(Lt) },
+ { ALT: () => this.CONSUME(Le) },
+ { ALT: () => this.CONSUME(Gt) },
+ { ALT: () => this.CONSUME(Ge) },
+ // GeneralComp
+ { ALT: () => this.CONSUME(Equal) },
+ { ALT: () => this.CONSUME(NotEqual) },
+ { ALT: () => this.CONSUME(LessThan) },
+ { ALT: () => this.CONSUME(LessThanEqual) },
+ { ALT: () => this.CONSUME(GreaterThan) },
+ { ALT: () => this.CONSUME(GreaterThanEqual) },
+ // NodeComp
+ { ALT: () => this.CONSUME(Is) },
+ { ALT: () => this.CONSUME2(Precede) },
+ { ALT: () => this.CONSUME(Follow) },
+ { ALT: () => this.SUBRULE2(this.RangeExpr) },
+ ]);
+ });
+ });
+
+ private RangeExpr = this.RULE('RangeExpr', () => {
+ this.SUBRULE(this.AdditiveExpr);
+ this.OPTION(() => {
+ this.CONSUME(To);
+ this.SUBRULE2(this.AdditiveExpr);
+ });
+ });
+
+ private AdditiveExpr = this.RULE('AdditiveExpr', () => {
+ this.SUBRULE(this.MultiplicativeExpr);
+ this.MANY(() => {
+ this.OR([{ ALT: () => this.CONSUME(Plus) }, { ALT: () => this.CONSUME(Minus) }]);
+ this.SUBRULE2(this.MultiplicativeExpr);
+ });
+ });
+
+ private MultiplicativeExpr = this.RULE('MultiplicativeExpr', () => {
+ this.SUBRULE(this.UnionExpr);
+ this.MANY(() => {
+ this.OR([
+ { ALT: () => this.CONSUME(Asterisk) },
+ { ALT: () => this.CONSUME(Div) },
+ { ALT: () => this.CONSUME(Idiv) },
+ { ALT: () => this.CONSUME(Mod) },
+ ]);
+ this.SUBRULE2(this.UnionExpr);
+ });
+ });
+
+ private UnionExpr = this.RULE('UnionExpr', () => {
+ this.SUBRULE(this.IntersectExceptExpr);
+ this.MANY(() => {
+ this.OR([{ ALT: () => this.CONSUME(Union) }, { ALT: () => this.CONSUME(Pipe) }]);
+ this.SUBRULE2(this.IntersectExceptExpr);
+ });
+ });
+
+ private IntersectExceptExpr = this.RULE('IntersectExceptExpr', () => {
+ this.SUBRULE(this.InstanceofExpr);
+ this.MANY(() => {
+ this.OR([{ ALT: () => this.CONSUME(Intersect) }, { ALT: () => this.CONSUME(Except) }]);
+ this.SUBRULE2(this.InstanceofExpr);
+ });
+ });
+
+ private InstanceofExpr = this.RULE('InstanceofExpr', () => {
+ // CastExpr
+ this.MANY(() => {
+ this.OR([{ ALT: () => this.CONSUME(Minus) }, { ALT: () => this.CONSUME(Plus) }]);
+ });
+ this.SUBRULE(this.PathExpr);
+ this.OPTION(() => {
+ this.CONSUME(Cast);
+ this.CONSUME(As);
+ this.SUBRULE(this.SingleType);
+ });
+ // CastableExpr
+ this.OPTION2(() => {
+ this.CONSUME(Castable);
+ this.CONSUME2(As);
+ this.SUBRULE2(this.SingleType);
+ });
+ // TreatExpr
+ this.OPTION3(() => {
+ this.CONSUME(Treat);
+ this.CONSUME3(As);
+ this.SUBRULE3(this.SequenceType);
+ });
+ // InstanceofExpr
+ this.OPTION4(() => {
+ this.CONSUME(Instance);
+ this.CONSUME(Of);
+ this.SUBRULE4(this.SequenceType);
+ });
+ });
+
+ private PathExpr = this.RULE('PathExpr', () => {
+ this.OR([
+ {
+ ALT: () => {
+ this.CONSUME(Slash);
+ this.OPTION(() => this.SUBRULE(this.RelativePathExpr));
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(DoubleSlash);
+ this.SUBRULE2(this.RelativePathExpr);
+ },
+ },
+ { ALT: () => this.SUBRULE3(this.RelativePathExpr) },
+ ]);
+ });
+
+ private ChildPathSegmentExpr = this.RULE('ChildPathSegmentExpr', () => {
+ this.OR([{ ALT: () => this.CONSUME(Slash) }, { ALT: () => this.CONSUME(DoubleSlash) }]);
+ this.SUBRULE2(this.StepExpr);
+ });
+
+ private RelativePathExpr = this.RULE('RelativePathExpr', () => {
+ this.SUBRULE(this.StepExpr);
+ this.MANY(() => this.SUBRULE2(this.ChildPathSegmentExpr));
+ this.OPTION(() => this.CONSUME(Slash));
+ });
+
+ private StepExpr = this.RULE('StepExpr', () => {
+ this.OR([
+ { ALT: () => this.SUBRULE(this.FilterExpr) },
+ {
+ ALT: () => {
+ this.OR2([
+ { ALT: () => this.SUBRULE(this.ReverseStep) },
+ {
+ ALT: () => {
+ // ForwardStep
+ this.OR3([
+ {
+ ALT: () => {
+ // ForwardAxis
+ this.OR4([
+ {
+ ALT: () => {
+ this.CONSUME(Child);
+ this.CONSUME(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(Descendant);
+ this.CONSUME2(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(Attribute);
+ this.CONSUME3(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(Self);
+ this.CONSUME4(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(DescendantOrSelf);
+ this.CONSUME5(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(FollowingSibling);
+ this.CONSUME6(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(Following);
+ this.CONSUME7(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(Namespace);
+ this.CONSUME8(DoubleColon);
+ },
+ },
+ ]);
+ this.SUBRULE(this.NodeTest);
+ },
+ },
+ {
+ ALT: () => {
+ this.OPTION(() => this.CONSUME(At));
+ this.SUBRULE2(this.NodeTest);
+ },
+ },
+ ]);
+ },
+ },
+ ]);
+ this.SUBRULE(this.PredicateList);
+ },
+ },
+ ]);
+ });
+
+ private ReverseStep = this.RULE('ReverseStep', () => {
+ this.OR([
+ {
+ ALT: () => {
+ this.SUBRULE(this.ReverseAxis);
+ this.SUBRULE(this.NodeTest);
+ },
+ },
+ { ALT: () => this.CONSUME(AbbrevReverseStep) },
+ ]);
+ });
+
+ private ReverseAxis = this.RULE('ReverseAxis', () => {
+ this.OR([
+ {
+ ALT: () => {
+ this.CONSUME(Parent);
+ this.CONSUME(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(Ancestor);
+ this.CONSUME2(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(PrecedingSibling);
+ this.CONSUME3(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(Preceding);
+ this.CONSUME4(DoubleColon);
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME(AncestorOrSelf);
+ this.CONSUME5(DoubleColon);
+ },
+ },
+ ]);
+ });
+
+ private NodeTest = this.RULE('NodeTest', () => {
+ this.OR([{ ALT: () => this.SUBRULE(this.KindTest) }, { ALT: () => this.SUBRULE(this.NameTest) }]);
+ });
+
+ private NameTest = this.RULE('NameTest', () => {
+ this.OR([
+ {
+ ALT: () => {
+ this.CONSUME(NCName);
+ this.OPTION(() => {
+ this.CONSUME(Colon);
+ this.OR2([{ ALT: () => this.CONSUME(Asterisk) }, { ALT: () => this.CONSUME2(NCName) }]);
+ });
+ },
+ },
+ {
+ ALT: () => {
+ this.CONSUME2(Asterisk);
+ this.OPTION2(() => {
+ this.CONSUME2(Colon);
+ this.CONSUME3(NCName);
+ });
+ },
+ },
+ ]);
+ });
+
+ private FilterExpr = this.RULE('FilterExpr', () => {
+ this.OR([
+ { ALT: () => this.SUBRULE(this.Literal) },
+ { ALT: () => this.SUBRULE(this.VarRef) },
+ { ALT: () => this.SUBRULE(this.ParenthesizedExpr) },
+ { ALT: () => this.CONSUME(ContextItemExpr) },
+ { ALT: () => this.SUBRULE(this.FunctionCall) },
+ ]);
+ this.SUBRULE(this.PredicateList);
+ });
+
+ private PredicateList = this.RULE('PredicateList', () => {
+ this.MANY(() => {
+ this.CONSUME(LSquare);
+ this.SUBRULE(this.Expr);
+ this.CONSUME(RSquare);
+ });
+ });
+
+ private Literal = this.RULE('Literal', () => {
+ this.OR([{ ALT: () => this.SUBRULE(this.NumericLiteral) }, { ALT: () => this.CONSUME(StringLiteral) }]);
+ });
+
+ private NumericLiteral = this.RULE('NumericLiteral', () => {
+ this.OR([
+ { ALT: () => this.CONSUME(IntegerLiteral) },
+ { ALT: () => this.CONSUME(DecimalLiteral) },
+ { ALT: () => this.CONSUME(DoubleLiteral) },
+ ]);
+ });
+
+ private VarRef = this.RULE('VarRef', () => {
+ this.CONSUME(Dollar);
+ this.SUBRULE(this.QName);
+ });
+
+ private ParenthesizedExpr = this.RULE('ParenthesizedExpr', () => {
+ this.CONSUME(LParen);
+ this.OPTION(() => this.SUBRULE(this.Expr));
+ this.CONSUME(RParen);
+ });
+
+ private FunctionCall = this.RULE('FunctionCall', () => {
+ this.SUBRULE(this.QName);
+ this.CONSUME(LParen);
+ this.OPTION(() => {
+ this.SUBRULE(this.ExprSingle);
+ this.MANY(() => {
+ this.CONSUME(Comma);
+ this.SUBRULE2(this.ExprSingle);
+ });
+ });
+ this.CONSUME(RParen);
+ });
+
+ private SingleType = this.RULE('SingleType', () => {
+ this.SUBRULE(this.QName);
+ this.OPTION(() => this.CONSUME(Question));
+ });
+
+ private SequenceType = this.RULE('SequenceType', () => {
+ this.OR([
+ {
+ ALT: () => {
+ this.CONSUME(EmptySequence);
+ this.CONSUME(LParen);
+ this.CONSUME(RParen);
+ },
+ },
+ {
+ ALT: () => {
+ this.SUBRULE(this.ItemType);
+ this.OPTION(() => this.SUBRULE(this.OccurrenceIndicator));
+ },
+ },
+ ]);
+ });
+
+ private OccurrenceIndicator = this.RULE('OccurrenceIndicator', () => {
+ this.OR([
+ { ALT: () => this.CONSUME(Question) },
+ { ALT: () => this.CONSUME(Asterisk) },
+ { ALT: () => this.CONSUME(Plus) },
+ ]);
+ });
+
+ private ItemType = this.RULE('ItemType', () => {
+ this.OR([
+ { ALT: () => this.SUBRULE(this.KindTest) },
+ {
+ ALT: () => {
+ this.CONSUME(Item);
+ this.CONSUME(LParen);
+ this.CONSUME(RParen);
+ },
+ },
+ { ALT: () => this.SUBRULE(this.QName) },
+ ]);
+ });
+
+ private KindTest = this.RULE('KindTest', () => {
+ this.OR([
+ { ALT: () => this.SUBRULE(this.DocumentTest) },
+ { ALT: () => this.SUBRULE(this.ElementTest) },
+ { ALT: () => this.SUBRULE(this.AttributeTest) },
+ { ALT: () => this.SUBRULE(this.SchemaElementTest) },
+ { ALT: () => this.SUBRULE(this.SchemaAttributeTest) },
+ { ALT: () => this.SUBRULE(this.PITest) },
+ { ALT: () => this.SUBRULE(this.CommentTest) },
+ { ALT: () => this.SUBRULE(this.TextTest) },
+ { ALT: () => this.SUBRULE(this.AnyKindTest) },
+ ]);
+ });
+
+ private AnyKindTest = this.RULE('AnyKindTest', () => {
+ this.CONSUME(Node);
+ this.CONSUME(LParen);
+ this.CONSUME(RParen);
+ });
+
+ private DocumentTest = this.RULE('DocumentTest', () => {
+ this.CONSUME(DocumentNode);
+ this.CONSUME(LParen);
+ this.OPTION(() => {
+ this.OR([{ ALT: () => this.SUBRULE(this.ElementTest) }, { ALT: () => this.SUBRULE(this.SchemaElementTest) }]);
+ });
+ this.CONSUME(RParen);
+ });
+
+ private TextTest = this.RULE('TextTest', () => {
+ this.CONSUME(Text);
+ this.CONSUME(LParen);
+ this.CONSUME(RParen);
+ });
+
+ private CommentTest = this.RULE('CommentTest', () => {
+ this.CONSUME(Comment);
+ this.CONSUME(LParen);
+ this.CONSUME(RParen);
+ });
+
+ private PITest = this.RULE('PITest', () => {
+ this.CONSUME(ProcessingInstruction);
+ this.CONSUME(LParen);
+ this.OPTION(() => {
+ this.OR([{ ALT: () => this.CONSUME(NCName) }, { ALT: () => this.CONSUME(StringLiteral) }]);
+ });
+ this.CONSUME(RParen);
+ });
+
+ private AttributeTest = this.RULE('AttributeTest', () => {
+ this.CONSUME(Attribute);
+ this.CONSUME(LParen);
+ this.OPTION(() => {
+ this.SUBRULE(this.AttribNameOrWildcard);
+ this.OPTION2(() => {
+ this.CONSUME(Comma);
+ this.SUBRULE(this.QName);
+ });
+ });
+ this.CONSUME(RParen);
+ });
+
+ private AttribNameOrWildcard = this.RULE('AttribNameOrWildcard', () => {
+ this.OR([{ ALT: () => this.SUBRULE(this.QName) }, { ALT: () => this.CONSUME(Asterisk) }]);
+ });
+
+ private SchemaAttributeTest = this.RULE('SchemaAttributeTest', () => {
+ this.CONSUME(SchemaAttribute);
+ this.CONSUME(LParen);
+ this.SUBRULE(this.QName);
+ this.CONSUME(RParen);
+ });
+
+ private ElementTest = this.RULE('ElementTest', () => {
+ this.CONSUME(Element);
+ this.CONSUME(LParen);
+ this.OPTION(() => {
+ this.SUBRULE(this.ElementNameOrWildcard);
+ this.OPTION2(() => {
+ this.CONSUME(Comma);
+ this.SUBRULE(this.QName);
+ this.OPTION3(() => this.CONSUME(Question));
+ });
+ });
+ this.CONSUME(RParen);
+ });
+
+ private ElementNameOrWildcard = this.RULE('ElementNameOrWildcard', () => {
+ this.OR([{ ALT: () => this.SUBRULE(this.QName) }, { ALT: () => this.CONSUME(Asterisk) }]);
+ });
+
+ private SchemaElementTest = this.RULE('SchemaElementTest', () => {
+ this.CONSUME(SchemaElement);
+ this.CONSUME(LParen);
+ this.SUBRULE(this.QName);
+ this.CONSUME(RParen);
+ });
+
+ private QName = this.RULE('QName', () => {
+ this.OPTION(() => {
+ this.CONSUME(NCName);
+ this.CONSUME(Colon);
+ });
+ this.CONSUME2(NCName);
+ });
+}
diff --git a/packages/ui/src/services/xpath/monaco-language.ts b/packages/ui/src/services/xpath/monaco-language.ts
new file mode 100644
index 000000000..574077ee5
--- /dev/null
+++ b/packages/ui/src/services/xpath/monaco-language.ts
@@ -0,0 +1,79 @@
+import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
+
+export const xpathLanguageID = 'xpath';
+
+type MonacoXPathLanguageMetadata = monaco.languages.ILanguageExtensionPoint & {
+ languageConfiguration: monaco.languages.LanguageConfiguration;
+ tokensProvider: monaco.languages.IMonarchLanguage;
+ completionItemProvider: monaco.languages.CompletionItemProvider;
+};
+
+const keywords = [
+ 'if',
+ 'for',
+ 'idiv',
+ 'div',
+ 'mod',
+ 'eq',
+ 'ne',
+ 'gt',
+ 'lt',
+ 'ge',
+ 'le',
+ 'is',
+ 'union',
+ 'intersect',
+ 'except',
+ 'to',
+];
+
+const operators = ['+', '-', '*', '<<', '>>', '|', ','];
+
+export const monacoXPathLanguageMetadata: MonacoXPathLanguageMetadata = {
+ id: xpathLanguageID,
+ languageConfiguration: {
+ brackets: [
+ ['[', ']'],
+ ['(', ')'],
+ ],
+ autoClosingPairs: [
+ { open: '[', close: ']' },
+ { open: '(', close: ')' },
+ ],
+ },
+ tokensProvider: {
+ keywords: keywords,
+ operators: operators,
+ tokenizer: {
+ root: [],
+ },
+ },
+
+ completionItemProvider: {
+ provideCompletionItems: (
+ model: monaco.editor.ITextModel,
+ position: monaco.Position,
+ _context: monaco.languages.CompletionContext,
+ _token: monaco.CancellationToken,
+ ): monaco.languages.ProviderResult => {
+ const suggestions = [
+ ...keywords.map((k) => {
+ const word = model.getWordUntilPosition(position);
+ const range: monaco.IRange = {
+ startLineNumber: position.lineNumber,
+ endLineNumber: position.lineNumber,
+ startColumn: word.startColumn,
+ endColumn: word.endColumn,
+ };
+ return {
+ label: k,
+ kind: monaco.languages.CompletionItemKind.Keyword,
+ insertText: k,
+ range: range,
+ };
+ }),
+ ];
+ return { suggestions: suggestions };
+ },
+ },
+};
diff --git a/packages/ui/src/services/xpath/xpath-parser.ts b/packages/ui/src/services/xpath/xpath-parser.ts
new file mode 100644
index 000000000..07db44e22
--- /dev/null
+++ b/packages/ui/src/services/xpath/xpath-parser.ts
@@ -0,0 +1,24 @@
+import type { CstNode, ILexingError, IRecognitionException } from 'chevrotain';
+
+export interface XPathParserResult {
+ cst: CstNode;
+ lexErrors: ILexingError[];
+ parseErrors: IRecognitionException[];
+}
+
+export interface XPathParser {
+ parseXPath(xpath: string): XPathParserResult;
+}
+
+export enum FunctionGroup {
+ String = 'String',
+ SubstringMatching = 'Substring Matching',
+ PatternMatching = 'Pattern Matching',
+ Numeric = 'Numeric',
+ DateAndTime = 'Date and Time',
+ Boolean = 'Boolean',
+ QName = 'QName',
+ Node = 'Node',
+ Sequence = 'Sequence',
+ Context = 'Context',
+}
diff --git a/packages/ui/src/services/xpath/xpath.service.test.ts b/packages/ui/src/services/xpath/xpath.service.test.ts
new file mode 100644
index 000000000..4c06dbe41
--- /dev/null
+++ b/packages/ui/src/services/xpath/xpath.service.test.ts
@@ -0,0 +1,125 @@
+import { XPathService } from './xpath.service';
+import { createSyntaxDiagramsCode } from 'chevrotain';
+import * as fs from 'fs';
+import { IFunctionDefinition } from '../../models/datamapper/mapping';
+import { FunctionGroup } from './xpath-parser';
+
+describe('XPathService', () => {
+ it('Generate Syntax Diagram', () => {
+ const gastProd = XPathService.parser.getSerializedGastProductions();
+ const html = createSyntaxDiagramsCode(gastProd);
+ fs.writeFileSync('dist/syntax-diagram.html', html);
+ });
+
+ describe('parse()', () => {
+ it('should parse a field path', () => {
+ const result = XPathService.parse('/aaa/bbb/ccc');
+ expect(result.cst).toBeDefined();
+ });
+
+ it('should parse a field which contains a reserved word in its spelling', () => {
+ let result = XPathService.parse('/shiporder/orderperson');
+ expect(result.lexErrors.length).toEqual(0);
+ expect(result.parseErrors.length).toEqual(0);
+ expect(result.cst).toBeDefined();
+ result = XPathService.parse('/shiporder/orderperson/');
+ expect(result.lexErrors.length).toEqual(0);
+ expect(result.parseErrors.length).toEqual(0);
+ expect(result.cst).toBeDefined();
+ result = XPathService.parse('/from/me/to/you');
+ expect(result.lexErrors.length).toEqual(0);
+ expect(result.parseErrors.length).toEqual(0);
+ expect(result.cst).toBeDefined();
+ });
+
+ it('should parse xpath with string literal', () => {
+ const result = XPathService.parse("'Hello', /shiporder/orderperson, '!'");
+ expect(result.lexErrors.length).toEqual(0);
+ expect(result.parseErrors.length).toEqual(0);
+ expect(result.cst).toBeDefined();
+ });
+ });
+
+ describe('validate()', () => {
+ it('should detect parse error', () => {
+ const result = XPathService.validate('((');
+ expect(result.hasErrors()).toBeTruthy();
+ });
+
+ it('should validate with empty string literal', () => {
+ const result = XPathService.validate("/ns0:ShipOrder/ns0:OrderPerson != ''");
+ // TODO parser error says it's redundant, possibly a bug in the parser
+ expect(result.hasErrors()).toBeTruthy();
+ expect(result.getCst()).toBeDefined();
+ });
+
+ it('should not get error with valid parenthesis', () => {
+ let result = XPathService.validate('(/Hello)');
+ expect(result.hasErrors()).toBeFalsy();
+ result = XPathService.validate('((/Hello))');
+ expect(result.hasErrors()).toBeFalsy();
+ });
+
+ it('should not get error with empty parenthesis', () => {
+ let result = XPathService.validate('()');
+ expect(result.hasErrors()).toBeFalsy();
+ result = XPathService.validate('(())');
+ expect(result.hasErrors()).toBeFalsy();
+ });
+
+ it('should not get error with empty function call', () => {
+ const result = XPathService.validate('upper-case()');
+ expect(result.hasErrors()).toBeFalsy();
+ });
+ });
+
+ describe('extractFieldPaths()', () => {
+ it('extract field', () => {
+ const paths = XPathService.extractFieldPaths('/aaa/bbb/ccc');
+ expect(paths.length).toEqual(1);
+ expect(paths[0]).toEqual('/aaa/bbb/ccc');
+ });
+
+ it('extract param field', () => {
+ const paths = XPathService.extractFieldPaths('$param1/aaa/bbb/ccc');
+ expect(paths.length).toEqual(1);
+ expect(paths[0]).toEqual('$param1/aaa/bbb/ccc');
+ });
+
+ it('extract fields from function calls', () => {
+ const paths = XPathService.extractFieldPaths(
+ 'concatenate(/aaa/bbb/ccc, upper-case(aaa/bbb/ddd), lower-case($param1/eee/fff))',
+ );
+ expect(paths.length).toEqual(3);
+ expect(paths[0]).toEqual('/aaa/bbb/ccc');
+ expect(paths[1]).toEqual('aaa/bbb/ddd');
+ expect(paths[2]).toEqual('$param1/eee/fff');
+ });
+
+ it('extract primitive source body', () => {
+ const paths = XPathService.extractFieldPaths('.');
+ expect(paths.length).toEqual(1);
+ expect(paths[0]).toEqual('/');
+ });
+ });
+
+ it('getXPathFunctionDefinitions()', () => {
+ const functionDefs = XPathService.getXPathFunctionDefinitions();
+ expect(Object.keys(functionDefs).length).toBeGreaterThan(9);
+ });
+
+ it('getXPathFunctionNames()', () => {
+ const functionDefs = XPathService.getXPathFunctionDefinitions();
+ const flattened = Object.keys(functionDefs).reduce((acc, value) => {
+ acc.push(...functionDefs[value as FunctionGroup]);
+ return acc;
+ }, [] as IFunctionDefinition[]);
+ const functionNames = XPathService.getXPathFunctionNames();
+ expect(functionNames.length).toEqual(flattened.length);
+ });
+
+ it('getMonacoXPathLanguageMetadata()', () => {
+ const metadata = XPathService.getMonacoXPathLanguageMetadata();
+ expect(metadata.id).toEqual('xpath');
+ });
+});
diff --git a/packages/ui/src/services/xpath/xpath.service.ts b/packages/ui/src/services/xpath/xpath.service.ts
new file mode 100644
index 000000000..76f5b15f4
--- /dev/null
+++ b/packages/ui/src/services/xpath/xpath.service.ts
@@ -0,0 +1,224 @@
+import { XPath2Parser } from './2.0/xpath-2.0-parser';
+import { FunctionGroup, XPathParserResult } from './xpath-parser';
+import { IFunctionDefinition } from '../../models/datamapper/mapping';
+import { XPATH_2_0_FUNCTIONS } from './2.0/xpath-2.0-functions';
+import { monacoXPathLanguageMetadata } from './monaco-language';
+import { CstElement, CstNode } from 'chevrotain';
+import { IField, PrimitiveDocument } from '../../models/datamapper/document';
+import { DocumentService } from '../document.service';
+import { DocumentType } from '../../models/datamapper/path';
+
+export class ValidatedXPathParseResult {
+ constructor(public parserResult?: XPathParserResult) {}
+ dataMapperErrors: string[] = [];
+ warnings: string[] = [];
+
+ hasErrors(): boolean {
+ return (
+ (this.parserResult && this.parserResult.lexErrors.length > 0) ||
+ (this.parserResult && this.parserResult?.parseErrors.length > 0) ||
+ this.dataMapperErrors.length > 0
+ );
+ }
+
+ getErrors(): string[] {
+ const answer = [];
+ if (this.parserResult) {
+ answer.push(...this.parserResult.lexErrors.map((e) => e.message));
+ answer.push(...this.parserResult.parseErrors.map((e) => e.message));
+ }
+ answer.push(...this.dataMapperErrors);
+ return answer;
+ }
+
+ hasWarnings(): boolean {
+ return this.warnings.length > 0;
+ }
+
+ getWarnings(): string[] {
+ return this.warnings;
+ }
+
+ getCst(): CstNode | undefined {
+ return this.parserResult?.cst;
+ }
+}
+
+export class XPathService {
+ static parser = new XPath2Parser();
+ static functions = XPATH_2_0_FUNCTIONS;
+
+ static parse(xpath: string): XPathParserResult {
+ return XPathService.parser.parseXPath(xpath);
+ }
+
+ static validate(xpath: string): ValidatedXPathParseResult {
+ if (!xpath) {
+ const answer = new ValidatedXPathParseResult();
+ answer.warnings.push('Empty Expression');
+ return answer;
+ }
+ const parserResult = XPathService.parse(xpath);
+ const validationResult = new ValidatedXPathParseResult(parserResult);
+ if (!validationResult.getCst()) return validationResult;
+
+ try {
+ XPathService.extractFieldPaths(xpath);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (error: any) {
+ const errorString =
+ 'DataMapper internal error: failed to render a mapping line from a valid XPath expression: ' +
+ ('message' in error ? error.message : error.toString());
+ validationResult.dataMapperErrors.push(errorString);
+ }
+ return validationResult;
+ }
+
+ static getXPathFunctionDefinitions(): Record {
+ return XPathService.functions;
+ }
+
+ static getXPathFunctionNames(): string[] {
+ return Object.values(XPathService.getXPathFunctionDefinitions()).reduce((acc, functions) => {
+ acc.push(...functions.map((f) => f.name));
+ return acc;
+ }, [] as string[]);
+ }
+
+ static getMonacoXPathLanguageMetadata() {
+ monacoXPathLanguageMetadata.tokensProvider.actions = XPathService.getXPathFunctionNames();
+ return monacoXPathLanguageMetadata;
+ }
+
+ static getNode(node: CstElement, paths: string[]) {
+ let answer: CstElement = node;
+ for (const path of paths) {
+ if (!('children' in answer) || !answer.children[path]) return undefined;
+ answer = answer.children[path][0];
+ }
+ return answer;
+ }
+
+ private static pathExprToString(node: CstNode) {
+ let answer = 'Slash' in node.children ? '/' : 'DoubleSlash' in node.children ? '//' : '';
+ if (!('children' in node.children.RelativePathExpr[0])) return answer;
+ const relativePathExpr = XPathService.getNode(node, ['RelativePathExpr']);
+ if (!relativePathExpr) return answer;
+ const stepExpr = XPathService.getNode(relativePathExpr, ['StepExpr']);
+ if (!stepExpr) return answer;
+ const varName = XPathService.getNode(stepExpr, ['FilterExpr', 'VarRef', 'QName', 'NCName']);
+ const contextItem = XPathService.getNode(stepExpr, ['FilterExpr', 'ContextItemExpr']);
+ const name = XPathService.extractNameFromStepExpr(stepExpr);
+ if (varName && 'image' in varName) {
+ answer += '$' + varName.image;
+ } else if (contextItem && 'image' in contextItem) {
+ answer += contextItem.image;
+ } else if (name) {
+ answer += name;
+ } else {
+ throw Error('Unknown RelativePathExpr: ' + relativePathExpr);
+ }
+ const following =
+ relativePathExpr && 'children' in relativePathExpr && relativePathExpr.children.ChildPathSegmentExpr;
+ return following
+ ? following.reduce((acc, value) => {
+ acc += '/';
+ const stepExpr = XPathService.getNode(value, ['StepExpr']);
+ const name = stepExpr && XPathService.extractNameFromStepExpr(stepExpr);
+ if (name) acc += name;
+ return acc;
+ }, answer)
+ : answer;
+ }
+
+ private static extractNameFromStepExpr(stepExpr: CstElement) {
+ const isAttribute = !!('children' in stepExpr && stepExpr.children['At']);
+ const nameTest = XPathService.getNode(stepExpr, ['NodeTest', 'NameTest']);
+ if (!nameTest || !('children' in nameTest)) return;
+ const ncNames = nameTest.children['NCName'];
+ const colon = nameTest.children['Colon'];
+ let answer = isAttribute ? '@' : '';
+ if (ncNames.length === 1 && (!colon || colon.length === 0) && 'image' in ncNames[0]) answer += ncNames[0].image;
+ else if (ncNames.length === 2 && colon?.length === 1 && 'image' in ncNames[0] && 'image' in ncNames[1])
+ answer += `${ncNames[0].image}:${ncNames[1].image}`;
+ return answer;
+ }
+
+ static extractFieldPaths(expression: string): string[] {
+ const parsed = XPathService.parse(expression);
+ if (!parsed.cst) return [];
+ const paths = XPathService.collectPathExpressions(parsed.cst);
+ return paths.reduce((acc, node) => {
+ if ('children' in node) {
+ acc.push(XPathService.pathExprToString(node));
+ } else if ('image' in node && node.image === '.') {
+ acc.push('/');
+ }
+ return acc;
+ }, [] as string[]);
+ }
+
+ private static collectPathExpressions(node: CstNode) {
+ const answer: CstElement[] = [];
+ if (node.name === 'PathExpr') {
+ answer.push(...XPathService.extractPathExprNode(node));
+ return answer;
+ }
+ return Object.entries(node.children).reduce((acc, [key, value]) => {
+ if (key === 'PathExpr') {
+ acc.push(...XPathService.extractPathExprNode(value[0] as CstNode));
+ } else {
+ value.forEach((child) => {
+ if ('children' in child) {
+ acc.push(...XPathService.collectPathExpressions(child));
+ }
+ });
+ }
+ return acc;
+ }, [] as CstElement[]);
+ }
+
+ private static extractPathExprNode(pathExprNode: CstNode): CstElement[] {
+ const filterExpr = XPathService.getNode(pathExprNode, ['RelativePathExpr', 'StepExpr', 'FilterExpr']);
+ if (!filterExpr) return [pathExprNode];
+
+ const literal = XPathService.getNode(filterExpr, ['Literal']);
+ if (literal) return [];
+
+ const contextItemExpr = XPathService.getNode(filterExpr, ['ContextItemExpr']);
+ if (contextItemExpr) return [contextItemExpr];
+
+ // Extract contents in parenthesis
+ const parenthesizedExpr = XPathService.getNode(filterExpr, ['ParenthesizedExpr']);
+ if (parenthesizedExpr && 'children' in parenthesizedExpr) {
+ const expr = parenthesizedExpr.children['Expr'];
+ return expr && expr.length > 0 ? XPathService.collectPathExpressions(expr[0] as CstNode) : [];
+ }
+
+ // Extract arguments in FunctionCall
+ const functionCall = XPathService.getNode(filterExpr, ['FunctionCall']);
+ if (functionCall && 'children' in functionCall) {
+ return functionCall.children.ExprSingle
+ ? functionCall.children.ExprSingle.flatMap((arg) =>
+ 'children' in arg ? XPathService.collectPathExpressions(arg) : [],
+ )
+ : [];
+ }
+
+ return [pathExprNode];
+ }
+
+ static addSource(expression: string, source: string): string {
+ return expression ? `${expression}, ${source}` : source;
+ }
+
+ static toXPath(source: PrimitiveDocument | IField, namespaceMap: { [prefix: string]: string }): string {
+ const doc = source.ownerDocument;
+ const prefix = doc.documentType === DocumentType.PARAM ? `$${doc.documentId}` : '';
+ const xpath = DocumentService.getFieldStack(source, true).reduceRight(
+ (acc, field) => acc + `/${DocumentService.getFieldExpressionNS(field, namespaceMap)}`,
+ prefix,
+ );
+ return xpath ? xpath : '.';
+ }
+}
diff --git a/packages/ui/src/stubs/BrowserFilePickerMetadataProvider.tsx b/packages/ui/src/stubs/BrowserFilePickerMetadataProvider.tsx
new file mode 100644
index 000000000..1ecffb255
--- /dev/null
+++ b/packages/ui/src/stubs/BrowserFilePickerMetadataProvider.tsx
@@ -0,0 +1,73 @@
+import { ChangeEvent, createRef, FunctionComponent, PropsWithChildren, useCallback, useRef } from 'react';
+import { readFileAsString } from './read-file-as-string';
+import { IMetadataApi, MetadataContext } from '../providers';
+
+export const BrowserFilePickerMetadataProvider: FunctionComponent = (props) => {
+ const fileInputRef = createRef();
+ const fileSelectionRef = useRef<{
+ resolve: (files: Record) => void;
+ reject: (error: unknown) => unknown;
+ }>();
+ const fileContentsRef = useRef>();
+
+ const askUserForFileSelection = useCallback(
+ (
+ _include: string,
+ _exclude?: string,
+ _options?: Record,
+ ): Promise => {
+ fileInputRef.current?.click();
+ return new Promise>((resolve, reject) => {
+ fileSelectionRef.current = { resolve, reject };
+ }).then((files) => {
+ fileContentsRef.current = files;
+ return Object.keys(files);
+ });
+ },
+ [fileInputRef],
+ );
+
+ const onImport = useCallback(async (event: ChangeEvent) => {
+ const schemaFiles = event.target.files;
+ if (!schemaFiles) return;
+ const fileContents: Record = {};
+ const fileContentPromises: Promise[] = [];
+ Array.from(schemaFiles).forEach((f) => {
+ const promise = readFileAsString(f).then((content) => (fileContents[f.name] = content));
+ fileContentPromises.push(promise);
+ });
+ await Promise.allSettled(fileContentPromises);
+
+ fileSelectionRef.current?.resolve(fileContents);
+ fileSelectionRef.current = undefined;
+ event.target.value = '';
+ }, []);
+
+ const getResourceContent = useCallback((path: string) => {
+ return Promise.resolve(fileContentsRef.current && fileContentsRef.current[path]);
+ }, []);
+
+ const metadataApi: IMetadataApi = {
+ askUserForFileSelection: askUserForFileSelection,
+ getResourceContent: getResourceContent,
+ shouldSaveSchema: true,
+ getMetadata: () => Promise.resolve(undefined),
+ setMetadata: () => Promise.resolve(),
+ deleteResource: () => Promise.resolve(true),
+ saveResourceContent: () => Promise.resolve(),
+ };
+
+ return (
+
+ {props.children}
+
+
+ );
+};
diff --git a/packages/ui/src/stubs/data-mapper.ts b/packages/ui/src/stubs/data-mapper.ts
new file mode 100644
index 000000000..ae0948deb
--- /dev/null
+++ b/packages/ui/src/stubs/data-mapper.ts
@@ -0,0 +1,73 @@
+import { parse } from 'yaml';
+import { DATAMAPPER_ID_PREFIX, XSLT_COMPONENT_NAME } from '../utils';
+import fs from 'fs';
+import { XmlSchemaDocumentService } from '../services/xml-schema-document.service';
+import { DocumentType } from '../models/datamapper/path';
+import { IDocument, PrimitiveDocument } from '../models/datamapper/document';
+
+export const datamapperRouteDefinitionStub = parse(`
+ from:
+ id: from-8888
+ uri: direct:start
+ parameters: {}
+ steps:
+ - step:
+ id: ${DATAMAPPER_ID_PREFIX}-1234
+ steps:
+ - to:
+ uri: ${XSLT_COMPONENT_NAME}:transform.xsl`);
+
+export const shipOrderXsd = fs
+ .readFileSync(__dirname + '/../../../xml-schema-ts/test-resources/ShipOrder.xsd')
+ .toString();
+export const testDocumentXsd = fs
+ .readFileSync(__dirname + '/../../../xml-schema-ts/test-resources/TestDocument.xsd')
+ .toString();
+export const noTopElementXsd = fs
+ .readFileSync(__dirname + '/../../../xml-schema-ts/test-resources/NoTopElement.xsd')
+ .toString();
+export const camelSpringXsd = fs
+ .readFileSync(__dirname + '/../../../xml-schema-ts/test-resources/camel-spring.xsd')
+ .toString();
+export const shipOrderToShipOrderXslt = fs
+ .readFileSync(__dirname + '/../../../xml-schema-ts/test-resources/ShipOrderToShipOrder.xsl')
+ .toString();
+export const shipOrderToShipOrderInvalidForEachXslt = fs
+ .readFileSync(__dirname + '/../../../xml-schema-ts/test-resources/ShipOrderToShipOrderInvalidForEach.xsl')
+ .toString();
+export const shipOrderEmptyFirstLineXsd = fs
+ .readFileSync(__dirname + '/../../../xml-schema-ts/test-resources/ShipOrderEmptyFirstLine.xsd')
+ .toString();
+
+export class TestUtil {
+ static createSourceOrderDoc() {
+ return XmlSchemaDocumentService.createXmlSchemaDocument(DocumentType.SOURCE_BODY, 'ShipOrder.xsd', shipOrderXsd);
+ }
+
+ static createCamelSpringXsdSourceDoc() {
+ return XmlSchemaDocumentService.createXmlSchemaDocument(
+ DocumentType.SOURCE_BODY,
+ 'camel-spring.xsd',
+ camelSpringXsd,
+ );
+ }
+
+ static createTargetOrderDoc() {
+ return XmlSchemaDocumentService.createXmlSchemaDocument(DocumentType.TARGET_BODY, 'ShipOrder.xsd', shipOrderXsd);
+ }
+
+ static createParamOrderDoc(name: string) {
+ const answer = XmlSchemaDocumentService.createXmlSchemaDocument(DocumentType.PARAM, name, shipOrderXsd);
+ answer.name = name;
+ return answer;
+ }
+
+ static createParameterMap() {
+ const sourceParamDoc = TestUtil.createParamOrderDoc('sourceParam1');
+ const sourcePrimitiveParamDoc = new PrimitiveDocument(DocumentType.PARAM, 'primitive');
+ return new Map([
+ ['sourceParam1', sourceParamDoc],
+ ['primitive', sourcePrimitiveParamDoc],
+ ]);
+ }
+}
diff --git a/packages/ui/src/stubs/read-file-as-string.test.ts b/packages/ui/src/stubs/read-file-as-string.test.ts
new file mode 100644
index 000000000..fc8bc777c
--- /dev/null
+++ b/packages/ui/src/stubs/read-file-as-string.test.ts
@@ -0,0 +1,11 @@
+import { readFileAsString } from './read-file-as-string';
+
+describe('readFileAsString()', () => {
+ it('should read', async () => {
+ const file = new File(['foo'], 'foo.txt', {
+ type: 'text/plain',
+ });
+ const answer = await readFileAsString(file);
+ expect(answer).toEqual('foo');
+ });
+});
diff --git a/packages/ui/src/stubs/read-file-as-string.ts b/packages/ui/src/stubs/read-file-as-string.ts
new file mode 100644
index 000000000..b9dfa4178
--- /dev/null
+++ b/packages/ui/src/stubs/read-file-as-string.ts
@@ -0,0 +1,9 @@
+export const readFileAsString = (file: File): Promise => {
+ const reader = new FileReader();
+ return new Promise((resolve, reject) => {
+ reader.onload = (e) => {
+ e.target ? resolve(e.target.result as string) : reject();
+ };
+ reader.readAsText(file);
+ });
+};
diff --git a/packages/ui/src/styles/_dnd.scss b/packages/ui/src/styles/_dnd.scss
new file mode 100644
index 000000000..5ea517ed9
--- /dev/null
+++ b/packages/ui/src/styles/_dnd.scss
@@ -0,0 +1,7 @@
+@mixin cursor-grab {
+ cursor: grab;
+
+ &:active {
+ cursor: grabbing;
+ }
+}
diff --git a/packages/ui/src/testing-api.ts b/packages/ui/src/testing-api.ts
index 689906ee2..4737f6bb1 100644
--- a/packages/ui/src/testing-api.ts
+++ b/packages/ui/src/testing-api.ts
@@ -5,6 +5,8 @@ export * from './models/camel';
export * from './providers';
export * from './utils';
export * from './stubs';
+export * from './components/DataMapper/debug';
+export * from './models/datamapper';
export type { EntitiesContextResult } from './hooks/entities';
export * from './components/Visualization/Canvas/controller.service';
diff --git a/packages/ui/src/utils/index.ts b/packages/ui/src/utils/index.ts
index 28917305a..7a05172ed 100644
--- a/packages/ui/src/utils/index.ts
+++ b/packages/ui/src/utils/index.ts
@@ -11,8 +11,11 @@ export * from './get-user-updated-properties-schema';
export * from './get-value';
export * from './get-viznodes-from-graph';
export * from './init-visible-flows';
+export * from './is-datamapper';
export * from './is-defined';
export * from './is-enum-type';
+export * from './is-to-processor';
+export * from './is-xslt-component';
export * from './join-path';
export * from './node-icon-resolver';
export * from './pipe-custom-schema';
diff --git a/packages/ui/src/utils/is-datamapper.test.ts b/packages/ui/src/utils/is-datamapper.test.ts
new file mode 100644
index 000000000..d86dc2c45
--- /dev/null
+++ b/packages/ui/src/utils/is-datamapper.test.ts
@@ -0,0 +1,30 @@
+import { Step } from '@kaoto/camel-catalog/types';
+import { datamapperRouteDefinitionStub } from '../stubs/data-mapper';
+import { isDataMapperNode } from './is-datamapper';
+
+describe('isDataMapperNode', () => {
+ it('should return true if it has the right id and a xslt component', () => {
+ const stepDefinition = datamapperRouteDefinitionStub.from.steps[0].step as Step;
+ const result = isDataMapperNode(stepDefinition);
+
+ expect(result).toBe(true);
+ });
+
+ it('should return false if it has the right id but no xslt component', () => {
+ const stepDefinition = datamapperRouteDefinitionStub.from.steps[0].step as Step;
+ stepDefinition.steps![0].to = { uri: 'direct:log' };
+
+ const result = isDataMapperNode(stepDefinition);
+
+ expect(result).toBe(false);
+ });
+
+ it('should return false if it has no id but a xslt component', () => {
+ const stepDefinition = datamapperRouteDefinitionStub.from.steps[0].step as Step;
+ stepDefinition.id = 'step-1234';
+
+ const result = isDataMapperNode(stepDefinition);
+
+ expect(result).toBe(false);
+ });
+});
diff --git a/packages/ui/src/utils/is-datamapper.ts b/packages/ui/src/utils/is-datamapper.ts
new file mode 100644
index 000000000..dc9f55c10
--- /dev/null
+++ b/packages/ui/src/utils/is-datamapper.ts
@@ -0,0 +1,18 @@
+import { ProcessorDefinition, Step } from '@kaoto/camel-catalog/types';
+
+export const DATAMAPPER_ID_PREFIX = 'kaoto-datamapper' as keyof ProcessorDefinition;
+export const XSLT_COMPONENT_NAME = 'xslt-saxon';
+
+export const isDataMapperNode = (stepDefinition: Step): stepDefinition is Step => {
+ const isDatamapperId = stepDefinition.id?.startsWith(DATAMAPPER_ID_PREFIX) ?? false;
+ const doesContainXslt =
+ stepDefinition.steps?.some((step) => {
+ if (typeof step.to === 'string') {
+ return step.to.startsWith(XSLT_COMPONENT_NAME);
+ }
+
+ return step.to?.uri?.startsWith(XSLT_COMPONENT_NAME);
+ }) ?? false;
+
+ return isDatamapperId && doesContainXslt;
+};
diff --git a/packages/ui/src/utils/is-to-processor.test.ts b/packages/ui/src/utils/is-to-processor.test.ts
new file mode 100644
index 000000000..88bffc814
--- /dev/null
+++ b/packages/ui/src/utils/is-to-processor.test.ts
@@ -0,0 +1,13 @@
+import { isToProcessor } from './is-to-processor';
+
+describe('isToProcessor', () => {
+ it.each([
+ [false, { to: 'mock' }],
+ [false, { toD: 'mock' }],
+ [false, {}],
+ [true, { to: { uri: undefined } }],
+ [true, { to: { uri: 'timer:myTimer' } }],
+ ] as const)('should return %s when toDefinition is %s', (result, toDefinition) => {
+ expect(isToProcessor(toDefinition)).toBe(result);
+ });
+});
diff --git a/packages/ui/src/utils/is-to-processor.ts b/packages/ui/src/utils/is-to-processor.ts
new file mode 100644
index 000000000..6efaa6cd2
--- /dev/null
+++ b/packages/ui/src/utils/is-to-processor.ts
@@ -0,0 +1,11 @@
+import { ProcessorDefinition, To } from '@kaoto/camel-catalog/types';
+import { isDefined } from './is-defined';
+
+export type ToObjectDef = { to: Exclude };
+
+export const isToProcessor = (toDefinition: ProcessorDefinition): toDefinition is ToObjectDef => {
+ const doesHaveTo = 'to' in toDefinition;
+ const isStringBased = typeof toDefinition.to === 'string';
+
+ return doesHaveTo && !isStringBased && isDefined(toDefinition.to);
+};
diff --git a/packages/ui/src/utils/is-xslt-component.test.ts b/packages/ui/src/utils/is-xslt-component.test.ts
new file mode 100644
index 000000000..e3be469f8
--- /dev/null
+++ b/packages/ui/src/utils/is-xslt-component.test.ts
@@ -0,0 +1,16 @@
+import { XSLT_COMPONENT_NAME } from './is-datamapper';
+import { isXSLTComponent } from './is-xslt-component';
+
+describe('isXSLTComponent', () => {
+ it.each([
+ [false, { to: 'mock' }],
+ [false, { toD: 'mock' }],
+ [false, {}],
+ [false, { to: { uri: undefined } }],
+ [false, { to: { uri: 'timer:myTimer' } }],
+ [true, { to: { uri: `${XSLT_COMPONENT_NAME}` } }],
+ [true, { to: { uri: `${XSLT_COMPONENT_NAME}:document.xsl` } }],
+ ] as const)('should return %s when toDefinition is %s', (result, toDefinition) => {
+ expect(isXSLTComponent(toDefinition)).toBe(result);
+ });
+});
diff --git a/packages/ui/src/utils/is-xslt-component.ts b/packages/ui/src/utils/is-xslt-component.ts
new file mode 100644
index 000000000..6311d6583
--- /dev/null
+++ b/packages/ui/src/utils/is-xslt-component.ts
@@ -0,0 +1,14 @@
+import { ProcessorDefinition } from '@kaoto/camel-catalog/types';
+import { XSLT_COMPONENT_NAME } from './is-datamapper';
+import type { ToObjectDef } from './is-to-processor';
+import { isToProcessor } from './is-to-processor';
+
+export type XsltComponentDef = ToObjectDef & { to: { uri: string } };
+
+export const isXSLTComponent = (toDefinition: ProcessorDefinition): toDefinition is XsltComponentDef => {
+ if (!isToProcessor(toDefinition)) {
+ return false;
+ }
+
+ return toDefinition.to.uri?.startsWith(XSLT_COMPONENT_NAME) ?? false;
+};
diff --git a/packages/ui/src/utils/node-icon-resolver.ts b/packages/ui/src/utils/node-icon-resolver.ts
index 4f2d989fe..95341c0b1 100644
--- a/packages/ui/src/utils/node-icon-resolver.ts
+++ b/packages/ui/src/utils/node-icon-resolver.ts
@@ -105,6 +105,7 @@ import icon_component_couchdb from '../assets/components/couchdb.svg';
import icon_component_cql from '../assets/components/cql.svg';
import icon_component_crypto from '../assets/components/crypto.svg';
import icon_component_cxf from '../assets/components/cxf.png';
+import icon_component_datamapper from '../assets/components/datamapper.png';
import icon_component_debezium from '../assets/components/debezium.svg';
import icon_component_dhis2 from '../assets/components/dhis2.svg';
import icon_component_direct from '../assets/components/direct.svg';
@@ -902,6 +903,8 @@ export class NodeIconResolver {
case 'idempotentConsumer':
return icon_eip_idempotent_consumer;
// case 'kamelet': handled on top
+ case 'kaoto-datamapper':
+ return icon_component_datamapper;
case 'loadBalance':
return icon_eip_load_balance;
case 'log':
diff --git a/packages/xml-schema-ts/.lintstagedrc.json b/packages/xml-schema-ts/.lintstagedrc.json
new file mode 100644
index 000000000..cafe25df7
--- /dev/null
+++ b/packages/xml-schema-ts/.lintstagedrc.json
@@ -0,0 +1,3 @@
+{
+ "*.ts": "yarn workspace @datamapper-poc/xml-schema-ts run eslint \"src/**/*.ts\"",
+}
diff --git a/packages/xml-schema-ts/README.md b/packages/xml-schema-ts/README.md
new file mode 100644
index 000000000..88e158055
--- /dev/null
+++ b/packages/xml-schema-ts/README.md
@@ -0,0 +1,16 @@
+XmlSchemaTS - XML Schema Parser written in TypeScript, ported from Apache XmlSchema
+==============================================
+
+This is supposed to be a minimal porting from [Apache XmlSchema](https://ws.apache.org/xmlschema/)
+to TypeScript for what is required for the Data Mapper with using standard DOMParser.
+The main focus is to parse the XML schema file and build a Data Mapper Document model.
+
+Always honor the upstream for the internal design so we can share the common sense.
+https://github.com/apache/ws-xmlschema
+
+See this test case for the basic usage
+https://github.com/KaotoIO/datamapper-poc/blob/main/packages/ui/src/util/xsd/XmlSchemaCollection.test.ts
+
+### Behavioral Changes
+- From what I understand from XML Schema definition, the top level elements are always assigned to the target namespace. In order to achieve this behavior, I made the following change
+ - https://github.com/KaotoIO/datamapper-poc/commit/92be1f4b21d37194bf627a845c785aa9462dab16#diff-f4482bd2efd45dc85f74b837385f37fde87ddb67c49dde92608c37549185b3adR35-R36
\ No newline at end of file
diff --git a/packages/xml-schema-ts/babel.config.cjs b/packages/xml-schema-ts/babel.config.cjs
new file mode 100644
index 000000000..d40df42bf
--- /dev/null
+++ b/packages/xml-schema-ts/babel.config.cjs
@@ -0,0 +1,8 @@
+// eslint-disable-next-line no-undef
+module.exports = {
+ presets: [
+ ['@babel/preset-env', { targets: { node: 'current' } }],
+ ['@babel/preset-react', { runtime: 'automatic' }],
+ '@babel/preset-typescript',
+ ],
+};
diff --git a/packages/xml-schema-ts/jest.config.js b/packages/xml-schema-ts/jest.config.js
new file mode 100644
index 000000000..48c95ec7c
--- /dev/null
+++ b/packages/xml-schema-ts/jest.config.js
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+export default {
+ testEnvironment: 'jsdom',
+ reporters: ['default'],
+ setupFilesAfterEnv: ['./jest.setup.ts'],
+ moduleDirectories: ['node_modules'],
+ testMatch: ['**/?(*.)+(test).[tj]s?(x)'],
+ modulePathIgnorePatterns: ['dist'],
+
+ // Indicates whether the coverage information should be collected while executing the test
+ collectCoverage: true,
+
+ // An array of glob patterns indicating a set of files for which coverage information should be collected
+ collectCoverageFrom: [
+ // Collect coverage from all ts and tsx files in the src folder
+ 'src/**/*.{ts,tsx}',
+ // Ignore all test files
+ '!src/**/*.test.{ts,tsx}',
+ // Ignore all declaration files
+ '!src/**/*.d.ts',
+ ],
+
+ // The directory where Jest should output its coverage files
+ coverageDirectory: 'coverage',
+
+ // An array of regexp pattern strings used to skip coverage collection
+ coveragePathIgnorePatterns: ['\\\\node_modules\\\\'],
+
+ // Indicates which provider should be used to instrument code for coverage
+ coverageProvider: 'babel',
+};
diff --git a/packages/xml-schema-ts/jest.setup.ts b/packages/xml-schema-ts/jest.setup.ts
new file mode 100644
index 000000000..e9bb7f2aa
--- /dev/null
+++ b/packages/xml-schema-ts/jest.setup.ts
@@ -0,0 +1,20 @@
+/*
+ * 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 '@testing-library/jest-dom';
diff --git a/packages/xml-schema-ts/package.json b/packages/xml-schema-ts/package.json
new file mode 100644
index 000000000..fbf7d7110
--- /dev/null
+++ b/packages/xml-schema-ts/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@kaoto/xml-schema-ts",
+ "version": "2.2.0-dev",
+ "type": "module",
+ "description": "Kaoto XmlSchemaTS",
+ "repository": "https://github.com/KaotoIO/kaoto",
+ "repositoryDirectory": "packages/xml-schema-ts",
+ "author": "The Kaoto Team",
+ "private": true,
+ "license": "Apache License v2.0",
+ "types": "./dist/esm/index.d.ts",
+ "main": "./dist/esm/index.js",
+ "exports": {
+ ".": {
+ "import": "./dist/esm/index.js",
+ "require": "./dist/cjs/index.js"
+ }
+ },
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "build": "rimraf dist && tsc --build tsconfig.cjs.json && tsc --build tsconfig.esm.json",
+ "test": "jest",
+ "test:watch": "jest --watch",
+ "lint": "yarn eslint \"src/**/*.{ts,tsx}\"",
+ "lint:fix": "yarn lint:code --fix"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.23.2",
+ "@babel/preset-env": "^7.21.5",
+ "@babel/preset-typescript": "^7.21.5",
+ "@testing-library/jest-dom": "^6.4.2",
+ "@types/jest": "^29.5.12",
+ "eslint": "^8.45.0",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-plugin-import": "^2.26.0",
+ "eslint-plugin-jest": "^27.2.1",
+ "eslint-plugin-prettier": "^5.0.0",
+ "jest": "^29.7.0",
+ "prettier": "^3.0.0",
+ "rimraf": "^6.0.0",
+ "typescript": "^5.4.2",
+ "vite": "^5.4.0"
+ }
+}
diff --git a/packages/xml-schema-ts/src/DocumentFragmentNodeList.ts b/packages/xml-schema-ts/src/DocumentFragmentNodeList.ts
new file mode 100644
index 000000000..947460f8a
--- /dev/null
+++ b/packages/xml-schema-ts/src/DocumentFragmentNodeList.ts
@@ -0,0 +1,62 @@
+export class DocumentFragmentNodeList implements NodeList {
+ private nodes: Node[] = [];
+ private fragment?: DocumentFragment;
+ length: number;
+
+ /**
+ * Create a list of the children of a given node that are elements with a specified qualified name.
+ *
+ * @param parentNode node from which to copy children.
+ * @param filterUri Namespace URI of children to copy.
+ * @param filterLocal Local name of children to copy.
+ */
+ constructor(parentNode: Node, filterUri?: string, filterLocal?: string) {
+ this.length = 0;
+ if (!parentNode.ownerDocument) {
+ throw new Error('Could not access the owner Document');
+ }
+ this.fragment = parentNode.ownerDocument.createDocumentFragment();
+ for (let child = parentNode.firstChild; child != null; child = child.nextSibling) {
+ if (filterUri == null && filterLocal == null) {
+ this.nodes.push(this.fragment.appendChild(child.cloneNode(true)));
+ continue;
+ }
+ if (child.nodeType == Node.ELEMENT_NODE) {
+ const childElement = child as Element;
+ if (childElement.namespaceURI === filterUri && childElement.localName === filterLocal) {
+ this.nodes.push(this.fragment.appendChild(child.cloneNode(true)));
+ }
+ }
+ }
+ this.length = this.nodes.length;
+ }
+
+ item(index: number) {
+ if (this.nodes == null) {
+ return null;
+ } else {
+ return this.nodes[index];
+ }
+ }
+
+ /**
+ * Java DOM doesn't have followings, but required in TypeScript
+ */
+
+ [index: number]: Node;
+ forEach(_callbackfn: (value: Node, key: number, parent: NodeList) => void, _thisArg?: object): void {
+ throw new Error('Method not implemented.');
+ }
+ entries(): IterableIterator<[number, Node]> {
+ throw new Error('Method not implemented.');
+ }
+ keys(): IterableIterator {
+ throw new Error('Method not implemented.');
+ }
+ values(): IterableIterator {
+ throw new Error('Method not implemented.');
+ }
+ [Symbol.iterator](): IterableIterator {
+ throw new Error('Method not implemented.');
+ }
+}
diff --git a/packages/xml-schema-ts/src/QName.ts b/packages/xml-schema-ts/src/QName.ts
new file mode 100644
index 000000000..e1979059e
--- /dev/null
+++ b/packages/xml-schema-ts/src/QName.ts
@@ -0,0 +1,47 @@
+export class QName {
+ constructor(
+ private namespaceURI: string | null,
+ private localPart: string | null,
+ private prefix: string | null = null,
+ ) {}
+
+ getNamespaceURI(): string | null {
+ return this.namespaceURI;
+ }
+
+ getLocalPart(): string | null {
+ return this.localPart;
+ }
+
+ getPrefix(): string | null {
+ return this.prefix;
+ }
+
+ valueOf(qNameAsString: string): QName {
+ if (qNameAsString == null) {
+ throw new Error('cannot create QName from null');
+ } else if (qNameAsString === '') {
+ return new QName(null, qNameAsString, '');
+ } else if (qNameAsString.charAt(0) !== '{') {
+ return new QName(null, qNameAsString, '');
+ } else if (qNameAsString.startsWith('{}')) {
+ return new QName(null, qNameAsString.substring(2), '');
+ } else {
+ const endOfNamespaceURI = qNameAsString.indexOf('}');
+ if (endOfNamespaceURI === -1) {
+ throw new Error(`cannot create QName from ${qNameAsString}, missing closing "}"`);
+ } else {
+ return new QName(
+ qNameAsString.substring(1, endOfNamespaceURI),
+ qNameAsString.substring(endOfNamespaceURI + 1),
+ '' /* prefix */,
+ );
+ }
+ }
+ }
+
+ toString() {
+ const answer = this.namespaceURI ? `{${this.namespaceURI}}` : '';
+ return answer + this.localPart;
+ }
+}
diff --git a/packages/xml-schema-ts/src/SchemaBuilder.ts b/packages/xml-schema-ts/src/SchemaBuilder.ts
new file mode 100644
index 000000000..4e5a54ea0
--- /dev/null
+++ b/packages/xml-schema-ts/src/SchemaBuilder.ts
@@ -0,0 +1,1718 @@
+import type { XmlSchemaCollection } from './XmlSchemaCollection';
+import type { XmlSchemaObject } from './XmlSchemaObject';
+import type { XmlSchemaIdentityConstraint } from './constraint/XmlSchemaIdentityConstraint';
+import type { NamespaceContext } from './utils/NamespaceContext';
+import type { ExtensionRegistry } from './extensions/ExtensionRegistry';
+
+import { DocumentFragmentNodeList } from './DocumentFragmentNodeList';
+import { QName } from './QName';
+import { SchemaKey } from './SchemaKey';
+import { XmlSchema } from './XmlSchema';
+import { XmlSchemaAll } from './particle/XmlSchemaAll';
+import { XmlSchemaAny } from './particle/XmlSchemaAny';
+import { XmlSchemaAnnotation } from './annotation/XmlSchemaAnnotation';
+import { XmlSchemaAnyAttribute } from './XmlSchemaAnyAttribute';
+import { XmlSchemaAppInfo } from './annotation/XmlSchemaAppInfo';
+import { XmlSchemaAttribute } from './attribute/XmlSchemaAttribute';
+import { XmlSchemaAttributeGroup } from './attribute/XmlSchemaAttributeGroup';
+import { XmlSchemaAttributeGroupRef } from './attribute/XmlSchemaAttributeGroupRef';
+import { XmlSchemaChoice } from './particle/XmlSchemaChoice';
+import { XmlSchemaComplexContent } from './complex/XmlSchemaComplexContent';
+import { XmlSchemaComplexContentExtension } from './complex/XmlSchemaComplexContentExtension';
+import { XmlSchemaComplexContentRestriction } from './complex/XmlSchemaComplexContentRestriction';
+import { XmlSchemaComplexType } from './complex/XmlSchemaComplexType';
+import { XmlSchemaContentProcessing, xmlSchemaContentProcessingValueOf } from './XmlSchemaContentProcessing';
+import { XmlSchemaDerivationMethod } from './XmlSchemaDerivationMethod';
+import { XmlSchemaElement } from './particle/XmlSchemaElement';
+import { XmlSchemaForm, xmlSchemaFormValueOf } from './XmlSchemaForm';
+import { XmlSchemaGroup } from './XmlSchemaGroup';
+import { XmlSchemaGroupRef } from './particle/XmlSchemaGroupRef';
+import { XmlSchemaImport } from './external/XmlSchemaImport';
+import { XmlSchemaInclude } from './external/XmlSchemaInclude';
+import { XmlSchemaKeyref } from './constraint/XmlSchemaKeyref';
+import { XmlSchemaNotation } from './XmlSchemaNotation';
+import { XmlSchemaSequence } from './particle/XmlSchemaSequence';
+import { XmlSchemaSimpleContent } from './simple/XmlSchemaSimpleContent';
+import { XmlSchemaSimpleContentExtension } from './simple/XmlSchemaSimpleContentExtension';
+import { XmlSchemaSimpleContentRestriction } from './simple/XmlSchemaSimpleContentRestriction';
+import { XmlSchemaSimpleType } from './simple/XmlSchemaSimpleType';
+import { XmlSchemaSimpleTypeList } from './simple/XmlSchemaSimpleTypeList';
+import { XmlSchemaSimpleTypeRestriction } from './simple/XmlSchemaSimpleTypeRestriction';
+import { XmlSchemaSimpleTypeUnion } from './simple/XmlSchemaSimpleTypeUnion';
+import { XmlSchemaUnique } from './constraint/XmlSchemaUnique';
+import { XmlSchemaXPath } from './XmlSchemaXPath';
+import { xmlSchemaUseValueOf } from './XmlSchemaUse';
+import { NodeNamespaceContext } from './utils/NodeNamespaceContext';
+import { XDOMUtil } from './utils/XDOMUtil';
+import * as Constants from './constants';
+import { XmlSchemaKey } from './constraint/XmlSchemaKey';
+import { XmlSchemaDocumentation } from './annotation/XmlSchemaDocumentation';
+import { XmlSchemaRedefine } from './external/XmlSchemaRedefine';
+import { XmlSchemaFacetConstructor } from './facet/XmlSchemaFacetConstructor';
+
+export class SchemaBuilder {
+ private resolvedSchemas = new Map();
+ private static readonly RESERVED_ATTRIBUTES = new Set([
+ 'name',
+ 'type',
+ 'default',
+ 'fixed',
+ 'form',
+ 'id',
+ 'use',
+ 'ref',
+ ]);
+ private currentSchema = new XmlSchema();
+ private extReg?: ExtensionRegistry;
+
+ constructor(
+ private collection: XmlSchemaCollection,
+ private currentValidator?: (s: XmlSchema) => void,
+ ) {
+ if (this.collection.getExtReg() != null) {
+ this.extReg = this.collection.getExtReg();
+ }
+ }
+
+ getExtReg() {
+ return this.extReg;
+ }
+
+ setExtReg(extReg: ExtensionRegistry) {
+ this.extReg = extReg;
+ }
+
+ build(doc: Document, uri?: string): XmlSchema {
+ const schemaEl = doc.documentElement as Element;
+ return this.handleXmlSchemaElement(schemaEl, uri);
+ }
+
+ getDerivation(el: Element, attrName: string) {
+ if (el.hasAttribute(attrName) && !(el.getAttribute(attrName) === '')) {
+ // #all | List of (extension | restriction | substitution)
+ const derivationMethod = el.getAttribute(attrName)!.trim();
+ return XmlSchemaDerivationMethod.schemaValueOf(derivationMethod);
+ }
+ return XmlSchemaDerivationMethod.NONE;
+ }
+
+ getEnumString(el: Element, attrName: string) {
+ if (el.hasAttribute(attrName)) {
+ return el.getAttribute(attrName)?.trim();
+ }
+ return 'none'; // local convention for empty value.
+ }
+
+ getFormDefault(el: Element, attrName: string) {
+ if (el.getAttributeNode(attrName) != null) {
+ const value = el.getAttribute(attrName)!;
+ return xmlSchemaFormValueOf(value);
+ } else {
+ return XmlSchemaForm.UNQUALIFIED;
+ }
+ }
+
+ getMaxOccurs(el: Element) {
+ if (el.getAttributeNode('maxOccurs') != null) {
+ const value = el.getAttribute('maxOccurs')!;
+ if ('unbounded' === value) {
+ return Number.MAX_SAFE_INTEGER;
+ } else {
+ return parseInt(value);
+ }
+ }
+ return 1;
+ }
+
+ getMinOccurs(el: Element) {
+ if (el.getAttributeNode('minOccurs') != null) {
+ const value = el.getAttribute('minOccurs')!;
+ if ('unbounded' === value) {
+ return Number.MAX_SAFE_INTEGER;
+ } else {
+ return parseInt(value);
+ }
+ }
+ return 1;
+ }
+
+ /**
+ * Handles the annotation Traversing if encounter appinfo or documentation add it to annotation collection
+ */
+ handleAnnotation(annotEl: Element) {
+ const annotation = new XmlSchemaAnnotation();
+ const content = annotation.getItems();
+ let appInfoObj: XmlSchemaAppInfo | null;
+
+ for (
+ let appinfo = XDOMUtil.getFirstChildElementNS(annotEl, XmlSchema.SCHEMA_NS, 'appinfo');
+ appinfo != null;
+ appinfo = XDOMUtil.getNextSiblingElementNS(appinfo, XmlSchema.SCHEMA_NS, 'appinfo')
+ ) {
+ appInfoObj = this.handleAppInfo(appinfo);
+ if (appInfoObj != null) {
+ content.push(appInfoObj);
+ }
+ }
+
+ for (
+ let documentation = XDOMUtil.getFirstChildElementNS(annotEl, XmlSchema.SCHEMA_NS, 'documentation');
+ documentation != null;
+ documentation = XDOMUtil.getNextSiblingElementNS(documentation, XmlSchema.SCHEMA_NS, 'documentation')
+ ) {
+ const docsObj = this.handleDocumentation(documentation);
+ if (docsObj != null) {
+ content.push(docsObj);
+ }
+ }
+
+ // process extra attributes and elements
+ this.processExtensibilityComponents(annotation, annotEl, true);
+ return annotation;
+ }
+
+ /**
+ * create new XmlSchemaAppinfo and add value gotten from element to this obj
+ *
+ * @param content
+ */
+ handleAppInfo(content: Element) {
+ const appInfo = new XmlSchemaAppInfo();
+ const markup = new DocumentFragmentNodeList(content);
+
+ if (!content.hasAttribute('source') && markup.length == 0) {
+ return null;
+ }
+
+ appInfo.setSource(this.getAttribute(content, 'source'));
+ appInfo.setMarkup(markup);
+ return appInfo;
+ }
+
+ /**
+ * Handle complex types
+ *
+ * @param schema
+ * @param complexEl
+ * @param schemaEl
+ * @param topLevel
+ */
+ handleComplexType(schema: XmlSchema, complexEl: Element, schemaEl: Element, topLevel: boolean) {
+ const ct = new XmlSchemaComplexType(schema, topLevel);
+
+ if (complexEl.hasAttribute('name')) {
+ // String namespace = (schema.targetNamespace==null)?
+ // "":schema.targetNamespace;
+
+ ct.setName(complexEl.getAttribute('name'));
+ }
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(complexEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ // String elPrefix = el.getPrefix() == null ? "" :
+ // el.getPrefix();
+ // if(elPrefix.equals(schema.schema_ns_prefix)) {
+ if (el.localName === 'sequence') {
+ ct.setParticle(this.handleSequence(schema, el, schemaEl));
+ } else if (el.localName === 'choice') {
+ ct.setParticle(this.handleChoice(schema, el, schemaEl));
+ } else if (el.localName === 'all') {
+ ct.setParticle(this.handleAll(schema, el, schemaEl));
+ } else if (el.localName === 'attribute') {
+ ct.getAttributes().push(this.handleAttribute(schema, el, schemaEl));
+ } else if (el.localName === 'attributeGroup') {
+ ct.getAttributes().push(this.handleAttributeGroupRef(schema, el));
+ } else if (el.localName === 'group') {
+ const group = this.handleGroupRef(schema, el, schemaEl);
+ if (group.getParticle() == null) {
+ ct.setParticle(group);
+ } else {
+ ct.setParticle(group.getParticle());
+ }
+ } else if (el.localName === 'simpleContent') {
+ ct.setContentModel(this.handleSimpleContent(schema, el, schemaEl));
+ } else if (el.localName === 'complexContent') {
+ ct.setContentModel(this.handleComplexContent(schema, el, schemaEl));
+ } else if (el.localName === 'annotation') {
+ ct.setAnnotation(this.handleAnnotation(el));
+ } else if (el.localName === 'anyAttribute') {
+ ct.setAnyAttribute(this.handleAnyAttribute(schema, el, schemaEl));
+ }
+ }
+ if (complexEl.hasAttribute('block')) {
+ const blockStr = complexEl.getAttribute('block')!;
+ ct.setBlock(XmlSchemaDerivationMethod.schemaValueOf(blockStr));
+ }
+ if (complexEl.hasAttribute('final')) {
+ const finalstr = complexEl.getAttribute('final')!;
+ ct.setFinal(XmlSchemaDerivationMethod.schemaValueOf(finalstr));
+ }
+ if (complexEl.hasAttribute('abstract')) {
+ const abs = complexEl.getAttribute('abstract')!;
+ if (abs.toLowerCase() === 'true') {
+ ct.setAbstract(true);
+ } else {
+ ct.setAbstract(false);
+ }
+ }
+ if (complexEl.hasAttribute('mixed')) {
+ const mixed = complexEl.getAttribute('mixed')!;
+ if (mixed.toLowerCase() === 'true') {
+ ct.setMixed(true);
+ } else {
+ ct.setMixed(false);
+ }
+ }
+
+ // process extra attributes and elements
+ this.processExtensibilityComponents(ct, complexEl, true);
+
+ return ct;
+ }
+
+ /**
+ * iterate each documentation element, create new XmlSchemaAppinfo and add
+ * to collection
+ */
+ handleDocumentation(content: Element) {
+ const documentation = new XmlSchemaDocumentation();
+ const markup = this.getChildren(content);
+
+ if (!content.hasAttribute('source') && !content.hasAttribute('xml:lang') && markup == null) {
+ return null;
+ }
+
+ documentation.setSource(this.getAttribute(content, 'source'));
+ documentation.setLanguage(this.getAttribute(content, 'xml:lang'));
+ documentation.setMarkup(new DocumentFragmentNodeList(content));
+
+ return documentation;
+ }
+
+ /**
+ * handle_complex_content_restriction
+ */
+ /**
+ * handle elements
+ *
+ * @param schema
+ * @param el
+ * @param schemaEl
+ * @param isGlobal
+ */
+ handleElement(schema: XmlSchema, el: Element, schemaEl: Element, isGlobal: boolean) {
+ const element = new XmlSchemaElement(schema, isGlobal);
+
+ if (el.getAttributeNode('name') != null) {
+ element.setName(el.getAttribute('name'));
+ }
+
+ // String namespace = (schema.targetNamespace==null)?
+ // "" : schema.targetNamespace;
+
+ let isQualified = schema.getElementFormDefault() == XmlSchemaForm.QUALIFIED;
+ isQualified = this.handleElementForm(el, element, isQualified);
+
+ this.handleElementName(isGlobal, element, isQualified);
+ this.handleElementAnnotation(el, element);
+ this.handleElementGlobalType(el, element);
+
+ let complexTypeEl: Element | null;
+ let keyEl: Element | null;
+ let keyrefEl: Element | null;
+ let uniqueEl: Element | null;
+ const simpleTypeEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'simpleType');
+ if (simpleTypeEl != null) {
+ const simpleType = this.handleSimpleType(schema, simpleTypeEl, schemaEl, false);
+ element.setSchemaType(simpleType);
+ element.setSchemaTypeName(simpleType.getQName());
+ } else {
+ complexTypeEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'complexType');
+ if (complexTypeEl != null) {
+ element.setSchemaType(this.handleComplexType(schema, complexTypeEl, schemaEl, false));
+ }
+ }
+
+ keyEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'key');
+ if (keyEl != null) {
+ while (keyEl != null) {
+ element.getConstraints().push(this.handleConstraint(keyEl, new XmlSchemaKey()));
+ keyEl = XDOMUtil.getNextSiblingElementNS(keyEl, XmlSchema.SCHEMA_NS, 'key');
+ }
+ }
+
+ keyrefEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'keyref');
+ if (keyrefEl != null) {
+ while (keyrefEl != null) {
+ const keyRef = this.handleConstraint(keyrefEl, new XmlSchemaKeyref()) as XmlSchemaKeyref;
+ if (keyrefEl.hasAttribute('refer')) {
+ const name = keyrefEl.getAttribute('refer')!;
+ keyRef.refer = this.getRefQName(name, el);
+ }
+ element.getConstraints().push(keyRef);
+ keyrefEl = XDOMUtil.getNextSiblingElementNS(keyrefEl, XmlSchema.SCHEMA_NS, 'keyref');
+ }
+ }
+
+ uniqueEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'unique');
+ if (uniqueEl != null) {
+ while (uniqueEl != null) {
+ element.getConstraints().push(this.handleConstraint(uniqueEl, new XmlSchemaUnique()));
+ uniqueEl = XDOMUtil.getNextSiblingElementNS(uniqueEl, XmlSchema.SCHEMA_NS, 'unique');
+ }
+ }
+
+ if (el.hasAttribute('abstract')) {
+ element.setAbstractElement(/true/i.test(el.getAttribute('abstract')!));
+ }
+
+ if (el.hasAttribute('block')) {
+ element.setBlock(this.getDerivation(el, 'block'));
+ }
+
+ if (el.hasAttribute('default')) {
+ element.setDefaultValue(el.getAttribute('default'));
+ }
+
+ if (el.hasAttribute('final')) {
+ element.setFinalDerivation(this.getDerivation(el, 'final'));
+ }
+
+ if (el.hasAttribute('fixed')) {
+ element.setFixedValue(el.getAttribute('fixed'));
+ }
+
+ if (el.hasAttribute('id')) {
+ element.setId(el.getAttribute('id'));
+ }
+
+ if (el.hasAttribute('nillable')) {
+ element.setNillable(/true/i.test(el.getAttribute('nillable')!));
+ }
+
+ if (el.hasAttribute('substitutionGroup')) {
+ const substitutionGroup = el.getAttribute('substitutionGroup')!;
+ element.setSubstitutionGroup(this.getRefQName(substitutionGroup, el));
+ }
+
+ element.setMinOccurs(this.getMinOccurs(el));
+ element.setMaxOccurs(this.getMaxOccurs(el));
+
+ // process extra attributes and elements
+ this.processExtensibilityComponents(element, el, true);
+
+ return element;
+ }
+
+ /**
+ * Handle the import
+ *
+ * @param schema
+ * @param importEl
+ * @param _schemaEl
+ * @return XmlSchemaObject
+ */
+ handleImport(schema: XmlSchema, importEl: Element, _schemaEl: Element) {
+ const schemaImport = new XmlSchemaImport(schema);
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(importEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const importAnnotation = this.handleAnnotation(annotationEl);
+ schemaImport.setAnnotation(importAnnotation);
+ }
+
+ schemaImport.namespace = importEl.getAttribute('namespace');
+ const uri = schemaImport.namespace;
+ schemaImport.schemaLocation = importEl.getAttribute('schemaLocation');
+
+ const validator = (pSchema: XmlSchema) => {
+ const isEmpty = (pValue: string | null) => {
+ return pValue == null || Constants.NULL_NS_URI === pValue;
+ };
+
+ let valid: boolean;
+ if (isEmpty(uri)) {
+ valid = isEmpty(pSchema.getSyntacticalTargetNamespace());
+ } else {
+ valid = pSchema.getSyntacticalTargetNamespace() === uri;
+ }
+ if (!valid) {
+ throw new Error(
+ 'An imported schema was announced to have the namespace ' +
+ uri +
+ ', but has the namespace ' +
+ pSchema.getSyntacticalTargetNamespace(),
+ );
+ }
+ };
+ schemaImport.schema = this.resolveXmlSchema(uri, schemaImport.schemaLocation, schema.getSourceURI(), validator);
+ return schemaImport;
+ }
+
+ /**
+ * Handles the include
+ *
+ * @param schema
+ * @param includeEl
+ * @param _schemaEl
+ */
+ handleInclude(schema: XmlSchema, includeEl: Element, _schemaEl: Element) {
+ const include = new XmlSchemaInclude(schema);
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(includeEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const includeAnnotation = this.handleAnnotation(annotationEl);
+ include.setAnnotation(includeAnnotation);
+ }
+
+ include.schemaLocation = includeEl.getAttribute('schemaLocation');
+
+ // includes are not supposed to have a target namespace
+ // we should be passing in a null in place of the target
+ // namespace
+
+ const validator = this.newIncludeValidator(schema);
+ include.schema = this.resolveXmlSchema(
+ schema.getLogicalTargetNamespace(),
+ include.schemaLocation,
+ schema.getSourceURI(),
+ validator,
+ );
+
+ // process extra attributes and elements
+ this.processExtensibilityComponents(include, includeEl, true);
+ return include;
+ }
+
+ /**
+ * Handles simple types
+ *
+ * @param schema
+ * @param simpleEl
+ * @param schemaEl
+ * @param topLevel
+ */
+ handleSimpleType(schema: XmlSchema, simpleEl: Element, schemaEl: Element, topLevel: boolean) {
+ const simpleType = new XmlSchemaSimpleType(schema, topLevel);
+ if (simpleEl.hasAttribute('name')) {
+ simpleType.setName(simpleEl.getAttribute('name'));
+ }
+
+ this.handleSimpleTypeFinal(simpleEl, simpleType);
+
+ const simpleTypeAnnotationEl = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (simpleTypeAnnotationEl != null) {
+ const simpleTypeAnnotation = this.handleAnnotation(simpleTypeAnnotationEl);
+
+ simpleType.setAnnotation(simpleTypeAnnotation);
+ }
+
+ const unionEl = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, 'union');
+ const listEl = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, 'list');
+ const restrictionEl = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS, 'restriction');
+ if (restrictionEl != null) {
+ this.handleSimpleTypeRestriction(schema, schemaEl, simpleType, restrictionEl);
+ } else if (listEl != null) {
+ this.handleSimpleTypeList(schema, schemaEl, simpleType, listEl);
+ } else if (unionEl != null) {
+ this.handleSimpleTypeUnion(schema, schemaEl, simpleType, unionEl);
+ }
+
+ // process extra attributes and elements
+ this.processExtensibilityComponents(simpleType, simpleEl, true);
+
+ return simpleType;
+ }
+
+ handleXmlSchemaElement(schemaEl: Element, systemId?: string): XmlSchema {
+ this.currentSchema.setNamespaceContext(NodeNamespaceContext.getNamespaceContext(schemaEl));
+ this.setNamespaceAttributes(this.currentSchema, schemaEl);
+
+ const schemaKey = new SchemaKey(this.currentSchema.getLogicalTargetNamespace(), systemId);
+ this.handleSchemaElementBasics(schemaEl, systemId, schemaKey);
+
+ let el = XDOMUtil.getFirstChildElementNS(schemaEl, XmlSchema.SCHEMA_NS);
+ for (; el != null; el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)) {
+ this.handleSchemaElementChild(schemaEl, el);
+ }
+
+ this.processExtensibilityComponents(this.currentSchema, schemaEl, false);
+ return this.currentSchema;
+ }
+
+ /**
+ * Resolve the schemas
+ *
+ * @param targetNamespace
+ * @param schemaLocation
+ * @param baseUri
+ * @param validator
+ */
+ resolveXmlSchema(
+ targetNamespace: string | null,
+ schemaLocation: string | null,
+ baseUri: string | null,
+ validator: (s: XmlSchema) => void,
+ ) {
+ if (baseUri == null) {
+ baseUri = this.collection.baseUri;
+ }
+ if (targetNamespace == null) {
+ targetNamespace = Constants.NULL_NS_URI;
+ }
+
+ if (
+ targetNamespace != null &&
+ schemaLocation != null &&
+ baseUri != null &&
+ this.getCachedSchema(targetNamespace, schemaLocation, baseUri) != null
+ ) {
+ return this.getCachedSchema(targetNamespace, schemaLocation, baseUri);
+ }
+
+ // use the entity resolver provided if the schema location is present
+ // null
+ if (schemaLocation != null && !('' === schemaLocation)) {
+ const source = this.collection.getSchemaResolver().resolveEntity(targetNamespace, schemaLocation, baseUri);
+
+ // the entity resolver was unable to resolve this!!
+ if (source == null) {
+ // try resolving it with the target namespace only with the
+ // known namespace map
+ return this.collection.getKnownSchema(targetNamespace);
+ }
+ //const systemId = source.getSystemId() == null ? schemaLocation : source.getSystemId();
+ const systemId = schemaLocation;
+ // Push repaired system id back into source where read sees it.
+ // It is perhaps a bad thing to patch the source, but this fixes
+ // a problem.
+ //source.setSystemId(systemId);
+ const key = new SchemaKey(targetNamespace, systemId);
+ const schema = this.collection.getSchema(key);
+ if (schema != null) {
+ return schema;
+ }
+ if (this.collection.check(key)) {
+ this.collection.push(key);
+ try {
+ const readSchema = this.collection.read(source, validator);
+ this.putCachedSchema(targetNamespace, schemaLocation, baseUri || '', readSchema);
+ return readSchema;
+ } finally {
+ this.collection.pop();
+ }
+ }
+ } else {
+ const schema = this.collection.getKnownSchema(targetNamespace);
+ if (schema != null) {
+ return schema;
+ }
+ }
+ return null;
+ }
+
+ setNamespaceAttributes(schema: XmlSchema, schemaEl: Element) {
+ // no targetnamespace found !
+ if (schemaEl.getAttributeNode('targetNamespace') != null) {
+ const contain = schemaEl.getAttribute('targetNamespace')!;
+ schema.setTargetNamespace(contain);
+ }
+ if (this.currentValidator != null) {
+ this.currentValidator(schema);
+ }
+ }
+
+ private getAttribute(content: Element, attrName: string) {
+ if (content.hasAttribute(attrName)) {
+ return content.getAttribute(attrName);
+ }
+ return null;
+ }
+
+ /**
+ * Return a cached schema if one exists for this thread. In order for schemas to be cached the thread must
+ * have done an initCache() previously. The parameters are used to construct a key used to lookup the
+ * schema
+ *
+ * @param targetNamespace
+ * @param schemaLocation
+ * @param baseUri
+ * @return The cached schema if one exists for this thread or null.
+ */
+ private getCachedSchema(targetNamespace: string, schemaLocation: string, baseUri: string) {
+ let resolvedSchema: XmlSchema | null = null;
+
+ if (this.resolvedSchemas != null) {
+ // cache is initialized, use it
+ const schemaKey = targetNamespace + schemaLocation + baseUri;
+ resolvedSchema = this.resolvedSchemas.get(schemaKey) || null;
+ }
+ return resolvedSchema;
+ }
+
+ private getChildren(content: Element) {
+ const result: Node[] = [];
+ for (let n = content.firstChild; n != null; n = n.nextSibling) {
+ result.push(n);
+ }
+ if (result.length == 0) {
+ return null;
+ } else {
+ return result;
+ }
+ }
+
+ private getRefQName(pName: string, pNode?: Node, pContext?: NamespaceContext) {
+ if (pNode) {
+ pContext = NodeNamespaceContext.getNamespaceContext(pNode);
+ }
+ if (!pContext) {
+ throw new Error('Either Node or NamespaceContext must be specified');
+ }
+
+ const offset = pName.indexOf(':');
+ let uri: string;
+ let localName: string;
+ let prefix: string;
+ if (offset == -1) {
+ uri = pContext.getNamespaceURI(Constants.DEFAULT_NS_PREFIX);
+ if (Constants.NULL_NS_URI === uri) {
+ if (
+ this.currentSchema.getTargetNamespace() == null &&
+ !(this.currentSchema.getLogicalTargetNamespace() === '')
+ ) {
+ // If object is unqualified in a schema without a target namespace then it could
+ // be that this schema is included in another one. The including namespace
+ // should then be used for this reference
+ return new QName(this.currentSchema.getLogicalTargetNamespace(), pName);
+ }
+ return new QName(Constants.NULL_NS_URI, pName);
+ }
+ localName = pName;
+ prefix = Constants.DEFAULT_NS_PREFIX;
+ } else {
+ prefix = pName.substring(0, offset);
+ uri = pContext.getNamespaceURI(prefix);
+ const parentSchema = this.currentSchema.getParent();
+ if (
+ uri == null ||
+ (Constants.NULL_NS_URI === uri && parentSchema != null && parentSchema.getNamespaceContext() != null)
+ ) {
+ uri = parentSchema!.getNamespaceContext()!.getNamespaceURI(prefix);
+ }
+
+ if (uri == null || Constants.NULL_NS_URI === uri) {
+ throw new Error('The prefix ' + prefix + ' is not bound.');
+ }
+ localName = pName.substring(offset + 1);
+ }
+ return new QName(uri, localName, prefix);
+ }
+
+ private handleAll(schema: XmlSchema, allEl: Element, schemaEl: Element) {
+ const all = new XmlSchemaAll();
+
+ // handle min and max occurences
+ all.setMinOccurs(this.getMinOccurs(allEl));
+ all.setMaxOccurs(this.getMaxOccurs(allEl));
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(allEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'element') {
+ const element = this.handleElement(schema, el, schemaEl, false);
+ all.getItems().push(element);
+ } else if (el.localName === 'annotation') {
+ const annotation = this.handleAnnotation(el);
+ all.setAnnotation(annotation);
+ }
+ }
+ return all;
+ }
+
+ private handleAny(schema: XmlSchema, anyEl: Element, _schemaEl: Element) {
+ const any = new XmlSchemaAny();
+
+ any.setTargetNamespace(schema.getLogicalTargetNamespace());
+
+ if (anyEl.hasAttribute('namespace')) {
+ any.setNamespace(anyEl.getAttribute('namespace'));
+ }
+
+ if (anyEl.hasAttribute('processContents')) {
+ const processContent = this.getEnumString(anyEl, 'processContents');
+
+ processContent != null && any.setProcessContent(xmlSchemaContentProcessingValueOf(processContent));
+ }
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(anyEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+ any.setAnnotation(annotation);
+ }
+ any.setMinOccurs(this.getMinOccurs(anyEl));
+ any.setMaxOccurs(this.getMaxOccurs(anyEl));
+
+ return any;
+ }
+
+ private handleAnyAttribute(_schema: XmlSchema, anyAttrEl: Element, _schemaEl: Element) {
+ const anyAttr = new XmlSchemaAnyAttribute();
+
+ if (anyAttrEl.hasAttribute('namespace')) {
+ anyAttr.namespace = anyAttrEl.getAttribute('namespace');
+ }
+
+ if (anyAttrEl.hasAttribute('processContents')) {
+ const contentProcessing = this.getEnumString(anyAttrEl, 'processContents');
+
+ anyAttr.processContent =
+ contentProcessing != null
+ ? xmlSchemaContentProcessingValueOf(contentProcessing)
+ : XmlSchemaContentProcessing.NONE;
+ }
+ if (anyAttrEl.hasAttribute('id')) {
+ anyAttr.setId(anyAttrEl.getAttribute('id'));
+ }
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(anyAttrEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+
+ anyAttr.setAnnotation(annotation);
+ }
+ return anyAttr;
+ }
+
+ /**
+ * Process attributes
+ *
+ * @param schema
+ * @param attrEl
+ * @param schemaEl
+ * @param topLevel
+ * @return
+ */
+ private handleAttribute(schema: XmlSchema, attrEl: Element, schemaEl: Element, topLevel: boolean = false) {
+ const attr = new XmlSchemaAttribute(schema, topLevel);
+
+ if (attrEl.hasAttribute('name')) {
+ const name = attrEl.getAttribute('name')!;
+ attr.setName(name);
+ }
+
+ if (attrEl.hasAttribute('type')) {
+ const name = attrEl.getAttribute('type')!;
+ attr.setSchemaTypeName(this.getRefQName(name, attrEl));
+ }
+
+ if (attrEl.hasAttribute('default')) {
+ attr.setDefaultValue(attrEl.getAttribute('default')!);
+ }
+
+ if (attrEl.hasAttribute('fixed')) {
+ attr.setFixedValue(attrEl.getAttribute('fixed')!);
+ }
+
+ if (attrEl.hasAttribute('form')) {
+ const formValue = this.getEnumString(attrEl, 'form')!;
+ attr.setForm(xmlSchemaFormValueOf(formValue));
+ }
+
+ if (attrEl.hasAttribute('id')) {
+ attr.setId(attrEl.getAttribute('id')!);
+ }
+
+ if (attrEl.hasAttribute('use')) {
+ const useType = this.getEnumString(attrEl, 'use')!;
+ attr.setUse(xmlSchemaUseValueOf(useType));
+ }
+ if (attrEl.hasAttribute('ref')) {
+ const name = attrEl.getAttribute('ref')!;
+ attr.getRef().setTargetQName(this.getRefQName(name, attrEl));
+ }
+
+ const simpleTypeEl = XDOMUtil.getFirstChildElementNS(attrEl, XmlSchema.SCHEMA_NS, 'simpleType');
+
+ if (simpleTypeEl != null) {
+ attr.setSchemaType(this.handleSimpleType(schema, simpleTypeEl, schemaEl, false));
+ }
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(attrEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+
+ attr.setAnnotation(annotation);
+ }
+
+ const attrNodes = attrEl.attributes;
+ const attrs: Attr[] = [];
+ let ctx: NodeNamespaceContext | null = null;
+ for (let i = 0; i < attrNodes.length; i++) {
+ const att = attrNodes.item(i) as Attr;
+ const attName = att.name;
+ if (!SchemaBuilder.RESERVED_ATTRIBUTES.has(attName)) {
+ attrs.push(att);
+ const value = att.value;
+
+ if (value.indexOf(':') > -1) {
+ // there is a possibility of some namespace mapping
+ const prefix = value.substring(0, value.indexOf(':'));
+ if (ctx == null) {
+ ctx = NodeNamespaceContext.getNamespaceContext(attrEl);
+ }
+ const namespace = ctx.getNamespaceURI(prefix);
+ if (Constants.NULL_NS_URI !== namespace) {
+ const nsAttr = attrEl.ownerDocument.createAttributeNS(Constants.XMLNS_ATTRIBUTE_NS_URI, 'xmlns:' + prefix);
+ nsAttr.value = namespace;
+ attrs.push(nsAttr);
+ }
+ }
+ }
+ }
+
+ if (attrs.length > 0) {
+ attr.setUnhandledAttributes(attrs);
+ }
+
+ // process extra attributes and elements
+ this.processExtensibilityComponents(attr, attrEl, true);
+ return attr;
+ }
+
+ private handleAttributeGroup(schema: XmlSchema, groupEl: Element, schemaEl: Element) {
+ const attrGroup = new XmlSchemaAttributeGroup(schema);
+
+ if (groupEl.hasAttribute('name')) {
+ attrGroup.setName(groupEl.getAttribute('name')!);
+ }
+ if (groupEl.hasAttribute('id')) {
+ attrGroup.setId(groupEl.getAttribute('id'));
+ }
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(groupEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'attribute') {
+ const attr = this.handleAttribute(schema, el, schemaEl);
+ attrGroup.getAttributes().push(attr);
+ } else if (el.localName === 'attributeGroup') {
+ const attrGroupRef = this.handleAttributeGroupRef(schema, el);
+ attrGroup.getAttributes().push(attrGroupRef);
+ } else if (el.localName === 'anyAttribute') {
+ attrGroup.setAnyAttribute(this.handleAnyAttribute(schema, el, schemaEl));
+ } else if (el.localName === 'annotation') {
+ const ann = this.handleAnnotation(el);
+ attrGroup.setAnnotation(ann);
+ }
+ }
+ return attrGroup;
+ }
+
+ private handleAttributeGroupRef(schema: XmlSchema, attrGroupEl: Element) {
+ const attrGroup = new XmlSchemaAttributeGroupRef(schema);
+
+ if (attrGroupEl.hasAttribute('ref')) {
+ const ref = attrGroupEl.getAttribute('ref')!;
+ attrGroup.getRef().setTargetQName(this.getRefQName(ref, attrGroupEl));
+ }
+
+ if (attrGroupEl.hasAttribute('id')) {
+ attrGroup.setId(attrGroupEl.getAttribute('id'));
+ }
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(attrGroupEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+ attrGroup.setAnnotation(annotation);
+ }
+ return attrGroup;
+ }
+
+ private handleChoice(schema: XmlSchema, choiceEl: Element, schemaEl: Element) {
+ const choice = new XmlSchemaChoice();
+
+ if (choiceEl.hasAttribute('id')) {
+ choice.setId(choiceEl.getAttribute('id'));
+ }
+
+ choice.setMinOccurs(this.getMinOccurs(choiceEl));
+ choice.setMaxOccurs(this.getMaxOccurs(choiceEl));
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(choiceEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'sequence') {
+ const seq = this.handleSequence(schema, el, schemaEl);
+ choice.getItems().push(seq);
+ } else if (el.localName === 'element') {
+ const element = this.handleElement(schema, el, schemaEl, false);
+ choice.getItems().push(element);
+ } else if (el.localName === 'group') {
+ const group = this.handleGroupRef(schema, el, schemaEl);
+ choice.getItems().push(group);
+ } else if (el.localName === 'choice') {
+ const choiceItem = this.handleChoice(schema, el, schemaEl);
+ choice.getItems().push(choiceItem);
+ } else if (el.localName === 'any') {
+ const any = this.handleAny(schema, el, schemaEl);
+ choice.getItems().push(any);
+ } else if (el.localName === 'annotation') {
+ const annotation = this.handleAnnotation(el);
+ choice.setAnnotation(annotation);
+ }
+ }
+ return choice;
+ }
+
+ private handleComplexContent(schema: XmlSchema, complexEl: Element, schemaEl: Element) {
+ const complexContent = new XmlSchemaComplexContent();
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(complexEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'restriction') {
+ complexContent.content = this.handleComplexContentRestriction(schema, el, schemaEl);
+ } else if (el.localName === 'extension') {
+ complexContent.content = this.handleComplexContentExtension(schema, el, schemaEl);
+ } else if (el.localName === 'annotation') {
+ complexContent.setAnnotation(this.handleAnnotation(el));
+ }
+ }
+
+ if (complexEl.hasAttribute('mixed')) {
+ const mixed = complexEl.getAttribute('mixed')!;
+ if (mixed.toLowerCase() === 'true') {
+ complexContent.setMixed(true);
+ } else {
+ complexContent.setMixed(false);
+ }
+ }
+
+ return complexContent;
+ }
+
+ private handleComplexContentExtension(schema: XmlSchema, extEl: Element, schemaEl: Element) {
+ const ext = new XmlSchemaComplexContentExtension();
+
+ if (extEl.hasAttribute('base')) {
+ const name = extEl.getAttribute('base')!;
+ ext.setBaseTypeName(this.getRefQName(name, extEl));
+ }
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(extEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'sequence') {
+ ext.setParticle(this.handleSequence(schema, el, schemaEl));
+ } else if (el.localName === 'choice') {
+ ext.setParticle(this.handleChoice(schema, el, schemaEl));
+ } else if (el.localName === 'all') {
+ ext.setParticle(this.handleAll(schema, el, schemaEl));
+ } else if (el.localName === 'attribute') {
+ ext.getAttributes().push(this.handleAttribute(schema, el, schemaEl));
+ } else if (el.localName === 'attributeGroup') {
+ ext.getAttributes().push(this.handleAttributeGroupRef(schema, el));
+ } else if (el.localName === 'group') {
+ ext.setParticle(this.handleGroupRef(schema, el, schemaEl));
+ } else if (el.localName === 'anyAttribute') {
+ ext.setAnyAttribute(this.handleAnyAttribute(schema, el, schemaEl));
+ } else if (el.localName === 'annotation') {
+ ext.setAnnotation(this.handleAnnotation(el));
+ }
+ }
+ return ext;
+ }
+
+ private handleComplexContentRestriction(schema: XmlSchema, restrictionEl: Element, schemaEl: Element) {
+ const restriction = new XmlSchemaComplexContentRestriction();
+
+ if (restrictionEl.hasAttribute('base')) {
+ const name = restrictionEl.getAttribute('base')!;
+ restriction.setBaseTypeName(this.getRefQName(name, restrictionEl));
+ }
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(restrictionEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'sequence') {
+ restriction.setParticle(this.handleSequence(schema, el, schemaEl));
+ } else if (el.localName === 'choice') {
+ restriction.setParticle(this.handleChoice(schema, el, schemaEl));
+ } else if (el.localName === 'all') {
+ restriction.setParticle(this.handleAll(schema, el, schemaEl));
+ } else if (el.localName === 'attribute') {
+ restriction.getAttributes().push(this.handleAttribute(schema, el, schemaEl));
+ } else if (el.localName === 'attributeGroup') {
+ restriction.getAttributes().push(this.handleAttributeGroupRef(schema, el));
+ } else if (el.localName === 'group') {
+ restriction.setParticle(this.handleGroupRef(schema, el, schemaEl));
+ } else if (el.localName === 'anyAttribute') {
+ restriction.setAnyAttribute(this.handleAnyAttribute(schema, el, schemaEl));
+ } else if (el.localName === 'annotation') {
+ restriction.setAnnotation(this.handleAnnotation(el));
+ }
+ }
+ return restriction;
+ }
+
+ private handleConstraint(constraintEl: Element, constraint: XmlSchemaIdentityConstraint) {
+ if (constraintEl.hasAttribute('name')) {
+ constraint.setName(constraintEl.getAttribute('name')!);
+ }
+
+ if (constraintEl.hasAttribute('refer')) {
+ const name = constraintEl.getAttribute('refer')!;
+ (constraint as XmlSchemaKeyref).refer = this.getRefQName(name, constraintEl);
+ }
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(constraintEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ // String elPrefix = el.getPrefix() == null ? ""
+ // : el.getPrefix();
+ // if(elPrefix.equals(schema.schema_ns_prefix)) {
+ if (el.localName === 'selector') {
+ const selectorXPath = new XmlSchemaXPath();
+ selectorXPath.xpath = el.getAttribute('xpath');
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'annotation');
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+
+ selectorXPath.setAnnotation(annotation);
+ }
+ constraint.setSelector(selectorXPath);
+ } else if (el.localName === 'field') {
+ const fieldXPath = new XmlSchemaXPath();
+ fieldXPath.xpath = el.getAttribute('xpath');
+ constraint.getFields().push(fieldXPath);
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+
+ fieldXPath.setAnnotation(annotation);
+ }
+ } else if (el.localName === 'annotation') {
+ const constraintAnnotation = this.handleAnnotation(el);
+ constraint.setAnnotation(constraintAnnotation);
+ }
+ }
+ return constraint;
+ }
+
+ private handleElementAnnotation(el: Element, element: XmlSchemaElement) {
+ const annotationEl = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+
+ element.setAnnotation(annotation);
+ }
+ }
+
+ private handleElementForm(el: Element, element: XmlSchemaElement, _isQualified: boolean) {
+ if (el.hasAttribute('form')) {
+ const formDef = el.getAttribute('form')!;
+ element.setForm(xmlSchemaFormValueOf(formDef));
+ }
+ return element.getForm() == XmlSchemaForm.QUALIFIED;
+ }
+
+ private handleElementGlobalType(el: Element, element: XmlSchemaElement) {
+ if (el.getAttributeNode('type') != null) {
+ const typeName = el.getAttribute('type')!;
+ element.setSchemaTypeName(this.getRefQName(typeName, el));
+ const typeQName = element.getSchemaTypeName()!;
+
+ const type = this.collection.getTypeByQName(typeQName);
+ if (type == null) {
+ // Could be a forward reference...
+ this.collection.addUnresolvedType(typeQName, element);
+ }
+ element.setSchemaType(type);
+ } else if (el.getAttributeNode('ref') != null) {
+ const refName = el.getAttribute('ref')!;
+ const refQName = this.getRefQName(refName, el);
+ element.getRef().setTargetQName(refQName);
+ }
+ }
+
+ private handleElementName(_isGlobal: boolean, _element: XmlSchemaElement, _isQualified: boolean) {}
+
+ /*
+ * handle_simple_content_restriction if( restriction has base attribute ) set the baseType else if(
+ * restriction has an inline simpleType ) handleSimpleType add facets if any to the restriction
+ */
+
+ /*
+ * handle_simple_content_extension extension should have a base name and cannot have any inline defn for(
+ * each childNode ) if( attribute) handleAttribute else if( attributeGroup) handleAttributeGroup else if(
+ * anyAttribute) handleAnyAttribute
+ */
+
+ private handleGroup(schema: XmlSchema, groupEl: Element, schemaEl: Element) {
+ const group = new XmlSchemaGroup(schema);
+ group.setName(groupEl.getAttribute('name'));
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(groupEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'all') {
+ group.setParticle(this.handleAll(schema, el, schemaEl));
+ } else if (el.localName === 'sequence') {
+ group.setParticle(this.handleSequence(schema, el, schemaEl));
+ } else if (el.localName === 'choice') {
+ group.setParticle(this.handleChoice(schema, el, schemaEl));
+ } else if (el.localName === 'annotation') {
+ const groupAnnotation = this.handleAnnotation(el);
+ group.setAnnotation(groupAnnotation);
+ }
+ }
+ return group;
+ }
+
+ private handleGroupRef(schema: XmlSchema, groupEl: Element, schemaEl: Element) {
+ const group = new XmlSchemaGroupRef();
+
+ group.setMaxOccurs(this.getMaxOccurs(groupEl));
+ group.setMinOccurs(this.getMinOccurs(groupEl));
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(groupEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+
+ group.setAnnotation(annotation);
+ }
+
+ if (groupEl.hasAttribute('ref')) {
+ const ref = groupEl.getAttribute('ref')!;
+ group.setRefName(this.getRefQName(ref, groupEl));
+ return group;
+ }
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(groupEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElement(el)
+ ) {
+ if (el.localName === 'sequence') {
+ group.setParticle(this.handleSequence(schema, el, schemaEl));
+ } else if (el.localName === 'all') {
+ group.setParticle(this.handleAll(schema, el, schemaEl));
+ } else if (el.localName === 'choice') {
+ group.setParticle(this.handleChoice(schema, el, schemaEl));
+ }
+ }
+ return group;
+ }
+
+ private handleNotation(schema: XmlSchema, notationEl: Element) {
+ const notation = new XmlSchemaNotation(schema);
+
+ if (notationEl.hasAttribute('id')) {
+ notation.setId(notationEl.getAttribute('id')!);
+ }
+
+ if (notationEl.hasAttribute('name')) {
+ notation.setName(notationEl.getAttribute('name')!);
+ }
+
+ if (notationEl.hasAttribute('public')) {
+ notation.setPublicNotation(notationEl.getAttribute('public')!);
+ }
+
+ if (notationEl.hasAttribute('system')) {
+ notation.setSystem(notationEl.getAttribute('system')!);
+ }
+
+ const annotationEl = XDOMUtil.getFirstChildElementNS(notationEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotationEl != null) {
+ const annotation = this.handleAnnotation(annotationEl);
+ notation.setAnnotation(annotation);
+ }
+
+ return notation;
+ }
+
+ /**
+ * Handle redefine
+ *
+ * @param schema
+ * @param redefineEl
+ * @param schemaEl
+ * @return
+ */
+ private handleRedefine(schema: XmlSchema, redefineEl: Element, schemaEl: Element) {
+ const redefine = new XmlSchemaRedefine(schema);
+ redefine.schemaLocation = redefineEl.getAttribute('schemaLocation');
+ const validator = this.newIncludeValidator(schema);
+
+ redefine.schema = this.resolveXmlSchema(
+ schema.getLogicalTargetNamespace(),
+ redefine.schemaLocation,
+ schema.getSourceURI(),
+ validator,
+ );
+
+ /*
+ * FIXME - This seems not right. Since the redefine should take into account the attributes of the
+ * original element we cannot just build the type defined in the redefine section - what we need to do
+ * is to get the original type object and modify it. However one may argue (quite reasonably) that the
+ * purpose of this object model is to provide just the representation and not the validation (as it
+ * has been always the case)
+ */
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(redefineEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'simpleType') {
+ const type = this.handleSimpleType(schema, el, schemaEl, false);
+
+ redefine.getSchemaTypes().set(type.getQName()!, type);
+ redefine.getItems().push(type);
+ } else if (el.localName === 'complexType') {
+ const type = this.handleComplexType(schema, el, schemaEl, true);
+
+ redefine.getSchemaTypes().set(type.getQName()!, type);
+ redefine.getItems().push(type);
+ } else if (el.localName === 'group') {
+ const group = this.handleGroup(schema, el, schemaEl);
+ redefine.getGroups().set(group.getQName()!, group);
+ redefine.getItems().push(group);
+ } else if (el.localName === 'attributeGroup') {
+ const group = this.handleAttributeGroup(schema, el, schemaEl);
+
+ redefine.getAttributeGroups().set(group.getQName()!, group);
+ redefine.getItems().push(group);
+ } else if (el.localName === 'annotation') {
+ const annotation = this.handleAnnotation(el);
+ redefine.setAnnotation(annotation);
+ }
+ }
+ return redefine;
+ }
+
+ private handleSchemaElementBasics(schemaEl: Element, systemId: string | null = null, schemaKey: SchemaKey): void {
+ if (!this.collection.containsSchema(schemaKey)) {
+ this.collection.addSchema(schemaKey, this.currentSchema);
+ this.currentSchema.setParent(this.collection); // establish parentage now.
+ } else {
+ throw new Error(
+ 'Schema name conflict in collection. Namespace: ' + this.currentSchema.getLogicalTargetNamespace(),
+ );
+ }
+
+ this.currentSchema.setElementFormDefault(this.getFormDefault(schemaEl, 'elementFormDefault'));
+ this.currentSchema.setAttributeFormDefault(this.getFormDefault(schemaEl, 'attributeFormDefault'));
+ this.currentSchema.setBlockDefault(this.getDerivation(schemaEl, 'blockDefault'));
+ this.currentSchema.setFinalDefault(this.getDerivation(schemaEl, 'finalDefault'));
+
+ /* set id and version attributes */
+ if (schemaEl.hasAttribute('id')) {
+ this.currentSchema.setId(schemaEl.getAttribute('id'));
+ }
+ if (schemaEl.hasAttribute('version')) {
+ this.currentSchema.setVersion(schemaEl.getAttribute('version'));
+ }
+
+ this.currentSchema.setSourceURI(systemId);
+ }
+
+ private handleSchemaElementChild(schemaEl: Element, el: Element): void {
+ if (el.localName === 'simpleType') {
+ const type = this.handleSimpleType(this.currentSchema, el, schemaEl, true);
+ this.collection.resolveType(type.getQName()!, type);
+ } else if (el.localName === 'complexType') {
+ const type = this.handleComplexType(this.currentSchema, el, schemaEl, true);
+ this.collection.resolveType(type.getQName()!, type);
+ } else if (el.localName === 'element') {
+ this.handleElement(this.currentSchema, el, schemaEl, true);
+ } else if (el.localName === 'include') {
+ this.handleInclude(this.currentSchema, el, schemaEl);
+ } else if (el.localName === 'import') {
+ this.handleImport(this.currentSchema, el, schemaEl);
+ } else if (el.localName === 'group') {
+ this.handleGroup(this.currentSchema, el, schemaEl);
+ } else if (el.localName === 'attributeGroup') {
+ this.handleAttributeGroup(this.currentSchema, el, schemaEl);
+ } else if (el.localName === 'attribute') {
+ this.handleAttribute(this.currentSchema, el, schemaEl, true);
+ } else if (el.localName === 'redefine') {
+ this.handleRedefine(this.currentSchema, el, schemaEl);
+ } else if (el.localName === 'notation') {
+ this.handleNotation(this.currentSchema, el);
+ } else if (el.localName === 'annotation') {
+ const annotation = this.handleAnnotation(el);
+ this.currentSchema.setAnnotation(annotation);
+ }
+ }
+
+ private handleSequence(schema: XmlSchema, sequenceEl: Element, schemaEl: Element) {
+ const sequence = new XmlSchemaSequence();
+
+ // handle min and max occurences
+ sequence.setMinOccurs(this.getMinOccurs(sequenceEl));
+ sequence.setMaxOccurs(this.getMaxOccurs(sequenceEl));
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(sequenceEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'sequence') {
+ const seq = this.handleSequence(schema, el, schemaEl);
+ sequence.getItems().push(seq);
+ } else if (el.localName === 'element') {
+ const element = this.handleElement(schema, el, schemaEl, false);
+ sequence.getItems().push(element);
+ } else if (el.localName === 'group') {
+ const group = this.handleGroupRef(schema, el, schemaEl);
+ sequence.getItems().push(group);
+ } else if (el.localName === 'choice') {
+ const choice = this.handleChoice(schema, el, schemaEl);
+ sequence.getItems().push(choice);
+ } else if (el.localName === 'any') {
+ const any = this.handleAny(schema, el, schemaEl);
+ sequence.getItems().push(any);
+ } else if (el.localName === 'annotation') {
+ const annotation = this.handleAnnotation(el);
+ sequence.setAnnotation(annotation);
+ }
+ }
+ return sequence;
+ }
+
+ private handleSimpleContent(schema: XmlSchema, simpleEl: Element, schemaEl: Element) {
+ const simpleContent = new XmlSchemaSimpleContent();
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(simpleEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'restriction') {
+ simpleContent.content = this.handleSimpleContentRestriction(schema, el, schemaEl);
+ } else if (el.localName === 'extension') {
+ simpleContent.content = this.handleSimpleContentExtension(schema, el, schemaEl);
+ } else if (el.localName === 'annotation') {
+ simpleContent.setAnnotation(this.handleAnnotation(el));
+ }
+ }
+ return simpleContent;
+ }
+
+ private handleSimpleContentExtension(schema: XmlSchema, extEl: Element, schemaEl: Element) {
+ const ext = new XmlSchemaSimpleContentExtension();
+
+ if (extEl.hasAttribute('base')) {
+ const name = extEl.getAttribute('base')!;
+ ext.setBaseTypeName(this.getRefQName(name, extEl));
+ }
+
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(extEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'attribute') {
+ const attr = this.handleAttribute(schema, el, schemaEl);
+ ext.getAttributes().push(attr);
+ } else if (el.localName === 'attributeGroup') {
+ const attrGroup = this.handleAttributeGroupRef(schema, el);
+ ext.getAttributes().push(attrGroup);
+ } else if (el.localName === 'anyAttribute') {
+ ext.setAnyAttribute(this.handleAnyAttribute(schema, el, schemaEl));
+ } else if (el.localName === 'annotation') {
+ const ann = this.handleAnnotation(el);
+ ext.setAnnotation(ann);
+ }
+ }
+ return ext;
+ }
+
+ private handleSimpleContentRestriction(schema: XmlSchema, restrictionEl: Element, schemaEl: Element) {
+ const restriction = new XmlSchemaSimpleContentRestriction();
+
+ if (restrictionEl.hasAttribute('base')) {
+ const name = restrictionEl.getAttribute('base')!;
+ restriction.setBaseTypeName(this.getRefQName(name, restrictionEl));
+ }
+
+ if (restrictionEl.hasAttribute('id')) {
+ restriction.setId(restrictionEl.getAttribute('id'));
+ }
+
+ // check back simpleContent tag children to add attributes and
+ // simpleType if any occur
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(restrictionEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName === 'attribute') {
+ const attr = this.handleAttribute(schema, el, schemaEl);
+ restriction.getAttributes().push(attr);
+ } else if (el.localName === 'attributeGroup') {
+ const attrGroup = this.handleAttributeGroupRef(schema, el);
+ restriction.getAttributes().push(attrGroup);
+ } else if (el.localName === 'simpleType') {
+ restriction.setBaseType(this.handleSimpleType(schema, el, schemaEl, false));
+ } else if (el.localName === 'anyAttribute') {
+ restriction.anyAttribute = this.handleAnyAttribute(schema, el, schemaEl);
+ } else if (el.localName === 'annotation') {
+ restriction.setAnnotation(this.handleAnnotation(el));
+ } else {
+ const facet = XmlSchemaFacetConstructor.construct(el);
+ const annotation = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotation != null) {
+ const facetAnnotation = this.handleAnnotation(annotation);
+ facet.setAnnotation(facetAnnotation);
+ }
+ restriction.getFacets().push(facet);
+ // process extra attributes and elements
+ this.processExtensibilityComponents(facet, el, true);
+ }
+ }
+ return restriction;
+ }
+
+ private handleSimpleTypeFinal(simpleEl: Element, simpleType: XmlSchemaSimpleType) {
+ if (simpleEl.hasAttribute('final')) {
+ const finalstr = simpleEl.getAttribute('final')!;
+ simpleType.setFinal(XmlSchemaDerivationMethod.schemaValueOf(finalstr));
+ }
+ }
+
+ private handleSimpleTypeList(schema: XmlSchema, schemaEl: Element, simpleType: XmlSchemaSimpleType, listEl: Element) {
+ const list = new XmlSchemaSimpleTypeList();
+
+ /******
+ * if( list has an itemType attribute ) set the baseTypeName and look up the base type else if( list
+ * has a SimpleTypeElement as child) get that element and do a handleSimpleType set the list has the
+ * content of the simpleType
+ */
+ const inlineListType = XDOMUtil.getFirstChildElementNS(listEl, XmlSchema.SCHEMA_NS, 'simpleType');
+ if (listEl.hasAttribute('itemType')) {
+ const name = listEl.getAttribute('itemType')!;
+ list.itemTypeName = this.getRefQName(name, listEl);
+ } else if (inlineListType != null) {
+ list.itemType = this.handleSimpleType(schema, inlineListType, schemaEl, false);
+ }
+
+ const listAnnotationEl = XDOMUtil.getFirstChildElementNS(listEl, XmlSchema.SCHEMA_NS, 'annotation');
+ if (listAnnotationEl != null) {
+ const listAnnotation = this.handleAnnotation(listAnnotationEl);
+ list.setAnnotation(listAnnotation);
+ }
+ simpleType.content = list;
+ }
+
+ private handleSimpleTypeRestriction(
+ schema: XmlSchema,
+ schemaEl: Element,
+ simpleType: XmlSchemaSimpleType,
+ restrictionEl: Element,
+ ) {
+ const restriction = new XmlSchemaSimpleTypeRestriction();
+
+ const restAnnotationEl = XDOMUtil.getFirstChildElementNS(restrictionEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (restAnnotationEl != null) {
+ const restAnnotation = this.handleAnnotation(restAnnotationEl);
+ restriction.setAnnotation(restAnnotation);
+ }
+ /**
+ * if (restriction has a base attribute ) set the baseTypeName and look up the base type else if(
+ * restriction has a SimpleType Element as child) get that element and do a handleSimpleType; get the
+ * children of restriction other than annotation and simpleTypes and construct facets from it; set the
+ * restriction has the content of the simpleType
+ **/
+
+ const inlineSimpleType = XDOMUtil.getFirstChildElementNS(restrictionEl, XmlSchema.SCHEMA_NS, 'simpleType');
+
+ if (restrictionEl.hasAttribute('base')) {
+ const ctx = NodeNamespaceContext.getNamespaceContext(restrictionEl);
+ restriction.setBaseTypeName(this.getRefQName(restrictionEl.getAttribute('base')!, undefined, ctx));
+ } else if (inlineSimpleType != null) {
+ restriction.setBaseType(this.handleSimpleType(schema, inlineSimpleType, schemaEl, false));
+ }
+ for (
+ let el = XDOMUtil.getFirstChildElementNS(restrictionEl, XmlSchema.SCHEMA_NS);
+ el != null;
+ el = XDOMUtil.getNextSiblingElementNS(el, XmlSchema.SCHEMA_NS)
+ ) {
+ if (el.localName !== 'annotation' && el.localName !== 'simpleType') {
+ const facet = XmlSchemaFacetConstructor.construct(el);
+ const annotation = XDOMUtil.getFirstChildElementNS(el, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (annotation != null) {
+ const facetAnnotation = this.handleAnnotation(annotation);
+ facet.setAnnotation(facetAnnotation);
+ }
+ // process extra attributes and elements
+ this.processExtensibilityComponents(facet, el, true);
+ restriction.getFacets().push(facet);
+ }
+ }
+ simpleType.content = restriction;
+ }
+
+ private handleSimpleTypeUnion(
+ schema: XmlSchema,
+ schemaEl: Element,
+ simpleType: XmlSchemaSimpleType,
+ unionEl: Element,
+ ) {
+ const union = new XmlSchemaSimpleTypeUnion();
+
+ /******
+ * if( union has a memberTypes attribute ) add the memberTypeSources string for (each memberType in
+ * the list ) lookup(memberType) for( all SimpleType child Elements) add the simpleTypeName (if any)
+ * to the memberType Sources do a handleSimpleType with the simpleTypeElement
+ */
+ if (unionEl.hasAttribute('memberTypes')) {
+ const memberTypes = unionEl.getAttribute('memberTypes')!;
+ union.setMemberTypesSource(memberTypes);
+ const v: QName[] = [];
+ for (const member of memberTypes.split(' ')) {
+ v.push(this.getRefQName(member, unionEl));
+ }
+ union.setMemberTypesQNames(v);
+ }
+
+ let inlineUnionType = XDOMUtil.getFirstChildElementNS(unionEl, XmlSchema.SCHEMA_NS, 'simpleType');
+ while (inlineUnionType != null) {
+ const unionSimpleType = this.handleSimpleType(schema, inlineUnionType, schemaEl, false);
+
+ union.getBaseTypes().push(unionSimpleType);
+
+ if (!unionSimpleType.isAnonymous()) {
+ union.setMemberTypesSource(union.getMemberTypesSource() + ' ' + unionSimpleType.getName());
+ }
+
+ inlineUnionType = XDOMUtil.getNextSiblingElementNS(inlineUnionType, XmlSchema.SCHEMA_NS, 'simpleType');
+ }
+
+ // NodeList annotations = unionEl.getElementsByTagNameNS(
+ // XmlSchema.SCHEMA_NS, "annotation");
+ const unionAnnotationEl = XDOMUtil.getFirstChildElementNS(unionEl, XmlSchema.SCHEMA_NS, 'annotation');
+
+ if (unionAnnotationEl != null) {
+ const unionAnnotation = this.handleAnnotation(unionAnnotationEl);
+
+ union.setAnnotation(unionAnnotation);
+ }
+ simpleType.content = union;
+ }
+
+ private newIncludeValidator(schema: XmlSchema) {
+ return (pSchema: XmlSchema) => {
+ const isEmpty = (pValue?: string | null) => {
+ return pValue == null || Constants.NULL_NS_URI === pValue;
+ };
+ if (isEmpty(pSchema.getSyntacticalTargetNamespace())) {
+ pSchema.setLogicalTargetNamespace(schema.getLogicalTargetNamespace());
+ } else {
+ if (pSchema.getSyntacticalTargetNamespace() !== schema.getLogicalTargetNamespace()) {
+ let msg = 'An included schema was announced to have the default target namespace';
+ if (!isEmpty(schema.getLogicalTargetNamespace())) {
+ msg += ' or the target namespace ' + schema.getLogicalTargetNamespace();
+ }
+ throw new Error(msg + ', but has the target namespace ' + pSchema.getLogicalTargetNamespace());
+ }
+ }
+ };
+ }
+
+ private processExtensibilityComponents(
+ schemaObject: XmlSchemaObject,
+ parentElement: Element,
+ namespaces: boolean,
+ ): void {
+ if (this.extReg != null) {
+ // process attributes
+ const attributes = parentElement.attributes;
+ for (let i = 0; i < attributes.length; i++) {
+ const attribute = attributes.item(i) as Attr;
+
+ const namespaceURI = attribute.namespaceURI;
+ const name = attribute.localName;
+
+ if (
+ namespaceURI != null &&
+ '' !== namespaceURI && // ignore unqualified attributes
+ // ignore namespaces
+ (namespaces || !namespaceURI.startsWith(Constants.XMLNS_ATTRIBUTE_NS_URI)) &&
+ // does not belong to the schema namespace by any chance!
+ Constants.URI_2001_SCHEMA_XSD !== namespaceURI
+ ) {
+ const qName = new QName(namespaceURI, name);
+ this.extReg.deserializeExtension(schemaObject, qName, attribute);
+ }
+ }
+
+ // process elements
+ let child = parentElement.firstChild;
+ while (child != null) {
+ if (child.nodeType == Node.ELEMENT_NODE) {
+ const extElement = child as Element;
+ const namespaceURI = extElement.namespaceURI;
+ const name = extElement.localName;
+
+ if (namespaceURI != null && Constants.URI_2001_SCHEMA_XSD !== namespaceURI) {
+ // does not belong to the schema namespace
+ const qName = new QName(namespaceURI, name);
+ this.extReg.deserializeExtension(schemaObject, qName, extElement);
+ }
+ }
+ child = child.nextSibling;
+ }
+ }
+ }
+
+ /**
+ * Add an XmlSchema to the cache if the current thread has the cache enabled. The first three parameters
+ * are used to construct a key
+ *
+ * @param targetNamespace
+ * @param schemaLocation
+ * @param baseUri This parameter is the value put under the key (if the cache is enabled)
+ * @param readSchema
+ */
+ private putCachedSchema(targetNamespace: string, schemaLocation: string, baseUri: string, readSchema: XmlSchema) {
+ if (this.resolvedSchemas != null) {
+ const schemaKey = targetNamespace + schemaLocation + baseUri;
+ this.resolvedSchemas.set(schemaKey, readSchema);
+ }
+ }
+}
diff --git a/packages/xml-schema-ts/src/SchemaKey.ts b/packages/xml-schema-ts/src/SchemaKey.ts
new file mode 100644
index 000000000..ed71570bd
--- /dev/null
+++ b/packages/xml-schema-ts/src/SchemaKey.ts
@@ -0,0 +1,21 @@
+export class SchemaKey {
+ private namespace: string;
+ private systemId: string;
+
+ constructor(namespace?: string | null, systemId?: string | null) {
+ this.namespace = namespace != null ? namespace : '';
+ this.systemId = systemId != null ? systemId : '';
+ }
+
+ toString() {
+ return this.namespace === '' ? this.systemId : `{${this.namespace}}${this.systemId}`;
+ }
+
+ getNamespace() {
+ return this.namespace;
+ }
+
+ getSystemId() {
+ return this.systemId;
+ }
+}
diff --git a/packages/xml-schema-ts/src/TypeReceiver.ts b/packages/xml-schema-ts/src/TypeReceiver.ts
new file mode 100644
index 000000000..10d9bbec0
--- /dev/null
+++ b/packages/xml-schema-ts/src/TypeReceiver.ts
@@ -0,0 +1,5 @@
+import { XmlSchemaType } from './XmlSchemaType';
+
+export interface TypeReceiver {
+ setType(type: XmlSchemaType): void;
+}
diff --git a/packages/xml-schema-ts/src/XmlSchema.ts b/packages/xml-schema-ts/src/XmlSchema.ts
new file mode 100644
index 000000000..d7cb02b12
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchema.ts
@@ -0,0 +1,801 @@
+import type { XmlSchemaAttribute } from './attribute/XmlSchemaAttribute';
+import type { XmlSchemaAttributeGroup } from './attribute/XmlSchemaAttributeGroup';
+import type { XmlSchemaCollection } from './XmlSchemaCollection';
+import type { XmlSchemaElement } from './particle/XmlSchemaElement';
+import type { XmlSchemaExternal } from './external/XmlSchemaExternal';
+import type { XmlSchemaGroup } from './XmlSchemaGroup';
+import type { XmlSchemaNotation } from './XmlSchemaNotation';
+import type { XmlSchemaObject } from './XmlSchemaObject';
+import type { XmlSchemaType } from './XmlSchemaType';
+import type { NamespaceContextOwner } from './utils/NamespaceContextOwner';
+import type { NamespacePrefixList } from './utils/NamespacePrefixList';
+
+import { QName } from './QName';
+import { SchemaKey } from './SchemaKey';
+import { URI_2001_SCHEMA_XSD } from './constants';
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+import { XmlSchemaDerivationMethod } from './XmlSchemaDerivationMethod';
+import { XmlSchemaForm } from './XmlSchemaForm';
+import { XmlSchemaImport } from './external/XmlSchemaImport';
+import { XmlSchemaInclude } from './external/XmlSchemaInclude';
+import { QNameMap } from './utils/ObjectMap';
+
+export class XmlSchema extends XmlSchemaAnnotated implements NamespaceContextOwner {
+ static readonly SCHEMA_NS = URI_2001_SCHEMA_XSD;
+ static readonly UTF_8_ENCODING = 'UTF-8';
+
+ private items: XmlSchemaObject[] = [];
+ private parent: XmlSchemaCollection | null = null;
+ private blockDefault = XmlSchemaDerivationMethod.NONE;
+ private finalDefault = XmlSchemaDerivationMethod.NONE;
+ private elementFormDefault = XmlSchemaForm.UNQUALIFIED;
+ private attributeFormDefault = XmlSchemaForm.UNQUALIFIED;
+ private externals: XmlSchemaExternal[] = [];
+ private attributeGroups = new QNameMap();
+ private attributes = new QNameMap();
+ private elements = new QNameMap();
+ private groups = new QNameMap();
+ private notations = new QNameMap();
+ private schemaTypes = new QNameMap();
+ private syntacticalTargetNamespace: string | null = null;
+ private schemaNamespacePrefix: string | null = null;
+ private logicalTargetNamespace: string | null = null;
+ private version: string | null = null;
+ private namespaceContext: NamespacePrefixList | null = null;
+ private inputEncoding: string | null = null;
+
+ constructor(namespace?: string, systemId?: string, parent?: XmlSchemaCollection) {
+ super();
+ if (namespace == null) return;
+ const systemIdToUse = systemId ? systemId : namespace;
+ this.parent = parent || null;
+ this.logicalTargetNamespace = namespace;
+ this.syntacticalTargetNamespace = namespace;
+ const schemaKey = new SchemaKey(this.logicalTargetNamespace, systemIdToUse);
+ if (this.parent?.containsSchema(schemaKey)) {
+ throw new Error(`Schema name '${schemaKey.toString()}' conflicts in collection`);
+ }
+ this.parent?.addSchema(schemaKey, this);
+ }
+
+ /**
+ * Return an array of DOM documents consisting of this schema and any schemas that it references.
+ * Referenced schemas are only returned if the {@link XmlSchemaExternal} objects corresponding to them
+ * have their 'schema' fields filled in.
+ *
+ * @return DOM documents.
+ getAllSchemas() {
+ const xser = new XmlSchemaSerializer();
+ xser.setExtReg(this.parent.getExtReg());
+ return xser.serializeSchema(this, true);
+
+ } catch (XmlSchemaSerializer.XmlSchemaSerializerException e) {
+ throw new XmlSchemaException("Error serializing schema", e);
+ }
+ }
+ */
+
+ /**
+ *
+ * @param name
+ * @param deep
+ * @param schemaStack
+ * @protected
+ */
+ getAttributeByQName(name: QName, deep: boolean = true, schemaStack?: XmlSchema[]): XmlSchemaAttribute | null {
+ if (schemaStack != null && schemaStack.includes(this)) {
+ // recursive schema - just return null
+ return null;
+ }
+ let attribute = this.attributes.get(name) as XmlSchemaAttribute | null;
+ if (deep) {
+ if (attribute == null) {
+ // search the imports
+ for (const item of this.externals) {
+ const schema = this.getSchema(item);
+
+ if (schema != null) {
+ if (schemaStack == null) {
+ schemaStack = [];
+ }
+ schemaStack.push(this);
+ attribute = schema.getAttributeByQName(name, deep, schemaStack);
+ if (attribute != null) {
+ return attribute;
+ }
+ }
+ }
+ } else {
+ return attribute;
+ }
+ }
+ return attribute;
+ }
+
+ /**
+ * Look for an attribute by its local name.
+ *
+ * @param name
+ * @return the attribute
+ */
+ getAttributeByName(name: string) {
+ const nameToSearchFor = new QName(this.getTargetNamespace(), name);
+ return this.getAttributeByQName(nameToSearchFor, false);
+ }
+
+ /**
+ * @return the default attribute form for this schema.
+ */
+ getAttributeFormDefault() {
+ return this.attributeFormDefault;
+ }
+
+ /**
+ * Retrieve an attribute group by QName.
+ *
+ * @param name
+ * @param deep
+ * @param schemaStack
+ * @return
+ */
+ getAttributeGroupByQName(
+ name: QName,
+ deep: boolean = true,
+ schemaStack?: XmlSchema[],
+ ): XmlSchemaAttributeGroup | null {
+ if (schemaStack != null && schemaStack.includes(this)) {
+ // recursive schema - just return null
+ return null;
+ }
+
+ let group = this.attributeGroups.get(name) || null;
+ if (deep) {
+ if (group == null) {
+ // search the imports
+ for (const item of this.externals) {
+ const schema = this.getSchema(item);
+
+ if (schema != null) {
+ // create an empty stack - push the current parent in
+ // and
+ // use the protected method to process the schema
+ if (schemaStack == null) {
+ schemaStack = [];
+ }
+ schemaStack.push(this);
+ group = schema.getAttributeGroupByQName(name, deep, schemaStack);
+ if (group != null) {
+ return group;
+ }
+ }
+ }
+ } else {
+ return group;
+ }
+ }
+ return group;
+ }
+
+ /**
+ * Return a map containing all the defined attribute groups of this schema. The keys are QNames, where the
+ * namespace will always be the target namespace of this schema. This makes it easier to look up items for
+ * cross-schema references.
+ *
+ * If org.apache.ws.commons.schema.protectReadOnlyCollections
+ * is 'true', this will return a map that checks at runtime.
+ *
+ * @return the map of attribute groups.
+ */
+ getAttributeGroups() {
+ return this.attributeGroups;
+ }
+
+ /**
+ * Return a map containing all the defined attributes of this schema. The keys are QNames, where the
+ * namespace will always be the target namespace of this schema. This makes it easier to look up items for
+ * cross-schema references.
+ *
+ * If org.apache.ws.commons.schema.protectReadOnlyCollections
+ * is 'true', this will return a map that checks at runtime.
+ *
+ * @return the map of attributes.
+ */
+ getAttributes() {
+ return this.attributes;
+ }
+
+ /**
+ * Return the default block value for this schema.
+ *
+ * @return the default block value.
+ */
+ getBlockDefault() {
+ return this.blockDefault;
+ }
+
+ /**
+ * Look for a element by its QName.
+ *
+ * @param name
+ * @param deep
+ * @param schemaStack
+ * @return the element.
+ */
+ getElementByQName(name: QName, deep: boolean = true, schemaStack?: XmlSchema[]): XmlSchemaElement | null {
+ if (schemaStack != null && schemaStack.includes(this)) {
+ // recursive schema - just return null
+ return null;
+ }
+
+ let element = this.elements.get(name) || null;
+ if (deep) {
+ if (element == null) {
+ // search the imports
+ for (const item of this.externals) {
+ const schema = this.getSchema(item);
+
+ if (schema != null) {
+ // create an empty stack - push the current parent in
+ // and
+ // use the protected method to process the schema
+ if (schemaStack == null) {
+ schemaStack = [];
+ }
+ schemaStack.push(this);
+ element = schema.getElementByQName(name, deep, schemaStack);
+ if (element != null) {
+ return element;
+ }
+ }
+ }
+ } else {
+ return element;
+ }
+ }
+ return element;
+ }
+
+ /**
+ * get an element by its local name.
+ *
+ * @param name
+ * @return the element.
+ */
+ getElementByName(name: string) {
+ const nameToSearchFor = new QName(this.getTargetNamespace(), name);
+ return this.getElementByQName(nameToSearchFor, false);
+ }
+
+ /**
+ * @return the default element form for this schema.
+ */
+ getElementFormDefault() {
+ return this.elementFormDefault;
+ }
+
+ /**
+ * Return a map containing all the defined elements of this schema. The keys are QNames, where the
+ * namespace will always be the target namespace of this schema. This makes it easier to look up items for
+ * cross-schema references.
+ *
+ * If org.apache.ws.commons.schema.protectReadOnlyCollections
+ * is 'true', this will return a map that checks at runtime
+ *
+ * @return the map of elements.
+ */
+ getElements(): QNameMap {
+ return this.elements;
+ }
+
+ /**
+ * Return all of the includes, imports, and redefines for this schema.
+ *
+ * If org.apache.ws.commons.schema.protectReadOnlyCollections
+ * is 'true', this will return a list that checks at runtime
+ *
+ * @return a list of the objects representing includes, imports, and redefines.
+ */
+ getExternals() {
+ return this.externals;
+ }
+
+ /**
+ * @return the default 'final' value for this schema.
+ */
+ getFinalDefault() {
+ return this.finalDefault;
+ }
+
+ /**
+ * Retrieve a group by QName.
+ *
+ * @param name
+ * @param deep
+ * @param schemaStack
+ * @return
+ */
+ getGroupByQName(name: QName, deep: boolean = true, schemaStack?: XmlSchema[]): XmlSchemaGroup | null {
+ if (schemaStack != null && schemaStack.includes(this)) {
+ // recursive schema - just return null
+ return null;
+ }
+ let group = this.groups.get(name) || null;
+ if (deep) {
+ if (group == null) {
+ // search the imports
+ for (const item of this.externals) {
+ const schema = this.getSchema(item);
+
+ if (schema != null) {
+ // create an empty stack - push the current parent in
+ // and
+ // use the protected method to process the schema
+ if (schemaStack == null) {
+ schemaStack = [];
+ }
+ schemaStack.push(this);
+ group = schema.getGroupByQName(name, deep, schemaStack);
+ if (group != null) {
+ return group;
+ }
+ }
+ }
+ } else {
+ return group;
+ }
+ }
+ return group;
+ }
+
+ /**
+ * Return a map containing all the defined groups of this schema. The keys are QNames, where the namespace
+ * will always be the target namespace of this schema. This makes it easier to look up items for
+ * cross-schema references.
+ * If org.apache.ws.commons.schema.protectReadOnlyCollections
+ * is 'true', this will return a map that checks at runtime
+ *
+ * @return the map of groups.
+ */
+ getGroups() {
+ return this.groups;
+ }
+
+ /**
+ * Return the character encoding for this schema. This will only be present if either the schema was read
+ * from an XML document or there was a call to {@link #setInputEncoding(String)}.
+ *
+ * @return
+ */
+ getInputEncoding() {
+ return this.inputEncoding;
+ }
+
+ /**
+ * Return all of the global items in this schema.
+ * If org.apache.ws.commons.schema.protectReadOnlyCollections
+ * is 'true', this will return a map that checks at runtime.
+ * @return all of the global items from this schema.
+ *
+ */
+ getItems() {
+ return this.items;
+ }
+
+ /**
+ * Return the logical target namespace. If a schema document has no target namespace, but it is referenced
+ * via an xs:include or xs:redefine, its logical target namespace is the target namespace of the including
+ * schema.
+ *
+ * @return the logical target namespace.
+ */
+ getLogicalTargetNamespace() {
+ return this.logicalTargetNamespace;
+ }
+
+ getNamespaceContext(): NamespacePrefixList | null {
+ return this.namespaceContext;
+ }
+
+ /**
+ * Retrieve a notation by QName.
+ *
+ * @param name
+ * @param deep
+ * @param schemaStack
+ * @return the notation
+ */
+ getNotationByQName(name: QName, deep: boolean = true, schemaStack?: XmlSchema[]): XmlSchemaNotation | null {
+ if (schemaStack != null && schemaStack.includes(this)) {
+ // recursive schema - just return null
+ return null;
+ }
+ let notation = this.notations.get(name) || null;
+ if (deep) {
+ if (notation == null) {
+ // search the imports
+ for (const item of this.externals) {
+ const schema = this.getSchema(item);
+
+ if (schema != null) {
+ // create an empty stack - push the current parent in
+ // and
+ // use the protected method to process the schema
+ if (schemaStack == null) {
+ schemaStack = [];
+ }
+ schemaStack.push(this);
+ notation = schema.getNotationByQName(name, deep, schemaStack);
+ if (notation != null) {
+ return notation;
+ }
+ }
+ }
+ } else {
+ return notation;
+ }
+ }
+ return notation;
+ }
+
+ /**
+ * Return a map containing all the defined notations of this schema. The keys are QNames, where the
+ * namespace will always be the target namespace of this schema. This makes it easier to look up items for
+ * cross-schema references.
+ *
+ * If org.apache.ws.commons.schema.protectReadOnlyCollections
+ * is 'true', this will return a map that checks at runtime.
+ *
+ * @return the map of notations.
+ */
+ getNotations() {
+ return this.notations;
+ }
+
+ /**
+ * Return the parent XmlSchemaCollection. If this schema was not initialized in a collection the return
+ * value will be null.
+ *
+ * @return the parent collection.
+ */
+ getParent() {
+ return this.parent;
+ }
+
+ /**
+ * Retrieve a DOM tree for this one schema, independent of any included or related schemas.
+ *
+ * @return The DOM document.
+ * @throws XmlSchemaSerializerException
+ getSchemaDocument() {
+ const xser = new XmlSchemaSerializer();
+ xser.setExtReg(this.parent.getExtReg());
+ return xser.serializeSchema(this, false)[0];
+ }
+ */
+
+ /**
+ * @return the namespace prefix for the target namespace.
+ */
+ getSchemaNamespacePrefix() {
+ return this.schemaNamespacePrefix;
+ }
+
+ /**
+ * Return a map containing all the defined types of this schema. The keys are QNames, where the namespace
+ * will always be the target namespace of this schema. This makes it easier to look up items for
+ * cross-schema references.
+ *
+ * @return the map of types.
+ */
+ getSchemaTypes() {
+ return this.schemaTypes;
+ }
+
+ /**
+ * Return the declared target namespace of this schema.
+ *
+ * @see #getLogicalTargetNamespace()
+ * @return the namespace URI.
+ */
+ getTargetNamespace() {
+ return this.syntacticalTargetNamespace;
+ }
+
+ /**
+ * Search this schema, and its peers in its parent collection, for a schema type specified by QName.
+ *
+ * @param name the type name.
+ * @param deep
+ * @param schemaStack
+ * @return the type.
+ */
+ getTypeByQName(name: QName, deep: boolean = true, schemaStack?: XmlSchema[]): XmlSchemaType | null {
+ if (schemaStack != null && schemaStack.includes(this)) {
+ // recursive schema - just return null
+ return null;
+ }
+ let type = this.schemaTypes.get(name) || null;
+
+ if (deep) {
+ if (type == null) {
+ // search the imports
+ for (const item of this.externals) {
+ const schema = this.getSchema(item);
+
+ if (schema != null) {
+ // create an empty stack - push the current parent
+ // use the protected method to process the schema
+ if (schemaStack == null) {
+ schemaStack = [];
+ }
+ schemaStack.push(this);
+ type = schema.getTypeByQName(name, deep, schemaStack);
+ if (type != null) {
+ return type;
+ }
+ }
+ }
+ } else {
+ return type;
+ }
+ }
+ return type;
+ }
+
+ /**
+ * Retrieve a named type from this schema.
+ *
+ * @param name
+ * @return the type.
+ */
+ getTypeByName(name: string) {
+ const nameToSearchFor = new QName(this.getTargetNamespace(), name);
+ return this.getTypeByQName(nameToSearchFor, false);
+ }
+
+ /**
+ * Return the declared XML Schema version of this schema. XmlSchema supports only version 1.0.
+ *
+ * @return
+ */
+ getVersion() {
+ return this.version;
+ }
+
+ /**
+ * Set the declared XML Schema version of this schema
+ *
+ * @param version the new version.
+ */
+ setVersion(version: string | null) {
+ this.version = version;
+ }
+
+ /**
+ * Set the default attribute form for this schema.
+ *
+ * @param attributeFormDefault
+ */
+ setAttributeFormDefault(attributeFormDefault: XmlSchemaForm) {
+ this.attributeFormDefault = attributeFormDefault;
+ }
+
+ /**
+ * Set the default block value for this schema.
+ *
+ * @param blockDefault the new block value.
+ */
+ setBlockDefault(blockDefault: XmlSchemaDerivationMethod) {
+ this.blockDefault = blockDefault;
+ }
+
+ /**
+ * Set the default element form for this schema.
+ *
+ * @param elementFormDefault the element form. This may not be null.
+ */
+ setElementFormDefault(elementFormDefault: XmlSchemaForm) {
+ this.elementFormDefault = elementFormDefault;
+ }
+
+ /**
+ * Set the default 'final' value for this schema. The value may not be null.
+ *
+ * @param finalDefault the new final value.
+ */
+ setFinalDefault(finalDefault: XmlSchemaDerivationMethod) {
+ this.finalDefault = finalDefault;
+ }
+
+ /**
+ * Set the character encoding name for the schema. This is typically set when reading a schema from an XML
+ * file, so that it can be written back out in the same encoding.
+ *
+ * @param encoding Character encoding name.
+ */
+ setInputEncoding(encoding: string) {
+ this.inputEncoding = encoding;
+ }
+
+ /**
+ * Sets the schema elements namespace context. This may be used for schema serialization, until a better
+ * mechanism was found.
+ */
+ setNamespaceContext(namespaceContext: NamespacePrefixList): void {
+ this.namespaceContext = namespaceContext;
+ }
+
+ /**
+ * Set the namespace prefix corresponding to the target namespace.
+ *
+ * @param schemaNamespacePrefix
+ */
+ setSchemaNamespacePrefix(schemaNamespacePrefix: string) {
+ this.schemaNamespacePrefix = schemaNamespacePrefix;
+ }
+
+ /**
+ * Set the target namespace for this schema.
+ *
+ * @param targetNamespace the new target namespace URI. A value of "" is ignored.
+ */
+ setTargetNamespace(targetNamespace: string) {
+ if ('' !== targetNamespace) {
+ this.logicalTargetNamespace = targetNamespace;
+ this.syntacticalTargetNamespace = targetNamespace;
+ }
+ }
+
+ /**
+ * Serialize the schema as XML to the specified stream using the encoding established with
+ * {@link #setInputEncoding(String)}.
+ *
+ * @param out - the output stream to write to
+ * @throws UnsupportedEncodingException for an invalid encoding.
+ public void write(OutputStream out) throws UnsupportedEncodingException {
+ if (this.inputEncoding != null && !"".equals(this.inputEncoding)) {
+ write(new OutputStreamWriter(out, this.inputEncoding));
+} else {
+ // As per the XML spec the default is taken to be UTF 8
+ write(new OutputStreamWriter(out, UTF_8_ENCODING));
+}
+
+}
+ */
+
+ /**
+ * Serialize the schema as XML to the specified stream using the encoding established with
+ * {@link #setInputEncoding(String)}.
+ *
+ * @param out - the output stream to write to
+ * @param options - a map of options
+ * @throws UnsupportedEncodingException
+ *
+ *
+public void write(OutputStream out, Map options) throws UnsupportedEncodingException {
+ if (this.inputEncoding != null && !"".equals(this.inputEncoding)) {
+ write(new OutputStreamWriter(out, this.inputEncoding), options);
+ } else {
+ write(new OutputStreamWriter(out, UTF_8_ENCODING), options);
+ }
+}
+*/
+
+ /**
+ * Serialize the schema to a {@link java.io.Writer}.
+ *
+ * @param writer - the writer to write this
+public void write(Writer writer) {
+ serializeInternal(writer, null);
+}
+ */
+
+ /**
+ * Serialize the schema to a {@link java.io.Writer}.
+ *
+ * @param writer - the writer to write this
+public void write(Writer writer, Map options) {
+ serializeInternal(writer, options);
+}
+ */
+
+ getSyntacticalTargetNamespace() {
+ return this.syntacticalTargetNamespace;
+ }
+
+ setLogicalTargetNamespace(logicalTargetNamespace: string | null) {
+ this.logicalTargetNamespace = logicalTargetNamespace;
+ }
+
+ setParent(parent: XmlSchemaCollection) {
+ this.parent = parent;
+ }
+
+ setSyntacticalTargetNamespace(syntacticalTargetNamespace: string) {
+ this.syntacticalTargetNamespace = syntacticalTargetNamespace;
+ }
+
+ /**
+ * Get a schema from an import
+ *
+ * @param includeOrImport
+ * @return return the schema object.
+ */
+ private getSchema(includeOrImport: object): XmlSchema | null {
+ let schema: XmlSchema | null = null;
+ if (includeOrImport instanceof XmlSchemaImport) {
+ schema = (includeOrImport as XmlSchemaImport).getSchema();
+ } else if (includeOrImport instanceof XmlSchemaInclude) {
+ schema = (includeOrImport as XmlSchemaInclude).getSchema();
+ }
+ return schema;
+ }
+
+ /**
+ * Load the default options
+ *
+ * @param options - the map of
+ private loadDefaultOptions(options: Map ) {
+ options.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ options.put(OutputKeys.INDENT, "yes");
+ }
+ */
+
+ /**
+ * serialize the schema - this is the method tht does to work
+ *
+ * @param out
+ * @param options
+private void serializeInternal(Writer out, Map options) {
+
+ try {
+ XmlSchemaSerializer xser = new XmlSchemaSerializer();
+ xser.setExtReg(this.parent.getExtReg());
+ Document[] serializedSchemas = xser.serializeSchema(this, false);
+ TransformerFactory trFac = TransformerFactory.newInstance();
+ trFac.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+
+ try {
+ trFac.setAttribute("indent-number", "4");
+ } catch (IllegalArgumentException e) {
+ // do nothing - we'll just silently let this pass if it
+ // was not compatible
+ }
+
+ Source source = new DOMSource(serializedSchemas[0]);
+ Result result = new StreamResult(out);
+ javax.xml.transform.Transformer tr = trFac.newTransformer();
+
+ // use the input encoding if there is one
+ if (this.inputEncoding != null && !"".equals(this.inputEncoding)) {
+ tr.setOutputProperty(OutputKeys.ENCODING, this.inputEncoding);
+ }
+
+ // let these be configured from outside if any is present
+ // Note that one can enforce the encoding by passing the necessary
+ // property in options
+
+ if (options == null) {
+ options = new HashMap();
+ loadDefaultOptions(options);
+ }
+ Iterator keys = options.keySet().iterator();
+ while (keys.hasNext()) {
+ Object key = keys.next();
+ tr.setOutputProperty((String)key, options.get(key));
+ }
+
+ tr.transform(source, result);
+ out.flush();
+ } catch (TransformerConfigurationException e) {
+ throw new XmlSchemaException(e.getMessage());
+ } catch (TransformerException e) {
+ throw new XmlSchemaException(e.getMessage());
+ } catch (XmlSchemaSerializer.XmlSchemaSerializerException e) {
+ throw new XmlSchemaException(e.getMessage());
+ } catch (IOException e) {
+ throw new XmlSchemaException(e.getMessage());
+ }
+}
+ */
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaAnnotated.ts b/packages/xml-schema-ts/src/XmlSchemaAnnotated.ts
new file mode 100644
index 000000000..179b0b32b
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaAnnotated.ts
@@ -0,0 +1,30 @@
+import type { XmlSchemaAnnotation } from './annotation/XmlSchemaAnnotation';
+import { XmlSchemaObject } from './XmlSchemaObject';
+
+export class XmlSchemaAnnotated extends XmlSchemaObject {
+ private annotation?: XmlSchemaAnnotation;
+ private id?: string | null;
+ private unhandledAttributes?: Attr[];
+
+ getId() {
+ return this.id;
+ }
+ setId(id: string | null) {
+ this.id = id;
+ }
+ getAnnotation() {
+ return this.annotation;
+ }
+ setAnnotation(annotation: XmlSchemaAnnotation) {
+ this.annotation = annotation;
+ }
+ getUnhandledAttributes() {
+ return this.unhandledAttributes;
+ }
+ setUnhandledAttributes(unhandledAttributes: Attr[]) {
+ this.unhandledAttributes = unhandledAttributes;
+ }
+ toString() {
+ return this.id == null ? super.toString() : super.toString() + `[id:${this.id}]`;
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaAnyAttribute.ts b/packages/xml-schema-ts/src/XmlSchemaAnyAttribute.ts
new file mode 100644
index 000000000..067cf8752
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaAnyAttribute.ts
@@ -0,0 +1,27 @@
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+import { XmlSchemaContentProcessing } from './XmlSchemaContentProcessing';
+
+/**
+ * Enables any attribute from the specified namespace or namespaces to appear in the containing complexType
+ * element. Represents the World Wide Web Consortium (W3C) anyAttribute element.
+ */
+export class XmlSchemaAnyAttribute extends XmlSchemaAnnotated {
+ namespace: string | null = null;
+ processContent: XmlSchemaContentProcessing = XmlSchemaContentProcessing.NONE;
+
+ getNamespace() {
+ return this.namespace;
+ }
+
+ setNamespace(namespace: string) {
+ this.namespace = namespace;
+ }
+
+ getProcessContent() {
+ return this.processContent;
+ }
+
+ setProcessContent(processContent: XmlSchemaContentProcessing) {
+ this.processContent = processContent;
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaCollection.test.ts b/packages/xml-schema-ts/src/XmlSchemaCollection.test.ts
new file mode 100644
index 000000000..cf66d6044
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaCollection.test.ts
@@ -0,0 +1,144 @@
+import { XmlSchemaCollection } from './XmlSchemaCollection';
+import fs from 'fs';
+import { QName } from './QName';
+import { XmlSchemaComplexType } from './complex/XmlSchemaComplexType';
+import { XmlSchemaAttribute } from './attribute/XmlSchemaAttribute';
+import { XmlSchemaUse } from './XmlSchemaUse';
+import { XmlSchemaSequence } from './particle/XmlSchemaSequence';
+import { XmlSchemaElement } from './particle/XmlSchemaElement';
+import { XmlSchemaAttributeGroupRef } from './attribute/XmlSchemaAttributeGroupRef';
+import { XmlSchemaSimpleType } from './simple/XmlSchemaSimpleType';
+import { screen } from '@testing-library/react';
+import { XmlSchemaComplexContentExtension } from './complex/XmlSchemaComplexContentExtension';
+
+describe('XmlSchemaCollection', () => {
+ const orderXsd = fs.readFileSync(__dirname + '/../test-resources/ShipOrder.xsd').toString();
+ const testXsd = fs.readFileSync(__dirname + '/../test-resources/TestDocument.xsd').toString();
+ const namedTypesXsd = fs.readFileSync(__dirname + '/../test-resources/NamedTypes.xsd').toString();
+ const camelSpringXsd = fs.readFileSync(__dirname + '/../test-resources/camel-spring.xsd').toString();
+ const orderXsdEmptyFirstLine = fs
+ .readFileSync(__dirname + '/../test-resources/ShipOrderEmptyFirstLine.xsd')
+ .toString();
+
+ it('should parse ShipOrder XML schema', () => {
+ const collection = new XmlSchemaCollection();
+ const xmlSchema = collection.read(orderXsd, () => {});
+ const attributes = xmlSchema.getAttributes();
+ expect(attributes.size).toEqual(0);
+
+ const elements = xmlSchema.getElements();
+ expect(elements.size).toEqual(1);
+ const shipOrderElement = elements.get(new QName('io.kaoto.datamapper.poc.test', 'ShipOrder'));
+ expect(shipOrderElement!.getName()).toEqual('ShipOrder');
+ expect(shipOrderElement!.getWireName()?.getNamespaceURI()).toEqual('io.kaoto.datamapper.poc.test');
+ expect(shipOrderElement!.getWireName()?.getLocalPart()).toEqual('ShipOrder');
+ expect(shipOrderElement!.getMinOccurs()).toEqual(1);
+ expect(shipOrderElement!.getMaxOccurs()).toEqual(1);
+ const shipOrderComplexType = shipOrderElement!.getSchemaType() as XmlSchemaComplexType;
+ const shipOrderAttributes = shipOrderComplexType.getAttributes();
+ expect(shipOrderAttributes.length).toBe(1);
+ const orderIdAttr = shipOrderAttributes[0] as XmlSchemaAttribute;
+ expect(orderIdAttr.getName()).toEqual('OrderId');
+ expect(orderIdAttr.getWireName()?.getNamespaceURI()).toBe('');
+ expect(orderIdAttr.getWireName()?.getLocalPart()).toBe('OrderId');
+ expect(orderIdAttr.getSchemaType()).toBeNull();
+ expect(orderIdAttr.getSchemaTypeName()?.getLocalPart()).toEqual('string');
+ expect(orderIdAttr.getUse()).toEqual(XmlSchemaUse.REQUIRED);
+ expect(orderIdAttr.getFixedValue()).toEqual('2');
+
+ const shipOrderSequence = shipOrderComplexType.getParticle() as XmlSchemaSequence;
+ const shipOrderSequenceMembers = shipOrderSequence.getItems();
+ expect(shipOrderSequenceMembers.length).toBe(3);
+
+ const orderPerson = shipOrderSequenceMembers[0] as XmlSchemaElement;
+ expect(orderPerson.getSchemaType() instanceof XmlSchemaSimpleType).toBeTruthy();
+ expect(orderPerson.getSchemaTypeName()?.getLocalPart()).toEqual('string');
+ expect(orderPerson.getName()).toEqual('OrderPerson');
+ expect(orderPerson.getWireName()?.getNamespaceURI()).toEqual('io.kaoto.datamapper.poc.test');
+ expect(orderPerson.getWireName()?.getLocalPart()).toEqual('OrderPerson');
+ expect(orderPerson.getMinOccurs()).toEqual(1);
+ expect(orderPerson.getMaxOccurs()).toEqual(1);
+
+ const shipTo = shipOrderSequenceMembers[1] as XmlSchemaElement;
+ const shipToSchemaType = shipTo.getSchemaType() as XmlSchemaComplexType;
+ const shipToSequence = shipToSchemaType.getParticle() as XmlSchemaSequence;
+ const shipToSequenceMenbers = shipToSequence.getItems();
+ expect(shipToSequenceMenbers.length).toBe(4);
+ expect(shipTo.getSchemaTypeName()).toBeNull();
+ expect(shipTo.getName()).toEqual('ShipTo');
+ expect(shipTo.getWireName()?.getNamespaceURI()).toEqual('');
+ expect(shipTo.getWireName()?.getLocalPart()).toEqual('ShipTo');
+ expect(shipTo.getMinOccurs()).toEqual(1);
+ expect(shipTo.getMaxOccurs()).toEqual(1);
+
+ const item = shipOrderSequenceMembers[2] as XmlSchemaElement;
+ expect(item.getMaxOccurs()).toBe(Number.MAX_SAFE_INTEGER);
+ const itemSchemaType = item.getSchemaType() as XmlSchemaComplexType;
+ const itemSequence = itemSchemaType.getParticle() as XmlSchemaSequence;
+ const itemSequenceMembers = itemSequence.getItems();
+ expect(itemSequenceMembers.length).toEqual(4);
+ const itemNote = itemSequenceMembers[1] as XmlSchemaElement;
+ expect(itemNote.getMinOccurs()).toEqual(0);
+ const itemQuantity = itemSequenceMembers[2] as XmlSchemaElement;
+ expect(itemQuantity.getSchemaTypeName()?.getLocalPart()).toEqual('positiveInteger');
+ const itemPrice = itemSequenceMembers[3] as XmlSchemaElement;
+ expect(itemPrice.getSchemaTypeName()?.getLocalPart()).toEqual('decimal');
+ });
+
+ it('should parse TestDocument XML schema', () => {
+ const collection = new XmlSchemaCollection();
+ const xmlSchema = collection.read(testXsd, () => {});
+ const attributes = xmlSchema.getAttributes();
+ expect(attributes.size).toEqual(0);
+ const elements = xmlSchema.getElements();
+ expect(elements.size).toEqual(1);
+ const testDocumentElement = elements.get(new QName('io.kaoto.datamapper.poc.test', 'TestDocument'));
+ const testDocumentComplexType = testDocumentElement!.getSchemaType() as XmlSchemaComplexType;
+ const testDocumentAttributes = testDocumentComplexType.getAttributes();
+ expect(testDocumentAttributes.length).toBe(1);
+ const attrGroupRef = (testDocumentAttributes[0] as XmlSchemaAttributeGroupRef).getRef();
+ expect(attrGroupRef.getTarget()).toBeTruthy();
+ });
+
+ it('should parse NamedTypes XML schema', () => {
+ const collection = new XmlSchemaCollection();
+ const xmlSchema = collection.read(namedTypesXsd, () => {});
+ const elements = xmlSchema.getElements();
+ expect(elements.size).toEqual(1);
+ const element1 = elements.get(new QName('io.kaoto.datamapper.poc.test', 'Element1'));
+ const element1ComplexType = element1!.getSchemaType() as XmlSchemaComplexType;
+ const element1Sequence = element1ComplexType.getParticle() as XmlSchemaSequence;
+ const element1SequenceMembers = element1Sequence.getItems();
+ expect(element1SequenceMembers.length).toEqual(1);
+ const element1Simple1 = element1SequenceMembers[0] as XmlSchemaElement;
+ const element1Simple1SchemaType = element1Simple1.getSchemaType();
+ expect(element1Simple1.getWireName()?.getNamespaceURI()).toEqual('');
+ expect(element1Simple1.getWireName()?.getLocalPart()).toEqual('Element1Simple1');
+ });
+
+ it('should parse camel-spring XML schema', () => {
+ const collection = new XmlSchemaCollection();
+ const xmlSchema = collection.read(camelSpringXsd, () => {});
+ const aggregate = xmlSchema.getElements().get(new QName('http://camel.apache.org/schema/spring', 'aggregate'));
+ const aggregateComplexType = aggregate!.getSchemaType() as XmlSchemaComplexType;
+ expect(aggregateComplexType.getParticle()).toBeNull();
+ const aggregateComplexContent = aggregateComplexType
+ .getContentModel()
+ ?.getContent() as XmlSchemaComplexContentExtension;
+ expect(aggregateComplexContent.getBaseTypeName()?.getLocalPart()).toEqual('output');
+ expect(aggregateComplexContent.getAttributes().length).toEqual(22);
+ const particle = aggregateComplexContent.getParticle() as XmlSchemaSequence;
+ expect(particle.getItems().length).toEqual(6);
+ });
+
+ it('should parse ShipOrderEmptyFirstLine.xsd', () => {
+ const collection = new XmlSchemaCollection();
+ try {
+ collection.read(orderXsdEmptyFirstLine, () => {});
+ } catch (error) {
+ expect(error.message).toContain('an XML declaration must be at the start of the document');
+ return;
+ }
+ fail('No error was thrown');
+ });
+});
diff --git a/packages/xml-schema-ts/src/XmlSchemaCollection.ts b/packages/xml-schema-ts/src/XmlSchemaCollection.ts
new file mode 100644
index 000000000..eb1b8a64e
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaCollection.ts
@@ -0,0 +1,602 @@
+import type { QName } from './QName';
+import type { SchemaKey } from './SchemaKey';
+import type { TypeReceiver } from './TypeReceiver';
+import type { XmlSchemaFacet } from './facet/XmlSchemaFacet';
+import type { XmlSchemaType } from './XmlSchemaType';
+import type { CollectionURIResolver } from './resolver/CollectionURIResolver';
+import type { URIResolver } from './resolver/URIResolver';
+import type { NamespacePrefixList } from './utils/NamespacePrefixList';
+
+import { XmlSchema } from './XmlSchema';
+import { XmlSchemaMaxInclusiveFacet } from './facet/XmlSchemaMaxInclusiveFacet';
+import { XmlSchemaMinInclusiveFacet } from './facet/XmlSchemaMinInclusiveFacet';
+import { XmlSchemaPatternFacet } from './facet/XmlSchemaPatternFacet';
+import { XmlSchemaWhiteSpaceFacet } from './facet/XmlSchemaWhiteSpaceFacet';
+import { XmlSchemaSimpleTypeRestriction } from './simple/XmlSchemaSimpleTypeRestriction';
+import { XmlSchemaSimpleTypeList } from './simple/XmlSchemaSimpleTypeList';
+import { SchemaBuilder } from './SchemaBuilder';
+import { XmlSchemaSimpleType } from './simple/XmlSchemaSimpleType';
+import { ExtensionRegistry } from './extensions/ExtensionRegistry';
+import * as Constants from './constants';
+import { DefaultURIResolver } from './resolver/DefaultURIResolver';
+import { XmlSchemaFractionDigitsFacet } from './facet/XmlSchemaFractionDigitsFacet';
+import { QNameMap, SchemaKeyMap } from './utils/ObjectMap';
+
+export class XmlSchemaCollection {
+ baseUri: string | null;
+ private stack: SchemaKey[];
+ private unresolvedTypes: QNameMap;
+ private xsd: XmlSchema;
+ private extReg: ExtensionRegistry;
+
+ private knownNamespaceMap: Record;
+ private namespaceContext: NamespacePrefixList | null;
+ private schemaResolver: URIResolver;
+ private schemas: SchemaKeyMap;
+ constructor() {
+ this.baseUri = null;
+ this.stack = [];
+ this.unresolvedTypes = new QNameMap();
+ this.extReg = new ExtensionRegistry();
+ this.knownNamespaceMap = {};
+ this.namespaceContext = null;
+ this.schemaResolver = new DefaultURIResolver();
+ this.schemas = new SchemaKeyMap();
+ this.xsd = new XmlSchema(XmlSchema.SCHEMA_NS, undefined, this);
+ this.init();
+ }
+
+ /**
+ * Return an indication of whether a particular schema is not in the working stack of schemas. This function,
+ * while public, is probably not useful outside of the implementation.
+ *
+ * @param pKey schema key
+ * @return false if the schema is in the stack.
+ */
+ check(pKey: SchemaKey) {
+ return !this.stack.includes(pKey);
+ }
+
+ getExtReg() {
+ return this.extReg;
+ }
+
+ /**
+ * get the namespace map
+ *
+ * @return a map of previously known XMLSchema objects keyed by their namespace (String)
+ */
+ getKnownNamespaceMap() {
+ return this.knownNamespaceMap;
+ }
+
+ /**
+ * Retrieve the namespace context.
+ *
+ * @return the namespace context.
+ */
+ getNamespaceContext() {
+ return this.namespaceContext;
+ }
+
+ /**
+ * Retrieve the custom URI resolver, if any.
+ *
+ * @return the current resolver.
+ */
+ getSchemaResolver() {
+ return this.schemaResolver;
+ }
+
+ /**
+ * Retrieve a global type from the schema collection.
+ *
+ * @param schemaTypeName the QName of the type.
+ * @return the type object, or null.
+ */
+ getTypeByQName(schemaTypeName: QName) {
+ const uri = schemaTypeName.getNamespaceURI();
+ for (const entry of this.schemas.entries()) {
+ if (entry[0].getNamespace() === uri) {
+ const type = entry[1].getTypeByQName(schemaTypeName);
+ if (type != null) {
+ return type;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve a set containing the XmlSchema instances with the given system ID. In general, this will
+ * return a single instance, or none. However, if the schema has no targetNamespace attribute and was
+ * included from schemata with different target namespaces, then it may occur, that multiple schema
+ * instances with different logical target namespaces may be returned.
+ *
+ * @param systemId the system id for this schema
+ * @return array of XmlSchema objects
+ */
+ getXmlSchema(systemId: string | null) {
+ if (systemId == null) {
+ systemId = '';
+ }
+ const result: XmlSchema[] = [];
+ for (const entry of this.schemas.entries()) {
+ if (entry[0].getSystemId() === systemId) {
+ result.push(entry[1]);
+ }
+ }
+ return result;
+ }
+
+ getXmlSchemas() {
+ return Array.from(this.schemas.values());
+ }
+
+ init(): void {
+ /*
+ * Defined in section 4.
+ */
+ this.addSimpleType(this.xsd, Constants.XSD_ANYSIMPLETYPE.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_ANYTYPE.getLocalPart()!);
+
+ /*
+ * Primitive types 3.2.1 string 3.2.2 boolean 3.2.3 decimal 3.2.4 float 3.2.5 double 3.2.6 duration
+ * 3.2.7 dateTime 3.2.8 time 3.2.9 date 3.2.10 gYearMonth 3.2.11 gYear 3.2.12 gMonthDay 3.2.13 gDay
+ * 3.2.14 gMonth 3.2.15 hexBinary 3.2.16 base64Binary 3.2.17 anyURI 3.2.18 QName 3.2.19 NOTATION
+ */
+ this.addSimpleType(this.xsd, Constants.XSD_STRING.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_BOOLEAN.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_FLOAT.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_DOUBLE.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_QNAME.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_DECIMAL.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_DURATION.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_DATE.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_TIME.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_DATETIME.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_DAY.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_MONTH.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_MONTHDAY.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_YEAR.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_YEARMONTH.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NOTATION.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_HEXBIN.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_BASE64.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_ANYURI.getLocalPart()!);
+
+ /*
+ * 3.3.1 normalizedString 3.3.2 token 3.3.3 language 3.3.4 NMTOKEN 3.3.5 NMTOKENS 3.3.6 Name 3.3.7
+ * NCName 3.3.8 ID 3.3.9 IDREF 3.3.10 IDREFS 3.3.11 ENTITY 3.3.12 ENTITIES 3.3.13 integer 3.3.14
+ * nonPositiveInteger 3.3.15 negativeInteger 3.3.16 long 3.3.17 int 3.3.18 short 3.3.19 byte 3.3.20
+ * nonNegativeInteger 3.3.21 unsignedLong 3.3.22 unsignedInt 3.3.23 unsignedShort 3.3.24 unsignedByte
+ * 3.3.25 positiveInteger
+ */
+
+ // derived types from decimal
+ this.addSimpleType(this.xsd, Constants.XSD_LONG.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_SHORT.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_BYTE.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_INTEGER.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_INT.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_POSITIVEINTEGER.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NEGATIVEINTEGER.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NONPOSITIVEINTEGER.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NONNEGATIVEINTEGER.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_UNSIGNEDBYTE.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_UNSIGNEDINT.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_UNSIGNEDLONG.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_UNSIGNEDSHORT.getLocalPart()!);
+
+ // derived types from string
+ this.addSimpleType(this.xsd, Constants.XSD_NAME.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NORMALIZEDSTRING.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NCNAME.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NMTOKEN.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_NMTOKENS.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_ENTITY.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_ENTITIES.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_ID.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_IDREF.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_IDREFS.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_LANGUAGE.getLocalPart()!);
+ this.addSimpleType(this.xsd, Constants.XSD_TOKEN.getLocalPart()!);
+
+ // 2.5.3 setup built-in datatype hierarchy
+ this.setupBuiltinDatatypeHierarchy(this.xsd);
+
+ /*
+ * Removed loading ExtensionRegistry from system property.
+ * It should be enough to register it from application side when necessary.
+ */
+ }
+
+ private setupBuiltinDatatypeHierarchy(xsd: XmlSchema) {
+ this.setDerivationByRestriction(xsd, Constants.XSD_ANYSIMPLETYPE, Constants.XSD_ANYTYPE);
+ this.setDerivationByRestriction(xsd, Constants.XSD_DURATION, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_DATETIME, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_TIME, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_DATE, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_YEARMONTH, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_YEAR, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_MONTHDAY, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_DAY, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_MONTH, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_BOOLEAN, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_BASE64, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_HEXBIN, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_FLOAT, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_DOUBLE, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_ANYURI, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_QNAME, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NOTATION, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_DECIMAL, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('collapse', true),
+ ]);
+
+ this.setDerivationByRestriction(xsd, Constants.XSD_INTEGER, Constants.XSD_DECIMAL, [
+ new XmlSchemaFractionDigitsFacet(0, true),
+ new XmlSchemaPatternFacet('[\\-+]?[0-9]+', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NONPOSITIVEINTEGER, Constants.XSD_INTEGER, [
+ new XmlSchemaMaxInclusiveFacet(0, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NEGATIVEINTEGER, Constants.XSD_NONPOSITIVEINTEGER, [
+ new XmlSchemaMaxInclusiveFacet(-1, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_LONG, Constants.XSD_INTEGER, [
+ new XmlSchemaMinInclusiveFacet(BigInt('-9223372036854775808'), false),
+ new XmlSchemaMaxInclusiveFacet(BigInt('9223372036854775807'), false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_INT, Constants.XSD_LONG, [
+ new XmlSchemaMinInclusiveFacet(-2147483648, false),
+ new XmlSchemaMaxInclusiveFacet(2147483647, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_SHORT, Constants.XSD_INT, [
+ new XmlSchemaMinInclusiveFacet(-32768, false),
+ new XmlSchemaMaxInclusiveFacet(32767, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_BYTE, Constants.XSD_SHORT, [
+ new XmlSchemaMinInclusiveFacet(-128, false),
+ new XmlSchemaMaxInclusiveFacet(127, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NONNEGATIVEINTEGER, Constants.XSD_INTEGER, [
+ new XmlSchemaMinInclusiveFacet(0, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_POSITIVEINTEGER, Constants.XSD_NONNEGATIVEINTEGER, [
+ new XmlSchemaMinInclusiveFacet(1, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_UNSIGNEDLONG, Constants.XSD_NONNEGATIVEINTEGER, [
+ new XmlSchemaMaxInclusiveFacet(BigInt('18446744073709551615'), false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_UNSIGNEDINT, Constants.XSD_UNSIGNEDLONG, [
+ new XmlSchemaMaxInclusiveFacet(4294967295, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_UNSIGNEDSHORT, Constants.XSD_UNSIGNEDINT, [
+ new XmlSchemaMaxInclusiveFacet(65535, false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_UNSIGNEDBYTE, Constants.XSD_UNSIGNEDSHORT, [
+ new XmlSchemaMaxInclusiveFacet(255, false),
+ ]);
+
+ this.setDerivationByRestriction(xsd, Constants.XSD_STRING, Constants.XSD_ANYSIMPLETYPE, [
+ new XmlSchemaWhiteSpaceFacet('preserve', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NORMALIZEDSTRING, Constants.XSD_STRING, [
+ new XmlSchemaWhiteSpaceFacet('replace', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_TOKEN, Constants.XSD_NORMALIZEDSTRING, [
+ new XmlSchemaWhiteSpaceFacet('collapse', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_LANGUAGE, Constants.XSD_TOKEN, [
+ new XmlSchemaPatternFacet('[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NMTOKEN, Constants.XSD_TOKEN, [
+ new XmlSchemaPatternFacet('\\c+', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NAME, Constants.XSD_NMTOKEN, [
+ new XmlSchemaPatternFacet('\\i\\c*', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_NCNAME, Constants.XSD_TOKEN, [
+ new XmlSchemaPatternFacet('[\\i-[:]][\\c-[:]]*', false),
+ ]);
+ this.setDerivationByRestriction(xsd, Constants.XSD_ID, Constants.XSD_NCNAME);
+ this.setDerivationByRestriction(xsd, Constants.XSD_IDREF, Constants.XSD_NCNAME);
+ this.setDerivationByRestriction(xsd, Constants.XSD_ENTITY, Constants.XSD_NCNAME);
+
+ this.setDerivationByList(xsd, Constants.XSD_NMTOKENS, Constants.XSD_NMTOKEN);
+ this.setDerivationByList(xsd, Constants.XSD_IDREFS, Constants.XSD_IDREF);
+ this.setDerivationByList(xsd, Constants.XSD_ENTITIES, Constants.XSD_ENTITY);
+ }
+
+ private setDerivationByRestriction(xsd: XmlSchema, child: QName, parent: QName, facets?: XmlSchemaFacet[]) {
+ const simple = xsd.getTypeByQName(child) as XmlSchemaSimpleType;
+ const restriction = new XmlSchemaSimpleTypeRestriction();
+ restriction.setBaseTypeName(parent);
+ restriction.setBaseType(xsd.getTypeByQName(parent) as XmlSchemaSimpleType);
+
+ facets != null && restriction.getFacets().push(...facets);
+ simple.setContent(restriction);
+ }
+
+ private setDerivationByList(xsd: XmlSchema, child: QName, parent: QName) {
+ const simple = xsd.getTypeByQName(child) as XmlSchemaSimpleType;
+ const restriction = new XmlSchemaSimpleTypeList();
+ restriction.setItemTypeName(parent);
+ restriction.setItemType(xsd.getTypeByQName(parent) as XmlSchemaSimpleType);
+ simple.setContent(restriction);
+ }
+
+ /**
+ * Pop the stack of schemas. This function, while public, is probably not useful outside of the
+ * implementation.
+ */
+ pop() {
+ this.stack.pop();
+ }
+
+ /**
+ * Push a schema onto the stack of schemas. This function, while public, is probably not useful outside of
+ * the implementation.
+ *
+ * @param pKey the schema key.
+ */
+ push(pKey: SchemaKey) {
+ this.stack.push(pKey);
+ }
+
+ read(content: string, validator: (schema: XmlSchema) => void): XmlSchema {
+ const parser = new DOMParser();
+ const document = parser.parseFromString(content, 'text/xml');
+ const error = document.querySelector('parsererror');
+ if (error)
+ throw new Error(
+ `XML Parser Error: ${error.textContent ?? 'The XML schema file had a parse error, but there was no reason provided'}`,
+ );
+ const builder = new SchemaBuilder(this, validator);
+ return builder.build(document);
+ }
+
+ /**
+ * Return the schema from this collection for a particular targetNamespace.
+ *
+ * @param uri target namespace URI.
+ * @return the schema.
+ */
+ schemaForNamespace(uri: string) {
+ for (const entry of Array.from(this.schemas.entries())) {
+ if (entry[0].getNamespace() === uri) {
+ return entry[1];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Set the base URI. This is used when schemas need to be loaded from relative locations
+ *
+ * @param baseUri baseUri for this collection.
+ */
+ setBaseUri(baseUri: string) {
+ this.baseUri = baseUri;
+ const target = (this.schemaResolver as CollectionURIResolver)?.setCollectionBaseURI;
+ target && target(baseUri);
+ }
+
+ setExtReg(extReg: ExtensionRegistry) {
+ this.extReg = extReg;
+ }
+
+ /**
+ * sets the known namespace map
+ *
+ * @param knownNamespaceMap a map of previously known XMLSchema objects keyed by their namespace (String)
+ */
+ setKnownNamespaceMap(knownNamespaceMap: Record) {
+ this.knownNamespaceMap = knownNamespaceMap;
+ }
+
+ /**
+ * Set the namespace context for this collection, which controls the assignment of namespace prefixes to
+ * namespaces.
+ *
+ * @param namespaceContext the context.
+ */
+ setNamespaceContext(namespaceContext: NamespacePrefixList) {
+ this.namespaceContext = namespaceContext;
+ }
+
+ /**
+ * Register a custom URI resolver
+ *
+ * @param schemaResolver resolver
+ */
+ setSchemaResolver(schemaResolver: URIResolver) {
+ this.schemaResolver = schemaResolver;
+ }
+
+ addSchema(pKey: SchemaKey, pSchema: XmlSchema) {
+ if (this.schemas?.has(pKey)) {
+ throw new Error(
+ `A schema with target namespace ${pKey.getNamespace()} and system ID ${pKey.getSystemId()} is already present.`,
+ );
+ }
+ this.schemas.set(pKey, pSchema);
+ }
+
+ addUnresolvedType(type: QName, receiver: TypeReceiver) {
+ let receivers = this.unresolvedTypes.get(type);
+ if (receivers == null) {
+ receivers = [];
+ this.unresolvedTypes.set(type, receivers);
+ }
+ receivers.push(receiver);
+ }
+
+ containsSchema(pKey: SchemaKey): boolean {
+ return !!this.schemas && this.schemas.has(pKey);
+ }
+
+ /**
+ * gets a schema from the external namespace map
+ *
+ * @param namespace
+ * @return
+ */
+ getKnownSchema(namespace: string | null) {
+ return namespace == null ? null : this.knownNamespaceMap[namespace];
+ }
+
+ /**
+ * Get a schema given a SchemaKey
+ *
+ * @param pKey
+ * @return
+ */
+ getSchema(pKey: SchemaKey) {
+ return this.schemas.get(pKey);
+ }
+
+ resolveType(typeName: QName, type: XmlSchemaType) {
+ const receivers = this.unresolvedTypes.get(typeName);
+ if (receivers == null) {
+ return;
+ }
+ for (const receiver of receivers) {
+ receiver.setType(type);
+ }
+ this.unresolvedTypes.delete(typeName);
+ }
+
+ private addSimpleType(schema: XmlSchema, typeName: string) {
+ const type = new XmlSchemaSimpleType(schema, true);
+ type.setName(typeName);
+ }
+
+ /**
+ * Find a global attribute by QName in this collection of schemas.
+ *
+ * @param schemaAttributeName the name of the attribute.
+ * @return the attribute or null.
+ */
+ getAttributeByQName(schemaAttributeName: QName | null) {
+ if (schemaAttributeName == null) {
+ return null;
+ }
+ const uri = schemaAttributeName.getNamespaceURI();
+ for (const entry of Array.from(this.schemas.entries())) {
+ if (entry[0].getNamespace() === uri) {
+ const attribute = entry[1].getAttributeByQName(schemaAttributeName);
+ if (attribute != null) {
+ return attribute;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve a global element from the schema collection.
+ *
+ * @param qname the element QName.
+ * @return the element object, or null.
+ */
+ getElementByQName(qname: QName | null) {
+ if (qname == null) {
+ return null;
+ }
+ const uri = qname.getNamespaceURI();
+ for (const entry of Array.from(this.schemas.entries())) {
+ if (entry[0].getNamespace() === uri) {
+ const element = entry[1].getElementByQName(qname);
+ if (element != null) {
+ return element;
+ }
+ }
+ }
+ return null;
+ }
+
+ getAttributeGroupByQName(name: QName | null) {
+ if (name == null) {
+ return null;
+ }
+ const uri = name.getNamespaceURI();
+ const entries = this.schemas.entries();
+ for (const entry of Array.from(this.schemas.entries())) {
+ if (entry[0].getNamespace() === uri) {
+ const group = entry[1].getAttributeGroupByQName(name);
+ if (group != null) {
+ return group;
+ }
+ }
+ }
+ return null;
+ }
+
+ getGroupByQName(name: QName | null) {
+ if (name == null) {
+ return null;
+ }
+ const uri = name.getNamespaceURI();
+ for (const entry of Array.from(this.schemas.entries())) {
+ if (entry[0].getNamespace() === uri) {
+ const group = entry[1].getGroupByQName(name);
+ if (group != null) {
+ return group;
+ }
+ }
+ }
+ return null;
+ }
+
+ getNotationByQName(name: QName | null) {
+ if (name == null) {
+ return null;
+ }
+ const uri = name.getNamespaceURI();
+ for (const entry of Array.from(this.schemas.entries())) {
+ if (entry[0].getNamespace() === uri) {
+ const notation = entry[1].getNotationByQName(name);
+ if (notation != null) {
+ return notation;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaContent.ts b/packages/xml-schema-ts/src/XmlSchemaContent.ts
new file mode 100644
index 000000000..0d524117a
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaContent.ts
@@ -0,0 +1,6 @@
+/**
+ * An abstract class for schema content.
+ */
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+
+export abstract class XmlSchemaContent extends XmlSchemaAnnotated {}
diff --git a/packages/xml-schema-ts/src/XmlSchemaContentModel.ts b/packages/xml-schema-ts/src/XmlSchemaContentModel.ts
new file mode 100644
index 000000000..63033eed3
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaContentModel.ts
@@ -0,0 +1,10 @@
+import type { XmlSchemaContent } from './XmlSchemaContent';
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+
+/**
+ * An abstract class for the schema content model.
+ */
+export abstract class XmlSchemaContentModel extends XmlSchemaAnnotated {
+ abstract setContent(content: XmlSchemaContent | null): void;
+ abstract getContent(): XmlSchemaContent | null;
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaContentProcessing.ts b/packages/xml-schema-ts/src/XmlSchemaContentProcessing.ts
new file mode 100644
index 000000000..a74b71b7e
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaContentProcessing.ts
@@ -0,0 +1,14 @@
+/**
+ * Provides information about the validation mode of any and anyAttribute element replacements.
+ */
+
+export enum XmlSchemaContentProcessing {
+ LAX = 'LAX',
+ NONE = 'NONE',
+ SKIP = 'SKIP',
+ STRICT = 'STRICT',
+}
+
+export function xmlSchemaContentProcessingValueOf(name: string) {
+ return XmlSchemaContentProcessing[name.toUpperCase() as keyof typeof XmlSchemaContentProcessing];
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaContentType.ts b/packages/xml-schema-ts/src/XmlSchemaContentType.ts
new file mode 100644
index 000000000..89faf4a35
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaContentType.ts
@@ -0,0 +1,15 @@
+/**
+ * Enumerations for the content model of the complex type. This represents the content in the
+ * post-schema-validation infoset.
+ */
+
+export enum XmlSchemaContentType {
+ ELEMENT_ONLY = 'ELEMENT_ONLY',
+ EMPTY = 'EMPTY',
+ MIXED = 'MIXED',
+ TEXT_ONLY = 'TEXT_ONLY',
+}
+
+export function xmlSchemaContentTypeValueOf(name: string) {
+ return XmlSchemaContentType[name.toUpperCase() as keyof typeof XmlSchemaContentType];
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaDerivationMethod.ts b/packages/xml-schema-ts/src/XmlSchemaDerivationMethod.ts
new file mode 100644
index 000000000..e734e4c19
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaDerivationMethod.ts
@@ -0,0 +1,130 @@
+export class XmlSchemaDerivationMethod {
+ static readonly NONE = new XmlSchemaDerivationMethod();
+ private all = false;
+ private empty = false;
+ private extension = false;
+ private list = false;
+ private restriction = false;
+ private substitution = false;
+ private union = false;
+
+ static schemaValueOf(name: string): XmlSchemaDerivationMethod {
+ const tokens = name.split('\\s');
+ const method = new XmlSchemaDerivationMethod();
+ for (const t in tokens) {
+ if ('#all' === t.toLowerCase() || 'all' === t.toLowerCase()) {
+ if (method.notAll()) {
+ throw new Error('Derivation method cannot be #all and something else.');
+ } else {
+ method.setAll(true);
+ }
+ } else {
+ if (method.isAll()) {
+ throw new Error('Derivation method cannot be #all and something else.');
+ }
+ if ('extension' === t) {
+ method.setExtension(true);
+ } else if ('list' === t) {
+ method.setList(true);
+ } else if ('restriction' === t) {
+ method.setRestriction(true);
+ } else if ('substitution' === t) {
+ method.setSubstitution(true);
+ } else if ('union' === t) {
+ method.setUnion(true);
+ }
+ }
+ }
+ return method;
+ }
+
+ notAll(): boolean {
+ return this.empty || this.extension || this.list || this.restriction || this.substitution || this.union;
+ }
+
+ isAll(): boolean {
+ return this.all;
+ }
+
+ setAll(all: boolean) {
+ this.all = all;
+ if (all) {
+ this.empty = false;
+ this.extension = false;
+ this.list = false;
+ this.restriction = false;
+ this.substitution = false;
+ this.union = false;
+ }
+ }
+
+ isEmpty() {
+ return this.empty;
+ }
+
+ setEmpty(empty: boolean) {
+ this.empty = empty;
+ }
+
+ isExtension() {
+ return this.extension;
+ }
+
+ setExtension(extension: boolean) {
+ this.extension = extension;
+ }
+
+ isList() {
+ return this.list;
+ }
+
+ setList(list: boolean) {
+ this.list = list;
+ }
+
+ isNone() {
+ return !(
+ this.all ||
+ this.empty ||
+ this.extension ||
+ this.list ||
+ this.restriction ||
+ this.substitution ||
+ this.union
+ );
+ }
+
+ setNone(_none: boolean) {
+ this.all = false;
+ this.empty = false;
+ this.extension = false;
+ this.list = false;
+ this.restriction = false;
+ this.substitution = false;
+ this.union = false;
+ }
+
+ isRestriction() {
+ return this.restriction;
+ }
+
+ setRestriction(restriction: boolean) {
+ this.restriction = restriction;
+ }
+
+ isSubstitution() {
+ return this.substitution;
+ }
+
+ setSubstitution(substitution: boolean) {
+ this.substitution = substitution;
+ }
+
+ isUnion() {
+ return this.union;
+ }
+
+ setUnion(union: boolean) {
+ this.union = union;
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaDocumentation.ts b/packages/xml-schema-ts/src/XmlSchemaDocumentation.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/xml-schema-ts/src/XmlSchemaForm.ts b/packages/xml-schema-ts/src/XmlSchemaForm.ts
new file mode 100644
index 000000000..5e76fa151
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaForm.ts
@@ -0,0 +1,9 @@
+export enum XmlSchemaForm {
+ NONE = 'none',
+ QUALIFIED = 'qualified',
+ UNQUALIFIED = 'unqualified',
+}
+
+export function xmlSchemaFormValueOf(value: string) {
+ return XmlSchemaForm[value.toUpperCase() as keyof typeof XmlSchemaForm];
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaGroup.ts b/packages/xml-schema-ts/src/XmlSchemaGroup.ts
new file mode 100644
index 000000000..24bbf2114
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaGroup.ts
@@ -0,0 +1,63 @@
+import type { XmlSchema } from './XmlSchema';
+import type { XmlSchemaAllMember } from './particle/XmlSchemaAllMember';
+import type { XmlSchemaChoiceMember } from './particle/XmlSchemaChoiceMember';
+import type { XmlSchemaGroupParticle } from './particle/XmlSchemaGroupParticle';
+import type { XmlSchemaSequenceMember } from './particle/XmlSchemaSequenceMember';
+import type { XmlSchemaNamed } from './utils/XmlSchemaNamed';
+
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+import { XmlSchemaNamedImpl } from './utils/XmlSchemaNamedImpl';
+
+export class XmlSchemaGroup
+ extends XmlSchemaAnnotated
+ implements XmlSchemaNamed, XmlSchemaChoiceMember, XmlSchemaSequenceMember, XmlSchemaAllMember
+{
+ private particle: XmlSchemaGroupParticle | null = null;
+ private namedDelegate: XmlSchemaNamedImpl;
+
+ constructor(parent: XmlSchema) {
+ super();
+ this.namedDelegate = new XmlSchemaNamedImpl(parent, true);
+ const fParent = parent;
+ fParent.getItems().push(this);
+ }
+
+ getParticle() {
+ return this.particle;
+ }
+
+ setParticle(particle: XmlSchemaGroupParticle) {
+ this.particle = particle;
+ }
+
+ getName() {
+ return this.namedDelegate.getName();
+ }
+
+ getParent() {
+ return this.namedDelegate.getParent();
+ }
+
+ getQName() {
+ return this.namedDelegate.getQName();
+ }
+
+ isAnonymous() {
+ return this.namedDelegate.isAnonymous();
+ }
+
+ isTopLevel() {
+ return this.namedDelegate.isTopLevel();
+ }
+
+ setName(name: string | null) {
+ const fName = name;
+ if (this.getQName() != null) {
+ this.getParent().getGroups().delete(this.getQName()!);
+ }
+ this.namedDelegate.setName(fName);
+ if (fName != null) {
+ this.getParent().getGroups().set(this.getQName()!, this);
+ }
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaItemWithRef.ts b/packages/xml-schema-ts/src/XmlSchemaItemWithRef.ts
new file mode 100644
index 000000000..7e8983939
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaItemWithRef.ts
@@ -0,0 +1,7 @@
+import { XmlSchemaNamed } from './utils/XmlSchemaNamed';
+import { XmlSchemaRef } from './utils/XmlSchemaRef';
+import { XmlSchemaItemWithRefBase } from './XmlSchemaItemWithRefBase';
+
+export interface XmlSchemaItemWithRef extends XmlSchemaItemWithRefBase {
+ getRef(): XmlSchemaRef;
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaItemWithRefBase.ts b/packages/xml-schema-ts/src/XmlSchemaItemWithRefBase.ts
new file mode 100644
index 000000000..06547c309
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaItemWithRefBase.ts
@@ -0,0 +1,19 @@
+import { QName } from './QName';
+import { XmlSchemaRefBase } from './utils/XmlSchemaRefBase';
+
+export interface XmlSchemaItemWithRefBase {
+ /**
+ * @return true if this object has a non-null ref.
+ */
+ isRef(): boolean;
+
+ /**
+ * @return the Qualified Name of the target of the ref.
+ */
+ getTargetQName(): QName | null;
+
+ /**
+ * @return the non-generic reference object.
+ */
+ getRefBase(): XmlSchemaRefBase;
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaNotation.ts b/packages/xml-schema-ts/src/XmlSchemaNotation.ts
new file mode 100644
index 000000000..d55bc6289
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaNotation.ts
@@ -0,0 +1,73 @@
+import type { XmlSchema } from './XmlSchema';
+import type { XmlSchemaNamed } from './utils/XmlSchemaNamed';
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+import { XmlSchemaNamedImpl } from './utils/XmlSchemaNamedImpl';
+
+export class XmlSchemaNotation extends XmlSchemaAnnotated implements XmlSchemaNamed {
+ private system: string | null = null;
+ private publicNotation: string | null = null;
+ private namedDelegate: XmlSchemaNamedImpl;
+
+ /**
+ * Creates new XmlSchemaNotation
+ */
+ constructor(parent: XmlSchema) {
+ super();
+ this.namedDelegate = new XmlSchemaNamedImpl(parent, true);
+ const fParent = parent;
+ fParent.getItems().push(this);
+ }
+
+ getPublic() {
+ return this.publicNotation;
+ }
+
+ setPublic(isPublic: string) {
+ this.publicNotation = isPublic;
+ }
+
+ getSystem() {
+ return this.system;
+ }
+
+ setSystem(system: string) {
+ this.system = system;
+ }
+
+ getParent() {
+ return this.namedDelegate.getParent();
+ }
+
+ getQName() {
+ return this.namedDelegate.getQName();
+ }
+
+ isAnonymous() {
+ return this.namedDelegate.isAnonymous();
+ }
+
+ isTopLevel() {
+ return this.namedDelegate.isTopLevel();
+ }
+
+ setPublicNotation(publicNotation: string) {
+ this.publicNotation = publicNotation;
+ }
+
+ getPublicNotation() {
+ return this.publicNotation;
+ }
+
+ getName() {
+ return this.namedDelegate.getName();
+ }
+
+ setName(name: string) {
+ const fName = name;
+ if (this.getName() != null) {
+ this.getParent().getNotations().delete(this.getQName()!);
+ }
+ this.namedDelegate.setName(fName);
+ this.getParent().getNotations().set(this.getQName()!, this);
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaObject.ts b/packages/xml-schema-ts/src/XmlSchemaObject.ts
new file mode 100644
index 000000000..72bad56d0
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaObject.ts
@@ -0,0 +1,45 @@
+import { XmlSchemaObjectBase } from './utils/XmlSchemaObjectBase';
+
+export abstract class XmlSchemaObject implements XmlSchemaObjectBase {
+ lineNumber?: number;
+ linePosition?: number;
+ sourceURI: string | null = null;
+
+ private metaInfoMap = new Map();
+
+ addMetaInfo(key: string, value: object) {
+ this.metaInfoMap.set(key, value);
+ }
+
+ getLineNumber() {
+ return this.lineNumber;
+ }
+
+ getLinePosition() {
+ return this.linePosition;
+ }
+
+ getMetaInfoMap() {
+ return this.metaInfoMap;
+ }
+
+ getSourceURI() {
+ return this.sourceURI;
+ }
+
+ setLineNumber(lineNumber: number) {
+ this.lineNumber = lineNumber;
+ }
+
+ setLinePosition(linePosition: number) {
+ this.linePosition = linePosition;
+ }
+
+ setMetaInfoMap(metaInfoMap: Map) {
+ this.metaInfoMap = metaInfoMap;
+ }
+
+ setSourceURI(sourceURI: string | null) {
+ this.sourceURI = sourceURI;
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaType.ts b/packages/xml-schema-ts/src/XmlSchemaType.ts
new file mode 100644
index 000000000..815b56993
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaType.ts
@@ -0,0 +1,102 @@
+import type { XmlSchema } from './XmlSchema';
+import type { XmlSchemaNamed } from './utils/XmlSchemaNamed';
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+import { XmlSchemaDerivationMethod } from './XmlSchemaDerivationMethod';
+import { XmlSchemaNamedImpl } from './utils/XmlSchemaNamedImpl';
+
+export class XmlSchemaType extends XmlSchemaAnnotated implements XmlSchemaNamed {
+ private deriveBy: XmlSchemaDerivationMethod | null = null;
+ private finalDerivation: XmlSchemaDerivationMethod;
+ private finalResolved?: XmlSchemaDerivationMethod;
+ private _isMixed = false;
+ private namedDelegate: XmlSchemaNamedImpl;
+
+ constructor(schema: XmlSchema, topLevel: boolean) {
+ super();
+ this.namedDelegate = new XmlSchemaNamedImpl(schema, topLevel);
+ this.finalDerivation = XmlSchemaDerivationMethod.NONE;
+ if (topLevel) {
+ schema.getItems().push(this);
+ }
+ }
+
+ getDeriveBy() {
+ return this.deriveBy;
+ }
+
+ getFinal() {
+ return this.finalDerivation;
+ }
+
+ setFinal(finalDerivationValue: XmlSchemaDerivationMethod) {
+ this.finalDerivation = finalDerivationValue;
+ }
+
+ getFinalResolved() {
+ return this.finalResolved;
+ }
+
+ isMixed() {
+ return this._isMixed;
+ }
+
+ setMixed(isMixedValue: boolean) {
+ this._isMixed = isMixedValue;
+ }
+
+ getName() {
+ return this.namedDelegate.getName();
+ }
+
+ getParent() {
+ return this.namedDelegate.getParent();
+ }
+
+ getQName() {
+ return this.namedDelegate.getQName();
+ }
+
+ isAnonymous() {
+ return this.namedDelegate.isAnonymous();
+ }
+
+ isTopLevel() {
+ return this.namedDelegate.isTopLevel();
+ }
+
+ setName(name: string | null) {
+ /*
+ * Inside a redefine, a 'non-top-level' type can have a name.
+ * This requires us to tolerate this case (non-top-level, named) even it
+ * in any other case it's completely invalid.
+ */
+ if (this.isTopLevel() && name == null) {
+ throw new Error('A non-top-level type may not be anonyous.');
+ }
+ if (this.isTopLevel() && this.getName() != null) {
+ const qname = this.getQName();
+ qname && this.getParent().getSchemaTypes().delete(qname);
+ }
+ this.namedDelegate.setName(name!);
+ if (this.isTopLevel()) {
+ const qname = this.getQName();
+ qname && this.getParent().getSchemaTypes().set(qname, this);
+ }
+ }
+
+ setFinalResolved(finalResolved: XmlSchemaDerivationMethod) {
+ this.finalResolved = finalResolved;
+ }
+
+ setFinalDerivation(finalDerivation: XmlSchemaDerivationMethod) {
+ this.finalDerivation = finalDerivation;
+ }
+
+ getFinalDerivation() {
+ return this.finalDerivation;
+ }
+
+ setDeriveBy(deriveBy: XmlSchemaDerivationMethod) {
+ this.deriveBy = deriveBy;
+ }
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaUse.ts b/packages/xml-schema-ts/src/XmlSchemaUse.ts
new file mode 100644
index 000000000..28fbc0a47
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaUse.ts
@@ -0,0 +1,13 @@
+/**
+ * use= values.
+ */
+export enum XmlSchemaUse {
+ NONE = 'NONE',
+ OPTIONAL = 'OPTIONAL',
+ PROHIBITED = 'PROHIBITED',
+ REQUIRED = 'REQUIRED',
+}
+
+export function xmlSchemaUseValueOf(name: string) {
+ return XmlSchemaUse[name.toUpperCase() as keyof typeof XmlSchemaUse];
+}
diff --git a/packages/xml-schema-ts/src/XmlSchemaXPath.ts b/packages/xml-schema-ts/src/XmlSchemaXPath.ts
new file mode 100644
index 000000000..8f126ac11
--- /dev/null
+++ b/packages/xml-schema-ts/src/XmlSchemaXPath.ts
@@ -0,0 +1,17 @@
+/**
+ * Class for XML Path Language (XPath) expressions. Represents the World Wide Web Consortium (W3C) selector
+ * element. The World Wide Web Consortium (W3C) field element is a collection of XmlSchemaXPath classes.
+ */
+import { XmlSchemaAnnotated } from './XmlSchemaAnnotated';
+
+export class XmlSchemaXPath extends XmlSchemaAnnotated {
+ xpath: string | null = null;
+
+ getXPath() {
+ return this.xpath;
+ }
+
+ setXPath(xpathString: string) {
+ this.xpath = xpathString;
+ }
+}
diff --git a/packages/xml-schema-ts/src/annotation/XmlSchemaAnnotation.ts b/packages/xml-schema-ts/src/annotation/XmlSchemaAnnotation.ts
new file mode 100644
index 000000000..98cd02829
--- /dev/null
+++ b/packages/xml-schema-ts/src/annotation/XmlSchemaAnnotation.ts
@@ -0,0 +1,10 @@
+import type { XmlSchemaAnnotationItem } from './XmlSchemaAnnotationItem';
+import { XmlSchemaObject } from '../XmlSchemaObject';
+
+export class XmlSchemaAnnotation extends XmlSchemaObject {
+ private items: XmlSchemaAnnotationItem[] = [];
+
+ public getItems() {
+ return this.items;
+ }
+}
diff --git a/packages/xml-schema-ts/src/annotation/XmlSchemaAnnotationItem.ts b/packages/xml-schema-ts/src/annotation/XmlSchemaAnnotationItem.ts
new file mode 100644
index 000000000..22b1c0851
--- /dev/null
+++ b/packages/xml-schema-ts/src/annotation/XmlSchemaAnnotationItem.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaObject } from '../XmlSchemaObject';
+
+export abstract class XmlSchemaAnnotationItem extends XmlSchemaObject {}
diff --git a/packages/xml-schema-ts/src/annotation/XmlSchemaAppInfo.ts b/packages/xml-schema-ts/src/annotation/XmlSchemaAppInfo.ts
new file mode 100644
index 000000000..92aa20ffb
--- /dev/null
+++ b/packages/xml-schema-ts/src/annotation/XmlSchemaAppInfo.ts
@@ -0,0 +1,29 @@
+import { XmlSchemaAnnotationItem } from './XmlSchemaAnnotationItem';
+
+export class XmlSchemaAppInfo extends XmlSchemaAnnotationItem {
+ /**
+ * Provides the source of the application information.
+ */
+ source: string | null = null;
+
+ /**
+ * Returns an array of XmlNode that represents the document text markup.
+ */
+ markup: NodeList | null = null;
+
+ public getSource() {
+ return this.source;
+ }
+
+ public setSource(source: string | null) {
+ this.source = source;
+ }
+
+ public getMarkup() {
+ return this.markup;
+ }
+
+ public setMarkup(markup: NodeList | null) {
+ this.markup = markup;
+ }
+}
diff --git a/packages/xml-schema-ts/src/annotation/XmlSchemaDocumentation.ts b/packages/xml-schema-ts/src/annotation/XmlSchemaDocumentation.ts
new file mode 100644
index 000000000..389c1dedb
--- /dev/null
+++ b/packages/xml-schema-ts/src/annotation/XmlSchemaDocumentation.ts
@@ -0,0 +1,38 @@
+import { XmlSchemaAnnotationItem } from './XmlSchemaAnnotationItem';
+
+export class XmlSchemaDocumentation extends XmlSchemaAnnotationItem {
+ /**
+ * Provides the source of the application information.
+ */
+ source: string | null = null;
+ language: string | null = null;
+
+ /**
+ * Returns an array of XmlNode that represents the document text markup.
+ */
+ markup: NodeList | null = null;
+
+ getSource() {
+ return this.source;
+ }
+
+ setSource(source: string | null) {
+ this.source = source;
+ }
+
+ getMarkup() {
+ return this.markup;
+ }
+
+ setMarkup(markup: NodeList) {
+ this.markup = markup;
+ }
+
+ getLanguage() {
+ return this.language;
+ }
+
+ setLanguage(language: string | null) {
+ this.language = language;
+ }
+}
diff --git a/packages/xml-schema-ts/src/attribute/XmlSchemaAttribute.ts b/packages/xml-schema-ts/src/attribute/XmlSchemaAttribute.ts
new file mode 100644
index 000000000..64e3d7b67
--- /dev/null
+++ b/packages/xml-schema-ts/src/attribute/XmlSchemaAttribute.ts
@@ -0,0 +1,155 @@
+import type { QName } from '../QName';
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaAttributeGroupMember } from './XmlSchemaAttributeGroupMember';
+import type { XmlSchemaItemWithRef } from '../XmlSchemaItemWithRef';
+import type { XmlSchemaSimpleType } from '../simple/XmlSchemaSimpleType';
+import type { XmlSchemaNamedWithForm } from '../utils/XmlSchemaNamedWithForm';
+
+import { XmlSchemaNamedWithFormImpl } from '../utils/XmlSchemaNamedWithFormImpl';
+import { XmlSchemaNamedType } from '../utils/XmlSchemaNamedType';
+import { XmlSchemaRef } from '../utils/XmlSchemaRef';
+import { XmlSchemaAttributeOrGroupRef } from './XmlSchemaAttributeOrGroupRef';
+import { XmlSchemaForm } from '../XmlSchemaForm';
+import { XmlSchemaUse } from '../XmlSchemaUse';
+
+export class XmlSchemaAttribute
+ extends XmlSchemaAttributeOrGroupRef
+ implements XmlSchemaNamedWithForm, XmlSchemaAttributeGroupMember, XmlSchemaItemWithRef
+{
+ private defaultValue: string | null = null;
+ private fixedValue: string | null = null;
+ private schemaType: XmlSchemaSimpleType | null = null;
+ private schemaTypeName: QName | null = null;
+ private use: XmlSchemaUse;
+ private namedDelegate: XmlSchemaNamedWithFormImpl;
+ private ref: XmlSchemaRef;
+
+ /**
+ * Create a new attribute.
+ * @param schema containing scheme.
+ * @param topLevel true if a global attribute.
+ */
+ constructor(schema: XmlSchema, topLevel: boolean) {
+ super();
+ this.namedDelegate = new XmlSchemaNamedWithFormImpl(schema, topLevel, false);
+ this.ref = new XmlSchemaRef(schema, XmlSchemaNamedType.XmlSchemaAttribute);
+ this.namedDelegate.setRefObject(this.ref);
+ this.ref.setNamedObject(this.namedDelegate);
+ this.use = XmlSchemaUse.NONE;
+ if (topLevel) {
+ schema.getItems().push(this);
+ }
+ }
+
+ getDefaultValue() {
+ return this.defaultValue;
+ }
+
+ setDefaultValue(defaultValue: string) {
+ this.defaultValue = defaultValue;
+ }
+
+ getFixedValue() {
+ return this.fixedValue;
+ }
+
+ setFixedValue(fixedValue: string) {
+ this.fixedValue = fixedValue;
+ }
+
+ getRef(): XmlSchemaRef {
+ return this.ref;
+ }
+
+ getSchemaType() {
+ return this.schemaType;
+ }
+
+ setSchemaType(schemaType: XmlSchemaSimpleType) {
+ this.schemaType = schemaType;
+ }
+
+ getSchemaTypeName() {
+ return this.schemaTypeName;
+ }
+
+ setSchemaTypeName(schemaTypeName: QName) {
+ this.schemaTypeName = schemaTypeName;
+ }
+
+ getUse() {
+ return this.use;
+ }
+
+ setUse(use: XmlSchemaUse) {
+ if (this.namedDelegate.isTopLevel() && use != null) {
+ throw new Error("Top-level attributes may not have a 'use'");
+ }
+ this.use = use;
+ }
+
+ getName() {
+ return this.namedDelegate.getName();
+ }
+
+ getParent() {
+ return this.namedDelegate.getParent();
+ }
+
+ getQName() {
+ return this.namedDelegate.getQName();
+ }
+
+ isAnonymous() {
+ return this.namedDelegate.isAnonymous();
+ }
+
+ isTopLevel() {
+ return this.namedDelegate.isTopLevel();
+ }
+
+ setName(name: string) {
+ const fName = name;
+ if (this.isTopLevel() && this.getName() != null) {
+ this.getParent().getAttributes().delete(this.getQName()!);
+ }
+ this.namedDelegate.setName(fName);
+ if (this.isTopLevel()) {
+ if (fName == null) {
+ throw new Error('Top-level attributes may not be anonymous');
+ }
+ this.getParent().getAttributes().set(this.getQName()!, this);
+ }
+ }
+
+ isFormSpecified() {
+ return this.namedDelegate.isFormSpecified();
+ }
+
+ getForm() {
+ return this.namedDelegate.getForm();
+ }
+
+ setForm(form: XmlSchemaForm) {
+ if (this.isTopLevel() && form != XmlSchemaForm.NONE) {
+ throw new Error("Top-level attributes may not have a 'form'");
+ }
+ this.namedDelegate.setForm(form);
+ }
+
+ getWireName() {
+ return this.namedDelegate.getWireName();
+ }
+
+ isRef() {
+ return this.ref.getTargetQName() != null;
+ }
+
+ getTargetQName() {
+ return this.ref.getTargetQName();
+ }
+
+ getRefBase() {
+ return this.ref;
+ }
+}
diff --git a/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroup.ts b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroup.ts
new file mode 100644
index 000000000..228f34b6e
--- /dev/null
+++ b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroup.ts
@@ -0,0 +1,66 @@
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaAnyAttribute } from '../XmlSchemaAnyAttribute';
+import type { XmlSchemaAttributeGroupMember } from './XmlSchemaAttributeGroupMember';
+import type { XmlSchemaNamed } from '../utils/XmlSchemaNamed';
+import { XmlSchemaAnnotated } from '../XmlSchemaAnnotated';
+import { XmlSchemaNamedImpl } from '../utils/XmlSchemaNamedImpl';
+
+export class XmlSchemaAttributeGroup
+ extends XmlSchemaAnnotated
+ implements XmlSchemaNamed, XmlSchemaAttributeGroupMember
+{
+ private anyAttribute: XmlSchemaAnyAttribute | null = null;
+ private attributes: XmlSchemaAttributeGroupMember[] = [];
+ private namedDelegate: XmlSchemaNamedImpl;
+
+ /**
+ * Creates new XmlSchemaAttributeGroup
+ */
+ constructor(parent: XmlSchema) {
+ super();
+ const fParent = parent;
+ this.namedDelegate = new XmlSchemaNamedImpl(parent, true);
+ fParent.getItems().push(this);
+ }
+
+ getAnyAttribute() {
+ return this.anyAttribute;
+ }
+
+ setAnyAttribute(anyAttribute: XmlSchemaAnyAttribute) {
+ this.anyAttribute = anyAttribute;
+ }
+
+ getAttributes() {
+ return this.attributes;
+ }
+
+ getName() {
+ return this.namedDelegate.getName();
+ }
+
+ getParent() {
+ return this.namedDelegate.getParent();
+ }
+
+ getQName() {
+ return this.namedDelegate.getQName();
+ }
+
+ isAnonymous() {
+ return this.namedDelegate.isAnonymous();
+ }
+
+ isTopLevel() {
+ return this.namedDelegate.isTopLevel();
+ }
+
+ setName(name: string) {
+ const fName = name;
+ if (fName != null) {
+ this.getQName() != null && this.getParent().getAttributeGroups().delete(this.getQName()!);
+ }
+ this.namedDelegate.setName(fName);
+ this.getQName() != null && this.getParent().getAttributeGroups().set(this.getQName()!, this);
+ }
+}
diff --git a/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroupMember.ts b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroupMember.ts
new file mode 100644
index 000000000..f7b91af9c
--- /dev/null
+++ b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroupMember.ts
@@ -0,0 +1,5 @@
+/**
+ * Implemented by the types that can go into an attribute group.
+ */
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+export interface XmlSchemaAttributeGroupMember {}
diff --git a/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroupRef.ts b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroupRef.ts
new file mode 100644
index 000000000..1b5aced89
--- /dev/null
+++ b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeGroupRef.ts
@@ -0,0 +1,48 @@
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaAttributeGroup } from './XmlSchemaAttributeGroup';
+import type { XmlSchemaAttributeGroupMember } from './XmlSchemaAttributeGroupMember';
+import type { XmlSchemaItemWithRef } from '../XmlSchemaItemWithRef';
+import { XmlSchemaAttributeOrGroupRef } from './XmlSchemaAttributeOrGroupRef';
+import { XmlSchemaNamedType } from '../utils/XmlSchemaNamedType';
+import { XmlSchemaRef } from '../utils/XmlSchemaRef';
+
+/**
+ * Class for the attribute group reference.
+ * Represents the World Wide Web Consortium (W3C) attributeGroup
+ * element with the ref attribute.
+ */
+export class XmlSchemaAttributeGroupRef
+ extends XmlSchemaAttributeOrGroupRef
+ implements XmlSchemaAttributeGroupMember, XmlSchemaItemWithRef
+{
+ private ref: XmlSchemaRef;
+
+ /**
+ * Create an attribute group reference.
+ * @param parent containing schema.
+ */
+ constructor(parent: XmlSchema) {
+ super();
+ this.ref = new XmlSchemaRef(parent, XmlSchemaNamedType.XmlSchemaAttributeGroup);
+ }
+
+ /**
+ * Return the reference object.
+ * @return
+ */
+ public getRef() {
+ return this.ref;
+ }
+
+ isRef() {
+ return this.ref.getTargetQName() != null;
+ }
+
+ getTargetQName() {
+ return this.ref.getTargetQName();
+ }
+
+ public getRefBase() {
+ return this.ref;
+ }
+}
diff --git a/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeOrGroupRef.ts b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeOrGroupRef.ts
new file mode 100644
index 000000000..26c395d79
--- /dev/null
+++ b/packages/xml-schema-ts/src/attribute/XmlSchemaAttributeOrGroupRef.ts
@@ -0,0 +1,8 @@
+import { XmlSchemaAnnotated } from '../XmlSchemaAnnotated';
+
+/**
+ * Several objects in the model allow either an XmlSchemaAttribute or
+ * an XmlSchemaAttributeGroupRef. This type is here only allow
+ * tight type specifications for them.
+ */
+export class XmlSchemaAttributeOrGroupRef extends XmlSchemaAnnotated {}
diff --git a/packages/xml-schema-ts/src/complex/XmlSchemaComplexContent.ts b/packages/xml-schema-ts/src/complex/XmlSchemaComplexContent.ts
new file mode 100644
index 000000000..bfb32de6e
--- /dev/null
+++ b/packages/xml-schema-ts/src/complex/XmlSchemaComplexContent.ts
@@ -0,0 +1,35 @@
+import type { XmlSchemaContent } from '../XmlSchemaContent';
+import { XmlSchemaContentModel } from '../XmlSchemaContentModel';
+
+/**
+ * Class that represents the complex content model for complex types. Contains extensions or restrictions on a
+ * complex type that has mixed content or elements only. Represents the World Wide Web Consortium (W3C)
+ * complexContent element.
+ */
+export class XmlSchemaComplexContent extends XmlSchemaContentModel {
+ /*
+ * One of either the XmlSchemaComplexContentRestriction or XmlSchemaComplexContentExtension classes.
+ */
+ content: XmlSchemaContent | null = null;
+ /*
+ * Indicates that this type has a mixed content model. Character data is allowed to appear between the
+ * child elements of the complex type.
+ */
+ private mixed: boolean = false;
+
+ getContent() {
+ return this.content;
+ }
+
+ setContent(content: XmlSchemaContent) {
+ this.content = content;
+ }
+
+ isMixed() {
+ return this.mixed;
+ }
+
+ setMixed(mixed: boolean) {
+ this.mixed = mixed;
+ }
+}
diff --git a/packages/xml-schema-ts/src/complex/XmlSchemaComplexContentExtension.ts b/packages/xml-schema-ts/src/complex/XmlSchemaComplexContentExtension.ts
new file mode 100644
index 000000000..13a2f9ba0
--- /dev/null
+++ b/packages/xml-schema-ts/src/complex/XmlSchemaComplexContentExtension.ts
@@ -0,0 +1,57 @@
+/**
+ * Class for complex types with a complex content model derived by extension. Extends the complex type by
+ * adding attributes or elements. Represents the World Wide Web Consortium (W3C) extension element for complex
+ * content.
+ */
+import type { QName } from '../QName';
+import type { XmlSchemaAnyAttribute } from '../XmlSchemaAnyAttribute';
+import type { XmlSchemaAttributeOrGroupRef } from '../attribute/XmlSchemaAttributeOrGroupRef';
+import type { XmlSchemaParticle } from '../particle/XmlSchemaParticle';
+import { XmlSchemaContent } from '../XmlSchemaContent';
+
+export class XmlSchemaComplexContentExtension extends XmlSchemaContent {
+ /* Allows an XmlSchemaAnyAttribute to be used for the attribute value. */
+ private anyAttribute: XmlSchemaAnyAttribute | null = null;
+ /*
+ * Contains XmlSchemaAttribute and XmlSchemaAttributeGroupRef. Collection of attributes for the simple
+ * type.
+ */
+ private attributes: XmlSchemaAttributeOrGroupRef[] = [];
+ /* Name of the built-in data type, simple type, or complex type. */
+ private baseTypeName: QName | null = null;
+
+ /* One of the XmlSchemaGroupRef, XmlSchemaChoice, XmlSchemaAll, or XmlSchemaSequence classes. */
+ private particle: XmlSchemaParticle | null = null;
+
+ setAnyAttribute(anyAttribute: XmlSchemaAnyAttribute) {
+ this.anyAttribute = anyAttribute;
+ }
+
+ getAnyAttribute() {
+ return this.anyAttribute;
+ }
+
+ public getAttributes() {
+ return this.attributes;
+ }
+
+ setBaseTypeName(baseTypeName: QName) {
+ this.baseTypeName = baseTypeName;
+ }
+
+ getBaseTypeName() {
+ return this.baseTypeName;
+ }
+
+ getParticle() {
+ return this.particle;
+ }
+
+ setParticle(particle: XmlSchemaParticle) {
+ this.particle = particle;
+ }
+
+ setAttributes(attributes: XmlSchemaAttributeOrGroupRef[]) {
+ this.attributes = attributes;
+ }
+}
diff --git a/packages/xml-schema-ts/src/complex/XmlSchemaComplexContentRestriction.ts b/packages/xml-schema-ts/src/complex/XmlSchemaComplexContentRestriction.ts
new file mode 100644
index 000000000..a133f75ae
--- /dev/null
+++ b/packages/xml-schema-ts/src/complex/XmlSchemaComplexContentRestriction.ts
@@ -0,0 +1,58 @@
+/**
+ * Class for complex types with a complex content model that are derived by restriction. Restricts the
+ * contents of the complex type to a subset of the inherited complex type. Represents the World Wide Web
+ * Consortium (W3C) restriction element for complex content.
+ */
+import type { QName } from '../QName';
+import type { XmlSchemaAnyAttribute } from '../XmlSchemaAnyAttribute';
+import type { XmlSchemaAttributeOrGroupRef } from '../attribute/XmlSchemaAttributeOrGroupRef';
+import type { XmlSchemaParticle } from '../particle/XmlSchemaParticle';
+import { XmlSchemaContent } from '../XmlSchemaContent';
+
+export class XmlSchemaComplexContentRestriction extends XmlSchemaContent {
+ /* Allows an XmlSchemaAnyAttribute to be used for the attribute value. */
+ private anyAttribute: XmlSchemaAnyAttribute | null = null;
+ /*
+ * Contains XmlSchemaAttribute and XmlSchemaAttributeGroupRef. Collection of attributes for the simple
+ * type.
+ */
+ private attributes: XmlSchemaAttributeOrGroupRef[] = [];
+ /* Name of the built-in data type, simple type, or complex type. */
+ private baseTypeName: QName | null = null;
+ /*
+ * One of the XmlSchemaGroupRef, XmlSchemaChoice, XmlSchemaAll, or XmlSchemaSequence classes.
+ */
+ private particle: XmlSchemaParticle | null = null;
+
+ setAnyAttribute(anyAttribute: XmlSchemaAnyAttribute) {
+ this.anyAttribute = anyAttribute;
+ }
+
+ getAnyAttribute() {
+ return this.anyAttribute;
+ }
+
+ getAttributes() {
+ return this.attributes;
+ }
+
+ setBaseTypeName(baseTypeName: QName) {
+ this.baseTypeName = baseTypeName;
+ }
+
+ getBaseTypeName() {
+ return this.baseTypeName;
+ }
+
+ getParticle() {
+ return this.particle;
+ }
+
+ setParticle(particle: XmlSchemaParticle) {
+ this.particle = particle;
+ }
+
+ setAttributes(attributes: XmlSchemaAttributeOrGroupRef[]) {
+ this.attributes = attributes;
+ }
+}
diff --git a/packages/xml-schema-ts/src/complex/XmlSchemaComplexType.ts b/packages/xml-schema-ts/src/complex/XmlSchemaComplexType.ts
new file mode 100644
index 000000000..247ff579a
--- /dev/null
+++ b/packages/xml-schema-ts/src/complex/XmlSchemaComplexType.ts
@@ -0,0 +1,137 @@
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaAnyAttribute } from '../XmlSchemaAnyAttribute';
+import type { XmlSchemaAttributeOrGroupRef } from '../attribute/XmlSchemaAttributeOrGroupRef';
+import type { XmlSchemaContentModel } from '../XmlSchemaContentModel';
+import type { XmlSchemaContentType } from '../XmlSchemaContentType';
+import type { XmlSchemaParticle } from '../particle/XmlSchemaParticle';
+
+import { XmlSchemaType } from '../XmlSchemaType';
+import { XmlSchemaDerivationMethod } from '../XmlSchemaDerivationMethod';
+import { XmlSchemaComplexContentExtension } from './XmlSchemaComplexContentExtension';
+import { XmlSchemaComplexContentRestriction } from './XmlSchemaComplexContentRestriction';
+
+export class XmlSchemaComplexType extends XmlSchemaType {
+ private anyAttribute: XmlSchemaAnyAttribute | null = null;
+ private attributeWildcard: XmlSchemaAnyAttribute | null = null;
+ private attributes: XmlSchemaAttributeOrGroupRef[] = [];
+ private block: XmlSchemaDerivationMethod = XmlSchemaDerivationMethod.NONE;
+ private blockResolved: XmlSchemaDerivationMethod | null = null;
+ private contentModel: XmlSchemaContentModel | null = null;
+ private contentType: XmlSchemaContentType | null = null;
+ private particleType: XmlSchemaParticle | null = null;
+ private particle: XmlSchemaParticle | null = null;
+ private _isAbstract: boolean = false;
+
+ /**
+ * Creates new XmlSchemaComplexType
+ */
+ constructor(schema: XmlSchema, topLevel: boolean) {
+ super(schema, topLevel);
+ }
+
+ getAnyAttribute() {
+ return this.anyAttribute;
+ }
+
+ setAnyAttribute(anyAttribute: XmlSchemaAnyAttribute) {
+ this.anyAttribute = anyAttribute;
+ }
+
+ public getAttributes() {
+ return this.attributes;
+ }
+
+ public getAttributeWildcard() {
+ return this.attributeWildcard;
+ }
+
+ getBlock() {
+ return this.block;
+ }
+
+ setBlock(block: XmlSchemaDerivationMethod) {
+ this.block = block;
+ }
+
+ getBlockResolved() {
+ return this.blockResolved;
+ }
+
+ getContentModel() {
+ return this.contentModel;
+ }
+
+ setContentModel(contentModel: XmlSchemaContentModel) {
+ this.contentModel = contentModel;
+ }
+
+ getContentType() {
+ return this.contentType;
+ }
+
+ setContentType(contentType: XmlSchemaContentType) {
+ this.contentType = contentType;
+ }
+
+ getContentTypeParticle() {
+ return this.particleType;
+ }
+
+ isAbstract() {
+ return this._isAbstract;
+ }
+
+ setAbstract(b: boolean) {
+ this._isAbstract = b;
+ }
+
+ getParticle() {
+ return this.particle;
+ }
+
+ setParticle(particle: XmlSchemaParticle | null) {
+ this.particle = particle;
+ }
+
+ /**
+ * Return the QName of the base schema type, if any, as defined in the content model.
+ */
+ getBaseSchemaTypeName() {
+ const model = this.getContentModel();
+ if (model == null) {
+ return null;
+ }
+ const content = model.getContent();
+ if (content == null) {
+ return null;
+ }
+
+ if (content instanceof XmlSchemaComplexContentExtension) {
+ return (content as XmlSchemaComplexContentExtension).getBaseTypeName();
+ }
+ if (content instanceof XmlSchemaComplexContentRestriction) {
+ return (content as XmlSchemaComplexContentRestriction).getBaseTypeName();
+ }
+ return null;
+ }
+
+ setAttributeWildcard(attributeWildcard: XmlSchemaAnyAttribute) {
+ this.attributeWildcard = attributeWildcard;
+ }
+
+ setAttributes(attributes: XmlSchemaAttributeOrGroupRef[]) {
+ this.attributes = attributes;
+ }
+
+ setBlockResolved(blockResolved: XmlSchemaDerivationMethod) {
+ this.blockResolved = blockResolved;
+ }
+
+ setParticleType(particleType: XmlSchemaParticle) {
+ this.particleType = particleType;
+ }
+
+ getParticleType() {
+ return this.particleType;
+ }
+}
diff --git a/packages/xml-schema-ts/src/constants.ts b/packages/xml-schema-ts/src/constants.ts
new file mode 100644
index 000000000..1e580f874
--- /dev/null
+++ b/packages/xml-schema-ts/src/constants.ts
@@ -0,0 +1,83 @@
+import { QName } from './QName';
+
+export const DEFAULT_NS_PREFIX = '';
+export const NULL_NS_URI = '';
+
+//
+// Schema Namespaces
+//
+export const URI_2001_SCHEMA_XSD = 'http://www.w3.org/2001/XMLSchema';
+export const URI_2001_SCHEMA_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
+export const XML_NS_PREFIX = 'xml';
+export const XML_NS_URI = 'http://www.w3.org/XML/1998/namespace';
+export const XMLNS_ATTRIBUTE = 'xmlns';
+export const XMLNS_ATTRIBUTE_NS_URI = 'http://www.w3.org/2000/xmlns/';
+export const XMLNS_PREFIX = 'xml';
+export const XMLNS_URI = 'http://www.w3.org/XML/1998/namespace';
+export const XSD_ANY = new QName(URI_2001_SCHEMA_XSD, 'any');
+export const XSD_ANYATOMICTYPE = new QName(URI_2001_SCHEMA_XSD, 'anyAtomicType');
+export const XSD_ANYSIMPLETYPE = new QName(URI_2001_SCHEMA_XSD, 'anySimpleType');
+export const XSD_ANYTYPE = new QName(URI_2001_SCHEMA_XSD, 'anyType');
+export const XSD_ANYURI = new QName(URI_2001_SCHEMA_XSD, 'anyURI');
+export const XSD_BASE64 = new QName(URI_2001_SCHEMA_XSD, 'base64Binary');
+export const XSD_BOOLEAN = new QName(URI_2001_SCHEMA_XSD, 'boolean');
+export const XSD_BYTE = new QName(URI_2001_SCHEMA_XSD, 'byte');
+export const XSD_DATE = new QName(URI_2001_SCHEMA_XSD, 'date');
+export const XSD_DATETIME = new QName(URI_2001_SCHEMA_XSD, 'dateTime');
+export const XSD_DAY = new QName(URI_2001_SCHEMA_XSD, 'gDay');
+export const XSD_DECIMAL = new QName(URI_2001_SCHEMA_XSD, 'decimal');
+
+export const XSD_DOUBLE = new QName(URI_2001_SCHEMA_XSD, 'double');
+export const XSD_DURATION = new QName(URI_2001_SCHEMA_XSD, 'duration');
+
+export const XSD_ENTITIES = new QName(URI_2001_SCHEMA_XSD, 'ENTITIES');
+export const XSD_ENTITY = new QName(URI_2001_SCHEMA_XSD, 'ENTITY');
+export const XSD_FLOAT = new QName(URI_2001_SCHEMA_XSD, 'float');
+export const XSD_HEXBIN = new QName(URI_2001_SCHEMA_XSD, 'hexBinary');
+export const XSD_ID = new QName(URI_2001_SCHEMA_XSD, 'ID');
+export const XSD_IDREF = new QName(URI_2001_SCHEMA_XSD, 'IDREF');
+export const XSD_IDREFS = new QName(URI_2001_SCHEMA_XSD, 'IDREFS');
+export const XSD_INT = new QName(URI_2001_SCHEMA_XSD, 'int');
+
+export const XSD_INTEGER = new QName(URI_2001_SCHEMA_XSD, 'integer');
+export const XSD_LANGUAGE = new QName(URI_2001_SCHEMA_XSD, 'language');
+export const XSD_LONG = new QName(URI_2001_SCHEMA_XSD, 'long');
+export const XSD_MONTH = new QName(URI_2001_SCHEMA_XSD, 'gMonth');
+export const XSD_MONTHDAY = new QName(URI_2001_SCHEMA_XSD, 'gMonthDay');
+export const XSD_NAME = new QName(URI_2001_SCHEMA_XSD, 'Name');
+
+export const XSD_NCNAME = new QName(URI_2001_SCHEMA_XSD, 'NCName');
+export const XSD_NEGATIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, 'negativeInteger');
+export const XSD_NMTOKEN = new QName(URI_2001_SCHEMA_XSD, 'NMTOKEN');
+export const XSD_NMTOKENS = new QName(URI_2001_SCHEMA_XSD, 'NMTOKENS');
+export const XSD_NONNEGATIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, 'nonNegativeInteger');
+export const XSD_NONPOSITIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, 'nonPositiveInteger');
+export const XSD_NORMALIZEDSTRING = new QName(URI_2001_SCHEMA_XSD, 'normalizedString');
+export const XSD_NOTATION = new QName(URI_2001_SCHEMA_XSD, 'NOTATION');
+export const XSD_POSITIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, 'positiveInteger');
+export const XSD_QNAME = new QName(URI_2001_SCHEMA_XSD, 'QName');
+export const XSD_SCHEMA = new QName(URI_2001_SCHEMA_XSD, 'schema');
+export const XSD_SHORT = new QName(URI_2001_SCHEMA_XSD, 'short');
+// Define qnames for the all of the XSD and SOAP-ENC encodings
+export const XSD_STRING = new QName(URI_2001_SCHEMA_XSD, 'string');
+
+export const XSD_TIME = new QName(URI_2001_SCHEMA_XSD, 'time');
+
+export const XSD_TOKEN = new QName(URI_2001_SCHEMA_XSD, 'token');
+
+export const XSD_UNSIGNEDBYTE = new QName(URI_2001_SCHEMA_XSD, 'unsignedByte');
+
+export const XSD_UNSIGNEDINT = new QName(URI_2001_SCHEMA_XSD, 'unsignedInt');
+
+export const XSD_UNSIGNEDLONG = new QName(URI_2001_SCHEMA_XSD, 'unsignedLong');
+
+export const XSD_UNSIGNEDSHORT = new QName(URI_2001_SCHEMA_XSD, 'unsignedShort');
+
+export const XSD_YEAR = new QName(URI_2001_SCHEMA_XSD, 'gYear');
+
+export const XSD_YEARMONTH = new QName(URI_2001_SCHEMA_XSD, 'gYearMonth');
+
+export class MetaDataConstants {
+ static readonly EXTERNAL_ATTRIBUTES = 'EXTERNAL_ATTRIBUTES';
+ static readonly EXTERNAL_ELEMENTS = 'EXTERNAL_ELEMENTS';
+}
diff --git a/packages/xml-schema-ts/src/constraint/XmlSchemaIdentityConstraint.ts b/packages/xml-schema-ts/src/constraint/XmlSchemaIdentityConstraint.ts
new file mode 100644
index 000000000..96ec9550d
--- /dev/null
+++ b/packages/xml-schema-ts/src/constraint/XmlSchemaIdentityConstraint.ts
@@ -0,0 +1,34 @@
+import type { XmlSchemaXPath } from '../XmlSchemaXPath';
+import { XmlSchemaAnnotated } from '../XmlSchemaAnnotated';
+
+export class XmlSchemaIdentityConstraint extends XmlSchemaAnnotated {
+ private fields: XmlSchemaXPath[] = [];
+
+ private name: string | null = null;
+
+ private selector: XmlSchemaXPath | null = null;
+
+ getFields() {
+ return this.fields;
+ }
+
+ getName() {
+ return this.name;
+ }
+
+ getSelector() {
+ return this.selector;
+ }
+
+ setName(name: string) {
+ this.name = name;
+ }
+
+ setSelector(selector: XmlSchemaXPath) {
+ this.selector = selector;
+ }
+
+ setFields(fields: XmlSchemaXPath[]) {
+ this.fields = fields;
+ }
+}
diff --git a/packages/xml-schema-ts/src/constraint/XmlSchemaKey.ts b/packages/xml-schema-ts/src/constraint/XmlSchemaKey.ts
new file mode 100644
index 000000000..16bb16d17
--- /dev/null
+++ b/packages/xml-schema-ts/src/constraint/XmlSchemaKey.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaIdentityConstraint } from './XmlSchemaIdentityConstraint';
+
+export class XmlSchemaKey extends XmlSchemaIdentityConstraint {}
diff --git a/packages/xml-schema-ts/src/constraint/XmlSchemaKeyref.ts b/packages/xml-schema-ts/src/constraint/XmlSchemaKeyref.ts
new file mode 100644
index 000000000..5e0a0ed1b
--- /dev/null
+++ b/packages/xml-schema-ts/src/constraint/XmlSchemaKeyref.ts
@@ -0,0 +1,14 @@
+import type { QName } from '../QName';
+import { XmlSchemaIdentityConstraint } from './XmlSchemaIdentityConstraint';
+
+export class XmlSchemaKeyref extends XmlSchemaIdentityConstraint {
+ refer: QName | null = null;
+
+ getRefer() {
+ return this.refer;
+ }
+
+ setRefer(refer: QName) {
+ this.refer = refer;
+ }
+}
diff --git a/packages/xml-schema-ts/src/constraint/XmlSchemaUnique.ts b/packages/xml-schema-ts/src/constraint/XmlSchemaUnique.ts
new file mode 100644
index 000000000..de67139ab
--- /dev/null
+++ b/packages/xml-schema-ts/src/constraint/XmlSchemaUnique.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaIdentityConstraint } from './XmlSchemaIdentityConstraint';
+
+export class XmlSchemaUnique extends XmlSchemaIdentityConstraint {}
diff --git a/packages/xml-schema-ts/src/extensions/DefaultExtensionDeserializer.ts b/packages/xml-schema-ts/src/extensions/DefaultExtensionDeserializer.ts
new file mode 100644
index 000000000..0c0818822
--- /dev/null
+++ b/packages/xml-schema-ts/src/extensions/DefaultExtensionDeserializer.ts
@@ -0,0 +1,60 @@
+import type { ExtensionDeserializer } from './ExtensionDeserializer';
+import type { QName } from '../QName';
+import type { XmlSchemaObject } from '../XmlSchemaObject';
+import { MetaDataConstants } from '../constants';
+
+/**
+ * Default deserializer. The action taken when there is nothing specific to be done would be to attach the raw
+ * element object as it is to the meta information map for an element or the raw attribute object
+ */
+export class DefaultExtensionDeserializer implements ExtensionDeserializer {
+ /**
+ * deserialize the given element
+ *
+ * @param schemaObject - Parent schema element
+ * @param name - the QName of the element/attribute to be deserialized. in the case where a deserializer
+ * is used to handle multiple elements/attributes this may be useful to determine the correct
+ * deserialization
+ * @param node - the raw DOM Node read from the source. This will be the extension element itself if for
+ * an element or the extension attribute object if it is an attribute
+ */
+ deserialize(schemaObject: XmlSchemaObject, name: QName, node: Node) {
+ // we just attach the raw node either to the meta map of
+ // elements or the attributes
+
+ let metaInfoMap = schemaObject.getMetaInfoMap();
+ if (metaInfoMap == null) {
+ metaInfoMap = new Map();
+ }
+
+ if (node.nodeType == Node.ATTRIBUTE_NODE) {
+ let attribMap: Map;
+ if (metaInfoMap.has(MetaDataConstants.EXTERNAL_ATTRIBUTES)) {
+ attribMap = metaInfoMap.get(MetaDataConstants.EXTERNAL_ATTRIBUTES) as Map;
+ } else {
+ attribMap = new Map();
+ metaInfoMap.set(MetaDataConstants.EXTERNAL_ATTRIBUTES, attribMap);
+ }
+ attribMap.set(name, node);
+ } else if (node.nodeType == Node.ELEMENT_NODE) {
+ let elementMap;
+ if (metaInfoMap.has(MetaDataConstants.EXTERNAL_ELEMENTS)) {
+ elementMap = metaInfoMap.get(MetaDataConstants.EXTERNAL_ELEMENTS) as Map;
+ } else {
+ elementMap = new Map();
+ metaInfoMap.set(MetaDataConstants.EXTERNAL_ELEMENTS, elementMap);
+ }
+ elementMap.set(name, node);
+ }
+
+ // subsequent processing takes place only if this map is not empty
+ if (metaInfoMap.size !== 0) {
+ const metaInfoMapFromSchemaElement = schemaObject.getMetaInfoMap();
+ if (metaInfoMapFromSchemaElement == null) {
+ schemaObject.setMetaInfoMap(metaInfoMap);
+ } else {
+ metaInfoMap.forEach((value, key) => metaInfoMapFromSchemaElement.set(key, value));
+ }
+ }
+ }
+}
diff --git a/packages/xml-schema-ts/src/extensions/DefaultExtensionSerializer.ts b/packages/xml-schema-ts/src/extensions/DefaultExtensionSerializer.ts
new file mode 100644
index 000000000..f20543fc1
--- /dev/null
+++ b/packages/xml-schema-ts/src/extensions/DefaultExtensionSerializer.ts
@@ -0,0 +1,40 @@
+import type { ExtensionSerializer } from './ExtensionSerializer';
+import type { XmlSchemaObject } from '../XmlSchemaObject';
+import { MetaDataConstants } from '../constants';
+
+/**
+
+ */
+export class DefaultExtensionSerializer implements ExtensionSerializer {
+ /**
+ * serialize the given element
+ *
+ * @param schemaObject - Parent schema element
+ * @param _typeName - the class of the object to be serialized
+ * @param node - The DOM Node that is the parent of the serialzation
+ */
+ serialize(schemaObject: XmlSchemaObject, _typeName: string, node: Node) {
+ // serialization is somewhat tricky in most cases hence this default serializer will
+ // do the exact reverse of the deserializer - look for any plain 'as is' items
+ // and attach them to the parent node.
+ // we just attach the raw node either to the meta map of
+ // elements or the attributes
+ const metaInfoMap = schemaObject.getMetaInfoMap();
+ const parentDoc = node.ownerDocument;
+ if (metaInfoMap.has(MetaDataConstants.EXTERNAL_ATTRIBUTES)) {
+ const attribMap = metaInfoMap.get(MetaDataConstants.EXTERNAL_ATTRIBUTES) as Map;
+ for (const value of attribMap.values()) {
+ if (node.nodeType == Node.ELEMENT_NODE) {
+ (node as Element).setAttributeNodeNS(parentDoc!.importNode(value, true) as Attr);
+ }
+ }
+ }
+
+ if (metaInfoMap.has(MetaDataConstants.EXTERNAL_ELEMENTS)) {
+ const elementMap = metaInfoMap.get(MetaDataConstants.EXTERNAL_ELEMENTS) as Map;
+ for (const value of elementMap.values()) {
+ node.appendChild(parentDoc!.importNode(value, true));
+ }
+ }
+ }
+}
diff --git a/packages/xml-schema-ts/src/extensions/ExtensionDeserializer.ts b/packages/xml-schema-ts/src/extensions/ExtensionDeserializer.ts
new file mode 100644
index 000000000..ab0ed4697
--- /dev/null
+++ b/packages/xml-schema-ts/src/extensions/ExtensionDeserializer.ts
@@ -0,0 +1,22 @@
+import { QName } from '../QName';
+import { XmlSchemaObject } from '../XmlSchemaObject';
+
+/**
+ * Interface for the extension deserializer. The purpose of an instance of this is to deserialize the relevant
+ * attribute/element and perhaps generate a desired custom object. This custom object can be stored in the
+ * metadata map of the parent schema object. When to invoke a given deserializer is a decision taken by the
+ * extension registry
+ */
+export interface ExtensionDeserializer {
+ /**
+ * deserialize the given element
+ *
+ * @param schemaObject - Parent schema element
+ * @param name - the QName of the element/attribute to be deserialized. in the case where a deserializer
+ * is used to handle multiple elements/attributes this may be useful to determine the correct
+ * deserialization
+ * @param domNode - the raw DOM Node read from the source. This will be the extension element itself if
+ * for an element or the extension attribute object if it is an attribute
+ */
+ deserialize(schemaObject: XmlSchemaObject, name: QName, domNode: Node): void;
+}
diff --git a/packages/xml-schema-ts/src/extensions/ExtensionRegistry.ts b/packages/xml-schema-ts/src/extensions/ExtensionRegistry.ts
new file mode 100644
index 000000000..f6969dba8
--- /dev/null
+++ b/packages/xml-schema-ts/src/extensions/ExtensionRegistry.ts
@@ -0,0 +1,113 @@
+import { QName } from '../QName';
+import { XmlSchemaObject } from '../XmlSchemaObject';
+import { DefaultExtensionDeserializer } from './DefaultExtensionDeserializer';
+import { DefaultExtensionSerializer } from './DefaultExtensionSerializer';
+import { ExtensionDeserializer } from './ExtensionDeserializer';
+import { ExtensionSerializer } from './ExtensionSerializer';
+
+export class ExtensionRegistry {
+ /**
+ * Maps for the storage of extension serializers /deserializers
+ */
+ private extensionSerializers = new Map();
+ private extensionDeserializers = new Map();
+
+ /**
+ * Default serializer and serializer
+ */
+ private defaultExtensionSerializer = new DefaultExtensionSerializer();
+ private defaultExtensionDeserializer = new DefaultExtensionDeserializer();
+
+ getDefaultExtensionSerializer() {
+ return this.defaultExtensionSerializer;
+ }
+
+ setDefaultExtensionSerializer(defaultExtensionSerializer: ExtensionSerializer) {
+ this.defaultExtensionSerializer = defaultExtensionSerializer;
+ }
+
+ getDefaultExtensionDeserializer() {
+ return this.defaultExtensionDeserializer;
+ }
+
+ setDefaultExtensionDeserializer(defaultExtensionDeserializer: ExtensionDeserializer) {
+ this.defaultExtensionDeserializer = defaultExtensionDeserializer;
+ }
+
+ /**
+ * Register a deserializer with a QName
+ *
+ * @param name
+ * @param deserializer
+ */
+ registerDeserializer(name: QName, deserializer: ExtensionDeserializer) {
+ this.extensionDeserializers.set(name, deserializer);
+ }
+
+ /**
+ * Register a serializer with a Class
+ *
+ * @param classOfType - the class of the object that would be serialized
+ * @param serializer - an instance of the deserializer
+ */
+ registerSerializer(typeName: string, serializer: ExtensionSerializer) {
+ this.extensionSerializers.set(typeName, serializer);
+ }
+
+ /**
+ * remove the registration for a serializer with a Class
+ *
+ * @param classOfType - the Class of the element/attribute the serializer is associated with
+ */
+ unregisterSerializer(typeName: string) {
+ this.extensionSerializers.delete(typeName);
+ }
+
+ /**
+ * remove the registration for a deserializer with a QName
+ *
+ * @param name - the QName fo the element that the deserializer is associated with
+ */
+ unregisterDeserializer(name: QName) {
+ this.extensionDeserializers.delete(name);
+ }
+
+ /**
+ * Serialize a given extension element
+ *
+ * @param parentSchemaObject - the parent schema object. This is what would contain the extension object,
+ * probably in side its meta information map
+ * @param typeName - The class of type to be serialized
+ * @param node - the parent DOM Node that will ultimately be serialized. The XMLSchema serialization
+ * mechanism is to create a DOM tree first and serialize it
+ */
+ serializeExtension(parentSchemaObject: XmlSchemaObject, typeName: string, node: Node) {
+ const serializerObject = this.extensionSerializers.get(typeName);
+ if (serializerObject != null) {
+ serializerObject.serialize(parentSchemaObject, typeName, node);
+ } else if (this.defaultExtensionSerializer != null) {
+ this.defaultExtensionSerializer.serialize(parentSchemaObject, typeName, node);
+ }
+ }
+
+ /**
+ * Deserialize a given extension element
+ *
+ * @param parentSchemaObject - the parent schema object. This is anticipated to be created already and the
+ * relevant object would contain the extension object, probably in side its meta information
+ * map
+ * @param name - The qname of the element/attribute to be deserialized. This will be used to search for
+ * the extension as well as by the deserializer if a single deserializer is registered against
+ * a number of qnames
+ * @param rawNode - the raw DOM Node read from the source. This will be the extension element itself if
+ * for an element or extension attribute itself in case of an attribute
+ */
+ deserializeExtension(parentSchemaObject: XmlSchemaObject, name: QName, rawNode: Node) {
+ const deserializerObject = this.extensionDeserializers.get(name);
+ if (deserializerObject != null) {
+ deserializerObject.deserialize(parentSchemaObject, name, rawNode);
+ } else if (this.defaultExtensionDeserializer != null) {
+ this.defaultExtensionDeserializer.deserialize(parentSchemaObject, name, rawNode);
+ }
+ }
+}
diff --git a/packages/xml-schema-ts/src/extensions/ExtensionSerializer.ts b/packages/xml-schema-ts/src/extensions/ExtensionSerializer.ts
new file mode 100644
index 000000000..24f387c6a
--- /dev/null
+++ b/packages/xml-schema-ts/src/extensions/ExtensionSerializer.ts
@@ -0,0 +1,19 @@
+import { XmlSchemaObject } from '../XmlSchemaObject';
+
+/**
+ * Interface for the extension serializer. The purpose of an instance of this is to serialize the relevant
+ * custom object and generate attribute/elementa desired . This custom object may be stored in the metadata
+ * map of the parent schema object. When to invoke a given serializer is a decision taken by the extension
+ * registry
+ */
+export interface ExtensionSerializer {
+ /**
+ * serialize the given element
+ *
+ * @param schemaObject - Parent schema object.contains the extension to be serialized
+ * @param typeName - The class of type to be serialized
+ * @param domNode - the parent DOM Node that will ultimately be serialized. The XMLSchema serialization
+ * mechanism is to create a DOM tree first and serialize it
+ */
+ serialize(schemaObject: XmlSchemaObject, typeName: string, domNode: Node): void;
+}
diff --git a/packages/xml-schema-ts/src/external/XmlSchemaExternal.ts b/packages/xml-schema-ts/src/external/XmlSchemaExternal.ts
new file mode 100644
index 000000000..5c4bd4e57
--- /dev/null
+++ b/packages/xml-schema-ts/src/external/XmlSchemaExternal.ts
@@ -0,0 +1,39 @@
+import type { XmlSchema } from '../XmlSchema';
+import { XmlSchemaAnnotated } from '../XmlSchemaAnnotated';
+
+export abstract class XmlSchemaExternal extends XmlSchemaAnnotated {
+ schema: XmlSchema | null = null;
+ schemaLocation: string | null = null;
+
+ /**
+ * Creates new XmlSchemaExternal
+ */
+ protected constructor(parent: XmlSchema) {
+ super();
+ const fParent = parent;
+ fParent.getExternals().push(this);
+ fParent.getItems().push(this);
+ }
+
+ public getSchema() {
+ return this.schema;
+ }
+
+ /**
+ * Store a reference to an XmlSchema corresponding to this item. This only
+ * case in which this will be read is if you ask the XmlSchemaSerializer
+ * to serialize external schemas.
+ * @param sc schema reference
+ */
+ public setSchema(sc: XmlSchema) {
+ this.schema = sc;
+ }
+
+ public getSchemaLocation() {
+ return this.schemaLocation;
+ }
+
+ public setSchemaLocation(schemaLocation: string) {
+ this.schemaLocation = schemaLocation;
+ }
+}
diff --git a/packages/xml-schema-ts/src/external/XmlSchemaImport.ts b/packages/xml-schema-ts/src/external/XmlSchemaImport.ts
new file mode 100644
index 000000000..fb5928512
--- /dev/null
+++ b/packages/xml-schema-ts/src/external/XmlSchemaImport.ts
@@ -0,0 +1,21 @@
+import { XmlSchemaExternal } from './XmlSchemaExternal';
+import type { XmlSchema } from '../XmlSchema';
+
+export class XmlSchemaImport extends XmlSchemaExternal {
+ namespace: string | null = null;
+
+ /**
+ * Creates new XmlSchemaImport
+ */
+ constructor(parent: XmlSchema) {
+ super(parent);
+ }
+
+ getNamespace(): string | null {
+ return this.namespace;
+ }
+
+ setNamespace(namespace: string) {
+ this.namespace = namespace;
+ }
+}
diff --git a/packages/xml-schema-ts/src/external/XmlSchemaInclude.ts b/packages/xml-schema-ts/src/external/XmlSchemaInclude.ts
new file mode 100644
index 000000000..d4f8979ff
--- /dev/null
+++ b/packages/xml-schema-ts/src/external/XmlSchemaInclude.ts
@@ -0,0 +1,11 @@
+import { XmlSchemaExternal } from './XmlSchemaExternal';
+import type { XmlSchema } from '../XmlSchema';
+
+export class XmlSchemaInclude extends XmlSchemaExternal {
+ /**
+ * Creates new XmlSchemaInclude
+ */
+ constructor(parent: XmlSchema) {
+ super(parent);
+ }
+}
diff --git a/packages/xml-schema-ts/src/external/XmlSchemaRedefine.ts b/packages/xml-schema-ts/src/external/XmlSchemaRedefine.ts
new file mode 100644
index 000000000..9294636df
--- /dev/null
+++ b/packages/xml-schema-ts/src/external/XmlSchemaRedefine.ts
@@ -0,0 +1,43 @@
+import type { QName } from '../QName';
+import type { XmlSchemaGroup } from '../XmlSchemaGroup';
+import type { XmlSchemaType } from '../XmlSchemaType';
+import type { XmlSchemaAttributeGroup } from '../attribute/XmlSchemaAttributeGroup';
+import type { XmlSchemaObject } from '../XmlSchemaObject';
+import type { XmlSchema } from '../XmlSchema';
+import { XmlSchemaExternal } from './XmlSchemaExternal';
+
+/**
+ * Allows simple and complex types, groups, and attribute groups from external schema files to be redefined in
+ * the current schema. This class provides versioning for the schema elements. Represents the World Wide Web
+ * Consortium (W3C) redefine element.
+ */
+export class XmlSchemaRedefine extends XmlSchemaExternal {
+ private attributeGroups = new Map();
+ private groups = new Map();
+ private schemaTypes = new Map();
+
+ private items: XmlSchemaObject[] = [];
+
+ /**
+ * Creates new XmlSchemaRedefine
+ */
+ constructor(parent: XmlSchema) {
+ super(parent);
+ }
+
+ getAttributeGroups() {
+ return this.attributeGroups;
+ }
+
+ getGroups() {
+ return this.groups;
+ }
+
+ getItems() {
+ return this.items;
+ }
+
+ getSchemaTypes() {
+ return this.schemaTypes;
+ }
+}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaEnumerationFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaEnumerationFacet.ts
new file mode 100644
index 000000000..3171cf5ae
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaEnumerationFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaEnumerationFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaFacet.ts
new file mode 100644
index 000000000..f7099129f
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaFacet.ts
@@ -0,0 +1,25 @@
+import { XmlSchemaAnnotated } from '../XmlSchemaAnnotated';
+
+export abstract class XmlSchemaFacet extends XmlSchemaAnnotated {
+ fixed: boolean | undefined;
+ value: object | string | number | bigint | null;
+
+ constructor(value?: object | string | number | bigint | null, fixed?: boolean) {
+ super();
+ this.value = value || null;
+ this.fixed = fixed;
+ }
+
+ getValue(): object | string | number | bigint | null {
+ return this.value;
+ }
+ isFixed(): boolean {
+ return !!this.fixed && this.fixed;
+ }
+ setFixed(fixed: boolean) {
+ this.fixed = fixed;
+ }
+ setValue(value: object | string | number | bigint | null) {
+ this.value = value;
+ }
+}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaFacetConstructor.ts b/packages/xml-schema-ts/src/facet/XmlSchemaFacetConstructor.ts
new file mode 100644
index 000000000..59cf844fc
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaFacetConstructor.ts
@@ -0,0 +1,57 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+import { XmlSchemaEnumerationFacet } from './XmlSchemaEnumerationFacet';
+import { XmlSchemaFractionDigitsFacet } from './XmlSchemaFractionDigitsFacet';
+import { XmlSchemaLengthFacet } from './XmlSchemaLengthFacet';
+import { XmlSchemaMaxExclusiveFacet } from './XmlSchemaMaxExclusiveFacet';
+import { XmlSchemaMaxInclusiveFacet } from './XmlSchemaMaxInclusiveFacet';
+import { XmlSchemaMaxLengthFacet } from './XmlSchemaMaxLengthFacet';
+import { XmlSchemaMinLengthFacet } from './XmlSchemaMinLengthFacet';
+import { XmlSchemaMinExclusiveFacet } from './XmlSchemaMinExclusiveFacet';
+import { XmlSchemaMinInclusiveFacet } from './XmlSchemaMinInclusiveFacet';
+import { XmlSchemaPatternFacet } from './XmlSchemaPatternFacet';
+import { XmlSchemaTotalDigitsFacet } from './XmlSchemaTotalDigitsFacet';
+import { XmlSchemaWhiteSpaceFacet } from './XmlSchemaWhiteSpaceFacet';
+
+export class XmlSchemaFacetConstructor {
+ static construct(el: Element) {
+ const name = el.localName;
+ let fixed = false;
+ if (el.getAttribute('fixed') === 'true') {
+ fixed = true;
+ }
+ let facet: XmlSchemaFacet;
+ if ('enumeration' === name) {
+ facet = new XmlSchemaEnumerationFacet();
+ } else if ('fractionDigits' === name) {
+ facet = new XmlSchemaFractionDigitsFacet();
+ } else if ('length' === name) {
+ facet = new XmlSchemaLengthFacet();
+ } else if ('maxExclusive' === name) {
+ facet = new XmlSchemaMaxExclusiveFacet();
+ } else if ('maxInclusive' === name) {
+ facet = new XmlSchemaMaxInclusiveFacet();
+ } else if ('maxLength' === name) {
+ facet = new XmlSchemaMaxLengthFacet();
+ } else if ('minLength' === name) {
+ facet = new XmlSchemaMinLengthFacet();
+ } else if ('minExclusive' === name) {
+ facet = new XmlSchemaMinExclusiveFacet();
+ } else if ('minInclusive' === name) {
+ facet = new XmlSchemaMinInclusiveFacet();
+ } else if ('pattern' === name) {
+ facet = new XmlSchemaPatternFacet();
+ } else if ('totalDigits' === name) {
+ facet = new XmlSchemaTotalDigitsFacet();
+ } else if ('whiteSpace' === name) {
+ facet = new XmlSchemaWhiteSpaceFacet();
+ } else {
+ throw new Error('Incorrect facet with name "' + name + '" found.');
+ }
+ if (el.hasAttribute('id')) {
+ facet.setId(el.getAttribute('id'));
+ }
+ facet.setFixed(fixed);
+ facet.setValue(el.getAttribute('value'));
+ return facet;
+ }
+}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaFractionDigitsFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaFractionDigitsFacet.ts
new file mode 100644
index 000000000..a219293c8
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaFractionDigitsFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaNumericFacet } from './XmlSchemaNumericFacet';
+
+export class XmlSchemaFractionDigitsFacet extends XmlSchemaNumericFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaLengthFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaLengthFacet.ts
new file mode 100644
index 000000000..ce929a29f
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaLengthFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaLengthFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaMaxExclusiveFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaMaxExclusiveFacet.ts
new file mode 100644
index 000000000..d1d793e92
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaMaxExclusiveFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaMaxExclusiveFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaMaxInclusiveFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaMaxInclusiveFacet.ts
new file mode 100644
index 000000000..92d263824
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaMaxInclusiveFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaMaxInclusiveFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaMaxLengthFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaMaxLengthFacet.ts
new file mode 100644
index 000000000..3fd56f34a
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaMaxLengthFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaMaxLengthFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaMinExclusiveFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaMinExclusiveFacet.ts
new file mode 100644
index 000000000..c10a9f5d4
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaMinExclusiveFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaMinExclusiveFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaMinInclusiveFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaMinInclusiveFacet.ts
new file mode 100644
index 000000000..ca8056018
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaMinInclusiveFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaMinInclusiveFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaMinLengthFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaMinLengthFacet.ts
new file mode 100644
index 000000000..ca9218fea
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaMinLengthFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaMinLengthFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaNumericFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaNumericFacet.ts
new file mode 100644
index 000000000..d66a2be75
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaNumericFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export abstract class XmlSchemaNumericFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaPatternFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaPatternFacet.ts
new file mode 100644
index 000000000..61b6ef521
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaPatternFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaPatternFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaTotalDigitsFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaTotalDigitsFacet.ts
new file mode 100644
index 000000000..39c540a86
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaTotalDigitsFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaTotalDigitsFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/facet/XmlSchemaWhiteSpaceFacet.ts b/packages/xml-schema-ts/src/facet/XmlSchemaWhiteSpaceFacet.ts
new file mode 100644
index 000000000..96371ed0f
--- /dev/null
+++ b/packages/xml-schema-ts/src/facet/XmlSchemaWhiteSpaceFacet.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaFacet } from './XmlSchemaFacet';
+
+export class XmlSchemaWhiteSpaceFacet extends XmlSchemaFacet {}
diff --git a/packages/xml-schema-ts/src/index.ts b/packages/xml-schema-ts/src/index.ts
new file mode 100644
index 000000000..fa40c2691
--- /dev/null
+++ b/packages/xml-schema-ts/src/index.ts
@@ -0,0 +1,31 @@
+export { QNameMap } from './utils/ObjectMap';
+export { XmlSchema } from './XmlSchema';
+export { XmlSchemaAll } from './particle/XmlSchemaAll';
+export { XmlSchemaAny } from './particle/XmlSchemaAny';
+export { XmlSchemaAllMember } from './particle/XmlSchemaAllMember';
+export { XmlSchemaAttribute } from './attribute/XmlSchemaAttribute';
+export { XmlSchemaAttributeGroup } from './attribute/XmlSchemaAttributeGroup';
+export { XmlSchemaAttributeGroupMember } from './attribute/XmlSchemaAttributeGroupMember';
+export { XmlSchemaAttributeGroupRef } from './attribute/XmlSchemaAttributeGroupRef';
+export { XmlSchemaAttributeOrGroupRef } from './attribute/XmlSchemaAttributeOrGroupRef';
+export { XmlSchemaChoice } from './particle/XmlSchemaChoice';
+export { XmlSchemaChoiceMember } from './particle/XmlSchemaChoiceMember';
+export { XmlSchemaCollection } from './XmlSchemaCollection';
+export { XmlSchemaComplexContentExtension } from './complex/XmlSchemaComplexContentExtension';
+export { XmlSchemaComplexContentRestriction } from './complex/XmlSchemaComplexContentRestriction';
+export { XmlSchemaComplexType } from './complex/XmlSchemaComplexType';
+export { XmlSchemaContentModel } from './XmlSchemaContentModel';
+export { XmlSchemaElement } from './particle/XmlSchemaElement';
+export { XmlSchemaGroup } from './XmlSchemaGroup';
+export { XmlSchemaGroupParticle } from './particle/XmlSchemaGroupParticle';
+export { XmlSchemaGroupRef } from './particle/XmlSchemaGroupRef';
+export { XmlSchemaObjectBase } from './utils/XmlSchemaObjectBase';
+export { XmlSchemaParticle } from './particle/XmlSchemaParticle';
+export { XmlSchemaRef } from './utils/XmlSchemaRef';
+export { XmlSchemaSequence } from './particle/XmlSchemaSequence';
+export { XmlSchemaSequenceMember } from './particle/XmlSchemaSequenceMember';
+export { XmlSchemaSimpleContentExtension } from './simple/XmlSchemaSimpleContentExtension';
+export { XmlSchemaSimpleContentRestriction } from './simple/XmlSchemaSimpleContentRestriction';
+export { XmlSchemaSimpleType } from './simple/XmlSchemaSimpleType';
+export { XmlSchemaType } from './XmlSchemaType';
+export { XmlSchemaUse } from './XmlSchemaUse';
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaAll.ts b/packages/xml-schema-ts/src/particle/XmlSchemaAll.ts
new file mode 100644
index 000000000..adf607f50
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaAll.ts
@@ -0,0 +1,10 @@
+import { XmlSchemaAllMember } from './XmlSchemaAllMember';
+import { XmlSchemaGroupParticle } from './XmlSchemaGroupParticle';
+
+export class XmlSchemaAll extends XmlSchemaGroupParticle {
+ private items: XmlSchemaAllMember[] = [];
+
+ public getItems() {
+ return this.items;
+ }
+}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaAllMember.ts b/packages/xml-schema-ts/src/particle/XmlSchemaAllMember.ts
new file mode 100644
index 000000000..336959901
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaAllMember.ts
@@ -0,0 +1,4 @@
+import { XmlSchemaObjectBase } from '../utils/XmlSchemaObjectBase';
+
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+export interface XmlSchemaAllMember extends XmlSchemaObjectBase {}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaAny.ts b/packages/xml-schema-ts/src/particle/XmlSchemaAny.ts
new file mode 100644
index 000000000..c34dd9a26
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaAny.ts
@@ -0,0 +1,64 @@
+/**
+ * Enables any element from the specified namespace or namespaces to appear in the containing complexType
+ * element. Represents the World Wide Web Consortium (W3C) any element.
+ */
+import type { XmlSchemaAllMember } from './XmlSchemaAllMember';
+import type { XmlSchemaChoiceMember } from './XmlSchemaChoiceMember';
+import type { XmlSchemaSequenceMember } from './XmlSchemaSequenceMember';
+import { XmlSchemaContentProcessing } from '../XmlSchemaContentProcessing';
+import { XmlSchemaParticle } from './XmlSchemaParticle';
+
+export class XmlSchemaAny
+ extends XmlSchemaParticle
+ implements XmlSchemaChoiceMember, XmlSchemaSequenceMember, XmlSchemaAllMember
+{
+ /**
+ * Namespaces containing the elements that can be used.
+ */
+ private namespace: string | null = null;
+ private processContent: XmlSchemaContentProcessing = XmlSchemaContentProcessing.NONE;
+ private targetNamespace: string | null = null;
+
+ getNamespace() {
+ return this.namespace;
+ }
+
+ setNamespace(namespace: string | null) {
+ this.namespace = namespace;
+ }
+
+ getProcessContent() {
+ return this.processContent;
+ }
+
+ setProcessContent(processContent: XmlSchemaContentProcessing) {
+ this.processContent = processContent;
+ }
+
+ /**
+ * {@link #getNamespace()} returns the namespace or set of namespaces
+ * that this wildcard element is valid for. The target namespaces may
+ * include ##other
, ##targetNamespace
. The
+ * ##other
directive means any namespace other than the
+ * schema's target namespace, while the ##targetNamespace
+ * directive means the element must be in the schema's target
+ * namespace. Resolving either of these requires knowledge of what
+ * the schema's target namespace is, which is returned by this method.
+ *
+ * @return The wildcard element's target namespace.
+ */
+ getTargetNamespace() {
+ return this.targetNamespace;
+ }
+
+ /**
+ * Sets the schema's target namespace.
+ *
+ * @param namespace The schema's target namespace.
+ *
+ * @see #getTargetNamespace()
+ */
+ setTargetNamespace(namespace: string | null) {
+ this.targetNamespace = namespace;
+ }
+}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaChoice.ts b/packages/xml-schema-ts/src/particle/XmlSchemaChoice.ts
new file mode 100644
index 000000000..87066cdbc
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaChoice.ts
@@ -0,0 +1,17 @@
+import { XmlSchemaChoiceMember } from './XmlSchemaChoiceMember';
+import { XmlSchemaGroupParticle } from './XmlSchemaGroupParticle';
+import { XmlSchemaSequenceMember } from './XmlSchemaSequenceMember';
+
+/**
+ * Allows only one of its children to appear in an instance. Represents the World Wide Web Consortium (W3C)
+ * choice (compositor) element.
+ *
+ * This can contain any of (element|group|choice|sequence|any)*.
+ */
+export class XmlSchemaChoice extends XmlSchemaGroupParticle implements XmlSchemaChoiceMember, XmlSchemaSequenceMember {
+ private items: XmlSchemaChoiceMember[] = [];
+
+ public getItems() {
+ return this.items;
+ }
+}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaChoiceMember.ts b/packages/xml-schema-ts/src/particle/XmlSchemaChoiceMember.ts
new file mode 100644
index 000000000..fe661a4da
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaChoiceMember.ts
@@ -0,0 +1,4 @@
+import { XmlSchemaObjectBase } from '../utils/XmlSchemaObjectBase';
+
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+export interface XmlSchemaChoiceMember extends XmlSchemaObjectBase {}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaElement.ts b/packages/xml-schema-ts/src/particle/XmlSchemaElement.ts
new file mode 100644
index 000000000..3c998e4c0
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaElement.ts
@@ -0,0 +1,248 @@
+import type { QName } from '../QName';
+import type { TypeReceiver } from '../TypeReceiver';
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaAllMember } from './XmlSchemaAllMember';
+import type { XmlSchemaChoiceMember } from './XmlSchemaChoiceMember';
+import type { XmlSchemaForm } from '../XmlSchemaForm';
+import type { XmlSchemaIdentityConstraint } from '../constraint/XmlSchemaIdentityConstraint';
+import type { XmlSchemaItemWithRef } from '../XmlSchemaItemWithRef';
+import type { XmlSchemaSequenceMember } from './XmlSchemaSequenceMember';
+import type { XmlSchemaType } from '../XmlSchemaType';
+import type { XmlSchemaNamedWithForm } from '../utils/XmlSchemaNamedWithForm';
+
+import { XmlSchemaNamedWithFormImpl } from '../utils/XmlSchemaNamedWithFormImpl';
+import { XmlSchemaRef } from '../utils/XmlSchemaRef';
+import { XmlSchemaNamedType } from '../utils/XmlSchemaNamedType';
+import { XmlSchemaParticle } from './XmlSchemaParticle';
+import { XmlSchemaDerivationMethod } from '../XmlSchemaDerivationMethod';
+
+export class XmlSchemaElement
+ extends XmlSchemaParticle
+ implements
+ TypeReceiver,
+ XmlSchemaNamedWithForm,
+ XmlSchemaChoiceMember,
+ XmlSchemaSequenceMember,
+ XmlSchemaAllMember,
+ XmlSchemaItemWithRef
+{
+ /**
+ * Attribute used to block a type derivation.
+ */
+ private block: XmlSchemaDerivationMethod;
+
+ private constraints: XmlSchemaIdentityConstraint[] = [];
+
+ /**
+ * Provides the default value of the element if its content is a simple type or the element's content is
+ * textOnly.
+ */
+ defaultValue: string | null = null;
+ fixedValue: string | null = null;
+
+ finalDerivation: XmlSchemaDerivationMethod;
+
+ abstractElement: boolean;
+ nillable: boolean;
+ ref: XmlSchemaRef;
+
+ /**
+ * Returns the type of the element. This can either be a complex type or a simple type.
+ */
+ private schemaType: XmlSchemaType | null = null;
+
+ /**
+ * QName of a built-in data type defined in this schema or another schema indicated by the specified
+ * namespace.
+ */
+ private schemaTypeName: QName | null = null;
+
+ /**
+ * QName of an element that can be a substitute for this element.
+ */
+ private substitutionGroup: QName | null = null;
+
+ private namedDelegate: XmlSchemaNamedWithFormImpl;
+
+ /**
+ * Creates new XmlSchemaElement
+ */
+ constructor(parentSchema: XmlSchema, topLevel: boolean) {
+ super();
+ this.namedDelegate = new XmlSchemaNamedWithFormImpl(parentSchema, topLevel, true);
+ this.ref = new XmlSchemaRef(parentSchema, XmlSchemaNamedType.XmlSchemaElement);
+ this.namedDelegate.setRefObject(this.ref);
+ this.ref.setNamedObject(this.namedDelegate);
+
+ this.abstractElement = false;
+ this.nillable = false;
+ this.finalDerivation = XmlSchemaDerivationMethod.NONE;
+ this.block = XmlSchemaDerivationMethod.NONE;
+ const fParentSchema = parentSchema;
+ if (topLevel) {
+ fParentSchema.getItems().push(this);
+ }
+ }
+
+ /**
+ * Returns a collection of constraints on the element.
+ */
+ getConstraints() {
+ return this.constraints;
+ }
+
+ getDefaultValue() {
+ return this.defaultValue;
+ }
+
+ setDefaultValue(defaultValue: string | null) {
+ this.defaultValue = defaultValue;
+ }
+
+ getBlock(): XmlSchemaDerivationMethod {
+ return this.block;
+ }
+
+ setBlock(block: XmlSchemaDerivationMethod) {
+ this.block = block;
+ }
+
+ getFinal(): XmlSchemaDerivationMethod {
+ return this.finalDerivation;
+ }
+
+ setFinal(finalDerivationValue: XmlSchemaDerivationMethod) {
+ this.finalDerivation = finalDerivationValue;
+ }
+
+ getFixedValue() {
+ return this.fixedValue;
+ }
+
+ setFixedValue(fixedValue: string | null) {
+ this.fixedValue = fixedValue;
+ }
+
+ isAbstract() {
+ return this.abstractElement;
+ }
+
+ setAbstract(isAbstract: boolean) {
+ this.abstractElement = isAbstract;
+ }
+
+ isNillable() {
+ return this.nillable;
+ }
+
+ setNillable(isNillable: boolean) {
+ this.nillable = isNillable;
+ }
+
+ getRef() {
+ return this.ref;
+ }
+
+ getSchemaType() {
+ return this.schemaType;
+ }
+
+ setSchemaType(schemaType: XmlSchemaType | null) {
+ this.schemaType = schemaType;
+ }
+
+ getSchemaTypeName() {
+ return this.schemaTypeName;
+ }
+
+ setSchemaTypeName(schemaTypeName: QName | null) {
+ this.schemaTypeName = schemaTypeName;
+ }
+
+ getSubstitutionGroup() {
+ return this.substitutionGroup;
+ }
+
+ setSubstitutionGroup(substitutionGroup: QName) {
+ this.substitutionGroup = substitutionGroup;
+ }
+
+ setType(type: XmlSchemaType) {
+ this.schemaType = type;
+ }
+
+ getName() {
+ return this.namedDelegate.getName();
+ }
+
+ getParent() {
+ return this.namedDelegate.getParent();
+ }
+
+ getQName() {
+ return this.namedDelegate.getQName();
+ }
+
+ isAnonymous() {
+ return this.namedDelegate.isAnonymous();
+ }
+
+ isTopLevel() {
+ return this.namedDelegate.isTopLevel();
+ }
+
+ setName(name: string | null) {
+ const fName = name;
+ if (this.isTopLevel() && this.getName() != null) {
+ this.getParent().getElements().delete(this.getQName()!);
+ }
+ this.namedDelegate.setName(fName);
+ if (this.namedDelegate.isTopLevel()) {
+ this.getParent().getElements().set(this.getQName()!, this);
+ }
+ }
+
+ getForm() {
+ return this.namedDelegate.getForm();
+ }
+
+ isFormSpecified() {
+ return this.namedDelegate.isFormSpecified();
+ }
+
+ setForm(form: XmlSchemaForm) {
+ this.namedDelegate.setForm(form);
+ }
+
+ getWireName() {
+ return this.namedDelegate.getWireName();
+ }
+
+ setFinalDerivation(finalDerivation: XmlSchemaDerivationMethod) {
+ this.finalDerivation = finalDerivation;
+ }
+
+ getFinalDerivation() {
+ return this.finalDerivation;
+ }
+
+ setAbstractElement(abstractElement: boolean) {
+ this.abstractElement = abstractElement;
+ }
+
+ isAbstractElement() {
+ return this.abstractElement;
+ }
+
+ isRef() {
+ return this.ref.getTargetQName() != null;
+ }
+
+ getTargetQName() {
+ return this.ref.getTargetQName();
+ }
+
+ getRefBase() {
+ return this.ref;
+ }
+}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaGroupParticle.ts b/packages/xml-schema-ts/src/particle/XmlSchemaGroupParticle.ts
new file mode 100644
index 000000000..a729ec0b3
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaGroupParticle.ts
@@ -0,0 +1,6 @@
+import { XmlSchemaParticle } from './XmlSchemaParticle';
+
+/**
+ * Common type for items that can serve as the particle of a group.
+ */
+export abstract class XmlSchemaGroupParticle extends XmlSchemaParticle {}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaGroupRef.ts b/packages/xml-schema-ts/src/particle/XmlSchemaGroupRef.ts
new file mode 100644
index 000000000..c3af24e22
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaGroupRef.ts
@@ -0,0 +1,35 @@
+import type { QName } from '../QName';
+import type { XmlSchemaGroupParticle } from './XmlSchemaGroupParticle';
+import type { XmlSchemaAllMember } from './XmlSchemaAllMember';
+import type { XmlSchemaChoiceMember } from './XmlSchemaChoiceMember';
+import type { XmlSchemaSequenceMember } from './XmlSchemaSequenceMember';
+import { XmlSchemaParticle } from './XmlSchemaParticle';
+
+/**
+ * Class used within complex types that defines the reference to groups defined at the schema level.
+ * Represents the World Wide Web Consortium (W3C) group element with ref attribute.
+ */
+export class XmlSchemaGroupRef
+ extends XmlSchemaParticle
+ implements XmlSchemaSequenceMember, XmlSchemaChoiceMember, XmlSchemaAllMember
+{
+ private particle: XmlSchemaGroupParticle | null = null;
+
+ private refName: QName | null = null;
+
+ getParticle() {
+ return this.particle;
+ }
+
+ getRefName() {
+ return this.refName;
+ }
+
+ setRefName(refName: QName) {
+ this.refName = refName;
+ }
+
+ setParticle(particle: XmlSchemaGroupParticle) {
+ this.particle = particle;
+ }
+}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaParticle.ts b/packages/xml-schema-ts/src/particle/XmlSchemaParticle.ts
new file mode 100644
index 000000000..2394f4e24
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaParticle.ts
@@ -0,0 +1,25 @@
+import { XmlSchemaAnnotated } from '../XmlSchemaAnnotated';
+
+export abstract class XmlSchemaParticle extends XmlSchemaAnnotated {
+ static readonly DEFAULT_MAX_OCCURS = 1;
+ static readonly DEFAULT_MIN_OCCURS = 1;
+
+ private maxOccurs = XmlSchemaParticle.DEFAULT_MAX_OCCURS;
+ private minOccurs = XmlSchemaParticle.DEFAULT_MIN_OCCURS;
+
+ setMaxOccurs(maxOccurs: number) {
+ this.maxOccurs = maxOccurs;
+ }
+
+ getMaxOccurs() {
+ return this.maxOccurs;
+ }
+
+ setMinOccurs(minOccurs: number) {
+ this.minOccurs = minOccurs;
+ }
+
+ getMinOccurs() {
+ return this.minOccurs;
+ }
+}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaSequence.ts b/packages/xml-schema-ts/src/particle/XmlSchemaSequence.ts
new file mode 100644
index 000000000..79d0221f1
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaSequence.ts
@@ -0,0 +1,24 @@
+/**
+ * Requires the elements in the group to appear in the specified sequence within the containing element.
+ * Represents the World Wide Web Consortium (W3C) sequence (compositor) element.
+ *
+ * (element|group|choice|sequence|any)
+ */
+import { XmlSchemaSequenceMember } from './XmlSchemaSequenceMember';
+import { XmlSchemaChoiceMember } from './XmlSchemaChoiceMember';
+import { XmlSchemaGroupParticle } from './XmlSchemaGroupParticle';
+
+export class XmlSchemaSequence
+ extends XmlSchemaGroupParticle
+ implements XmlSchemaChoiceMember, XmlSchemaSequenceMember
+{
+ private items: XmlSchemaSequenceMember[] = [];
+
+ /**
+ * The elements contained within the compositor. Collection of XmlSchemaElement, XmlSchemaGroupRef,
+ * XmlSchemaChoice, XmlSchemaSequence, or XmlSchemaAny.
+ */
+ getItems() {
+ return this.items;
+ }
+}
diff --git a/packages/xml-schema-ts/src/particle/XmlSchemaSequenceMember.ts b/packages/xml-schema-ts/src/particle/XmlSchemaSequenceMember.ts
new file mode 100644
index 000000000..1f191026e
--- /dev/null
+++ b/packages/xml-schema-ts/src/particle/XmlSchemaSequenceMember.ts
@@ -0,0 +1,4 @@
+import { XmlSchemaObjectBase } from '../utils/XmlSchemaObjectBase';
+
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+export interface XmlSchemaSequenceMember extends XmlSchemaObjectBase {}
diff --git a/packages/xml-schema-ts/src/resolver/CollectionURIResolver.ts b/packages/xml-schema-ts/src/resolver/CollectionURIResolver.ts
new file mode 100644
index 000000000..0724f483d
--- /dev/null
+++ b/packages/xml-schema-ts/src/resolver/CollectionURIResolver.ts
@@ -0,0 +1,7 @@
+import { URIResolver } from './URIResolver';
+
+export interface CollectionURIResolver extends URIResolver {
+ setCollectionBaseURI(uri: string): void;
+
+ getCollectionBaseURI(): string | undefined;
+}
diff --git a/packages/xml-schema-ts/src/resolver/DefaultURIResolver.ts b/packages/xml-schema-ts/src/resolver/DefaultURIResolver.ts
new file mode 100644
index 000000000..7ad9a0418
--- /dev/null
+++ b/packages/xml-schema-ts/src/resolver/DefaultURIResolver.ts
@@ -0,0 +1,19 @@
+import { CollectionURIResolver } from './CollectionURIResolver';
+
+export class DefaultURIResolver implements CollectionURIResolver {
+ private collectionBaseUri?: string;
+
+ getCollectionBaseURI(): string | undefined {
+ return this.collectionBaseUri;
+ }
+
+ resolveEntity(targetNamespace: string | null, schemaLocation: string, baseUri: string | null): string {
+ throw new Error(
+ `XML schema External entity resolution is not yet supported: [namespace:${targetNamespace}, schemaLocation:${schemaLocation}, baseUri:${baseUri}]`,
+ );
+ }
+
+ setCollectionBaseURI(uri: string): void {
+ this.collectionBaseUri = uri;
+ }
+}
diff --git a/packages/xml-schema-ts/src/resolver/URIResolver.ts b/packages/xml-schema-ts/src/resolver/URIResolver.ts
new file mode 100644
index 000000000..9a50e10f5
--- /dev/null
+++ b/packages/xml-schema-ts/src/resolver/URIResolver.ts
@@ -0,0 +1,3 @@
+export interface URIResolver {
+ resolveEntity(targetNamespace: string | null, schemaLocation: string, baseUri: string | null): string;
+}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContent.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContent.ts
new file mode 100644
index 000000000..0eb04b0ab
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContent.ts
@@ -0,0 +1,19 @@
+/**
+ * Class for simple types and complex types with a simple content model. Represents the World Wide Web
+ * Consortium (W3C) simpleContent element.
+ */
+import type { XmlSchemaContent } from '../XmlSchemaContent';
+import { XmlSchemaContentModel } from '../XmlSchemaContentModel';
+
+export class XmlSchemaSimpleContent extends XmlSchemaContentModel {
+ /* One of XmlSchemaSimpleContentRestriction or XmlSchemaSimpleContentExtension. */
+ content: XmlSchemaContent | null = null;
+
+ getContent() {
+ return this.content;
+ }
+
+ setContent(content: XmlSchemaContent) {
+ this.content = content;
+ }
+}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContentExtension.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContentExtension.ts
new file mode 100644
index 000000000..1148d1c39
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContentExtension.ts
@@ -0,0 +1,46 @@
+import type { XmlSchemaAttributeOrGroupRef } from '../attribute/XmlSchemaAttributeOrGroupRef';
+import type { XmlSchemaAnyAttribute } from '../XmlSchemaAnyAttribute';
+import type { QName } from '../QName';
+import { XmlSchemaContent } from '../XmlSchemaContent';
+
+/**
+ * Class for simple types that are derived by extension. Extends the simple type content of the element by
+ * adding attributes. Represents the World Wide Web Consortium (W3C) extension element for simple content.
+ */
+export class XmlSchemaSimpleContentExtension extends XmlSchemaContent {
+ /* Allows an XmlSchemaAnyAttribute to be used for the attribute value. */
+ private anyAttribute: XmlSchemaAnyAttribute | null = null;
+
+ /*
+ * Contains XmlSchemaAttribute and XmlSchemaAttributeGroupRef. Collection of attributes for the simple
+ * type.
+ */
+ private attributes: XmlSchemaAttributeOrGroupRef[] = [];
+
+ /* Name of the built-in data type, simple type, or complex type. */
+ private baseTypeName: QName | null = null;
+
+ getAnyAttribute() {
+ return this.anyAttribute;
+ }
+
+ getAttributes() {
+ return this.attributes;
+ }
+
+ getBaseTypeName() {
+ return this.baseTypeName;
+ }
+
+ setAnyAttribute(anyAttribute: XmlSchemaAnyAttribute) {
+ this.anyAttribute = anyAttribute;
+ }
+
+ setBaseTypeName(baseTypeName: QName) {
+ this.baseTypeName = baseTypeName;
+ }
+
+ setAttributes(attributes: XmlSchemaAttributeOrGroupRef[]) {
+ this.attributes = attributes;
+ }
+}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContentRestriction.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContentRestriction.ts
new file mode 100644
index 000000000..2451d5ee5
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleContentRestriction.ts
@@ -0,0 +1,64 @@
+/**
+ * Class for simple types that are derived by restriction. Restricts the range of values for the element to a
+ * subset of the inherited simple types. Represents the World Wide Web Consortium (W3C) restriction element
+ * for simple content.
+ */
+
+import type { QName } from '../QName';
+import type { XmlSchemaAnyAttribute } from '../XmlSchemaAnyAttribute';
+import type { XmlSchemaAttributeOrGroupRef } from '../attribute/XmlSchemaAttributeOrGroupRef';
+import type { XmlSchemaFacet } from '../facet/XmlSchemaFacet';
+import type { XmlSchemaSimpleType } from './XmlSchemaSimpleType';
+import { XmlSchemaContent } from '../XmlSchemaContent';
+
+export class XmlSchemaSimpleContentRestriction extends XmlSchemaContent {
+ anyAttribute: XmlSchemaAnyAttribute | null = null;
+ /*
+ * Contains XmlSchemaAttribute and XmlSchemaAttributeGroupRef. Collection of attributes for the simple
+ * type.
+ */
+ private attributes: XmlSchemaAttributeOrGroupRef[] = [];
+
+ /* Derived from the type specified by the base value. */
+ private baseType: XmlSchemaSimpleType | null = null;
+
+ /* Name of the built-in data type, simple type, or complex type. */
+ private baseTypeName: QName | null = null;
+
+ /* One or more of the facet classes: */
+ private facets: XmlSchemaFacet[] = [];
+
+ /* Allows an XmlSchemaAnyAttribute to be used for the attribute value. */
+
+ setAnyAttribute(anyAttribute: XmlSchemaAnyAttribute) {
+ this.anyAttribute = anyAttribute;
+ }
+
+ getAnyAttribute() {
+ return this.anyAttribute;
+ }
+
+ getAttributes() {
+ return this.attributes;
+ }
+
+ setBaseType(baseType: XmlSchemaSimpleType) {
+ this.baseType = baseType;
+ }
+
+ getBaseType() {
+ return this.baseType;
+ }
+
+ setBaseTypeName(baseTypeName: QName) {
+ this.baseTypeName = baseTypeName;
+ }
+
+ getBaseTypeName() {
+ return this.baseTypeName;
+ }
+
+ getFacets() {
+ return this.facets;
+ }
+}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleType.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleType.ts
new file mode 100644
index 000000000..88c66b339
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleType.ts
@@ -0,0 +1,14 @@
+import type { XmlSchemaSimpleTypeContent } from './XmlSchemaSimpleTypeContent';
+
+import { XmlSchemaType } from '../XmlSchemaType';
+
+export class XmlSchemaSimpleType extends XmlSchemaType {
+ content?: XmlSchemaSimpleTypeContent;
+
+ getContent() {
+ return this.content;
+ }
+ setContent(content: XmlSchemaSimpleTypeContent) {
+ this.content = content;
+ }
+}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeContent.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeContent.ts
new file mode 100644
index 000000000..868336ccd
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeContent.ts
@@ -0,0 +1,3 @@
+import { XmlSchemaAnnotated } from '../XmlSchemaAnnotated';
+
+export abstract class XmlSchemaSimpleTypeContent extends XmlSchemaAnnotated {}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeList.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeList.ts
new file mode 100644
index 000000000..b3d145013
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeList.ts
@@ -0,0 +1,25 @@
+import type { QName } from '../QName';
+import type { XmlSchemaSimpleType } from './XmlSchemaSimpleType';
+
+import { XmlSchemaSimpleTypeContent } from './XmlSchemaSimpleTypeContent';
+
+export class XmlSchemaSimpleTypeList extends XmlSchemaSimpleTypeContent {
+ itemType?: XmlSchemaSimpleType;
+ itemTypeName?: QName;
+
+ getItemType() {
+ return this.itemType;
+ }
+
+ setItemType(itemType: XmlSchemaSimpleType) {
+ this.itemType = itemType;
+ }
+
+ getItemTypeName() {
+ return this.itemTypeName;
+ }
+
+ setItemTypeName(itemTypeName: QName) {
+ this.itemTypeName = itemTypeName;
+ }
+}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeRestriction.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeRestriction.ts
new file mode 100644
index 000000000..04b44d790
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeRestriction.ts
@@ -0,0 +1,31 @@
+import type { XmlSchemaSimpleType } from './XmlSchemaSimpleType';
+import type { XmlSchemaFacet } from '../facet/XmlSchemaFacet';
+import type { QName } from '../QName';
+
+import { XmlSchemaSimpleTypeContent } from './XmlSchemaSimpleTypeContent';
+
+export class XmlSchemaSimpleTypeRestriction extends XmlSchemaSimpleTypeContent {
+ private baseType?: XmlSchemaSimpleType;
+ private baseTypeName?: QName;
+ private facets: XmlSchemaFacet[] = [];
+
+ getBaseType() {
+ return this.baseType;
+ }
+
+ setBaseType(baseType: XmlSchemaSimpleType) {
+ this.baseType = baseType;
+ }
+
+ getBaseTypeName() {
+ return this.baseTypeName;
+ }
+
+ setBaseTypeName(baseTypeName: QName) {
+ this.baseTypeName = baseTypeName;
+ }
+
+ getFacets() {
+ return this.facets;
+ }
+}
diff --git a/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeUnion.ts b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeUnion.ts
new file mode 100644
index 000000000..44fd301b9
--- /dev/null
+++ b/packages/xml-schema-ts/src/simple/XmlSchemaSimpleTypeUnion.ts
@@ -0,0 +1,33 @@
+/**
+ * Class for the union of simpleType elements. Defines a simpleType element as a list of values of a specified
+ * data type. Represents the World Wide Web Consortium (W3C) union element.
+ */
+import type { QName } from '../QName';
+import type { XmlSchemaSimpleType } from './XmlSchemaSimpleType';
+import { XmlSchemaSimpleTypeContent } from './XmlSchemaSimpleTypeContent';
+
+export class XmlSchemaSimpleTypeUnion extends XmlSchemaSimpleTypeContent {
+ private baseTypes: XmlSchemaSimpleType[] = [];
+ private memberTypesSource: string | null = null;
+ private memberTypesQNames: QName[] = [];
+
+ getBaseTypes() {
+ return this.baseTypes;
+ }
+
+ setMemberTypesSource(memberTypesSources: string) {
+ this.memberTypesSource = memberTypesSources;
+ }
+
+ getMemberTypesSource() {
+ return this.memberTypesSource;
+ }
+
+ getMemberTypesQNames() {
+ return this.memberTypesQNames;
+ }
+
+ setMemberTypesQNames(memberTypesQNames: QName[]) {
+ this.memberTypesQNames = memberTypesQNames;
+ }
+}
diff --git a/packages/xml-schema-ts/src/utils/NamespaceContext.ts b/packages/xml-schema-ts/src/utils/NamespaceContext.ts
new file mode 100644
index 000000000..dbbded459
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/NamespaceContext.ts
@@ -0,0 +1,7 @@
+export interface NamespaceContext {
+ getNamespaceURI(var1: string): string;
+
+ getPrefix(var1: string): string;
+
+ getPrefixes(var1: string): string[];
+}
diff --git a/packages/xml-schema-ts/src/utils/NamespaceContextOwner.ts b/packages/xml-schema-ts/src/utils/NamespaceContextOwner.ts
new file mode 100644
index 000000000..2877281e3
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/NamespaceContextOwner.ts
@@ -0,0 +1,5 @@
+import { NamespacePrefixList } from './NamespacePrefixList';
+
+export interface NamespaceContextOwner {
+ getNamespaceContext(): NamespacePrefixList | null;
+}
diff --git a/packages/xml-schema-ts/src/utils/NamespacePrefixList.ts b/packages/xml-schema-ts/src/utils/NamespacePrefixList.ts
new file mode 100644
index 000000000..5a7408639
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/NamespacePrefixList.ts
@@ -0,0 +1,5 @@
+import { NamespaceContext } from './NamespaceContext';
+
+export interface NamespacePrefixList extends NamespaceContext {
+ getDeclaredPrefixes(): string[];
+}
diff --git a/packages/xml-schema-ts/src/utils/NodeNamespaceContext.ts b/packages/xml-schema-ts/src/utils/NodeNamespaceContext.ts
new file mode 100644
index 000000000..43f2127fc
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/NodeNamespaceContext.ts
@@ -0,0 +1,67 @@
+import type { NamespacePrefixList } from './NamespacePrefixList';
+import { NULL_NS_URI, XML_NS_PREFIX, XML_NS_URI, XMLNS_ATTRIBUTE, XMLNS_ATTRIBUTE_NS_URI } from '../constants';
+import { PrefixCollector } from './PrefixCollector';
+
+export class NodeNamespaceContext implements NamespacePrefixList {
+ private prefixes?: string[];
+
+ private constructor(private declarations: Record) {}
+
+ static getNamespaceContext(pNode: Node): NodeNamespaceContext {
+ const declarations: Record = {};
+ PrefixCollector.searchAllPrefixDeclarations(pNode, (pPrefix: string, pNamespaceURI: string) => {
+ declarations[pPrefix] = pNamespaceURI;
+ });
+ return new NodeNamespaceContext(declarations);
+ }
+
+ getDeclaredPrefixes(): string[] {
+ if (this.prefixes == null) {
+ this.prefixes = Object.keys(this.declarations);
+ }
+ return this.prefixes;
+ }
+
+ getNamespaceURI(pPrefix: string): string {
+ if (pPrefix == null) {
+ throw new Error('Prefix cannot be null');
+ }
+ if (XML_NS_PREFIX === pPrefix) {
+ return XML_NS_URI;
+ }
+ if (XMLNS_ATTRIBUTE === pPrefix) {
+ return XMLNS_ATTRIBUTE_NS_URI;
+ }
+ const uri = this.declarations[pPrefix];
+ return uri == null ? NULL_NS_URI : uri;
+ }
+
+ getPrefix(pNamespaceURI: string): string {
+ if (pNamespaceURI == null) {
+ throw new Error('Namespace URI cannot be null');
+ }
+ if (XML_NS_URI === pNamespaceURI) {
+ return XML_NS_PREFIX;
+ }
+ if (XMLNS_ATTRIBUTE_NS_URI === pNamespaceURI) {
+ return XMLNS_ATTRIBUTE;
+ }
+ const found = Object.entries(this.declarations).find((entry) => entry[1] === pNamespaceURI);
+ return found ? found[0] : '';
+ }
+
+ getPrefixes(pNamespaceURI: string): string[] {
+ if (pNamespaceURI == null) {
+ throw new Error('Namespace URI cannot be null');
+ }
+ if (XML_NS_URI === pNamespaceURI) {
+ return [XML_NS_PREFIX];
+ }
+ if (XMLNS_ATTRIBUTE_NS_URI === pNamespaceURI) {
+ return [XMLNS_ATTRIBUTE];
+ }
+ return Object.entries(this.declarations)
+ .filter((entry) => entry[1] === pNamespaceURI)
+ .map((entry) => entry[0]);
+ }
+}
diff --git a/packages/xml-schema-ts/src/utils/ObjectMap.test.ts b/packages/xml-schema-ts/src/utils/ObjectMap.test.ts
new file mode 100644
index 000000000..ed776a44f
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/ObjectMap.test.ts
@@ -0,0 +1,33 @@
+import { QNameMap, SchemaKeyMap } from './ObjectMap';
+import { XmlSchema } from '../XmlSchema';
+import { SchemaKey } from '../SchemaKey';
+import { QName } from '../QName';
+
+describe('ObjectMap', () => {
+ describe('SchemaKeyMap', () => {
+ it('keys(), values() and entries() should work', () => {
+ const map = new SchemaKeyMap();
+ map.set(new SchemaKey('a', 'b'), new XmlSchema());
+ map.set(new SchemaKey('c', 'd'), new XmlSchema());
+ let keys = map.keys();
+ expect(keys.next().value.getNamespace()).toEqual('a');
+ expect(keys.next().value.getNamespace()).toEqual('c');
+ keys = map.keys();
+ const keysArray = Array.from(keys);
+ expect(keysArray.length).toEqual(2);
+ const values = map.values();
+ expect(Array.from(values).length).toEqual(2);
+ const entries = map.entries();
+ expect(Array.from(entries).length).toEqual(2);
+ });
+ });
+
+ describe('QNameMap', () => {
+ it('should ignore QName prefix', () => {
+ const map = new QNameMap();
+ map.set(new QName('a', 'b'), new XmlSchema());
+ map.set(new QName('c', 'd'), new XmlSchema());
+ expect(map.get(new QName('a', 'b', 'c'))).toBeTruthy();
+ });
+ });
+});
diff --git a/packages/xml-schema-ts/src/utils/ObjectMap.ts b/packages/xml-schema-ts/src/utils/ObjectMap.ts
new file mode 100644
index 000000000..587a6b524
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/ObjectMap.ts
@@ -0,0 +1,112 @@
+import { QName } from '../QName';
+import { SchemaKey } from '../SchemaKey';
+
+/**
+ * The Map which uses a class instance as a key where if the stringified key matches then it's considered same.
+ */
+abstract class ObjectMap {
+ private delegate = new Map();
+
+ get(key: K) {
+ return this.delegate.get(this.keyToString(key));
+ }
+
+ set(key: K, value: V) {
+ this.delegate.set(this.keyToString(key), value);
+ }
+
+ has(key: K) {
+ return this.delegate.has(this.keyToString(key));
+ }
+
+ delete(key: K) {
+ this.delegate.delete(this.keyToString(key));
+ }
+
+ get size() {
+ return this.delegate.size;
+ }
+
+ clear() {
+ this.delegate.clear();
+ }
+
+ abstract stringToKey(stringified: string): K;
+ abstract keyToString(key: K): string;
+
+ keys(): IterableIterator {
+ const delegateKeys = this.delegate.keys();
+ return new KeysBridge(delegateKeys, this.stringToKey);
+ }
+
+ entries(): IterableIterator<[K, V]> {
+ const delegateEntries = this.delegate.entries();
+ return new EntriesBridge(delegateEntries, this.stringToKey);
+ }
+
+ values(): IterableIterator {
+ return this.delegate.values();
+ }
+}
+
+class KeysBridge implements IterableIterator {
+ constructor(
+ private delegateKeys: IterableIterator,
+ private stringToKey: (stringifiedKey: string) => K,
+ ) {}
+
+ [Symbol.iterator](): IterableIterator {
+ return this;
+ }
+
+ /* eslint-disable @typescript-eslint/no-explicit-any */
+ next(): IteratorResult {
+ const next = this.delegateKeys.next();
+ if (!next.value) {
+ return next as any;
+ }
+ const key: K = this.stringToKey(next.value);
+ return { value: key };
+ }
+}
+
+class EntriesBridge implements IterableIterator<[K, V]> {
+ constructor(
+ private delegateEntries: IterableIterator<[string, V]>,
+ private stringToKey: (stringifiedKey: string) => K,
+ ) {}
+
+ [Symbol.iterator](): IterableIterator<[K, V]> {
+ return this;
+ }
+
+ /* eslint-disable @typescript-eslint/no-explicit-any */
+ next(): IteratorResult<[K, V], [K, V] | undefined> {
+ const next = this.delegateEntries.next();
+ if (!next.value) {
+ return next as any;
+ }
+ const key: K = this.stringToKey(next.value[0]);
+ return { value: [key, next.value[1]] };
+ }
+}
+
+export class QNameMap extends ObjectMap {
+ stringToKey(stringified: string): QName {
+ const obj = Object.assign(new QName(null, null), JSON.parse(stringified));
+ obj.prefix = undefined;
+ return obj;
+ }
+ keyToString(key: QName): string {
+ return JSON.stringify(new QName(key.getNamespaceURI(), key.getLocalPart()));
+ }
+}
+
+export class SchemaKeyMap extends ObjectMap {
+ stringToKey(stringified: string): SchemaKey {
+ return Object.assign(new SchemaKey(), JSON.parse(stringified));
+ }
+ keyToString(key: SchemaKey): string {
+ return JSON.stringify(key);
+ }
+}
diff --git a/packages/xml-schema-ts/src/utils/PrefixCollector.ts b/packages/xml-schema-ts/src/utils/PrefixCollector.ts
new file mode 100644
index 000000000..4eb1617cb
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/PrefixCollector.ts
@@ -0,0 +1,33 @@
+import { DEFAULT_NS_PREFIX, XMLNS_ATTRIBUTE, XMLNS_ATTRIBUTE_NS_URI } from '../constants';
+
+export class PrefixCollector {
+ static searchLocalPrefixDeclarations(
+ pNode: Node,
+ declarePrefix: (pPrefix: string, pNamespaceURI: string) => void,
+ ): void {
+ const type = pNode.nodeType;
+ if (type === Node.ELEMENT_NODE || type === Node.DOCUMENT_NODE) {
+ const map = (pNode as Element).attributes;
+ for (let i = 0; map != null && i < map.length; i++) {
+ const attr = map.item(i);
+ const uri = attr?.namespaceURI;
+ if (XMLNS_ATTRIBUTE_NS_URI === uri) {
+ const localName = attr?.localName;
+ const prefix = XMLNS_ATTRIBUTE === localName ? DEFAULT_NS_PREFIX : localName;
+ declarePrefix(prefix!, attr!.nodeValue!);
+ }
+ }
+ }
+ }
+
+ static searchAllPrefixDeclarations(
+ pNode: Node,
+ declarePrefix: (pPrefix: string, pNamespaceURI: string) => void,
+ ): void {
+ const parent = pNode.parentNode;
+ if (parent != null) {
+ PrefixCollector.searchAllPrefixDeclarations(parent, declarePrefix);
+ }
+ PrefixCollector.searchLocalPrefixDeclarations(pNode, declarePrefix);
+ }
+}
diff --git a/packages/xml-schema-ts/src/utils/XDOMUtil.ts b/packages/xml-schema-ts/src/utils/XDOMUtil.ts
new file mode 100644
index 000000000..d728d4e01
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XDOMUtil.ts
@@ -0,0 +1,85 @@
+/**
+ * Merging DOMUtil and XDOMUtil. In TypeScript, inheritance and method overloading
+ * is different from Java, which caused a problem on these relationship.
+ */
+export class XDOMUtil {
+ /**
+ * Finds and returns the next sibling element node.
+ */
+ static getNextSiblingElement(node: Node): Element | null {
+ // search for node
+ let sibling = node.nextSibling;
+ while (sibling != null) {
+ if (sibling.nodeType == Node.ELEMENT_NODE) {
+ return sibling as Element;
+ }
+ sibling = sibling.nextSibling;
+ }
+ // not found
+ return null;
+ } // getNextSiblingElement(Node):Element
+
+ /**
+ * Finds and returns the first child node with the given qualified name.
+ */
+ static getFirstChildElementNS(parent: Node, uri: string, localpart?: string): Element | null {
+ // search for node
+ let child = parent.firstChild;
+ while (child != null) {
+ if (child.nodeType == Node.ELEMENT_NODE) {
+ const childElement = child as Element;
+ const childURI = childElement.namespaceURI;
+ if (childURI != null && childURI === uri) {
+ if (localpart == null || childElement.localName === localpart) {
+ return childElement;
+ }
+ }
+ }
+ child = child.nextSibling;
+ }
+ // not found
+ return null;
+ } // getFirstChildElementNS(Node,String,String):Element
+
+ /**
+ * Finds and returns the next sibling node with the given qualified name.
+ */
+ static getNextSiblingElementByNamesNS(node: Node, elemNames: string[][]) {
+ // search for node
+ let sibling = node.nextSibling;
+ while (sibling != null) {
+ if (sibling.nodeType == Node.ELEMENT_NODE) {
+ const siblingElement = sibling as Element;
+ for (const elemName of elemNames) {
+ const uri = siblingElement.namespaceURI;
+ if (uri != null && uri === elemName[0] && siblingElement.localName === elemName[1]) {
+ return siblingElement;
+ }
+ }
+ }
+ sibling = sibling.nextSibling;
+ }
+ // not found
+ return null;
+ } // getNextSiblingdElementNS(Node,String[][]):Element
+
+ /**
+ * Finds and returns the next sibling node with the given qualified name.
+ */
+ static getNextSiblingElementNS(node: Node, uri: string, localpart?: string) {
+ // search for node
+ let sibling = node.nextSibling;
+ while (sibling != null) {
+ if (sibling.nodeType == Node.ELEMENT_NODE) {
+ const siblingElement = sibling as Element;
+ const siblingURI = siblingElement.namespaceURI;
+ if (siblingURI != null && siblingURI === uri && (localpart == null || siblingElement.localName === localpart)) {
+ return siblingElement;
+ }
+ }
+ sibling = sibling.nextSibling;
+ }
+ // not found
+ return null;
+ } // getNextSiblingdElementNS(Node,String,String):Element
+}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaNamed.ts b/packages/xml-schema-ts/src/utils/XmlSchemaNamed.ts
new file mode 100644
index 000000000..87421280f
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaNamed.ts
@@ -0,0 +1,46 @@
+import type { QName } from '../QName';
+import type { XmlSchema } from '../XmlSchema';
+import { XmlSchemaObjectBase } from './XmlSchemaObjectBase';
+
+export interface XmlSchemaNamed extends XmlSchemaObjectBase {
+ /**
+ * Retrieve the name.
+ * @return the local name of this object within its schema.
+ */
+ getName(): string | null;
+
+ /**
+ * @return true if this object has no name.
+ */
+ isAnonymous(): boolean;
+
+ /**
+ * Set the name. Set to null to render the object anonymous, or to prepare to
+ * change it to refer to some other object.
+ * @param name the name.
+ */
+ setName(name: string): void;
+
+ /**
+ * Retrieve the parent schema.
+ * @return the containing schema.
+ */
+ getParent(): XmlSchema;
+
+ /**
+ * Get the QName for this object. This is always the formal name that identifies this
+ * item in the schema. If the item has a form (an element or attribute), and the form
+ * is 'unqualified', this is not the appropriate QName in an instance
+ * document. For those items, the getWiredName method returns the appropriate
+ * QName for an instance document.
+ * @see XmlSchemaNamedWithForm#getWireName()
+ * @return The qualified name of this object.
+ */
+ getQName(): QName | null;
+
+ /**
+ * @return true if this item is a top-level item of the schema; false if this item
+ * is nested inside of some other schema object.
+ */
+ isTopLevel(): boolean;
+}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaNamedImpl.ts b/packages/xml-schema-ts/src/utils/XmlSchemaNamedImpl.ts
new file mode 100644
index 000000000..d0c1ee86d
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaNamedImpl.ts
@@ -0,0 +1,72 @@
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaNamed } from './XmlSchemaNamed';
+import type { XmlSchemaRefBase } from './XmlSchemaRefBase';
+import { QName } from '../QName';
+
+export class XmlSchemaNamedImpl implements XmlSchemaNamed {
+ protected parentSchema: XmlSchema;
+ /*
+ * Some objects implement both name= and ref=. This reference allows us some error
+ * checking.
+ */
+ protected refTwin?: XmlSchemaRefBase;
+ // Store the name as a QName for the convenience of QName fans.
+ private qname: QName | null = null;
+ private topLevel: boolean = false;
+
+ /**
+ * Create a new named object.
+ * @param parent the parent schema.
+ * @param topLevel
+ */
+ constructor(parent: XmlSchema, topLevel: boolean) {
+ this.parentSchema = parent;
+ this.topLevel = topLevel;
+ }
+
+ /**
+ * If the named object also implements ref=, it should pass the reference object
+ * here for some error checking.
+ * @param refBase
+ */
+ setRefObject(refBase: XmlSchemaRefBase) {
+ this.refTwin = refBase;
+ }
+
+ getName() {
+ if (this.qname == null) {
+ return null;
+ } else {
+ return this.qname.getLocalPart();
+ }
+ }
+
+ isAnonymous() {
+ return this.qname == null;
+ }
+
+ setName(name: string | null) {
+ if (name == null) {
+ this.qname = null;
+ } else if ('' === name) {
+ throw new Error('Attempt to set empty name.');
+ } else {
+ if (this.refTwin != null && this.refTwin.getTargetQName() != null) {
+ throw new Error("Attempt to set name on object with ref='xxx'");
+ }
+ this.qname = new QName(this.parentSchema.getLogicalTargetNamespace(), name);
+ }
+ }
+
+ getParent() {
+ return this.parentSchema;
+ }
+
+ getQName() {
+ return this.qname;
+ }
+
+ public isTopLevel() {
+ return this.topLevel;
+ }
+}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaNamedType.ts b/packages/xml-schema-ts/src/utils/XmlSchemaNamedType.ts
new file mode 100644
index 000000000..0bcbe50d6
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaNamedType.ts
@@ -0,0 +1,8 @@
+export enum XmlSchemaNamedType {
+ XmlSchemaElement,
+ XmlSchemaAttribute,
+ XmlSchemaType,
+ XmlSchemaAttributeGroup,
+ XmlSchemaGroup,
+ XmlSchemaNotation,
+}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaNamedWithForm.ts b/packages/xml-schema-ts/src/utils/XmlSchemaNamedWithForm.ts
new file mode 100644
index 000000000..c540bc6be
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaNamedWithForm.ts
@@ -0,0 +1,4 @@
+import { XmlSchemaNamed } from './XmlSchemaNamed';
+
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+export interface XmlSchemaNamedWithForm extends XmlSchemaNamed {}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaNamedWithFormImpl.ts b/packages/xml-schema-ts/src/utils/XmlSchemaNamedWithFormImpl.ts
new file mode 100644
index 000000000..529f72dcb
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaNamedWithFormImpl.ts
@@ -0,0 +1,74 @@
+import type { XmlSchemaNamedWithForm } from './XmlSchemaNamedWithForm';
+import type { XmlSchema } from '../XmlSchema';
+import { XmlSchemaNamedImpl } from './XmlSchemaNamedImpl';
+import { QName } from '../QName';
+import { XmlSchemaForm } from '../XmlSchemaForm';
+
+/**
+ *
+ */
+export class XmlSchemaNamedWithFormImpl extends XmlSchemaNamedImpl implements XmlSchemaNamedWithForm {
+ private form = XmlSchemaForm.NONE;
+ private element = false;
+ private wireName: QName | null = null;
+
+ /**
+ * Delegate object for managing names for attributes and elements.
+ * @param parent containing schema.
+ * @param topLevel if this object is global.
+ * @param element true for an element, false for an attribute.
+ */
+ constructor(parent: XmlSchema, topLevel: boolean, element: boolean) {
+ super(parent, topLevel);
+ this.element = element;
+ }
+
+ /**
+ * Return the effective 'form' for this item. If the item
+ * has an explicit form declaration, this returns that declared form. If not,
+ * it returns the appropriate default form from the containing schema.
+ * @return {@link XmlSchemaForm#QUALIFIED} or {@link XmlSchemaForm#UNQUALIFIED}.
+ */
+ getForm() {
+ if (this.form != XmlSchemaForm.NONE) {
+ return this.form;
+ } else if (this.isTopLevel()) {
+ return XmlSchemaForm.QUALIFIED;
+ } else if (this.element) {
+ return this.parentSchema.getElementFormDefault();
+ } else {
+ return this.parentSchema.getAttributeFormDefault();
+ }
+ }
+
+ isFormSpecified() {
+ return this.form != XmlSchemaForm.NONE;
+ }
+
+ setForm(form: XmlSchemaForm) {
+ if (form == null) {
+ throw new Error('form may not be null. ' + 'Pass XmlSchemaForm.NONE to use schema default.');
+ }
+ this.form = form;
+ this.setName(this.getName());
+ }
+
+ setName(name: string | null) {
+ super.setName(name);
+ if (this.getForm() == XmlSchemaForm.QUALIFIED) {
+ this.wireName = this.getQName();
+ } else {
+ this.wireName = new QName('', this.getName());
+ }
+ }
+
+ getWireName() {
+ // If this is a ref= case, then we take the name from the ref=, not from the QName.
+ // what about ref='foo' form='unqualified'? Is that possible?
+ if (this.refTwin != null && this.refTwin.getTargetQName() != null) {
+ return this.refTwin.getTargetQName();
+ } else {
+ return this.wireName;
+ }
+ }
+}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaObjectBase.ts b/packages/xml-schema-ts/src/utils/XmlSchemaObjectBase.ts
new file mode 100644
index 000000000..eac8e3378
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaObjectBase.ts
@@ -0,0 +1,2 @@
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+export interface XmlSchemaObjectBase {}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaRef.ts b/packages/xml-schema-ts/src/utils/XmlSchemaRef.ts
new file mode 100644
index 000000000..18e56f2fa
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaRef.ts
@@ -0,0 +1,43 @@
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaNamed } from './XmlSchemaNamed';
+import { XmlSchemaRefBase } from './XmlSchemaRefBase';
+import { XmlSchemaNamedType } from './XmlSchemaNamedType';
+
+export class XmlSchemaRef extends XmlSchemaRefBase {
+ private targetObject: XmlSchemaNamed | null = null;
+ private targetType: XmlSchemaNamedType;
+
+ constructor(parent: XmlSchema, targetType: XmlSchemaNamedType) {
+ super();
+ this.parent = parent;
+ this.targetType = targetType;
+ }
+
+ forgetTargetObject() {
+ this.targetObject = null;
+ }
+
+ getTarget(): T | null {
+ if (this.targetObject == null && this.targetQName != null) {
+ const parentCollection = this.parent!.getParent();
+ if (parentCollection == null) {
+ return this.targetObject;
+ }
+
+ if (this.targetType === XmlSchemaNamedType.XmlSchemaElement) {
+ this.targetObject = parentCollection.getElementByQName(this.targetQName);
+ } else if (this.targetType == XmlSchemaNamedType.XmlSchemaAttribute) {
+ this.targetObject = parentCollection.getAttributeByQName(this.targetQName);
+ } else if (this.targetType == XmlSchemaNamedType.XmlSchemaType) {
+ this.targetObject = parentCollection.getTypeByQName(this.targetQName);
+ } else if (this.targetType == XmlSchemaNamedType.XmlSchemaAttributeGroup) {
+ this.targetObject = parentCollection.getAttributeGroupByQName(this.targetQName);
+ } else if (this.targetType == XmlSchemaNamedType.XmlSchemaGroup) {
+ this.targetObject = parentCollection.getGroupByQName(this.targetQName);
+ } else if (this.targetType == XmlSchemaNamedType.XmlSchemaNotation) {
+ this.targetObject = parentCollection.getNotationByQName(this.targetQName);
+ }
+ }
+ return this.targetObject as T;
+ }
+}
diff --git a/packages/xml-schema-ts/src/utils/XmlSchemaRefBase.ts b/packages/xml-schema-ts/src/utils/XmlSchemaRefBase.ts
new file mode 100644
index 000000000..dcf409588
--- /dev/null
+++ b/packages/xml-schema-ts/src/utils/XmlSchemaRefBase.ts
@@ -0,0 +1,30 @@
+import type { XmlSchema } from '../XmlSchema';
+import type { XmlSchemaNamed } from './XmlSchemaNamed';
+import { QName } from '../QName';
+
+export abstract class XmlSchemaRefBase {
+ protected parent: XmlSchema | null = null;
+ protected targetQName: QName | null = null;
+ private namedTwin?: XmlSchemaNamed;
+
+ protected abstract forgetTargetObject(): void;
+
+ setNamedObject(named: XmlSchemaNamed) {
+ this.namedTwin = named;
+ }
+
+ getTargetQName() {
+ return this.targetQName;
+ }
+
+ setTargetQName(targetQName: QName) {
+ if (this.targetQName != null && this.namedTwin != null && !this.namedTwin.isAnonymous()) {
+ throw new Error('It is invalid to set the ref= name for an item that has a name.');
+ }
+ /**
+ * We could possibly complain about no ref and also no name.
+ */
+ this.targetQName = targetQName;
+ this.forgetTargetObject();
+ }
+}
diff --git a/packages/xml-schema-ts/src/xml-parser.test.ts b/packages/xml-schema-ts/src/xml-parser.test.ts
new file mode 100644
index 000000000..98afab7ee
--- /dev/null
+++ b/packages/xml-schema-ts/src/xml-parser.test.ts
@@ -0,0 +1,30 @@
+import * as fs from 'fs';
+
+describe.skip('XML parser', () => {
+ describe('DOMParser', () => {
+ const parser = new DOMParser();
+
+ it('should parse XML schema', () => {
+ const orderXsd = fs.readFileSync(__dirname + '/../../../../test-resources/ShipOrder.xsd').toString();
+ const xmlDoc = parser.parseFromString(orderXsd, 'text/xml');
+ expect(xmlDoc).toBeDefined();
+ const schema = xmlDoc.getElementsByTagName('xs:schema')[0];
+ console.log(
+ `nodeName=${schema!.nodeName}, localName=${schema!.localName}, namespaceURI=${schema!.namespaceURI}, prefix=${schema.prefix}`,
+ );
+ const children = schema.childNodes;
+ children.forEach((v) => {
+ const el = v as Element;
+ console.log(
+ `nodeName=${el!.nodeName}, localName=${el!.localName}, namespaceURI=${el!.namespaceURI}, prefix=${el.prefix}`,
+ );
+ });
+ });
+
+ it('should parse XML document', () => {
+ const orderXml = fs.readFileSync(__dirname + '/../../../../test-resources/ExampleOrder.xml').toString();
+ const xmlDoc = parser.parseFromString(orderXml, 'text/xml');
+ expect(xmlDoc).toBeDefined();
+ });
+ });
+});
diff --git a/packages/xml-schema-ts/test-resources/Account.xsd b/packages/xml-schema-ts/test-resources/Account.xsd
new file mode 100644
index 000000000..03003ad77
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/Account.xsd
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/Cart.xsd b/packages/xml-schema-ts/test-resources/Cart.xsd
new file mode 100644
index 000000000..84ce73691
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/Cart.xsd
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/ExampleOrder.xml b/packages/xml-schema-ts/test-resources/ExampleOrder.xml
new file mode 100644
index 000000000..dfe89181b
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/ExampleOrder.xml
@@ -0,0 +1,23 @@
+
+
+
+ Jon Doh
+
+ sometext
+
+ Jon Doh
+ 123 Jon Rd
+ Doh
+ MA
+
+ -
+
Apple
+ 1
+ 3
+
+ -
+
Lemon
+ 1
+ 3
+
+
\ No newline at end of file
diff --git a/packages/xml-schema-ts/test-resources/NamedTypes.xsd b/packages/xml-schema-ts/test-resources/NamedTypes.xsd
new file mode 100644
index 000000000..f64216551
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/NamedTypes.xsd
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/NoTopElement.xsd b/packages/xml-schema-ts/test-resources/NoTopElement.xsd
new file mode 100644
index 000000000..6850c5ee0
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/NoTopElement.xsd
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/ShipOrder.xsd b/packages/xml-schema-ts/test-resources/ShipOrder.xsd
new file mode 100644
index 000000000..cda29d71e
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/ShipOrder.xsd
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/ShipOrderEmptyFirstLine.xsd b/packages/xml-schema-ts/test-resources/ShipOrderEmptyFirstLine.xsd
new file mode 100644
index 000000000..cfab0b133
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/ShipOrderEmptyFirstLine.xsd
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/ShipOrderToShipOrder.xsl b/packages/xml-schema-ts/test-resources/ShipOrderToShipOrder.xsl
new file mode 100644
index 000000000..cbf4f2d5d
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/ShipOrderToShipOrder.xsl
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/xml-schema-ts/test-resources/ShipOrderToShipOrderInvalidForEach.xsl b/packages/xml-schema-ts/test-resources/ShipOrderToShipOrderInvalidForEach.xsl
new file mode 100644
index 000000000..d55fb7073
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/ShipOrderToShipOrderInvalidForEach.xsl
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/TestDocument.xsd b/packages/xml-schema-ts/test-resources/TestDocument.xsd
new file mode 100644
index 000000000..ce46edb95
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/TestDocument.xsd
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/xml-schema-ts/test-resources/account-ns.xsd b/packages/xml-schema-ts/test-resources/account-ns.xsd
new file mode 100644
index 000000000..624aacfe7
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/account-ns.xsd
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/account.xsd b/packages/xml-schema-ts/test-resources/account.xsd
new file mode 100644
index 000000000..f59e17cc1
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/account.xsd
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/camel-spring.xsd b/packages/xml-schema-ts/test-resources/camel-spring.xsd
new file mode 100644
index 000000000..8ab41d30d
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/camel-spring.xsd
@@ -0,0 +1,18474 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/xml-schema-ts/test-resources/cart-ns.xsd b/packages/xml-schema-ts/test-resources/cart-ns.xsd
new file mode 100644
index 000000000..c81f1484d
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/cart-ns.xsd
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/cart.xsd b/packages/xml-schema-ts/test-resources/cart.xsd
new file mode 100644
index 000000000..79b256355
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/cart.xsd
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/hello.xsd b/packages/xml-schema-ts/test-resources/hello.xsd
new file mode 100644
index 000000000..8dc58b8a4
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/hello.xsd
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/packages/xml-schema-ts/test-resources/hello.xsl b/packages/xml-schema-ts/test-resources/hello.xsl
new file mode 100644
index 000000000..dbe9922cb
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/hello.xsl
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/xml-schema-ts/test-resources/shiporder-ns.xsd b/packages/xml-schema-ts/test-resources/shiporder-ns.xsd
new file mode 100644
index 000000000..bfa8aae31
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/shiporder-ns.xsd
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/test-resources/shiporder.xsd b/packages/xml-schema-ts/test-resources/shiporder.xsd
new file mode 100644
index 000000000..0d14b13ba
--- /dev/null
+++ b/packages/xml-schema-ts/test-resources/shiporder.xsd
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/xml-schema-ts/tsconfig.cjs.json b/packages/xml-schema-ts/tsconfig.cjs.json
new file mode 100644
index 000000000..7bd691fdf
--- /dev/null
+++ b/packages/xml-schema-ts/tsconfig.cjs.json
@@ -0,0 +1,13 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": "src",
+ "outDir": "dist/cjs",
+ "rootDir": "src",
+ "module": "commonjs",
+ "target": "es6",
+ "esModuleInterop": true,
+ "moduleResolution": "node"
+ },
+ "include": ["src"]
+}
diff --git a/packages/xml-schema-ts/tsconfig.esm.json b/packages/xml-schema-ts/tsconfig.esm.json
new file mode 100644
index 000000000..147793c44
--- /dev/null
+++ b/packages/xml-schema-ts/tsconfig.esm.json
@@ -0,0 +1,13 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": "src",
+ "outDir": "dist/esm",
+ "rootDir": "src",
+ "module": "es6",
+ "target": "es6",
+ "esModuleInterop": true,
+ "moduleResolution": "node"
+ },
+ "include": ["src"]
+}
diff --git a/packages/xml-schema-ts/tsconfig.json b/packages/xml-schema-ts/tsconfig.json
new file mode 100644
index 000000000..64a09d2f2
--- /dev/null
+++ b/packages/xml-schema-ts/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "exclude": ["node_modules"],
+ "compilerOptions": {
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "target": "ES2020",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "useDefineForClassFields": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "noImplicitAny": false,
+ "noImplicitThis": true,
+ "removeComments": true,
+ "strictNullChecks": true,
+ "experimentalDecorators": true,
+ "downlevelIteration": true,
+ "skipLibCheck": true,
+ "jsx": "react-jsx",
+ "types": [
+ "@testing-library/jest-dom",
+ "@types/jest",
+ "@types/node",
+ ],
+ }
+}
diff --git a/yarn.lock b/yarn.lock
index 0a58730c7..c392b3f98 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -50,14 +50,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/compat-data@npm:^7.25.2, @babel/compat-data@npm:^7.25.4":
+"@babel/compat-data@npm:^7.25.2":
version: 7.25.4
resolution: "@babel/compat-data@npm:7.25.4"
checksum: 10/d37a8936cc355a9ca3050102e03d179bdae26bd2e5c99a977637376c192b23637a039795f153c849437a086727628c9860e2c6af92d7151396e2362c09176337
languageName: node
linkType: hard
-"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.9, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.2":
+"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.9, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4":
version: 7.25.2
resolution: "@babel/core@npm:7.25.2"
dependencies:
@@ -80,6 +80,29 @@ __metadata:
languageName: node
linkType: hard
+"@babel/core@npm:^7.24.5":
+ version: 7.24.7
+ resolution: "@babel/core@npm:7.24.7"
+ dependencies:
+ "@ampproject/remapping": "npm:^2.2.0"
+ "@babel/code-frame": "npm:^7.24.7"
+ "@babel/generator": "npm:^7.24.7"
+ "@babel/helper-compilation-targets": "npm:^7.24.7"
+ "@babel/helper-module-transforms": "npm:^7.24.7"
+ "@babel/helpers": "npm:^7.24.7"
+ "@babel/parser": "npm:^7.24.7"
+ "@babel/template": "npm:^7.24.7"
+ "@babel/traverse": "npm:^7.24.7"
+ "@babel/types": "npm:^7.24.7"
+ convert-source-map: "npm:^2.0.0"
+ debug: "npm:^4.1.0"
+ gensync: "npm:^1.0.0-beta.2"
+ json5: "npm:^2.2.3"
+ semver: "npm:^6.3.1"
+ checksum: 10/ef8cc1afa3ccecee6d1f5660c487ccc2a3f25106830ea9040e80ef4b2092e053607ee4ddd03493e4f7ef2f9967a956ca53b830d54c5bee738eeb58cce679dd4a
+ languageName: node
+ linkType: hard
+
"@babel/generator@npm:^7.24.7, @babel/generator@npm:^7.7.2":
version: 7.24.7
resolution: "@babel/generator@npm:7.24.7"
@@ -136,7 +159,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-compilation-targets@npm:^7.24.8, @babel/helper-compilation-targets@npm:^7.25.2":
+"@babel/helper-compilation-targets@npm:^7.25.2":
version: 7.25.2
resolution: "@babel/helper-compilation-targets@npm:7.25.2"
dependencies:
@@ -168,23 +191,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-create-class-features-plugin@npm:^7.25.4":
- version: 7.25.4
- resolution: "@babel/helper-create-class-features-plugin@npm:7.25.4"
- dependencies:
- "@babel/helper-annotate-as-pure": "npm:^7.24.7"
- "@babel/helper-member-expression-to-functions": "npm:^7.24.8"
- "@babel/helper-optimise-call-expression": "npm:^7.24.7"
- "@babel/helper-replace-supers": "npm:^7.25.0"
- "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7"
- "@babel/traverse": "npm:^7.25.4"
- semver: "npm:^6.3.1"
- peerDependencies:
- "@babel/core": ^7.0.0
- checksum: 10/47218da9fd964af30d41f0635d9e33eed7518e03aa8f10c3eb8a563bb2c14f52be3e3199db5912ae0e26058c23bb511c811e565c55ecec09427b04b867ed13c2
- languageName: node
- linkType: hard
-
"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-create-regexp-features-plugin@npm:7.24.7"
@@ -198,20 +204,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-create-regexp-features-plugin@npm:^7.25.0, @babel/helper-create-regexp-features-plugin@npm:^7.25.2":
- version: 7.25.2
- resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.2"
- dependencies:
- "@babel/helper-annotate-as-pure": "npm:^7.24.7"
- regexpu-core: "npm:^5.3.1"
- semver: "npm:^6.3.1"
- peerDependencies:
- "@babel/core": ^7.0.0
- checksum: 10/33dd627eef9e4229aba66789efd8fb7342fc2667b821d4b7947c7294f6d472cf025ff2db9b358a1e03de98376de44e839f0611a456a57127fd6e4b4dbfc96c51
- languageName: node
- linkType: hard
-
-"@babel/helper-define-polyfill-provider@npm:^0.6.2":
+"@babel/helper-define-polyfill-provider@npm:^0.6.1, @babel/helper-define-polyfill-provider@npm:^0.6.2":
version: 0.6.2
resolution: "@babel/helper-define-polyfill-provider@npm:0.6.2"
dependencies:
@@ -264,16 +257,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-member-expression-to-functions@npm:^7.24.8":
- version: 7.24.8
- resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8"
- dependencies:
- "@babel/traverse": "npm:^7.24.8"
- "@babel/types": "npm:^7.24.8"
- checksum: 10/ac878761cfd0a46c081cda0da75cc186f922cf16e8ecdd0c4fb6dca4330d9fe4871b41a9976224cf9669c9e7fe0421b5c27349f2e99c125fa0be871b327fa770
- languageName: node
- linkType: hard
-
"@babel/helper-module-imports@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-module-imports@npm:7.24.7"
@@ -299,7 +282,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.25.0, @babel/helper-module-transforms@npm:^7.25.2":
+"@babel/helper-module-transforms@npm:^7.25.2":
version: 7.25.2
resolution: "@babel/helper-module-transforms@npm:7.25.2"
dependencies:
@@ -329,13 +312,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-plugin-utils@npm:^7.24.8":
- version: 7.24.8
- resolution: "@babel/helper-plugin-utils@npm:7.24.8"
- checksum: 10/adbc9fc1142800a35a5eb0793296924ee8057fe35c61657774208670468a9fbfbb216f2d0bc46c680c5fefa785e5ff917cc1674b10bd75cdf9a6aa3444780630
- languageName: node
- linkType: hard
-
"@babel/helper-remap-async-to-generator@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-remap-async-to-generator@npm:7.24.7"
@@ -349,19 +325,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-remap-async-to-generator@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/helper-remap-async-to-generator@npm:7.25.0"
- dependencies:
- "@babel/helper-annotate-as-pure": "npm:^7.24.7"
- "@babel/helper-wrap-function": "npm:^7.25.0"
- "@babel/traverse": "npm:^7.25.0"
- peerDependencies:
- "@babel/core": ^7.0.0
- checksum: 10/6b1ab73a067008c92e2fe5b7a9f39aab32e7f5a8c5eaf0a864436c21791f708ad8619d4a509febdfe934aeb373af4baa7c7d9f41181b385e09f39eaf11ca108e
- languageName: node
- linkType: hard
-
"@babel/helper-replace-supers@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-replace-supers@npm:7.24.7"
@@ -375,19 +338,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-replace-supers@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/helper-replace-supers@npm:7.25.0"
- dependencies:
- "@babel/helper-member-expression-to-functions": "npm:^7.24.8"
- "@babel/helper-optimise-call-expression": "npm:^7.24.7"
- "@babel/traverse": "npm:^7.25.0"
- peerDependencies:
- "@babel/core": ^7.0.0
- checksum: 10/97c6c17780cb9692132f7243f5a21fb6420104cb8ff8752dc03cfc9a1912a243994c0290c77ff096637ab6f2a7363b63811cfc68c2bad44e6b39460ac2f6a63f
- languageName: node
- linkType: hard
-
"@babel/helper-simple-access@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-simple-access@npm:7.24.7"
@@ -464,14 +414,13 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-wrap-function@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/helper-wrap-function@npm:7.25.0"
+"@babel/helpers@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/helpers@npm:7.24.7"
dependencies:
- "@babel/template": "npm:^7.25.0"
- "@babel/traverse": "npm:^7.25.0"
- "@babel/types": "npm:^7.25.0"
- checksum: 10/08724128b9c540c02a59f02f9c1c9940fe5363d85d0f30ec826a4f926afdb26fa4ec33ca2b88b4aa745fe3dbe1f44be2969b8a03af259af7945d8cd3262168d3
+ "@babel/template": "npm:^7.24.7"
+ "@babel/types": "npm:^7.24.7"
+ checksum: 10/f7496f0d7a0b13ea86136ac2053371027125734170328215f8a90eac96fafaaae4e5398c0729bdadf23261c00582a31e14bc70113427653b718220641a917f9d
languageName: node
linkType: hard
@@ -517,37 +466,26 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.3":
- version: 7.25.3
- resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.3"
- dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/traverse": "npm:^7.25.3"
- peerDependencies:
- "@babel/core": ^7.0.0
- checksum: 10/9743feb0152f2ac686aaee6dfd41e8ea211989a459d4c2b10b531442f6865057cd1a502515634c25462b155bc58f0710267afed72396780e9b72be25370dd577
- languageName: node
- linkType: hard
-
-"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.0"
+"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-environment-visitor": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0
- checksum: 10/5e504bba884a4500e71224d344efb1e70ebbeabd621e07a58f2d3c0d14a71a49c97b4989259a288cdbbfacebfea224397acf1217d26c77aebf9aa35bdd988249
+ checksum: 10/d5091ca6b58c54316c4d3b6e8120a1bb70cfe2e61cb7ec11f5fdc8ba3ff5124de21e527fabc28f239bf6efc0660046aa416e8fc1e3d920d0e57b78edb507ec3f
languageName: node
linkType: hard
-"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.0"
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0
- checksum: 10/f574beb1d4f723bb9b913ce379259a55b50a308364585ccb83e00d933465c26c04cbbc85a06e6d4c829279eb1021b3236133d486b3ff11cfd90ad815c8b478d2
+ checksum: 10/f0e0e9bdcf5479f8c5b4494353dc64dee37205e5ffd30920e649e75537a8f795cdcf32dfb40a00e908469a5d61cf62806bc359294cb2a6f2e604bf4efe086301
languageName: node
linkType: hard
@@ -564,15 +502,15 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.0"
+"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/traverse": "npm:^7.25.0"
+ "@babel/helper-environment-visitor": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0
- checksum: 10/de04a9342e9a0db1673683112c83cdc52173f489f45aeed864ceba72dfba8c8588e565171e64cb2a408a09269e5fb35c6ab4ef50e3e649c4f8c0c787feb5c048
+ checksum: 10/ad63317eb72ca7e160394e9223768b1f826287eaf65297f2794d0203510225f20dd9858bce217af4a050754abf94565841617b45b35a2de355c4e2bba546b39c
languageName: node
linkType: hard
@@ -839,17 +777,17 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-async-generator-functions@npm:^7.25.4":
- version: 7.25.4
- resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.4"
+"@babel/plugin-transform-async-generator-functions@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/helper-remap-async-to-generator": "npm:^7.25.0"
+ "@babel/helper-environment-visitor": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
+ "@babel/helper-remap-async-to-generator": "npm:^7.24.7"
"@babel/plugin-syntax-async-generators": "npm:^7.8.4"
- "@babel/traverse": "npm:^7.25.4"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/0004d910bbec3ef916acf5c7cf8b11671e65d2dd425a82f1101838b9b6243bfdf9578335584d9dedd20acc162796b687930e127c6042484e05b758af695e6cb8
+ checksum: 10/cf0a4b5ffc6d7f3f3bf12d4792535e8a46332714211326fd5058a6e45988891ee402b26cb9cc6c7121b2c8283ebd160e431827f885bdfa51d6127f934bd9ba7f
languageName: node
linkType: hard
@@ -877,18 +815,18 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-block-scoping@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/plugin-transform-block-scoping@npm:7.25.0"
+"@babel/plugin-transform-block-scoping@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-block-scoping@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/981e565a8ff1e1f8d539b5ff067328517233142b131329d11e6c60405204e2a4a993828c367f7dc729a9608aabebdada869616563816e5f8f1385e91ac0fa4d6
+ checksum: 10/9656e7bb0673279e18d9f9408027786f1b20d657e2cc106456e0bd7826bd12d81813299adbef2b2a5837b05740f2295fe8fb62389122d38c9e961b3005270777
languageName: node
linkType: hard
-"@babel/plugin-transform-class-properties@npm:^7.22.5":
+"@babel/plugin-transform-class-properties@npm:^7.22.5, @babel/plugin-transform-class-properties@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-class-properties@npm:7.24.7"
dependencies:
@@ -900,18 +838,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-class-properties@npm:^7.25.4":
- version: 7.25.4
- resolution: "@babel/plugin-transform-class-properties@npm:7.25.4"
- dependencies:
- "@babel/helper-create-class-features-plugin": "npm:^7.25.4"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 10/203a21384303d66fb5d841b77cba8b8994623ff4d26d208e3d05b36858c4919626a8d74871fa4b9195310c2e7883bf180359c4f5a76481ea55190c224d9746f4
- languageName: node
- linkType: hard
-
"@babel/plugin-transform-class-static-block@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-class-static-block@npm:7.24.7"
@@ -925,19 +851,21 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-classes@npm:^7.25.4":
- version: 7.25.4
- resolution: "@babel/plugin-transform-classes@npm:7.25.4"
+"@babel/plugin-transform-classes@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-classes@npm:7.24.7"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^7.24.7"
- "@babel/helper-compilation-targets": "npm:^7.25.2"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/helper-replace-supers": "npm:^7.25.0"
- "@babel/traverse": "npm:^7.25.4"
+ "@babel/helper-compilation-targets": "npm:^7.24.7"
+ "@babel/helper-environment-visitor": "npm:^7.24.7"
+ "@babel/helper-function-name": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
+ "@babel/helper-replace-supers": "npm:^7.24.7"
+ "@babel/helper-split-export-declaration": "npm:^7.24.7"
globals: "npm:^11.1.0"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/17db5889803529bec366c6f0602687fdd605c2fec8cb6fe918261cb55cd89e9d8c9aa2aa6f3fd64d36492ce02d7d0752b09a284b0f833c1185f7dad9b9506310
+ checksum: 10/5d5577fcb0ec9ef33d889358c54720abe462325bed5483d71f9aa0a704f491520777be5411d6fd8a08a8ebe352e2445d46d1e6577a5a2c9333bc37b9ff8b9a74
languageName: node
linkType: hard
@@ -953,14 +881,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-destructuring@npm:^7.24.8":
- version: 7.24.8
- resolution: "@babel/plugin-transform-destructuring@npm:7.24.8"
+"@babel/plugin-transform-destructuring@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-destructuring@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/e3bba0bb050592615fbf062ea07ae94f99e9cf22add006eaa66ed672d67ff7051b578a5ea68a7d79f9184fb3c27c65333d86b0b8ea04f9810bcccbeea2ffbe76
+ checksum: 10/eec43df24a07b3c61f335883e50c6642762fdd3cc5c5f95532cebeb51ea9bf77ca9a38011b678d91549dd75e29e1c58bd6e0ebc34bb763c300bc2cc65801e663
languageName: node
linkType: hard
@@ -987,18 +915,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.0"
- dependencies:
- "@babel/helper-create-regexp-features-plugin": "npm:^7.25.0"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- peerDependencies:
- "@babel/core": ^7.0.0
- checksum: 10/869c08def8eb80e3619c77e7af962dd82323a8447697298f461624077593c7b7082fc2238989880a0c0ba94bc6442300fd23e33255ac225760bc8bb755268941
- languageName: node
- linkType: hard
-
"@babel/plugin-transform-dynamic-import@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.7"
@@ -1059,16 +975,16 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-function-name@npm:^7.25.1":
- version: 7.25.1
- resolution: "@babel/plugin-transform-function-name@npm:7.25.1"
+"@babel/plugin-transform-function-name@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-function-name@npm:7.24.7"
dependencies:
- "@babel/helper-compilation-targets": "npm:^7.24.8"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/traverse": "npm:^7.25.1"
+ "@babel/helper-compilation-targets": "npm:^7.24.7"
+ "@babel/helper-function-name": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/1b4cd214c8523f7fa024fcda540ffe5503eda0e0be08b7c21405c96a870b5fe8bb1bda9e23a43a31467bf3dfc3a08edca250cf7f55f09dc40759a1ca6c6d6a4a
+ checksum: 10/9d4dcffea45acd255fed4a97e372ada234579f9bae01a4d0ced657091f159edf1635ff2a666508a08f8e59390def09ae6ce8372679faad894aa6f3247728ebe1
languageName: node
linkType: hard
@@ -1084,14 +1000,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-literals@npm:^7.25.2":
- version: 7.25.2
- resolution: "@babel/plugin-transform-literals@npm:7.25.2"
+"@babel/plugin-transform-literals@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-literals@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/d9728625a6d55305610dd37057fe1a3473df4f3789fef693c900516caf8958dfb341394ecf69ce9b60c82c422ad2954491a7e4d4533432fd5df812827443d6e9
+ checksum: 10/bf341a5a0ffb5129670ac9a14ea53b67bd1d3d0e13173ce7ac2d4184c4b405d33f67df68c59a2e94a895bf80269ec1df82c011d9ddb686f9f08a40c37b881177
languageName: node
linkType: hard
@@ -1143,30 +1059,17 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-modules-commonjs@npm:^7.24.8":
- version: 7.24.8
- resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8"
- dependencies:
- "@babel/helper-module-transforms": "npm:^7.24.8"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/helper-simple-access": "npm:^7.24.7"
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 10/18e5d229767c7b5b6ff0cbf1a8d2d555965b90201839d0ac2dc043b56857624ea344e59f733f028142a8c1d54923b82e2a0185694ef36f988d797bfbaf59819c
- languageName: node
- linkType: hard
-
-"@babel/plugin-transform-modules-systemjs@npm:^7.25.0":
- version: 7.25.0
- resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.0"
+"@babel/plugin-transform-modules-systemjs@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.7"
dependencies:
- "@babel/helper-module-transforms": "npm:^7.25.0"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-hoist-variables": "npm:^7.24.7"
+ "@babel/helper-module-transforms": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
"@babel/helper-validator-identifier": "npm:^7.24.7"
- "@babel/traverse": "npm:^7.25.0"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/2c38efdbaf6faf730cdcb0c5e42d2d15bb114eecf184db078319de496b5e3ce68d499e531265a0e13e29f0dcaa001f240773db5c4c078eac7f4456d6c8bddd88
+ checksum: 10/14f0ed1a252a2a04e075cd9051b809e33cd45374a2495dc0a428517893b8e951819acc8343c61d348c51ba54e42660bc93990a77aa3460d16a1c21d52d9c2cf1
languageName: node
linkType: hard
@@ -1280,19 +1183,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-optional-chaining@npm:^7.24.8":
- version: 7.24.8
- resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8"
- dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7"
- "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3"
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 10/1f873fb9d86c280b64dfe5ebc59244b459b717ed72a7682da2386db3d9e11fc9d831cfc2e11d37262b4325a7a0e3ccbccfb8cd0b944caf199d3c9e03fff7b0af
- languageName: node
- linkType: hard
-
"@babel/plugin-transform-parameters@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-parameters@npm:7.24.7"
@@ -1304,7 +1194,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-private-methods@npm:^7.22.5":
+"@babel/plugin-transform-private-methods@npm:^7.22.5, @babel/plugin-transform-private-methods@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-private-methods@npm:7.24.7"
dependencies:
@@ -1316,18 +1206,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-private-methods@npm:^7.25.4":
- version: 7.25.4
- resolution: "@babel/plugin-transform-private-methods@npm:7.25.4"
- dependencies:
- "@babel/helper-create-class-features-plugin": "npm:^7.25.4"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 10/d5c29ba121d6ce40e8055a632c32e69006c513607145a29701f93b416a8c53a60e53565df417218e2d8b7f1ba73adb837601e8e9d0a3215da50e4c9507f9f1fa
- languageName: node
- linkType: hard
-
"@babel/plugin-transform-private-property-in-object@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.7"
@@ -1375,7 +1253,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-react-jsx-self@npm:^7.24.7":
+"@babel/plugin-transform-react-jsx-self@npm:^7.24.5":
version: 7.24.7
resolution: "@babel/plugin-transform-react-jsx-self@npm:7.24.7"
dependencies:
@@ -1386,7 +1264,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-react-jsx-source@npm:^7.24.7":
+"@babel/plugin-transform-react-jsx-source@npm:^7.24.1":
version: 7.24.7
resolution: "@babel/plugin-transform-react-jsx-source@npm:7.24.7"
dependencies:
@@ -1492,14 +1370,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-typeof-symbol@npm:^7.24.8":
- version: 7.24.8
- resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.8"
+"@babel/plugin-transform-typeof-symbol@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.7"
dependencies:
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/5f113fed94b694ec4a40a27b8628ce736cfa172b69fcffa2833c9a41895032127f3daeea552e94fdb4a3ce4e8cd51de67a670ab87a1f447a0cf55c9cb2d7ed11
+ checksum: 10/c07847a3bcb27509d392de7a59b9836669b90ca508d4b63b36bb73b63413bc0b2571a64410b65999a73abeac99957b31053225877dcbfaf4eb21d8cc0ae4002f
languageName: node
linkType: hard
@@ -1552,31 +1430,30 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-unicode-sets-regex@npm:^7.25.4":
- version: 7.25.4
- resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.25.4"
+"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.24.7"
dependencies:
- "@babel/helper-create-regexp-features-plugin": "npm:^7.25.2"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
+ "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
peerDependencies:
"@babel/core": ^7.0.0
- checksum: 10/d5d07d17932656fa4d62fd67ecaa1a5e4c2e92365a924f1a2a8cf8108762f137a30cd55eb3a7d0504258f27a19ad0decca6b62a5c37a5aada709cbb46c4a871f
+ checksum: 10/183b72d5987dc93f9971667ce3f26d28b0e1058e71b129733dd9d5282aecba4c062b67c9567526780d2defd2bfbf950ca58d8306dc90b2761fd1e960d867ddb7
languageName: node
linkType: hard
"@babel/preset-env@npm:^7.21.5, @babel/preset-env@npm:^7.24.4":
- version: 7.25.4
- resolution: "@babel/preset-env@npm:7.25.4"
+ version: 7.24.7
+ resolution: "@babel/preset-env@npm:7.24.7"
dependencies:
- "@babel/compat-data": "npm:^7.25.4"
- "@babel/helper-compilation-targets": "npm:^7.25.2"
- "@babel/helper-plugin-utils": "npm:^7.24.8"
- "@babel/helper-validator-option": "npm:^7.24.8"
- "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.25.3"
- "@babel/plugin-bugfix-safari-class-field-initializer-scope": "npm:^7.25.0"
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.25.0"
+ "@babel/compat-data": "npm:^7.24.7"
+ "@babel/helper-compilation-targets": "npm:^7.24.7"
+ "@babel/helper-plugin-utils": "npm:^7.24.7"
+ "@babel/helper-validator-option": "npm:^7.24.7"
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.7"
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.7"
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.7"
- "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.25.0"
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.7"
"@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2"
"@babel/plugin-syntax-async-generators": "npm:^7.8.4"
"@babel/plugin-syntax-class-properties": "npm:^7.12.13"
@@ -1597,30 +1474,29 @@ __metadata:
"@babel/plugin-syntax-top-level-await": "npm:^7.14.5"
"@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6"
"@babel/plugin-transform-arrow-functions": "npm:^7.24.7"
- "@babel/plugin-transform-async-generator-functions": "npm:^7.25.4"
+ "@babel/plugin-transform-async-generator-functions": "npm:^7.24.7"
"@babel/plugin-transform-async-to-generator": "npm:^7.24.7"
"@babel/plugin-transform-block-scoped-functions": "npm:^7.24.7"
- "@babel/plugin-transform-block-scoping": "npm:^7.25.0"
- "@babel/plugin-transform-class-properties": "npm:^7.25.4"
+ "@babel/plugin-transform-block-scoping": "npm:^7.24.7"
+ "@babel/plugin-transform-class-properties": "npm:^7.24.7"
"@babel/plugin-transform-class-static-block": "npm:^7.24.7"
- "@babel/plugin-transform-classes": "npm:^7.25.4"
+ "@babel/plugin-transform-classes": "npm:^7.24.7"
"@babel/plugin-transform-computed-properties": "npm:^7.24.7"
- "@babel/plugin-transform-destructuring": "npm:^7.24.8"
+ "@babel/plugin-transform-destructuring": "npm:^7.24.7"
"@babel/plugin-transform-dotall-regex": "npm:^7.24.7"
"@babel/plugin-transform-duplicate-keys": "npm:^7.24.7"
- "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "npm:^7.25.0"
"@babel/plugin-transform-dynamic-import": "npm:^7.24.7"
"@babel/plugin-transform-exponentiation-operator": "npm:^7.24.7"
"@babel/plugin-transform-export-namespace-from": "npm:^7.24.7"
"@babel/plugin-transform-for-of": "npm:^7.24.7"
- "@babel/plugin-transform-function-name": "npm:^7.25.1"
+ "@babel/plugin-transform-function-name": "npm:^7.24.7"
"@babel/plugin-transform-json-strings": "npm:^7.24.7"
- "@babel/plugin-transform-literals": "npm:^7.25.2"
+ "@babel/plugin-transform-literals": "npm:^7.24.7"
"@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.7"
"@babel/plugin-transform-member-expression-literals": "npm:^7.24.7"
"@babel/plugin-transform-modules-amd": "npm:^7.24.7"
- "@babel/plugin-transform-modules-commonjs": "npm:^7.24.8"
- "@babel/plugin-transform-modules-systemjs": "npm:^7.25.0"
+ "@babel/plugin-transform-modules-commonjs": "npm:^7.24.7"
+ "@babel/plugin-transform-modules-systemjs": "npm:^7.24.7"
"@babel/plugin-transform-modules-umd": "npm:^7.24.7"
"@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.7"
"@babel/plugin-transform-new-target": "npm:^7.24.7"
@@ -1629,9 +1505,9 @@ __metadata:
"@babel/plugin-transform-object-rest-spread": "npm:^7.24.7"
"@babel/plugin-transform-object-super": "npm:^7.24.7"
"@babel/plugin-transform-optional-catch-binding": "npm:^7.24.7"
- "@babel/plugin-transform-optional-chaining": "npm:^7.24.8"
+ "@babel/plugin-transform-optional-chaining": "npm:^7.24.7"
"@babel/plugin-transform-parameters": "npm:^7.24.7"
- "@babel/plugin-transform-private-methods": "npm:^7.25.4"
+ "@babel/plugin-transform-private-methods": "npm:^7.24.7"
"@babel/plugin-transform-private-property-in-object": "npm:^7.24.7"
"@babel/plugin-transform-property-literals": "npm:^7.24.7"
"@babel/plugin-transform-regenerator": "npm:^7.24.7"
@@ -1640,20 +1516,20 @@ __metadata:
"@babel/plugin-transform-spread": "npm:^7.24.7"
"@babel/plugin-transform-sticky-regex": "npm:^7.24.7"
"@babel/plugin-transform-template-literals": "npm:^7.24.7"
- "@babel/plugin-transform-typeof-symbol": "npm:^7.24.8"
+ "@babel/plugin-transform-typeof-symbol": "npm:^7.24.7"
"@babel/plugin-transform-unicode-escapes": "npm:^7.24.7"
"@babel/plugin-transform-unicode-property-regex": "npm:^7.24.7"
"@babel/plugin-transform-unicode-regex": "npm:^7.24.7"
- "@babel/plugin-transform-unicode-sets-regex": "npm:^7.25.4"
+ "@babel/plugin-transform-unicode-sets-regex": "npm:^7.24.7"
"@babel/preset-modules": "npm:0.1.6-no-external-plugins"
babel-plugin-polyfill-corejs2: "npm:^0.4.10"
- babel-plugin-polyfill-corejs3: "npm:^0.10.6"
+ babel-plugin-polyfill-corejs3: "npm:^0.10.4"
babel-plugin-polyfill-regenerator: "npm:^0.6.1"
- core-js-compat: "npm:^3.37.1"
+ core-js-compat: "npm:^3.31.0"
semver: "npm:^6.3.1"
peerDependencies:
"@babel/core": ^7.0.0-0
- checksum: 10/45ca65bdc7fa11ca51167804052460eda32bf2e6620c7ba998e2d95bc867595913532ee7d748e97e808eabcc66aabe796bd75c59014d996ec8183fa5a7245862
+ checksum: 10/2fd90c46efefadb48dae6d13de190ac48753af187ee394924cf532c79870ebb87658bd31f06649630827a478b17a4adc41717cc6d4c460ff2ed9fafa51e5b515
languageName: node
linkType: hard
@@ -1785,7 +1661,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.1, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.25.3, @babel/traverse@npm:^7.25.4":
+"@babel/traverse@npm:^7.25.2":
version: 7.25.6
resolution: "@babel/traverse@npm:7.25.6"
dependencies:
@@ -1811,7 +1687,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/types@npm:^7.24.8, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.6":
+"@babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.6":
version: 7.25.6
resolution: "@babel/types@npm:7.25.6"
dependencies:
@@ -1861,13 +1737,38 @@ __metadata:
languageName: node
linkType: hard
-"@bundled-es-modules/tough-cookie@npm:^0.1.6":
- version: 0.1.6
- resolution: "@bundled-es-modules/tough-cookie@npm:0.1.6"
+"@chevrotain/cst-dts-gen@npm:10.5.0":
+ version: 10.5.0
+ resolution: "@chevrotain/cst-dts-gen@npm:10.5.0"
dependencies:
- "@types/tough-cookie": "npm:^4.0.5"
- tough-cookie: "npm:^4.1.4"
- checksum: 10/4f24a820f02c08c3ca0ff21272317357152093f76f9c8cc182517f61fa426ae53dadc4d68a3d6da5078e8d73f0ff8c0907a9f994c0be756162ba9c7358533e57
+ "@chevrotain/gast": "npm:10.5.0"
+ "@chevrotain/types": "npm:10.5.0"
+ lodash: "npm:4.17.21"
+ checksum: 10/99027773daed40c80ce676eee3401a12a92be78679f977097d1afeeb6e9c05b14e5404d909b6b62c8ad6fed354fad215273297e2cf3b89353b600fe2bb8e483f
+ languageName: node
+ linkType: hard
+
+"@chevrotain/gast@npm:10.5.0":
+ version: 10.5.0
+ resolution: "@chevrotain/gast@npm:10.5.0"
+ dependencies:
+ "@chevrotain/types": "npm:10.5.0"
+ lodash: "npm:4.17.21"
+ checksum: 10/539453540abd6b3005d69deb3e9504233ef52d91f5881adfb865a1c394731ab59983a223a906def79e7f4740ee8e97d2b7c8e0292c8158b567a2ea4a23f6c33d
+ languageName: node
+ linkType: hard
+
+"@chevrotain/types@npm:10.5.0":
+ version: 10.5.0
+ resolution: "@chevrotain/types@npm:10.5.0"
+ checksum: 10/71526b43651124d06c9432871bba64b701b5c6ed4cf3715aa5803448f5c9d27ac65b441e6ce255392ed0f408e2db95e3246f133bd91914eb852f01973fbc8b8b
+ languageName: node
+ linkType: hard
+
+"@chevrotain/utils@npm:10.5.0":
+ version: 10.5.0
+ resolution: "@chevrotain/utils@npm:10.5.0"
+ checksum: 10/92571b905e33c8cb7ba83935e9b8c5a46b4528d9906ad26d74f1530da33e4888cfac15fc4cea6212843cb62350906a88671d586afd9019ceb176ae2c3a1a402e
languageName: node
linkType: hard
@@ -1887,44 +1788,44 @@ __metadata:
languageName: node
linkType: hard
-"@csstools/css-parser-algorithms@npm:^3.0.1":
- version: 3.0.1
- resolution: "@csstools/css-parser-algorithms@npm:3.0.1"
+"@csstools/css-parser-algorithms@npm:^2.6.3":
+ version: 2.6.3
+ resolution: "@csstools/css-parser-algorithms@npm:2.6.3"
peerDependencies:
- "@csstools/css-tokenizer": ^3.0.1
- checksum: 10/02649a70ab7bab1fd000ca1d196ffb93ad3e2e0f36b4aa064f7973cd31edc5f7e63f8eaf7b94d801a0bfd207386b8b23cbe40be6e871c27042b084c3a717349e
+ "@csstools/css-tokenizer": ^2.3.1
+ checksum: 10/b893e284ebcccf37d7928be31be94fb0d6725defc544b39892d5e59ed5950b413366491817539b0add08deb9fc258c57588053d4436f84b7bd3b43bfeee67bb1
languageName: node
linkType: hard
-"@csstools/css-tokenizer@npm:^3.0.1":
- version: 3.0.1
- resolution: "@csstools/css-tokenizer@npm:3.0.1"
- checksum: 10/81ae01b2d3ec40ed3dc78f8507cbfdfe1dbc4ae3f8c8e29b8bb4414216a8c7a7a936fa0faa3d11a1e49ad72209aec7c05ad8450a4ffc30ba288aa074b4a0e3b3
+"@csstools/css-tokenizer@npm:^2.3.1":
+ version: 2.3.1
+ resolution: "@csstools/css-tokenizer@npm:2.3.1"
+ checksum: 10/25c8643151667bfc2ce653174786d9f97fea93aa38d48432937bc634d8478dfa03e5e6ad18d3fff3d6fa245e9f6578f87ca07d9fd764a274702e4bb8dd34dede
languageName: node
linkType: hard
-"@csstools/media-query-list-parser@npm:^3.0.1":
- version: 3.0.1
- resolution: "@csstools/media-query-list-parser@npm:3.0.1"
+"@csstools/media-query-list-parser@npm:^2.1.11":
+ version: 2.1.11
+ resolution: "@csstools/media-query-list-parser@npm:2.1.11"
peerDependencies:
- "@csstools/css-parser-algorithms": ^3.0.1
- "@csstools/css-tokenizer": ^3.0.1
- checksum: 10/794344c67b126ad93d516ab3f01254d44cfa794c3401e34e8cc62ddc7fc13c9ab6c76cb517b643dbda47b57f2eb578c6a11c4a9a4b516d88e260a4016b64ce7f
+ "@csstools/css-parser-algorithms": ^2.6.3
+ "@csstools/css-tokenizer": ^2.3.1
+ checksum: 10/23ede5583c6f1f51ec45b9293fcaf1ecac0f69c7ea750bfe2245926a66a6ae8f7dea8b3604fc4a5b8be4a25c1bccf519a357bf926d486a7ff479e89685011ff4
languageName: node
linkType: hard
-"@csstools/selector-specificity@npm:^4.0.0":
- version: 4.0.0
- resolution: "@csstools/selector-specificity@npm:4.0.0"
+"@csstools/selector-specificity@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "@csstools/selector-specificity@npm:3.1.1"
peerDependencies:
- postcss-selector-parser: ^6.1.0
- checksum: 10/7076c1d8af0fba94f06718f87fba5bfea583f39089efa906ae38b5ecd6912d3d5865f7047a871ac524b1057e4c970622b2ade456b90d69fb9393902250057994
+ postcss-selector-parser: ^6.0.13
+ checksum: 10/3786a6afea97b08ad739ee8f4004f7e0a9e25049cee13af809dbda6462090744012a54bd9275a44712791e8f103f85d21641f14e81799f9dab946b0459a5e1ef
languageName: node
linkType: hard
-"@cypress/request@npm:^3.0.6":
- version: 3.0.6
- resolution: "@cypress/request@npm:3.0.6"
+"@cypress/request@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "@cypress/request@npm:3.0.1"
dependencies:
aws-sign2: "npm:~0.7.0"
aws4: "npm:^1.8.0"
@@ -1932,19 +1833,19 @@ __metadata:
combined-stream: "npm:~1.0.6"
extend: "npm:~3.0.2"
forever-agent: "npm:~0.6.1"
- form-data: "npm:~4.0.0"
- http-signature: "npm:~1.4.0"
+ form-data: "npm:~2.3.2"
+ http-signature: "npm:~1.3.6"
is-typedarray: "npm:~1.0.0"
isstream: "npm:~0.1.2"
json-stringify-safe: "npm:~5.0.1"
mime-types: "npm:~2.1.19"
performance-now: "npm:^2.1.0"
- qs: "npm:6.13.0"
+ qs: "npm:6.10.4"
safe-buffer: "npm:^5.1.2"
- tough-cookie: "npm:^5.0.0"
+ tough-cookie: "npm:^4.1.3"
tunnel-agent: "npm:^0.6.0"
uuid: "npm:^8.3.2"
- checksum: 10/ac1782111d93e0dbee2d2b2f35d9acf6821ef36eef9f4c3991e5903138fe2b8394a207c8c6e50a2b6cb2057e0ee5ebfc37cb7571c460c9685e80c948c25f6972
+ checksum: 10/bf48bed6d6e493c05493902fb08b1d0646e7ec4300cf834816c2616f781db1a7fc447bd6f81de7c3076d738e8a6d75354e21d332f8f7ef8d9101d9b2f8e15b3a
languageName: node
linkType: hard
@@ -1974,6 +1875,42 @@ __metadata:
languageName: node
linkType: hard
+"@dnd-kit/accessibility@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "@dnd-kit/accessibility@npm:3.1.0"
+ dependencies:
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ react: ">=16.8.0"
+ checksum: 10/750a0537877d5dde3753e9ef59d19628b553567e90fc3e3b14a79bded08f47f4a7161bc0d003d7cd6b3bd9e10aa233628dca07d2aa5a2120cac84555ba1653d8
+ languageName: node
+ linkType: hard
+
+"@dnd-kit/core@npm:^6.1.0":
+ version: 6.1.0
+ resolution: "@dnd-kit/core@npm:6.1.0"
+ dependencies:
+ "@dnd-kit/accessibility": "npm:^3.1.0"
+ "@dnd-kit/utilities": "npm:^3.2.2"
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ react: ">=16.8.0"
+ react-dom: ">=16.8.0"
+ checksum: 10/cf9e99763fbd9220cb6fdde2950c19fdf6248391234f5ee835601814124445fd8a6e4b3f5bc35543c802d359db8cc47f07d87046577adc41952ae981a03fbda0
+ languageName: node
+ linkType: hard
+
+"@dnd-kit/utilities@npm:^3.2.2":
+ version: 3.2.2
+ resolution: "@dnd-kit/utilities@npm:3.2.2"
+ dependencies:
+ tslib: "npm:^2.0.0"
+ peerDependencies:
+ react: ">=16.8.0"
+ checksum: 10/6cfe46a5fcdaced943982e7ae66b08b89235493e106eb5bc833737c25905e13375c6ecc3aa0c357d136cb21dae3966213dba063f19b7a60b1235a29a7b05ff84
+ languageName: node
+ linkType: hard
+
"@dual-bundle/import-meta-resolve@npm:^4.1.0":
version: 4.1.0
resolution: "@dual-bundle/import-meta-resolve@npm:4.1.0"
@@ -2153,7 +2090,7 @@ __metadata:
languageName: node
linkType: hard
-"@eslint-community/regexpp@npm:^4.10.0":
+"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1":
version: 4.10.1
resolution: "@eslint-community/regexpp@npm:4.10.1"
checksum: 10/54f13817caf90545502d7a19e1b61df79087aee9584342ffc558b6d067530764a47f1c484f493f43e2c70cfdff59ccfd5f26df2af298c4ad528469e599bd1d53
@@ -2178,6 +2115,23 @@ __metadata:
languageName: node
linkType: hard
+"@eslint/eslintrc@npm:^2.1.4":
+ version: 2.1.4
+ resolution: "@eslint/eslintrc@npm:2.1.4"
+ dependencies:
+ ajv: "npm:^6.12.4"
+ debug: "npm:^4.3.2"
+ espree: "npm:^9.6.0"
+ globals: "npm:^13.19.0"
+ ignore: "npm:^5.2.0"
+ import-fresh: "npm:^3.2.1"
+ js-yaml: "npm:^4.1.0"
+ minimatch: "npm:^3.1.2"
+ strip-json-comments: "npm:^3.1.1"
+ checksum: 10/7a3b14f4b40fc1a22624c3f84d9f467a3d9ea1ca6e9a372116cb92507e485260359465b58e25bcb6c9981b155416b98c9973ad9b796053fd7b3f776a6946bce8
+ languageName: node
+ linkType: hard
+
"@eslint/eslintrc@npm:^3.1.0":
version: 3.1.0
resolution: "@eslint/eslintrc@npm:3.1.0"
@@ -2195,6 +2149,13 @@ __metadata:
languageName: node
linkType: hard
+"@eslint/js@npm:8.57.0":
+ version: 8.57.0
+ resolution: "@eslint/js@npm:8.57.0"
+ checksum: 10/3c501ce8a997cf6cbbaf4ed358af5492875e3550c19b9621413b82caa9ae5382c584b0efa79835639e6e0ddaa568caf3499318e5bdab68643ef4199dce5eb0a0
+ languageName: node
+ linkType: hard
+
"@eslint/js@npm:9.10.0, @eslint/js@npm:^9.10.0":
version: 9.10.0
resolution: "@eslint/js@npm:9.10.0"
@@ -2234,6 +2195,17 @@ __metadata:
languageName: node
linkType: hard
+"@humanwhocodes/config-array@npm:^0.11.14":
+ version: 0.11.14
+ resolution: "@humanwhocodes/config-array@npm:0.11.14"
+ dependencies:
+ "@humanwhocodes/object-schema": "npm:^2.0.2"
+ debug: "npm:^4.3.1"
+ minimatch: "npm:^3.0.5"
+ checksum: 10/3ffb24ecdfab64014a230e127118d50a1a04d11080cbb748bc21629393d100850496456bbcb4e8c438957fe0934430d731042f1264d6a167b62d32fc2863580a
+ languageName: node
+ linkType: hard
+
"@humanwhocodes/module-importer@npm:^1.0.1":
version: 1.0.1
resolution: "@humanwhocodes/module-importer@npm:1.0.1"
@@ -2241,6 +2213,13 @@ __metadata:
languageName: node
linkType: hard
+"@humanwhocodes/object-schema@npm:^2.0.2":
+ version: 2.0.3
+ resolution: "@humanwhocodes/object-schema@npm:2.0.3"
+ checksum: 10/05bb99ed06c16408a45a833f03a732f59bf6184795d4efadd33238ff8699190a8c871ad1121241bb6501589a9598dc83bf25b99dcbcf41e155cdf36e35e937a3
+ languageName: node
+ linkType: hard
+
"@humanwhocodes/retry@npm:^0.3.0":
version: 0.3.0
resolution: "@humanwhocodes/retry@npm:0.3.0"
@@ -2286,28 +2265,60 @@ __metadata:
languageName: node
linkType: hard
-"@inquirer/core@npm:^9.2.1":
- version: 9.2.1
- resolution: "@inquirer/core@npm:9.2.1"
+"@inquirer/core@npm:^9.1.0":
+ version: 9.1.0
+ resolution: "@inquirer/core@npm:9.1.0"
dependencies:
- "@inquirer/figures": "npm:^1.0.6"
- "@inquirer/type": "npm:^2.0.0"
+ "@inquirer/figures": "npm:^1.0.5"
+ "@inquirer/type": "npm:^1.5.3"
"@types/mute-stream": "npm:^0.0.4"
- "@types/node": "npm:^22.5.5"
+ "@types/node": "npm:^22.5.2"
"@types/wrap-ansi": "npm:^3.0.0"
ansi-escapes: "npm:^4.3.2"
+ cli-spinners: "npm:^2.9.2"
cli-width: "npm:^4.1.0"
mute-stream: "npm:^1.0.0"
signal-exit: "npm:^4.1.0"
strip-ansi: "npm:^6.0.1"
wrap-ansi: "npm:^6.2.0"
yoctocolors-cjs: "npm:^2.1.2"
- checksum: 10/bf35e46e70add8ffa9e9d4ae6b528ac660484afca082bca31af95ce8a145a2f8c8d0d07cc7a8627771452e68ade9849c9c9c450a004133ed10ac2d6730900452
+ checksum: 10/4aff54e4df53c2d8b93ab12e543f67b2f3193b448f8b0111eb111c21df1a7fdd0a7d081bf0a9029db8bda1a25031c11e643ac046df21c2b12edb3f096bb7c119
languageName: node
linkType: hard
-"@inquirer/expand@npm:^3.0.1":
- version: 3.0.1
+"@inquirer/core@npm:^9.2.1":
+ version: 9.2.1
+ resolution: "@inquirer/core@npm:9.2.1"
+ dependencies:
+ "@inquirer/figures": "npm:^1.0.6"
+ "@inquirer/type": "npm:^2.0.0"
+ "@types/mute-stream": "npm:^0.0.4"
+ "@types/node": "npm:^22.5.5"
+ "@types/wrap-ansi": "npm:^3.0.0"
+ ansi-escapes: "npm:^4.3.2"
+ cli-width: "npm:^4.1.0"
+ mute-stream: "npm:^1.0.0"
+ signal-exit: "npm:^4.1.0"
+ strip-ansi: "npm:^6.0.1"
+ wrap-ansi: "npm:^6.2.0"
+ yoctocolors-cjs: "npm:^2.1.2"
+ checksum: 10/bf35e46e70add8ffa9e9d4ae6b528ac660484afca082bca31af95ce8a145a2f8c8d0d07cc7a8627771452e68ade9849c9c9c450a004133ed10ac2d6730900452
+ languageName: node
+ linkType: hard
+
+"@inquirer/expand@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "@inquirer/expand@npm:2.3.0"
+ dependencies:
+ "@inquirer/core": "npm:^9.1.0"
+ "@inquirer/type": "npm:^1.5.3"
+ yoctocolors-cjs: "npm:^2.1.2"
+ checksum: 10/fdc9b2d0a509e9c0120fda8e1c044593b1f4b68038fd13e19fc35cc305f1e132fddd482bc1b44966cbcab06d579d130cabbb5cac50d917549d16d7e66fad4e74
+ languageName: node
+ linkType: hard
+
+"@inquirer/expand@npm:^3.0.1":
+ version: 3.0.1
resolution: "@inquirer/expand@npm:3.0.1"
dependencies:
"@inquirer/core": "npm:^9.2.1"
@@ -2324,6 +2335,13 @@ __metadata:
languageName: node
linkType: hard
+"@inquirer/figures@npm:^1.0.5":
+ version: 1.0.5
+ resolution: "@inquirer/figures@npm:1.0.5"
+ checksum: 10/60a51b2cdef03c89be25071c23d8c4ae427c56d8ac1b00bf054ca7be446674adc4edd66c15465fe6a81ff0726b024bf37f8a2903a8387ef968d33058da3e7a15
+ languageName: node
+ linkType: hard
+
"@inquirer/figures@npm:^1.0.6":
version: 1.0.6
resolution: "@inquirer/figures@npm:1.0.6"
@@ -2331,6 +2349,16 @@ __metadata:
languageName: node
linkType: hard
+"@inquirer/input@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "@inquirer/input@npm:2.3.0"
+ dependencies:
+ "@inquirer/core": "npm:^9.1.0"
+ "@inquirer/type": "npm:^1.5.3"
+ checksum: 10/1b6291f49be4e0ba6150b1b9971676cc5aec0271a946b9115975da21c7e32ee8bea6edd7b72689ed403f79f759d12e909920cca44684c02173ad9524de143341
+ languageName: node
+ linkType: hard
+
"@inquirer/input@npm:^3.0.1":
version: 3.0.1
resolution: "@inquirer/input@npm:3.0.1"
@@ -2341,6 +2369,19 @@ __metadata:
languageName: node
linkType: hard
+"@inquirer/select@npm:^2.5.0":
+ version: 2.5.0
+ resolution: "@inquirer/select@npm:2.5.0"
+ dependencies:
+ "@inquirer/core": "npm:^9.1.0"
+ "@inquirer/figures": "npm:^1.0.5"
+ "@inquirer/type": "npm:^1.5.3"
+ ansi-escapes: "npm:^4.3.2"
+ yoctocolors-cjs: "npm:^2.1.2"
+ checksum: 10/c47ec8ad1133bd7218d3c62e0fa62ecd2476ac291c87535e37956f47d12e2c1c2e4232fcc7b90de036bfe111bb9071a690d8d6d34b9839eb4c5c236bac309a6e
+ languageName: node
+ linkType: hard
+
"@inquirer/select@npm:^3.0.1":
version: 3.0.1
resolution: "@inquirer/select@npm:3.0.1"
@@ -2361,6 +2402,15 @@ __metadata:
languageName: node
linkType: hard
+"@inquirer/type@npm:^1.5.3":
+ version: 1.5.3
+ resolution: "@inquirer/type@npm:1.5.3"
+ dependencies:
+ mute-stream: "npm:^1.0.0"
+ checksum: 10/63976016f10a0cba725243dbe0beea88ee0090874e454482070e62e54a478405f3662acd3d97ce24516ada049e6e2aa72db627b65b2308f90a7398e11a287bd5
+ languageName: node
+ linkType: hard
+
"@inquirer/type@npm:^2.0.0":
version: 2.0.0
resolution: "@inquirer/type@npm:2.0.0"
@@ -2384,13 +2434,6 @@ __metadata:
languageName: node
linkType: hard
-"@isaacs/string-locale-compare@npm:^1.1.0":
- version: 1.1.0
- resolution: "@isaacs/string-locale-compare@npm:1.1.0"
- checksum: 10/85682b14602f32023e487f62bc4076fe13cd3e887df9cca36acc0d41ea99b403100d586acb9367331526f3ee737d802ecaa582f59020998d75991e62a7ef0db5
- languageName: node
- linkType: hard
-
"@istanbuljs/load-nyc-config@npm:^1.0.0":
version: 1.1.0
resolution: "@istanbuljs/load-nyc-config@npm:1.1.0"
@@ -2821,9 +2864,11 @@ __metadata:
"@babel/preset-env": "npm:^7.21.5"
"@babel/preset-react": "npm:^7.18.6"
"@babel/preset-typescript": "npm:^7.21.5"
+ "@dnd-kit/core": "npm:^6.1.0"
"@eslint/js": "npm:^9.10.0"
"@kaoto-next/uniforms-patternfly": "npm:^0.7.14"
"@kaoto/camel-catalog": "workspace:*"
+ "@kaoto/xml-schema-ts": "workspace:*"
"@kie-tools-core/editor": "npm:0.32.0"
"@kie-tools-core/notifications": "npm:0.32.0"
"@patternfly/patternfly": "npm:5.4.2"
@@ -2846,10 +2891,13 @@ __metadata:
"@types/react": "npm:^18.2.25"
"@types/react-dom": "npm:^18.2.10"
"@types/uuid": "npm:^10.0.0"
+ "@types/xml-name-validator": "npm:^4.0.3"
+ "@visx/shape": "npm:^3.12.0"
"@vitejs/plugin-react": "npm:^4.0.3"
ajv: "npm:^8.12.0"
ajv-formats: "npm:^3.0.0"
babel-jest: "npm:^29.4.2"
+ chevrotain: "npm:10.5.0"
clsx: "npm:^2.1.0"
copyfiles: "npm:^2.4.1"
eslint: "npm:^9.10.0"
@@ -2889,6 +2937,8 @@ __metadata:
vite: "npm:^5.4.0"
vite-plugin-dts: "npm:^4.0.2"
vite-plugin-static-copy: "npm:^1.0.6"
+ xml-formatter: "npm:^3.6.2"
+ xml-name-validator: "npm:^5.0.0"
yaml: "npm:^2.3.2"
zustand: "npm:^4.3.9"
peerDependencies:
@@ -2905,6 +2955,28 @@ __metadata:
languageName: unknown
linkType: soft
+"@kaoto/xml-schema-ts@workspace:*, @kaoto/xml-schema-ts@workspace:packages/xml-schema-ts":
+ version: 0.0.0-use.local
+ resolution: "@kaoto/xml-schema-ts@workspace:packages/xml-schema-ts"
+ dependencies:
+ "@babel/core": "npm:^7.23.2"
+ "@babel/preset-env": "npm:^7.21.5"
+ "@babel/preset-typescript": "npm:^7.21.5"
+ "@testing-library/jest-dom": "npm:^6.4.2"
+ "@types/jest": "npm:^29.5.12"
+ eslint: "npm:^8.45.0"
+ eslint-config-prettier: "npm:^9.0.0"
+ eslint-plugin-import: "npm:^2.26.0"
+ eslint-plugin-jest: "npm:^27.2.1"
+ eslint-plugin-prettier: "npm:^5.0.0"
+ jest: "npm:^29.7.0"
+ prettier: "npm:^3.0.0"
+ rimraf: "npm:^6.0.0"
+ typescript: "npm:^5.4.2"
+ vite: "npm:^5.4.0"
+ languageName: unknown
+ linkType: soft
+
"@kie-tools-core/backend@npm:0.32.0":
version: 0.32.0
resolution: "@kie-tools-core/backend@npm:0.32.0"
@@ -3036,7 +3108,69 @@ __metadata:
languageName: node
linkType: hard
-"@lerna-lite/cli@npm:3.9.2, @lerna-lite/cli@npm:^3.0.0":
+"@lerna-lite/cli@npm:3.5.1":
+ version: 3.5.1
+ resolution: "@lerna-lite/cli@npm:3.5.1"
+ dependencies:
+ "@lerna-lite/core": "npm:3.5.1"
+ "@lerna-lite/init": "npm:3.5.1"
+ dedent: "npm:^1.5.3"
+ dotenv: "npm:^16.4.5"
+ import-local: "npm:^3.1.0"
+ load-json-file: "npm:^7.0.1"
+ npmlog: "npm:^7.0.1"
+ yargs: "npm:^17.7.2"
+ peerDependenciesMeta:
+ "@lerna-lite/exec":
+ optional: true
+ "@lerna-lite/list":
+ optional: true
+ "@lerna-lite/publish":
+ optional: true
+ "@lerna-lite/run":
+ optional: true
+ "@lerna-lite/version":
+ optional: true
+ "@lerna-lite/watch":
+ optional: true
+ bin:
+ lerna: dist/cli.js
+ checksum: 10/f75aa82856140ccde90c5ab4269de1f81a23b411000c1f5e73b8d0d2f93e4bc97171267a852f8d71f4f6a95cd9f2daebd85452e57c6094413277606d7417e9b8
+ languageName: node
+ linkType: hard
+
+"@lerna-lite/cli@npm:3.9.1":
+ version: 3.9.1
+ resolution: "@lerna-lite/cli@npm:3.9.1"
+ dependencies:
+ "@lerna-lite/core": "npm:3.9.1"
+ "@lerna-lite/init": "npm:3.9.1"
+ "@lerna-lite/npmlog": "npm:3.8.0"
+ dedent: "npm:^1.5.3"
+ dotenv: "npm:^16.4.5"
+ import-local: "npm:^3.2.0"
+ load-json-file: "npm:^7.0.1"
+ yargs: "npm:^17.7.2"
+ peerDependenciesMeta:
+ "@lerna-lite/exec":
+ optional: true
+ "@lerna-lite/list":
+ optional: true
+ "@lerna-lite/publish":
+ optional: true
+ "@lerna-lite/run":
+ optional: true
+ "@lerna-lite/version":
+ optional: true
+ "@lerna-lite/watch":
+ optional: true
+ bin:
+ lerna: dist/cli.js
+ checksum: 10/94e8837711d3a18c829cc5051d480ef551dc4e7462ca6581524690d1a1f2971caad40f0c40b95c90ea39ba442e506a1174ab05c1920f1fbb200d97b73d5b2515
+ languageName: node
+ linkType: hard
+
+"@lerna-lite/cli@npm:^3.0.0":
version: 3.9.2
resolution: "@lerna-lite/cli@npm:3.9.2"
dependencies:
@@ -3067,6 +3201,76 @@ __metadata:
languageName: node
linkType: hard
+"@lerna-lite/core@npm:3.5.1":
+ version: 3.5.1
+ resolution: "@lerna-lite/core@npm:3.5.1"
+ dependencies:
+ "@npmcli/run-script": "npm:^8.1.0"
+ chalk: "npm:^5.3.0"
+ clone-deep: "npm:^4.0.1"
+ config-chain: "npm:^1.1.13"
+ cosmiconfig: "npm:^9.0.0"
+ dedent: "npm:^1.5.3"
+ execa: "npm:^8.0.1"
+ fs-extra: "npm:^11.2.0"
+ glob-parent: "npm:^6.0.2"
+ globby: "npm:^14.0.1"
+ inquirer: "npm:^9.2.23"
+ is-ci: "npm:^3.0.1"
+ json5: "npm:^2.2.3"
+ load-json-file: "npm:^7.0.1"
+ minimatch: "npm:^9.0.4"
+ npm-package-arg: "npm:^11.0.2"
+ npmlog: "npm:^7.0.1"
+ p-map: "npm:^7.0.2"
+ p-queue: "npm:^8.0.1"
+ resolve-from: "npm:^5.0.0"
+ semver: "npm:^7.6.2"
+ slash: "npm:^5.1.0"
+ strong-log-transformer: "npm:^2.1.0"
+ write-file-atomic: "npm:^5.0.1"
+ write-json-file: "npm:^5.0.0"
+ write-package: "npm:^7.0.1"
+ checksum: 10/82c5cec0fb591a5bedf2a86edfc0ae4c4e3102ae42fddee11767ff76ebcbe2c5b0d3a620e283edc2c97dd93e44c43a4e7b412bb30dbeaba36d80365c9e0c2fb4
+ languageName: node
+ linkType: hard
+
+"@lerna-lite/core@npm:3.9.1":
+ version: 3.9.1
+ resolution: "@lerna-lite/core@npm:3.9.1"
+ dependencies:
+ "@inquirer/expand": "npm:^2.3.0"
+ "@inquirer/input": "npm:^2.3.0"
+ "@inquirer/select": "npm:^2.5.0"
+ "@lerna-lite/npmlog": "npm:^3.8.0"
+ "@npmcli/run-script": "npm:^8.1.0"
+ chalk: "npm:^5.3.0"
+ clone-deep: "npm:^4.0.1"
+ config-chain: "npm:^1.1.13"
+ cosmiconfig: "npm:^9.0.0"
+ dedent: "npm:^1.5.3"
+ execa: "npm:^8.0.1"
+ fs-extra: "npm:^11.2.0"
+ glob-parent: "npm:^6.0.2"
+ globby: "npm:^14.0.2"
+ is-ci: "npm:^3.0.1"
+ json5: "npm:^2.2.3"
+ load-json-file: "npm:^7.0.1"
+ minimatch: "npm:^9.0.5"
+ npm-package-arg: "npm:^11.0.3"
+ p-map: "npm:^7.0.2"
+ p-queue: "npm:^8.0.1"
+ resolve-from: "npm:^5.0.0"
+ semver: "npm:^7.6.3"
+ slash: "npm:^5.1.0"
+ strong-log-transformer: "npm:^2.1.0"
+ write-file-atomic: "npm:^5.0.1"
+ write-json-file: "npm:^6.0.0"
+ write-package: "npm:^7.1.0"
+ checksum: 10/494c4c3c2568b127670bc2ad74059041290ede4d24f5e12fb07506f3979f0fd8ad1ef6dcd762bf3057c25a78108a79ad9adebcd831ade1e2f18533edf8e9526a
+ languageName: node
+ linkType: hard
+
"@lerna-lite/core@npm:3.9.2":
version: 3.9.2
resolution: "@lerna-lite/core@npm:3.9.2"
@@ -3103,6 +3307,30 @@ __metadata:
languageName: node
linkType: hard
+"@lerna-lite/init@npm:3.5.1":
+ version: 3.5.1
+ resolution: "@lerna-lite/init@npm:3.5.1"
+ dependencies:
+ "@lerna-lite/core": "npm:3.5.1"
+ fs-extra: "npm:^11.2.0"
+ p-map: "npm:^7.0.2"
+ write-json-file: "npm:^5.0.0"
+ checksum: 10/7e03e90468dc7b49e37abf79e26e9e3997985159ec5622b6e081d54c68463336fe7b07fe9a2d356bd0c7ea3356d12cc0c7678da173080685eee503d87b00ddd0
+ languageName: node
+ linkType: hard
+
+"@lerna-lite/init@npm:3.9.1":
+ version: 3.9.1
+ resolution: "@lerna-lite/init@npm:3.9.1"
+ dependencies:
+ "@lerna-lite/core": "npm:3.9.1"
+ fs-extra: "npm:^11.2.0"
+ p-map: "npm:^7.0.2"
+ write-json-file: "npm:^6.0.0"
+ checksum: 10/5193e963b6d4b57376389fea1db67eda579e96ad49be03d0d3f7686881ae0640c66ed7823b2ec462d2add5acd52beb5011380f75ca2146a6c4a035d8b4b70b1e
+ languageName: node
+ linkType: hard
+
"@lerna-lite/init@npm:3.9.2":
version: 3.9.2
resolution: "@lerna-lite/init@npm:3.9.2"
@@ -3133,47 +3361,89 @@ __metadata:
linkType: hard
"@lerna-lite/publish@npm:^3.0.0":
- version: 3.9.2
- resolution: "@lerna-lite/publish@npm:3.9.2"
- dependencies:
- "@lerna-lite/cli": "npm:3.9.2"
- "@lerna-lite/core": "npm:3.9.2"
- "@lerna-lite/npmlog": "npm:^3.8.0"
- "@lerna-lite/version": "npm:3.9.2"
- "@npmcli/arborist": "npm:^7.5.4"
- "@npmcli/package-json": "npm:^5.2.1"
- byte-size: "npm:^9.0.0"
+ version: 3.5.2
+ resolution: "@lerna-lite/publish@npm:3.5.2"
+ dependencies:
+ "@lerna-lite/cli": "npm:3.5.1"
+ "@lerna-lite/core": "npm:3.5.1"
+ "@lerna-lite/version": "npm:3.5.2"
+ byte-size: "npm:^8.1.1"
+ chalk: "npm:^5.3.0"
columnify: "npm:^1.6.0"
fs-extra: "npm:^11.2.0"
- globby: "npm:^14.0.2"
+ glob: "npm:^10.4.1"
has-unicode: "npm:^2.0.1"
libnpmaccess: "npm:^8.0.6"
libnpmpublish: "npm:^9.0.9"
normalize-path: "npm:^3.0.0"
- npm-package-arg: "npm:^11.0.3"
- npm-packlist: "npm:^8.0.2"
- npm-registry-fetch: "npm:^17.1.0"
+ npm-package-arg: "npm:^11.0.2"
+ npm-packlist: "npm:^5.1.3"
+ npm-registry-fetch: "npm:^17.0.1"
+ npmlog: "npm:^7.0.1"
p-map: "npm:^7.0.2"
p-pipe: "npm:^4.0.0"
pacote: "npm:^18.0.6"
- picocolors: "npm:^1.1.0"
- semver: "npm:^7.6.3"
- ssri: "npm:^11.0.0"
+ pify: "npm:^6.1.0"
+ read-package-json: "npm:^7.0.1"
+ semver: "npm:^7.6.2"
+ ssri: "npm:^10.0.6"
tar: "npm:^6.2.1"
temp-dir: "npm:^3.0.0"
- checksum: 10/eb06506e3dd0b161e193115851b671b421fa178db078714be1e79832cc33cf86bcdabb77d1b87b90497bc7086e4e60b55e68f0d9a1c4e733dfd66fdb129dd4ce
+ checksum: 10/f05b4cc762a4be7cda2e0bd686c5bd716ff736959141094ff0951be577630f66416d3b45911510be9549a1bc27964840a96125b4ebf8c85fd0246a0e1e3bb217
languageName: node
linkType: hard
-"@lerna-lite/version@npm:3.9.2, @lerna-lite/version@npm:^3.0.0":
- version: 3.9.2
- resolution: "@lerna-lite/version@npm:3.9.2"
+"@lerna-lite/version@npm:3.5.2":
+ version: 3.5.2
+ resolution: "@lerna-lite/version@npm:3.5.2"
dependencies:
- "@lerna-lite/cli": "npm:3.9.2"
- "@lerna-lite/core": "npm:3.9.2"
+ "@lerna-lite/cli": "npm:3.5.1"
+ "@lerna-lite/core": "npm:3.5.1"
+ "@octokit/plugin-enterprise-rest": "npm:^6.0.1"
+ "@octokit/rest": "npm:^20.1.1"
+ chalk: "npm:^5.3.0"
+ conventional-changelog-angular: "npm:^7.0.0"
+ conventional-changelog-core: "npm:^7.0.0"
+ conventional-changelog-writer: "npm:^7.0.1"
+ conventional-commits-parser: "npm:^5.0.0"
+ conventional-recommended-bump: "npm:^9.0.0"
+ dedent: "npm:^1.5.3"
+ fs-extra: "npm:^11.2.0"
+ get-stream: "npm:^9.0.1"
+ git-url-parse: "npm:^14.0.0"
+ graceful-fs: "npm:^4.2.11"
+ is-stream: "npm:^4.0.1"
+ load-json-file: "npm:^7.0.1"
+ make-dir: "npm:^5.0.0"
+ minimatch: "npm:^9.0.4"
+ new-github-release-url: "npm:^2.0.0"
+ node-fetch: "npm:^3.3.2"
+ npm-package-arg: "npm:^11.0.2"
+ npmlog: "npm:^7.0.1"
+ p-limit: "npm:^5.0.0"
+ p-map: "npm:^7.0.2"
+ p-pipe: "npm:^4.0.0"
+ p-reduce: "npm:^3.0.0"
+ pify: "npm:^6.1.0"
+ semver: "npm:^7.6.2"
+ slash: "npm:^5.1.0"
+ temp-dir: "npm:^3.0.0"
+ uuid: "npm:^9.0.1"
+ write-json-file: "npm:^5.0.0"
+ checksum: 10/392c502ab89eb5adad9f2624b73b0b112cefceeed1ca2e327d41052dd84c55385b203fcdf94a0a2874de7d17715564a2faa07e787a2cbf8251c2d1f5d1ddc8f1
+ languageName: node
+ linkType: hard
+
+"@lerna-lite/version@npm:^3.0.0":
+ version: 3.9.1
+ resolution: "@lerna-lite/version@npm:3.9.1"
+ dependencies:
+ "@lerna-lite/cli": "npm:3.9.1"
+ "@lerna-lite/core": "npm:3.9.1"
"@lerna-lite/npmlog": "npm:^3.8.0"
"@octokit/plugin-enterprise-rest": "npm:^6.0.1"
"@octokit/rest": "npm:^21.0.2"
+ chalk: "npm:^5.3.0"
conventional-changelog-angular: "npm:^7.0.0"
conventional-changelog-core: "npm:^7.0.0"
conventional-changelog-writer: "npm:^7.0.1"
@@ -3195,14 +3465,22 @@ __metadata:
p-map: "npm:^7.0.2"
p-pipe: "npm:^4.0.0"
p-reduce: "npm:^3.0.0"
- picocolors: "npm:^1.1.0"
pify: "npm:^6.1.0"
semver: "npm:^7.6.3"
slash: "npm:^5.1.0"
temp-dir: "npm:^3.0.0"
uuid: "npm:^10.0.0"
write-json-file: "npm:^6.0.0"
- checksum: 10/1b032db7674535914783765914fc4c1800dd616d264466f59782faf700f4cfdaa25e842ae57e268e0496dd5bbdfecb26a45a29ac6b93301f7b2741518cb0566d
+ checksum: 10/25c693ab84cf094535dd0bff26ef0683083f46bb17f7ff00f9cb16c20ab15cfd8925604476a61a59e0d8a69845d82087484546658f83e331eb06ad5cb4e65119
+ languageName: node
+ linkType: hard
+
+"@ljharb/through@npm:^2.3.13":
+ version: 2.3.13
+ resolution: "@ljharb/through@npm:2.3.13"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ checksum: 10/6150c6c43a726d52c26863ed6dc4ab54fa7cf625c81463a5ddec86278c99e23bf94dfc99ebf09a9ac3191332d4a27344e092f7e07f252b8cd600e2b38e645870
languageName: node
linkType: hard
@@ -3218,28 +3496,28 @@ __metadata:
languageName: node
linkType: hard
-"@microsoft/api-extractor-model@npm:7.29.6":
- version: 7.29.6
- resolution: "@microsoft/api-extractor-model@npm:7.29.6"
+"@microsoft/api-extractor-model@npm:7.29.4":
+ version: 7.29.4
+ resolution: "@microsoft/api-extractor-model@npm:7.29.4"
dependencies:
"@microsoft/tsdoc": "npm:~0.15.0"
"@microsoft/tsdoc-config": "npm:~0.17.0"
- "@rushstack/node-core-library": "npm:5.7.0"
- checksum: 10/7339366297a4438e33aef34fac4fa1fea3b7357fefd0a88da18221fa80152397326fb383563106f995899a382119f5c95f357abc3aa7448fcc1a2bee021696aa
+ "@rushstack/node-core-library": "npm:5.5.1"
+ checksum: 10/50bd4e58bfe9d43e0ca4a72324601ce17c015e517b0803bb787d1067bef9372a23bbbf2551f47d1c5a7fef742826ffa18aea43b96c823b82c07f745e3ea25657
languageName: node
linkType: hard
-"@microsoft/api-extractor@npm:7.47.7":
- version: 7.47.7
- resolution: "@microsoft/api-extractor@npm:7.47.7"
+"@microsoft/api-extractor@npm:7.47.4":
+ version: 7.47.4
+ resolution: "@microsoft/api-extractor@npm:7.47.4"
dependencies:
- "@microsoft/api-extractor-model": "npm:7.29.6"
+ "@microsoft/api-extractor-model": "npm:7.29.4"
"@microsoft/tsdoc": "npm:~0.15.0"
"@microsoft/tsdoc-config": "npm:~0.17.0"
- "@rushstack/node-core-library": "npm:5.7.0"
+ "@rushstack/node-core-library": "npm:5.5.1"
"@rushstack/rig-package": "npm:0.5.3"
- "@rushstack/terminal": "npm:0.14.0"
- "@rushstack/ts-command-line": "npm:4.22.6"
+ "@rushstack/terminal": "npm:0.13.3"
+ "@rushstack/ts-command-line": "npm:4.22.3"
lodash: "npm:~4.17.15"
minimatch: "npm:~3.0.3"
resolve: "npm:~1.22.1"
@@ -3248,7 +3526,7 @@ __metadata:
typescript: "npm:5.4.2"
bin:
api-extractor: bin/api-extractor
- checksum: 10/eef9d5087c72e23181aebcc8ee17678a99c27ee54a527a0f347e3a2b1432fc4f660127b3e1b9cc83e7375dfe174ec4699b7e433b91f789837290c943994a8ab2
+ checksum: 10/e7be27981cc4ba34d3fcc694d044bb952835d77ab908ce1d528cd76d7100cee33137c0d13257332dd12e07dae1d0937f0f5218348f3c9f7b2258dda89dce47cc
languageName: node
linkType: hard
@@ -3295,17 +3573,24 @@ __metadata:
languageName: node
linkType: hard
-"@mswjs/interceptors@npm:^0.35.8":
- version: 0.35.9
- resolution: "@mswjs/interceptors@npm:0.35.9"
+"@mswjs/cookies@npm:^1.1.0":
+ version: 1.1.1
+ resolution: "@mswjs/cookies@npm:1.1.1"
+ checksum: 10/85ece5b3e6e480fb86e8970ef35a945fdbc9041cfa2414d9bc15ee407560a8b53175af91d36056bd7ec0b21c6af667dc12989a8f7ba2d59a13b3302e00a624c6
+ languageName: node
+ linkType: hard
+
+"@mswjs/interceptors@npm:^0.29.0":
+ version: 0.29.1
+ resolution: "@mswjs/interceptors@npm:0.29.1"
dependencies:
"@open-draft/deferred-promise": "npm:^2.2.0"
"@open-draft/logger": "npm:^0.3.0"
"@open-draft/until": "npm:^2.0.0"
is-node-process: "npm:^1.2.0"
- outvariant: "npm:^1.4.3"
+ outvariant: "npm:^1.2.1"
strict-event-emitter: "npm:^0.5.1"
- checksum: 10/9eaf8d7876c9a38c2c9a1259873f8ad27ab41c68a49f7e14a55cd9f596458d9232adb85a5084b044d4eead3be1e7ef5bf54ed6d774d16b02d96caf1e7faa2ab3
+ checksum: 10/6a6ee6eb3db0fed60bbeb710288f8c1e2cac84f08254756b684dbd553b04449dfe4cce1261fcc83772ee114be2043d9777e2ee6d72bc8d14fd394f961827e528
languageName: node
linkType: hard
@@ -3349,52 +3634,7 @@ __metadata:
languageName: node
linkType: hard
-"@npmcli/arborist@npm:^7.5.4":
- version: 7.5.4
- resolution: "@npmcli/arborist@npm:7.5.4"
- dependencies:
- "@isaacs/string-locale-compare": "npm:^1.1.0"
- "@npmcli/fs": "npm:^3.1.1"
- "@npmcli/installed-package-contents": "npm:^2.1.0"
- "@npmcli/map-workspaces": "npm:^3.0.2"
- "@npmcli/metavuln-calculator": "npm:^7.1.1"
- "@npmcli/name-from-folder": "npm:^2.0.0"
- "@npmcli/node-gyp": "npm:^3.0.0"
- "@npmcli/package-json": "npm:^5.1.0"
- "@npmcli/query": "npm:^3.1.0"
- "@npmcli/redact": "npm:^2.0.0"
- "@npmcli/run-script": "npm:^8.1.0"
- bin-links: "npm:^4.0.4"
- cacache: "npm:^18.0.3"
- common-ancestor-path: "npm:^1.0.1"
- hosted-git-info: "npm:^7.0.2"
- json-parse-even-better-errors: "npm:^3.0.2"
- json-stringify-nice: "npm:^1.1.4"
- lru-cache: "npm:^10.2.2"
- minimatch: "npm:^9.0.4"
- nopt: "npm:^7.2.1"
- npm-install-checks: "npm:^6.2.0"
- npm-package-arg: "npm:^11.0.2"
- npm-pick-manifest: "npm:^9.0.1"
- npm-registry-fetch: "npm:^17.0.1"
- pacote: "npm:^18.0.6"
- parse-conflict-json: "npm:^3.0.0"
- proc-log: "npm:^4.2.0"
- proggy: "npm:^2.0.0"
- promise-all-reject-late: "npm:^1.0.0"
- promise-call-limit: "npm:^3.0.1"
- read-package-json-fast: "npm:^3.0.2"
- semver: "npm:^7.3.7"
- ssri: "npm:^10.0.6"
- treeverse: "npm:^3.0.0"
- walk-up-path: "npm:^3.0.1"
- bin:
- arborist: bin/index.js
- checksum: 10/b77170754f419171e5ca2abfb679a9c811443e2b67036916a62eda81fd069f12c98186941cd73a0d36c2ec76cda638b43ceeb4c5fae39de1bb9df825432f3ef7
- languageName: node
- linkType: hard
-
-"@npmcli/fs@npm:^3.1.0, @npmcli/fs@npm:^3.1.1":
+"@npmcli/fs@npm:^3.1.0":
version: 3.1.1
resolution: "@npmcli/fs@npm:3.1.1"
dependencies:
@@ -3419,7 +3659,7 @@ __metadata:
languageName: node
linkType: hard
-"@npmcli/installed-package-contents@npm:^2.0.1, @npmcli/installed-package-contents@npm:^2.1.0":
+"@npmcli/installed-package-contents@npm:^2.0.1":
version: 2.1.0
resolution: "@npmcli/installed-package-contents@npm:2.1.0"
dependencies:
@@ -3431,63 +3671,16 @@ __metadata:
languageName: node
linkType: hard
-"@npmcli/map-workspaces@npm:^3.0.2":
- version: 3.0.6
- resolution: "@npmcli/map-workspaces@npm:3.0.6"
- dependencies:
- "@npmcli/name-from-folder": "npm:^2.0.0"
- glob: "npm:^10.2.2"
- minimatch: "npm:^9.0.0"
- read-package-json-fast: "npm:^3.0.0"
- checksum: 10/b364b155991a4ff85db5ea5b9f809ab65936350fc36fe1e51d5ab8cd479bba57e69f02e17215c0e2126e383074c2987c268d8e589aacd26c9962e028f4da98f2
- languageName: node
- linkType: hard
-
-"@npmcli/metavuln-calculator@npm:^7.1.1":
- version: 7.1.1
- resolution: "@npmcli/metavuln-calculator@npm:7.1.1"
- dependencies:
- cacache: "npm:^18.0.0"
- json-parse-even-better-errors: "npm:^3.0.0"
- pacote: "npm:^18.0.0"
- proc-log: "npm:^4.1.0"
- semver: "npm:^7.3.5"
- checksum: 10/57163b4bde4af3f5badb0c9b0c868f9539e2a112ee73c606680b7548b148bf58e793952d74eb1e581c9cc2e630bc03bc60adc04b3f1e7960482f97af817f28d2
- languageName: node
- linkType: hard
-
-"@npmcli/name-from-folder@npm:^2.0.0":
- version: 2.0.0
- resolution: "@npmcli/name-from-folder@npm:2.0.0"
- checksum: 10/75beb40373f916cfcf7327958b3ab920ab4e32d24217197927dd1c76a325c7645695011fce9cb2a8f93616f8b74946e84eebe3830303e11ed9d400dae623a99b
- languageName: node
- linkType: hard
-
"@npmcli/node-gyp@npm:^3.0.0":
- version: 3.0.0
- resolution: "@npmcli/node-gyp@npm:3.0.0"
- checksum: 10/dd9fed3e80df8fbb20443f28651a8ed7235f2c15286ecc010e2d3cd392c85912e59ef29218c0b02f098defb4cbc8cdf045aab1d32d5cef6ace289913196ed5df
- languageName: node
- linkType: hard
-
-"@npmcli/package-json@npm:^5.0.0, @npmcli/package-json@npm:^5.1.0":
- version: 5.2.0
- resolution: "@npmcli/package-json@npm:5.2.0"
- dependencies:
- "@npmcli/git": "npm:^5.0.0"
- glob: "npm:^10.2.2"
- hosted-git-info: "npm:^7.0.0"
- json-parse-even-better-errors: "npm:^3.0.0"
- normalize-package-data: "npm:^6.0.0"
- proc-log: "npm:^4.0.0"
- semver: "npm:^7.5.3"
- checksum: 10/c3d2218877bfc005bca3b7a11f53825bf16a68811b8e8ed0c9b219cceb8e8e646d70efab8c5d6decbd8007f286076468b3f456dab4d41d648aff73a5f3a6fce2
+ version: 3.0.0
+ resolution: "@npmcli/node-gyp@npm:3.0.0"
+ checksum: 10/dd9fed3e80df8fbb20443f28651a8ed7235f2c15286ecc010e2d3cd392c85912e59ef29218c0b02f098defb4cbc8cdf045aab1d32d5cef6ace289913196ed5df
languageName: node
linkType: hard
-"@npmcli/package-json@npm:^5.2.1":
- version: 5.2.1
- resolution: "@npmcli/package-json@npm:5.2.1"
+"@npmcli/package-json@npm:^5.0.0, @npmcli/package-json@npm:^5.1.0":
+ version: 5.2.0
+ resolution: "@npmcli/package-json@npm:5.2.0"
dependencies:
"@npmcli/git": "npm:^5.0.0"
glob: "npm:^10.2.2"
@@ -3496,7 +3689,7 @@ __metadata:
normalize-package-data: "npm:^6.0.0"
proc-log: "npm:^4.0.0"
semver: "npm:^7.5.3"
- checksum: 10/304a819b93f79a6e0e56cb371961a66d2db72142e310d545ecbbbe4d917025a30601aa8e63a5f0cc28f0fe281c116bdaf79b334619b105a1d027a2b769ecd137
+ checksum: 10/c3d2218877bfc005bca3b7a11f53825bf16a68811b8e8ed0c9b219cceb8e8e646d70efab8c5d6decbd8007f286076468b3f456dab4d41d648aff73a5f3a6fce2
languageName: node
linkType: hard
@@ -3509,15 +3702,6 @@ __metadata:
languageName: node
linkType: hard
-"@npmcli/query@npm:^3.1.0":
- version: 3.1.0
- resolution: "@npmcli/query@npm:3.1.0"
- dependencies:
- postcss-selector-parser: "npm:^6.0.10"
- checksum: 10/fa79ae317934c95d14b89cb149cb8eb0b2a4e611acf0661681cfa964bf9af6740f60efe095c8bb7e880398e0955666408cc8a3ffede90e87922cb81cce1efcdb
- languageName: node
- linkType: hard
-
"@npmcli/redact@npm:^2.0.0":
version: 2.0.1
resolution: "@npmcli/redact@npm:2.0.1"
@@ -3539,6 +3723,13 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/auth-token@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "@octokit/auth-token@npm:4.0.0"
+ checksum: 10/60e42701e341d700f73c518c7a35675d36d79fa9d5e838cc3ade96d147e49f5ba74db2e07b2337c2b95aaa540aa42088116df2122daa25633f9e70a2c8785c44
+ languageName: node
+ linkType: hard
+
"@octokit/auth-token@npm:^5.0.0":
version: 5.1.1
resolution: "@octokit/auth-token@npm:5.1.1"
@@ -3546,6 +3737,21 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/core@npm:^5.0.2":
+ version: 5.2.0
+ resolution: "@octokit/core@npm:5.2.0"
+ dependencies:
+ "@octokit/auth-token": "npm:^4.0.0"
+ "@octokit/graphql": "npm:^7.1.0"
+ "@octokit/request": "npm:^8.3.1"
+ "@octokit/request-error": "npm:^5.1.0"
+ "@octokit/types": "npm:^13.0.0"
+ before-after-hook: "npm:^2.2.0"
+ universal-user-agent: "npm:^6.0.0"
+ checksum: 10/2e40baf0b5c6949922436a653c213be43befd9690c43dd89872f669f3ac23117ae8ae5e5d6c18094813756c71c3f4fbedd575a891f0b89e12f58b2c38b7f3c13
+ languageName: node
+ linkType: hard
+
"@octokit/core@npm:^6.1.2":
version: 6.1.2
resolution: "@octokit/core@npm:6.1.2"
@@ -3571,6 +3777,27 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/endpoint@npm:^9.0.1":
+ version: 9.0.5
+ resolution: "@octokit/endpoint@npm:9.0.5"
+ dependencies:
+ "@octokit/types": "npm:^13.1.0"
+ universal-user-agent: "npm:^6.0.0"
+ checksum: 10/212122f653bf076ec37dd7de44bd54db74aa3cd16be4c395c91444488331becd83351e26b30248168e2cc28fc07b1a96e8f74adbbab02826f76de92e069f391f
+ languageName: node
+ linkType: hard
+
+"@octokit/graphql@npm:^7.1.0":
+ version: 7.1.0
+ resolution: "@octokit/graphql@npm:7.1.0"
+ dependencies:
+ "@octokit/request": "npm:^8.3.0"
+ "@octokit/types": "npm:^13.0.0"
+ universal-user-agent: "npm:^6.0.0"
+ checksum: 10/da6857a69dc93cd20a11d3a905db4214d269d246a6aaee1d8734f922024b08ffdef0b3cba2ac79917633043b4f50464242b0bd92a265c960083dfff5b833dbbe
+ languageName: node
+ linkType: hard
+
"@octokit/graphql@npm:^8.0.0":
version: 8.1.1
resolution: "@octokit/graphql@npm:8.1.1"
@@ -3596,6 +3823,17 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/plugin-paginate-rest@npm:11.3.1":
+ version: 11.3.1
+ resolution: "@octokit/plugin-paginate-rest@npm:11.3.1"
+ dependencies:
+ "@octokit/types": "npm:^13.5.0"
+ peerDependencies:
+ "@octokit/core": 5
+ checksum: 10/82f5bcc3a536a44bed0a205c8301176c0d210b7a1c6d035a79b31a102e2e02f46234a38629cc984a21be544194ac69151814e9a909416aa7389cdffd1297bcd9
+ languageName: node
+ linkType: hard
+
"@octokit/plugin-paginate-rest@npm:^11.0.0":
version: 11.3.3
resolution: "@octokit/plugin-paginate-rest@npm:11.3.3"
@@ -3607,6 +3845,15 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/plugin-request-log@npm:^4.0.0":
+ version: 4.0.1
+ resolution: "@octokit/plugin-request-log@npm:4.0.1"
+ peerDependencies:
+ "@octokit/core": 5
+ checksum: 10/fd8c0a201490cba00084689a0d1d54fc7b5ab5b6bdb7e447056b947b1754f78526e9685400eab10d3522bfa7b5bc49c555f41ec412c788610b96500b168f3789
+ languageName: node
+ linkType: hard
+
"@octokit/plugin-request-log@npm:^5.3.1":
version: 5.3.1
resolution: "@octokit/plugin-request-log@npm:5.3.1"
@@ -3616,6 +3863,17 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/plugin-rest-endpoint-methods@npm:13.2.2":
+ version: 13.2.2
+ resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.2.2"
+ dependencies:
+ "@octokit/types": "npm:^13.5.0"
+ peerDependencies:
+ "@octokit/core": ^5
+ checksum: 10/9eccc1a22aa0b65f3f9378f26a74c386683db420c33202998918df1eef492e93212e1849e1d85530f425602663cfc2bfbf385a30991b8a04470334c74ba2386b
+ languageName: node
+ linkType: hard
+
"@octokit/plugin-rest-endpoint-methods@npm:^13.0.0":
version: 13.2.4
resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.2.4"
@@ -3627,6 +3885,17 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/request-error@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "@octokit/request-error@npm:5.1.0"
+ dependencies:
+ "@octokit/types": "npm:^13.1.0"
+ deprecation: "npm:^2.0.0"
+ once: "npm:^1.4.0"
+ checksum: 10/d03f9f7a408af673cd991eeb450b6f4a5cee6c368f6349eb0211dfc0404fddfcff8b5225ef186020a2a1829adba0aa8c9174155b49ab2ed00a94fb9a886a1dd3
+ languageName: node
+ linkType: hard
+
"@octokit/request-error@npm:^6.0.1":
version: 6.1.4
resolution: "@octokit/request-error@npm:6.1.4"
@@ -3636,6 +3905,18 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/request@npm:^8.3.0, @octokit/request@npm:^8.3.1":
+ version: 8.4.0
+ resolution: "@octokit/request@npm:8.4.0"
+ dependencies:
+ "@octokit/endpoint": "npm:^9.0.1"
+ "@octokit/request-error": "npm:^5.1.0"
+ "@octokit/types": "npm:^13.1.0"
+ universal-user-agent: "npm:^6.0.0"
+ checksum: 10/176cd83c68bde87111a01d50e2d21cf12ec362c1a30b33649eb8771d37397f6d6dd0b0844aab8d59b16d74c825252e39cadd52e37a4b1669d6facd1cb2cdc995
+ languageName: node
+ linkType: hard
+
"@octokit/request@npm:^9.0.0":
version: 9.1.3
resolution: "@octokit/request@npm:9.1.3"
@@ -3648,6 +3929,18 @@ __metadata:
languageName: node
linkType: hard
+"@octokit/rest@npm:^20.1.1":
+ version: 20.1.1
+ resolution: "@octokit/rest@npm:20.1.1"
+ dependencies:
+ "@octokit/core": "npm:^5.0.2"
+ "@octokit/plugin-paginate-rest": "npm:11.3.1"
+ "@octokit/plugin-request-log": "npm:^4.0.0"
+ "@octokit/plugin-rest-endpoint-methods": "npm:13.2.2"
+ checksum: 10/a5d557323f3ebcf813bf0965f04084dc52e71525315f865646e084713099a2baa340752caebafb17595b31c5011df0f42a15359e145046d85b5051af37a516f9
+ languageName: node
+ linkType: hard
+
"@octokit/rest@npm:^21.0.2":
version: 21.0.2
resolution: "@octokit/rest@npm:21.0.2"
@@ -3845,121 +4138,121 @@ __metadata:
languageName: node
linkType: hard
-"@rollup/rollup-android-arm-eabi@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-android-arm-eabi@npm:4.21.2"
+"@rollup/rollup-android-arm-eabi@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-android-arm-eabi@npm:4.20.0"
conditions: os=android & cpu=arm
languageName: node
linkType: hard
-"@rollup/rollup-android-arm64@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-android-arm64@npm:4.21.2"
+"@rollup/rollup-android-arm64@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-android-arm64@npm:4.20.0"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-darwin-arm64@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-darwin-arm64@npm:4.21.2"
+"@rollup/rollup-darwin-arm64@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-darwin-arm64@npm:4.20.0"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-darwin-x64@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-darwin-x64@npm:4.21.2"
+"@rollup/rollup-darwin-x64@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-darwin-x64@npm:4.20.0"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm-gnueabihf@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.21.2"
+"@rollup/rollup-linux-arm-gnueabihf@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.20.0"
conditions: os=linux & cpu=arm & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm-musleabihf@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.21.2"
+"@rollup/rollup-linux-arm-musleabihf@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.20.0"
conditions: os=linux & cpu=arm & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm64-gnu@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.21.2"
+"@rollup/rollup-linux-arm64-gnu@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.20.0"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm64-musl@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-arm64-musl@npm:4.21.2"
+"@rollup/rollup-linux-arm64-musl@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-arm64-musl@npm:4.20.0"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.2"
+"@rollup/rollup-linux-powerpc64le-gnu@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.20.0"
conditions: os=linux & cpu=ppc64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-riscv64-gnu@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.21.2"
+"@rollup/rollup-linux-riscv64-gnu@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.20.0"
conditions: os=linux & cpu=riscv64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-s390x-gnu@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.21.2"
+"@rollup/rollup-linux-s390x-gnu@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.20.0"
conditions: os=linux & cpu=s390x & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-x64-gnu@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-x64-gnu@npm:4.21.2"
+"@rollup/rollup-linux-x64-gnu@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-x64-gnu@npm:4.20.0"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-x64-musl@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-linux-x64-musl@npm:4.21.2"
+"@rollup/rollup-linux-x64-musl@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-linux-x64-musl@npm:4.20.0"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-win32-arm64-msvc@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.21.2"
+"@rollup/rollup-win32-arm64-msvc@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.20.0"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-win32-ia32-msvc@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.21.2"
+"@rollup/rollup-win32-ia32-msvc@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.20.0"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
-"@rollup/rollup-win32-x64-msvc@npm:4.21.2":
- version: 4.21.2
- resolution: "@rollup/rollup-win32-x64-msvc@npm:4.21.2"
+"@rollup/rollup-win32-x64-msvc@npm:4.20.0":
+ version: 4.20.0
+ resolution: "@rollup/rollup-win32-x64-msvc@npm:4.20.0"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
-"@rushstack/node-core-library@npm:5.7.0":
- version: 5.7.0
- resolution: "@rushstack/node-core-library@npm:5.7.0"
+"@rushstack/node-core-library@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@rushstack/node-core-library@npm:5.5.1"
dependencies:
ajv: "npm:~8.13.0"
ajv-draft-04: "npm:~1.0.0"
@@ -3974,7 +4267,7 @@ __metadata:
peerDependenciesMeta:
"@types/node":
optional: true
- checksum: 10/ed2bd40f5b99fb3853564e0c493f33926cd78008e4e265cb2849f8887ba4d48ea1b1940b6e7286f047ee9a3a419fbf826141c96e4798b7ecf80a4e4709e429bc
+ checksum: 10/e2d44c9bd00ecff3a108ae4aeff707a724e50cd3c6cb229f42fcee5be0aeafb1f3a420dd4e3eeaad4968c47b280d5d1a4017adf557479fe9314271b8efd44468
languageName: node
linkType: hard
@@ -3988,30 +4281,30 @@ __metadata:
languageName: node
linkType: hard
-"@rushstack/terminal@npm:0.14.0":
- version: 0.14.0
- resolution: "@rushstack/terminal@npm:0.14.0"
+"@rushstack/terminal@npm:0.13.3":
+ version: 0.13.3
+ resolution: "@rushstack/terminal@npm:0.13.3"
dependencies:
- "@rushstack/node-core-library": "npm:5.7.0"
+ "@rushstack/node-core-library": "npm:5.5.1"
supports-color: "npm:~8.1.1"
peerDependencies:
"@types/node": "*"
peerDependenciesMeta:
"@types/node":
optional: true
- checksum: 10/3a25652cad37d61c7d66a8bf3ea037f45b7fa639e15fc8af4b5e4cf6b45b0b7b534d211e0861b33322cf89888a70f2da97ec1a9675af3ae228998535d347c608
+ checksum: 10/2cc2fc62d811e539f7f6cd7902cf0fcc78a5061732c444e05c3e9466cf45f8129e605da763e1b94e78420699fab8ede4421c6b97ca8733bc87e660f6d0e39acb
languageName: node
linkType: hard
-"@rushstack/ts-command-line@npm:4.22.6":
- version: 4.22.6
- resolution: "@rushstack/ts-command-line@npm:4.22.6"
+"@rushstack/ts-command-line@npm:4.22.3":
+ version: 4.22.3
+ resolution: "@rushstack/ts-command-line@npm:4.22.3"
dependencies:
- "@rushstack/terminal": "npm:0.14.0"
+ "@rushstack/terminal": "npm:0.13.3"
"@types/argparse": "npm:1.0.38"
argparse: "npm:~1.0.9"
string-argv: "npm:~0.3.1"
- checksum: 10/18dcdad213ce33bb7a354664e1e58f7f8f94f16f635b27f4e974a93514b7dafb7a08e181a9888d3fb82b846856a44e7e2d417f2fde18686ddb83b28f12eab0e7
+ checksum: 10/64509a787022944ee8bbb5e860f6791d004bc5c8a0c8a74f35b4e30622ea3ef5b1912acf1c7af3eb183407d62059eb4982c9ad2d69eea7e3b53c4d1c76736b43
languageName: node
linkType: hard
@@ -4180,9 +4473,9 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/addon-actions@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-actions@npm:8.2.9"
+"@storybook/addon-actions@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-actions@npm:8.2.8"
dependencies:
"@storybook/global": "npm:^5.0.0"
"@types/uuid": "npm:^9.0.1"
@@ -4190,47 +4483,47 @@ __metadata:
polished: "npm:^4.2.2"
uuid: "npm:^9.0.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/afde25d35194911daaa6aee025cd9da51397100ab78602b5969767bd6d26e12d86f1148b1daf5bb97b2e1836565e492cc4458a7494bedeea2e4601a8b03a2175
+ storybook: ^8.2.8
+ checksum: 10/775ad1e21f9e13188e02c46dbd6f71dbbd0919e1942eb3d86c12b8b12aaefec59f9e8afb874a4494e668effb1c9d6a0a998accd8628dde37c0935cdbf0c1ebf9
languageName: node
linkType: hard
-"@storybook/addon-backgrounds@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-backgrounds@npm:8.2.9"
+"@storybook/addon-backgrounds@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-backgrounds@npm:8.2.8"
dependencies:
"@storybook/global": "npm:^5.0.0"
memoizerific: "npm:^1.11.3"
ts-dedent: "npm:^2.0.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/a93cd5a68c012de5ed4dafa4e1d1c3c06406ca8d5d19809e3dcf7c2f369d5c28b4ccf0d846a45f91665a33bef8831093376a070d61155d167494dd88f4b9b901
+ storybook: ^8.2.8
+ checksum: 10/87a692eaba48352ea1324a36ec13486953b073a3fca847c12c6353403ca3de5c18472985a028ea059380c19010e9babc7af78bbeb4cd9ae3318d5ceaa8ef9e9e
languageName: node
linkType: hard
-"@storybook/addon-controls@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-controls@npm:8.2.9"
+"@storybook/addon-controls@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-controls@npm:8.2.8"
dependencies:
dequal: "npm:^2.0.2"
lodash: "npm:^4.17.21"
ts-dedent: "npm:^2.0.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/0027db4387f909268d60dba205f07e57a22873634463a8c28aa24d2945610ac6a4b9d199697ffb1cf2eeba907dd76e4e84c8e6583e55443d109f4210db6210c5
+ storybook: ^8.2.8
+ checksum: 10/c66f5099ccb6ec284ad39149181dd621cbc9f4abdc303b01871dcd2e5279f7deb9a5901d66d13e6b8a8f9ea363bae34950024a6b2de953fb6c9abaf1d660c31b
languageName: node
linkType: hard
-"@storybook/addon-docs@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-docs@npm:8.2.9"
+"@storybook/addon-docs@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-docs@npm:8.2.8"
dependencies:
"@babel/core": "npm:^7.24.4"
"@mdx-js/react": "npm:^3.0.0"
- "@storybook/blocks": "npm:8.2.9"
- "@storybook/csf-plugin": "npm:8.2.9"
+ "@storybook/blocks": "npm:8.2.8"
+ "@storybook/csf-plugin": "npm:8.2.8"
"@storybook/global": "npm:^5.0.0"
- "@storybook/react-dom-shim": "npm:8.2.9"
+ "@storybook/react-dom-shim": "npm:8.2.8"
"@types/react": "npm:^16.8.0 || ^17.0.0 || ^18.0.0"
fs-extra: "npm:^11.1.0"
react: "npm:^16.8.0 || ^17.0.0 || ^18.0.0"
@@ -4239,115 +4532,115 @@ __metadata:
rehype-slug: "npm:^6.0.0"
ts-dedent: "npm:^2.0.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/7e940327b84cc257da72498e6295d8124044b7e3ae00453f9302a86c19642915743b567237f47989bdc5d3fbeb7d7cf8e9035a91d6b34c08c795838e8d00a82a
+ storybook: ^8.2.8
+ checksum: 10/4f8617e4d5d41d912f033a5f0b1ee6699f0e37bf257c8d313aa9f85c03dd33d834aa12f8fedb7cdf8111146d6394ce4687a83d2ce88f32ddfbfce564fc5a2448
languageName: node
linkType: hard
"@storybook/addon-essentials@npm:^8.2.8":
- version: 8.2.9
- resolution: "@storybook/addon-essentials@npm:8.2.9"
- dependencies:
- "@storybook/addon-actions": "npm:8.2.9"
- "@storybook/addon-backgrounds": "npm:8.2.9"
- "@storybook/addon-controls": "npm:8.2.9"
- "@storybook/addon-docs": "npm:8.2.9"
- "@storybook/addon-highlight": "npm:8.2.9"
- "@storybook/addon-measure": "npm:8.2.9"
- "@storybook/addon-outline": "npm:8.2.9"
- "@storybook/addon-toolbars": "npm:8.2.9"
- "@storybook/addon-viewport": "npm:8.2.9"
+ version: 8.2.8
+ resolution: "@storybook/addon-essentials@npm:8.2.8"
+ dependencies:
+ "@storybook/addon-actions": "npm:8.2.8"
+ "@storybook/addon-backgrounds": "npm:8.2.8"
+ "@storybook/addon-controls": "npm:8.2.8"
+ "@storybook/addon-docs": "npm:8.2.8"
+ "@storybook/addon-highlight": "npm:8.2.8"
+ "@storybook/addon-measure": "npm:8.2.8"
+ "@storybook/addon-outline": "npm:8.2.8"
+ "@storybook/addon-toolbars": "npm:8.2.8"
+ "@storybook/addon-viewport": "npm:8.2.8"
ts-dedent: "npm:^2.0.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/70cc46b9188cf61a30af578fa79d15135e6c51e9406f9d044668fd395c4c93b9a408481039da6dc824100016dd76da711daef79897252e982382d2262292103d
+ storybook: ^8.2.8
+ checksum: 10/8c41e118b0f745ffef400d6d50008f8da8b24190da293e423585b1c94b7528c2327dcf20631d3198b76052892b46a49b7bed5daba6ac88f849e7118373a01445
languageName: node
linkType: hard
-"@storybook/addon-highlight@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-highlight@npm:8.2.9"
+"@storybook/addon-highlight@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-highlight@npm:8.2.8"
dependencies:
"@storybook/global": "npm:^5.0.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/273a10768ec0abcc4f816972ec581c0be3963a6c85cb99dda7be0c605bf47fb92538c9a1b3339f2c38c38f9ad9ca3f784ec0b2c8b3bb55e153407351faff8f1b
+ storybook: ^8.2.8
+ checksum: 10/7791a7c5e153a5b3cf5c94343baea1d0dcffc926c7c919ff30080ee46ed9d6e42a192755dcc18dd82113db38020295c86f7f816d987e9ccb810e3fd51cb08add
languageName: node
linkType: hard
"@storybook/addon-interactions@npm:^8.2.8":
- version: 8.2.9
- resolution: "@storybook/addon-interactions@npm:8.2.9"
+ version: 8.2.8
+ resolution: "@storybook/addon-interactions@npm:8.2.8"
dependencies:
"@storybook/global": "npm:^5.0.0"
- "@storybook/instrumenter": "npm:8.2.9"
- "@storybook/test": "npm:8.2.9"
+ "@storybook/instrumenter": "npm:8.2.8"
+ "@storybook/test": "npm:8.2.8"
polished: "npm:^4.2.2"
ts-dedent: "npm:^2.2.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/6ed572a281b7b295e858324b961b02c32a18d0f7a1870cde5f00d111a8fade57dd7f975f32ffcfdf3a6565b03943e98c8fcc1875be866fa6bbc17d26b67f412d
+ storybook: ^8.2.8
+ checksum: 10/510d072eadb12c25cb15ee6544173e7bfec7bfb3c0f4a8bc727817067ff440bc89b827697c2bdf6ff3cce3eeaf22391741c87ef8baa1f99e3b784d2d4ccf64a9
languageName: node
linkType: hard
"@storybook/addon-links@npm:^8.2.8":
- version: 8.2.9
- resolution: "@storybook/addon-links@npm:8.2.9"
+ version: 8.2.8
+ resolution: "@storybook/addon-links@npm:8.2.8"
dependencies:
"@storybook/csf": "npm:0.1.11"
"@storybook/global": "npm:^5.0.0"
ts-dedent: "npm:^2.0.0"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- storybook: ^8.2.9
+ storybook: ^8.2.8
peerDependenciesMeta:
react:
optional: true
- checksum: 10/e6b14e2cb6763f25027965c90404afb2572b27298e3d1fafa136176113ad4296b1ce48eaa8caf4f521fb6d3404921f17eb3cbe62061ebdc5f2324e0c85333742
+ checksum: 10/b4aba8ce96bb93a3e456e0e75f6d30215aeb5fd9a72de8336231837fbc8e8656b742882aaec9acf247153001c2ed0b1574c86aaa17ec9d01cf5dda579d74d2dd
languageName: node
linkType: hard
-"@storybook/addon-measure@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-measure@npm:8.2.9"
+"@storybook/addon-measure@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-measure@npm:8.2.8"
dependencies:
"@storybook/global": "npm:^5.0.0"
tiny-invariant: "npm:^1.3.1"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/5a0c31b617bfdcd024c5325ab48771b8cf7b726336e24b9b0c7d4a4e8bda2093a8c2c264272b7fb36bf010f1bd54896df45b6f9092d020e696226b34e23ce208
+ storybook: ^8.2.8
+ checksum: 10/6aef93238a10e04f95ce838cdaec3676422a81c8ca1ec0dc2ddd4d61943e32d15328c496d801cc995ac0b3d7912d584d2044cc651adc9b2071af2271fb0bb4ad
languageName: node
linkType: hard
-"@storybook/addon-outline@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-outline@npm:8.2.9"
+"@storybook/addon-outline@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-outline@npm:8.2.8"
dependencies:
"@storybook/global": "npm:^5.0.0"
ts-dedent: "npm:^2.0.0"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/ad88e5d501270e7e47e955ff9e9c2aa3c5a3d9b38fe592cc7e4b5890d5c905a5ab9b644bdf7d566cdd9f66ae9ca9b9ac481f95f759a41cdfff5a3dd43103602d
+ storybook: ^8.2.8
+ checksum: 10/ef7aee9ffb930e2f29d87237709d5117fb398a9ce3b639ec1b26170d22a744f277f3867287902c16a9ea96e1ed520b92a4de2d8abbcb45fa5859fdd13603b406
languageName: node
linkType: hard
-"@storybook/addon-toolbars@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-toolbars@npm:8.2.9"
+"@storybook/addon-toolbars@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-toolbars@npm:8.2.8"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/77811c752d74f4fb0f5ab6d4a836a5c940a00a7ed9c4779327e1531ea704b4950ea542d5b3bd88380414d13218a3acd93fa7b67f923830cc2aef70e70881d43f
+ storybook: ^8.2.8
+ checksum: 10/e24a6e65c3b543c19bd737291f559fd0242ee6f4745dc6abab1d0ff6f4627d23c17746590c23498d02816a637d6bc0ff53150daa52be47e22787ae7e1b21d373
languageName: node
linkType: hard
-"@storybook/addon-viewport@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/addon-viewport@npm:8.2.9"
+"@storybook/addon-viewport@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/addon-viewport@npm:8.2.8"
dependencies:
memoizerific: "npm:^1.11.3"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/1e634e8bdae61d5d89b4a04ccfc0ddbde3c480e9bf8655772be27ff88edc0d6556305eb48dd3e47b105446e02856511f9f4988399de633663f5f08dcf2610dca
+ storybook: ^8.2.8
+ checksum: 10/c44da651f8373ebea9eb74c8a89764e75dc68489576d3b176b9f67649e986826b9d978554fb2be731fbd84a506e9e3b6f8d1bf463ce7bfd1bc890c047a0bf169
languageName: node
linkType: hard
@@ -4401,7 +4694,38 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/blocks@npm:8.2.9, @storybook/blocks@npm:^8.2.8":
+"@storybook/blocks@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/blocks@npm:8.2.8"
+ dependencies:
+ "@storybook/csf": "npm:0.1.11"
+ "@storybook/global": "npm:^5.0.0"
+ "@storybook/icons": "npm:^1.2.5"
+ "@types/lodash": "npm:^4.14.167"
+ color-convert: "npm:^2.0.1"
+ dequal: "npm:^2.0.2"
+ lodash: "npm:^4.17.21"
+ markdown-to-jsx: "npm:^7.4.5"
+ memoizerific: "npm:^1.11.3"
+ polished: "npm:^4.2.2"
+ react-colorful: "npm:^5.1.2"
+ telejson: "npm:^7.2.0"
+ ts-dedent: "npm:^2.0.0"
+ util-deprecate: "npm:^1.0.2"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.8
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ checksum: 10/257e6fb22fc2c5a8fed817a3a9d5c793089dbb11d736fae09fab703611c103ce2ba895c41b68d82529123d0d25cafa27a8a8f5ee2bc04d54c5e0c40440daf398
+ languageName: node
+ linkType: hard
+
+"@storybook/blocks@npm:^8.2.8":
version: 8.2.9
resolution: "@storybook/blocks@npm:8.2.9"
dependencies:
@@ -4432,11 +4756,11 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/builder-vite@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/builder-vite@npm:8.2.9"
+"@storybook/builder-vite@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/builder-vite@npm:8.2.8"
dependencies:
- "@storybook/csf-plugin": "npm:8.2.9"
+ "@storybook/csf-plugin": "npm:8.2.8"
"@types/find-cache-dir": "npm:^3.2.1"
browser-assert: "npm:^1.2.1"
es-module-lexer: "npm:^1.5.0"
@@ -4447,7 +4771,7 @@ __metadata:
ts-dedent: "npm:^2.0.0"
peerDependencies:
"@preact/preset-vite": "*"
- storybook: ^8.2.9
+ storybook: ^8.2.8
typescript: ">= 4.3.x"
vite: ^4.0.0 || ^5.0.0
vite-plugin-glimmerx: "*"
@@ -4458,7 +4782,7 @@ __metadata:
optional: true
vite-plugin-glimmerx:
optional: true
- checksum: 10/ed8e28b6949089939611ed25530be019c8bc80d79a232a022862c9052e3a683ca2122e9ec1fd3a349a476a14fabede98fb24d4cc88c5fc518de66afef026f771
+ checksum: 10/b742c90dfad3fb6a56df010027287fca66ab41594799b0ff3ebeeb4fdbc3825d0d7d52171ef539686939afa40d054591c77fef839c28da2edce490fb8e9a36c2
languageName: node
linkType: hard
@@ -4489,11 +4813,11 @@ __metadata:
linkType: hard
"@storybook/channels@npm:^8.2.8":
- version: 8.2.9
- resolution: "@storybook/channels@npm:8.2.9"
+ version: 8.2.8
+ resolution: "@storybook/channels@npm:8.2.8"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/377b325433fb350bb2e1fbb1c2744cbc5d22ac6af542adf9f3d895f66cde95273462c80fa3d51a9f53235196c685182601277be7e165bdd192dfeecc03e9b2b9
+ storybook: ^8.2.8
+ checksum: 10/ab3ead0f1a6cb0ba689c8e3febd687a8beee2d0f14f3855adae690c3e78d6820aed3f333b3a1c14e24e37e25574369889577446e21a90218e06a4df1dae9a573
languageName: node
linkType: hard
@@ -4538,14 +4862,14 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/codemod@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/codemod@npm:8.2.9"
+"@storybook/codemod@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/codemod@npm:8.2.8"
dependencies:
"@babel/core": "npm:^7.24.4"
"@babel/preset-env": "npm:^7.24.4"
"@babel/types": "npm:^7.24.0"
- "@storybook/core": "npm:8.2.9"
+ "@storybook/core": "npm:8.2.8"
"@storybook/csf": "npm:0.1.11"
"@types/cross-spawn": "npm:^6.0.2"
cross-spawn: "npm:^7.0.3"
@@ -4555,7 +4879,7 @@ __metadata:
prettier: "npm:^3.1.1"
recast: "npm:^0.23.5"
tiny-invariant: "npm:^1.3.1"
- checksum: 10/a0760f6612038f1a771c89c0d9054439af5b29865b44bdebb26ea6bbbf4ed768db92d349f44deb72297085e5c6c43a029b9b7d29ac531f8d998752d9c2273bf4
+ checksum: 10/2eb4d35e1226364b2dc03a86c5eb588bc7cfb7cd8d316068ed960ff8285de7598ce96d3270b58037525ed525c26b2dbc8f82a03fe1b1696ca9037cbb4af15226
languageName: node
linkType: hard
@@ -4597,17 +4921,17 @@ __metadata:
linkType: hard
"@storybook/core-events@npm:^8.2.8":
- version: 8.2.9
- resolution: "@storybook/core-events@npm:8.2.9"
+ version: 8.2.8
+ resolution: "@storybook/core-events@npm:8.2.8"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/6ac658a75702c645695d82fbd69da5cf4d559050ffa1f0023729ad34c0d84965b2abeeb65efd168b0cdb049314de002c00267eaf692064e3efeae1337cc3ba52
+ storybook: ^8.2.8
+ checksum: 10/0e2831a9b1454a11c0c87ada530ebc680d96ffc830593b0494ffa7a99572105c6dbfbd4e05e1865bce44bb6100ca1622c128becd663213f36549f24bbe8a9a37
languageName: node
linkType: hard
-"@storybook/core@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/core@npm:8.2.9"
+"@storybook/core@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/core@npm:8.2.8"
dependencies:
"@storybook/csf": "npm:0.1.11"
"@types/express": "npm:^4.17.21"
@@ -4620,18 +4944,18 @@ __metadata:
recast: "npm:^0.23.5"
util: "npm:^0.12.4"
ws: "npm:^8.2.3"
- checksum: 10/38602bae881a9824520b9369fdb37c4178bbdcc158934905af6d11963df289e9b958bdc05ef61773c70274a41188c473040e7d9113cc3043475f48005ec8f479
+ checksum: 10/baebc94d56169419e0223df8942aa5c4ee36f67e141d3cdd47add95ff39ef3676b7924eeaf518da81b2bce663421f10820cb8071c36df7e330bb2531fb47d58c
languageName: node
linkType: hard
-"@storybook/csf-plugin@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/csf-plugin@npm:8.2.9"
+"@storybook/csf-plugin@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/csf-plugin@npm:8.2.8"
dependencies:
unplugin: "npm:^1.3.1"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/514171f66a4e71849ee7a4efacc3051de0714fda56dfdb7581f5d08a268d5a9d0bee6264404bd766f631f2ab8a0358b4c226ecfcee8965d8560d1afc5d17c1b9
+ storybook: ^8.2.8
+ checksum: 10/400fb62367279ead2a2c4c5e856aa8c6e7bfeed081206a3f5a2c73554b725c277281b0360e9407997d434fa228148a04b73f27ee082486980803c6a74eb49846
languageName: node
linkType: hard
@@ -4670,16 +4994,16 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/instrumenter@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/instrumenter@npm:8.2.9"
+"@storybook/instrumenter@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/instrumenter@npm:8.2.8"
dependencies:
"@storybook/global": "npm:^5.0.0"
"@vitest/utils": "npm:^1.3.1"
util: "npm:^0.12.4"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/c31a3ec70e252975f56d141942db1e8187b976fbb69e718f6ec83fe1b693457a1ca9173341ae17a8bff294ff02dfe734449c7120098442f01d3e14dd3b20f667
+ storybook: ^8.2.8
+ checksum: 10/6a6f109e09075adfa96ca131f98774555c7fba50a182ce20014dbd4458fd74a57b97266b7558feb0da82242a984d7fabf29062b71867d8b530825d6c8cedd159
languageName: node
linkType: hard
@@ -4701,6 +5025,17 @@ __metadata:
languageName: node
linkType: hard
+"@storybook/react-dom-shim@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/react-dom-shim@npm:8.2.8"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.8
+ checksum: 10/2fd275f7a3c1a1e10ecc99a22533408b8da622ffd3b40cff6728883cb9ada7fe3eae97b05da56874573b2ab575129ad45a5466362d7b8deede9929c6596d8780
+ languageName: node
+ linkType: hard
+
"@storybook/react-dom-shim@npm:8.2.9":
version: 8.2.9
resolution: "@storybook/react-dom-shim@npm:8.2.9"
@@ -4713,13 +5048,13 @@ __metadata:
linkType: hard
"@storybook/react-vite@npm:^8.2.8":
- version: 8.2.9
- resolution: "@storybook/react-vite@npm:8.2.9"
+ version: 8.2.8
+ resolution: "@storybook/react-vite@npm:8.2.8"
dependencies:
"@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.3.1"
"@rollup/pluginutils": "npm:^5.0.2"
- "@storybook/builder-vite": "npm:8.2.9"
- "@storybook/react": "npm:8.2.9"
+ "@storybook/builder-vite": "npm:8.2.8"
+ "@storybook/react": "npm:8.2.8"
find-up: "npm:^5.0.0"
magic-string: "npm:^0.30.0"
react-docgen: "npm:^7.0.0"
@@ -4728,13 +5063,50 @@ __metadata:
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
- storybook: ^8.2.9
+ storybook: ^8.2.8
vite: ^4.0.0 || ^5.0.0
- checksum: 10/1acae6bae3c5f4cb0067a23235f2e5030f28b35b74e279b7a74795b49a230e331cf3dec498645ccfe24726bb04dbb1d56b696b03a51c281ccb26e6000416e2c2
+ checksum: 10/24c9b77978d7667d7365210951a5cc221ace1f0c915bf21a9cfb5a53b6a3dc65c732bd04b444dd97e62ba00b36267260c2fdcb3d34a8848980c5d6ccb1136f95
+ languageName: node
+ linkType: hard
+
+"@storybook/react@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/react@npm:8.2.8"
+ dependencies:
+ "@storybook/components": "npm:^8.2.8"
+ "@storybook/global": "npm:^5.0.0"
+ "@storybook/manager-api": "npm:^8.2.8"
+ "@storybook/preview-api": "npm:^8.2.8"
+ "@storybook/react-dom-shim": "npm:8.2.8"
+ "@storybook/theming": "npm:^8.2.8"
+ "@types/escodegen": "npm:^0.0.6"
+ "@types/estree": "npm:^0.0.51"
+ "@types/node": "npm:^18.0.0"
+ acorn: "npm:^7.4.1"
+ acorn-jsx: "npm:^5.3.1"
+ acorn-walk: "npm:^7.2.0"
+ escodegen: "npm:^2.1.0"
+ html-tags: "npm:^3.1.0"
+ lodash: "npm:^4.17.21"
+ prop-types: "npm:^15.7.2"
+ react-element-to-jsx-string: "npm:^15.0.0"
+ semver: "npm:^7.3.7"
+ ts-dedent: "npm:^2.0.0"
+ type-fest: "npm:~2.19"
+ util-deprecate: "npm:^1.0.2"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
+ storybook: ^8.2.8
+ typescript: ">= 4.2.x"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10/bc48a9460326d0a3e2558eac803078d2d91d40946c14123a303018a33fc4c1795606c7a004aab39b29c818f1e0c15d23e541582d401c0409c1bc911e537545d5
languageName: node
linkType: hard
-"@storybook/react@npm:8.2.9, @storybook/react@npm:^8.2.8":
+"@storybook/react@npm:^8.2.8":
version: 8.2.9
resolution: "@storybook/react@npm:8.2.9"
dependencies:
@@ -4825,12 +5197,12 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/test@npm:8.2.9":
- version: 8.2.9
- resolution: "@storybook/test@npm:8.2.9"
+"@storybook/test@npm:8.2.8":
+ version: 8.2.8
+ resolution: "@storybook/test@npm:8.2.8"
dependencies:
"@storybook/csf": "npm:0.1.11"
- "@storybook/instrumenter": "npm:8.2.9"
+ "@storybook/instrumenter": "npm:8.2.8"
"@testing-library/dom": "npm:10.1.0"
"@testing-library/jest-dom": "npm:6.4.5"
"@testing-library/user-event": "npm:14.5.2"
@@ -4838,8 +5210,8 @@ __metadata:
"@vitest/spy": "npm:1.6.0"
util: "npm:^0.12.4"
peerDependencies:
- storybook: ^8.2.9
- checksum: 10/2440fac3b9f2205f5ef9762dccbfcb72bbe4f5db881c57c5ceb06fecfd072e039643ed2456d2b3260af6a4419f6fecafa77d247f9570afd553e4b0e8a19175a3
+ storybook: ^8.2.8
+ checksum: 10/b804085d04923333fa7223be0edb34e8c1b1d5ae86f4382369680da7f1af351fc2220f702a402397ecd0712bcdeca6a1cad2c70f293ffd13855a4258c5258d4f
languageName: node
linkType: hard
@@ -4878,90 +5250,90 @@ __metadata:
languageName: node
linkType: hard
-"@swc/core-darwin-arm64@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-darwin-arm64@npm:1.7.28"
+"@swc/core-darwin-arm64@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-darwin-arm64@npm:1.7.14"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"@swc/core-darwin-x64@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-darwin-x64@npm:1.7.28"
+"@swc/core-darwin-x64@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-darwin-x64@npm:1.7.14"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"@swc/core-linux-arm-gnueabihf@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.28"
+"@swc/core-linux-arm-gnueabihf@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.14"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
-"@swc/core-linux-arm64-gnu@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-linux-arm64-gnu@npm:1.7.28"
+"@swc/core-linux-arm64-gnu@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-linux-arm64-gnu@npm:1.7.14"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
-"@swc/core-linux-arm64-musl@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-linux-arm64-musl@npm:1.7.28"
+"@swc/core-linux-arm64-musl@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-linux-arm64-musl@npm:1.7.14"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
-"@swc/core-linux-x64-gnu@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-linux-x64-gnu@npm:1.7.28"
+"@swc/core-linux-x64-gnu@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-linux-x64-gnu@npm:1.7.14"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
-"@swc/core-linux-x64-musl@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-linux-x64-musl@npm:1.7.28"
+"@swc/core-linux-x64-musl@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-linux-x64-musl@npm:1.7.14"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
-"@swc/core-win32-arm64-msvc@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-win32-arm64-msvc@npm:1.7.28"
+"@swc/core-win32-arm64-msvc@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-win32-arm64-msvc@npm:1.7.14"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"@swc/core-win32-ia32-msvc@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-win32-ia32-msvc@npm:1.7.28"
+"@swc/core-win32-ia32-msvc@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-win32-ia32-msvc@npm:1.7.14"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
-"@swc/core-win32-x64-msvc@npm:1.7.28":
- version: 1.7.28
- resolution: "@swc/core-win32-x64-msvc@npm:1.7.28"
+"@swc/core-win32-x64-msvc@npm:1.7.14":
+ version: 1.7.14
+ resolution: "@swc/core-win32-x64-msvc@npm:1.7.14"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@swc/core@npm:^1.7.14":
- version: 1.7.28
- resolution: "@swc/core@npm:1.7.28"
- dependencies:
- "@swc/core-darwin-arm64": "npm:1.7.28"
- "@swc/core-darwin-x64": "npm:1.7.28"
- "@swc/core-linux-arm-gnueabihf": "npm:1.7.28"
- "@swc/core-linux-arm64-gnu": "npm:1.7.28"
- "@swc/core-linux-arm64-musl": "npm:1.7.28"
- "@swc/core-linux-x64-gnu": "npm:1.7.28"
- "@swc/core-linux-x64-musl": "npm:1.7.28"
- "@swc/core-win32-arm64-msvc": "npm:1.7.28"
- "@swc/core-win32-ia32-msvc": "npm:1.7.28"
- "@swc/core-win32-x64-msvc": "npm:1.7.28"
+ version: 1.7.14
+ resolution: "@swc/core@npm:1.7.14"
+ dependencies:
+ "@swc/core-darwin-arm64": "npm:1.7.14"
+ "@swc/core-darwin-x64": "npm:1.7.14"
+ "@swc/core-linux-arm-gnueabihf": "npm:1.7.14"
+ "@swc/core-linux-arm64-gnu": "npm:1.7.14"
+ "@swc/core-linux-arm64-musl": "npm:1.7.14"
+ "@swc/core-linux-x64-gnu": "npm:1.7.14"
+ "@swc/core-linux-x64-musl": "npm:1.7.14"
+ "@swc/core-win32-arm64-msvc": "npm:1.7.14"
+ "@swc/core-win32-ia32-msvc": "npm:1.7.14"
+ "@swc/core-win32-x64-msvc": "npm:1.7.14"
"@swc/counter": "npm:^0.1.3"
"@swc/types": "npm:^0.1.12"
peerDependencies:
@@ -4990,7 +5362,7 @@ __metadata:
peerDependenciesMeta:
"@swc/helpers":
optional: true
- checksum: 10/a477e79387ecc8b68c2bdbbdc88cc61f27a02c5d00f0d77134f9e2de166786a4ee9f7388d6ffd44fc01bfef5311a15cc3132052bab72fb43246dc42705fedb60
+ checksum: 10/75cc386a7538da58fd2c8e141503b6efc9d1fddda4fa87c0e54e32422b5e5276eac259fc6a6a83d5f6758480f739d178a5c36d1209127c0459ca006f7075b0a6
languageName: node
linkType: hard
@@ -5121,6 +5493,21 @@ __metadata:
languageName: node
linkType: hard
+"@testing-library/jest-dom@npm:^6.4.2":
+ version: 6.5.0
+ resolution: "@testing-library/jest-dom@npm:6.5.0"
+ dependencies:
+ "@adobe/css-tools": "npm:^4.4.0"
+ aria-query: "npm:^5.0.0"
+ chalk: "npm:^3.0.0"
+ css.escape: "npm:^1.5.1"
+ dom-accessibility-api: "npm:^0.6.3"
+ lodash: "npm:^4.17.21"
+ redent: "npm:^3.0.0"
+ checksum: 10/3d2080888af5fd7306f57448beb5a23f55d965e265b5e53394fffc112dfb0678d616a5274ff0200c46c7618f293520f86fc8562eecd8bdbc0dbb3294d63ec431
+ languageName: node
+ linkType: hard
+
"@testing-library/react@npm:^16.0.0":
version: 16.0.0
resolution: "@testing-library/react@npm:16.0.0"
@@ -5299,6 +5686,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-array@npm:3.0.3":
+ version: 3.0.3
+ resolution: "@types/d3-array@npm:3.0.3"
+ checksum: 10/2fee8da651edf772dfa1f1527cc2fd3f39a711de341a93faf4c304dc6a45ae498341481fe0805bfa0c6f7d329453e65cae2f9635503c2cdc8480903ebed67db7
+ languageName: node
+ linkType: hard
+
"@types/d3-axis@npm:*":
version: 3.0.6
resolution: "@types/d3-axis@npm:3.0.6"
@@ -5331,6 +5725,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-color@npm:3.1.0":
+ version: 3.1.0
+ resolution: "@types/d3-color@npm:3.1.0"
+ checksum: 10/c5e2129602d5d28bd178632198b158f5d27c958252a9ddf9fdc86ac38b987ae96fdd465be88913914d2ce8a4975358f86ea56362d0ac01365b234a5a8bc31861
+ languageName: node
+ linkType: hard
+
"@types/d3-contour@npm:*":
version: 3.0.6
resolution: "@types/d3-contour@npm:3.0.6"
@@ -5348,6 +5749,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-delaunay@npm:6.0.1":
+ version: 6.0.1
+ resolution: "@types/d3-delaunay@npm:6.0.1"
+ checksum: 10/a4c62fdc6fe4a579ed84696d0c208b0b43249a7a6789cee8f6d80f75d31d09b02ca9d831a5a724bd7933ff1a56224a9d07a629b31a6602836f9cbd0629faca64
+ languageName: node
+ linkType: hard
+
"@types/d3-dispatch@npm:*":
version: 3.0.6
resolution: "@types/d3-dispatch@npm:3.0.6"
@@ -5408,7 +5816,14 @@ __metadata:
languageName: node
linkType: hard
-"@types/d3-geo@npm:*":
+"@types/d3-format@npm:3.0.1":
+ version: 3.0.1
+ resolution: "@types/d3-format@npm:3.0.1"
+ checksum: 10/f52886eeec5d471c8fcb83d9731fd8d98a6e119666a7480880513c7cc8654c1e43d0e6d5ae8023d0c22c376ba17c560c9aaca8daea488a2d1fb117366d228f0a
+ languageName: node
+ linkType: hard
+
+"@types/d3-geo@npm:*, @types/d3-geo@npm:3.1.0":
version: 3.1.0
resolution: "@types/d3-geo@npm:3.1.0"
dependencies:
@@ -5433,6 +5848,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-interpolate@npm:3.0.1":
+ version: 3.0.1
+ resolution: "@types/d3-interpolate@npm:3.0.1"
+ dependencies:
+ "@types/d3-color": "npm:*"
+ checksum: 10/806642d869366ec1b2caeb47a716654611728d3281ac7e2d9f06e2a5a0482ec6028952abbec394b722da8d50f81b4ce9158c741620ea8fec231226ea3bc4bb18
+ languageName: node
+ linkType: hard
+
"@types/d3-path@npm:*":
version: 3.1.0
resolution: "@types/d3-path@npm:3.1.0"
@@ -5440,6 +5864,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-path@npm:^1, @types/d3-path@npm:^1.0.8":
+ version: 1.0.11
+ resolution: "@types/d3-path@npm:1.0.11"
+ checksum: 10/faddcf4d636317aed4191afc55e0c49bfc9ccb24ab1594b8d0cd3aee5a522cd1fe51eb8ebc4e43494b6f78d8b0e8cae858495240830d32052ea1c10f0926626c
+ languageName: node
+ linkType: hard
+
"@types/d3-polygon@npm:*":
version: 3.0.2
resolution: "@types/d3-polygon@npm:3.0.2"
@@ -5477,6 +5908,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-scale@npm:4.0.2":
+ version: 4.0.2
+ resolution: "@types/d3-scale@npm:4.0.2"
+ dependencies:
+ "@types/d3-time": "npm:*"
+ checksum: 10/09ded5f71b915f512718774c08663f76d6518f5085d7e94ae562f9ffd1fe48ee493a33d4766cb9d324df0144bcf67a36853329c84122653bb2660e024ebf579b
+ languageName: node
+ linkType: hard
+
"@types/d3-selection@npm:*":
version: 3.0.10
resolution: "@types/d3-selection@npm:3.0.10"
@@ -5493,6 +5933,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-shape@npm:^1.3.1":
+ version: 1.3.12
+ resolution: "@types/d3-shape@npm:1.3.12"
+ dependencies:
+ "@types/d3-path": "npm:^1"
+ checksum: 10/fcb51938332c9af5d749956385fe5b6a9cd9c174619f6bf5e419efa3c4d0d0b3df919eb971bf94cacd95a24dac10f97bcf373d1fe53dcd9ae2d5dd909cbec7f0
+ languageName: node
+ linkType: hard
+
"@types/d3-time-format@npm:*":
version: 4.0.3
resolution: "@types/d3-time-format@npm:4.0.3"
@@ -5500,6 +5949,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-time-format@npm:2.1.0":
+ version: 2.1.0
+ resolution: "@types/d3-time-format@npm:2.1.0"
+ checksum: 10/803931c31f2725606fab35b8d6ae6fa04bda80f35675e57e9e4668988391728284f7993f76798d5dbd9d11f815abae55e9f831e36da80b1c6c354060cdc09f1b
+ languageName: node
+ linkType: hard
+
"@types/d3-time@npm:*":
version: 3.0.3
resolution: "@types/d3-time@npm:3.0.3"
@@ -5507,6 +5963,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-time@npm:3.0.0":
+ version: 3.0.0
+ resolution: "@types/d3-time@npm:3.0.0"
+ checksum: 10/7ef819c98eb0254dc5df901c94ec7f435f9becdedff048c89f905403b934a4d8dee7730659549d60e5ce18e0e9010009b1ab1522aadc724751edaecafc54ba53
+ languageName: node
+ linkType: hard
+
"@types/d3-timer@npm:*":
version: 3.0.2
resolution: "@types/d3-timer@npm:3.0.2"
@@ -5730,13 +6193,13 @@ __metadata:
languageName: node
linkType: hard
-"@types/jest@npm:^29.4.0":
- version: 29.5.14
- resolution: "@types/jest@npm:29.5.14"
+"@types/jest@npm:^29.4.0, @types/jest@npm:^29.5.12":
+ version: 29.5.12
+ resolution: "@types/jest@npm:29.5.12"
dependencies:
expect: "npm:^29.0.0"
pretty-format: "npm:^29.0.0"
- checksum: 10/59ec7a9c4688aae8ee529316c43853468b6034f453d08a2e1064b281af9c81234cec986be796288f1bbb29efe943bc950e70c8fa8faae1e460d50e3cf9760f9b
+ checksum: 10/312e8dcf92cdd5a5847d6426f0940829bca6fe6b5a917248f3d7f7ef5d85c9ce78ef05e47d2bbabc40d41a930e0e36db2d443d2610a9e3db9062da2d5c904211
languageName: node
linkType: hard
@@ -5751,34 +6214,34 @@ __metadata:
languageName: node
linkType: hard
-"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15":
+"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.9":
version: 7.0.15
resolution: "@types/json-schema@npm:7.0.15"
checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7
languageName: node
linkType: hard
-"@types/lodash@npm:^4":
+"@types/json5@npm:^0.0.29":
+ version: 0.0.29
+ resolution: "@types/json5@npm:0.0.29"
+ checksum: 10/4e5aed58cabb2bbf6f725da13421aa50a49abb6bc17bfab6c31b8774b073fa7b50d557c61f961a09a85f6056151190f8ac95f13f5b48136ba5841f7d4484ec56
+ languageName: node
+ linkType: hard
+
+"@types/lodash@npm:^4, @types/lodash@npm:^4.14.172":
version: 4.17.13
resolution: "@types/lodash@npm:4.17.13"
checksum: 10/ddb34e20810c71be2d9445bcc4b64ec25b83976738454de709854b79c7f655b03704b76235445699956d65012987720e0e429a35489de65495cdb5420202d905
languageName: node
linkType: hard
-"@types/lodash@npm:^4.14.167":
+"@types/lodash@npm:^4.14.167, @types/lodash@npm:^4.17.0":
version: 4.17.5
resolution: "@types/lodash@npm:4.17.5"
checksum: 10/10e2e9cbeb16998026f4071f9f5f2a38b651eba15302f512e0b8ab904c07c197ca0282d2821f64e53c2b692d7046af0a1ce3ead190fb077cbe4036948fce1924
languageName: node
linkType: hard
-"@types/lodash@npm:^4.17.7":
- version: 4.17.7
- resolution: "@types/lodash@npm:4.17.7"
- checksum: 10/b8177f19cf962414a66989837481b13f546afc2e98e8d465bec59e6ac03a59c584eb7053ce511cde3a09c5f3096d22a5ae22cfb56b23f3b0da75b0743b6b1a44
- languageName: node
- linkType: hard
-
"@types/mdx@npm:^2.0.0":
version: 2.0.13
resolution: "@types/mdx@npm:2.0.13"
@@ -5819,20 +6282,29 @@ __metadata:
linkType: hard
"@types/node@npm:^18.0.0":
- version: 18.19.54
- resolution: "@types/node@npm:18.19.54"
+ version: 18.19.36
+ resolution: "@types/node@npm:18.19.36"
dependencies:
undici-types: "npm:~5.26.4"
- checksum: 10/99cbad8b8d7493c8c9b1df77229f5684dc1477383db8bd7692792700df1a059bc66cd49625bde29d8da072da6a553ed08cf914866a6989a66300355571db124e
+ checksum: 10/417756b2ee26babd92bbf5fe626e08f192f67b03219f897b479fe3329997f8a251bfb8488d2468d59a7ada42f5bb8283411d3be72184b74bd142e3b9b3b4bfc5
languageName: node
linkType: hard
"@types/node@npm:^20.0.0, @types/node@npm:^20.12.13":
- version: 20.16.10
- resolution: "@types/node@npm:20.16.10"
+ version: 20.16.5
+ resolution: "@types/node@npm:20.16.5"
+ dependencies:
+ undici-types: "npm:~6.19.2"
+ checksum: 10/39a8457149dc17cdea57afc90d4da53182fdb8b958d5bb065a15d123d81d4efa6b51a0de92428d05ead2e63ce07195586f71083401b99cdbcd04662344fbf7a1
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:^22.5.2":
+ version: 22.5.4
+ resolution: "@types/node@npm:22.5.4"
dependencies:
undici-types: "npm:~6.19.2"
- checksum: 10/f0832d16fed07737c2c3edd6cb6414a22e8379173e56e701ab8890b8798c8f9bc37337332631818f813ff7f8c0e168e9900e8f44cdfd2406d15150289c813acc
+ checksum: 10/d46e0abf437b36bdf89011287aa43873d68ea6f2521a11b5c9a033056fd0d07af36daf51439010e8d41c62c55d0b00e9b5e09ed00bb2617723f73f28a873903a
languageName: node
linkType: hard
@@ -5865,11 +6337,11 @@ __metadata:
linkType: hard
"@types/react-dom@npm:^18.2.10":
- version: 18.3.1
- resolution: "@types/react-dom@npm:18.3.1"
+ version: 18.3.0
+ resolution: "@types/react-dom@npm:18.3.0"
dependencies:
"@types/react": "npm:*"
- checksum: 10/33f9ba79b26641ddf00a8699c30066b7e3573ab254e97475bf08f82fab83a6d3ce8d4ebad86afeb49bb8df3374390a9ba93125cece33badc4b3e8f7eac3c84d8
+ checksum: 10/6ff53f5a7b7fba952a68e114d3b542ebdc1e87a794234785ebab0bcd9bde7fb4885f21ebaf93d26dc0a1b5b93287f42cad68b78ae04dddf6b20da7aceff0beaf
languageName: node
linkType: hard
@@ -5883,12 +6355,12 @@ __metadata:
linkType: hard
"@types/react@npm:*, @types/react@npm:^16.8.0 || ^17.0.0 || ^18.0.0, @types/react@npm:^18.2.25":
- version: 18.3.12
- resolution: "@types/react@npm:18.3.12"
+ version: 18.3.3
+ resolution: "@types/react@npm:18.3.3"
dependencies:
"@types/prop-types": "npm:*"
csstype: "npm:^3.0.2"
- checksum: 10/c9bbdfeacd5347d2240e0d2cb5336bc57dbc1b9ff557b6c4024b49df83419e4955553518169d3736039f1b62608e15b35762a6c03d49bd86e33add4b43b19033
+ checksum: 10/68e203b7f1f91d6cf21f33fc7af9d6d228035a26c83f514981e54aa3da695d0ec6af10c277c6336de1dd76c4adbe9563f3a21f80c4462000f41e5f370b46e96c
languageName: node
linkType: hard
@@ -5899,7 +6371,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/semver@npm:^7.3.4":
+"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4":
version: 7.5.8
resolution: "@types/semver@npm:7.5.8"
checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178
@@ -5955,7 +6427,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/tough-cookie@npm:*, @types/tough-cookie@npm:^4.0.5":
+"@types/tough-cookie@npm:*":
version: 4.0.5
resolution: "@types/tough-cookie@npm:4.0.5"
checksum: 10/01fd82efc8202670865928629697b62fe9bf0c0dcbc5b1c115831caeb073a2c0abb871ff393d7df1ae94ea41e256cb87d2a5a91fd03cdb1b0b4384e08d4ee482
@@ -5997,6 +6469,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/xml-name-validator@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "@types/xml-name-validator@npm:4.0.3"
+ checksum: 10/2a89715fcc09731506c295d21f65f553c303ef61c61a8979ff87c2098d77f0e229f0ab1e1ce4019b9ffb7575ddb6c55cc1f98951f768338a662f8c34bdc5f09b
+ languageName: node
+ linkType: hard
+
"@types/yargs-parser@npm:*":
version: 21.0.3
resolution: "@types/yargs-parser@npm:21.0.3"
@@ -6063,6 +6542,16 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/scope-manager@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/scope-manager@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ checksum: 10/e827770baa202223bc0387e2fd24f630690809e460435b7dc9af336c77322290a770d62bd5284260fa881c86074d6a9fd6c97b07382520b115f6786b8ed499da
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/scope-manager@npm:8.5.0":
version: 8.5.0
resolution: "@typescript-eslint/scope-manager@npm:8.5.0"
@@ -6088,6 +6577,13 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/types@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/types@npm:5.62.0"
+ checksum: 10/24e8443177be84823242d6729d56af2c4b47bfc664dd411a1d730506abf2150d6c31bdefbbc6d97c8f91043e3a50e0c698239dcb145b79bb6b0c34469aaf6c45
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/types@npm:8.5.0":
version: 8.5.0
resolution: "@typescript-eslint/types@npm:8.5.0"
@@ -6095,6 +6591,24 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/typescript-estree@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/typescript-estree@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ debug: "npm:^4.3.4"
+ globby: "npm:^11.1.0"
+ is-glob: "npm:^4.0.3"
+ semver: "npm:^7.3.7"
+ tsutils: "npm:^3.21.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10/06c975eb5f44b43bd19fadc2e1023c50cf87038fe4c0dd989d4331c67b3ff509b17fa60a3251896668ab4d7322bdc56162a9926971218d2e1a1874d2bef9a52e
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/typescript-estree@npm:8.5.0":
version: 8.5.0
resolution: "@typescript-eslint/typescript-estree@npm:8.5.0"
@@ -6128,6 +6642,34 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/utils@npm:^5.10.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/utils@npm:5.62.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.2.0"
+ "@types/json-schema": "npm:^7.0.9"
+ "@types/semver": "npm:^7.3.12"
+ "@typescript-eslint/scope-manager": "npm:5.62.0"
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/typescript-estree": "npm:5.62.0"
+ eslint-scope: "npm:^5.1.1"
+ semver: "npm:^7.3.7"
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ checksum: 10/15ef13e43998a082b15f85db979f8d3ceb1f9ce4467b8016c267b1738d5e7cdb12aa90faf4b4e6dd6486c236cf9d33c463200465cf25ff997dbc0f12358550a1
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/visitor-keys@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/visitor-keys@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ eslint-visitor-keys: "npm:^3.3.0"
+ checksum: 10/dc613ab7569df9bbe0b2ca677635eb91839dfb2ca2c6fa47870a5da4f160db0b436f7ec0764362e756d4164e9445d49d5eb1ff0b87f4c058946ae9d8c92eb388
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/visitor-keys@npm:8.5.0":
version: 8.5.0
resolution: "@typescript-eslint/visitor-keys@npm:8.5.0"
@@ -6138,25 +6680,106 @@ __metadata:
languageName: node
linkType: hard
-"@ungap/structured-clone@npm:^1.0.0":
+"@ungap/structured-clone@npm:^1.0.0, @ungap/structured-clone@npm:^1.2.0":
version: 1.2.0
resolution: "@ungap/structured-clone@npm:1.2.0"
checksum: 10/c6fe89a505e513a7592e1438280db1c075764793a2397877ff1351721fe8792a966a5359769e30242b3cd023f2efb9e63ca2ca88019d73b564488cc20e3eab12
languageName: node
linkType: hard
+"@visx/curve@npm:3.12.0":
+ version: 3.12.0
+ resolution: "@visx/curve@npm:3.12.0"
+ dependencies:
+ "@types/d3-shape": "npm:^1.3.1"
+ d3-shape: "npm:^1.0.6"
+ checksum: 10/aa066ce88751d49919254b7a43b62803e315e7a203dfe186ad7e546a47112e0299312550ea54586d3f1e05ed2a53253a5fbf1530d06d8fead3a1cb270406c1f3
+ languageName: node
+ linkType: hard
+
+"@visx/group@npm:3.12.0":
+ version: 3.12.0
+ resolution: "@visx/group@npm:3.12.0"
+ dependencies:
+ "@types/react": "npm:*"
+ classnames: "npm:^2.3.1"
+ prop-types: "npm:^15.6.2"
+ peerDependencies:
+ react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0
+ checksum: 10/bf96859d6a38d7038eb757bd39f47e4f5861f15a1dd33dd6ba6b0e823071b77214721dfa5e6e0d3a0085a3316e48b7d703f82847f7afec54b50aa8188f6149ff
+ languageName: node
+ linkType: hard
+
+"@visx/scale@npm:3.12.0":
+ version: 3.12.0
+ resolution: "@visx/scale@npm:3.12.0"
+ dependencies:
+ "@visx/vendor": "npm:3.12.0"
+ checksum: 10/6d0741a59af520de14960c5111e145a7f823670911259f19b3f9712cf1791ee9b1abd15a045172032928aae8ba76dc50b01e59b634255de74b56585449b47196
+ languageName: node
+ linkType: hard
+
+"@visx/shape@npm:^3.12.0":
+ version: 3.12.0
+ resolution: "@visx/shape@npm:3.12.0"
+ dependencies:
+ "@types/d3-path": "npm:^1.0.8"
+ "@types/d3-shape": "npm:^1.3.1"
+ "@types/lodash": "npm:^4.14.172"
+ "@types/react": "npm:*"
+ "@visx/curve": "npm:3.12.0"
+ "@visx/group": "npm:3.12.0"
+ "@visx/scale": "npm:3.12.0"
+ classnames: "npm:^2.3.1"
+ d3-path: "npm:^1.0.5"
+ d3-shape: "npm:^1.2.0"
+ lodash: "npm:^4.17.21"
+ prop-types: "npm:^15.5.10"
+ peerDependencies:
+ react: ^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0
+ checksum: 10/68a7e9ba651048dec721429c38f5d81a49e5b5a50460875b23ce0e7a41f62b6900920f544874756abd27f9341b2d452f448ff91710d32be439f0700ca1b95519
+ languageName: node
+ linkType: hard
+
+"@visx/vendor@npm:3.12.0":
+ version: 3.12.0
+ resolution: "@visx/vendor@npm:3.12.0"
+ dependencies:
+ "@types/d3-array": "npm:3.0.3"
+ "@types/d3-color": "npm:3.1.0"
+ "@types/d3-delaunay": "npm:6.0.1"
+ "@types/d3-format": "npm:3.0.1"
+ "@types/d3-geo": "npm:3.1.0"
+ "@types/d3-interpolate": "npm:3.0.1"
+ "@types/d3-scale": "npm:4.0.2"
+ "@types/d3-time": "npm:3.0.0"
+ "@types/d3-time-format": "npm:2.1.0"
+ d3-array: "npm:3.2.1"
+ d3-color: "npm:3.1.0"
+ d3-delaunay: "npm:6.0.2"
+ d3-format: "npm:3.1.0"
+ d3-geo: "npm:3.1.0"
+ d3-interpolate: "npm:3.0.1"
+ d3-scale: "npm:4.0.2"
+ d3-time: "npm:3.1.0"
+ d3-time-format: "npm:4.1.0"
+ internmap: "npm:2.0.3"
+ checksum: 10/34375e0bbd0b18232acd9241875a657c95d9c8cd97e52cd5a17d3c8364a88d43495ab730ecd6fea2e9641d364b49f68a030599133a1130fad887917bf5cdd379
+ languageName: node
+ linkType: hard
+
"@vitejs/plugin-react@npm:^4.0.3":
- version: 4.3.3
- resolution: "@vitejs/plugin-react@npm:4.3.3"
+ version: 4.3.1
+ resolution: "@vitejs/plugin-react@npm:4.3.1"
dependencies:
- "@babel/core": "npm:^7.25.2"
- "@babel/plugin-transform-react-jsx-self": "npm:^7.24.7"
- "@babel/plugin-transform-react-jsx-source": "npm:^7.24.7"
+ "@babel/core": "npm:^7.24.5"
+ "@babel/plugin-transform-react-jsx-self": "npm:^7.24.5"
+ "@babel/plugin-transform-react-jsx-source": "npm:^7.24.1"
"@types/babel__core": "npm:^7.20.5"
react-refresh: "npm:^0.14.2"
peerDependencies:
vite: ^4.2.0 || ^5.0.0
- checksum: 10/816b47c54aefce198ce2fb2b3e63b5f158ab33b04713dbec0e780a89c5126d4ea6b08544972464c43096b16e90e7f467fcf19692fad30d4f8ca5bf9a386f38b3
+ checksum: 10/a9d1eb30c968bf719a3277067211493746579aee14a7af8c0edb2cde38e8e5bbd461e62a41c3590e2c6eb04a047114eb3e97dcd591967625fbbc7aead8dfaf90
languageName: node
linkType: hard
@@ -6192,30 +6815,57 @@ __metadata:
languageName: node
linkType: hard
-"@volar/language-core@npm:2.4.4, @volar/language-core@npm:~2.4.1":
- version: 2.4.4
- resolution: "@volar/language-core@npm:2.4.4"
+"@volar/language-core@npm:2.3.4":
+ version: 2.3.4
+ resolution: "@volar/language-core@npm:2.3.4"
dependencies:
- "@volar/source-map": "npm:2.4.4"
- checksum: 10/f4bd77ff08ae2c2568afa72a96d585d02376b2196584c4a521e1edb748133ff702600e519032aee280b980d40f79ece2323fc332897d7f3115963012ecde4233
+ "@volar/source-map": "npm:2.3.4"
+ checksum: 10/eff3d21aecfd01d61f10808169d8fe7dcb30cafabaa369803ce9e1fb1c3b22f42a89fe742c3e75bb80386d5d372ab09b1024378d64f5537d171d8d128569f809
languageName: node
linkType: hard
-"@volar/source-map@npm:2.4.4":
- version: 2.4.4
- resolution: "@volar/source-map@npm:2.4.4"
- checksum: 10/513c6f23a1e5f59efa6914fd395243392277bd15217ff6986cd36eb965f68b26c29b7b14cc65bc9e5fe514d9ba801379e5118498b4104052764e70c7f1a96609
+"@volar/language-core@npm:2.4.0-alpha.18, @volar/language-core@npm:~2.4.0-alpha.18":
+ version: 2.4.0-alpha.18
+ resolution: "@volar/language-core@npm:2.4.0-alpha.18"
+ dependencies:
+ "@volar/source-map": "npm:2.4.0-alpha.18"
+ checksum: 10/82cb160aeccca770a937235f7bdcb2ab51dd4aa5182a16d1a30b057728111b7828bc3e22c7287d80888043a4ec5b67339ac3eaf1ce7338e8cd5efdb4a933608d
languageName: node
linkType: hard
-"@volar/typescript@npm:^2.4.4":
- version: 2.4.4
- resolution: "@volar/typescript@npm:2.4.4"
+"@volar/source-map@npm:2.3.4":
+ version: 2.3.4
+ resolution: "@volar/source-map@npm:2.3.4"
+ checksum: 10/4892024d34661e3687560077565a53759b90feea01cd98d941eb4d82a77e8928a87c791d9ff5f9734702d9180b6d0e2c39ebd2d0a557de913089b3594eecc5ba
+ languageName: node
+ linkType: hard
+
+"@volar/source-map@npm:2.4.0-alpha.18":
+ version: 2.4.0-alpha.18
+ resolution: "@volar/source-map@npm:2.4.0-alpha.18"
+ checksum: 10/7cf5540fffc86a2528222caa87accfe4f8e18f331b1a72b9608a557f17014bf6b3d7a09a3157502e7515fd55ac448b0535e067e0127f3bfefb711003efb2fad3
+ languageName: node
+ linkType: hard
+
+"@volar/typescript@npm:^2.3.4":
+ version: 2.3.4
+ resolution: "@volar/typescript@npm:2.3.4"
+ dependencies:
+ "@volar/language-core": "npm:2.3.4"
+ path-browserify: "npm:^1.0.1"
+ vscode-uri: "npm:^3.0.8"
+ checksum: 10/6bdf2295cb0a9ff3ab5d8d00825765171e9d3e738c540001401b83ccf07edfe50df8eec248b55cade773cec9c0108e6bad5663b949f3cfed8e109d0bb9204809
+ languageName: node
+ linkType: hard
+
+"@volar/typescript@npm:~2.4.0-alpha.18":
+ version: 2.4.0-alpha.18
+ resolution: "@volar/typescript@npm:2.4.0-alpha.18"
dependencies:
- "@volar/language-core": "npm:2.4.4"
+ "@volar/language-core": "npm:2.4.0-alpha.18"
path-browserify: "npm:^1.0.1"
vscode-uri: "npm:^3.0.8"
- checksum: 10/c04ac64bff10cb79327f7b4157cc2e6e94147d673043bd273184afe2f01a6ded0181bc1207c32ac97c4da270e245da629baf121d7ba275194c42aa2d2ad4c64b
+ checksum: 10/860dce51f5f9442ef4a6ff34840a3303ce07adcc1ec080f113ab62b1284d765dfd587cee5af500c2960b73d196e2d3e58329e760b1a6fb45658fb0e950d37f13
languageName: node
linkType: hard
@@ -6252,11 +6902,11 @@ __metadata:
languageName: node
linkType: hard
-"@vue/language-core@npm:2.1.6":
- version: 2.1.6
- resolution: "@vue/language-core@npm:2.1.6"
+"@vue/language-core@npm:2.0.29":
+ version: 2.0.29
+ resolution: "@vue/language-core@npm:2.0.29"
dependencies:
- "@volar/language-core": "npm:~2.4.1"
+ "@volar/language-core": "npm:~2.4.0-alpha.18"
"@vue/compiler-dom": "npm:^3.4.0"
"@vue/compiler-vue2": "npm:^2.7.16"
"@vue/shared": "npm:^3.4.0"
@@ -6269,7 +6919,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 10/640d4af0031975620cd3a8050bb4b0f4ed333f241ded195e3bf8c4e571c720b4e3bec3947caf2b10e4e2de19deb7621982d15439de3732d510cd43e325c74a50
+ checksum: 10/60859b53f8df2f8da336c126750c4f96ffa1c3da050181dc1e8bb80b40d482fa43194e7f2d255e31f2ebd842e11b57f89789b57a8bd9cc79f3b584eb2e0fe251
languageName: node
linkType: hard
@@ -6380,7 +7030,7 @@ __metadata:
languageName: node
linkType: hard
-"acorn@npm:^8.1.0, acorn@npm:^8.11.0, acorn@npm:^8.11.3, acorn@npm:^8.4.1, acorn@npm:^8.8.1":
+"acorn@npm:^8.1.0, acorn@npm:^8.11.0, acorn@npm:^8.11.3, acorn@npm:^8.4.1, acorn@npm:^8.8.1, acorn@npm:^8.9.0":
version: 8.12.0
resolution: "acorn@npm:8.12.0"
bin:
@@ -6523,12 +7173,10 @@ __metadata:
languageName: node
linkType: hard
-"ansi-escapes@npm:^7.0.0":
- version: 7.0.0
- resolution: "ansi-escapes@npm:7.0.0"
- dependencies:
- environment: "npm:^1.0.0"
- checksum: 10/2d0e2345087bd7ae6bf122b9cc05ee35560d40dcc061146edcdc02bc2d7c7c50143cd12a22e69a0b5c0f62b948b7bc9a4539ee888b80f5bd33cdfd82d01a70ab
+"ansi-escapes@npm:^6.2.0":
+ version: 6.2.1
+ resolution: "ansi-escapes@npm:6.2.1"
+ checksum: 10/3b064937dc8a0645ed8094bc8b09483ee718f3aa3139746280e6c2ea80e28c0a3ce66973d0f33e88e60021abbf67e5f877deabfc810e75edf8a19dfa128850be
languageName: node
linkType: hard
@@ -6588,7 +7236,7 @@ __metadata:
languageName: node
linkType: hard
-"aproba@npm:^2.0.0":
+"aproba@npm:^1.0.3 || ^2.0.0, aproba@npm:^2.0.0":
version: 2.0.0
resolution: "aproba@npm:2.0.0"
checksum: 10/c2b9a631298e8d6f3797547e866db642f68493808f5b37cd61da778d5f6ada890d16f668285f7d60bd4fc3b03889bd590ffe62cf81b700e9bb353431238a0a7b
@@ -6602,6 +7250,13 @@ __metadata:
languageName: node
linkType: hard
+"are-we-there-yet@npm:^4.0.0":
+ version: 4.0.2
+ resolution: "are-we-there-yet@npm:4.0.2"
+ checksum: 10/86feb4e8384b0820adaf7693bd02f602d001b0e5f051744dc2d05b30b74f9bd3e1e6f1a0c70fdadeddd837b8e5f8f77569a1a286078fb39b32a0a8f3724660d7
+ languageName: node
+ linkType: hard
+
"arg@npm:^4.1.0":
version: 4.1.3
resolution: "arg@npm:4.1.3"
@@ -6674,7 +7329,7 @@ __metadata:
languageName: node
linkType: hard
-"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8":
+"array-includes@npm:^3.1.6, array-includes@npm:^3.1.7, array-includes@npm:^3.1.8":
version: 3.1.8
resolution: "array-includes@npm:3.1.8"
dependencies:
@@ -6709,7 +7364,21 @@ __metadata:
languageName: node
linkType: hard
-"array.prototype.flat@npm:^1.3.1":
+"array.prototype.findlastindex@npm:^1.2.3":
+ version: 1.2.5
+ resolution: "array.prototype.findlastindex@npm:1.2.5"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.0.0"
+ es-shim-unscopables: "npm:^1.0.2"
+ checksum: 10/7c5c821f357cd53ab6cc305de8086430dd8d7a2485db87b13f843e868055e9582b1fd338f02338f67fc3a1603ceaf9610dd2a470b0b506f9d18934780f95b246
+ languageName: node
+ linkType: hard
+
+"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.2":
version: 1.3.2
resolution: "array.prototype.flat@npm:1.3.2"
dependencies:
@@ -6936,15 +7605,15 @@ __metadata:
languageName: node
linkType: hard
-"babel-plugin-polyfill-corejs3@npm:^0.10.6":
- version: 0.10.6
- resolution: "babel-plugin-polyfill-corejs3@npm:0.10.6"
+"babel-plugin-polyfill-corejs3@npm:^0.10.4":
+ version: 0.10.4
+ resolution: "babel-plugin-polyfill-corejs3@npm:0.10.4"
dependencies:
- "@babel/helper-define-polyfill-provider": "npm:^0.6.2"
- core-js-compat: "npm:^3.38.0"
+ "@babel/helper-define-polyfill-provider": "npm:^0.6.1"
+ core-js-compat: "npm:^3.36.1"
peerDependencies:
"@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
- checksum: 10/360ac9054a57a18c540059dc627ad5d84d15f79790cb3d84d19a02eec7188c67d08a07db789c3822d6f5df22d918e296d1f27c4055fec2e287d328f09ea8a78a
+ checksum: 10/a69ed5a95bb55e9b7ea37307d56113f7e24054d479c15de6d50fa61388b5334bed1f9b6414cde6c575fa910a4de4d1ab4f2d22720967d57c4fec9d1b8f61b355
languageName: node
linkType: hard
@@ -7023,6 +7692,13 @@ __metadata:
languageName: node
linkType: hard
+"before-after-hook@npm:^2.2.0":
+ version: 2.2.3
+ resolution: "before-after-hook@npm:2.2.3"
+ checksum: 10/e676f769dbc4abcf4b3317db2fd2badb4a92c0710e0a7da12cf14b59c3482d4febf835ad7de7874499060fd4e13adf0191628e504728b3c5bb4ec7a878c09940
+ languageName: node
+ linkType: hard
+
"before-after-hook@npm:^3.0.2":
version: 3.0.2
resolution: "before-after-hook@npm:3.0.2"
@@ -7030,18 +7706,6 @@ __metadata:
languageName: node
linkType: hard
-"bin-links@npm:^4.0.4":
- version: 4.0.4
- resolution: "bin-links@npm:4.0.4"
- dependencies:
- cmd-shim: "npm:^6.0.0"
- npm-normalize-package-bin: "npm:^3.0.0"
- read-cmd-shim: "npm:^4.0.0"
- write-file-atomic: "npm:^5.0.0"
- checksum: 10/58d62143aacdbb783b076e9bdd970d8470f2750e1076d6fd1ae559fa532c4647478dd2550a911ba22d4c9e6339881451046e2fbc4b8958f4bf3bf8e5144d1e4d
- languageName: node
- linkType: hard
-
"binary-extensions@npm:^2.0.0":
version: 2.3.0
resolution: "binary-extensions@npm:2.3.0"
@@ -7129,7 +7793,7 @@ __metadata:
languageName: node
linkType: hard
-"browserslist@npm:^4.22.2":
+"browserslist@npm:^4.22.2, browserslist@npm:^4.23.0":
version: 4.23.1
resolution: "browserslist@npm:4.23.1"
dependencies:
@@ -7143,7 +7807,7 @@ __metadata:
languageName: node
linkType: hard
-"browserslist@npm:^4.23.1, browserslist@npm:^4.23.3":
+"browserslist@npm:^4.23.1":
version: 4.23.3
resolution: "browserslist@npm:4.23.3"
dependencies:
@@ -7197,10 +7861,10 @@ __metadata:
languageName: node
linkType: hard
-"byte-size@npm:^9.0.0":
- version: 9.0.0
- resolution: "byte-size@npm:9.0.0"
- checksum: 10/10a2ce3433e83526d6151055aa82e414e7b15e20a9714314a17a11313b9029a4f7b0acda441d3ad8f61f1592b4ffc1649ae30a0faeb3f5561ee9995ba7de0c8e
+"byte-size@npm:^8.1.1":
+ version: 8.1.1
+ resolution: "byte-size@npm:8.1.1"
+ checksum: 10/eacd83b5f39b4b35115160201553150c3c085473ddb1e788d0f4ee22a2f3461470de5732eef8d7874efbbd883b7ae1277190b579128060e616d606ff419fe1e0
languageName: node
linkType: hard
@@ -7231,26 +7895,6 @@ __metadata:
languageName: node
linkType: hard
-"cacache@npm:^18.0.3":
- version: 18.0.4
- resolution: "cacache@npm:18.0.4"
- dependencies:
- "@npmcli/fs": "npm:^3.1.0"
- fs-minipass: "npm:^3.0.0"
- glob: "npm:^10.2.2"
- lru-cache: "npm:^10.0.1"
- minipass: "npm:^7.0.3"
- minipass-collect: "npm:^2.0.1"
- minipass-flush: "npm:^1.0.5"
- minipass-pipeline: "npm:^1.2.4"
- p-map: "npm:^4.0.0"
- ssri: "npm:^10.0.0"
- tar: "npm:^6.1.11"
- unique-filename: "npm:^3.0.0"
- checksum: 10/ca2f7b2d3003f84d362da9580b5561058ccaecd46cba661cbcff0375c90734b610520d46b472a339fd032d91597ad6ed12dde8af81571197f3c9772b5d35b104
- languageName: node
- linkType: hard
-
"cachedir@npm:^2.3.0":
version: 2.4.0
resolution: "cachedir@npm:2.4.0"
@@ -7359,7 +8003,7 @@ __metadata:
languageName: node
linkType: hard
-"chalk@npm:~5.3.0":
+"chalk@npm:^5.3.0, chalk@npm:~5.3.0":
version: 5.3.0
resolution: "chalk@npm:5.3.0"
checksum: 10/6373caaab21bd64c405bfc4bd9672b145647fc9482657b5ea1d549b3b2765054e9d3d928870cdf764fb4aad67555f5061538ff247b8310f110c5c888d92397ea
@@ -7373,6 +8017,13 @@ __metadata:
languageName: node
linkType: hard
+"chardet@npm:^0.7.0":
+ version: 0.7.0
+ resolution: "chardet@npm:0.7.0"
+ checksum: 10/b0ec668fba5eeec575ed2559a0917ba41a6481f49063c8445400e476754e0957ee09e44dc032310f526182b8f1bf25e9d4ed371f74050af7be1383e06bc44952
+ languageName: node
+ linkType: hard
+
"check-error@npm:^1.0.3":
version: 1.0.3
resolution: "check-error@npm:1.0.3"
@@ -7389,6 +8040,20 @@ __metadata:
languageName: node
linkType: hard
+"chevrotain@npm:10.5.0":
+ version: 10.5.0
+ resolution: "chevrotain@npm:10.5.0"
+ dependencies:
+ "@chevrotain/cst-dts-gen": "npm:10.5.0"
+ "@chevrotain/gast": "npm:10.5.0"
+ "@chevrotain/types": "npm:10.5.0"
+ "@chevrotain/utils": "npm:10.5.0"
+ lodash: "npm:4.17.21"
+ regexp-to-ast: "npm:0.5.0"
+ checksum: 10/f39738bf4429736bc68130548c4fd00846b5ef2b057cfab0e757abae0568519271040f403f60aeb2a4aee826b64cd2c026b6bf5ae746fcf632b458b10731568f
+ languageName: node
+ linkType: hard
+
"chokidar@npm:^3.5.3, chokidar@npm:^3.6.0":
version: 3.6.0
resolution: "chokidar@npm:3.6.0"
@@ -7416,8 +8081,8 @@ __metadata:
linkType: hard
"chromatic@npm:^11.0.0":
- version: 11.11.0
- resolution: "chromatic@npm:11.11.0"
+ version: 11.5.4
+ resolution: "chromatic@npm:11.5.4"
peerDependencies:
"@chromatic-com/cypress": ^0.*.* || ^1.0.0
"@chromatic-com/playwright": ^0.*.* || ^1.0.0
@@ -7430,7 +8095,7 @@ __metadata:
chroma: dist/bin.js
chromatic: dist/bin.js
chromatic-cli: dist/bin.js
- checksum: 10/5b1fd78af5b0c68b4a3d85f0886326c8bb790e3da7b69c8375a829cc9fa697c7d701d2ef2891109d0b9024102d402b163e5653b3f597d40d01baa74393ed4599
+ checksum: 10/7d89292a2f3470f57f342d64776c915c6a27e83b0fc422d2bb9018ea0d838b330c81373dd188b27f48eb1adb0b3aafb6a750f9720bdb29e478932c92c3978fd1
languageName: node
linkType: hard
@@ -7464,6 +8129,13 @@ __metadata:
languageName: node
linkType: hard
+"classnames@npm:^2.3.1":
+ version: 2.5.1
+ resolution: "classnames@npm:2.5.1"
+ checksum: 10/58eb394e8817021b153bb6e7d782cfb667e4ab390cb2e9dac2fc7c6b979d1cc2b2a733093955fc5c94aa79ef5c8c89f11ab77780894509be6afbb91dddd79d15
+ languageName: node
+ linkType: hard
+
"clean-stack@npm:^2.0.0":
version: 2.2.0
resolution: "clean-stack@npm:2.2.0"
@@ -7471,6 +8143,19 @@ __metadata:
languageName: node
linkType: hard
+"cli-color@npm:^2.0.4":
+ version: 2.0.4
+ resolution: "cli-color@npm:2.0.4"
+ dependencies:
+ d: "npm:^1.0.1"
+ es5-ext: "npm:^0.10.64"
+ es6-iterator: "npm:^2.0.3"
+ memoizee: "npm:^0.4.15"
+ timers-ext: "npm:^0.1.7"
+ checksum: 10/6706fbb98f5db62c47deaba7116a1e37470c936dc861b84a180b5ce1a58fbf50ae6582b30a65e4b30ddb39e0469d3bac6851a9d925ded02b7e0c1c00858ef14b
+ languageName: node
+ linkType: hard
+
"cli-cursor@npm:^3.1.0":
version: 3.1.0
resolution: "cli-cursor@npm:3.1.0"
@@ -7480,12 +8165,12 @@ __metadata:
languageName: node
linkType: hard
-"cli-cursor@npm:^5.0.0":
- version: 5.0.0
- resolution: "cli-cursor@npm:5.0.0"
+"cli-cursor@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "cli-cursor@npm:4.0.0"
dependencies:
- restore-cursor: "npm:^5.0.0"
- checksum: 10/1eb9a3f878b31addfe8d82c6d915ec2330cec8447ab1f117f4aa34f0137fbb3137ec3466e1c9a65bcb7557f6e486d343f2da57f253a2f668d691372dfa15c090
+ restore-cursor: "npm:^4.0.0"
+ checksum: 10/ab3f3ea2076e2176a1da29f9d64f72ec3efad51c0960898b56c8a17671365c26e67b735920530eaf7328d61f8bd41c27f46b9cf6e4e10fe2fa44b5e8c0e392cc
languageName: node
linkType: hard
@@ -7583,13 +8268,6 @@ __metadata:
languageName: node
linkType: hard
-"cmd-shim@npm:^6.0.0":
- version: 6.0.3
- resolution: "cmd-shim@npm:6.0.3"
- checksum: 10/791c9779cf57deae978ef24daf7e49e7fdb2070cc273aa7d691ed258a660ad3861edbc9f39daa2b6e5f72a64526b6812c04f08becc54402618b99946ccad7d71
- languageName: node
- linkType: hard
-
"co@npm:^4.6.0":
version: 4.6.0
resolution: "co@npm:4.6.0"
@@ -7676,7 +8354,7 @@ __metadata:
languageName: node
linkType: hard
-"combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6":
+"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6":
version: 1.0.8
resolution: "combined-stream@npm:1.0.8"
dependencies:
@@ -7706,13 +8384,6 @@ __metadata:
languageName: node
linkType: hard
-"common-ancestor-path@npm:^1.0.1":
- version: 1.0.1
- resolution: "common-ancestor-path@npm:1.0.1"
- checksum: 10/1d2e4186067083d8cc413f00fc2908225f04ae4e19417ded67faa6494fb313c4fcd5b28a52326d1a62b466e2b3a4325e92c31133c5fee628cdf8856b3a57c3d7
- languageName: node
- linkType: hard
-
"common-tags@npm:^1.8.0":
version: 1.8.2
resolution: "common-tags@npm:1.8.2"
@@ -7938,12 +8609,12 @@ __metadata:
languageName: node
linkType: hard
-"core-js-compat@npm:^3.37.1, core-js-compat@npm:^3.38.0":
- version: 3.38.1
- resolution: "core-js-compat@npm:3.38.1"
+"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.36.1":
+ version: 3.37.1
+ resolution: "core-js-compat@npm:3.37.1"
dependencies:
- browserslist: "npm:^4.23.3"
- checksum: 10/4e2f219354fd268895f79486461a12df96f24ed307321482fe2a43529c5a64e7c16bcba654980ba217d603444f5141d43a79058aeac77511085f065c5da72207
+ browserslist: "npm:^4.23.0"
+ checksum: 10/30c6fdbd9ff179cc53951814689b8aabec106e5de6cddfa7a7feacc96b66d415b8eebcf5ec8f7c68ef35c552fe7d39edb8b15b1ce0f27379a272295b6e937061
languageName: node
linkType: hard
@@ -8118,10 +8789,10 @@ __metadata:
linkType: hard
"cypress@npm:^13.11.0":
- version: 13.15.2
- resolution: "cypress@npm:13.15.2"
+ version: 13.11.0
+ resolution: "cypress@npm:13.11.0"
dependencies:
- "@cypress/request": "npm:^3.0.6"
+ "@cypress/request": "npm:^3.0.0"
"@cypress/xvfb": "npm:^1.2.4"
"@types/sinonjs__fake-timers": "npm:8.1.1"
"@types/sizzle": "npm:^2.3.2"
@@ -8132,7 +8803,6 @@ __metadata:
cachedir: "npm:^2.3.0"
chalk: "npm:^4.1.0"
check-more-types: "npm:^2.24.0"
- ci-info: "npm:^4.0.0"
cli-cursor: "npm:^3.1.0"
cli-table3: "npm:~0.6.1"
commander: "npm:^6.2.1"
@@ -8147,6 +8817,7 @@ __metadata:
figures: "npm:^3.2.0"
fs-extra: "npm:^9.1.0"
getos: "npm:^3.2.1"
+ is-ci: "npm:^3.0.1"
is-installed-globally: "npm:~0.4.0"
lazy-ass: "npm:^1.6.0"
listr2: "npm:^3.8.3"
@@ -8160,13 +8831,12 @@ __metadata:
request-progress: "npm:^3.0.0"
semver: "npm:^7.5.3"
supports-color: "npm:^8.1.1"
- tmp: "npm:~0.2.3"
- tree-kill: "npm:1.2.2"
+ tmp: "npm:~0.2.1"
untildify: "npm:^4.0.0"
yauzl: "npm:^2.10.0"
bin:
cypress: bin/cypress
- checksum: 10/cf5746744adf2cca916dc1c99bf7d9794599bb0ee42d78d5f656f05140f73962788104d5df88314cc0bee2540795186256c75f2d4fc3652a17d5fba1495e1b06
+ checksum: 10/3890f8db0ad91b5ff103dde4e7a8f47575bf55c3304ce3aa44776596580463fb2eead56f1b8ae29ebb2592879ffbccca158ae67a7db33dabdeb818c619bb5c2d
languageName: node
linkType: hard
@@ -8179,6 +8849,15 @@ __metadata:
languageName: node
linkType: hard
+"d3-array@npm:3.2.1":
+ version: 3.2.1
+ resolution: "d3-array@npm:3.2.1"
+ dependencies:
+ internmap: "npm:1 - 2"
+ checksum: 10/5522a1e193f87a6a2e1ee784065b0e9c11b3602a388a1060aac91a6a0374fa2234436bc253312ca7b1517b91b2eea2ea9191b1e37e76c8b2bf4d422f41990dec
+ languageName: node
+ linkType: hard
+
"d3-axis@npm:3":
version: 3.0.0
resolution: "d3-axis@npm:3.0.0"
@@ -8208,7 +8887,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-color@npm:1 - 3, d3-color@npm:3":
+"d3-color@npm:1 - 3, d3-color@npm:3, d3-color@npm:3.1.0":
version: 3.1.0
resolution: "d3-color@npm:3.1.0"
checksum: 10/536ba05bfd9f4fcd6fa289b5974f5c846b21d186875684637e22bf6855e6aba93e24a2eb3712985c6af3f502fbbfa03708edb72f58142f626241a8a17258e545
@@ -8233,6 +8912,15 @@ __metadata:
languageName: node
linkType: hard
+"d3-delaunay@npm:6.0.2":
+ version: 6.0.2
+ resolution: "d3-delaunay@npm:6.0.2"
+ dependencies:
+ delaunator: "npm:5"
+ checksum: 10/66b25c023eaf3335f1cca2d375954573e583d907aff9d1212cef714bbccb6c84d860ed0bcebaf2bd1fba88c1f0827a3515dd1d43127732a029a83c30ffb4d9f9
+ languageName: node
+ linkType: hard
+
"d3-dispatch@npm:1 - 3, d3-dispatch@npm:3":
version: 3.0.1
resolution: "d3-dispatch@npm:3.0.1"
@@ -8315,7 +9003,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-format@npm:1 - 3, d3-format@npm:3":
+"d3-format@npm:1 - 3, d3-format@npm:3, d3-format@npm:3.1.0":
version: 3.1.0
resolution: "d3-format@npm:3.1.0"
checksum: 10/a0fe23d2575f738027a3db0ce57160e5a473ccf24808c1ed46d45ef4f3211076b34a18b585547d34e365e78dcc26dd4ab15c069731fc4b1c07a26bfced09ea31
@@ -8331,6 +9019,15 @@ __metadata:
languageName: node
linkType: hard
+"d3-geo@npm:3.1.0":
+ version: 3.1.0
+ resolution: "d3-geo@npm:3.1.0"
+ dependencies:
+ d3-array: "npm:2.5.0 - 3"
+ checksum: 10/d214c2951c327501699b49f73fcbf417284468f41b31cd8f34c1975137a2544e4bb8080f35fa216659dba91c60f35b7bc857cd6b8297cf4f0fd37343269d9f8a
+ languageName: node
+ linkType: hard
+
"d3-hierarchy@npm:3":
version: 3.1.2
resolution: "d3-hierarchy@npm:3.1.2"
@@ -8338,7 +9035,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3":
+"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3, d3-interpolate@npm:3.0.1":
version: 3.0.1
resolution: "d3-interpolate@npm:3.0.1"
dependencies:
@@ -8347,13 +9044,6 @@ __metadata:
languageName: node
linkType: hard
-"d3-path@npm:1":
- version: 1.0.9
- resolution: "d3-path@npm:1.0.9"
- checksum: 10/6ce1747837ea2a449d9ea32e169a382978ab09a4805eb408feb6bbc12cb5f5f6ce29aefc252dd9a815d420f4813d672f75578b78b3bbaf7811f54d8c7f93fd11
- languageName: node
- linkType: hard
-
"d3-path@npm:1 - 3, d3-path@npm:3, d3-path@npm:^3.1.0":
version: 3.1.0
resolution: "d3-path@npm:3.1.0"
@@ -8361,6 +9051,13 @@ __metadata:
languageName: node
linkType: hard
+"d3-path@npm:1, d3-path@npm:^1.0.5":
+ version: 1.0.9
+ resolution: "d3-path@npm:1.0.9"
+ checksum: 10/6ce1747837ea2a449d9ea32e169a382978ab09a4805eb408feb6bbc12cb5f5f6ce29aefc252dd9a815d420f4813d672f75578b78b3bbaf7811f54d8c7f93fd11
+ languageName: node
+ linkType: hard
+
"d3-polygon@npm:3":
version: 3.0.1
resolution: "d3-polygon@npm:3.0.1"
@@ -8392,7 +9089,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-scale@npm:4":
+"d3-scale@npm:4, d3-scale@npm:4.0.2":
version: 4.0.2
resolution: "d3-scale@npm:4.0.2"
dependencies:
@@ -8428,7 +9125,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-shape@npm:^1.3.5":
+"d3-shape@npm:^1.0.6, d3-shape@npm:^1.2.0, d3-shape@npm:^1.3.5":
version: 1.3.7
resolution: "d3-shape@npm:1.3.7"
dependencies:
@@ -8437,7 +9134,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-time-format@npm:2 - 4, d3-time-format@npm:4":
+"d3-time-format@npm:2 - 4, d3-time-format@npm:4, d3-time-format@npm:4.1.0":
version: 4.1.0
resolution: "d3-time-format@npm:4.1.0"
dependencies:
@@ -8446,7 +9143,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3":
+"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3, d3-time@npm:3.1.0":
version: 3.1.0
resolution: "d3-time@npm:3.1.0"
dependencies:
@@ -8535,6 +9232,16 @@ __metadata:
languageName: node
linkType: hard
+"d@npm:1, d@npm:^1.0.1, d@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "d@npm:1.0.2"
+ dependencies:
+ es5-ext: "npm:^0.10.64"
+ type: "npm:^2.7.2"
+ checksum: 10/a3f45ef964622f683f6a1cb9b8dcbd75ce490cd2f4ac9794099db3d8f0e2814d412d84cd3fe522e58feb1f273117bb480f29c5381f6225f0abca82517caaa77a
+ languageName: node
+ linkType: hard
+
"dargs@npm:^8.0.0":
version: 8.1.0
resolution: "dargs@npm:8.1.0"
@@ -8625,7 +9332,7 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5":
+"debug@npm:4, debug@npm:4.3.5, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:~4.3.4":
version: 4.3.5
resolution: "debug@npm:4.3.5"
dependencies:
@@ -8637,18 +9344,6 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:4.3.7":
- version: 4.3.7
- resolution: "debug@npm:4.3.7"
- dependencies:
- ms: "npm:^2.1.3"
- peerDependenciesMeta:
- supports-color:
- optional: true
- checksum: 10/71168908b9a78227ab29d5d25fe03c5867750e31ce24bf2c44a86efc5af041758bb56569b0a3d48a9b5344c00a24a777e6f4100ed6dfd9534a42c1dde285125a
- languageName: node
- linkType: hard
-
"debug@npm:^3.1.0, debug@npm:^3.2.7":
version: 3.2.7
resolution: "debug@npm:3.2.7"
@@ -8658,7 +9353,7 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:^4.3.6, debug@npm:~4.3.6":
+"debug@npm:^4.3.6":
version: 4.3.6
resolution: "debug@npm:4.3.6"
dependencies:
@@ -8731,6 +9426,13 @@ __metadata:
languageName: node
linkType: hard
+"deepmerge-ts@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "deepmerge-ts@npm:5.1.0"
+ checksum: 10/0f615ccfb27b93a286abc315d7d1ec171f1befe9c511c2799ca7184c11fc6a6f29f5368d446c6885338de0d95cf6cb66a5ff4c55141a1265012730bd69408cf9
+ languageName: node
+ linkType: hard
+
"deepmerge-ts@npm:^7.1.0":
version: 7.1.0
resolution: "deepmerge-ts@npm:7.1.0"
@@ -8806,6 +9508,13 @@ __metadata:
languageName: node
linkType: hard
+"deprecation@npm:^2.0.0":
+ version: 2.3.1
+ resolution: "deprecation@npm:2.3.1"
+ checksum: 10/f56a05e182c2c195071385455956b0c4106fe14e36245b00c689ceef8e8ab639235176a96977ba7c74afb173317fac2e0ec6ec7a1c6d1e6eaa401c586c714132
+ languageName: node
+ linkType: hard
+
"dequal@npm:^2.0.2, dequal@npm:^2.0.3":
version: 2.0.3
resolution: "dequal@npm:2.0.3"
@@ -8827,7 +9536,7 @@ __metadata:
languageName: node
linkType: hard
-"detect-indent@npm:^7.0.1":
+"detect-indent@npm:^7.0.0, detect-indent@npm:^7.0.1":
version: 7.0.1
resolution: "detect-indent@npm:7.0.1"
checksum: 10/cbf3f0b1c3c881934ca94428e1179b26ab2a587e0d719031d37a67fb506d49d067de54ff057cb1e772e75975fed5155c01cd4518306fee60988b1486e3fc7768
@@ -9073,13 +9782,6 @@ __metadata:
languageName: node
linkType: hard
-"environment@npm:^1.0.0":
- version: 1.1.0
- resolution: "environment@npm:1.1.0"
- checksum: 10/dd3c1b9825e7f71f1e72b03c2344799ac73f2e9ef81b78ea8b373e55db021786c6b9f3858ea43a436a2c4611052670ec0afe85bc029c384cc71165feee2f4ba6
- languageName: node
- linkType: hard
-
"err-code@npm:^2.0.2":
version: 2.0.3
resolution: "err-code@npm:2.0.3"
@@ -9252,6 +9954,51 @@ __metadata:
languageName: node
linkType: hard
+"es5-ext@npm:^0.10.35, es5-ext@npm:^0.10.46, es5-ext@npm:^0.10.62, es5-ext@npm:^0.10.64, es5-ext@npm:~0.10.14, es5-ext@npm:~0.10.2":
+ version: 0.10.64
+ resolution: "es5-ext@npm:0.10.64"
+ dependencies:
+ es6-iterator: "npm:^2.0.3"
+ es6-symbol: "npm:^3.1.3"
+ esniff: "npm:^2.0.1"
+ next-tick: "npm:^1.1.0"
+ checksum: 10/0c5d8657708b1695ddc4b06f4e0b9fbdda4d2fe46d037b6bedb49a7d1931e542ec9eecf4824d59e1d357e93229deab014bb4b86485db2d41b1d68e54439689ce
+ languageName: node
+ linkType: hard
+
+"es6-iterator@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "es6-iterator@npm:2.0.3"
+ dependencies:
+ d: "npm:1"
+ es5-ext: "npm:^0.10.35"
+ es6-symbol: "npm:^3.1.1"
+ checksum: 10/dbadecf3d0e467692815c2b438dfa99e5a97cbbecf4a58720adcb467a04220e0e36282399ba297911fd472c50ae4158fffba7ed0b7d4273fe322b69d03f9e3a5
+ languageName: node
+ linkType: hard
+
+"es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3":
+ version: 3.1.4
+ resolution: "es6-symbol@npm:3.1.4"
+ dependencies:
+ d: "npm:^1.0.2"
+ ext: "npm:^1.7.0"
+ checksum: 10/3743119fe61f89e2f049a6ce52bd82fab5f65d13e2faa72453b73f95c15292c3cb9bdf3747940d504517e675e45fd375554c6b5d35d2bcbefd35f5489ecba546
+ languageName: node
+ linkType: hard
+
+"es6-weak-map@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "es6-weak-map@npm:2.0.3"
+ dependencies:
+ d: "npm:1"
+ es5-ext: "npm:^0.10.46"
+ es6-iterator: "npm:^2.0.3"
+ es6-symbol: "npm:^3.1.1"
+ checksum: 10/5958a321cf8dfadc82b79eeaa57dc855893a4afd062b4ef5c9ded0010d3932099311272965c3d3fdd3c85df1d7236013a570e704fa6c1f159bbf979c203dd3a3
+ languageName: node
+ linkType: hard
+
"esbuild-register@npm:^3.5.0":
version: 3.5.0
resolution: "esbuild-register@npm:3.5.0"
@@ -9396,7 +10143,7 @@ __metadata:
languageName: node
linkType: hard
-"eslint-config-prettier@npm:^9.1.0":
+"eslint-config-prettier@npm:^9.0.0, eslint-config-prettier@npm:^9.1.0":
version: 9.1.0
resolution: "eslint-config-prettier@npm:9.1.0"
peerDependencies:
@@ -9407,6 +10154,94 @@ __metadata:
languageName: node
linkType: hard
+"eslint-import-resolver-node@npm:^0.3.9":
+ version: 0.3.9
+ resolution: "eslint-import-resolver-node@npm:0.3.9"
+ dependencies:
+ debug: "npm:^3.2.7"
+ is-core-module: "npm:^2.13.0"
+ resolve: "npm:^1.22.4"
+ checksum: 10/d52e08e1d96cf630957272e4f2644dcfb531e49dcfd1edd2e07e43369eb2ec7a7d4423d417beee613201206ff2efa4eb9a582b5825ee28802fc7c71fcd53ca83
+ languageName: node
+ linkType: hard
+
+"eslint-module-utils@npm:^2.8.0":
+ version: 2.8.1
+ resolution: "eslint-module-utils@npm:2.8.1"
+ dependencies:
+ debug: "npm:^3.2.7"
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ checksum: 10/3e7892c0a984c963632da56b30ccf8254c29b535467138f91086c2ecdb2ebd10e2be61b54e553f30e5abf1d14d47a7baa0dac890e3a658fd3cd07dca63afbe6d
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-import@npm:^2.26.0":
+ version: 2.29.1
+ resolution: "eslint-plugin-import@npm:2.29.1"
+ dependencies:
+ array-includes: "npm:^3.1.7"
+ array.prototype.findlastindex: "npm:^1.2.3"
+ array.prototype.flat: "npm:^1.3.2"
+ array.prototype.flatmap: "npm:^1.3.2"
+ debug: "npm:^3.2.7"
+ doctrine: "npm:^2.1.0"
+ eslint-import-resolver-node: "npm:^0.3.9"
+ eslint-module-utils: "npm:^2.8.0"
+ hasown: "npm:^2.0.0"
+ is-core-module: "npm:^2.13.1"
+ is-glob: "npm:^4.0.3"
+ minimatch: "npm:^3.1.2"
+ object.fromentries: "npm:^2.0.7"
+ object.groupby: "npm:^1.0.1"
+ object.values: "npm:^1.1.7"
+ semver: "npm:^6.3.1"
+ tsconfig-paths: "npm:^3.15.0"
+ peerDependencies:
+ eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+ checksum: 10/5865f05c38552145423c535326ec9a7113ab2305c7614c8b896ff905cfabc859c8805cac21e979c9f6f742afa333e6f62f812eabf891a7e8f5f0b853a32593c1
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-jest@npm:^27.2.1":
+ version: 27.9.0
+ resolution: "eslint-plugin-jest@npm:27.9.0"
+ dependencies:
+ "@typescript-eslint/utils": "npm:^5.10.0"
+ peerDependencies:
+ "@typescript-eslint/eslint-plugin": ^5.0.0 || ^6.0.0 || ^7.0.0
+ eslint: ^7.0.0 || ^8.0.0
+ jest: "*"
+ peerDependenciesMeta:
+ "@typescript-eslint/eslint-plugin":
+ optional: true
+ jest:
+ optional: true
+ checksum: 10/bca54347280c06c56516faea76042134dd74355c2de6c23361ba0e8736ecc01c62b144eea7eda7570ea4f4ee511c583bb8dab00d7153a1bd1740eb77b0038fd4
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-prettier@npm:^5.0.0":
+ version: 5.1.3
+ resolution: "eslint-plugin-prettier@npm:5.1.3"
+ dependencies:
+ prettier-linter-helpers: "npm:^1.0.0"
+ synckit: "npm:^0.8.6"
+ peerDependencies:
+ "@types/eslint": ">=8.0.0"
+ eslint: ">=8.0.0"
+ eslint-config-prettier: "*"
+ prettier: ">=3.0.0"
+ peerDependenciesMeta:
+ "@types/eslint":
+ optional: true
+ eslint-config-prettier:
+ optional: true
+ checksum: 10/4f26a30444adc61ed692cdb5a9f7e8d9f5794f0917151051e66755ce032a08c3cc72c8b5d56101412e90f6d77035bd8194ea8731e9c16aacdd5ae345a8dae188
+ languageName: node
+ linkType: hard
+
"eslint-plugin-prettier@npm:^5.2.1":
version: 5.2.1
resolution: "eslint-plugin-prettier@npm:5.2.1"
@@ -9464,6 +10299,26 @@ __metadata:
languageName: node
linkType: hard
+"eslint-scope@npm:^5.1.1":
+ version: 5.1.1
+ resolution: "eslint-scope@npm:5.1.1"
+ dependencies:
+ esrecurse: "npm:^4.3.0"
+ estraverse: "npm:^4.1.1"
+ checksum: 10/c541ef384c92eb5c999b7d3443d80195fcafb3da335500946f6db76539b87d5826c8f2e1d23bf6afc3154ba8cd7c8e566f8dc00f1eea25fdf3afc8fb9c87b238
+ languageName: node
+ linkType: hard
+
+"eslint-scope@npm:^7.2.2":
+ version: 7.2.2
+ resolution: "eslint-scope@npm:7.2.2"
+ dependencies:
+ esrecurse: "npm:^4.3.0"
+ estraverse: "npm:^5.2.0"
+ checksum: 10/5c660fb905d5883ad018a6fea2b49f3cb5b1cbf2cd4bd08e98646e9864f9bc2c74c0839bed2d292e90a4a328833accc197c8f0baed89cbe8d605d6f918465491
+ languageName: node
+ linkType: hard
+
"eslint-scope@npm:^8.0.2":
version: 8.0.2
resolution: "eslint-scope@npm:8.0.2"
@@ -9474,7 +10329,7 @@ __metadata:
languageName: node
linkType: hard
-"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.3":
+"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3":
version: 3.4.3
resolution: "eslint-visitor-keys@npm:3.4.3"
checksum: 10/3f357c554a9ea794b094a09bd4187e5eacd1bc0d0653c3adeb87962c548e6a1ab8f982b86963ae1337f5d976004146536dcee5d0e2806665b193fbfbf1a9231b
@@ -9488,6 +10343,54 @@ __metadata:
languageName: node
linkType: hard
+"eslint@npm:^8.45.0":
+ version: 8.57.0
+ resolution: "eslint@npm:8.57.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.2.0"
+ "@eslint-community/regexpp": "npm:^4.6.1"
+ "@eslint/eslintrc": "npm:^2.1.4"
+ "@eslint/js": "npm:8.57.0"
+ "@humanwhocodes/config-array": "npm:^0.11.14"
+ "@humanwhocodes/module-importer": "npm:^1.0.1"
+ "@nodelib/fs.walk": "npm:^1.2.8"
+ "@ungap/structured-clone": "npm:^1.2.0"
+ ajv: "npm:^6.12.4"
+ chalk: "npm:^4.0.0"
+ cross-spawn: "npm:^7.0.2"
+ debug: "npm:^4.3.2"
+ doctrine: "npm:^3.0.0"
+ escape-string-regexp: "npm:^4.0.0"
+ eslint-scope: "npm:^7.2.2"
+ eslint-visitor-keys: "npm:^3.4.3"
+ espree: "npm:^9.6.1"
+ esquery: "npm:^1.4.2"
+ esutils: "npm:^2.0.2"
+ fast-deep-equal: "npm:^3.1.3"
+ file-entry-cache: "npm:^6.0.1"
+ find-up: "npm:^5.0.0"
+ glob-parent: "npm:^6.0.2"
+ globals: "npm:^13.19.0"
+ graphemer: "npm:^1.4.0"
+ ignore: "npm:^5.2.0"
+ imurmurhash: "npm:^0.1.4"
+ is-glob: "npm:^4.0.0"
+ is-path-inside: "npm:^3.0.3"
+ js-yaml: "npm:^4.1.0"
+ json-stable-stringify-without-jsonify: "npm:^1.0.1"
+ levn: "npm:^0.4.1"
+ lodash.merge: "npm:^4.6.2"
+ minimatch: "npm:^3.1.2"
+ natural-compare: "npm:^1.4.0"
+ optionator: "npm:^0.9.3"
+ strip-ansi: "npm:^6.0.1"
+ text-table: "npm:^0.2.0"
+ bin:
+ eslint: bin/eslint.js
+ checksum: 10/00496e218b23747a7a9817bf58b522276d0dc1f2e546dceb4eea49f9871574088f72f1f069a6b560ef537efa3a75261b8ef70e51ef19033da1cc4c86a755ef15
+ languageName: node
+ linkType: hard
+
"eslint@npm:^9.10.0":
version: 9.10.0
resolution: "eslint@npm:9.10.0"
@@ -9537,6 +10440,18 @@ __metadata:
languageName: node
linkType: hard
+"esniff@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "esniff@npm:2.0.1"
+ dependencies:
+ d: "npm:^1.0.1"
+ es5-ext: "npm:^0.10.62"
+ event-emitter: "npm:^0.3.5"
+ type: "npm:^2.7.2"
+ checksum: 10/f6a2abd2f8c5fe57c5fcf53e5407c278023313d0f6c3a92688e7122ab9ac233029fd424508a196ae5bc561aa1f67d23f4e2435b1a0d378030f476596129056ac
+ languageName: node
+ linkType: hard
+
"espree@npm:^10.0.1, espree@npm:^10.1.0":
version: 10.1.0
resolution: "espree@npm:10.1.0"
@@ -9548,6 +10463,17 @@ __metadata:
languageName: node
linkType: hard
+"espree@npm:^9.6.0, espree@npm:^9.6.1":
+ version: 9.6.1
+ resolution: "espree@npm:9.6.1"
+ dependencies:
+ acorn: "npm:^8.9.0"
+ acorn-jsx: "npm:^5.3.2"
+ eslint-visitor-keys: "npm:^3.4.1"
+ checksum: 10/255ab260f0d711a54096bdeda93adff0eadf02a6f9b92f02b323e83a2b7fc258797919437ad331efec3930475feb0142c5ecaaf3cdab4befebd336d47d3f3134
+ languageName: node
+ linkType: hard
+
"esprima@npm:^4.0.0, esprima@npm:^4.0.1, esprima@npm:~4.0.0":
version: 4.0.1
resolution: "esprima@npm:4.0.1"
@@ -9558,6 +10484,15 @@ __metadata:
languageName: node
linkType: hard
+"esquery@npm:^1.4.2":
+ version: 1.5.0
+ resolution: "esquery@npm:1.5.0"
+ dependencies:
+ estraverse: "npm:^5.1.0"
+ checksum: 10/e65fcdfc1e0ff5effbf50fb4f31ea20143ae5df92bb2e4953653d8d40aa4bc148e0d06117a592ce4ea53eeab1dafdfded7ea7e22a5be87e82d73757329a1b01d
+ languageName: node
+ linkType: hard
+
"esquery@npm:^1.5.0":
version: 1.6.0
resolution: "esquery@npm:1.6.0"
@@ -9576,6 +10511,13 @@ __metadata:
languageName: node
linkType: hard
+"estraverse@npm:^4.1.1":
+ version: 4.3.0
+ resolution: "estraverse@npm:4.3.0"
+ checksum: 10/3f67ad02b6dbfaddd9ea459cf2b6ef4ecff9a6082a7af9d22e445b9abc082ad9ca47e1825557b293fcdae477f4714e561123e30bb6a5b2f184fb2bad4a9497eb
+ languageName: node
+ linkType: hard
+
"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0":
version: 5.3.0
resolution: "estraverse@npm:5.3.0"
@@ -9613,6 +10555,16 @@ __metadata:
languageName: node
linkType: hard
+"event-emitter@npm:^0.3.5":
+ version: 0.3.5
+ resolution: "event-emitter@npm:0.3.5"
+ dependencies:
+ d: "npm:1"
+ es5-ext: "npm:~0.10.14"
+ checksum: 10/a7f5ea80029193f4869782d34ef7eb43baa49cd397013add1953491b24588468efbe7e3cc9eb87d53f33397e7aab690fd74c079ec440bf8b12856f6bdb6e9396
+ languageName: node
+ linkType: hard
+
"event-stream@npm:=3.3.4":
version: 3.3.4
resolution: "event-stream@npm:3.3.4"
@@ -9768,6 +10720,15 @@ __metadata:
languageName: node
linkType: hard
+"ext@npm:^1.7.0":
+ version: 1.7.0
+ resolution: "ext@npm:1.7.0"
+ dependencies:
+ type: "npm:^2.7.2"
+ checksum: 10/666a135980b002df0e75c8ac6c389140cdc59ac953db62770479ee2856d58ce69d2f845e5f2586716350b725400f6945e51e9159573158c39f369984c72dcd84
+ languageName: node
+ linkType: hard
+
"extend@npm:~3.0.2":
version: 3.0.2
resolution: "extend@npm:3.0.2"
@@ -9775,6 +10736,17 @@ __metadata:
languageName: node
linkType: hard
+"external-editor@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "external-editor@npm:3.1.0"
+ dependencies:
+ chardet: "npm:^0.7.0"
+ iconv-lite: "npm:^0.4.24"
+ tmp: "npm:^0.0.33"
+ checksum: 10/776dff1d64a1d28f77ff93e9e75421a81c062983fd1544279d0a32f563c0b18c52abbb211f31262e2827e48edef5c9dc8f960d06dd2d42d1654443b88568056b
+ languageName: node
+ linkType: hard
+
"extract-zip@npm:2.0.1":
version: 2.0.1
resolution: "extract-zip@npm:2.0.1"
@@ -9920,6 +10892,15 @@ __metadata:
languageName: node
linkType: hard
+"file-entry-cache@npm:^6.0.1":
+ version: 6.0.1
+ resolution: "file-entry-cache@npm:6.0.1"
+ dependencies:
+ flat-cache: "npm:^3.0.4"
+ checksum: 10/099bb9d4ab332cb93c48b14807a6918a1da87c45dce91d4b61fd40e6505d56d0697da060cb901c729c90487067d93c9243f5da3dc9c41f0358483bfdebca736b
+ languageName: node
+ linkType: hard
+
"file-entry-cache@npm:^8.0.0":
version: 8.0.0
resolution: "file-entry-cache@npm:8.0.0"
@@ -10032,6 +11013,17 @@ __metadata:
languageName: node
linkType: hard
+"flat-cache@npm:^3.0.4":
+ version: 3.2.0
+ resolution: "flat-cache@npm:3.2.0"
+ dependencies:
+ flatted: "npm:^3.2.9"
+ keyv: "npm:^4.5.3"
+ rimraf: "npm:^3.0.2"
+ checksum: 10/02381c6ece5e9fa5b826c9bbea481d7fd77645d96e4b0b1395238124d581d10e56f17f723d897b6d133970f7a57f0fab9148cbbb67237a0a0ffe794ba60c0c70
+ languageName: node
+ linkType: hard
+
"flat-cache@npm:^4.0.0":
version: 4.0.1
resolution: "flat-cache@npm:4.0.1"
@@ -10111,7 +11103,7 @@ __metadata:
languageName: node
linkType: hard
-"form-data@npm:^4.0.0, form-data@npm:~4.0.0":
+"form-data@npm:^4.0.0":
version: 4.0.0
resolution: "form-data@npm:4.0.0"
dependencies:
@@ -10122,6 +11114,17 @@ __metadata:
languageName: node
linkType: hard
+"form-data@npm:~2.3.2":
+ version: 2.3.3
+ resolution: "form-data@npm:2.3.3"
+ dependencies:
+ asynckit: "npm:^0.4.0"
+ combined-stream: "npm:^1.0.6"
+ mime-types: "npm:^2.1.12"
+ checksum: 10/1b6f3ccbf4540e535887b42218a2431a3f6cfdea320119c2affa2a7a374ad8fdd1e60166fc865181f45d49b1684c3e90e7b2190d3fe016692957afb9cf0d0d02
+ languageName: node
+ linkType: hard
+
"formdata-polyfill@npm:^4.0.10":
version: 4.0.10
resolution: "formdata-polyfill@npm:4.0.10"
@@ -10256,6 +11259,22 @@ __metadata:
languageName: node
linkType: hard
+"gauge@npm:^5.0.0":
+ version: 5.0.2
+ resolution: "gauge@npm:5.0.2"
+ dependencies:
+ aproba: "npm:^1.0.3 || ^2.0.0"
+ color-support: "npm:^1.1.3"
+ console-control-strings: "npm:^1.1.0"
+ has-unicode: "npm:^2.0.1"
+ signal-exit: "npm:^4.0.1"
+ string-width: "npm:^4.2.3"
+ strip-ansi: "npm:^6.0.1"
+ wide-align: "npm:^1.1.5"
+ checksum: 10/7ed6930e03622e3651182d9312ea763e208e7e71bf126505a59a4424820af2715fdbc4f0655f92a092f3f1015c425094421c9d1a898dbe33cf6779d3e7e91e5c
+ languageName: node
+ linkType: hard
+
"gensync@npm:^1.0.0-beta.2":
version: 1.0.0-beta.2
resolution: "gensync@npm:1.0.0-beta.2"
@@ -10426,6 +11445,15 @@ __metadata:
languageName: node
linkType: hard
+"git-url-parse@npm:^14.0.0":
+ version: 14.0.0
+ resolution: "git-url-parse@npm:14.0.0"
+ dependencies:
+ git-up: "npm:^7.0.0"
+ checksum: 10/c19430947895676c59ce472d534c88e5d2d9f443e6b6e4deaa8ad9ad921ded6c27a996b219503775c37fbb90f4a3c02a5f106f14b61286386f9e5098dff7d634
+ languageName: node
+ linkType: hard
+
"git-url-parse@npm:^15.0.0":
version: 15.0.0
resolution: "git-url-parse@npm:15.0.0"
@@ -10471,7 +11499,7 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.12":
+"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.12, glob@npm:^10.4.1":
version: 10.4.1
resolution: "glob@npm:10.4.1"
dependencies:
@@ -10516,6 +11544,19 @@ __metadata:
languageName: node
linkType: hard
+"glob@npm:^8.0.1":
+ version: 8.1.0
+ resolution: "glob@npm:8.1.0"
+ dependencies:
+ fs.realpath: "npm:^1.0.0"
+ inflight: "npm:^1.0.4"
+ inherits: "npm:2"
+ minimatch: "npm:^5.0.1"
+ once: "npm:^1.3.0"
+ checksum: 10/9aab1c75eb087c35dbc41d1f742e51d0507aa2b14c910d96fb8287107a10a22f4bbdce26fc0a3da4c69a20f7b26d62f1640b346a4f6e6becfff47f335bb1dc5e
+ languageName: node
+ linkType: hard
+
"global-dirs@npm:^3.0.0":
version: 3.0.1
resolution: "global-dirs@npm:3.0.1"
@@ -10562,6 +11603,15 @@ __metadata:
languageName: node
linkType: hard
+"globals@npm:^13.19.0":
+ version: 13.24.0
+ resolution: "globals@npm:13.24.0"
+ dependencies:
+ type-fest: "npm:^0.20.2"
+ checksum: 10/62c5b1997d06674fc7191d3e01e324d3eda4d65ac9cc4e78329fa3b5c4fd42a0e1c8722822497a6964eee075255ce21ccf1eec2d83f92ef3f06653af4d0ee28e
+ languageName: node
+ linkType: hard
+
"globals@npm:^14.0.0":
version: 14.0.0
resolution: "globals@npm:14.0.0"
@@ -10570,9 +11620,9 @@ __metadata:
linkType: hard
"globals@npm:^15.9.0":
- version: 15.10.0
- resolution: "globals@npm:15.10.0"
- checksum: 10/d649208c62406fa71f131be643cb6d18703be5e612f8fa4da8a35bda56ce5a6a8caeb13a2f5a927e4d3324d73872e897067eb6f92ddd46a29876ffa5c4910cb8
+ version: 15.9.0
+ resolution: "globals@npm:15.9.0"
+ checksum: 10/19bca70131c5d3e0d4171deed0f8ae16adda19f18d39b67421056f1eaa160b4433c3ffc8eb69b8b19adebbbdad4834d8a0494c5fe1ae295f0f769a5c0331d794
languageName: node
linkType: hard
@@ -10795,7 +11845,7 @@ __metadata:
languageName: node
linkType: hard
-"hosted-git-info@npm:^7.0.0, hosted-git-info@npm:^7.0.2":
+"hosted-git-info@npm:^7.0.0":
version: 7.0.2
resolution: "hosted-git-info@npm:7.0.2"
dependencies:
@@ -10875,14 +11925,14 @@ __metadata:
languageName: node
linkType: hard
-"http-signature@npm:~1.4.0":
- version: 1.4.0
- resolution: "http-signature@npm:1.4.0"
+"http-signature@npm:~1.3.6":
+ version: 1.3.6
+ resolution: "http-signature@npm:1.3.6"
dependencies:
assert-plus: "npm:^1.0.0"
jsprim: "npm:^2.0.2"
- sshpk: "npm:^1.18.0"
- checksum: 10/f9f5eed4ac5db5e1ec6d00652680c7d8b76d553560017e34505c0c22c37abb2e6d22b9268ed4a8542aa9746852a2d64850531091e443393c9c8e0f4fd4174455
+ sshpk: "npm:^1.14.1"
+ checksum: 10/5f08e0c82174999da97114facb0d0d47e268d60b6fc10f92cb87b99d5ccccd36f79b9508c29dda0b4f4e3a1b2f7bcaf847e68ecd5da2f1fc465fcd1d054b7884
languageName: node
linkType: hard
@@ -10928,15 +11978,15 @@ __metadata:
linkType: hard
"husky@npm:^9.0.0":
- version: 9.1.6
- resolution: "husky@npm:9.1.6"
+ version: 9.0.11
+ resolution: "husky@npm:9.0.11"
bin:
- husky: bin.js
- checksum: 10/421ccd8850378231aaefd70dbe9e4f1549b84ffe3a6897f93a202242bbc04e48bd498169aef43849411105d9fcf7c192b757d42661e28d06b934a609a4eb8771
+ husky: bin.mjs
+ checksum: 10/8a9b7cb9dc8494b470b3b47b386e65d579608c6206da80d3cc8b71d10e37947264af3dfe00092368dad9673b51d2a5ee87afb4b2291e77ba9e7ec1ac36e56cd1
languageName: node
linkType: hard
-"iconv-lite@npm:0.4.24":
+"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24":
version: 0.4.24
resolution: "iconv-lite@npm:0.4.24"
dependencies:
@@ -10961,6 +12011,15 @@ __metadata:
languageName: node
linkType: hard
+"ignore-walk@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "ignore-walk@npm:5.0.1"
+ dependencies:
+ minimatch: "npm:^5.0.1"
+ checksum: 10/a88b3fbda155496363fb3db66c7c7b85cf04d614fb51146f0aa5fc6b35c65370c57f9e6c550cd6048651fc378985b7a2bb9015c9fcb3e0dc798fc0728746703c
+ languageName: node
+ linkType: hard
+
"ignore-walk@npm:^6.0.4":
version: 6.0.5
resolution: "ignore-walk@npm:6.0.5"
@@ -10977,17 +12036,10 @@ __metadata:
languageName: node
linkType: hard
-"ignore@npm:^5.3.2":
- version: 5.3.2
- resolution: "ignore@npm:5.3.2"
- checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98
- languageName: node
- linkType: hard
-
"immutable@npm:^4.0.0":
- version: 4.3.7
- resolution: "immutable@npm:4.3.7"
- checksum: 10/37d963c5050f03ae5f3714ba7a43d469aa482051087f4c65d673d1501c309ea231d87480c792e19fa85e2eaf965f76af5d0aa92726505f3cfe4af91619dfb80b
+ version: 4.3.6
+ resolution: "immutable@npm:4.3.6"
+ checksum: 10/59fedb67f26e265035616b27e33ef90b53b434cf76fb09212ec2d6ae32ee8d2fe2641e6dc32dbc78498c521fbf5f72c6740d39affba63a0a36a3884272371857
languageName: node
linkType: hard
@@ -11008,7 +12060,7 @@ __metadata:
languageName: node
linkType: hard
-"import-local@npm:^3.0.2":
+"import-local@npm:^3.0.2, import-local@npm:^3.1.0":
version: 3.1.0
resolution: "import-local@npm:3.1.0"
dependencies:
@@ -11084,6 +12136,29 @@ __metadata:
languageName: node
linkType: hard
+"inquirer@npm:^9.2.23":
+ version: 9.2.23
+ resolution: "inquirer@npm:9.2.23"
+ dependencies:
+ "@inquirer/figures": "npm:^1.0.3"
+ "@ljharb/through": "npm:^2.3.13"
+ ansi-escapes: "npm:^4.3.2"
+ chalk: "npm:^5.3.0"
+ cli-cursor: "npm:^3.1.0"
+ cli-width: "npm:^4.1.0"
+ external-editor: "npm:^3.1.0"
+ lodash: "npm:^4.17.21"
+ mute-stream: "npm:1.0.0"
+ ora: "npm:^5.4.1"
+ run-async: "npm:^3.0.0"
+ rxjs: "npm:^7.8.1"
+ string-width: "npm:^4.2.3"
+ strip-ansi: "npm:^6.0.1"
+ wrap-ansi: "npm:^6.2.0"
+ checksum: 10/ccc05c4d64ee583ac6d1ad602ae1b76c25da6d6ca8923bbac9158f76bad2eb9c628b5b5201b135fcc32f9651ed1b9ed99e6489f9afa5f00db443447f1f9ad391
+ languageName: node
+ linkType: hard
+
"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.7":
version: 1.0.7
resolution: "internal-slot@npm:1.0.7"
@@ -11095,7 +12170,7 @@ __metadata:
languageName: node
linkType: hard
-"internmap@npm:1 - 2":
+"internmap@npm:1 - 2, internmap@npm:2.0.3":
version: 2.0.3
resolution: "internmap@npm:2.0.3"
checksum: 10/873e0e7fcfe32f999aa0997a0b648b1244508e56e3ea6b8259b5245b50b5eeb3853fba221f96692bd6d1def501da76c32d64a5cb22a0b26cdd9b445664f805e0
@@ -11217,7 +12292,7 @@ __metadata:
languageName: node
linkType: hard
-"is-core-module@npm:^2.13.0, is-core-module@npm:^2.8.1":
+"is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1, is-core-module@npm:^2.8.1":
version: 2.13.1
resolution: "is-core-module@npm:2.13.1"
dependencies:
@@ -11420,6 +12495,13 @@ __metadata:
languageName: node
linkType: hard
+"is-promise@npm:^2.2.2":
+ version: 2.2.2
+ resolution: "is-promise@npm:2.2.2"
+ checksum: 10/18bf7d1c59953e0ad82a1ed963fb3dc0d135c8f299a14f89a17af312fc918373136e56028e8831700e1933519630cc2fd4179a777030330fde20d34e96f40c78
+ languageName: node
+ linkType: hard
+
"is-regex@npm:^1.1.2, is-regex@npm:^1.1.4":
version: 1.1.4
resolution: "is-regex@npm:1.1.4"
@@ -11512,7 +12594,7 @@ __metadata:
languageName: node
linkType: hard
-"is-typedarray@npm:~1.0.0":
+"is-typedarray@npm:^1.0.0, is-typedarray@npm:~1.0.0":
version: 1.0.0
resolution: "is-typedarray@npm:1.0.0"
checksum: 10/4b433bfb0f9026f079f4eb3fbaa4ed2de17c9995c3a0b5c800bec40799b4b2a8b4e051b1ada77749deb9ded4ae52fe2096973f3a93ff83df1a5a7184a669478c
@@ -12189,16 +13271,16 @@ __metadata:
languageName: node
linkType: hard
-"joi@npm:^17.13.3":
- version: 17.13.3
- resolution: "joi@npm:17.13.3"
+"joi@npm:^17.11.0":
+ version: 17.13.1
+ resolution: "joi@npm:17.13.1"
dependencies:
"@hapi/hoek": "npm:^9.3.0"
"@hapi/topo": "npm:^5.1.0"
"@sideway/address": "npm:^4.1.5"
"@sideway/formula": "npm:^3.0.1"
"@sideway/pinpoint": "npm:^2.0.0"
- checksum: 10/4c150db0c820c3a52f4a55c82c1fc5e144a5b5f4da9ffebc7339a15469d1a447ebb427ced446efcb9709ab56bd71a06c4c67c9381bc1b9f9ae63fc7c89209bdf
+ checksum: 10/9e34f93afbb490e12d7ec4aa05803788cd9ff4de00af30389c9d0f4af193ae85941365f80cb0ac38d0d04a45b85ee3a8b78cb0c10b5efeccce8922d68719603c
languageName: node
linkType: hard
@@ -12352,7 +13434,7 @@ __metadata:
languageName: node
linkType: hard
-"json-parse-even-better-errors@npm:^3.0.0, json-parse-even-better-errors@npm:^3.0.2":
+"json-parse-even-better-errors@npm:^3.0.0":
version: 3.0.2
resolution: "json-parse-even-better-errors@npm:3.0.2"
checksum: 10/6f04ea6c9ccb783630a59297959247e921cc90b917b8351197ca7fd058fccc7079268fd9362be21ba876fc26aa5039369dd0a2280aae49aae425784794a94927
@@ -12360,21 +13442,24 @@ __metadata:
linkType: hard
"json-schema-to-typescript@npm:^15.0.0":
- version: 15.0.2
- resolution: "json-schema-to-typescript@npm:15.0.2"
+ version: 15.0.0
+ resolution: "json-schema-to-typescript@npm:15.0.0"
dependencies:
"@apidevtools/json-schema-ref-parser": "npm:^11.5.5"
"@types/json-schema": "npm:^7.0.15"
- "@types/lodash": "npm:^4.17.7"
+ "@types/lodash": "npm:^4.17.0"
+ cli-color: "npm:^2.0.4"
glob: "npm:^10.3.12"
is-glob: "npm:^4.0.3"
js-yaml: "npm:^4.1.0"
lodash: "npm:^4.17.21"
minimist: "npm:^1.2.8"
+ mkdirp: "npm:^3.0.1"
+ node-fetch: "npm:^3.3.2"
prettier: "npm:^3.2.5"
bin:
json2ts: dist/src/cli.js
- checksum: 10/bdb6772822226a3d53ec6ac51cb68b79dc9eaee8019411e7b5b3fc4ecc6c1aa79923206f634f126ead709078e2d306985c45e8d715178a8a9103321a3552d948
+ checksum: 10/ac62f4190932087c67d0a2ee23e659ce9a9b3413cdb60d0e109fefc4795305022033a8965cc9cbba08cd515aa3c9bdc9727fd71a714f6b8cf96a2d20b6faf082
languageName: node
linkType: hard
@@ -12406,13 +13491,6 @@ __metadata:
languageName: node
linkType: hard
-"json-stringify-nice@npm:^1.1.4":
- version: 1.1.4
- resolution: "json-stringify-nice@npm:1.1.4"
- checksum: 10/0e02cae900a1f24df64613dd10a54b354e4ba2b17822f0d7f0d2708182e71a8bbbfac107d54d3ae8fa3d8bab3556e20cef84f193ace92c9df7bc30872ec2926e
- languageName: node
- linkType: hard
-
"json-stringify-safe@npm:^5.0.1, json-stringify-safe@npm:~5.0.1":
version: 5.0.1
resolution: "json-stringify-safe@npm:5.0.1"
@@ -12420,6 +13498,17 @@ __metadata:
languageName: node
linkType: hard
+"json5@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "json5@npm:1.0.2"
+ dependencies:
+ minimist: "npm:^1.2.0"
+ bin:
+ json5: lib/cli.js
+ checksum: 10/a78d812dbbd5642c4f637dd130954acfd231b074965871c3e28a5bbd571f099d623ecf9161f1960c4ddf68e0cc98dee8bebfdb94a71ad4551f85a1afc94b63f6
+ languageName: node
+ linkType: hard
+
"json5@npm:^2.2.2, json5@npm:^2.2.3":
version: 2.2.3
resolution: "json5@npm:2.2.3"
@@ -12499,20 +13588,6 @@ __metadata:
languageName: node
linkType: hard
-"just-diff-apply@npm:^5.2.0":
- version: 5.5.0
- resolution: "just-diff-apply@npm:5.5.0"
- checksum: 10/5515c436c89e9ef934f1ea2aac447588c38dd017247ed85254537b005706e64321ca7a9c246fe7106338da1ef3a693f8550ebf11759c854713e9ccffb788a43b
- languageName: node
- linkType: hard
-
-"just-diff@npm:^6.0.0":
- version: 6.0.2
- resolution: "just-diff@npm:6.0.2"
- checksum: 10/4c6b14d6be2a3391b020ea2b3d1a0acf2f4c60fcb16681c7f6f76d4c0f1841fae5b00c1a2e719980992e46320e4b6c55a4713683cb1873dd41a2621f08c9f8e8
- languageName: node
- linkType: hard
-
"just-extend@npm:^6.2.0":
version: 6.2.0
resolution: "just-extend@npm:6.2.0"
@@ -12532,7 +13607,7 @@ __metadata:
languageName: unknown
linkType: soft
-"keyv@npm:^4.5.4":
+"keyv@npm:^4.5.3, keyv@npm:^4.5.4":
version: 4.5.4
resolution: "keyv@npm:4.5.4"
dependencies:
@@ -12562,13 +13637,6 @@ __metadata:
languageName: node
linkType: hard
-"known-css-properties@npm:^0.34.0":
- version: 0.34.0
- resolution: "known-css-properties@npm:0.34.0"
- checksum: 10/0e93e83f84537e89b9dc56c16aff511ed9f24128fe509c3f601ce495eb10bf6678e2f4ff521f6b53feabc7bd18088e43efb31aae4cb771da831ef1408c23211a
- languageName: node
- linkType: hard
-
"kolorist@npm:^1.8.0":
version: 1.8.0
resolution: "kolorist@npm:1.8.0"
@@ -12626,7 +13694,7 @@ __metadata:
languageName: node
linkType: hard
-"lilconfig@npm:~3.1.2":
+"lilconfig@npm:~3.1.1":
version: 3.1.2
resolution: "lilconfig@npm:3.1.2"
checksum: 10/8058403850cfad76d6041b23db23f730e52b6c17a8c28d87b90766639ca0ee40c748a3e85c2d7bd133d572efabff166c4b015e5d25e01fd666cb4b13cfada7f0
@@ -12648,22 +13716,22 @@ __metadata:
linkType: hard
"lint-staged@npm:^15.0.0":
- version: 15.2.10
- resolution: "lint-staged@npm:15.2.10"
+ version: 15.2.7
+ resolution: "lint-staged@npm:15.2.7"
dependencies:
chalk: "npm:~5.3.0"
commander: "npm:~12.1.0"
- debug: "npm:~4.3.6"
+ debug: "npm:~4.3.4"
execa: "npm:~8.0.1"
- lilconfig: "npm:~3.1.2"
- listr2: "npm:~8.2.4"
- micromatch: "npm:~4.0.8"
+ lilconfig: "npm:~3.1.1"
+ listr2: "npm:~8.2.1"
+ micromatch: "npm:~4.0.7"
pidtree: "npm:~0.6.0"
string-argv: "npm:~0.3.2"
- yaml: "npm:~2.5.0"
+ yaml: "npm:~2.4.2"
bin:
lint-staged: bin/lint-staged.js
- checksum: 10/ab6930cd633dbb5b6ec7c81fc06c65df41e9f80d93dd22e0d79c6e272cdfd8110a0fbdec60303d46a06b30bcd92261153630e2c937531b77ec5ae41e7e9d90d3
+ checksum: 10/7557bcf4e8dc0555f2c7e6a8ab6f5dfd7faaaed632a5d9e598768c86f786267ca216f8005068796a8118884d322a1c7f8f93e57c01b3e556475b77297ddad34f
languageName: node
linkType: hard
@@ -12688,17 +13756,17 @@ __metadata:
languageName: node
linkType: hard
-"listr2@npm:~8.2.4":
- version: 8.2.4
- resolution: "listr2@npm:8.2.4"
+"listr2@npm:~8.2.1":
+ version: 8.2.1
+ resolution: "listr2@npm:8.2.1"
dependencies:
cli-truncate: "npm:^4.0.0"
colorette: "npm:^2.0.20"
eventemitter3: "npm:^5.0.1"
- log-update: "npm:^6.1.0"
- rfdc: "npm:^1.4.1"
+ log-update: "npm:^6.0.0"
+ rfdc: "npm:^1.3.1"
wrap-ansi: "npm:^9.0.0"
- checksum: 10/344d2397e127bf802935925e95b54468eef745fbbaf9326eb33a1634ae2d6e86cdb527ef48cb83a19a50671955d39b3e2608c74db85530df07b5674f5de115e1
+ checksum: 10/1d33348682fee7af49c91d508f970fb58897fbc722a17ae6b9d4d904c909e105ead8c123652238bc99462b1e323c56e6e62877a03d788ca32fe706cfec283789
languageName: node
linkType: hard
@@ -12798,7 +13866,7 @@ __metadata:
languageName: node
linkType: hard
-"lodash@npm:^4.0.0, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:~4.17.15":
+"lodash@npm:4.17.21, lodash@npm:^4.0.0, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:~4.17.15":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532
@@ -12827,16 +13895,16 @@ __metadata:
languageName: node
linkType: hard
-"log-update@npm:^6.1.0":
- version: 6.1.0
- resolution: "log-update@npm:6.1.0"
+"log-update@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "log-update@npm:6.0.0"
dependencies:
- ansi-escapes: "npm:^7.0.0"
- cli-cursor: "npm:^5.0.0"
- slice-ansi: "npm:^7.1.0"
+ ansi-escapes: "npm:^6.2.0"
+ cli-cursor: "npm:^4.0.0"
+ slice-ansi: "npm:^7.0.0"
strip-ansi: "npm:^7.1.0"
wrap-ansi: "npm:^9.0.0"
- checksum: 10/5abb4131e33b1e7f8416bb194fe17a3603d83e4657c5bf5bb81ce4187f3b00ea481643b85c3d5cefe6037a452cdcf7f1391ab8ea0d9c23e75d19589830ec4f11
+ checksum: 10/b345f392c356087290918f1bdaae84ee38699c89c9274fafbb6f4cee2fe6f89f9737000111279a40e651fbe0e9c08803b0457c2a4800d8a405752804f73058a8
languageName: node
linkType: hard
@@ -12867,13 +13935,6 @@ __metadata:
languageName: node
linkType: hard
-"lru-cache@npm:^10.2.2":
- version: 10.4.3
- resolution: "lru-cache@npm:10.4.3"
- checksum: 10/e6e90267360476720fa8e83cc168aa2bf0311f3f2eea20a6ba78b90a885ae72071d9db132f40fda4129c803e7dcec3a6b6a6fbb44ca90b081630b810b5d6a41a
- languageName: node
- linkType: hard
-
"lru-cache@npm:^11.0.0":
version: 11.0.0
resolution: "lru-cache@npm:11.0.0"
@@ -12899,6 +13960,15 @@ __metadata:
languageName: node
linkType: hard
+"lru-queue@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "lru-queue@npm:0.1.0"
+ dependencies:
+ es5-ext: "npm:~0.10.2"
+ checksum: 10/55b08ee3a7dbefb7d8ee2d14e0a97c69a887f78bddd9e28a687a1944b57e09513d4b401db515279e8829d52331df12a767f3ed27ca67c3322c723cc25c06403f
+ languageName: node
+ linkType: hard
+
"lz-string@npm:^1.5.0":
version: 1.5.0
resolution: "lz-string@npm:1.5.0"
@@ -13050,6 +14120,22 @@ __metadata:
languageName: node
linkType: hard
+"memoizee@npm:^0.4.15":
+ version: 0.4.17
+ resolution: "memoizee@npm:0.4.17"
+ dependencies:
+ d: "npm:^1.0.2"
+ es5-ext: "npm:^0.10.64"
+ es6-weak-map: "npm:^2.0.3"
+ event-emitter: "npm:^0.3.5"
+ is-promise: "npm:^2.2.2"
+ lru-queue: "npm:^0.1.0"
+ next-tick: "npm:^1.1.0"
+ timers-ext: "npm:^0.1.7"
+ checksum: 10/b7abda74d1057878f3570c45995f24da8a4f8636e0e9a7c29a6709be2314bf40c7d78e3be93c0b1660ba419de5740fa5e447c400ab5df407ffbd236421066380
+ languageName: node
+ linkType: hard
+
"memoizerific@npm:^1.11.3":
version: 1.11.3
resolution: "memoizerific@npm:1.11.3"
@@ -13101,7 +14187,7 @@ __metadata:
languageName: node
linkType: hard
-"micromatch@npm:^4.0.4":
+"micromatch@npm:^4.0.4, micromatch@npm:^4.0.7, micromatch@npm:~4.0.7":
version: 4.0.7
resolution: "micromatch@npm:4.0.7"
dependencies:
@@ -13111,16 +14197,6 @@ __metadata:
languageName: node
linkType: hard
-"micromatch@npm:^4.0.8, micromatch@npm:~4.0.8":
- version: 4.0.8
- resolution: "micromatch@npm:4.0.8"
- dependencies:
- braces: "npm:^3.0.3"
- picomatch: "npm:^2.3.1"
- checksum: 10/6bf2a01672e7965eb9941d1f02044fad2bd12486b5553dc1116ff24c09a8723157601dc992e74c911d896175918448762df3b3fd0a6b61037dd1a9766ddfbf58
- languageName: node
- linkType: hard
-
"mime-db@npm:1.52.0":
version: 1.52.0
resolution: "mime-db@npm:1.52.0"
@@ -13160,13 +14236,6 @@ __metadata:
languageName: node
linkType: hard
-"mimic-function@npm:^5.0.0":
- version: 5.0.1
- resolution: "mimic-function@npm:5.0.1"
- checksum: 10/eb5893c99e902ccebbc267c6c6b83092966af84682957f79313311edb95e8bb5f39fb048d77132b700474d1c86d90ccc211e99bae0935447a4834eb4c882982c
- languageName: node
- linkType: hard
-
"min-document@npm:^2.19.0":
version: 2.19.0
resolution: "min-document@npm:2.19.0"
@@ -13201,6 +14270,15 @@ __metadata:
languageName: node
linkType: hard
+"minimatch@npm:^5.0.1":
+ version: 5.1.6
+ resolution: "minimatch@npm:5.1.6"
+ dependencies:
+ brace-expansion: "npm:^2.0.1"
+ checksum: 10/126b36485b821daf96d33b5c821dac600cc1ab36c87e7a532594f9b1652b1fa89a1eebcaad4dff17c764dce1a7ac1531327f190fed5f97d8f6e5f889c116c429
+ languageName: node
+ linkType: hard
+
"minimatch@npm:^9.0.0, minimatch@npm:^9.0.3, minimatch@npm:^9.0.4":
version: 9.0.4
resolution: "minimatch@npm:9.0.4"
@@ -13339,6 +14417,15 @@ __metadata:
languageName: node
linkType: hard
+"mkdirp@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "mkdirp@npm:3.0.1"
+ bin:
+ mkdirp: dist/cjs/src/bin.js
+ checksum: 10/16fd79c28645759505914561e249b9a1f5fe3362279ad95487a4501e4467abeb714fd35b95307326b8fd03f3c7719065ef11a6f97b7285d7888306d1bd2232ba
+ languageName: node
+ linkType: hard
+
"mlly@npm:^1.4.2, mlly@npm:^1.7.1":
version: 1.7.1
resolution: "mlly@npm:1.7.1"
@@ -13477,7 +14564,7 @@ __metadata:
languageName: node
linkType: hard
-"ms@npm:2.1.3, ms@npm:^2.1.1, ms@npm:^2.1.3":
+"ms@npm:2.1.3, ms@npm:^2.1.1":
version: 2.1.3
resolution: "ms@npm:2.1.3"
checksum: 10/aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
@@ -13496,14 +14583,14 @@ __metadata:
linkType: hard
"msw@npm:^2.0.2":
- version: 2.4.9
- resolution: "msw@npm:2.4.9"
+ version: 2.3.1
+ resolution: "msw@npm:2.3.1"
dependencies:
"@bundled-es-modules/cookie": "npm:^2.0.0"
"@bundled-es-modules/statuses": "npm:^1.0.1"
- "@bundled-es-modules/tough-cookie": "npm:^0.1.6"
"@inquirer/confirm": "npm:^3.0.0"
- "@mswjs/interceptors": "npm:^0.35.8"
+ "@mswjs/cookies": "npm:^1.1.0"
+ "@mswjs/interceptors": "npm:^0.29.0"
"@open-draft/until": "npm:^2.1.0"
"@types/cookie": "npm:^0.6.0"
"@types/statuses": "npm:^2.0.4"
@@ -13512,18 +14599,18 @@ __metadata:
headers-polyfill: "npm:^4.0.2"
is-node-process: "npm:^1.2.0"
outvariant: "npm:^1.4.2"
- path-to-regexp: "npm:^6.3.0"
+ path-to-regexp: "npm:^6.2.0"
strict-event-emitter: "npm:^0.5.1"
type-fest: "npm:^4.9.0"
yargs: "npm:^17.7.2"
peerDependencies:
- typescript: ">= 4.8.x"
+ typescript: ">= 4.7.x"
peerDependenciesMeta:
typescript:
optional: true
bin:
msw: cli/index.js
- checksum: 10/fe00b2d2934993cfb26661ab919944a677d68f097d1e5990a0a4245334741412855abe499dd77822212c586dd8dd002ef8062f0f4f451a6955bd5dccab1905a8
+ checksum: 10/449df7c48f82eaa3de4b40ca106be232b09dcf7f736b1bb7410109702f803262016db35247b299c1ec378346678f48d1d50752ee18fc90329c2531326cec7ec4
languageName: node
linkType: hard
@@ -13534,7 +14621,7 @@ __metadata:
languageName: node
linkType: hard
-"mute-stream@npm:^1.0.0":
+"mute-stream@npm:1.0.0, mute-stream@npm:^1.0.0":
version: 1.0.0
resolution: "mute-stream@npm:1.0.0"
checksum: 10/36fc968b0e9c9c63029d4f9dc63911950a3bdf55c9a87f58d3a266289b67180201cade911e7699f8b2fa596b34c9db43dad37649e3f7fdd13c3bb9edb0017ee7
@@ -13580,6 +14667,13 @@ __metadata:
languageName: node
linkType: hard
+"next-tick@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "next-tick@npm:1.1.0"
+ checksum: 10/83b5cf36027a53ee6d8b7f9c0782f2ba87f4858d977342bfc3c20c21629290a2111f8374d13a81221179603ffc4364f38374b5655d17b6a8f8a8c77bdea4fe8b
+ languageName: node
+ linkType: hard
+
"nise@npm:^5.1.0":
version: 5.1.9
resolution: "nise@npm:5.1.9"
@@ -13692,7 +14786,7 @@ __metadata:
languageName: node
linkType: hard
-"nopt@npm:^7.0.0, nopt@npm:^7.2.1":
+"nopt@npm:^7.0.0":
version: 7.2.1
resolution: "nopt@npm:7.2.1"
dependencies:
@@ -13722,6 +14816,15 @@ __metadata:
languageName: node
linkType: hard
+"npm-bundled@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "npm-bundled@npm:2.0.1"
+ dependencies:
+ npm-normalize-package-bin: "npm:^2.0.0"
+ checksum: 10/adf5d727915cbd61603e2171ba67e39319efa343ceb72868348232a36ad774a8365d5af5e1aad29acc41c3caeda4ebd80e5b7a3da319985509aeedf79e352c0d
+ languageName: node
+ linkType: hard
+
"npm-bundled@npm:^3.0.0":
version: 3.0.1
resolution: "npm-bundled@npm:3.0.1"
@@ -13731,7 +14834,7 @@ __metadata:
languageName: node
linkType: hard
-"npm-install-checks@npm:^6.0.0, npm-install-checks@npm:^6.2.0":
+"npm-install-checks@npm:^6.0.0":
version: 6.3.0
resolution: "npm-install-checks@npm:6.3.0"
dependencies:
@@ -13740,6 +14843,13 @@ __metadata:
languageName: node
linkType: hard
+"npm-normalize-package-bin@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "npm-normalize-package-bin@npm:2.0.0"
+ checksum: 10/7c5379f9b188b564c4332c97bdd9a5d6b7b15f02b5823b00989d6a0e6fb31eb0280f02b0a924f930e1fcaf00e60fae333aec8923d2a4c7747613c7d629d8aa25
+ languageName: node
+ linkType: hard
+
"npm-normalize-package-bin@npm:^3.0.0":
version: 3.0.1
resolution: "npm-normalize-package-bin@npm:3.0.1"
@@ -13771,7 +14881,21 @@ __metadata:
languageName: node
linkType: hard
-"npm-packlist@npm:^8.0.0, npm-packlist@npm:^8.0.2":
+"npm-packlist@npm:^5.1.3":
+ version: 5.1.3
+ resolution: "npm-packlist@npm:5.1.3"
+ dependencies:
+ glob: "npm:^8.0.1"
+ ignore-walk: "npm:^5.0.1"
+ npm-bundled: "npm:^2.0.0"
+ npm-normalize-package-bin: "npm:^2.0.0"
+ bin:
+ npm-packlist: bin/index.js
+ checksum: 10/78aa1c69a349c40cf7ba556581bff2dd5cbc1455614a44bd673e076f7f402096ac7c01660c45ec17cbd51bf0db3a4df7e9bc3a0a8e8e497ebf6d53848f33dfad
+ languageName: node
+ linkType: hard
+
+"npm-packlist@npm:^8.0.0":
version: 8.0.2
resolution: "npm-packlist@npm:8.0.2"
dependencies:
@@ -13781,30 +14905,18 @@ __metadata:
linkType: hard
"npm-pick-manifest@npm:^9.0.0":
- version: 9.0.1
- resolution: "npm-pick-manifest@npm:9.0.1"
- dependencies:
- npm-install-checks: "npm:^6.0.0"
- npm-normalize-package-bin: "npm:^3.0.0"
- npm-package-arg: "npm:^11.0.0"
- semver: "npm:^7.3.5"
- checksum: 10/870053b63c8765a5d22df3aabcf09505342dd30398c68e15a57cc32e9da629c361b12285d72bd0bac100786623d2f2dc5ced16270f39dda7c14660fae677590e
- languageName: node
- linkType: hard
-
-"npm-pick-manifest@npm:^9.0.1":
- version: 9.1.0
- resolution: "npm-pick-manifest@npm:9.1.0"
+ version: 9.0.1
+ resolution: "npm-pick-manifest@npm:9.0.1"
dependencies:
npm-install-checks: "npm:^6.0.0"
npm-normalize-package-bin: "npm:^3.0.0"
npm-package-arg: "npm:^11.0.0"
semver: "npm:^7.3.5"
- checksum: 10/e759e4fe4076da9169cf522964a80bbc096d50cd24c8c44b50b44706c4479bd9d9d018fbdb76c6ea0c6037e012e07c6c917a1ecaa7ae1a1169cddfae1c0f24b6
+ checksum: 10/870053b63c8765a5d22df3aabcf09505342dd30398c68e15a57cc32e9da629c361b12285d72bd0bac100786623d2f2dc5ced16270f39dda7c14660fae677590e
languageName: node
linkType: hard
-"npm-registry-fetch@npm:^17.0.0, npm-registry-fetch@npm:^17.0.1, npm-registry-fetch@npm:^17.1.0":
+"npm-registry-fetch@npm:^17.0.0, npm-registry-fetch@npm:^17.0.1":
version: 17.1.0
resolution: "npm-registry-fetch@npm:17.1.0"
dependencies:
@@ -13838,6 +14950,18 @@ __metadata:
languageName: node
linkType: hard
+"npmlog@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "npmlog@npm:7.0.1"
+ dependencies:
+ are-we-there-yet: "npm:^4.0.0"
+ console-control-strings: "npm:^1.1.0"
+ gauge: "npm:^5.0.0"
+ set-blocking: "npm:^2.0.0"
+ checksum: 10/37cc2796a4b47bb82b5fc5d111f812d5856b30f8dd29d3e9ecce30fe966bd4389926e818ec5e7f11e9fcc60220ef9c65d7e4c56dd5101ee19d8f5e60320e558b
+ languageName: node
+ linkType: hard
+
"nwsapi@npm:^2.2.2":
version: 2.2.10
resolution: "nwsapi@npm:2.2.10"
@@ -13914,7 +15038,7 @@ __metadata:
languageName: node
linkType: hard
-"object.fromentries@npm:^2.0.8":
+"object.fromentries@npm:^2.0.7, object.fromentries@npm:^2.0.8":
version: 2.0.8
resolution: "object.fromentries@npm:2.0.8"
dependencies:
@@ -13926,7 +15050,18 @@ __metadata:
languageName: node
linkType: hard
-"object.values@npm:^1.1.6, object.values@npm:^1.2.0":
+"object.groupby@npm:^1.0.1":
+ version: 1.0.3
+ resolution: "object.groupby@npm:1.0.3"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ es-abstract: "npm:^1.23.2"
+ checksum: 10/44cb86dd2c660434be65f7585c54b62f0425b0c96b5c948d2756be253ef06737da7e68d7106e35506ce4a44d16aa85a413d11c5034eb7ce5579ec28752eb42d0
+ languageName: node
+ linkType: hard
+
+"object.values@npm:^1.1.6, object.values@npm:^1.1.7, object.values@npm:^1.2.0":
version: 1.2.0
resolution: "object.values@npm:1.2.0"
dependencies:
@@ -13980,15 +15115,6 @@ __metadata:
languageName: node
linkType: hard
-"onetime@npm:^7.0.0":
- version: 7.0.0
- resolution: "onetime@npm:7.0.0"
- dependencies:
- mimic-function: "npm:^5.0.0"
- checksum: 10/eb08d2da9339819e2f9d52cab9caf2557d80e9af8c7d1ae86e1a0fef027d00a88e9f5bd67494d350df360f7c559fbb44e800b32f310fb989c860214eacbb561c
- languageName: node
- linkType: hard
-
"optionator@npm:^0.9.3":
version: 0.9.4
resolution: "optionator@npm:0.9.4"
@@ -14020,6 +15146,13 @@ __metadata:
languageName: node
linkType: hard
+"os-tmpdir@npm:~1.0.2":
+ version: 1.0.2
+ resolution: "os-tmpdir@npm:1.0.2"
+ checksum: 10/5666560f7b9f10182548bf7013883265be33620b1c1b4a4d405c25be2636f970c5488ff3e6c48de75b55d02bde037249fe5dbfbb4c0fb7714953d56aed062e6d
+ languageName: node
+ linkType: hard
+
"ospath@npm:^1.2.2":
version: 1.2.2
resolution: "ospath@npm:1.2.2"
@@ -14027,20 +15160,13 @@ __metadata:
languageName: node
linkType: hard
-"outvariant@npm:^1.4.0, outvariant@npm:^1.4.2":
+"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0, outvariant@npm:^1.4.2":
version: 1.4.2
resolution: "outvariant@npm:1.4.2"
checksum: 10/f16ba035fb65d1cbe7d2e06693dd42183c46bc8456713d9ddb5182d067defa7d78217edab0a2d3e173d3bacd627b2bd692195c7087c225b82548fbf52c677b38
languageName: node
linkType: hard
-"outvariant@npm:^1.4.3":
- version: 1.4.3
- resolution: "outvariant@npm:1.4.3"
- checksum: 10/3a7582745850cb344d49641867a4c080858c54f4091afd91b9c0765ba6e471c2bc841348f0fff344845ddd0a4db42fd5d68c6f7ebaf32d4b676a3a9987b2488a
- languageName: node
- linkType: hard
-
"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0":
version: 2.3.0
resolution: "p-limit@npm:2.3.0"
@@ -14068,6 +15194,15 @@ __metadata:
languageName: node
linkType: hard
+"p-limit@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "p-limit@npm:5.0.0"
+ dependencies:
+ yocto-queue: "npm:^1.0.0"
+ checksum: 10/87bf5837dee6942f0dbeff318436179931d9a97848d1b07dbd86140a477a5d2e6b90d9701b210b4e21fe7beaea2979dfde366e4f576fa644a59bd4d6a6371da7
+ languageName: node
+ linkType: hard
+
"p-limit@npm:^6.1.0":
version: 6.1.0
resolution: "p-limit@npm:6.1.0"
@@ -14174,7 +15309,7 @@ __metadata:
languageName: node
linkType: hard
-"pacote@npm:^18.0.0, pacote@npm:^18.0.6":
+"pacote@npm:^18.0.6":
version: 18.0.6
resolution: "pacote@npm:18.0.6"
dependencies:
@@ -14210,17 +15345,6 @@ __metadata:
languageName: node
linkType: hard
-"parse-conflict-json@npm:^3.0.0":
- version: 3.0.1
- resolution: "parse-conflict-json@npm:3.0.1"
- dependencies:
- json-parse-even-better-errors: "npm:^3.0.0"
- just-diff: "npm:^6.0.0"
- just-diff-apply: "npm:^5.2.0"
- checksum: 10/ceb13ca90bd75610559125dc7b519e2806c096640142d6524e9b1ffdf08d6625b03a29d8afe4630d95460f703b9d5bc6dac21fcdcb00089213ffdb70800c900b
- languageName: node
- linkType: hard
-
"parse-json@npm:^5.2.0":
version: 5.2.0
resolution: "parse-json@npm:5.2.0"
@@ -14374,20 +15498,13 @@ __metadata:
languageName: node
linkType: hard
-"path-to-regexp@npm:^6.2.1":
+"path-to-regexp@npm:^6.2.0, path-to-regexp@npm:^6.2.1":
version: 6.2.2
resolution: "path-to-regexp@npm:6.2.2"
checksum: 10/f7d11c1a9e02576ce0294f4efdc523c11b73894947afdf7b23a0d0f7c6465d7a7772166e770ddf1495a8017cc0ee99e3e8a15ed7302b6b948b89a6dd4eea895e
languageName: node
linkType: hard
-"path-to-regexp@npm:^6.3.0":
- version: 6.3.0
- resolution: "path-to-regexp@npm:6.3.0"
- checksum: 10/6822f686f01556d99538b350722ef761541ec0ce95ca40ce4c29e20a5b492fe8361961f57993c71b2418de12e604478dcf7c430de34b2c31a688363a7a944d9c
- languageName: node
- linkType: hard
-
"path-type@npm:^4.0.0":
version: 4.0.0
resolution: "path-type@npm:4.0.0"
@@ -14581,13 +15698,6 @@ __metadata:
languageName: node
linkType: hard
-"postcss-resolve-nested-selector@npm:^0.1.6":
- version: 0.1.6
- resolution: "postcss-resolve-nested-selector@npm:0.1.6"
- checksum: 10/85453901afe2a4db497b4e0d2c9cf2a097a08fa5d45bc646547025176217050334e423475519a1e6c74a1f31ade819d16bb37a39914e5321e250695ee3feea14
- languageName: node
- linkType: hard
-
"postcss-safe-parser@npm:^7.0.0":
version: 7.0.0
resolution: "postcss-safe-parser@npm:7.0.0"
@@ -14606,16 +15716,6 @@ __metadata:
languageName: node
linkType: hard
-"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.1.2":
- version: 6.1.2
- resolution: "postcss-selector-parser@npm:6.1.2"
- dependencies:
- cssesc: "npm:^3.0.0"
- util-deprecate: "npm:^1.0.2"
- checksum: 10/190034c94d809c115cd2f32ee6aade84e933450a43ec3899c3e78e7d7b33efd3a2a975bb45d7700b6c5b196c06a7d9acf3f1ba6f1d87032d9675a29d8bca1dd3
- languageName: node
- linkType: hard
-
"postcss-selector-parser@npm:^6.1.0":
version: 6.1.0
resolution: "postcss-selector-parser@npm:6.1.0"
@@ -14633,14 +15733,36 @@ __metadata:
languageName: node
linkType: hard
-"postcss@npm:^8.4.41, postcss@npm:^8.4.43, postcss@npm:^8.4.45":
- version: 8.4.47
- resolution: "postcss@npm:8.4.47"
+"postcss@npm:^8.4.38":
+ version: 8.4.38
+ resolution: "postcss@npm:8.4.38"
dependencies:
nanoid: "npm:^3.3.7"
- picocolors: "npm:^1.1.0"
- source-map-js: "npm:^1.2.1"
- checksum: 10/f2b50ba9b6fcb795232b6bb20de7cdc538c0025989a8ed9c4438d1960196ba3b7eaff41fdb1a5c701b3504651ea87aeb685577707f0ae4d6ce6f3eae5df79a81
+ picocolors: "npm:^1.0.0"
+ source-map-js: "npm:^1.2.0"
+ checksum: 10/6e44a7ed835ffa9a2b096e8d3e5dfc6bcf331a25c48aeb862dd54e3aaecadf814fa22be224fd308f87d08adf2299164f88c5fd5ab1c4ef6cbd693ceb295377f4
+ languageName: node
+ linkType: hard
+
+"postcss@npm:^8.4.40":
+ version: 8.4.41
+ resolution: "postcss@npm:8.4.41"
+ dependencies:
+ nanoid: "npm:^3.3.7"
+ picocolors: "npm:^1.0.1"
+ source-map-js: "npm:^1.2.0"
+ checksum: 10/6e6176c2407eff60493ca60a706c6b7def20a722c3adda94ea1ece38345eb99964191336fd62b62652279cec6938e79e0b1e1d477142c8d3516e7a725a74ee37
+ languageName: node
+ linkType: hard
+
+"postcss@npm:^8.4.45":
+ version: 8.4.45
+ resolution: "postcss@npm:8.4.45"
+ dependencies:
+ nanoid: "npm:^3.3.7"
+ picocolors: "npm:^1.0.1"
+ source-map-js: "npm:^1.2.0"
+ checksum: 10/7eaf7346d04929ee979548ece5e34d253eae6f175346e298b2c4621ad6f4ee00adfe7abe72688640e910c0361ae50537c5dda3e35fd1066491282c342b3ee5c8
languageName: node
linkType: hard
@@ -14705,7 +15827,7 @@ __metadata:
languageName: node
linkType: hard
-"proc-log@npm:^4.0.0, proc-log@npm:^4.1.0, proc-log@npm:^4.2.0":
+"proc-log@npm:^4.0.0, proc-log@npm:^4.2.0":
version: 4.2.0
resolution: "proc-log@npm:4.2.0"
checksum: 10/4e1394491b717f6c1ade15c570ecd4c2b681698474d3ae2d303c1e4b6ab9455bd5a81566211e82890d5a5ae9859718cc6954d5150bb18b09b72ecb297beae90a
@@ -14726,27 +15848,6 @@ __metadata:
languageName: node
linkType: hard
-"proggy@npm:^2.0.0":
- version: 2.0.0
- resolution: "proggy@npm:2.0.0"
- checksum: 10/9c96830d30516534c91e1260cae98d2c12aa32ea4ca7ff979876557ae293581c4874c95daf80497a7350179e7fec6d119cd589ef09af9c925f5842161897ed7e
- languageName: node
- linkType: hard
-
-"promise-all-reject-late@npm:^1.0.0":
- version: 1.0.1
- resolution: "promise-all-reject-late@npm:1.0.1"
- checksum: 10/f5e5c1bfed975c26b6dec007393e1026c437716d87c9c688cfa026bb904c190155211d23fe795c03c4394f88563471aec56b3ad263bff5ed68dad734513c2912
- languageName: node
- linkType: hard
-
-"promise-call-limit@npm:^3.0.1":
- version: 3.0.1
- resolution: "promise-call-limit@npm:3.0.1"
- checksum: 10/f1b3c4d3a9c5482ce27ec5f40311e1389adb9bb10c16166e61c96d29ab22c701691d5225bf6745a162858f45dfb46cc82275fd09e7aa57846fc446c7855c2f06
- languageName: node
- linkType: hard
-
"promise-inflight@npm:^1.0.1":
version: 1.0.1
resolution: "promise-inflight@npm:1.0.1"
@@ -14774,7 +15875,7 @@ __metadata:
languageName: node
linkType: hard
-"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
+"prop-types@npm:^15.5.10, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@@ -14865,21 +15966,21 @@ __metadata:
languageName: node
linkType: hard
-"qs@npm:6.11.0":
- version: 6.11.0
- resolution: "qs@npm:6.11.0"
+"qs@npm:6.10.4":
+ version: 6.10.4
+ resolution: "qs@npm:6.10.4"
dependencies:
side-channel: "npm:^1.0.4"
- checksum: 10/5a3bfea3e2f359ede1bfa5d2f0dbe54001aa55e40e27dc3e60fab814362d83a9b30758db057c2011b6f53a2d4e4e5150194b5bac45372652aecb3e3c0d4b256e
+ checksum: 10/8887a53f63180e0e0291deafef581e550bc3656f2453adc8d3ca34b49c04354d31079962f7faf90ab8f5fd6e3d70ee6645042b27814a757a3a5d5708ae3f58e0
languageName: node
linkType: hard
-"qs@npm:6.13.0":
- version: 6.13.0
- resolution: "qs@npm:6.13.0"
+"qs@npm:6.11.0":
+ version: 6.11.0
+ resolution: "qs@npm:6.11.0"
dependencies:
- side-channel: "npm:^1.0.6"
- checksum: 10/f548b376e685553d12e461409f0d6e5c59ec7c7d76f308e2a888fd9db3e0c5e89902bedd0754db3a9038eda5f27da2331a6f019c8517dc5e0a16b3c9a6e9cef8
+ side-channel: "npm:^1.0.4"
+ checksum: 10/5a3bfea3e2f359ede1bfa5d2f0dbe54001aa55e40e27dc3e60fab814362d83a9b30758db057c2011b6f53a2d4e4e5150194b5bac45372652aecb3e3c0d4b256e
languageName: node
linkType: hard
@@ -15054,15 +16155,15 @@ __metadata:
linkType: hard
"react-monaco-editor@npm:^0.56.0":
- version: 0.56.2
- resolution: "react-monaco-editor@npm:0.56.2"
+ version: 0.56.0
+ resolution: "react-monaco-editor@npm:0.56.0"
dependencies:
prop-types: "npm:^15.8.1"
peerDependencies:
"@types/react": ">=16 <= 18"
- monaco-editor: ^0.52.0
+ monaco-editor: ^0.50.0
react: ">=16 <= 18"
- checksum: 10/9e891803f766ab81349e1579ffc8cd7cba27eb34ac5113aaf34798f0998629da68415f67e2a0e76057ae632fe019c355eeab89baa607e612239315381777fff4
+ checksum: 10/6d6b351cb3b41b727d5f1d54c8e8bf45499e127cbaf667ff3a3fbb200cfb7eaeeca4f79a262a572b87724061ad863268ba8bd5dc89f42e22ebf9e68169b9984b
languageName: node
linkType: hard
@@ -15131,20 +16232,15 @@ __metadata:
languageName: node
linkType: hard
-"read-cmd-shim@npm:^4.0.0":
- version: 4.0.0
- resolution: "read-cmd-shim@npm:4.0.0"
- checksum: 10/69a83acf0a3e2357762d5944a6f4a3f3c5527d0f9fe8a5c9362225aaf702ccfa580ff3bc0b84809c99e88861a5e5be147629717f02ff9befdac68fca1ccc7664
- languageName: node
- linkType: hard
-
-"read-package-json-fast@npm:^3.0.0, read-package-json-fast@npm:^3.0.2":
- version: 3.0.2
- resolution: "read-package-json-fast@npm:3.0.2"
+"read-package-json@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "read-package-json@npm:7.0.1"
dependencies:
+ glob: "npm:^10.2.2"
json-parse-even-better-errors: "npm:^3.0.0"
+ normalize-package-data: "npm:^6.0.0"
npm-normalize-package-bin: "npm:^3.0.0"
- checksum: 10/8d406869f045f1d76e2a99865a8fd1c1af9c1dc06200b94d2b07eef87ed734b22703a8d72e1cd36ea36cc48e22020bdd187f88243c7dd0563f72114d38c17072
+ checksum: 10/4b5684f4ee96ff29d0ec62452d2b1ed2b3fb7e452cd1a1f40869d896082816a231a1e157fa3e72137e140ca961cbe7eeabc952658fc38235c85b202c91f2e584
languageName: node
linkType: hard
@@ -15171,7 +16267,7 @@ __metadata:
languageName: node
linkType: hard
-"read-pkg@npm:^9.0.1":
+"read-pkg@npm:^9.0.0, read-pkg@npm:^9.0.1":
version: 9.0.1
resolution: "read-pkg@npm:9.0.1"
dependencies:
@@ -15308,6 +16404,13 @@ __metadata:
languageName: node
linkType: hard
+"regexp-to-ast@npm:0.5.0":
+ version: 0.5.0
+ resolution: "regexp-to-ast@npm:0.5.0"
+ checksum: 10/41f5c38f568cb64378812e8e77b1dc383a3975e311063bfb2a83179fc1e6601c59b1b32d5b85996eb2ae50b9ccb73e551268b9e32caae3ec60acd0f705d4a58c
+ languageName: node
+ linkType: hard
+
"regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.2":
version: 1.5.2
resolution: "regexp.prototype.flags@npm:1.5.2"
@@ -15439,7 +16542,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@npm:^1.14.2, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2":
+"resolve@npm:^1.14.2, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2":
version: 1.22.8
resolution: "resolve@npm:1.22.8"
dependencies:
@@ -15465,7 +16568,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin":
+"resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin":
version: 1.22.8
resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d"
dependencies:
@@ -15501,13 +16604,13 @@ __metadata:
languageName: node
linkType: hard
-"restore-cursor@npm:^5.0.0":
- version: 5.1.0
- resolution: "restore-cursor@npm:5.1.0"
+"restore-cursor@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "restore-cursor@npm:4.0.0"
dependencies:
- onetime: "npm:^7.0.0"
- signal-exit: "npm:^4.1.0"
- checksum: 10/838dd54e458d89cfbc1a923b343c1b0f170a04100b4ce1733e97531842d7b440463967e521216e8ab6c6f8e89df877acc7b7f4c18ec76e99fb9bf5a60d358d2c
+ onetime: "npm:^5.1.0"
+ signal-exit: "npm:^3.0.2"
+ checksum: 10/5b675c5a59763bf26e604289eab35711525f11388d77f409453904e1e69c0d37ae5889295706b2c81d23bd780165084d040f9b68fffc32cc921519031c4fa4af
languageName: node
linkType: hard
@@ -15525,13 +16628,24 @@ __metadata:
languageName: node
linkType: hard
-"rfdc@npm:^1.3.0, rfdc@npm:^1.4.1":
+"rfdc@npm:^1.3.0, rfdc@npm:^1.3.1":
version: 1.4.1
resolution: "rfdc@npm:1.4.1"
checksum: 10/2f3d11d3d8929b4bfeefc9acb03aae90f971401de0add5ae6c5e38fec14f0405e6a4aad8fdb76344bfdd20c5193110e3750cbbd28ba86d73729d222b6cf4a729
languageName: node
linkType: hard
+"rimraf@npm:^3.0.2":
+ version: 3.0.2
+ resolution: "rimraf@npm:3.0.2"
+ dependencies:
+ glob: "npm:^7.1.3"
+ bin:
+ rimraf: bin.js
+ checksum: 10/063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5
+ languageName: node
+ linkType: hard
+
"rimraf@npm:^6.0.0":
version: 6.0.1
resolution: "rimraf@npm:6.0.1"
@@ -15562,26 +16676,26 @@ __metadata:
languageName: node
linkType: hard
-"rollup@npm:^4.20.0":
- version: 4.21.2
- resolution: "rollup@npm:4.21.2"
- dependencies:
- "@rollup/rollup-android-arm-eabi": "npm:4.21.2"
- "@rollup/rollup-android-arm64": "npm:4.21.2"
- "@rollup/rollup-darwin-arm64": "npm:4.21.2"
- "@rollup/rollup-darwin-x64": "npm:4.21.2"
- "@rollup/rollup-linux-arm-gnueabihf": "npm:4.21.2"
- "@rollup/rollup-linux-arm-musleabihf": "npm:4.21.2"
- "@rollup/rollup-linux-arm64-gnu": "npm:4.21.2"
- "@rollup/rollup-linux-arm64-musl": "npm:4.21.2"
- "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.21.2"
- "@rollup/rollup-linux-riscv64-gnu": "npm:4.21.2"
- "@rollup/rollup-linux-s390x-gnu": "npm:4.21.2"
- "@rollup/rollup-linux-x64-gnu": "npm:4.21.2"
- "@rollup/rollup-linux-x64-musl": "npm:4.21.2"
- "@rollup/rollup-win32-arm64-msvc": "npm:4.21.2"
- "@rollup/rollup-win32-ia32-msvc": "npm:4.21.2"
- "@rollup/rollup-win32-x64-msvc": "npm:4.21.2"
+"rollup@npm:^4.13.0":
+ version: 4.20.0
+ resolution: "rollup@npm:4.20.0"
+ dependencies:
+ "@rollup/rollup-android-arm-eabi": "npm:4.20.0"
+ "@rollup/rollup-android-arm64": "npm:4.20.0"
+ "@rollup/rollup-darwin-arm64": "npm:4.20.0"
+ "@rollup/rollup-darwin-x64": "npm:4.20.0"
+ "@rollup/rollup-linux-arm-gnueabihf": "npm:4.20.0"
+ "@rollup/rollup-linux-arm-musleabihf": "npm:4.20.0"
+ "@rollup/rollup-linux-arm64-gnu": "npm:4.20.0"
+ "@rollup/rollup-linux-arm64-musl": "npm:4.20.0"
+ "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.20.0"
+ "@rollup/rollup-linux-riscv64-gnu": "npm:4.20.0"
+ "@rollup/rollup-linux-s390x-gnu": "npm:4.20.0"
+ "@rollup/rollup-linux-x64-gnu": "npm:4.20.0"
+ "@rollup/rollup-linux-x64-musl": "npm:4.20.0"
+ "@rollup/rollup-win32-arm64-msvc": "npm:4.20.0"
+ "@rollup/rollup-win32-ia32-msvc": "npm:4.20.0"
+ "@rollup/rollup-win32-x64-msvc": "npm:4.20.0"
"@types/estree": "npm:1.0.5"
fsevents: "npm:~2.3.2"
dependenciesMeta:
@@ -15621,7 +16735,14 @@ __metadata:
optional: true
bin:
rollup: dist/bin/rollup
- checksum: 10/5d679af1a04170f7164e3e975a375adb76f9bbf34d1ad8d9c3fa789252d377e7d364dfee054a4283121f9f9368d7b35404b9d42fb260be314d34739243ab0722
+ checksum: 10/448bd835715aa0f78c6888314e31fb92f1b83325ef0ff861a5a322c2bc87d200b2b6c4acb9223fb669c27ae0c4b071003b6877eec1d3411174615a4057db8946
+ languageName: node
+ linkType: hard
+
+"run-async@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "run-async@npm:3.0.0"
+ checksum: 10/97fb8747f7765b77ebcd311d3a33548099336f04c6434e0763039b98c1de0f1b4421000695aff8751f309c0b995d8dfd620c1f1e4c35572da38c101488165305
languageName: node
linkType: hard
@@ -15948,7 +17069,7 @@ __metadata:
languageName: node
linkType: hard
-"semver@npm:^7.1.1, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0":
+"semver@npm:^7.1.1, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2":
version: 7.6.2
resolution: "semver@npm:7.6.2"
bin:
@@ -16116,13 +17237,13 @@ __metadata:
linkType: hard
"simple-git@npm:^3.22.0":
- version: 3.27.0
- resolution: "simple-git@npm:3.27.0"
+ version: 3.25.0
+ resolution: "simple-git@npm:3.25.0"
dependencies:
"@kwsites/file-exists": "npm:^1.1.1"
"@kwsites/promise-deferred": "npm:^1.1.1"
debug: "npm:^4.3.5"
- checksum: 10/c56c88dd1b5f6ad45c6034eb44f25ee61929a2a5832bd015b8b1b71331071e43bf631edbcc4a8529fa692f9b17576595d95c89218bc5d67be66ed0c1aedc7a76
+ checksum: 10/f284162c941e36970db171eacfe0df1f7ce50313fa7841b95abb704ec78ffe4f27b6a46a4b621ed88711104faa295eb47fb2b54b23cead4400cb2204ed491074
languageName: node
linkType: hard
@@ -16206,7 +17327,7 @@ __metadata:
languageName: node
linkType: hard
-"slice-ansi@npm:^7.1.0":
+"slice-ansi@npm:^7.0.0":
version: 7.1.0
resolution: "slice-ansi@npm:7.1.0"
dependencies:
@@ -16260,13 +17381,6 @@ __metadata:
languageName: node
linkType: hard
-"source-map-js@npm:^1.2.1":
- version: 1.2.1
- resolution: "source-map-js@npm:1.2.1"
- checksum: 10/ff9d8c8bf096d534a5b7707e0382ef827b4dd360a577d3f34d2b9f48e12c9d230b5747974ee7c607f0df65113732711bb701fe9ece3c7edbd43cb2294d707df3
- languageName: node
- linkType: hard
-
"source-map-support@npm:0.5.13":
version: 0.5.13
resolution: "source-map-support@npm:0.5.13"
@@ -16365,7 +17479,7 @@ __metadata:
languageName: node
linkType: hard
-"sshpk@npm:^1.18.0":
+"sshpk@npm:^1.14.1":
version: 1.18.0
resolution: "sshpk@npm:1.18.0"
dependencies:
@@ -16395,15 +17509,6 @@ __metadata:
languageName: node
linkType: hard
-"ssri@npm:^11.0.0":
- version: 11.0.0
- resolution: "ssri@npm:11.0.0"
- dependencies:
- minipass: "npm:^7.0.3"
- checksum: 10/e2fb25d3b010586ed50a89a94dbe04a15ac3b7c60492031c8c6b22e5880dbc80ef9f8b1f7df928be7a8fbe198acef57811f0fb647394f698a4b870f43ac9fb5c
- languageName: node
- linkType: hard
-
"stable@npm:^0.1.8":
version: 0.1.8
resolution: "stable@npm:0.1.8"
@@ -16421,22 +17526,22 @@ __metadata:
linkType: hard
"start-server-and-test@npm:^2.0.0":
- version: 2.0.8
- resolution: "start-server-and-test@npm:2.0.8"
+ version: 2.0.4
+ resolution: "start-server-and-test@npm:2.0.4"
dependencies:
arg: "npm:^5.0.2"
bluebird: "npm:3.7.2"
check-more-types: "npm:2.24.0"
- debug: "npm:4.3.7"
+ debug: "npm:4.3.5"
execa: "npm:5.1.1"
lazy-ass: "npm:1.6.0"
ps-tree: "npm:1.2.0"
- wait-on: "npm:8.0.1"
+ wait-on: "npm:7.2.0"
bin:
server-test: src/bin/start.js
start-server-and-test: src/bin/start.js
start-test: src/bin/start.js
- checksum: 10/4067c3dd120e1e515e4d087f2a60faebaae512517374dc30d14b29492a6761e2ab72f82c8bcb72f0eefc060fd7345674821e1255bb58a6ceaa5a1fac4257790a
+ checksum: 10/2125ed5ab7a0c9ece9fc3f3f6192f1b6d66a55ca7a8eab5c82a5d3b85d9299072c3f079b4b34ee81745668015ce1a00653aa764fbf650eb92de1dfa050ee0a07
languageName: node
linkType: hard
@@ -16471,8 +17576,8 @@ __metadata:
linkType: hard
"storybook-addon-remix-react-router@npm:^3.0.0":
- version: 3.0.1
- resolution: "storybook-addon-remix-react-router@npm:3.0.1"
+ version: 3.0.0
+ resolution: "storybook-addon-remix-react-router@npm:3.0.0"
dependencies:
compare-versions: "npm:^6.0.0"
react-inspector: "npm:6.0.2"
@@ -16492,7 +17597,7 @@ __metadata:
optional: true
react-dom:
optional: true
- checksum: 10/13fa62a60500813e53a508c03e8c8fc5e29021ab03cd42e27edd272ad26ac106d54e4f6f986b773c2501ee962de6d655b4f634c3f7aff920094668422955d704
+ checksum: 10/2213883135e894399c05f1ced0245d61fe679f4b61fe0a97cf2c5ceb0456aa9d2ad538e9fcdeebf4c9971220c36e839303059c3313561299fadf91c45d87c04c
languageName: node
linkType: hard
@@ -16517,13 +17622,13 @@ __metadata:
linkType: hard
"storybook@npm:^8.2.8":
- version: 8.2.9
- resolution: "storybook@npm:8.2.9"
+ version: 8.2.8
+ resolution: "storybook@npm:8.2.8"
dependencies:
"@babel/core": "npm:^7.24.4"
"@babel/types": "npm:^7.24.0"
- "@storybook/codemod": "npm:8.2.9"
- "@storybook/core": "npm:8.2.9"
+ "@storybook/codemod": "npm:8.2.8"
+ "@storybook/core": "npm:8.2.8"
"@types/semver": "npm:^7.3.4"
"@yarnpkg/fslib": "npm:2.10.3"
"@yarnpkg/libzip": "npm:2.3.0"
@@ -16552,7 +17657,7 @@ __metadata:
getstorybook: ./bin/index.cjs
sb: ./bin/index.cjs
storybook: ./bin/index.cjs
- checksum: 10/2d5473ba1ab31067d07c63d79799db05cf81927f517945999d124a337f209d685b2e1e4ff37d13924410ec5582d28f474fee6dee98be08f079869ec831c10df8
+ checksum: 10/f00d98cb89792a1e66087f5f72752daea83983afe97a8ba5691f43629ede4b3e96d276eb49398d3167136beb05d92b18873191b5798b639ba20986bcd2cdd852
languageName: node
linkType: hard
@@ -16867,14 +17972,14 @@ __metadata:
linkType: hard
"stylelint-prettier@npm:^5.0.0":
- version: 5.0.2
- resolution: "stylelint-prettier@npm:5.0.2"
+ version: 5.0.0
+ resolution: "stylelint-prettier@npm:5.0.0"
dependencies:
prettier-linter-helpers: "npm:^1.0.0"
peerDependencies:
prettier: ">=3.0.0"
stylelint: ">=16.0.0"
- checksum: 10/bee52ac6bfd03bfec07a429556d05e1cc754be9f0cf6802e19f06410d7d4cf6b2a01ca987f5e6f7816d8c88a0e73d04aa5b04be43fd121a9f805a9ab079a3719
+ checksum: 10/1d55f03bbc66c769643672789ebc6f48d6af573e8ef867ea919c7fd0fa70b9750183405641808c16a9a024f895092b23d0732d7ddda4c05ba6a21cceceee9205
languageName: node
linkType: hard
@@ -16894,20 +17999,20 @@ __metadata:
linkType: hard
"stylelint@npm:^16.1.0":
- version: 16.9.0
- resolution: "stylelint@npm:16.9.0"
+ version: 16.6.1
+ resolution: "stylelint@npm:16.6.1"
dependencies:
- "@csstools/css-parser-algorithms": "npm:^3.0.1"
- "@csstools/css-tokenizer": "npm:^3.0.1"
- "@csstools/media-query-list-parser": "npm:^3.0.1"
- "@csstools/selector-specificity": "npm:^4.0.0"
+ "@csstools/css-parser-algorithms": "npm:^2.6.3"
+ "@csstools/css-tokenizer": "npm:^2.3.1"
+ "@csstools/media-query-list-parser": "npm:^2.1.11"
+ "@csstools/selector-specificity": "npm:^3.1.1"
"@dual-bundle/import-meta-resolve": "npm:^4.1.0"
balanced-match: "npm:^2.0.0"
colord: "npm:^2.9.3"
cosmiconfig: "npm:^9.0.0"
css-functions-list: "npm:^3.2.2"
css-tree: "npm:^2.3.1"
- debug: "npm:^4.3.6"
+ debug: "npm:^4.3.4"
fast-glob: "npm:^3.3.2"
fastest-levenshtein: "npm:^1.0.16"
file-entry-cache: "npm:^9.0.0"
@@ -16915,30 +18020,30 @@ __metadata:
globby: "npm:^11.1.0"
globjoin: "npm:^0.1.4"
html-tags: "npm:^3.3.1"
- ignore: "npm:^5.3.2"
+ ignore: "npm:^5.3.1"
imurmurhash: "npm:^0.1.4"
is-plain-object: "npm:^5.0.0"
- known-css-properties: "npm:^0.34.0"
+ known-css-properties: "npm:^0.31.0"
mathml-tag-names: "npm:^2.1.3"
meow: "npm:^13.2.0"
- micromatch: "npm:^4.0.8"
+ micromatch: "npm:^4.0.7"
normalize-path: "npm:^3.0.0"
picocolors: "npm:^1.0.1"
- postcss: "npm:^8.4.41"
- postcss-resolve-nested-selector: "npm:^0.1.6"
+ postcss: "npm:^8.4.38"
+ postcss-resolve-nested-selector: "npm:^0.1.1"
postcss-safe-parser: "npm:^7.0.0"
- postcss-selector-parser: "npm:^6.1.2"
+ postcss-selector-parser: "npm:^6.1.0"
postcss-value-parser: "npm:^4.2.0"
resolve-from: "npm:^5.0.0"
string-width: "npm:^4.2.3"
strip-ansi: "npm:^7.1.0"
- supports-hyperlinks: "npm:^3.1.0"
+ supports-hyperlinks: "npm:^3.0.0"
svg-tags: "npm:^1.0.0"
table: "npm:^6.8.2"
write-file-atomic: "npm:^5.0.1"
bin:
stylelint: bin/stylelint.mjs
- checksum: 10/0a7a697b066af36047fd02c952d59d5b26ac5db7f5772b75481310734c0e722970abb830d60460ea95afb618c51520cc09363dd9b83ae237afb0767b55fb0331
+ checksum: 10/81c6f97f9fb2ae31a9abc9f10ddbe595cde697e42cab56f7d745dda2e5378bd9e083f2c12f9d0082745c6283974ad0537bbc0ea71a1bf910fb4de836b1407bd9
languageName: node
linkType: hard
@@ -16969,13 +18074,13 @@ __metadata:
languageName: node
linkType: hard
-"supports-hyperlinks@npm:^3.1.0":
- version: 3.1.0
- resolution: "supports-hyperlinks@npm:3.1.0"
+"supports-hyperlinks@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "supports-hyperlinks@npm:3.0.0"
dependencies:
has-flag: "npm:^4.0.0"
supports-color: "npm:^7.0.0"
- checksum: 10/e893fb035ecd86e42c5225dc1cd24db56eb950ed77b2e8f59c7aaf2836b8b2ef276ffd11f0df88b0b12184832aa2333f875eefcb74d3c47ed2633b6b41d4be43
+ checksum: 10/911075a412d8bcfbbca413e8963d56ed0975e35ff98d599ef85301aed4221428653145263828b6c58cb4cb6ff24596be83ead3cca221a88a70428af93d5e2a73
languageName: node
linkType: hard
@@ -17007,6 +18112,16 @@ __metadata:
languageName: node
linkType: hard
+"synckit@npm:^0.8.6":
+ version: 0.8.8
+ resolution: "synckit@npm:0.8.8"
+ dependencies:
+ "@pkgr/core": "npm:^0.1.0"
+ tslib: "npm:^2.6.2"
+ checksum: 10/2864a5c3e689ad5b991bebbd8a583c5682c4fa08a4f39986b510b6b5d160c08fc3672444069f8f96ed6a9d12772879c674c1f61e728573eadfa90af40a765b74
+ languageName: node
+ linkType: hard
+
"synckit@npm:^0.9.1":
version: 0.9.1
resolution: "synckit@npm:0.9.1"
@@ -17153,6 +18268,16 @@ __metadata:
languageName: node
linkType: hard
+"timers-ext@npm:^0.1.7":
+ version: 0.1.8
+ resolution: "timers-ext@npm:0.1.8"
+ dependencies:
+ es5-ext: "npm:^0.10.64"
+ next-tick: "npm:^1.1.0"
+ checksum: 10/8abd168c57029e25d1fa4b7e101b053e261479e43ba4a32ead76e601e7037f74f850c311e22dc3dbb50dc211b34b092e0a349274d3997a493295e9ec725e6395
+ languageName: node
+ linkType: hard
+
"tiny-invariant@npm:^1.3.1, tiny-invariant@npm:^1.3.3":
version: 1.3.3
resolution: "tiny-invariant@npm:1.3.3"
@@ -17167,25 +18292,16 @@ __metadata:
languageName: node
linkType: hard
-"tldts-core@npm:^6.1.59":
- version: 6.1.59
- resolution: "tldts-core@npm:6.1.59"
- checksum: 10/0a3ed78384409aeb33e41d186f273ee423574f33947301746178fd9cdd5f730c647cbc27ef40b214a16101169d3f8b92384231064021887f1f25b6d70ac72aaf
- languageName: node
- linkType: hard
-
-"tldts@npm:^6.1.32":
- version: 6.1.59
- resolution: "tldts@npm:6.1.59"
+"tmp@npm:^0.0.33":
+ version: 0.0.33
+ resolution: "tmp@npm:0.0.33"
dependencies:
- tldts-core: "npm:^6.1.59"
- bin:
- tldts: bin/cli.js
- checksum: 10/c460c79fd110cf8fdac68fe4c084c4fb11c8a541880fc74c812189cf5d42bb16abe4acdaebd2d5dbff172cd87a2678b7f4a80cccf8b9e72d2378885b1a80a2c8
+ os-tmpdir: "npm:~1.0.2"
+ checksum: 10/09c0abfd165cff29b32be42bc35e80b8c64727d97dedde6550022e88fa9fd39a084660415ed8e3ebaa2aca1ee142f86df8b31d4196d4f81c774a3a20fd4b6abf
languageName: node
linkType: hard
-"tmp@npm:~0.2.3":
+"tmp@npm:~0.2.1":
version: 0.2.3
resolution: "tmp@npm:0.2.3"
checksum: 10/7b13696787f159c9754793a83aa79a24f1522d47b87462ddb57c18ee93ff26c74cbb2b8d9138f571d2e0e765c728fb2739863a672b280528512c6d83d511c6fa
@@ -17222,7 +18338,7 @@ __metadata:
languageName: node
linkType: hard
-"tough-cookie@npm:^4.1.2, tough-cookie@npm:^4.1.4":
+"tough-cookie@npm:^4.1.2, tough-cookie@npm:^4.1.3":
version: 4.1.4
resolution: "tough-cookie@npm:4.1.4"
dependencies:
@@ -17234,15 +18350,6 @@ __metadata:
languageName: node
linkType: hard
-"tough-cookie@npm:^5.0.0":
- version: 5.0.0
- resolution: "tough-cookie@npm:5.0.0"
- dependencies:
- tldts: "npm:^6.1.32"
- checksum: 10/a98d3846ed386e399e8b470c1eb08a6a296944246eabc55c9fe79d629bd2cdaa62f5a6572f271fe0060987906bd20468d72a219a3b4cbe51086bea48d2d677b6
- languageName: node
- linkType: hard
-
"tr46@npm:^3.0.0":
version: 3.0.0
resolution: "tr46@npm:3.0.0"
@@ -17259,22 +18366,6 @@ __metadata:
languageName: node
linkType: hard
-"tree-kill@npm:1.2.2":
- version: 1.2.2
- resolution: "tree-kill@npm:1.2.2"
- bin:
- tree-kill: cli.js
- checksum: 10/49117f5f410d19c84b0464d29afb9642c863bc5ba40fcb9a245d474c6d5cc64d1b177a6e6713129eb346b40aebb9d4631d967517f9fbe8251c35b21b13cd96c7
- languageName: node
- linkType: hard
-
-"treeverse@npm:^3.0.0":
- version: 3.0.0
- resolution: "treeverse@npm:3.0.0"
- checksum: 10/a053ad73f800c64c53ecf0effe7ea12e16eae1cf03f0901ac6b61390b6440d05d0aa8c942b6e77d2e9237d247b36fd405284942419f3817c9c3ef43bc5236218
- languageName: node
- linkType: hard
-
"ts-api-utils@npm:^1.3.0":
version: 1.3.0
resolution: "ts-api-utils@npm:1.3.0"
@@ -17329,6 +18420,18 @@ __metadata:
languageName: node
linkType: hard
+"tsconfig-paths@npm:^3.15.0":
+ version: 3.15.0
+ resolution: "tsconfig-paths@npm:3.15.0"
+ dependencies:
+ "@types/json5": "npm:^0.0.29"
+ json5: "npm:^1.0.2"
+ minimist: "npm:^1.2.6"
+ strip-bom: "npm:^3.0.0"
+ checksum: 10/2041beaedc6c271fc3bedd12e0da0cc553e65d030d4ff26044b771fac5752d0460944c0b5e680f670c2868c95c664a256cec960ae528888db6ded83524e33a14
+ languageName: node
+ linkType: hard
+
"tsconfig-paths@npm:^4.2.0":
version: 4.2.0
resolution: "tsconfig-paths@npm:4.2.0"
@@ -17340,7 +18443,7 @@ __metadata:
languageName: node
linkType: hard
-"tslib@npm:^1.13.0":
+"tslib@npm:^1.13.0, tslib@npm:^1.8.1":
version: 1.14.1
resolution: "tslib@npm:1.14.1"
checksum: 10/7dbf34e6f55c6492637adb81b555af5e3b4f9cc6b998fb440dac82d3b42bdc91560a35a5fb75e20e24a076c651438234da6743d139e4feabf0783f3cdfe1dddb
@@ -17368,6 +18471,17 @@ __metadata:
languageName: node
linkType: hard
+"tsutils@npm:^3.21.0":
+ version: 3.21.0
+ resolution: "tsutils@npm:3.21.0"
+ dependencies:
+ tslib: "npm:^1.8.1"
+ peerDependencies:
+ typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ checksum: 10/ea036bec1dd024e309939ffd49fda7a351c0e87a1b8eb049570dd119d447250e2c56e0e6c00554e8205760e7417793fdebff752a46e573fbe07d4f375502a5b2
+ languageName: node
+ linkType: hard
+
"tuf-js@npm:^2.2.1":
version: 2.2.1
resolution: "tuf-js@npm:2.2.1"
@@ -17411,6 +18525,13 @@ __metadata:
languageName: node
linkType: hard
+"type-fest@npm:^0.20.2":
+ version: 0.20.2
+ resolution: "type-fest@npm:0.20.2"
+ checksum: 10/8907e16284b2d6cfa4f4817e93520121941baba36b39219ea36acfe64c86b9dbc10c9941af450bd60832c8f43464974d51c0957f9858bc66b952b66b6914cbb9
+ languageName: node
+ linkType: hard
+
"type-fest@npm:^0.21.3":
version: 0.21.3
resolution: "type-fest@npm:0.21.3"
@@ -17463,6 +18584,13 @@ __metadata:
languageName: node
linkType: hard
+"type@npm:^2.7.2":
+ version: 2.7.3
+ resolution: "type@npm:2.7.3"
+ checksum: 10/82e99e7795b3de3ecfe685680685e79a77aea515fad9f60b7c55fbf6d43a5c360b1e6e9443354ec8906b38cdf5325829c69f094cb7cd2a1238e85bef9026dc04
+ languageName: node
+ linkType: hard
+
"typed-array-buffer@npm:^1.0.2":
version: 1.0.2
resolution: "typed-array-buffer@npm:1.0.2"
@@ -17515,6 +18643,15 @@ __metadata:
languageName: node
linkType: hard
+"typedarray-to-buffer@npm:^3.1.5":
+ version: 3.1.5
+ resolution: "typedarray-to-buffer@npm:3.1.5"
+ dependencies:
+ is-typedarray: "npm:^1.0.0"
+ checksum: 10/7c850c3433fbdf4d04f04edfc751743b8f577828b8e1eb93b95a3bce782d156e267d83e20fb32b3b47813e69a69ab5e9b5342653332f7d21c7d1210661a7a72c
+ languageName: node
+ linkType: hard
+
"typescript-eslint@npm:^8.5.0":
version: 8.5.0
resolution: "typescript-eslint@npm:8.5.0"
@@ -17718,6 +18855,13 @@ __metadata:
languageName: node
linkType: hard
+"universal-user-agent@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "universal-user-agent@npm:6.0.1"
+ checksum: 10/fdc8e1ae48a05decfc7ded09b62071f571c7fe0bd793d700704c80cea316101d4eac15cc27ed2bb64f4ce166d2684777c3198b9ab16034f547abea0d3aa1c93c
+ languageName: node
+ linkType: hard
+
"universal-user-agent@npm:^7.0.0, universal-user-agent@npm:^7.0.2":
version: 7.0.2
resolution: "universal-user-agent@npm:7.0.2"
@@ -17819,12 +18963,12 @@ __metadata:
languageName: node
linkType: hard
-"use-sync-external-store@npm:1.2.2":
- version: 1.2.2
- resolution: "use-sync-external-store@npm:1.2.2"
+"use-sync-external-store@npm:1.2.0":
+ version: 1.2.0
+ resolution: "use-sync-external-store@npm:1.2.0"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
- checksum: 10/671e9c190aab9a8374a5d468c6ba17f52c38b6fae970110bc196fc1e2b57204149aea9619be49a1bb5207fb6e51d8afd19c3bcb94afe61813fed039821461dc0
+ checksum: 10/a676216affc203876bd47981103f201f28c2731361bb186367e12d287a7566763213a8816910c6eb88265eccd4c230426eb783d64c373c4a180905be8820ed8e
languageName: node
linkType: hard
@@ -17884,7 +19028,7 @@ __metadata:
languageName: node
linkType: hard
-"uuid@npm:^9.0.0":
+"uuid@npm:^9.0.0, uuid@npm:^9.0.1":
version: 9.0.1
resolution: "uuid@npm:9.0.1"
bin:
@@ -17954,25 +19098,26 @@ __metadata:
linkType: hard
"vite-plugin-dts@npm:^4.0.2":
- version: 4.2.3
- resolution: "vite-plugin-dts@npm:4.2.3"
+ version: 4.0.2
+ resolution: "vite-plugin-dts@npm:4.0.2"
dependencies:
- "@microsoft/api-extractor": "npm:7.47.7"
+ "@microsoft/api-extractor": "npm:7.47.4"
"@rollup/pluginutils": "npm:^5.1.0"
- "@volar/typescript": "npm:^2.4.4"
- "@vue/language-core": "npm:2.1.6"
+ "@volar/typescript": "npm:^2.3.4"
+ "@vue/language-core": "npm:2.0.29"
compare-versions: "npm:^6.1.1"
debug: "npm:^4.3.6"
kolorist: "npm:^1.8.0"
local-pkg: "npm:^0.5.0"
magic-string: "npm:^0.30.11"
+ vue-tsc: "npm:2.0.29"
peerDependencies:
typescript: "*"
vite: "*"
peerDependenciesMeta:
vite:
optional: true
- checksum: 10/7031d3d2dff9aeb5f9378ec22b9deade7ea95608eb551a028c0232bac66ecfc079f94e9dff46cab5d60a41cbc1913b729f161c666ab305d011e326194514e76c
+ checksum: 10/7028ee320d4e743317d244c553524a3dbfbf871651ad59368a6a5fba71ff4778548ce109fa5348500ff7d55c6b64570cfe14207489bad9ba9ef04948d62fe40d
languageName: node
linkType: hard
@@ -17991,13 +19136,13 @@ __metadata:
linkType: hard
"vite@npm:^5.4.0":
- version: 5.4.11
- resolution: "vite@npm:5.4.11"
+ version: 5.4.0
+ resolution: "vite@npm:5.4.0"
dependencies:
esbuild: "npm:^0.21.3"
fsevents: "npm:~2.3.3"
- postcss: "npm:^8.4.43"
- rollup: "npm:^4.20.0"
+ postcss: "npm:^8.4.40"
+ rollup: "npm:^4.13.0"
peerDependencies:
"@types/node": ^18.0.0 || >=20.0.0
less: "*"
@@ -18029,7 +19174,7 @@ __metadata:
optional: true
bin:
vite: bin/vite.js
- checksum: 10/719c4dea896e9547958643354003c8c9ea98e5367196d98f5f46cffb3ec963fead3ea5853f5af941c79bbfb73583dec19bbb0d28d2f644b95d7f59c55e22919d
+ checksum: 10/5a98b1d30cc8c0263551f417a360102d40b78b9170e9e58a99c1a394ab700c7e604d3c52dafda323c11356a76eba865800d3d8588b33a8febdeaddd5a8981410
languageName: node
linkType: hard
@@ -18071,6 +19216,21 @@ __metadata:
languageName: node
linkType: hard
+"vue-tsc@npm:2.0.29":
+ version: 2.0.29
+ resolution: "vue-tsc@npm:2.0.29"
+ dependencies:
+ "@volar/typescript": "npm:~2.4.0-alpha.18"
+ "@vue/language-core": "npm:2.0.29"
+ semver: "npm:^7.5.4"
+ peerDependencies:
+ typescript: ">=5.0.0"
+ bin:
+ vue-tsc: ./bin/vue-tsc.js
+ checksum: 10/deabe919d3d3a9c9974791d91c32244c7e831a7d613a281e1e9a9f65bfaa917723883afda79d1d06b67f886dbd23cfdf3ec902a40674f907f0bb792e8eeab088
+ languageName: node
+ linkType: hard
+
"w3c-xmlserializer@npm:^4.0.0":
version: 4.0.0
resolution: "w3c-xmlserializer@npm:4.0.0"
@@ -18080,18 +19240,18 @@ __metadata:
languageName: node
linkType: hard
-"wait-on@npm:8.0.1":
- version: 8.0.1
- resolution: "wait-on@npm:8.0.1"
+"wait-on@npm:7.2.0":
+ version: 7.2.0
+ resolution: "wait-on@npm:7.2.0"
dependencies:
- axios: "npm:^1.7.7"
- joi: "npm:^17.13.3"
+ axios: "npm:^1.6.1"
+ joi: "npm:^17.11.0"
lodash: "npm:^4.17.21"
minimist: "npm:^1.2.8"
rxjs: "npm:^7.8.1"
bin:
wait-on: bin/wait-on
- checksum: 10/41f933031b994718dfb50af35bb843f7f7017d601ef22927e92c211736fadd21808fdbf7ae367e998bcaf995cb9c05cf6160552dc655db9082aeecc346bc926d
+ checksum: 10/00299e3b651c70d7082d02b93d9d4784cbe851914f1674d795d578d4826876193fdc7bee7e9491264b7c2d242ac9fe6e1fd09e1143409f730f13a7ee2da67fff
languageName: node
linkType: hard
@@ -18379,6 +19539,18 @@ __metadata:
languageName: node
linkType: hard
+"write-file-atomic@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "write-file-atomic@npm:3.0.3"
+ dependencies:
+ imurmurhash: "npm:^0.1.4"
+ is-typedarray: "npm:^1.0.0"
+ signal-exit: "npm:^3.0.2"
+ typedarray-to-buffer: "npm:^3.1.5"
+ checksum: 10/0955ab94308b74d32bc252afe69d8b42ba4b8a28b8d79f399f3f405969f82623f981e35d13129a52aa2973450f342107c06d86047572637584e85a1c0c246bf3
+ languageName: node
+ linkType: hard
+
"write-file-atomic@npm:^4.0.2":
version: 4.0.2
resolution: "write-file-atomic@npm:4.0.2"
@@ -18389,7 +19561,7 @@ __metadata:
languageName: node
linkType: hard
-"write-file-atomic@npm:^5.0.0, write-file-atomic@npm:^5.0.1":
+"write-file-atomic@npm:^5.0.1":
version: 5.0.1
resolution: "write-file-atomic@npm:5.0.1"
dependencies:
@@ -18399,6 +19571,18 @@ __metadata:
languageName: node
linkType: hard
+"write-json-file@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "write-json-file@npm:5.0.0"
+ dependencies:
+ detect-indent: "npm:^7.0.0"
+ is-plain-obj: "npm:^4.0.0"
+ sort-keys: "npm:^5.0.0"
+ write-file-atomic: "npm:^3.0.3"
+ checksum: 10/6df0e8857c6ebe091cf8d23fa3405f004e7febf10307ad3d4da7b1ddfe1fa80e7cdd9832d3a554e253b6d3a6255d67b66f419cea0f8724abb25949be392eb23b
+ languageName: node
+ linkType: hard
+
"write-json-file@npm:^6.0.0":
version: 6.0.0
resolution: "write-json-file@npm:6.0.0"
@@ -18411,6 +19595,19 @@ __metadata:
languageName: node
linkType: hard
+"write-package@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "write-package@npm:7.0.1"
+ dependencies:
+ deepmerge-ts: "npm:^5.1.0"
+ read-pkg: "npm:^9.0.0"
+ sort-keys: "npm:^5.0.0"
+ type-fest: "npm:^4.6.0"
+ write-json-file: "npm:^5.0.0"
+ checksum: 10/e4ac07ff5d240bf1eaa2dd587bfa2bdb13092ba2d36989edff2db197947ba0b573227c1f11f4b3c7dc1fc4431a97bd5fa9810e14136e9405cdcc8945ebe70263
+ languageName: node
+ linkType: hard
+
"write-package@npm:^7.1.0":
version: 7.1.0
resolution: "write-package@npm:7.1.0"
@@ -18439,6 +19636,15 @@ __metadata:
languageName: node
linkType: hard
+"xml-formatter@npm:^3.6.2":
+ version: 3.6.3
+ resolution: "xml-formatter@npm:3.6.3"
+ dependencies:
+ xml-parser-xo: "npm:^4.1.2"
+ checksum: 10/5089a30d179499f15760e4492d3dac21cce653e96375e56fc95769ec779d5ac8c9c465f2f78f41eb74391b6af5e8331040553c7194c1832e6627d663d3d41216
+ languageName: node
+ linkType: hard
+
"xml-name-validator@npm:^4.0.0":
version: 4.0.0
resolution: "xml-name-validator@npm:4.0.0"
@@ -18446,6 +19652,20 @@ __metadata:
languageName: node
linkType: hard
+"xml-name-validator@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "xml-name-validator@npm:5.0.0"
+ checksum: 10/43f30f3f6786e406dd665acf08cd742d5f8a46486bd72517edb04b27d1bcd1599664c2a4a99fc3f1e56a3194bff588b12f178b7972bc45c8047bdc4c3ac8d4a1
+ languageName: node
+ linkType: hard
+
+"xml-parser-xo@npm:^4.1.2":
+ version: 4.1.2
+ resolution: "xml-parser-xo@npm:4.1.2"
+ checksum: 10/e75387bdcaa03ddc53628e0b9697c7cc16ba11ed25afb5194a8d87f6c7aef2e879b00ceca64377e939f751414282e9b236e20031a6d0fe287981170ae217c34c
+ languageName: node
+ linkType: hard
+
"xmlchars@npm:^2.2.0":
version: 2.2.0
resolution: "xmlchars@npm:2.2.0"
@@ -18481,7 +19701,7 @@ __metadata:
languageName: node
linkType: hard
-"yaml@npm:^2.0.0, yaml@npm:^2.3.2":
+"yaml@npm:^2.0.0, yaml@npm:^2.3.2, yaml@npm:~2.4.2":
version: 2.4.5
resolution: "yaml@npm:2.4.5"
bin:
@@ -18490,15 +19710,6 @@ __metadata:
languageName: node
linkType: hard
-"yaml@npm:~2.5.0":
- version: 2.5.1
- resolution: "yaml@npm:2.5.1"
- bin:
- yaml: bin.mjs
- checksum: 10/0eecb679db75ea6a989ad97715a9fa5d946972945aa6aa7d2175bca66c213b5564502ccb1cdd04b1bf816ee38b5c43e4e2fda3ff6f5e09da24dabb51ae92c57d
- languageName: node
- linkType: hard
-
"yargs-parser@npm:^20.2.2":
version: 20.2.9
resolution: "yargs-parser@npm:20.2.9"
@@ -18589,10 +19800,10 @@ __metadata:
linkType: hard
"zustand@npm:^4.3.9":
- version: 4.5.5
- resolution: "zustand@npm:4.5.5"
+ version: 4.5.2
+ resolution: "zustand@npm:4.5.2"
dependencies:
- use-sync-external-store: "npm:1.2.2"
+ use-sync-external-store: "npm:1.2.0"
peerDependencies:
"@types/react": ">=16.8"
immer: ">=9.0.6"
@@ -18604,6 +19815,6 @@ __metadata:
optional: true
react:
optional: true
- checksum: 10/481b8210187b69678074a1ca51107654c2379688e90407bfcb7961e0803a259742bfd0d77171c3f07e290896ad55fe9659b3863f30d34cb2572650ead1249f25
+ checksum: 10/9e9e92ce7378c5de1d7682f4f10340a1c07a81b673ad0a125b59883a6ade3f2bf39eac6ccc5b05630f9df6ed925291f681592db59ccd3815685c2e83f67c8525
languageName: node
linkType: hard