🎨 Set up linting and formatting (#2120)

* ⬆️ Upgrade TS to 4.3.5

* 👕 Add ESLint configs

* 🎨 Add Prettier config

* 📦 Add deps and commands

*  Adjust global .editorconfig to new ruleset

* 🔥 Remove unneeded local .editorconfig

* 📦 Update deps in editor-ui

* 🔨 Limit Prettier to only TS files

*  Add recommended VSCode extensions

* 👕 Fix build

* 🔥 Remove Vue setting from global config

*  Disable prefer-default-export per feedback

* ✏️ Add forgotten divider

* 👕 Disable no-plusplus

* 👕 Disable class-methods-use-this

* ✏️ Alphabetize overrides

* 👕 Add one-var consecutive override

*  Revert one-var consecutive override

This reverts commit b9252cf935659ba6d76727ad484a1d3c00008fcc.

* 🎨 👕 Lint and format workflow package (#2121)

* 🎨 Format /workflow package

* 👕 Lint /workflow package

* 🎨 Re-format /workflow package

* 👕 Re-lint /workflow package

* ✏️ Fix typo

*  Consolidate if-checks

* 🔥 Remove prefer-default-export exceptions

* 🔥 Remove no-plusplus exceptions

* 🔥 Remove class-methods-use-this exceptions

* 🎨 👕 Lint and format node-dev package (#2122)

* 🎨 Format /node-dev package

*  Exclude templates from ESLint config

This keeps the templates consistent with the codebase while preventing lint exceptions from being made part of the templates.

* 👕 Lint /node-dev package

* 🔥 Remove prefer-default-export exceptions

* 🔥 Remove no-plusplus exceptions

* 🎨 👕 Lint and format core package (#2123)

* 🎨 Format /core package

* 👕 Lint /core package

* 🎨 Re-format /core package

* 👕 Re-lint /core package

* 🔥 Remove prefer-default-export exceptions

* 🔥 Remove no-plusplus exceptions

* 🔥 Remove class-methods-use-this exceptions

* 🎨 👕 Lint and format cli package (#2124)

* 🎨 Format /cli package

* 👕 Exclude migrations from linting

* 👕 Lint /cli package

* 🎨 Re-format /cli package

* 👕 Re-lint /cli package

* 👕 Fix build

* 🔥 Remove prefer-default-export exceptions

*  Update exceptions in ActiveExecutions

* 🔥 Remove no-plusplus exceptions

* 🔥 Remove class-methods-use-this exceptions

* 👕 fix lint issues

* 🔧 use package specific linter, remove tslint command

* 🔨 resolve build issue, sync dependencies

* 🔧 change lint command

Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
This commit is contained in:
Iván Ovejero
2021-08-29 20:58:11 +02:00
committed by GitHub
parent 223cd75685
commit 56c4c6991f
108 changed files with 11832 additions and 8416 deletions

View File

@@ -1,12 +1,7 @@
import {
UserSettings,
} from "n8n-core";
import { UserSettings } from 'n8n-core';
import { Command, flags } from '@oclif/command';
import {
buildFiles,
IBuildOptions,
} from '../src';
import { buildFiles, IBuildOptions } from '../src';
export class Build extends Command {
static description = 'Builds credentials and nodes and copies it to n8n custom extension folder';
@@ -24,11 +19,14 @@ export class Build extends Command {
description: `The path to copy the compiles files to [default: ${UserSettings.getUserN8nFolderCustomExtensionPath()}]`,
}),
watch: flags.boolean({
description: 'Starts in watch mode and automatically builds and copies file whenever they change',
description:
'Starts in watch mode and automatically builds and copies file whenever they change',
}),
};
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async run() {
// eslint-disable-next-line @typescript-eslint/no-shadow
const { flags } = this.parse(Build);
this.log('\nBuild credentials and nodes');
@@ -47,13 +45,12 @@ export class Build extends Command {
const outputDirectory = await buildFiles(options);
this.log(`The nodes got build and saved into the following folder:\n${outputDirectory}`);
} catch (error) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
this.log(`\nGOT ERROR: "${error.message}"`);
this.log('====================================');
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
this.log(error.stack);
return;
}
}
}

View File

@@ -1,25 +1,26 @@
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import * as changeCase from 'change-case';
import * as fs from 'fs';
import * as inquirer from 'inquirer';
import { Command } from '@oclif/command';
import { join } from 'path';
const { promisify } = require('util');
const fsAccess = promisify(fs.access);
import { createTemplate } from '../src';
import {
createTemplate
} from '../src';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { promisify } = require('util');
const fsAccess = promisify(fs.access);
export class New extends Command {
static description = 'Create new credentials/node';
static examples = [
`$ n8n-node-dev new`,
];
static examples = [`$ n8n-node-dev new`];
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async run() {
try {
this.log('\nCreate new credentials/node');
this.log('=========================');
@@ -30,10 +31,7 @@ export class New extends Command {
type: 'list',
default: 'Node',
message: 'What do you want to create?',
choices: [
'Credentials',
'Node',
],
choices: ['Credentials', 'Node'],
};
const typeAnswers = await inquirer.prompt(typeQuestion);
@@ -43,7 +41,6 @@ export class New extends Command {
let defaultName = '';
let getDescription = false;
if (typeAnswers.type === 'Node') {
// Create new node
@@ -54,11 +51,7 @@ export class New extends Command {
type: 'list',
default: 'Execute',
message: 'What kind of node do you want to create?',
choices: [
'Execute',
'Trigger',
'Webhook',
],
choices: ['Execute', 'Trigger', 'Webhook'],
};
const nodeTypeAnswers = await inquirer.prompt(nodeTypeQuestion);
@@ -91,7 +84,7 @@ export class New extends Command {
},
];
if (getDescription === true) {
if (getDescription) {
// Get also a node description
additionalQuestions.push({
name: 'description',
@@ -101,13 +94,19 @@ export class New extends Command {
});
}
const additionalAnswers = await inquirer.prompt(additionalQuestions as inquirer.QuestionCollection);
const additionalAnswers = await inquirer.prompt(
additionalQuestions as inquirer.QuestionCollection,
);
const nodeName = additionalAnswers.name;
// Define the source file to be used and the location and name of the new
// node file
const destinationFilePath = join(process.cwd(), `${changeCase.pascalCase(nodeName)}.${typeAnswers.type.toLowerCase()}.ts`);
const destinationFilePath = join(
process.cwd(),
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
`${changeCase.pascalCase(nodeName)}.${typeAnswers.type.toLowerCase()}.ts`,
);
const sourceFilePath = join(__dirname, '../../templates', sourceFolder, sourceFileName);
@@ -150,12 +149,13 @@ export class New extends Command {
this.log('\nExecution was successfull:');
this.log('====================================');
this.log('Node got created: ' + destinationFilePath);
this.log(`Node got created: ${destinationFilePath}`);
} catch (error) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
this.log(`\nGOT ERROR: "${error.message}"`);
this.log('====================================');
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
this.log(error.stack);
return;
}
}
}

View File

@@ -21,10 +21,11 @@
"scripts": {
"dev": "npm run watch",
"build": "tsc",
"format": "cd ../.. && node_modules/prettier/bin-prettier.js packages/node-dev/**/**.ts --write",
"lint": "cd ../.. && node_modules/eslint/bin/eslint.js packages/node-dev",
"lintfix": "cd ../.. && node_modules/eslint/bin/eslint.js packages/node-dev --fix",
"postpack": "rm -f oclif.manifest.json",
"prepack": "echo \"Building project...\" && rm -rf dist && tsc -b && oclif-dev manifest",
"tslint": "tslint -p tsconfig.json -c tslint.json",
"tslintfix": "tslint --fix -p tsconfig.json -c tslint.json",
"watch": "tsc --watch"
},
"bin": {
@@ -64,7 +65,7 @@
"oauth-1.0a": "^2.2.6",
"replace-in-file": "^6.0.0",
"request": "^2.88.2",
"tmp-promise": "^2.0.2",
"typescript": "~3.9.7"
"tmp-promise": "^3.0.2",
"typescript": "~4.3.5"
}
}

View File

@@ -1,26 +1,23 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { ChildProcess, spawn } from 'child_process';
const copyfiles = require('copyfiles');
import {
readFile as fsReadFile,
} from 'fs/promises';
import {
write as fsWrite,
} from 'fs';
import { readFile as fsReadFile } from 'fs/promises';
import { write as fsWrite } from 'fs';
import { join } from 'path';
import { file } from 'tmp-promise';
import { promisify } from 'util';
const fsReadFileAsync = promisify(fsReadFile);
const fsWriteAsync = promisify(fsWrite);
import { UserSettings } from 'n8n-core';
// eslint-disable-next-line import/no-cycle
import { IBuildOptions } from '.';
import {
UserSettings,
} from 'n8n-core';
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const copyfiles = require('copyfiles');
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const fsReadFileAsync = promisify(fsReadFile);
const fsWriteAsync = promisify(fsWrite);
/**
* Create a custom tsconfig file as tsc currently has no way to define a base
@@ -30,23 +27,26 @@ import {
* @export
* @returns
*/
export async function createCustomTsconfig () {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createCustomTsconfig() {
// Get path to simple tsconfig file which should be used for build
const tsconfigPath = join(__dirname, '../../src/tsconfig-build.json');
// Read the tsconfi file
const tsConfigString = await fsReadFile(tsconfigPath, { encoding: 'utf8'}) as string;
const tsConfigString = await fsReadFile(tsconfigPath, { encoding: 'utf8' });
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const tsConfig = JSON.parse(tsConfigString);
// Set absolute include paths
const newIncludeFiles = [];
// eslint-disable-next-line no-restricted-syntax
for (const includeFile of tsConfig.include) {
newIncludeFiles.push(join(process.cwd(), includeFile));
}
tsConfig.include = newIncludeFiles;
// Write new custom tsconfig file
// eslint-disable-next-line @typescript-eslint/unbound-method
const { fd, path, cleanup } = await file({ dir: process.cwd() });
await fsWriteAsync(fd, Buffer.from(JSON.stringify(tsConfig, null, 2), 'utf8'));
@@ -56,7 +56,6 @@ export async function createCustomTsconfig () {
};
}
/**
* Builds and copies credentials and nodes
*
@@ -64,7 +63,8 @@ export async function createCustomTsconfig () {
* @param {IBuildOptions} [options] Options to overwrite default behaviour
* @returns {Promise<string>}
*/
export async function buildFiles (options?: IBuildOptions): Promise<string> {
export async function buildFiles(options?: IBuildOptions): Promise<string> {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, no-param-reassign
options = options || {};
let typescriptPath;
@@ -79,24 +79,31 @@ export async function buildFiles (options?: IBuildOptions): Promise<string> {
const tsconfigData = await createCustomTsconfig();
const outputDirectory = options.destinationFolder || UserSettings.getUserN8nFolderCustomExtensionPath();
const outputDirectory =
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
options.destinationFolder || UserSettings.getUserN8nFolderCustomExtensionPath();
// Supply a node base path so that it finds n8n-core and n8n-workflow
const nodeModulesPath = join(__dirname, '../../node_modules/');
let buildCommand = `${tscPath} --p ${tsconfigData.path} --outDir ${outputDirectory} --rootDir ${process.cwd()} --baseUrl ${nodeModulesPath}`;
let buildCommand = `${tscPath} --p ${
tsconfigData.path
} --outDir ${outputDirectory} --rootDir ${process.cwd()} --baseUrl ${nodeModulesPath}`;
if (options.watch === true) {
buildCommand += ' --watch';
}
let buildProcess: ChildProcess;
try {
buildProcess = spawn('node', buildCommand.split(' '), { windowsVerbatimArguments: true, cwd: process.cwd() });
buildProcess = spawn('node', buildCommand.split(' '), {
windowsVerbatimArguments: true,
cwd: process.cwd(),
});
// Forward the output of the child process to the main one
// that the user can see what is happening
//@ts-ignore
// @ts-ignore
buildProcess.stdout.pipe(process.stdout);
//@ts-ignore
// @ts-ignore
buildProcess.stderr.pipe(process.stderr);
// Make sure that the child process gets also always terminated
@@ -105,27 +112,33 @@ export async function buildFiles (options?: IBuildOptions): Promise<string> {
buildProcess.kill();
});
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
let errorMessage = error.message;
if (error.stdout !== undefined) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
errorMessage = `${errorMessage}\nGot following output:\n${error.stdout}`;
}
// Remove the tmp tsconfig file
// eslint-disable-next-line @typescript-eslint/no-floating-promises
tsconfigData.cleanup();
throw new Error(errorMessage);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return new Promise((resolve, reject) => {
['*.png', '*.node.json'].forEach(filenamePattern => {
copyfiles(
[join(process.cwd(), `./${filenamePattern}`), outputDirectory],
{ up: true },
() => resolve(outputDirectory));
['*.png', '*.node.json'].forEach((filenamePattern) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
copyfiles([join(process.cwd(), `./${filenamePattern}`), outputDirectory], { up: true }, () =>
resolve(outputDirectory),
);
});
buildProcess.on('exit', code => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
buildProcess.on('exit', (code) => {
// Remove the tmp tsconfig file
// eslint-disable-next-line @typescript-eslint/no-floating-promises
tsconfigData.cleanup();
});
});

View File

@@ -1,10 +1,11 @@
import * as fs from 'fs';
import {replaceInFile, ReplaceInFileConfig } from 'replace-in-file';
import { replaceInFile, ReplaceInFileConfig } from 'replace-in-file';
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const { promisify } = require('util');
const fsCopyFile = promisify(fs.copyFile);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
const fsCopyFile = promisify(fs.copyFile);
/**
* Creates a new credentials or node
@@ -15,16 +16,18 @@ const fsCopyFile = promisify(fs.copyFile);
* @param {object} replaceValues The values to replace in the template file
* @returns {Promise<void>}
*/
export async function createTemplate(sourceFilePath: string, destinationFilePath: string, replaceValues: object): Promise<void> {
export async function createTemplate(
sourceFilePath: string,
destinationFilePath: string,
replaceValues: object,
): Promise<void> {
// Copy the file to then replace the values in it
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
await fsCopyFile(sourceFilePath, destinationFilePath);
// Replace the variables in the template file
const options: ReplaceInFileConfig = {
files: [
destinationFilePath,
],
files: [destinationFilePath],
from: [],
to: [],
};

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line import/no-cycle
export * from './Build';
export * from './Create';
export * from './Interfaces';

View File

@@ -1,12 +1,10 @@
import {
ICredentialType,
NodePropertyTypes,
} from 'n8n-workflow';
import { ICredentialType, NodePropertyTypes } from 'n8n-workflow';
export class ClassNameReplace implements ICredentialType {
name = 'N8nNameReplace';
displayName = 'DisplayNameReplace';
properties = [
// The credentials to get from user and save encrypted.
// Properties can be defined exactly in the same way

View File

@@ -1,10 +1,5 @@
import { IExecuteFunctions } from 'n8n-core';
import {
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
export class ClassNameReplace implements INodeType {
description: INodeTypeDescription = {
@@ -29,13 +24,11 @@ export class ClassNameReplace implements INodeType {
default: '',
placeholder: 'Placeholder value',
description: 'The description text',
}
]
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
let item: INodeExecutionData;
@@ -48,10 +41,9 @@ export class ClassNameReplace implements INodeType {
myString = this.getNodeParameter('myString', itemIndex, '') as string;
item = items[itemIndex];
item.json['myString'] = myString;
item.json.myString = myString;
}
return this.prepareOutputData(items);
}
}

View File

@@ -1,10 +1,5 @@
import { ITriggerFunctions } from 'n8n-core';
import {
INodeType,
INodeTypeDescription,
ITriggerResponse,
} from 'n8n-workflow';
import { INodeType, INodeTypeDescription, ITriggerResponse } from 'n8n-workflow';
export class ClassNameReplace implements INodeType {
description: INodeTypeDescription = {
@@ -32,12 +27,10 @@ export class ClassNameReplace implements INodeType {
default: 1,
description: 'Every how many minutes the workflow should be triggered.',
},
]
],
};
async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> {
const interval = this.getNodeParameter('interval', 1) as number;
if (interval <= 0) {
@@ -48,7 +41,7 @@ export class ClassNameReplace implements INodeType {
// Every time the emit function gets called a new workflow
// executions gets started with the provided entries.
const entry = {
'exampleKey': 'exampleData'
exampleKey: 'exampleData',
};
this.emit([this.helpers.returnJsonArray([entry])]);
};
@@ -78,6 +71,5 @@ export class ClassNameReplace implements INodeType {
closeFunction,
manualTriggerFunction,
};
}
}

View File

@@ -1,14 +1,6 @@
import {
IWebhookFunctions,
} from 'n8n-core';
import {
IDataObject,
INodeTypeDescription,
INodeType,
IWebhookResponseData,
} from 'n8n-workflow';
import { IWebhookFunctions } from 'n8n-core';
import { IDataObject, INodeTypeDescription, INodeType, IWebhookResponseData } from 'n8n-workflow';
export class ClassNameReplace implements INodeType {
description: INodeTypeDescription = {
@@ -47,25 +39,18 @@ export class ClassNameReplace implements INodeType {
],
};
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
// The data to return and so start the workflow with
const returnData: IDataObject[] = [];
returnData.push(
{
headers: this.getHeaderData(),
params: this.getParamsData(),
query: this.getQueryData(),
body: this.getBodyData(),
}
);
returnData.push({
headers: this.getHeaderData(),
params: this.getParamsData(),
query: this.getQueryData(),
body: this.getBodyData(),
});
return {
workflowData: [
this.helpers.returnJsonArray(returnData)
],
workflowData: [this.helpers.returnJsonArray(returnData)],
};
}
}