diff --git a/package-lock.json b/package-lock.json index f504776..670f696 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "@code0-tech/triangulum", "version": "0.1.0", "devDependencies": { - "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2414125487-fbc8a5ec8a2dd07cc76957d4315281c246e98d57", + "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2430052572-f89aa9d01636e56a17463920775d073b09dd132b", "@types/node": "^25.5.0", "@typescript/vfs": "^1.6.4", "typescript": "^6.0.2", @@ -17,7 +17,7 @@ "vitest": "^4.1.2" }, "peerDependencies": { - "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2414125487-fbc8a5ec8a2dd07cc76957d4315281c246e98d57", + "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2430052572-f89aa9d01636e56a17463920775d073b09dd132b", "@typescript/vfs": "^1.6.4", "typescript": "^5.9.3 || ^6.0.2" } @@ -73,9 +73,9 @@ } }, "node_modules/@code0-tech/sagittarius-graphql-types": { - "version": "0.0.0-experimental-2414125487-fbc8a5ec8a2dd07cc76957d4315281c246e98d57", - "resolved": "https://registry.npmjs.org/@code0-tech/sagittarius-graphql-types/-/sagittarius-graphql-types-0.0.0-experimental-2414125487-fbc8a5ec8a2dd07cc76957d4315281c246e98d57.tgz", - "integrity": "sha512-IRi0I6PLniH9ONZicXaMKaYEhdJn1cIDMrpPNCGWry0Ww6cGoU21mC3s88Ot/uGxPJ9VJJJjguVNQRc3w/FUwg==", + "version": "0.0.0-experimental-2430052572-f89aa9d01636e56a17463920775d073b09dd132b", + "resolved": "https://registry.npmjs.org/@code0-tech/sagittarius-graphql-types/-/sagittarius-graphql-types-0.0.0-experimental-2430052572-f89aa9d01636e56a17463920775d073b09dd132b.tgz", + "integrity": "sha512-2VszOdGXHQ9ECPQYCC76K/HHWXeG7PCUTiDHrfm60YO4IN2BnunKHIiPCDiVaDUqUfY+rQUNuOiX2GS87F/Hog==", "dev": true }, "node_modules/@emnapi/core": { @@ -753,9 +753,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -773,9 +770,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -793,9 +787,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -813,9 +804,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -833,9 +821,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -853,9 +838,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1460,6 +1442,7 @@ "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.18.0" } @@ -1943,6 +1926,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -2330,9 +2314,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2354,9 +2335,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2378,9 +2356,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2402,9 +2377,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2770,6 +2742,7 @@ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -2983,6 +2956,7 @@ "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3021,6 +2995,7 @@ "integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", diff --git a/package.json b/package.json index 20bee69..421ad79 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "build": "vite build" }, "devDependencies": { - "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2414125487-fbc8a5ec8a2dd07cc76957d4315281c246e98d57", + "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2430052572-f89aa9d01636e56a17463920775d073b09dd132b", "@types/node": "^25.5.0", "typescript": "^6.0.2", "vite": "^8.0.3", @@ -32,7 +32,7 @@ "@typescript/vfs": "^1.6.4" }, "peerDependencies": { - "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2414125487-fbc8a5ec8a2dd07cc76957d4315281c246e98d57", + "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2430052572-f89aa9d01636e56a17463920775d073b09dd132b", "typescript": "^5.9.3 || ^6.0.2", "@typescript/vfs": "^1.6.4" } diff --git a/src/suggestion/getReferenceSuggestions.ts b/src/suggestion/getReferenceSuggestions.ts index 1c8133c..f56bc0c 100644 --- a/src/suggestion/getReferenceSuggestions.ts +++ b/src/suggestion/getReferenceSuggestions.ts @@ -1,5 +1,12 @@ import ts from "typescript"; -import {DataType, Flow, FunctionDefinition, NodeFunction, ReferenceValue} from "@code0-tech/sagittarius-graphql-types"; +import { + DataType, + Flow, + FunctionDefinition, + NodeFunction, + ReferencePath, + ReferenceValue +} from "@code0-tech/sagittarius-graphql-types"; import {createCompilerHost, generateFlowSourceCode} from "../utils"; /** @@ -41,9 +48,9 @@ const extractObjectProperties = ( type: ts.Type, checker: ts.TypeChecker, expectedType: ts.Type, - currentPath: string[] = [] -): Array<{ path: string[]; type: ts.Type }> => { - const results: Array<{ path: string[]; type: ts.Type }> = []; + currentPath: ReferencePath[] = [] +): Array<{ path: ReferencePath[]; type: ts.Type }> => { + const results: Array<{ path: ReferencePath[]; type: ts.Type }> = []; // Add the current type if it matches the expected type if (checker.isTypeAssignableTo(type, expectedType)) { @@ -56,7 +63,7 @@ const extractObjectProperties = ( if (properties && properties.length > 0) { properties.forEach(property => { const propType = checker.getTypeOfSymbolAtLocation(property, property.valueDeclaration!); - const propName = property.getName(); + const propName = property.getName() as ReferencePath; const newPath = [...currentPath, propName]; // Recursively extract nested properties @@ -143,7 +150,7 @@ export const getReferenceSuggestions = ( allSymbols.forEach(symbol => { const name = symbol.getName(); - if (!name.startsWith("node_") && !name.startsWith("p_")) return; + if (!name.startsWith("node_") && !name.startsWith("p_") && !name.startsWith("flow_")) return; // Get the variable declaration const declaration = symbol.valueDeclaration || symbol.declarations?.[0]; @@ -175,7 +182,6 @@ export const getReferenceSuggestions = ( }; if (path.length > 0) { - //@ts-ignore referenceValue.referencePath = path; } @@ -211,12 +217,10 @@ export const getReferenceSuggestions = ( nodeFunctionId: nodeFunctionId as any, parameterIndex: isNaN(paramIndexFromName) ? 0 : paramIndexFromName, inputIndex: tupleIndex, - //@ts-ignore inputTypeIdentifier: (typeReference.target as any).labeledElementDeclarations?.[tupleIndex].name.getText() }; if (path.length > 0) { - //@ts-ignore referenceValue.referencePath = path; } @@ -225,6 +229,21 @@ export const getReferenceSuggestions = ( }); } } + else if (name.startsWith("flow_")) { + const propertyPaths = extractObjectProperties(symbolType, checker, expectedType) + propertyPaths.forEach(({ path }) => { + const referenceValue: ReferenceValue = { + __typename: 'ReferenceValue', + nodeFunctionId: null + }; + + if (path.length > 0) { + referenceValue.referencePath = path; + } + + referenceValues.push(referenceValue); + }) + } }); return referenceValues; diff --git a/src/utils.ts b/src/utils.ts index 611a64f..6322497 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -209,6 +209,7 @@ export function generateFlowSourceCode( }; const typeDefs = getSharedTypeDeclarations(dataTypes); + const flowTypeDeclaration = `declare function flow${flow?.signature ?? "(): void"}` const funcDeclarations = functions?.map(f => `declare function fn_${f.identifier?.replace(/::/g, '_')}${f.signature}`).join('\n'); const nextNodeIds = new Set(nodes.map(n => n?.nextNodeId).filter(id => !!id)); @@ -217,12 +218,14 @@ export function generateFlowSourceCode( if (p?.value?.__typename === "NodeFunctionIdWrapper" && p.value.id) subTreeIds.add(p.value.id); })); + const flowCode = flow ? `const flow_${sanitizeId(flow.id ?? "")} = flow(${flow.settings?.nodes?.map((setting, index) => `/* @pos undefined ${index} */ ${JSON.stringify(setting?.value)}`).join(", ") ?? ""});` : "" + const executionCode = nodes .filter(n => n?.id && !nextNodeIds.has(n.id) && !subTreeIds.has(n.id)) .map(n => generateNodeCode(n!.id!)) .join('\n'); - return `${typeDefs}\n${funcDeclarations}\n\n// --- Flow ---\n${executionCode}`; + return `${typeDefs}\n${flowTypeDeclaration}\n${funcDeclarations}\n\n// --- Flow ---\n${flowCode}\n${executionCode}`; } export interface InferredTypes { diff --git a/src/validation/getFlowValidation.ts b/src/validation/getFlowValidation.ts index 87a68c3..b2f1313 100644 --- a/src/validation/getFlowValidation.ts +++ b/src/validation/getFlowValidation.ts @@ -62,7 +62,7 @@ export const getFlowValidation = ( } if (closestMatch) { - nodeId = closestMatch[1] as NodeFunction['id']; + nodeId = closestMatch[1] === "undefined" ? undefined : closestMatch[1] as NodeFunction['id']; parameterIndex = parseInt(closestMatch[2], 10); } } diff --git a/test/flowValidation.test.ts b/test/flowValidation.test.ts index 2412099..d06b24e 100644 --- a/test/flowValidation.test.ts +++ b/test/flowValidation.test.ts @@ -1,6 +1,7 @@ import {describe, expect, it} from 'vitest'; import {getFlowValidation} from '../src/validation/getFlowValidation'; import {Flow} from "@code0-tech/sagittarius-graphql-types"; // Pfad ggf. anpassen +// @ts-ignore import {DATA_TYPES, FUNCTION_SIGNATURES} from "./data"; describe('getFlowValidation - Integrationstest', () => { @@ -69,7 +70,6 @@ describe('getFlowValidation - Integrationstest', () => { expect(result.isValid).toBe(true); expect(result.diagnostics).toHaveLength(0); result.diagnostics.forEach((error) => { - expect(error.nodeId).toBeDefined() expect(error.parameterIndex).toBeDefined() }) }); @@ -142,7 +142,6 @@ describe('getFlowValidation - Integrationstest', () => { expect(result.isValid).toBe(false); result.diagnostics.forEach((error) => { - expect(error.nodeId).toBeDefined() expect(error.parameterIndex).toBeDefined() }) }); @@ -192,7 +191,6 @@ describe('getFlowValidation - Integrationstest', () => { expect(result.isValid).toBe(true); expect(result.diagnostics).toHaveLength(0); result.diagnostics.forEach((error) => { - expect(error.nodeId).toBeDefined() expect(error.parameterIndex).toBeDefined() }) }); @@ -249,7 +247,6 @@ describe('getFlowValidation - Integrationstest', () => { expect(result.isValid).toBe(true); expect(result.diagnostics).toHaveLength(0); result.diagnostics.forEach((error) => { - expect(error.nodeId).toBeDefined() expect(error.parameterIndex).toBeDefined() }) }); @@ -261,8 +258,7 @@ describe('getFlowValidation - Integrationstest', () => { "id": "gid://sagittarius/Flow/1", "createdAt": "2026-03-17T14:02:31Z", "name": "Test", - "inputType": "REST_ADAPTER_INPUT", - "returnType": "HTTP_RESPONSE", + "signature": "(httpURL: HTTP_URL, httpMethod: HTTP_METHOD): REST_ADAPTER_INPUT<{}>", "nodes": { "__typename": "NodeFunctionConnection", "nodes": [ @@ -364,7 +360,6 @@ describe('getFlowValidation - Integrationstest', () => { expect(result.isValid).toBe(false); result.diagnostics.forEach((error) => { - expect(error.nodeId).toBeDefined() expect(error.parameterIndex).toBeDefined() }) }); @@ -376,8 +371,7 @@ describe('getFlowValidation - Integrationstest', () => { "id": "gid://sagittarius/Flow/1", "createdAt": "2026-03-17T14:02:31Z", "name": "Test", - "inputType": "REST_ADAPTER_INPUT", - "returnType": "HTTP_RESPONSE", + "signature": "(httpURL: HTTP_URL, httpMethod: HTTP_METHOD): REST_ADAPTER_INPUT<{}>", "nodes": { "__typename": "NodeFunctionConnection", "nodes": [ @@ -539,8 +533,6 @@ describe('getFlowValidation - Integrationstest', () => { expect(result.isValid).toBe(false); result.diagnostics.forEach((error) => { - - expect(error.nodeId).toBeDefined() expect(error.parameterIndex).toBeDefined() }) }); diff --git a/test/getReferenceSuggestions.test.ts b/test/getReferenceSuggestions.test.ts index 3e3d0f3..3a16782 100644 --- a/test/getReferenceSuggestions.test.ts +++ b/test/getReferenceSuggestions.test.ts @@ -10,8 +10,7 @@ describe('getReferenceSuggestions', () => { "id": "gid://sagittarius/Flow/1", "createdAt": "2026-03-17T14:02:31Z", "name": "Test", - "inputType": "REST_ADAPTER_INPUT", - "returnType": "HTTP_RESPONSE", + "signature": "(httpURL: HTTP_URL, httpMethod: HTTP_METHOD): REST_ADAPTER_INPUT<{}>", "nodes": { "__typename": "NodeFunctionConnection", "nodes": [ @@ -95,7 +94,7 @@ describe('getReferenceSuggestions', () => { "id": "gid://sagittarius/FlowSetting/1", "createdAt": "2026-03-17T14:17:48Z", "updatedAt": "2026-03-17T14:17:48Z", - "flowSettingIdentifier": "HTTP_METHOD", + "flowSettingIdentifier": "httpURL", "value": "" }, { @@ -103,7 +102,7 @@ describe('getReferenceSuggestions', () => { "id": "gid://sagittarius/FlowSetting/2", "createdAt": "2026-03-17T14:17:48Z", "updatedAt": "2026-03-17T14:17:48Z", - "flowSettingIdentifier": "HTTP_URL", + "flowSettingIdentifier": "httpMethod", "value": "" } ], @@ -137,8 +136,7 @@ describe('getReferenceSuggestions', () => { "id": "gid://sagittarius/Flow/1", "createdAt": "2026-03-17T14:02:31Z", "name": "Test", - "inputType": "REST_ADAPTER_INPUT", - "returnType": "HTTP_RESPONSE", + "signature": "(httpURL: HTTP_URL, httpMethod: HTTP_METHOD): REST_ADAPTER_INPUT<{}>", "nodes": { "__typename": "NodeFunctionConnection", "nodes": [