mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-20 03:12:15 +00:00
feat(Set Node): Overhaul (#6348)
Github issue / Community forum post (link here to close automatically): https://github.com/n8n-io/n8n/pull/6348 --------- Co-authored-by: Giulio Andreini <g.andreini@gmail.com> Co-authored-by: Marcus <marcus@n8n.io>
This commit is contained in:
@@ -571,7 +571,10 @@ export interface IN8nRequestOperationPaginationOffset extends IN8nRequestOperati
|
||||
}
|
||||
|
||||
export interface IGetNodeParameterOptions {
|
||||
// extract value from regex, works only when parameter type is resourceLocator
|
||||
extractValue?: boolean;
|
||||
// get raw value of parameter with unresolved expressions
|
||||
rawExpressions?: boolean;
|
||||
}
|
||||
|
||||
namespace ExecuteFunctions {
|
||||
@@ -1119,6 +1122,12 @@ export interface INodeProperties {
|
||||
modes?: INodePropertyMode[];
|
||||
requiresDataPath?: 'single' | 'multiple';
|
||||
doNotInherit?: boolean;
|
||||
// set expected type for the value which would be used for validation and type casting
|
||||
validateType?: FieldType;
|
||||
// works only if validateType is set
|
||||
// allows to skip validation during execution or set custom validation/casting logic inside node
|
||||
// inline error messages would still be shown in UI
|
||||
ignoreValidationDuringExecution?: boolean;
|
||||
}
|
||||
|
||||
export interface INodePropertyModeTypeOptions {
|
||||
@@ -1206,7 +1215,6 @@ export interface INodePropertyValueExtractorFunction {
|
||||
value: string | NodeParameterValue,
|
||||
): Promise<string | NodeParameterValue> | (string | NodeParameterValue);
|
||||
}
|
||||
|
||||
export type INodePropertyValueExtractor = INodePropertyValueExtractorRegex;
|
||||
|
||||
export interface IParameterDependencies {
|
||||
|
||||
@@ -36,6 +36,7 @@ import type {
|
||||
INodePropertyOptions,
|
||||
ResourceMapperValue,
|
||||
ValidationResult,
|
||||
GenericValue,
|
||||
} from './Interfaces';
|
||||
import { isResourceMapperValue, isValidResourceLocatorParameterValue } from './type-guards';
|
||||
import { deepCopy } from './utils';
|
||||
@@ -1081,7 +1082,7 @@ export const validateFieldType = (
|
||||
options?: INodePropertyOptions[],
|
||||
): ValidationResult => {
|
||||
if (value === null || value === undefined) return { valid: true };
|
||||
const defaultErrorMessage = `'${fieldName}' expects a ${type} but we got '${String(value)}'.`;
|
||||
const defaultErrorMessage = `'${fieldName}' expects a ${type} but we got '${String(value)}'`;
|
||||
switch (type.toLowerCase()) {
|
||||
case 'number': {
|
||||
try {
|
||||
@@ -1169,12 +1170,16 @@ export const tryToParseBoolean = (value: unknown): value is boolean => {
|
||||
return value.toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
const num = Number(value);
|
||||
if (num === 0) {
|
||||
return false;
|
||||
} else if (num === 1) {
|
||||
return true;
|
||||
// If value is not a empty string, try to parse it to a number
|
||||
if (!(typeof value === 'string' && value.trim() === '')) {
|
||||
const num = Number(value);
|
||||
if (num === 0) {
|
||||
return false;
|
||||
} else if (num === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Could not parse '${String(value)}' to boolean.`);
|
||||
};
|
||||
|
||||
@@ -1214,7 +1219,17 @@ export const tryToParseTime = (value: unknown): string => {
|
||||
|
||||
export const tryToParseArray = (value: unknown): unknown[] => {
|
||||
try {
|
||||
const parsed = JSON.parse(String(value));
|
||||
if (typeof value === 'object' && Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(String(value));
|
||||
} catch (e) {
|
||||
parsed = JSON.parse(String(value).replace(/'/g, '"'));
|
||||
}
|
||||
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new Error(`The value "${String(value)}" is not a valid array.`);
|
||||
}
|
||||
@@ -1306,6 +1321,30 @@ export const validateResourceMapperParameter = (
|
||||
return issues;
|
||||
};
|
||||
|
||||
export const validateParameter = (
|
||||
nodeProperties: INodeProperties,
|
||||
value: GenericValue,
|
||||
type: FieldType,
|
||||
): string | undefined => {
|
||||
const nodeName = nodeProperties.name;
|
||||
const options = type === 'options' ? nodeProperties.options : undefined;
|
||||
|
||||
if (!value?.toString().startsWith('=')) {
|
||||
const validationResult = validateFieldType(
|
||||
nodeName,
|
||||
value,
|
||||
type,
|
||||
options as INodePropertyOptions[],
|
||||
);
|
||||
|
||||
if (!validationResult.valid && validationResult.errorMessage) {
|
||||
return validationResult.errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds an issue if the parameter is not defined
|
||||
*
|
||||
@@ -1430,6 +1469,19 @@ export function getParameterIssues(
|
||||
foundIssues.parameters = { ...foundIssues.parameters, ...issues };
|
||||
}
|
||||
}
|
||||
} else if (nodeProperties.validateType) {
|
||||
const value = getParameterValueByPath(nodeValues, nodeProperties.name, path);
|
||||
const error = validateParameter(nodeProperties, value, nodeProperties.validateType);
|
||||
if (error) {
|
||||
if (foundIssues.parameters === undefined) {
|
||||
foundIssues.parameters = {};
|
||||
}
|
||||
if (foundIssues.parameters[nodeProperties.name] === undefined) {
|
||||
foundIssues.parameters[nodeProperties.name] = [];
|
||||
}
|
||||
|
||||
foundIssues.parameters[nodeProperties.name].push(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there are any child parameters
|
||||
|
||||
Reference in New Issue
Block a user