From 216c058417c81250dac77737514540ed2b05ae3a Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 29 May 2026 00:37:04 +0200 Subject: [PATCH 1/5] feat: add null check for function parameters in getNodeFunction --- src/util/nodes.util.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/nodes.util.ts b/src/util/nodes.util.ts index fbe3a33..d97a64c 100644 --- a/src/util/nodes.util.ts +++ b/src/util/nodes.util.ts @@ -68,6 +68,10 @@ const createNodeFunctionIfCompatible = ( functions: FunctionDefinition[], paramType: ts.Type ): NodeFunction | null => { + + if (func.parameters.length > 0) + return null; + // Extract the function signature and its return type const signature = checker.getSignatureFromDeclaration(func); const returnType = checker.getReturnTypeOfSignature(signature!); From 3e7765383e9fabef58ada2f99519f226434cd525 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 29 May 2026 00:37:09 +0200 Subject: [PATCH 2/5] feat: update schema test to reflect changes in SubFlowValue structure --- test/schema/schema.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/schema/schema.test.ts b/test/schema/schema.test.ts index a082e31..489afb3 100644 --- a/test/schema/schema.test.ts +++ b/test/schema/schema.test.ts @@ -1,6 +1,6 @@ -import {describe, expect, it} from "vitest"; +import {describe, it} from "vitest"; import {Flow} from "@code0-tech/sagittarius-graphql-types"; -import {getFlowValidation, getSignatureSchema, getTypeSchema} from "../../src"; +import {getSignatureSchema, getTypeSchema} from "../../src"; import {DATA_TYPES, FUNCTION_SIGNATURES} from "../data"; describe("Schema", () => { @@ -36,8 +36,8 @@ describe("Schema", () => { }, { value: { - __typename: "NodeFunctionIdWrapper", - id: "gid://sagittarius/NodeFunction/3" + __typename: "SubFlowValue", + startingNodeId: "gid://sagittarius/NodeFunction/3" } } ] From 2cac9da864a7dc3a343b91972b45e635a35b9c11 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 29 May 2026 00:37:17 +0200 Subject: [PATCH 3/5] feat: extend suggestions type to include SubFlowValue and integrate getSubFlows function --- src/util/schema.util.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/util/schema.util.ts b/src/util/schema.util.ts index a7d25ca..5044857 100644 --- a/src/util/schema.util.ts +++ b/src/util/schema.util.ts @@ -2,7 +2,14 @@ import ts, {FunctionDeclaration} from "typescript"; import {getValues} from "./values.util"; import {getReferences} from "./references.util"; import {getNodes} from "./nodes.util"; -import {FunctionDefinition, LiteralValue, NodeFunction, ReferenceValue,} from "@code0-tech/sagittarius-graphql-types"; +import { + FunctionDefinition, + LiteralValue, + NodeFunction, + ReferenceValue, + SubFlowValue, +} from "@code0-tech/sagittarius-graphql-types"; +import {getSubFlows} from "./subflows.util"; /** @@ -13,7 +20,7 @@ export interface Input { /** The type of input (string representation) */ input?: string; /** Array of suggested values (functions, references, or literals) */ - suggestions?: (NodeFunction | ReferenceValue | LiteralValue)[]; + suggestions?: (NodeFunction | ReferenceValue | LiteralValue | SubFlowValue)[]; } /** @@ -135,6 +142,12 @@ export const getSchema = ( functions, parameterType ), + ...getSubFlows( + checker, + functionDeclarations, + functions, + parameterType + ), ], } : {}; From 0d898c66f092284e7fddd41b6e81e28a0ebfe848 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 29 May 2026 00:37:23 +0200 Subject: [PATCH 4/5] feat: implement getSubFlows utility function to create SubFlowValue from compatible function declarations --- src/util/subflows.util.ts | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/util/subflows.util.ts diff --git a/src/util/subflows.util.ts b/src/util/subflows.util.ts new file mode 100644 index 0000000..24fd1bc --- /dev/null +++ b/src/util/subflows.util.ts @@ -0,0 +1,96 @@ +import ts from "typescript"; +import {FunctionDefinition, SubFlowValue, SubFlowValueSetting} from "@code0-tech/sagittarius-graphql-types"; +import {isSubFlow} from "./schema.util"; + +export const getSubFlows = ( + checker: ts.TypeChecker, + functionDeclarations: ts.FunctionDeclaration[], + functions: FunctionDefinition[], + paramType: ts.Type +): SubFlowValue[] => { + + if (!isSubFlow(paramType)) { + return []; + } + + return functionDeclarations.flatMap((func) => { + const subFlow = createSubFlowIfCompatible(checker, func, functions, paramType); + return subFlow ? [subFlow] : []; + }); + +} + +const createSubFlowIfCompatible = ( + checker: ts.TypeChecker, + func: ts.FunctionDeclaration, + functions: FunctionDefinition[], + paramType: ts.Type +): SubFlowValue | null => { + + // 2. Hole den Typ der Funktion (nicht nur den Return Type!) + const functionType = checker.getTypeAtLocation(func); + + // 3. Prüfe ob functionType zu paramType assignierbar ist + // paramType ist z.B. (number: number) => void + // functionType sollte auch (number: number) => void (oder kompatibel) sein + if (!checker.isTypeAssignableTo(functionType, paramType)) { + return null; + } + + // 4. Wenn kompatibel: Erstelle SubFlowValue + const functionName = normalizeFunctionName(func.name?.getText()); + const functionDefinition = functions.find((f) => f.identifier === functionName); + + if (!functionDefinition) { + return null; + } + + return buildSubFlowValue(functionDefinition); + +} + +/** + * Normalizes a function name by removing prefixes and replacing underscores with + * double colons (::). + * + * This function applies the following transformations: + * 1. Removes the "fn_" prefix + * 2. Replaces the first underscore with "::" + * 3. Replaces the second underscore with "::" + * + * Example: "fn_module_submodule" becomes "module::submodule" + * + * @param {string | undefined} rawName - The raw function name from the declaration + * + * @returns {string} The normalized function name, or an empty string if the input + * is undefined + * + * @private + */ +const normalizeFunctionName = (rawName: string | undefined): string => { + if (!rawName) { + return ""; + } + return rawName + .replace("fn_", "") + .replace("_", "::") + .replace("_", "::"); +} + +const buildSubFlowValue = (functionDefinition: FunctionDefinition): SubFlowValue => { + return { + __typename: "SubFlowValue", + functionDefinition: functionDefinition, + signature: functionDefinition.signature, + settings: functionDefinition.parameterDefinitions?.nodes?.map(param => { + const setting: SubFlowValueSetting = { + __typename: "SubFlowValueSetting", + identifier: param?.identifier, + defaultValue: param?.defaultValue ?? null, + hidden: param?.hidden ?? false, + optional: param?.optional ?? false, + } + return setting + }) + } +} \ No newline at end of file From 718a1198c546f384c2ea02d38596737ff75918c1 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 29 May 2026 00:38:19 +0200 Subject: [PATCH 5/5] feat: add getSubFlows and createSubFlowIfCompatible functions to extract SubFlowValues from compatible function declarations --- src/util/subflows.util.ts | 56 +++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/src/util/subflows.util.ts b/src/util/subflows.util.ts index 24fd1bc..39669ca 100644 --- a/src/util/subflows.util.ts +++ b/src/util/subflows.util.ts @@ -2,6 +2,22 @@ import ts from "typescript"; import {FunctionDefinition, SubFlowValue, SubFlowValueSetting} from "@code0-tech/sagittarius-graphql-types"; import {isSubFlow} from "./schema.util"; +/** + * Extracts and creates a list of SubFlowValue objects from function declarations + * that are compatible with the given parameter type. + * + * This function filters function declarations based on type compatibility and + * converts matching functions into SubFlowValue objects that can be used as + * sub-flows in a larger workflow. + * + * @param {ts.TypeChecker} checker - The TypeScript type checker for type analysis + * @param {ts.FunctionDeclaration[]} functionDeclarations - Array of function declarations to analyze + * @param {FunctionDefinition[]} functions - Array of function definitions for reference lookup + * @param {ts.Type} paramType - The target parameter type that functions must be compatible with + * + * @returns {SubFlowValue[]} An array of SubFlowValue objects for compatible functions, + * or an empty array if the paramType is not a sub-flow type + */ export const getSubFlows = ( checker: ts.TypeChecker, functionDeclarations: ts.FunctionDeclaration[], @@ -20,6 +36,23 @@ export const getSubFlows = ( } +/** + * Verifies that a function declaration is compatible with a given parameter type + * and creates a SubFlowValue if the types match. + * + * Type compatibility is checked by comparing the function type against the expected + * parameter type (e.g., a function signature like (number: number) => void). + * If compatible, the function is converted into a SubFlowValue object with its + * associated parameter settings. + * + * @param {ts.TypeChecker} checker - The TypeScript type checker for type analysis + * @param {ts.FunctionDeclaration} func - The function declaration to check + * @param {FunctionDefinition[]} functions - Array of function definitions for lookup + * @param {ts.Type} paramType - The expected parameter type to check compatibility against + * + * @returns {SubFlowValue | null} A SubFlowValue object if the function is compatible + * with the paramType and a matching function definition exists, or null otherwise + */ const createSubFlowIfCompatible = ( checker: ts.TypeChecker, func: ts.FunctionDeclaration, @@ -27,17 +60,17 @@ const createSubFlowIfCompatible = ( paramType: ts.Type ): SubFlowValue | null => { - // 2. Hole den Typ der Funktion (nicht nur den Return Type!) + // Get the full function type from the declaration const functionType = checker.getTypeAtLocation(func); - // 3. Prüfe ob functionType zu paramType assignierbar ist - // paramType ist z.B. (number: number) => void - // functionType sollte auch (number: number) => void (oder kompatibel) sein + // Check if the function type is assignable to the parameter type + // This ensures the function signature matches the expected interface + // e.g., paramType might be (number: number) => void, and functionType should be compatible if (!checker.isTypeAssignableTo(functionType, paramType)) { return null; } - // 4. Wenn kompatibel: Erstelle SubFlowValue + // If type-compatible, find the function definition and create the SubFlowValue const functionName = normalizeFunctionName(func.name?.getText()); const functionDefinition = functions.find((f) => f.identifier === functionName); @@ -77,6 +110,19 @@ const normalizeFunctionName = (rawName: string | undefined): string => { .replace("_", "::"); } +/** + * Constructs a SubFlowValue object from a function definition. + * + * This function transforms a FunctionDefinition into a SubFlowValue with all + * its parameter settings properly configured. Each parameter from the function + * definition is converted into a SubFlowValueSetting object that includes + * metadata such as identifier, default values, hidden status, and optional status. + * + * @param {FunctionDefinition} functionDefinition - The function definition to convert + * + * @returns {SubFlowValue} A SubFlowValue object with the function definition + * and all parameter settings configured + */ const buildSubFlowValue = (functionDefinition: FunctionDefinition): SubFlowValue => { return { __typename: "SubFlowValue",