n8n-nodes-python-raw
Version:
🚨 WARNING: 100% AI-GENERATED EXPERIMENTAL CODE - HIGH RISK! Use at own risk, not for production. Python execution for n8n with file processing, multiple credentials, debug tools. Personal use only - Commons Clause license.
1,046 lines (1,027 loc) • 144 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateCodeTemplateStatic = exports.PythonFunction = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const child_process_1 = require("child_process");
const fs = require("fs");
const path = require("path");
const tempy = require("tempy");
function getNodeVersionFromPackage() {
try {
let packageJson;
try {
packageJson = require('../../../package.json');
}
catch (e1) {
try {
packageJson = require('../../package.json');
}
catch (e2) {
console.warn('Could not load package.json dynamically, using fallback version');
return 14;
}
}
const version = packageJson.version;
const versionParts = version.split('.');
return parseInt(versionParts[1], 10) || 1;
}
catch (error) {
console.warn('Failed to read package version, using fallback version 14');
return 14;
}
}
async function cleanupScript(scriptPath) {
try {
if (fs.existsSync(scriptPath)) {
fs.unlinkSync(scriptPath);
console.log(`Cleaned up script: ${scriptPath}`);
}
}
catch (error) {
console.warn(`Failed to cleanup script ${scriptPath}:`, error);
}
}
function detectBinaryFiles(items) {
const binaryFiles = [];
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
const item = items[itemIndex];
if (item.binary) {
for (const [key, binaryData] of Object.entries(item.binary)) {
if (binaryData && binaryData.data && binaryData.fileName) {
binaryFiles.push({
key,
data: {
data: binaryData.data,
fileName: binaryData.fileName,
mimeType: binaryData.mimeType || 'application/octet-stream',
fileExtension: binaryData.fileExtension,
},
itemIndex,
});
}
}
}
}
return binaryFiles;
}
function validateFile(binaryFile, options) {
const buffer = Buffer.from(binaryFile.data.data, 'base64');
const sizeInMB = buffer.length / (1024 * 1024);
if (sizeInMB > options.maxFileSize) {
throw new Error(`File "${binaryFile.data.fileName}" is too large: ${sizeInMB.toFixed(2)}MB > ${options.maxFileSize}MB`);
}
console.log(`File "${binaryFile.data.fileName}" validated: ${sizeInMB.toFixed(2)}MB, type: ${binaryFile.data.mimeType}`);
}
function getFileExtension(filename) {
const extension = path.extname(filename).toLowerCase();
return extension.startsWith('.') ? extension.substring(1) : extension;
}
function sanitizeFileName(filename) {
return filename.replace(/[<>:"/\\|?*\x00-\x1f]/g, '_').substring(0, 255);
}
async function createTemporaryFiles(binaryFiles, options) {
const fileMappings = [];
for (const binaryFile of binaryFiles) {
try {
validateFile(binaryFile, options);
const buffer = Buffer.from(binaryFile.data.data, 'base64');
const extension = getFileExtension(binaryFile.data.fileName);
const sanitizedFileName = sanitizeFileName(binaryFile.data.fileName);
const fileMapping = {
filename: binaryFile.data.fileName,
mimetype: binaryFile.data.mimeType,
size: buffer.length,
binaryKey: binaryFile.key,
itemIndex: binaryFile.itemIndex,
extension,
};
if (options.accessMethod === 'base64' || options.accessMethod === 'both') {
fileMapping.base64Data = binaryFile.data.data;
}
if (options.accessMethod === 'temp_files' || options.accessMethod === 'both') {
const tempPath = tempy.file({
extension: extension || 'bin',
});
await fs.promises.writeFile(tempPath, binaryFile.data.data, 'base64');
fileMapping.tempPath = tempPath;
console.log(`Created temporary file: ${tempPath} (${(buffer.length / 1024).toFixed(1)}KB)`);
}
fileMappings.push(fileMapping);
}
catch (error) {
console.error(`Failed to process file "${binaryFile.data.fileName}":`, error);
throw new Error(`File processing failed for "${binaryFile.data.fileName}": ${error.message}`);
}
}
return fileMappings;
}
async function cleanupTemporaryFiles(fileMappings) {
let cleanedCount = 0;
let errorCount = 0;
for (const fileMapping of fileMappings) {
if (fileMapping.tempPath) {
try {
if (fs.existsSync(fileMapping.tempPath)) {
await fs.promises.unlink(fileMapping.tempPath);
cleanedCount++;
}
}
catch (error) {
errorCount++;
console.warn(`Failed to cleanup temporary file: ${fileMapping.tempPath}`, error);
}
}
}
if (cleanedCount > 0) {
console.log(`Cleaned up ${cleanedCount} temporary files`);
}
if (errorCount > 0) {
console.warn(`Failed to cleanup ${errorCount} temporary files`);
}
}
class PythonFunction {
constructor() {
this.description = {
displayName: 'Python Function (Raw)',
name: 'pythonFunctionRaw',
icon: 'fa:code',
group: ['transform'],
version: getNodeVersionFromPackage(),
description: 'Run custom Python script once and return raw output (exitCode, stdout, stderr)',
defaults: {
name: 'PythonFunctionRaw',
color: '#4B8BBE',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'pythonEnvVars',
required: false,
},
],
properties: [
{
displayName: 'Credentials Management',
name: 'credentialsManagement',
type: 'collection',
default: {},
placeholder: 'Add Credential Options',
description: 'Configure how credentials are included in the Python script',
options: [
{
displayName: 'Use Default Credential',
name: 'useDefaultCredential',
type: 'boolean',
default: true,
description: 'Include the credential selected in "Credential to connect with" dropdown above',
},
{
displayName: 'Multiple Credentials Method',
name: 'multipleCredentialsMethod',
type: 'options',
options: [
{
name: 'None (Use Default Only)',
value: 'none',
description: 'Use only the default credential from "Credential to connect with"',
},
{
name: 'Credential Names List',
value: 'names_list',
description: 'Enter credential names as comma-separated text',
},
{
name: 'Additional Credential Selectors',
value: 'selectors',
description: 'Use multiple credential selector dropdowns',
},
{
name: 'Dynamic Credential Collection',
value: 'collection',
description: 'Add/remove credential selectors dynamically',
},
{
name: 'JSON Configuration',
value: 'json_config',
description: 'Define credentials using JSON configuration',
},
],
default: 'none',
description: 'Choose how to add multiple credentials to the script',
},
{
displayName: 'Credential Names',
name: 'credentialNamesList',
type: 'string',
default: '',
placeholder: 'credential1, credential2, credential3',
description: 'Enter credential names separated by commas (must match exact credential names)',
displayOptions: {
show: {
multipleCredentialsMethod: ['names_list'],
},
},
},
{
displayName: 'Additional Credential 1',
name: 'additionalCredential1',
type: 'string',
default: '',
placeholder: 'Enter credential name',
description: 'Enter name of first additional Python Environment Variables credential',
displayOptions: {
show: {
multipleCredentialsMethod: ['selectors'],
},
},
},
{
displayName: 'Additional Credential 2',
name: 'additionalCredential2',
type: 'string',
default: '',
placeholder: 'Enter credential name',
description: 'Enter name of second additional Python Environment Variables credential',
displayOptions: {
show: {
multipleCredentialsMethod: ['selectors'],
},
},
},
{
displayName: 'Additional Credential 3',
name: 'additionalCredential3',
type: 'string',
default: '',
placeholder: 'Enter credential name',
description: 'Enter name of third additional Python Environment Variables credential',
displayOptions: {
show: {
multipleCredentialsMethod: ['selectors'],
},
},
},
{
displayName: 'Credential Collection',
name: 'credentialCollection',
type: 'fixedCollection',
default: { credentials: [] },
typeOptions: {
multipleValues: true,
},
description: 'Add multiple credentials dynamically',
displayOptions: {
show: {
multipleCredentialsMethod: ['collection'],
},
},
options: [
{
displayName: 'Credentials',
name: 'credentials',
values: [
{
displayName: 'Credential Name',
name: 'credentialName',
type: 'string',
default: '',
placeholder: 'Enter credential name',
description: 'Enter name of Python Environment Variables credential',
},
{
displayName: 'Variable Prefix',
name: 'variablePrefix',
type: 'string',
default: '',
placeholder: 'API1_, PROD_, etc.',
description: 'Optional prefix to add to all variables from this credential',
},
],
},
],
},
{
displayName: 'JSON Configuration',
name: 'jsonConfiguration',
type: 'json',
default: '{\n "credentials": [\n {\n "name": "credential1",\n "prefix": "API1_"\n },\n {\n "name": "credential2",\n "prefix": "PROD_"\n }\n ],\n "mergeStrategy": "last_wins"\n}',
description: 'Define credentials configuration in JSON format',
displayOptions: {
show: {
multipleCredentialsMethod: ['json_config'],
},
},
},
{
displayName: 'Variable Merge Strategy',
name: 'mergeStrategy',
type: 'options',
options: [
{
name: 'Last Selected Wins',
value: 'last_wins',
description: 'If variables have same name, last credential wins',
},
{
name: 'First Selected Wins',
value: 'first_wins',
description: 'If variables have same name, first credential wins',
},
{
name: 'Prefix with Source',
value: 'prefix_source',
description: 'Add credential name prefix to variables (e.g., CRED1_API_KEY)',
},
{
name: 'Skip Conflicts',
value: 'skip_conflicts',
description: 'Skip variables that would conflict (keep first occurrence)',
},
],
default: 'last_wins',
description: 'How to handle variable name conflicts between credentials',
displayOptions: {
show: {
multipleCredentialsMethod: ['names_list', 'selectors', 'collection'],
},
},
},
{
displayName: 'Hide Variable Values in Generated Script',
name: 'hideVariableValues',
type: 'boolean',
default: false,
description: 'Replace variable values with asterisks in generated scripts (for security)',
},
],
},
{
displayName: 'Python Code',
name: 'functionCode',
typeOptions: {
alwaysOpenEditWindow: true,
rows: 15,
},
type: 'string',
default: `# Example: Use with "Inject Variables" enabled (default)
# Environment and credentials variables are available as individual variables
# Control what's included via Script Generation Options
import json
import sys
# Input data from previous nodes (if "Include input_items Array" enabled)
print("Input items count:", len(input_items))
# Environment variables are available individually:
# MY_API_KEY, DB_HOST, PORT, etc. (from credentials or system env)
# Binary files from previous nodes (if "File Processing" enabled)
if 'input_files' in globals() and input_files:
print(f"Found {len(input_files)} files:")
for file_info in input_files:
filename = file_info['filename']
size_mb = file_info['size'] / (1024 * 1024)
file_type = file_info['extension']
print(f" - {filename} ({size_mb:.2f}MB, type: {file_type})")
# Access file content
if 'temp_path' in file_info:
# Read via temporary file path (recommended)
file_path = file_info['temp_path']
with open(file_path, 'rb') as f:
content = f.read()
print(f" Read {len(content)} bytes from {file_path}")
elif 'base64_data' in file_info:
# Read via base64 data
import base64
content = base64.b64decode(file_info['base64_data'])
print(f" Decoded {len(content)} bytes from base64")
# Legacy env_vars dict (if "Include env_vars Dictionary" enabled)
# print("Environment variables in dict:", len(env_vars))
result = {"processed_count": len(input_items), "status": "success"}
if 'input_files' in globals():
result["files_processed"] = len(input_files)
print(json.dumps(result))
# ===== OR =====
# Disable "Inject Variables" to run pure Python code:
#
# import requests # pip install requests
# response = requests.get("https://api.github.com/users/octocat")
# print(response.json())
`,
description: 'Python script to execute. Use "Inject Variables" option to access input_items and env_vars.',
noDataExpression: true,
},
{
displayName: 'Code Template Mode',
name: 'codeTemplateMode',
type: 'boolean',
default: false,
description: 'Enable code template extraction to view auto-generated Python code structure',
},
{
displayName: 'Extract Code Template',
name: 'extractCodeTemplate',
type: 'options',
noDataExpression: true,
options: [],
default: '',
typeOptions: {
loadOptionsMethod: 'generateCodeTemplate',
},
displayOptions: {
show: {
codeTemplateMode: [true],
},
},
description: '🔄 Click the refresh button to generate code template based on current node settings',
},
{
displayName: 'Auto-Generated Code Template',
name: 'autoGeneratedCode',
type: 'string',
displayOptions: {
show: {
codeTemplateMode: [true],
},
},
typeOptions: {
alwaysOpenEditWindow: false,
rows: 20,
editor: 'code',
editorLanguage: 'python',
},
default: `# ===== AUTO-GENERATED PYTHON CODE TEMPLATE =====
# This template shows the code structure that n8n automatically generates
# around your Python code.
#
# 🔄 IMPORTANT: Click the refresh button above to generate the current template
# based on your node settings (Script Generation Options, File Processing, etc.)
#
# The template will show:
# • Environment variables from credentials (as individual Python variables)
# • Input data from previous nodes (if "Include input_items Array" is enabled)
# • Binary file processing variables (if "File Processing" is enabled)
# • Output directory for generated files (if "Output File Processing" is enabled)
# • All necessary imports and boilerplate code
# Example template structure:
#!/usr/bin/env python3
# Auto-generated script for n8n Python Function (Raw)
import json
import sys
# Environment variables (from credentials and system)
API_KEY = "your_api_key_here" # From: main_credential
DATABASE_URL = "postgresql://user:pass@host:5432/db" # From: main_credential
DEBUG = "true" # From: main_credential
# Input data from previous nodes
input_items = [
{"id": 1, "name": "Sample Item 1", "status": "active"},
{"id": 2, "name": "Sample Item 2", "status": "pending"}
]
# Binary files from previous nodes (if File Processing enabled)
input_files = [
{
"filename": "example.txt",
"mimetype": "text/plain",
"size": 1024,
"extension": "txt",
"temp_path": "/tmp/example.txt",
"base64_data": "ZXhhbXBsZSBjb250ZW50"
}
]
# Output directory for generated files (if Output File Processing enabled)
output_dir = r"/tmp/n8n_output_YYYYMMDD_HHMMSS_random"
expected_filename = "result.json"
output_file_path = r"/tmp/n8n_output_YYYYMMDD_HHMMSS_random/result.json"
# === YOUR PYTHON CODE WOULD GO HERE ===
# 🔄 Click "Extract Code Template" button above to see the ACTUAL template
# generated for your current node configuration!`,
description: 'Shows the auto-generated Python code template with current node settings. Click the refresh button above to update with your current configuration.',
placeholder: 'Click "Extract Code Template" button above to generate current template...',
},
{
displayName: 'Inject Variables',
name: 'injectVariables',
type: 'boolean',
default: false,
description: 'Whether to inject input_items and env_vars variables. Enable for n8n integration features. Disable for pure Python scripts (recommended).',
},
{
displayName: 'Python Executable',
name: 'pythonPath',
type: 'string',
default: 'python3',
description: 'Path to Python executable (python3, python, or full path)',
},
{
displayName: 'Error Handling',
name: 'errorHandling',
type: 'options',
options: [
{
name: 'Return Error Details',
value: 'details',
description: 'Continue execution and return error information as output data (default behavior)',
},
{
name: 'Throw Error on Non-Zero Exit',
value: 'throw',
description: 'Stop workflow execution if script exits with non-zero code or system error occurs',
},
{
name: 'Ignore Exit Code',
value: 'ignore',
description: 'Continue execution regardless of exit code, only throw on system errors',
},
],
default: 'details',
description: 'How to handle Python script errors and non-zero exit codes',
},
{
displayName: 'Debug/Test Mode',
name: 'debugMode',
type: 'options',
options: [
{
name: 'Off',
value: 'off',
description: 'Normal execution without debug information (default)',
},
{
name: 'Basic Debug',
value: 'basic',
description: 'Add script content and basic execution info to output',
},
{
name: 'Full Debug',
value: 'full',
description: 'Add script content, metadata, timing, and detailed execution info',
},
{
name: 'Test Only',
value: 'test',
description: 'Validate script and show preview without executing (safe testing)',
},
{
name: 'Export Script',
value: 'export',
description: 'Full debug information plus script file as binary attachment',
},
],
default: 'off',
description: 'Choose debug and testing options for script development and troubleshooting',
},
{
displayName: 'Script Export Format',
name: 'scriptExportFormat',
type: 'options',
displayOptions: {
show: {
debugMode: ['export'],
},
},
options: [
{
name: 'Python File (.py)',
value: 'py',
description: 'Export as .py file (standard Python script format)',
},
{
name: 'Text File (.txt)',
value: 'txt',
description: 'Export as .txt file (useful when .py files are blocked by security policies)',
},
],
default: 'py',
description: 'Choose the file format for script export in debug mode',
},
{
displayName: 'Script Generation Options',
name: 'scriptOptions',
type: 'collection',
default: {},
placeholder: 'Add Option',
options: [
{
displayName: 'Include input_items Array',
name: 'includeInputItems',
type: 'boolean',
default: true,
description: 'Include input_items array in script (for accessing input data from previous nodes)',
},
{
displayName: 'Include env_vars Dictionary',
name: 'includeEnvVarsDict',
type: 'boolean',
default: false,
description: 'Include env_vars dictionary in script (for legacy compatibility - variables are already available individually)',
},
{
displayName: 'System Environment Variables',
name: 'systemEnvVars',
type: 'multiOptions',
default: [],
description: 'Select system environment variables to include in the script',
options: [],
typeOptions: {
loadOptionsMethod: 'getSystemEnvVars',
},
},
],
},
{
displayName: 'File Processing',
name: 'fileProcessing',
type: 'collection',
default: {},
placeholder: 'Add File Options',
description: 'Configure processing of binary files from previous nodes',
options: [
{
displayName: 'Enable File Processing',
name: 'enabled',
type: 'boolean',
default: false,
description: 'Automatically extract binary files from input and make them available in Python script',
},
{
displayName: 'File Access Method',
name: 'accessMethod',
type: 'options',
options: [
{
name: 'Temporary Files (Recommended)',
value: 'temp_files',
description: 'Save files to temporary paths accessible in script',
},
{
name: 'Base64 Content',
value: 'base64',
description: 'Provide file content as base64 strings',
},
{
name: 'Both Methods',
value: 'both',
description: 'Provide both temporary file paths and base64 content',
},
],
default: 'temp_files',
description: 'How to provide file access in the Python script',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Max File Size (MB)',
name: 'maxFileSize',
type: 'number',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
default: 100,
description: 'Maximum file size to process (1-1000 MB)',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Include File Metadata',
name: 'includeMetadata',
type: 'boolean',
default: true,
description: 'Include file metadata (size, mimetype, etc.) in script variables',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Auto-cleanup Temporary Files',
name: 'autoCleanup',
type: 'boolean',
default: true,
description: 'Automatically delete temporary files after script execution',
displayOptions: {
show: {
enabled: [true],
accessMethod: ['temp_files', 'both'],
},
},
},
],
},
{
displayName: 'Output File Processing',
name: 'outputFileProcessing',
type: 'collection',
default: {},
placeholder: 'Add Output File Options',
description: 'Configure automatic detection and processing of files generated by Python script',
options: [
{
displayName: 'Enable Output File Processing',
name: 'enabled',
type: 'boolean',
default: false,
description: 'Automatically detect and process files created by Python script in output directory',
},
{
displayName: 'Max Output File Size (MB)',
name: 'maxOutputFileSize',
type: 'number',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
default: 100,
description: 'Maximum output file size to process (1-1000 MB)',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Auto-cleanup Output Directory',
name: 'autoCleanupOutput',
type: 'boolean',
default: true,
description: 'Automatically delete output directory and files after processing',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Include File Metadata in Output',
name: 'includeOutputMetadata',
type: 'boolean',
default: true,
description: 'Include file metadata (size, mimetype, etc.) in output JSON',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Auto-Intercept File Operations',
name: 'autoInterceptFiles',
type: 'boolean',
default: true,
description: 'Automatically redirect all file write operations to output directory (works with any script without modification)',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Expected Output Filename',
name: 'expectedFileName',
type: 'string',
default: 'result.json',
placeholder: 'report.pdf, data.csv, result.json, etc.',
description: 'Filename you expect the Python script to create (required for automatic file detection)',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'File Detection Mode',
name: 'fileDetectionMode',
type: 'options',
options: [
{
name: 'Ready Variable Path',
value: 'variable_path',
description: 'Add output_file_path variable with full path to your script (recommended)',
},
{
name: 'Auto Search by Name',
value: 'auto_search',
description: 'Automatically find file by name after script execution',
},
],
default: 'variable_path',
description: 'How to provide the output file path to your Python script',
displayOptions: {
show: {
enabled: [true],
},
},
},
],
},
{
displayName: 'Parse Output',
name: 'parseOutput',
type: 'options',
options: [
{
name: 'None (Raw String)',
value: 'none',
description: 'Return stdout as raw string',
},
{
name: 'JSON',
value: 'json',
description: 'Parse stdout as JSON object',
},
{
name: 'Lines',
value: 'lines',
description: 'Split stdout into array of lines',
},
{
name: 'Smart Auto-detect',
value: 'smart',
description: 'Automatically detect and parse JSON, CSV, or return lines',
},
],
default: 'none',
description: 'How to parse the stdout output for easier data access',
},
{
displayName: 'Parse Options',
name: 'parseOptions',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
parseOutput: ['json', 'smart'],
},
},
options: [
{
displayName: 'Handle Multiple JSON Objects',
name: 'multipleJson',
type: 'boolean',
default: false,
description: 'Parse multiple JSON objects separated by newlines',
},
{
displayName: 'Strip Non-JSON Text',
name: 'stripNonJson',
type: 'boolean',
default: true,
description: 'Remove non-JSON text before and after JSON content',
},
{
displayName: 'Fallback on Parse Error',
name: 'fallbackOnError',
type: 'boolean',
default: true,
description: 'Keep original stdout if parsing fails',
},
],
},
{
displayName: 'Execution Mode',
name: 'executionMode',
type: 'options',
options: [
{
name: 'Once for All Items',
value: 'once',
description: 'Execute script once with all input items available (faster)',
},
{
name: 'Once per Item',
value: 'perItem',
description: 'Execute script separately for each input item (slower but more flexible)',
},
],
default: 'once',
description: 'Choose how many times to execute the Python script',
},
{
displayName: 'Pass Through Input Data',
name: 'passThrough',
type: 'boolean',
default: false,
description: 'Include original input data in the output alongside Python script results',
},
{
displayName: 'Pass Through Mode',
name: 'passThroughMode',
type: 'options',
displayOptions: {
show: {
passThrough: [true],
},
},
options: [
{
name: 'Merge with Result',
value: 'merge',
description: 'Add input fields directly to the result object',
},
{
name: 'Separate Field',
value: 'separate',
description: 'Add input data as "inputData" field in result',
},
{
name: 'Multiple Outputs',
value: 'multiple',
description: 'Return separate items for input data and Python result',
},
],
default: 'separate',
description: 'How to include input data in the output',
},
{
displayName: 'File Debug Options',
name: 'fileDebugOptions',
type: 'collection',
default: {},
placeholder: 'Add Debug Options',
description: 'Advanced debugging options for file processing issues',
options: [
{
displayName: 'Enable File Debugging',
name: 'enabled',
type: 'boolean',
default: false,
description: 'Include detailed file processing information in output for troubleshooting',
},
{
displayName: 'Debug Input Files',
name: 'includeInputFileDebug',
type: 'boolean',
default: true,
description: 'Include detailed information about input files processing',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Debug Output Files',
name: 'includeOutputFileDebug',
type: 'boolean',
default: true,
description: 'Include detailed information about output files and directory scanning',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Include System Information',
name: 'includeSystemInfo',
type: 'boolean',
default: true,
description: 'Include system information like permissions, disk space, environment variables',
displayOptions: {
show: {
enabled: [true],
},
},
},
{
displayName: 'Include Directory Listings',
name: 'includeDirectoryListing',
type: 'boolean',
default: false,
description: 'Include file listings from working directory, temp directory, and output directory',
displayOptions: {
show: {
enabled: [true],
},
},
},
],
},
],
};
this.methods = {
loadOptions: {
async generateCodeTemplate() {
try {
const currentNodeParameter = this.getCurrentNodeParameter;
const functionCode = currentNodeParameter('functionCode') || '';
const scriptOptions = currentNodeParameter('scriptOptions') || {};
const fileProcessing = currentNodeParameter('fileProcessing') || {};
const outputFileProcessing = currentNodeParameter('outputFileProcessing') || {};
const credentialsManagement = currentNodeParameter('credentialsManagement') || {};
const templateCode = generateCodeTemplateStatic(functionCode, scriptOptions.includeInputItems !== false, scriptOptions.includeEnvVarsDict === true, credentialsManagement.hideVariableValues === true, fileProcessing.enabled === true, outputFileProcessing.enabled === true);
const lines = templateCode.split('\n');
const nonEmptyLines = lines.filter(line => line.trim() !== '').length;
const timestamp = new Date().toLocaleString();
const hasUserCode = functionCode && functionCode.trim();
const previewLines = lines.slice(0, 20);
const preview = previewLines.join('\n') + (lines.length > 20 ? '\n\n# ... (truncated)' : '');
return [
{
name: `🔄 Generated Template (${lines.length} li