diff --git a/src/validation/getFlowValidation.ts b/src/validation/getFlowValidation.ts index 0ef915f..36e6e17 100644 --- a/src/validation/getFlowValidation.ts +++ b/src/validation/getFlowValidation.ts @@ -39,6 +39,25 @@ export const getFlowValidation = ( } } + const functionIdentifiers = new Set(functions?.map(f => f.identifier)); + const unreachableFunctionDiagnostics = (flow.nodes?.nodes ?? []) + .filter(n => n?.functionDefinition && !functionIdentifiers.has(n.functionDefinition.identifier)) + .map(n => ({ + nodeId: n!.id, + parameterIndex: null, + code: 0, + message: `The function definition "${n!.functionDefinition!.identifier}" is not reachable.`, + severity: "error" as const, + })); + + if (unreachableFunctionDiagnostics.length > 0) { + return { + isValid: false, + returnType: "void", + diagnostics: unreachableFunctionDiagnostics, + } + } + const sourceCode = generateFlowSourceCode(flow, functions, dataTypes); // 3. Virtual TypeScript Compilation diff --git a/test/flowValidation.test.ts b/test/flowValidation.test.ts index 00dd401..5ae0fda 100644 --- a/test/flowValidation.test.ts +++ b/test/flowValidation.test.ts @@ -934,10 +934,19 @@ describe('getFlowValidation - Integrationstest', () => { const result = getFlowValidation(flow, FUNCTION_SIGNATURES, DATA_TYPES); - expect(result.isValid).toBe(true); - result.diagnostics.forEach((error) => { - expect(error.parameterIndex).toBeDefined() - }) + expect(result.isValid).toBe(false); + expect(result.diagnostics).toEqual(expect.arrayContaining([ + expect.objectContaining({ + nodeId: "gid://sagittarius/NodeFunction/1", + message: 'The function definition "http::response::create" is not reachable.', + severity: "error", + }), + expect.objectContaining({ + nodeId: "gid://sagittarius/NodeFunction/4", + message: 'The function definition "http::response::create" is not reachable.', + severity: "error", + }), + ])); }); it('11', () => { @@ -1278,4 +1287,43 @@ describe('getFlowValidation - Integrationstest', () => { }) }); + it('fails when a node references an unreachable function definition', () => { + + const flow: Flow = { + startingNodeId: "gid://sagittarius/NodeFunction/1", + nodes: { + nodes: [ + { + id: "gid://sagittarius/NodeFunction/1", + functionDefinition: {identifier: "std::number::add"}, + parameters: { + nodes: [ + {value: {__typename: "LiteralValue", value: 1}}, + {value: {__typename: "LiteralValue", value: 2}} + ] + }, + nextNodeId: "gid://sagittarius/NodeFunction/2" + }, + { + id: "gid://sagittarius/NodeFunction/2", + functionDefinition: {identifier: "std::imaginary::nonexistent"}, + parameters: {nodes: []} + } + ] + } + }; + + const result = getFlowValidation(flow, FUNCTION_SIGNATURES, DATA_TYPES); + + expect(result.isValid).toBe(false); + expect(result.diagnostics).toEqual([ + expect.objectContaining({ + nodeId: "gid://sagittarius/NodeFunction/2", + parameterIndex: null, + message: 'The function definition "std::imaginary::nonexistent" is not reachable.', + severity: "error", + }) + ]); + }); + }); \ No newline at end of file