diff --git a/loader/fixture/a-imports-moved-b-visual-local/a.flyde b/loader/fixture/a-imports-moved-b-visual-local/a.flyde new file mode 100644 index 00000000..a96a69fd --- /dev/null +++ b/loader/fixture/a-imports-moved-b-visual-local/a.flyde @@ -0,0 +1,33 @@ +imports: + "./moved/b.flyde": AddOne +node: + id: TestMovedLocalVisualImport + inputs: + n: + mode: required + type: number + outputs: + r: + type: number + instances: + - id: addOneInst + nodeId: AddOne + inputConfig: {} + pos: + x: 200 + y: 100 + connections: + - from: + insId: __this + pinId: n + to: + insId: addOneInst + pinId: n + - from: + insId: addOneInst + pinId: r + to: + insId: __this + pinId: r + inputsPosition: {} + outputsPosition: {} diff --git a/loader/fixture/a-imports-moved-b-visual-local/moved/Add.flyde.js b/loader/fixture/a-imports-moved-b-visual-local/moved/Add.flyde.js new file mode 100644 index 00000000..d1bd6426 --- /dev/null +++ b/loader/fixture/a-imports-moved-b-visual-local/moved/Add.flyde.js @@ -0,0 +1,12 @@ +module.exports = { + id: "Add", + inputs: { + a: { mode: "required", type: "number" }, + }, + outputs: { + r: "number", + }, + run: (inputs, outputs) => { + outputs.r.next(inputs.a + 1); + }, +}; diff --git a/loader/fixture/a-imports-moved-b-visual-local/moved/b.flyde b/loader/fixture/a-imports-moved-b-visual-local/moved/b.flyde new file mode 100644 index 00000000..50044819 --- /dev/null +++ b/loader/fixture/a-imports-moved-b-visual-local/moved/b.flyde @@ -0,0 +1,33 @@ +imports: + "./Add.flyde.js": Add +node: + id: AddOne + inputs: + n: + mode: required + type: number + outputs: + r: + type: number + instances: + - id: plus1 + nodeId: Add + inputConfig: {} + pos: + x: 200 + y: 100 + connections: + - from: + insId: __this + pinId: n + to: + insId: plus1 + pinId: a + - from: + insId: plus1 + pinId: r + to: + insId: __this + pinId: r + inputsPosition: {} + outputsPosition: {} diff --git a/loader/src/resolver/server/findReferencedNodeServer.spec.ts b/loader/src/resolver/server/findReferencedNodeServer.spec.ts index 2913922f..265808ef 100644 --- a/loader/src/resolver/server/findReferencedNodeServer.spec.ts +++ b/loader/src/resolver/server/findReferencedNodeServer.spec.ts @@ -96,5 +96,5 @@ describe("findReferencedNodeServer", () => { }); function getFixturePath(path: string) { - return join(__dirname, "../../fixture", path); + return join(__dirname, "../../../fixture", path); } diff --git a/loader/src/resolver/server/findReferencedNodeServer.ts b/loader/src/resolver/server/findReferencedNodeServer.ts index ecfc88f6..cadae5a3 100644 --- a/loader/src/resolver/server/findReferencedNodeServer.ts +++ b/loader/src/resolver/server/findReferencedNodeServer.ts @@ -2,12 +2,14 @@ import { CodeNode, FlydeNode, isCodeNode, + isVisualNode, NodeInstance, AdvancedCodeNode, + VisualNode, } from "@flyde/core"; import * as _Nodes from "@flyde/nodes/dist/all"; -import { join } from "path"; +import { dirname, join, relative } from "path"; import { existsSync, readFileSync } from "fs"; import { resolveImportablePaths } from "./resolveImportablePaths"; import { deserializeFlowByPath } from "../../serdes"; @@ -50,8 +52,10 @@ export function createServerReferencedNodeFinder( if (isVisual) { try { const node = deserializeFlowByPath(path).node; - // No longer adding sourcePath - return { ...node, sourcePath: path }; + return { + ...rebaseFileNodeSources(node, path, fullFlowPath), + sourcePath: path, + }; } catch (e) { return []; } @@ -145,7 +149,7 @@ export function createServerReferencedNodeFinder( `Node ID mismatch: expected ${instance.nodeId} but found ${node.id} in ${fullFilePath}` ); } - return node as unknown as FlydeNode; + return rebaseFileNodeSources(node, fullFilePath, fullFlowPath) as unknown as FlydeNode; } // Update editorComponentBundlePath if it exists @@ -200,6 +204,51 @@ export function createServerReferencedNodeFinder( }; } +function rebaseFileNodeSources( + node: VisualNode, + sourceFlowPath: string, + targetFlowPath: string +): VisualNode { + const sourceDir = dirname(sourceFlowPath); + const targetDir = dirname(targetFlowPath); + + return { + ...node, + instances: node.instances.map((instance) => { + if (instance.source?.type === "file") { + const absoluteSourcePath = join(sourceDir, instance.source.data); + return { + ...instance, + source: { + ...instance.source, + data: relative(targetDir, absoluteSourcePath), + }, + }; + } + + if ( + instance.type === "visual" && + instance.source.type === "inline" && + isVisualNode(instance.source.data) + ) { + return { + ...instance, + source: { + ...instance.source, + data: rebaseFileNodeSources( + instance.source.data, + sourceFlowPath, + targetFlowPath + ), + }, + }; + } + + return instance; + }), + }; +} + function getLocalOrPackagePaths(fullFlowPath: string, importPath: string) { const fullImportPath = join(fullFlowPath, "..", importPath); diff --git a/loader/src/resolver/server/resolveFlowSever.spec.ts b/loader/src/resolver/server/resolveFlowSever.spec.ts index a6c66c56..02bfcef0 100644 --- a/loader/src/resolver/server/resolveFlowSever.spec.ts +++ b/loader/src/resolver/server/resolveFlowSever.spec.ts @@ -16,7 +16,7 @@ import { spiedOutput } from "@flyde/core/dist/test-utils"; import _ = require("lodash"); import { resolveVisualNode } from "../resolveVisualNode"; -const getFixturePath = (path: string) => join(__dirname, "../../fixture", path); +const getFixturePath = (path: string) => join(__dirname, "../../../fixture", path); describe("resolver", () => { it("resolves a blank .flyde file without any instances", () => { @@ -196,6 +196,28 @@ describe("resolver", () => { assert.equal(s.lastCall.args[0], 3); }).timeout(100); + it("resolves nested local imports relative to a moved visual node file", async () => { + const data = resolveFlowByPath( + getFixturePath("a-imports-moved-b-visual-local/a.flyde") + ); + const [s, r] = spiedOutput(); + const n = dynamicNodeInput(); + execute({ + node: data, + inputs: { n }, + outputs: { r }, + onBubbleError: (e) => { + console.error("Error in test:", e); + }, + }); + + n.subject.next(2); + + await new Promise(resolve => setTimeout(resolve, 50)); + + assert.equal(s.lastCall.args[0], 3); + }).timeout(100); + it("breaks on invalid schemas", () => { const invalidsRoot = getFixturePath("schema-validation/invalid"); const invalids = readdirSync(invalidsRoot);