Skip to content

Commit

Permalink
fix: Mapping line is not drawn
Browse files Browse the repository at this point in the history
Fixes: KaotoIO#360
Fixes: KaotoIO#363
  • Loading branch information
igarashitm committed Aug 1, 2024
1 parent 60c6c6f commit b1afd24
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 84 deletions.
27 changes: 23 additions & 4 deletions packages/ui/src/models/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export class NodePath {

export class Path {
constructor(
public expression: string,
public parent?: Path,
public readonly expression: string,
public readonly parent?: Path,
) {
this.isRelative = true;
let remainingExpression = this.expression;
Expand All @@ -56,7 +56,7 @@ export class Path {
this.parameterName = pos !== -1 ? remainingExpression.substring(1, pos) : remainingExpression.substring(1);
remainingExpression = pos !== -1 ? remainingExpression.substring(pos + 1) : '';
}
this.pathSegments = remainingExpression.split('/');
this.pathSegments = remainingExpression.split('/').map((segmentString) => new PathSegment(segmentString));
}

toString() {
Expand All @@ -76,5 +76,24 @@ export class Path {

isRelative: boolean;
parameterName?: string;
pathSegments: 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;
}
98 changes: 27 additions & 71 deletions packages/ui/src/services/mapping.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,79 +4,35 @@
//import { XmlSchemaDocumentService } from './xml-schema-document.service';
//import * as fs from 'node:fs';

describe('MappingService', () => {
it('TODO', () => {});
/*
const orderXsd = fs.readFileSync(__dirname + '/../../../../test-resources/ShipOrder.xsd').toString();
const sourceDoc = XmlSchemaDocumentService.createXmlSchemaDocument(
DocumentType.SOURCE_BODY,
'ShipOrder.xsd',
orderXsd,
);
const sourceParam = XmlSchemaDocumentService.createXmlSchemaDocument(DocumentType.PARAM, 'ShipOrder.xsd', orderXsd);
const targetDoc = XmlSchemaDocumentService.createXmlSchemaDocument(
DocumentType.TARGET_BODY,
'ShipOrder.xsd',
orderXsd,
);
describe('validateFieldPairForNewMapping()', () => {
it('validate mapping', () => {
const mapping = MappingService.createNewMapping(sourceDoc.fields[0], targetDoc.fields[0]);
const validated = MappingService.validateNodePairForMapping(
[mapping],
sourceDoc.fields[0].fields[0],
targetDoc.fields[0].fields[0],
);
expect(validated.sourceField?.fieldIdentifier.toString()).toEqual(sourceDoc.fields[0].fields[0].path.toString());
expect(validated.targetField?.fieldIdentifier.toString()).toEqual(targetDoc.fields[0].fields[0].path.toString());
});
it('invalidate duplicate mapping', () => {
const mapping = MappingService.createNewMapping(sourceDoc.fields[0], targetDoc.fields[0]);
let validated = MappingService.validateNodePairForMapping([mapping], sourceDoc.fields[0], targetDoc.fields[0]);
expect(validated.sourceField).toBeUndefined();
expect(validated.targetField).toBeUndefined();
validated = MappingService.validateNodePairForMapping([mapping], targetDoc.fields[0], sourceDoc.fields[0]);
expect(validated.sourceField).toBeUndefined();
expect(validated.targetField).toBeUndefined();
});
});
describe('createNewMapping', () => {
it('', () => {
const mapping = MappingService.createNewMapping(sourceDoc.fields[0], targetDoc.fields[0]);
expect(mapping.source.elements.length).toEqual(1);
expect(mapping.targetFields.length).toEqual(1);
});
});
import { MappingService } from './mapping.service';
import * as fs from 'fs';
import { TestUtil } from '../test/test-util';
import { MappingTree } from '../models/mapping';
import { MappingSerializerService } from './mapping-serializer.service';

describe('getMappingsFor', () => {
it('', () => {
const mapping1 = MappingService.createNewMapping(sourceDoc.fields[0].fields[0], targetDoc.fields[0].fields[0]);
const mapping2 = MappingService.createNewMapping(sourceDoc.fields[0].fields[1], targetDoc.fields[0].fields[1]);
const found = MappingService.getAllMappingsFor([mapping1, mapping2], sourceDoc.fields[0].fields[1]);
expect(found.length).toEqual(1);
expect((found[0].source.elements[0] as IFieldItem).field.fieldIdentifier.toString()).toEqual(
sourceDoc.fields[0].fields[1].fieldIdentifier.toString(),
);
});
});
describe('MappingService', () => {
const sourceDoc = TestUtil.createSourceOrderDoc();
const targetDoc = TestUtil.createTargetOrderDoc();
const paramsMap = TestUtil.createParameterMap();
const xsltFile = fs.readFileSync(__dirname + '/../../../../test-resources/ShipOrderToShipOrder.xsl').toString();

describe('removeMappingsForDocument', () => {
it('', () => {
const mapping1 = MappingService.createNewMapping(sourceDoc.fields[0].fields[0], targetDoc.fields[0].fields[0]);
const mapping2 = MappingService.createNewMapping(sourceParam.fields[0].fields[1], targetDoc.fields[0].fields[1]);
const cleaned = MappingService.removeAllMappingsForDocument(
[mapping1, mapping2],
sourceParam.documentType,
sourceParam.documentId,
);
expect(cleaned.length).toEqual(1);
expect((cleaned[0].source.elements[0] as IFieldItem).field.fieldIdentifier.toString()).toEqual(
sourceDoc.fields[0].fields[0].path.toString(),
);
describe('extractMappingLinks()', () => {
it('should return IMappingLink[]', () => {
const tree = new MappingTree(targetDoc.documentType, targetDoc.documentId);
MappingSerializerService.deserialize(xsltFile, targetDoc, tree, paramsMap);
const links = MappingService.extractMappingLinks(tree, paramsMap, sourceDoc);
expect(links.length).toEqual(5);
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-');
expect(links[2].targetNodePath).toMatch('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');
});
});
*/
});
12 changes: 10 additions & 2 deletions packages/ui/src/services/mapping.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ export class MappingService {
(document.documentType === DocumentType.SOURCE_BODY && !parsedPath.parameterName) ||
(document.documentType === DocumentType.PARAM && parsedPath.parameterName === document.documentId)
) {
return !DocumentService.getFieldFromPathSegments(document, parsedPath.pathSegments);
return !DocumentService.getFieldFromPathSegments(
document,
parsedPath.pathSegments.map((seg) => seg.name),
);
}
});
return !!stalePath;
Expand Down Expand Up @@ -332,7 +335,12 @@ export class MappingService {
return XPathService.extractFieldPaths(sourceXPath).reduce((acc, xpath) => {
const path = new Path(xpath);
const document = path.parameterName ? sourceParameterMap.get(path.parameterName) : sourceBody;
const sourceNodePath = document && DocumentService.getFieldFromPathSegments(document, path.pathSegments)?.path;
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[]);
Expand Down
30 changes: 23 additions & 7 deletions packages/ui/src/services/xpath/xpath.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,17 @@ export class XPathService {
if (!('children' in node.children.RelativePathExpr[0])) return answer;
const relativePathExpr = XPathService.getNode(node, ['RelativePathExpr']);
if (!relativePathExpr) return answer;
const varName = XPathService.getNode(relativePathExpr, ['StepExpr', 'FilterExpr', 'VarRef', 'QName', 'NCName']);
const contextItem = XPathService.getNode(relativePathExpr, ['StepExpr', 'FilterExpr', 'ContextItemExpr']);
const ncName = XPathService.getNode(relativePathExpr, ['StepExpr', 'NodeTest', 'NameTest', 'NCName']);
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 (ncName && 'image' in ncName) {
answer += ncName.image;
} else if (name) {
answer += name;
} else {
throw Error('Unknown RelativePathExpr: ' + relativePathExpr);
}
Expand All @@ -63,13 +65,27 @@ export class XPathService {
return following
? following.reduce((acc, value) => {
acc += '/';
const ncName = XPathService.getNode(value, ['StepExpr', 'NodeTest', 'NameTest', 'NCName']);
if (ncName && 'image' in ncName) acc += ncName.image;
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) {
const parsed = XPathService.parse(expression);
if (!parsed.cst) return [];
Expand Down

0 comments on commit b1afd24

Please sign in to comment.