mirror of
https://github.com/n8n-io/n8n.git
synced 2026-06-03 18:27:09 +02:00
81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
import { readFileSync, existsSync } from 'fs';
|
|
import { jsonParse, type INodeTypeDescription } from 'n8n-workflow';
|
|
import { join } from 'path';
|
|
|
|
interface NodeWithVersion extends INodeTypeDescription {
|
|
version: number | number[];
|
|
defaultVersion?: number;
|
|
}
|
|
|
|
// These types are ignored because they tend to cause issues when generating workflows
|
|
// Same as in ai-workflow-builder-agent.service.ts
|
|
const IGNORED_TYPES = new Set([
|
|
'@n8n/n8n-nodes-langchain.toolVectorStore',
|
|
'@n8n/n8n-nodes-langchain.documentGithubLoader',
|
|
'@n8n/n8n-nodes-langchain.code',
|
|
]);
|
|
|
|
// Parse disabled nodes from environment variable (comma-separated)
|
|
function getDisabledNodes(): Set<string> {
|
|
const disabledNodesEnv = process.env.N8N_EVALS_DISABLED_NODES ?? '';
|
|
return new Set(
|
|
disabledNodesEnv
|
|
.split(',')
|
|
.map((s) => s.trim())
|
|
.filter(Boolean),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Filter node types similar to production service:
|
|
* - Remove ignored types (hardcoded)
|
|
* - Remove disabled types (from env var)
|
|
* - Remove hidden nodes (except DataTable)
|
|
* - Merge tool nodes with their non-tool counterparts
|
|
*/
|
|
function filterNodeTypes(
|
|
nodeTypes: INodeTypeDescription[],
|
|
disabledNodes: Set<string>,
|
|
): INodeTypeDescription[] {
|
|
const visibleNodeTypes = nodeTypes.filter(
|
|
(nodeType) =>
|
|
!IGNORED_TYPES.has(nodeType.name) &&
|
|
!disabledNodes.has(nodeType.name) &&
|
|
// Filter out hidden nodes, except for the Data Table node which has custom hiding logic
|
|
(nodeType.hidden !== true || nodeType.name === 'n8n-nodes-base.dataTable'),
|
|
);
|
|
|
|
return visibleNodeTypes.map((nodeType) => {
|
|
// If the node type is a tool, merge it with the corresponding non-tool node type
|
|
const isTool = nodeType.name.endsWith('Tool');
|
|
if (!isTool) return nodeType;
|
|
|
|
const nonToolNode = nodeTypes.find((nt) => nt.name === nodeType.name.replace('Tool', ''));
|
|
if (!nonToolNode) return nodeType;
|
|
|
|
return { ...nonToolNode, ...nodeType };
|
|
});
|
|
}
|
|
|
|
export function loadNodesFromFile(): INodeTypeDescription[] {
|
|
const preferredPath = join(__dirname, '..', '.data', 'nodes.json');
|
|
const legacyPath = join(__dirname, '..', 'nodes.json');
|
|
const nodesPath = existsSync(preferredPath) ? preferredPath : legacyPath;
|
|
|
|
if (!existsSync(nodesPath)) {
|
|
throw new Error(
|
|
`nodes.json not found at ${nodesPath}. ` +
|
|
'Run n8n and export node definitions to evaluations/.data/nodes.json',
|
|
);
|
|
}
|
|
|
|
const nodesData = readFileSync(nodesPath, 'utf-8');
|
|
const allNodes = jsonParse<NodeWithVersion[]>(nodesData);
|
|
|
|
// Keep all version entries instead of selecting only the latest version.
|
|
// Workflows may use older node versions (e.g., removeDuplicates v1.1), and
|
|
// discarding those entries causes "Node type not found" validation errors.
|
|
const disabledNodes = getDisabledNodes();
|
|
return filterNodeTypes(allNodes, disabledNodes);
|
|
}
|