diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/CodeNode.svelte b/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/CodeNode.svelte index 88c0b33c..71822cc7 100644 --- a/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/CodeNode.svelte +++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/CodeNode.svelte @@ -22,22 +22,25 @@ let currentNode = useNodesData(currentNodeId); const { addParameter } = useAddParameter(); const { updateNodeData } = useSvelteFlow(); - const codeNodeHelp = `结果如何返回 -- 请把代码执行结果写到 _result 中。 -- JS:_result.answer = 'ok' -- Python:_result['answer'] = 'ok' + const codeNodeHelp = `JavaScript 如何返回结果 +- 定义 main 函数并返回对象,系统会自动执行。 +- main 接收由输入参数组成的对象。 输出参数如何配置 - 在“输出参数”中新增字段(如 answer、score)。 -- 字段名建议与 _result 的 key 保持一致,便于下游节点引用。 +- 字段名与 main 返回对象的 key 保持一致。 - 下游节点可引用:代码节点ID.输出参数名。 示例 - 代码里写: - _result.answer = '你好'; - _result.score = 95; + function main({ input }) { + return { answer: input, score: 95 }; + } - 输出参数配置:answer(String)、score(Number) -- 结束节点输出参数可引用:代码节点ID.answer、代码节点ID.score`; +- 结束节点输出参数可引用:代码节点ID.answer、代码节点ID.score + +兼容说明 +- 历史 JavaScript、Python 的 _result 写法仍然支持。`; const editorParameters = $derived.by(() => { return (currentNode?.current?.data?.parameters as Array) || data.parameters || []; @@ -115,7 +118,7 @@ { ).toBe(true); }); + it('should prefer main return snippets for javascript output', () => { + const completions = createBusinessCompletions('javascript', []); + const mainCompletion = completions.find((item) => item.label === 'main'); + const resultCompletion = completions.find( + (item) => item.label === 'result-object', + ); + + expect(mainCompletion).toMatchObject({ + type: 'snippet', + detail: '代码节点入口', + boost: 1000, + }); + expect(String(mainCompletion?.apply)).toContain('function main'); + expect(String(mainCompletion?.apply)).toContain('return {'); + expect(String(resultCompletion?.apply)).toBe( + "return { message: 'ok', data };", + ); + }); + it('should detect blocked nodes for comment/string/property contexts', () => { expect(shouldSkipBusinessCompletion('Comment')).toBe(true); expect(shouldSkipBusinessCompletion('LineComment')).toBe(true); diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/utils/codeCompletion.ts b/easyflow-ui-admin/packages/tinyflow-ui/src/components/utils/codeCompletion.ts index 448e92e1..fb03f4d8 100644 --- a/easyflow-ui-admin/packages/tinyflow-ui/src/components/utils/codeCompletion.ts +++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/utils/codeCompletion.ts @@ -30,21 +30,28 @@ const BLOCKED_NODE_NAMES = new Set([ ]); const JS_SNIPPETS: Array<{ label: string; insert: string; detail: string }> = [ + { + label: 'main', + detail: '代码节点入口', + insert: + 'function main({ input }) {\n return {\n output: input,\n };\n}', + }, { label: 'if-else', detail: '条件分支', insert: - 'if (condition) {\n _result.value = value;\n} else {\n _result.value = null;\n}', + 'if (condition) {\n return { value };\n}\nreturn { value: null };', }, { label: 'for-of', detail: '遍历数组', - insert: 'for (const item of items) {\n // TODO\n}\n_result.done = true;', + insert: + 'const result = [];\nfor (const item of items) {\n result.push(item);\n}\nreturn { result };', }, { label: 'result-object', detail: '返回对象', - insert: "_result.message = 'ok';\n_result.data = data;", + insert: "return { message: 'ok', data };", }, ]; @@ -99,7 +106,7 @@ export function createBusinessCompletions( const resultCompletion: Completion = { label: '_result', type: 'variable', - detail: '代码节点输出对象', + detail: '兼容旧版输出对象', boost: 900, }; @@ -118,7 +125,7 @@ export function createBusinessCompletions( type: 'snippet', detail: snippet.detail, apply: snippet.insert, - boost: 500, + boost: snippet.label === 'main' ? 1000 : 500, })); return dedupeCompletions([