mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-10 15:23:07 +00:00
* chore: update n8n to 2.4.4 and bump version to 2.33.3 - Updated n8n from 2.2.3 to 2.4.4 - Updated n8n-core from 2.2.2 to 2.4.2 - Updated n8n-workflow from 2.2.2 to 2.4.2 - Updated @n8n/n8n-nodes-langchain from 2.2.2 to 2.4.3 - Added new `icon` NodePropertyType (now 23 types total) - Rebuilt node database with 803 nodes (541 from n8n-nodes-base, 262 from @n8n/n8n-nodes-langchain) - Updated README badge with new n8n version - Updated CHANGELOG with dependency changes Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: update n8n-workflow version in Dockerfile for icon type support The Docker build was using n8n-workflow@^1.96.0 which doesn't have the new 'icon' NodePropertyType. Updated to n8n-workflow@^2.4.2 to match the project's package.json version. Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: update comments to reflect 23 NodePropertyTypes - Updated test comment from '22 standard types' to '23 standard types' - Updated header comment from n8n-workflow v1.120.3 to v2.4.2 Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
428 lines
12 KiB
TypeScript
428 lines
12 KiB
TypeScript
/**
|
|
* Type Structure Service
|
|
*
|
|
* Provides methods to query and work with n8n property type structures.
|
|
* This service is stateless and uses static methods following the project's
|
|
* PropertyFilter and ConfigValidator patterns.
|
|
*
|
|
* @module services/type-structure-service
|
|
* @since 2.23.0
|
|
*/
|
|
|
|
import type { NodePropertyTypes } from 'n8n-workflow';
|
|
import type { TypeStructure } from '../types/type-structures';
|
|
import {
|
|
isComplexType as isComplexTypeGuard,
|
|
isPrimitiveType as isPrimitiveTypeGuard,
|
|
} from '../types/type-structures';
|
|
import { TYPE_STRUCTURES, COMPLEX_TYPE_EXAMPLES } from '../constants/type-structures';
|
|
|
|
/**
|
|
* Result of type validation
|
|
*/
|
|
export interface TypeValidationResult {
|
|
/**
|
|
* Whether the value is valid for the type
|
|
*/
|
|
valid: boolean;
|
|
|
|
/**
|
|
* Validation errors if invalid
|
|
*/
|
|
errors: string[];
|
|
|
|
/**
|
|
* Warnings that don't prevent validity
|
|
*/
|
|
warnings: string[];
|
|
}
|
|
|
|
/**
|
|
* Service for querying and working with node property type structures
|
|
*
|
|
* Provides static methods to:
|
|
* - Get type structure definitions
|
|
* - Get example values
|
|
* - Validate type compatibility
|
|
* - Query type categories
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* // Get structure for a type
|
|
* const structure = TypeStructureService.getStructure('collection');
|
|
* console.log(structure.description); // "A group of related properties..."
|
|
*
|
|
* // Get example value
|
|
* const example = TypeStructureService.getExample('filter');
|
|
* console.log(example.combinator); // "and"
|
|
*
|
|
* // Check if type is complex
|
|
* if (TypeStructureService.isComplexType('resourceMapper')) {
|
|
* console.log('This type needs special handling');
|
|
* }
|
|
* ```
|
|
*/
|
|
export class TypeStructureService {
|
|
/**
|
|
* Get the structure definition for a property type
|
|
*
|
|
* Returns the complete structure definition including:
|
|
* - Type category (primitive/object/collection/special)
|
|
* - JavaScript type
|
|
* - Expected structure for complex types
|
|
* - Example values
|
|
* - Validation rules
|
|
*
|
|
* @param type - The NodePropertyType to query
|
|
* @returns Type structure definition, or null if type is unknown
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const structure = TypeStructureService.getStructure('string');
|
|
* console.log(structure.jsType); // "string"
|
|
* console.log(structure.example); // "Hello World"
|
|
* ```
|
|
*/
|
|
static getStructure(type: NodePropertyTypes): TypeStructure | null {
|
|
return TYPE_STRUCTURES[type] || null;
|
|
}
|
|
|
|
/**
|
|
* Get all type structure definitions
|
|
*
|
|
* Returns a record of all 23 NodePropertyTypes with their structures.
|
|
* Useful for documentation, validation setup, or UI generation.
|
|
*
|
|
* @returns Record mapping all types to their structures
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const allStructures = TypeStructureService.getAllStructures();
|
|
* console.log(Object.keys(allStructures).length); // 22
|
|
* ```
|
|
*/
|
|
static getAllStructures(): Record<NodePropertyTypes, TypeStructure> {
|
|
return { ...TYPE_STRUCTURES };
|
|
}
|
|
|
|
/**
|
|
* Get example value for a property type
|
|
*
|
|
* Returns a working example value that conforms to the type's
|
|
* expected structure. Useful for testing, documentation, or
|
|
* generating default values.
|
|
*
|
|
* @param type - The NodePropertyType to get an example for
|
|
* @returns Example value, or null if type is unknown
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const example = TypeStructureService.getExample('number');
|
|
* console.log(example); // 42
|
|
*
|
|
* const filterExample = TypeStructureService.getExample('filter');
|
|
* console.log(filterExample.combinator); // "and"
|
|
* ```
|
|
*/
|
|
static getExample(type: NodePropertyTypes): any {
|
|
const structure = this.getStructure(type);
|
|
return structure ? structure.example : null;
|
|
}
|
|
|
|
/**
|
|
* Get all example values for a property type
|
|
*
|
|
* Some types have multiple examples to show different use cases.
|
|
* This returns all available examples, or falls back to the
|
|
* primary example if only one exists.
|
|
*
|
|
* @param type - The NodePropertyType to get examples for
|
|
* @returns Array of example values
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const examples = TypeStructureService.getExamples('string');
|
|
* console.log(examples.length); // 4
|
|
* console.log(examples[0]); // ""
|
|
* console.log(examples[1]); // "A simple text"
|
|
* ```
|
|
*/
|
|
static getExamples(type: NodePropertyTypes): any[] {
|
|
const structure = this.getStructure(type);
|
|
if (!structure) return [];
|
|
|
|
return structure.examples || [structure.example];
|
|
}
|
|
|
|
/**
|
|
* Check if a property type is complex
|
|
*
|
|
* Complex types have nested structures and require special
|
|
* validation logic beyond simple type checking.
|
|
*
|
|
* Complex types: collection, fixedCollection, resourceLocator,
|
|
* resourceMapper, filter, assignmentCollection
|
|
*
|
|
* @param type - The property type to check
|
|
* @returns True if the type is complex
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* TypeStructureService.isComplexType('collection'); // true
|
|
* TypeStructureService.isComplexType('string'); // false
|
|
* ```
|
|
*/
|
|
static isComplexType(type: NodePropertyTypes): boolean {
|
|
return isComplexTypeGuard(type);
|
|
}
|
|
|
|
/**
|
|
* Check if a property type is primitive
|
|
*
|
|
* Primitive types map to simple JavaScript values and only
|
|
* need basic type validation.
|
|
*
|
|
* Primitive types: string, number, boolean, dateTime, color, json
|
|
*
|
|
* @param type - The property type to check
|
|
* @returns True if the type is primitive
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* TypeStructureService.isPrimitiveType('string'); // true
|
|
* TypeStructureService.isPrimitiveType('collection'); // false
|
|
* ```
|
|
*/
|
|
static isPrimitiveType(type: NodePropertyTypes): boolean {
|
|
return isPrimitiveTypeGuard(type);
|
|
}
|
|
|
|
/**
|
|
* Get all complex property types
|
|
*
|
|
* Returns an array of all property types that are classified
|
|
* as complex (having nested structures).
|
|
*
|
|
* @returns Array of complex type names
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const complexTypes = TypeStructureService.getComplexTypes();
|
|
* console.log(complexTypes);
|
|
* // ['collection', 'fixedCollection', 'resourceLocator', ...]
|
|
* ```
|
|
*/
|
|
static getComplexTypes(): NodePropertyTypes[] {
|
|
return Object.entries(TYPE_STRUCTURES)
|
|
.filter(([, structure]) => structure.type === 'collection' || structure.type === 'special')
|
|
.filter(([type]) => this.isComplexType(type as NodePropertyTypes))
|
|
.map(([type]) => type as NodePropertyTypes);
|
|
}
|
|
|
|
/**
|
|
* Get all primitive property types
|
|
*
|
|
* Returns an array of all property types that are classified
|
|
* as primitive (simple JavaScript values).
|
|
*
|
|
* @returns Array of primitive type names
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const primitiveTypes = TypeStructureService.getPrimitiveTypes();
|
|
* console.log(primitiveTypes);
|
|
* // ['string', 'number', 'boolean', 'dateTime', 'color', 'json']
|
|
* ```
|
|
*/
|
|
static getPrimitiveTypes(): NodePropertyTypes[] {
|
|
return Object.keys(TYPE_STRUCTURES).filter((type) =>
|
|
this.isPrimitiveType(type as NodePropertyTypes)
|
|
) as NodePropertyTypes[];
|
|
}
|
|
|
|
/**
|
|
* Get real-world examples for complex types
|
|
*
|
|
* Returns curated examples from actual n8n workflows showing
|
|
* different usage patterns for complex types.
|
|
*
|
|
* @param type - The complex type to get examples for
|
|
* @returns Object with named example scenarios, or null
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const examples = TypeStructureService.getComplexExamples('fixedCollection');
|
|
* console.log(examples.httpHeaders);
|
|
* // { headers: [{ name: 'Content-Type', value: 'application/json' }] }
|
|
* ```
|
|
*/
|
|
static getComplexExamples(
|
|
type: 'collection' | 'fixedCollection' | 'filter' | 'resourceMapper' | 'assignmentCollection'
|
|
): Record<string, any> | null {
|
|
return COMPLEX_TYPE_EXAMPLES[type] || null;
|
|
}
|
|
|
|
/**
|
|
* Validate basic type compatibility of a value
|
|
*
|
|
* Performs simple type checking to verify a value matches the
|
|
* expected JavaScript type for a property type. Does not perform
|
|
* deep structure validation for complex types.
|
|
*
|
|
* @param value - The value to validate
|
|
* @param type - The expected property type
|
|
* @returns Validation result with errors if invalid
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const result = TypeStructureService.validateTypeCompatibility(
|
|
* 'Hello',
|
|
* 'string'
|
|
* );
|
|
* console.log(result.valid); // true
|
|
*
|
|
* const result2 = TypeStructureService.validateTypeCompatibility(
|
|
* 123,
|
|
* 'string'
|
|
* );
|
|
* console.log(result2.valid); // false
|
|
* console.log(result2.errors[0]); // "Expected string but got number"
|
|
* ```
|
|
*/
|
|
static validateTypeCompatibility(
|
|
value: any,
|
|
type: NodePropertyTypes
|
|
): TypeValidationResult {
|
|
const structure = this.getStructure(type);
|
|
|
|
if (!structure) {
|
|
return {
|
|
valid: false,
|
|
errors: [`Unknown property type: ${type}`],
|
|
warnings: [],
|
|
};
|
|
}
|
|
|
|
const errors: string[] = [];
|
|
const warnings: string[] = [];
|
|
|
|
// Handle null/undefined
|
|
if (value === null || value === undefined) {
|
|
if (!structure.validation?.allowEmpty) {
|
|
errors.push(`Value is required for type ${type}`);
|
|
}
|
|
return { valid: errors.length === 0, errors, warnings };
|
|
}
|
|
|
|
// Check JavaScript type compatibility
|
|
const actualType = Array.isArray(value) ? 'array' : typeof value;
|
|
const expectedType = structure.jsType;
|
|
|
|
if (expectedType !== 'any' && actualType !== expectedType) {
|
|
// Special case: expressions are strings but might be allowed
|
|
const isExpression = typeof value === 'string' && value.includes('{{');
|
|
if (isExpression && structure.validation?.allowExpressions) {
|
|
warnings.push(
|
|
`Value contains n8n expression - cannot validate type until runtime`
|
|
);
|
|
} else {
|
|
errors.push(`Expected ${expectedType} but got ${actualType}`);
|
|
}
|
|
}
|
|
|
|
// Additional validation for specific types
|
|
if (type === 'dateTime' && typeof value === 'string') {
|
|
const pattern = structure.validation?.pattern;
|
|
if (pattern && !new RegExp(pattern).test(value)) {
|
|
errors.push(`Invalid dateTime format. Expected ISO 8601 format.`);
|
|
}
|
|
}
|
|
|
|
if (type === 'color' && typeof value === 'string') {
|
|
const pattern = structure.validation?.pattern;
|
|
if (pattern && !new RegExp(pattern).test(value)) {
|
|
errors.push(`Invalid color format. Expected 6-digit hex color (e.g., #FF5733).`);
|
|
}
|
|
}
|
|
|
|
if (type === 'json' && typeof value === 'string') {
|
|
try {
|
|
JSON.parse(value);
|
|
} catch {
|
|
errors.push(`Invalid JSON string. Must be valid JSON when parsed.`);
|
|
}
|
|
}
|
|
|
|
return {
|
|
valid: errors.length === 0,
|
|
errors,
|
|
warnings,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get type description
|
|
*
|
|
* Returns the human-readable description of what a property type
|
|
* represents and how it should be used.
|
|
*
|
|
* @param type - The property type
|
|
* @returns Description string, or null if type unknown
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const description = TypeStructureService.getDescription('filter');
|
|
* console.log(description);
|
|
* // "Defines conditions for filtering data with boolean logic"
|
|
* ```
|
|
*/
|
|
static getDescription(type: NodePropertyTypes): string | null {
|
|
const structure = this.getStructure(type);
|
|
return structure ? structure.description : null;
|
|
}
|
|
|
|
/**
|
|
* Get type notes
|
|
*
|
|
* Returns additional notes, warnings, or usage tips for a type.
|
|
* Not all types have notes.
|
|
*
|
|
* @param type - The property type
|
|
* @returns Array of note strings, or empty array
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const notes = TypeStructureService.getNotes('filter');
|
|
* console.log(notes[0]);
|
|
* // "Advanced filtering UI in n8n"
|
|
* ```
|
|
*/
|
|
static getNotes(type: NodePropertyTypes): string[] {
|
|
const structure = this.getStructure(type);
|
|
return structure?.notes || [];
|
|
}
|
|
|
|
/**
|
|
* Get JavaScript type for a property type
|
|
*
|
|
* Returns the underlying JavaScript type that the property
|
|
* type maps to (string, number, boolean, object, array, any).
|
|
*
|
|
* @param type - The property type
|
|
* @returns JavaScript type name, or null if unknown
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* TypeStructureService.getJavaScriptType('string'); // "string"
|
|
* TypeStructureService.getJavaScriptType('collection'); // "object"
|
|
* TypeStructureService.getJavaScriptType('multiOptions'); // "array"
|
|
* ```
|
|
*/
|
|
static getJavaScriptType(
|
|
type: NodePropertyTypes
|
|
): 'string' | 'number' | 'boolean' | 'object' | 'array' | 'any' | null {
|
|
const structure = this.getStructure(type);
|
|
return structure ? structure.jsType : null;
|
|
}
|
|
}
|