Skip to content

Commit

Permalink
Merge pull request #350 from XpressAI/fahreza/fix-union-typechecks
Browse files Browse the repository at this point in the history
🐛 Union Type Fixes + More Smart Link Fixes
  • Loading branch information
MFA-X-AI authored Aug 8, 2024
2 parents 4749f31 + af89e7d commit 8aaf074
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 46 deletions.
7 changes: 4 additions & 3 deletions src/commands/NodeActionCommands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ export function addNodeActionCommands(
const parseUnionType = (type: string): string[] => {
const unionMatch = type.match(/^Union\[(.*)\]$/);
if (unionMatch) {
return unionMatch[1].split('|').map(t => t.trim());
return unionMatch[1].split(/[\|,]/).map(t => t.trim());
}
return [type];
};
Expand All @@ -483,8 +483,9 @@ export function addNodeActionCommands(
for (let inPortIndex in inPorts) {
const inPort = inPorts[inPortIndex];
const inPortName = inPort.getOptions()['name'];
const inPortLabel = inPort.getOptions()['label'];
const inPortType = inPort.getOptions()['dataType'];
// handler for compulsory [★] ports
const inPortLabel = inPort.getOptions()['label'].replace(//g, '');
const inPortType = inPort.getOptions()['dataType'] ?? '';
const inPortLabelArr: string[] = inPortLabel.split('_');
const inPortTypes = parseUnionType(inPortType);
// Compare if there is similarity for each word
Expand Down
2 changes: 1 addition & 1 deletion src/components/port/CustomPortLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export class CustomPortLabel extends React.Component<CustomPortLabelProps> {
} else {
portType = portName.split("-")[1];
}
if (portType.includes(',')) {
if (portType.includes('Union')) {
portType = 'union';
}

Expand Down
111 changes: 69 additions & 42 deletions src/components/port/CustomPortModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,21 @@ export class CustomPortModel extends DefaultPortModel {
if (!port.canLinkToLinkedPort()) {
return false;
}

let canParameterLinkToPort = this.canParameterLinkToPort(this, port);

if(canParameterLinkToPort == false){
console.log("Parameter Link To Port failed.");
return false;
}

let canTriangleLinkToTriangle = this.canTriangleLinkToTriangle(this, port);

if (canTriangleLinkToTriangle == false){
port.getNode().getOptions().extras["borderColor"]="red";
port.getNode().getOptions().extras["tip"]="Triangle must be linked to triangle.";
port.getNode().setSelected(true);
console.log("triangle to triangle failed.");
//tested
return false;

// Check if it's a triangle-to-triangle link
if (this.options.label.includes('▶') || port.getOptions().label.includes('▶')) {
if (!this.canTriangleLinkToTriangle(this, port)) {
port.getNode().getOptions().extras["borderColor"]="red";
port.getNode().getOptions().extras["tip"]="Triangle must be linked to triangle.";
port.getNode().setSelected(true);
console.log("triangle to triangle failed.");
return false;
}
} else {
// Then check if it's a parameter link
if (!this.canParameterLinkToPort(this, port)) {
return false;
}
}

let checkLinkDirection = this.checkLinkDirection(this, port);
Expand Down Expand Up @@ -131,20 +129,21 @@ export class CustomPortModel extends DefaultPortModel {
if (this.isParameterNode(thisNodeModelType) == true){

if (!thisName.startsWith("parameter")){
targetPort.getNode().getOptions().extras["borderColor"]="red";
targetPort.getNode().getOptions().extras["tip"]= `Port ${thisLabel} linked is not a parameter, please link a non parameter node to it.`;
targetPort.getNode().getOptions().extras["borderColor"] = "red";
targetPort.getNode().getOptions().extras["tip"] = `Port ${thisLabel} linked is not a parameter, please link a ${thisLabel} node to it.`;
targetPort.getNode().setSelected(true);
return false;
}
}

let sourceDataType = thisPort.dataType;

// Use thisNodeModelType if sourceDataType is an empty string due to old workflow
let sourceDataType = thisPort.dataType || thisNodeModelType;
let targetDataType = targetPort.dataType;

if(!targetPort.isTypeCompatible(sourceDataType, targetDataType)) {
// if a list of types is provided for the port, parse it a bit to display it nicer
if (targetDataType.includes(',')) {
targetDataType = this.parsePortType(targetDataType);
if (targetDataType.includes('Union')) {
targetDataType = this.parseUnionPortType(targetDataType);
}
targetPort.getNode().getOptions().extras["borderColor"] = "red";
targetPort.getNode().getOptions().extras["tip"] = `Incorrect data type. Port ${thisLabel} is of type *\`${targetDataType}\`*. You have provided type *\`${sourceDataType}\`*.`;
Expand All @@ -164,26 +163,54 @@ export class CustomPortModel extends DefaultPortModel {
"chat": ["list"],
"secret": ["string", "int", "float"],
};

isTypeCompatible(sourceDataType, targetDataType) {
// Check for direct compatibility or 'any' type
if (sourceDataType === targetDataType || sourceDataType === 'any' || targetDataType === 'any') {
return true;

// Helper function to parse Union types
parseUnionType = (type: string): string[] => {
const unionMatch = type.match(/^Union\[(.*)\]$/);
if (unionMatch) {
return unionMatch[1].split(/[\|,]/).map(t => t.trim());
}
return [type];
}

// Helper function to map common types
mapCommonTypes = (type: string): string => {
const typeMapping = {
"str": "string",
"bool": "boolean",
"int": "integer",
};
return typeMapping[type] || type;
}
isTypeCompatible(sourceDataType, targetDataType) {
// Helper function to check type compatibility including Union types
const checkTypeCompatibility = (sourceDataTypes, targetDataTypes) => {
for (const sourceDataType of sourceDataTypes) {
for (const targetDataType of targetDataTypes) {
if (sourceDataType === targetDataType || sourceDataType === 'any' || targetDataType === 'any') {
return true;
}

// Check if the sourceDataType exists in the compatibility map
if (CustomPortModel.typeCompatibilityMap.hasOwnProperty(sourceDataType)) {
// Get the array of compatible data types for sourceDataType
const compatibleDataTypes = CustomPortModel.typeCompatibilityMap[sourceDataType];

// Check if targetDataType is in the array of compatible types
if (compatibleDataTypes.includes(targetDataType)) {
return true;
// Check if the sourceDataType exists in the compatibility map
if (CustomPortModel.typeCompatibilityMap.hasOwnProperty(sourceDataType)) {
// Get the array of compatible data types for sourceDataType
const compatibleDataTypes = CustomPortModel.typeCompatibilityMap[sourceDataType];
// Check if targetDataType is in the array of compatible types
if (compatibleDataTypes.includes(targetDataType)) {
return true;
}
}
}
}
}

// If multiple types are accepted by target node port, check if source port type is among them
if (targetDataType.includes(sourceDataType)) {
return false;
};

// Parse and map Union types
const sourceDataTypes = this.parseUnionType(sourceDataType).map(this.mapCommonTypes);
const targetDataTypes = this.parseUnionType(targetDataType).map(this.mapCommonTypes);

// Check for direct compatibility or 'any' type
if (checkTypeCompatibility(sourceDataTypes, targetDataTypes)) {
return true;
}

Expand Down Expand Up @@ -349,11 +376,11 @@ export class CustomPortModel extends DefaultPortModel {
* Parsed type looks like: type1 or type2
* @param portType - unparsed port type (looks like: "Union[type1, type2]")
*/
parsePortType = (portType: string) => {
parseUnionPortType = (portType: string) => {
// port type is of form: Union[type1, type2]
portType = portType.replace('Union', ''); // remove Union word
portType = portType.replace(/[\[\]]/g, ''); // remove square brackets
portType = portType.replace(',', ' or ');
portType = portType.replace(/[,|]/g, ' or '); // replace all commas and pipes with ' or '
return portType;
}

Expand Down

0 comments on commit 8aaf074

Please sign in to comment.