mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
⚡ Replace vorpal with oclif in node-dev
This commit is contained in:
parent
be3177a101
commit
cd75c63f83
5
packages/node-dev/bin/run
Executable file
5
packages/node-dev/bin/run
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
require('@oclif/command').run()
|
||||
.then(require('@oclif/command/flush'))
|
||||
.catch(require('@oclif/errors/handle'))
|
3
packages/node-dev/bin/run.cmd
Executable file
3
packages/node-dev/bin/run.cmd
Executable file
|
@ -0,0 +1,3 @@
|
|||
@echo off
|
||||
|
||||
node "%~dp0\run" %*
|
|
@ -1,49 +1,59 @@
|
|||
import Vorpal = require('vorpal');
|
||||
import { Args } from 'vorpal';
|
||||
import {
|
||||
UserSettings,
|
||||
} from "n8n-core";
|
||||
import { Command, flags } from '@oclif/command';
|
||||
|
||||
import {
|
||||
buildFiles,
|
||||
IBuildOptions,
|
||||
} from '../src';
|
||||
|
||||
import {
|
||||
UserSettings,
|
||||
} from "n8n-core";
|
||||
export class Build extends Command {
|
||||
static description = 'Builds credentials and nodes and copies it to n8n custom extension folder';
|
||||
|
||||
module.exports = (vorpal: Vorpal) => {
|
||||
return vorpal
|
||||
.command('build')
|
||||
// @ts-ignore
|
||||
.description('Builds credentials and nodes and copies it to n8n custom extension folder')
|
||||
.option('--destination <folder>',
|
||||
`The path to copy the compiles files to [default: ${UserSettings.getUserN8nFolderCustomExtensionPath()}]`)
|
||||
.option('--watch',
|
||||
'Starts in watch mode and automatically builds and copies file whenever they change')
|
||||
.option('\n')
|
||||
.action(async (args: Args) => {
|
||||
static examples = [
|
||||
`$ n8n-node-dev build`,
|
||||
`$ n8n-node-dev build --destination ~/n8n-nodes`,
|
||||
`$ n8n-node-dev build --watch`,
|
||||
];
|
||||
|
||||
console.log('\nBuild credentials and nodes');
|
||||
console.log('=========================');
|
||||
static flags = {
|
||||
help: flags.help({ char: 'h' }),
|
||||
destination: flags.string({
|
||||
char: 'd',
|
||||
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',
|
||||
}),
|
||||
};
|
||||
|
||||
try {
|
||||
const options: IBuildOptions = {};
|
||||
async run() {
|
||||
const { flags } = this.parse(Build);
|
||||
|
||||
if (args.options.destination) {
|
||||
options.destinationFolder = args.options.destination;
|
||||
}
|
||||
if (args.options.watch) {
|
||||
options.watch = true;
|
||||
}
|
||||
this.log('\nBuild credentials and nodes');
|
||||
this.log('=========================');
|
||||
|
||||
const outputDirectory = await buildFiles(options);
|
||||
try {
|
||||
const options: IBuildOptions = {};
|
||||
|
||||
console.log(`The nodes got build and saved into the following folder:\n${outputDirectory}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('\nGOT ERROR');
|
||||
console.error('====================================');
|
||||
console.error(error.message);
|
||||
return;
|
||||
if (flags.destination) {
|
||||
options.destinationFolder = flags.destination;
|
||||
}
|
||||
if (flags.watch) {
|
||||
options.watch = true;
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
const outputDirectory = await buildFiles(options);
|
||||
|
||||
this.log(`The nodes got build and saved into the following folder:\n${outputDirectory}`);
|
||||
|
||||
} catch (error) {
|
||||
this.error('\nGOT ERROR');
|
||||
this.error('====================================');
|
||||
this.error(error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
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';
|
||||
import Vorpal = require('vorpal');
|
||||
import { Args } from 'vorpal';
|
||||
|
||||
const { promisify } = require('util');
|
||||
const fsAccess = promisify(fs.access);
|
||||
|
@ -12,149 +11,151 @@ import {
|
|||
createTemplate
|
||||
} from '../src';
|
||||
|
||||
module.exports = (vorpal: Vorpal) => {
|
||||
return vorpal
|
||||
.command('new')
|
||||
// @ts-ignore
|
||||
.description('Create new credentials/node')
|
||||
.action(async (args: Args) => {
|
||||
try {
|
||||
console.log('\nCreate new credentials/node');
|
||||
console.log('=========================');
|
||||
export class New extends Command {
|
||||
static description = 'Create new credentials/node';
|
||||
|
||||
// Ask for the type of not to be created
|
||||
const typeQuestion: inquirer.QuestionCollection = {
|
||||
name: 'type',
|
||||
static examples = [
|
||||
`$ n8n-node-dev new`,
|
||||
];
|
||||
|
||||
async run() {
|
||||
|
||||
try {
|
||||
this.log('\nCreate new credentials/node');
|
||||
this.log('=========================');
|
||||
|
||||
// Ask for the type of not to be created
|
||||
const typeQuestion: inquirer.Question = {
|
||||
name: 'type',
|
||||
type: 'list',
|
||||
default: 'Node',
|
||||
message: 'What do you want to create?',
|
||||
choices: [
|
||||
'Credentials',
|
||||
'Node',
|
||||
],
|
||||
};
|
||||
|
||||
const typeAnswers = await inquirer.prompt(typeQuestion);
|
||||
|
||||
let sourceFolder = '';
|
||||
const sourceFileName = 'simple.ts';
|
||||
let defaultName = '';
|
||||
let getDescription = false;
|
||||
|
||||
|
||||
if (typeAnswers.type === 'Node') {
|
||||
// Create new node
|
||||
|
||||
getDescription = true;
|
||||
|
||||
const nodeTypeQuestion: inquirer.Question = {
|
||||
name: 'nodeType',
|
||||
type: 'list',
|
||||
default: 'Node',
|
||||
message: 'What do you want to create?',
|
||||
default: 'Execute',
|
||||
message: 'What kind of node do you want to create?',
|
||||
choices: [
|
||||
'Credentials',
|
||||
'Node',
|
||||
'Execute',
|
||||
'Trigger',
|
||||
'Webhook',
|
||||
],
|
||||
};
|
||||
|
||||
const typeAnswers = await inquirer.prompt(typeQuestion);
|
||||
const nodeTypeAnswers = await inquirer.prompt(nodeTypeQuestion);
|
||||
|
||||
let sourceFolder = '';
|
||||
const sourceFileName = 'simple.ts';
|
||||
let defaultName = '';
|
||||
let getDescription = false;
|
||||
|
||||
|
||||
if (typeAnswers.type === 'Node') {
|
||||
// Create new node
|
||||
|
||||
getDescription = true;
|
||||
|
||||
const nodeTypeQuestion: inquirer.QuestionCollection = {
|
||||
name: 'nodeType',
|
||||
type: 'list',
|
||||
default: 'Execute',
|
||||
message: 'What kind of node do you want to create?',
|
||||
choices: [
|
||||
'Execute',
|
||||
'Trigger',
|
||||
'Webhook',
|
||||
],
|
||||
};
|
||||
|
||||
const nodeTypeAnswers = await inquirer.prompt(nodeTypeQuestion);
|
||||
|
||||
// Choose a the template-source-file depending on user input.
|
||||
sourceFolder = 'execute';
|
||||
defaultName = 'My Node';
|
||||
if (nodeTypeAnswers.nodeType === 'Trigger') {
|
||||
sourceFolder = 'trigger';
|
||||
defaultName = 'My Trigger';
|
||||
} else if (nodeTypeAnswers.nodeType === 'Webhook') {
|
||||
sourceFolder = 'webhook';
|
||||
defaultName = 'My Webhook';
|
||||
}
|
||||
} else {
|
||||
// Create new credentials
|
||||
|
||||
sourceFolder = 'credentials';
|
||||
defaultName = 'My Service API';
|
||||
// Choose a the template-source-file depending on user input.
|
||||
sourceFolder = 'execute';
|
||||
defaultName = 'My Node';
|
||||
if (nodeTypeAnswers.nodeType === 'Trigger') {
|
||||
sourceFolder = 'trigger';
|
||||
defaultName = 'My Trigger';
|
||||
} else if (nodeTypeAnswers.nodeType === 'Webhook') {
|
||||
sourceFolder = 'webhook';
|
||||
defaultName = 'My Webhook';
|
||||
}
|
||||
} else {
|
||||
// Create new credentials
|
||||
|
||||
// Ask additional questions to know with what values the
|
||||
// variables in the template file should be replaced with
|
||||
const additionalQuestions = [
|
||||
sourceFolder = 'credentials';
|
||||
defaultName = 'My Service API';
|
||||
}
|
||||
|
||||
// Ask additional questions to know with what values the
|
||||
// variables in the template file should be replaced with
|
||||
const additionalQuestions = [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'input',
|
||||
default: defaultName,
|
||||
message: 'How should the node be called?',
|
||||
},
|
||||
];
|
||||
|
||||
if (getDescription === true) {
|
||||
// Get also a node description
|
||||
additionalQuestions.push({
|
||||
name: 'description',
|
||||
type: 'input',
|
||||
default: 'Node converts input data to chocolate',
|
||||
message: 'What should the node description be?',
|
||||
});
|
||||
}
|
||||
|
||||
const additionalAnswers = await inquirer.prompt(additionalQuestions as inquirer.Questions);
|
||||
|
||||
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 sourceFilePath = join(__dirname, '../../templates', sourceFolder, sourceFileName);
|
||||
|
||||
// Check if node with the same name already exists in target folder
|
||||
// to not overwrite it by accident
|
||||
try {
|
||||
await fsAccess(destinationFilePath);
|
||||
|
||||
// File does already exist. So ask if it should be overwritten.
|
||||
const overwriteQuestion: inquirer.Questions = [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'input',
|
||||
default: defaultName,
|
||||
message: 'How should the node be called?',
|
||||
name: 'overwrite',
|
||||
type: 'confirm',
|
||||
default: false,
|
||||
message: `The file "${destinationFilePath}" already exists and would be overwritten. Do you want to proceed and overwrite the file?`,
|
||||
},
|
||||
];
|
||||
|
||||
if (getDescription === true) {
|
||||
// Get also a node description
|
||||
additionalQuestions.push({
|
||||
name: 'description',
|
||||
type: 'input',
|
||||
default: 'Node converts input data to chocolate',
|
||||
message: 'What should the node description be?',
|
||||
});
|
||||
const overwriteAnswers = await inquirer.prompt(overwriteQuestion);
|
||||
|
||||
if (overwriteAnswers.overwrite === false) {
|
||||
this.log('\nNode creation got canceled!');
|
||||
return;
|
||||
}
|
||||
|
||||
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 sourceFilePath = join(__dirname, '../../templates', sourceFolder, sourceFileName);
|
||||
|
||||
// Check if node with the same name already exists in target folder
|
||||
// to not overwrite it by accident
|
||||
try {
|
||||
await fsAccess(destinationFilePath);
|
||||
|
||||
// File does already exist. So ask if it should be overwritten.
|
||||
const overwriteQuestion: inquirer.QuestionCollection = [
|
||||
{
|
||||
name: 'overwrite',
|
||||
type: 'confirm',
|
||||
default: false,
|
||||
message: `The file "${destinationFilePath}" already exists and would be overwritten. Do you want to proceed and overwrite the file?`,
|
||||
},
|
||||
];
|
||||
|
||||
const overwriteAnswers = await inquirer.prompt(overwriteQuestion);
|
||||
|
||||
if (overwriteAnswers.overwrite === false) {
|
||||
console.log('\nNode creation got canceled!');
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
// File does not exist. That is exactly what we want so go on.
|
||||
}
|
||||
|
||||
// Make sure that the variables in the template file get formated
|
||||
// in the correct way
|
||||
const replaceValues = {
|
||||
ClassNameReplace: changeCase.pascalCase(nodeName),
|
||||
DisplayNameReplace: changeCase.titleCase(nodeName),
|
||||
N8nNameReplace: changeCase.camelCase(nodeName),
|
||||
NodeDescriptionReplace: additionalAnswers.description,
|
||||
};
|
||||
|
||||
await createTemplate(sourceFilePath, destinationFilePath, replaceValues);
|
||||
|
||||
console.log('\nExecution was successfull:');
|
||||
console.log('====================================');
|
||||
|
||||
console.log('Node got created: ' + destinationFilePath);
|
||||
} catch (error) {
|
||||
console.error('\nGOT ERROR');
|
||||
console.error('====================================');
|
||||
console.error(error.message);
|
||||
return;
|
||||
// File does not exist. That is exactly what we want so go on.
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
// Make sure that the variables in the template file get formated
|
||||
// in the correct way
|
||||
const replaceValues = {
|
||||
ClassNameReplace: changeCase.pascalCase(nodeName),
|
||||
DisplayNameReplace: changeCase.titleCase(nodeName),
|
||||
N8nNameReplace: changeCase.camelCase(nodeName),
|
||||
NodeDescriptionReplace: additionalAnswers.description,
|
||||
};
|
||||
|
||||
await createTemplate(sourceFilePath, destinationFilePath, replaceValues);
|
||||
|
||||
this.log('\nExecution was successfull:');
|
||||
this.log('====================================');
|
||||
|
||||
this.log('Node got created: ' + destinationFilePath);
|
||||
} catch (error) {
|
||||
this.error('\nGOT ERROR');
|
||||
this.error('====================================');
|
||||
this.error(error.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import Vorpal = require('vorpal');
|
||||
|
||||
if (process.argv.length === 2) {
|
||||
// When no command is given choose by default help
|
||||
process.argv.push('help');
|
||||
}
|
||||
|
||||
const command = process.argv[2];
|
||||
|
||||
// Check if the command the user did enter is supported else stop
|
||||
const supportedCommands = [
|
||||
'build',
|
||||
'help',
|
||||
'new',
|
||||
];
|
||||
|
||||
if (!supportedCommands.includes(command)) {
|
||||
console.log(`The command "${command}" is not known!`);
|
||||
process.argv.push('help');
|
||||
}
|
||||
|
||||
const vorpal = new Vorpal();
|
||||
vorpal
|
||||
.use(require('./commands/build.js'))
|
||||
.use(require('./commands/new.js'))
|
||||
.delimiter('')
|
||||
.show()
|
||||
.parse(process.argv);
|
||||
|
||||
|
||||
process
|
||||
.on('unhandledRejection', (reason, p) => {
|
||||
console.error(reason, 'Unhandled Rejection at Promise', p);
|
||||
})
|
||||
.on('uncaughtException', err => {
|
||||
console.error(err, 'Uncaught Exception thrown');
|
||||
process.exit(1);
|
||||
});
|
|
@ -13,6 +13,10 @@
|
|||
},
|
||||
"main": "dist/src/index",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"oclif": {
|
||||
"commands": "./dist/commands",
|
||||
"bin": "run"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "npm run watch",
|
||||
"build": "tsc",
|
||||
|
@ -21,7 +25,7 @@
|
|||
"watch": "tsc --watch"
|
||||
},
|
||||
"bin": {
|
||||
"n8n-node-dev": "./dist/index.js"
|
||||
"n8n-node-dev": "./bin/run"
|
||||
},
|
||||
"keywords": [
|
||||
"development",
|
||||
|
@ -30,6 +34,7 @@
|
|||
"n8n"
|
||||
],
|
||||
"files": [
|
||||
"bin",
|
||||
"dist"
|
||||
],
|
||||
"devDependencies": {
|
||||
|
@ -39,13 +44,14 @@
|
|||
"tslint": "^5.17.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@oclif/command": "^1.5.18",
|
||||
"@oclif/errors": "^1.2.2",
|
||||
"change-case": "^3.1.0",
|
||||
"inquirer": "^6.3.1",
|
||||
"n8n-core": "^0.2.0",
|
||||
"n8n-workflow": "^0.3.0",
|
||||
"replace-in-file": "^4.1.0",
|
||||
"typescript": "~3.5.2",
|
||||
"vorpal": "^1.12.0"
|
||||
"typescript": "~3.5.2"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
|
|
Loading…
Reference in a new issue