Skip to content

Commit

Permalink
refactor(core): Refactor node-details endpoints (no-changelog)
Browse files Browse the repository at this point in the history
  • Loading branch information
netroy committed Oct 20, 2023
1 parent 3c0a166 commit 39b865e
Show file tree
Hide file tree
Showing 14 changed files with 401 additions and 581 deletions.
208 changes: 208 additions & 0 deletions packages/cli/src/DynamicNodeParameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import type {
ILoadOptions,
ILoadOptionsFunctions,
INode,
INodeExecutionData,
INodeListSearchResult,
INodeProperties,
INodePropertyOptions,
INodeType,
IRunExecutionData,
ITaskDataConnections,
IWorkflowExecuteAdditionalData,
ResourceMapperFields,
} from 'n8n-workflow';
import {
Workflow,
RoutingNode,
INodeCredentials,
INodeParameters,
INodeTypeNameVersion,
INodeTypes,
} from 'n8n-workflow';
import { NodeExecuteFunctions } from 'n8n-core';

export class DynamicNodeParameters {
protected node: INode;

protected nodeType: INodeType;

protected workflow: Workflow;

constructor(
nodeTypeNameAndVersion: INodeTypeNameVersion,
nodeTypes: INodeTypes,
currentNodeParameters: INodeParameters,
credentials?: INodeCredentials,
) {
this.nodeType = nodeTypes.getByNameAndVersion(
nodeTypeNameAndVersion.name,
nodeTypeNameAndVersion.version,
);

this.node = {
parameters: currentNodeParameters,
id: 'uuid-1234',
name: 'Temp-Node',
type: nodeTypeNameAndVersion.name,
typeVersion: nodeTypeNameAndVersion.version,
position: [0, 0],
};

if (credentials) {
this.node.credentials = credentials;
}

this.workflow = new Workflow({
nodes: [this.node],
connections: {},
active: false,
nodeTypes,
});
}

/** Returns the available options via a predefined method */
async getOptionsViaMethodName(
methodName: string,
path: string,
additionalData: IWorkflowExecuteAdditionalData,
): Promise<INodePropertyOptions[]> {
const method = this.getMethod('loadOptions', methodName);
const thisArgs = this.getThisArg(path, additionalData);
return method.call(thisArgs);

Check failure on line 72 in packages/cli/src/DynamicNodeParameters.ts

View workflow job for this annotation

GitHub Actions / Lint changes

Unsafe return of an `any` typed value
}

/** Returns the available options via a loadOptions param */
async getOptionsViaLoadOptions(
loadOptions: ILoadOptions,
additionalData: IWorkflowExecuteAdditionalData,
): Promise<INodePropertyOptions[]> {
const node = this.node;

if (!this.nodeType.description?.requestDefaults?.baseURL) {
// This in in here for now for security reasons.
// Background: As the full data for the request to make does get send, and the auth data
// will then be applied, would it be possible to retrieve that data like that. By at least
// requiring a baseURL to be defined can at least not a random server be called.
// In the future this code has to get improved that it does not use the request information from
// the request rather resolves it via the parameter-path and nodeType data.
throw new Error(
`The node-type "${node.type}" does not exist or does not have "requestDefaults.baseURL" defined!`,
);
}

const mode = 'internal';
const runIndex = 0;
const connectionInputData: INodeExecutionData[] = [];
const runExecutionData: IRunExecutionData = { resultData: { runData: {} } };

const routingNode = new RoutingNode(
this.workflow,
node,
connectionInputData,
runExecutionData ?? null,
additionalData,
mode,
);

// Create copy of node-type with the single property we want to get the data off
const tempNode: INodeType = {
...this.nodeType,
...{
description: {
...this.nodeType.description,
properties: [
{
displayName: '',
type: 'string',
name: '',
default: '',
routing: loadOptions.routing,
} as INodeProperties,
],
},
},
};

const inputData: ITaskDataConnections = {
main: [[{ json: {} }]],
};

const optionsData = await routingNode.runNode(
inputData,
runIndex,
tempNode,
{ node, source: null, data: {} },
NodeExecuteFunctions,
);

if (optionsData?.length === 0) {
return [];
}

if (!Array.isArray(optionsData)) {
throw new Error('The returned data is not an array!');
}

return optionsData[0].map((item) => item.json) as unknown as INodePropertyOptions[];
}

async getResourceLocatorResults(
methodName: string,
path: string,
additionalData: IWorkflowExecuteAdditionalData,
filter?: string,
paginationToken?: string,
): Promise<INodeListSearchResult> {
const method = this.getMethod('listSearch', methodName);
const thisArgs = this.getThisArg(path, additionalData);
return method.call(thisArgs, filter, paginationToken);

Check failure on line 159 in packages/cli/src/DynamicNodeParameters.ts

View workflow job for this annotation

GitHub Actions / Lint changes

Unsafe return of an `any` typed value
}

/** Returns the available mapping fields for the ResourceMapper component */
async getResourceMappingFields(
methodName: string,
path: string,
additionalData: IWorkflowExecuteAdditionalData,
): Promise<ResourceMapperFields> {
const method = this.getMethod('resourceMapping', methodName);
const thisArgs = this.getThisArg(path, additionalData);
return method.call(thisArgs);

Check failure on line 170 in packages/cli/src/DynamicNodeParameters.ts

View workflow job for this annotation

GitHub Actions / Lint changes

Unsafe return of an `any` typed value
}

protected getMethod(
type: 'resourceMapping',
methodName: string,
): (this: ILoadOptionsFunctions) => Promise<ResourceMapperFields>;
protected getMethod(
type: 'listSearch',
methodName: string,
): (
this: ILoadOptionsFunctions,
filter?: string | undefined,
paginationToken?: string | undefined,
) => Promise<INodeListSearchResult>;
protected getMethod(
type: 'loadOptions',
methodName: string,
): (this: ILoadOptionsFunctions) => Promise<INodePropertyOptions[]>;

protected getMethod(type: 'resourceMapping' | 'listSearch' | 'loadOptions', methodName: string) {
const method = this.nodeType.methods?.[type]?.[methodName];
if (typeof method !== 'function') {
throw new Error(
`The node-type "${this.node.type}" does not have the method "${methodName}" defined!`,
);
}
return method;
}

protected getThisArg(path: string, additionalData: IWorkflowExecuteAdditionalData) {
return NodeExecuteFunctions.getLoadOptionsFunctions(
this.workflow,
this.node,
path,
additionalData,
);
}
}
Loading

0 comments on commit 39b865e

Please sign in to comment.