mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-14 16:44:07 -08:00
5156313074
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions
Benchmark Docker Image CI / build (push) Waiting to run
97 lines
3 KiB
TypeScript
97 lines
3 KiB
TypeScript
import { CliWorkflowOperationError, SubworkflowOperationError } from 'n8n-workflow';
|
|
import type { INode } from 'n8n-workflow';
|
|
|
|
import { STARTING_NODES } from '@/constants';
|
|
|
|
/**
|
|
* Returns if the given id is a valid workflow id
|
|
*/
|
|
export function isWorkflowIdValid(id: string | null | undefined): boolean {
|
|
// TODO: could also check if id only contains nanoId characters
|
|
return typeof id === 'string' && id?.length <= 16;
|
|
}
|
|
|
|
function findWorkflowStart(executionMode: 'integrated' | 'cli') {
|
|
return function (nodes: INode[]) {
|
|
const executeWorkflowTriggerNode = nodes.find(
|
|
(node) => node.type === 'n8n-nodes-base.executeWorkflowTrigger',
|
|
);
|
|
|
|
if (executeWorkflowTriggerNode) return executeWorkflowTriggerNode;
|
|
|
|
const startNode = nodes.find((node) => STARTING_NODES.includes(node.type));
|
|
|
|
if (startNode) return startNode;
|
|
|
|
const title = 'Missing node to start execution';
|
|
const description =
|
|
"Please make sure the workflow you're calling contains an Execute Workflow Trigger node";
|
|
|
|
if (executionMode === 'integrated') {
|
|
throw new SubworkflowOperationError(title, description);
|
|
}
|
|
|
|
throw new CliWorkflowOperationError(title, description);
|
|
};
|
|
}
|
|
|
|
export const findSubworkflowStart = findWorkflowStart('integrated');
|
|
|
|
export const findCliWorkflowStart = findWorkflowStart('cli');
|
|
|
|
export const separate = <T>(array: T[], test: (element: T) => boolean) => {
|
|
const pass: T[] = [];
|
|
const fail: T[] = [];
|
|
|
|
array.forEach((i) => (test(i) ? pass : fail).push(i));
|
|
|
|
return [pass, fail];
|
|
};
|
|
|
|
export const toError = (maybeError: unknown) =>
|
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
maybeError instanceof Error ? maybeError : new Error(`${maybeError}`);
|
|
|
|
export function isStringArray(value: unknown): value is string[] {
|
|
return Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
}
|
|
|
|
export const isIntegerString = (value: string) => /^\d+$/.test(value);
|
|
|
|
export function isObjectLiteral(item: unknown): item is { [key: string]: string } {
|
|
return typeof item === 'object' && item !== null && !Array.isArray(item);
|
|
}
|
|
|
|
export function removeTrailingSlash(path: string) {
|
|
return path.endsWith('/') ? path.slice(0, -1) : path;
|
|
}
|
|
|
|
// return the difference between two arrays
|
|
export function rightDiff<T1, T2>(
|
|
[arr1, keyExtractor1]: [T1[], (item: T1) => string],
|
|
[arr2, keyExtractor2]: [T2[], (item: T2) => string],
|
|
): T2[] {
|
|
// create map { itemKey => true } for fast lookup for diff
|
|
const keyMap = arr1.reduce<{ [key: string]: true }>((map, item) => {
|
|
map[keyExtractor1(item)] = true;
|
|
return map;
|
|
}, {});
|
|
|
|
// diff against map
|
|
return arr2.reduce<T2[]>((acc, item) => {
|
|
if (!keyMap[keyExtractor2(item)]) {
|
|
acc.push(item);
|
|
}
|
|
return acc;
|
|
}, []);
|
|
}
|
|
|
|
/**
|
|
* Asserts that the passed in type is never.
|
|
* Can be used to make sure the type is exhausted
|
|
* in switch statements or if/else chains.
|
|
*/
|
|
export const assertNever = (_value: never) => {};
|
|
|
|
export const isPositiveInteger = (maybeInt: string) => /^[1-9]\d*$/.test(maybeInt);
|