diff --git a/packages/nodes-base/nodes/Code/Code.node.ts b/packages/nodes-base/nodes/Code/Code.node.ts index f7712364d3..8efebfa528 100644 --- a/packages/nodes-base/nodes/Code/Code.node.ts +++ b/packages/nodes-base/nodes/Code/Code.node.ts @@ -92,8 +92,9 @@ export class Code implements INodeType { const nodeMode = this.getNodeParameter('mode', 0) as CodeExecutionMode; const workflowMode = this.getMode(); + const node = this.getNode(); const language: CodeNodeEditorLanguage = - this.getNode()?.typeVersion === 2 + node.typeVersion === 2 ? (this.getNodeParameter('language', 0) as CodeNodeEditorLanguage) : 'javaScript'; const codeParameterName = language === 'python' ? 'pythonCode' : 'jsCode'; @@ -107,16 +108,16 @@ export class Code implements INodeType { context.item = context.$input.item; } - if (language === 'python') { - context.printOverwrite = workflowMode === 'manual' ? this.sendMessageToUI : null; - return new PythonSandbox(context, code, index, this.helpers); - } else { - const sandbox = new JavaScriptSandbox(context, code, index, workflowMode, this.helpers); - if (workflowMode === 'manual') { - sandbox.vm.on('console.log', this.sendMessageToUI); - } - return sandbox; - } + const Sandbox = language === 'python' ? PythonSandbox : JavaScriptSandbox; + const sandbox = new Sandbox(context, code, index, this.helpers); + sandbox.on( + 'output', + workflowMode === 'manual' + ? this.sendMessageToUI + : (...args) => + console.log(`[Workflow "${this.getWorkflow().id}"][Node "${node.name}"]`, ...args), + ); + return sandbox; }; // ---------------------------------- diff --git a/packages/nodes-base/nodes/Code/JavaScriptSandbox.ts b/packages/nodes-base/nodes/Code/JavaScriptSandbox.ts index 6980281d58..ce52de4232 100644 --- a/packages/nodes-base/nodes/Code/JavaScriptSandbox.ts +++ b/packages/nodes-base/nodes/Code/JavaScriptSandbox.ts @@ -1,6 +1,5 @@ -import type { NodeVMOptions } from 'vm2'; import { NodeVM, makeResolverFromLegacyOptions } from 'vm2'; -import type { IExecuteFunctions, INodeExecutionData, WorkflowExecuteMode } from 'n8n-workflow'; +import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow'; import { ValidationError } from './ValidationError'; import { ExecutionError } from './ExecutionError'; @@ -20,23 +19,13 @@ export const vmResolver = makeResolverFromLegacyOptions({ builtin: builtIn?.split(',') ?? [], }); -const getSandboxOptions = ( - context: SandboxContext, - workflowMode: WorkflowExecuteMode, -): NodeVMOptions => ({ - console: workflowMode === 'manual' ? 'redirect' : 'inherit', - sandbox: context, - require: vmResolver, -}); - export class JavaScriptSandbox extends Sandbox { - readonly vm: NodeVM; + private readonly vm: NodeVM; constructor( context: SandboxContext, private jsCode: string, itemIndex: number | undefined, - workflowMode: WorkflowExecuteMode, helpers: IExecuteFunctions['helpers'], ) { super( @@ -49,7 +38,13 @@ export class JavaScriptSandbox extends Sandbox { itemIndex, helpers, ); - this.vm = new NodeVM(getSandboxOptions(context, workflowMode)); + this.vm = new NodeVM({ + console: 'redirect', + sandbox: context, + require: vmResolver, + }); + + this.vm.on('console.log', (...args: unknown[]) => this.emit('output', ...args)); } async runCodeAllItems(): Promise { diff --git a/packages/nodes-base/nodes/Code/PythonSandbox.ts b/packages/nodes-base/nodes/Code/PythonSandbox.ts index cda9b1f80e..8be5e188b2 100644 --- a/packages/nodes-base/nodes/Code/PythonSandbox.ts +++ b/packages/nodes-base/nodes/Code/PythonSandbox.ts @@ -67,10 +67,7 @@ export class PythonSandbox extends Sandbox { globalsDict.set(key, value); } - await pyodide.runPythonAsync(` -if 'printOverwrite' in globals(): - print = printOverwrite - `); + pyodide.setStdout({ batched: (str) => this.emit('output', str) }); const runCode = ` async def __main(): diff --git a/packages/nodes-base/nodes/Code/Sandbox.ts b/packages/nodes-base/nodes/Code/Sandbox.ts index 8345a1263e..2c7152b963 100644 --- a/packages/nodes-base/nodes/Code/Sandbox.ts +++ b/packages/nodes-base/nodes/Code/Sandbox.ts @@ -1,3 +1,4 @@ +import { EventEmitter } from 'events'; import { ValidationError } from './ValidationError'; import { isObject } from './utils'; @@ -31,12 +32,14 @@ export function getSandboxContext(this: IExecuteFunctions, index: number): Sandb }; } -export abstract class Sandbox { +export abstract class Sandbox extends EventEmitter { constructor( private textKeys: SandboxTextKeys, protected itemIndex: number | undefined, protected helpers: IExecuteFunctions['helpers'], - ) {} + ) { + super(); + } abstract runCodeAllItems(): Promise; diff --git a/packages/nodes-base/nodes/Code/test/Code.node.test.ts b/packages/nodes-base/nodes/Code/test/Code.node.test.ts index 770295d1a1..04318b056e 100644 --- a/packages/nodes-base/nodes/Code/test/Code.node.test.ts +++ b/packages/nodes-base/nodes/Code/test/Code.node.test.ts @@ -20,6 +20,7 @@ describe('Test Code Node', () => { describe('Code Node unit test', () => { const node = new Code(); const thisArg = mock({ + getNode: () => mock(), helpers: { normalizeItems }, prepareOutputData: NodeHelpers.prepareOutputData, });