feat: 优化代码节点 main 编写体验
- 更新代码节点帮助、占位示例与补全片段 - 保留 _result 旧版兼容提示并补充补全测试
This commit is contained in:
@@ -22,22 +22,25 @@
|
|||||||
let currentNode = useNodesData(currentNodeId);
|
let currentNode = useNodesData(currentNodeId);
|
||||||
const { addParameter } = useAddParameter();
|
const { addParameter } = useAddParameter();
|
||||||
const { updateNodeData } = useSvelteFlow();
|
const { updateNodeData } = useSvelteFlow();
|
||||||
const codeNodeHelp = `结果如何返回
|
const codeNodeHelp = `JavaScript 如何返回结果
|
||||||
- 请把代码执行结果写到 _result 中。
|
- 定义 main 函数并返回对象,系统会自动执行。
|
||||||
- JS:_result.answer = 'ok'
|
- main 接收由输入参数组成的对象。
|
||||||
- Python:_result['answer'] = 'ok'
|
|
||||||
|
|
||||||
输出参数如何配置
|
输出参数如何配置
|
||||||
- 在“输出参数”中新增字段(如 answer、score)。
|
- 在“输出参数”中新增字段(如 answer、score)。
|
||||||
- 字段名建议与 _result 的 key 保持一致,便于下游节点引用。
|
- 字段名与 main 返回对象的 key 保持一致。
|
||||||
- 下游节点可引用:代码节点ID.输出参数名。
|
- 下游节点可引用:代码节点ID.输出参数名。
|
||||||
|
|
||||||
示例
|
示例
|
||||||
- 代码里写:
|
- 代码里写:
|
||||||
_result.answer = '你好';
|
function main({ input }) {
|
||||||
_result.score = 95;
|
return { answer: input, score: 95 };
|
||||||
|
}
|
||||||
- 输出参数配置:answer(String)、score(Number)
|
- 输出参数配置:answer(String)、score(Number)
|
||||||
- 结束节点输出参数可引用:代码节点ID.answer、代码节点ID.score`;
|
- 结束节点输出参数可引用:代码节点ID.answer、代码节点ID.score
|
||||||
|
|
||||||
|
兼容说明
|
||||||
|
- 历史 JavaScript、Python 的 _result 写法仍然支持。`;
|
||||||
|
|
||||||
const editorParameters = $derived.by(() => {
|
const editorParameters = $derived.by(() => {
|
||||||
return (currentNode?.current?.data?.parameters as Array<any>) || data.parameters || [];
|
return (currentNode?.current?.data?.parameters as Array<any>) || data.parameters || [];
|
||||||
@@ -115,7 +118,7 @@
|
|||||||
<CodeScriptEditor
|
<CodeScriptEditor
|
||||||
mode="textarea"
|
mode="textarea"
|
||||||
rows={10}
|
rows={10}
|
||||||
placeholder="请输入执行代码,注:输出内容需添加到_result中,如:_result['key'] = value 或者 _result.key = value"
|
placeholder={'请输入代码,例如:function main({ input }) { return { output: input }; }'}
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
engine={(data.engine as string) || (defaultEngine as string)}
|
engine={(data.engine as string) || (defaultEngine as string)}
|
||||||
parameters={editorParameters}
|
parameters={editorParameters}
|
||||||
|
|||||||
@@ -52,6 +52,25 @@ describe('codeCompletion utils', () => {
|
|||||||
).toBe(true);
|
).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', () => {
|
it('should detect blocked nodes for comment/string/property contexts', () => {
|
||||||
expect(shouldSkipBusinessCompletion('Comment')).toBe(true);
|
expect(shouldSkipBusinessCompletion('Comment')).toBe(true);
|
||||||
expect(shouldSkipBusinessCompletion('LineComment')).toBe(true);
|
expect(shouldSkipBusinessCompletion('LineComment')).toBe(true);
|
||||||
|
|||||||
@@ -30,21 +30,28 @@ const BLOCKED_NODE_NAMES = new Set([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const JS_SNIPPETS: Array<{ label: string; insert: string; detail: string }> = [
|
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',
|
label: 'if-else',
|
||||||
detail: '条件分支',
|
detail: '条件分支',
|
||||||
insert:
|
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',
|
label: 'for-of',
|
||||||
detail: '遍历数组',
|
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',
|
label: 'result-object',
|
||||||
detail: '返回对象',
|
detail: '返回对象',
|
||||||
insert: "_result.message = 'ok';\n_result.data = data;",
|
insert: "return { message: 'ok', data };",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -99,7 +106,7 @@ export function createBusinessCompletions(
|
|||||||
const resultCompletion: Completion = {
|
const resultCompletion: Completion = {
|
||||||
label: '_result',
|
label: '_result',
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
detail: '代码节点输出对象',
|
detail: '兼容旧版输出对象',
|
||||||
boost: 900,
|
boost: 900,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -118,7 +125,7 @@ export function createBusinessCompletions(
|
|||||||
type: 'snippet',
|
type: 'snippet',
|
||||||
detail: snippet.detail,
|
detail: snippet.detail,
|
||||||
apply: snippet.insert,
|
apply: snippet.insert,
|
||||||
boost: 500,
|
boost: snippet.label === 'main' ? 1000 : 500,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return dedupeCompletions([
|
return dedupeCompletions([
|
||||||
|
|||||||
Reference in New Issue
Block a user