architected v1.0.3
Architected
A tool for cli utilities.
About
Architected is a small wrapper around inquirer, listr and argi. It seamlessly manages arguments, user input and tasks.
Install
$ npm install --save architected
Usage
const architected = require('architected');
const config = {
// Configuration for architected
config: {
name: 'my cli app'
},
// The user input you want to receive.
input: {
name: {
message: 'A short description',
default: 'My default',
type: 'input'
}
},
// Cli commands
commands: {
name: {
message: 'A short description',
hidden: false
}
}
}
architected(config).then((result) => {
const { run, add } = result;
// Add a task
add('my first task', (ctx, task) => {
// Do the things
});
add('my second task', (ctx, task) => {
// Do other tings
});
// Run tasks
run().catch((err) => {
console.error(err);
});
}).catch((err) => {
console.error(err);
})
API
architected(config)
config
Configuration for architected.
name
Type: string
Required
The name of your project(will be used for --help
).
args
Type: array
Default: process.argv.slice(2)
Custom arguments. You should only change this if you have to.
commands
Commands passed as arguments.
Example:
Terminal:
my-app init
Code:
const architected = require('architected');
const config = {
config: {
name: 'my app'
},
commands: {
init: {
message: 'Add readme.md file'
}
}
}
architected(config).then((result) => {
const { run, add, ctx } = result;
// User called init
if (ctx.init) {
add('init stuff', (ctx, task) => {
});
}
run()
})
input
Input you want to receive.
name
Type: object
What the user input should be called. You need this to get the value of the user input.
message Type:
sting
A short description. It will be displayed in--help
and in the input prompt.default Type: every Will be used if the user does not specify a value.
save Type:
boolean
If set totrue
the user input will be saved and will be suggested next time the user executes your cli utility.boolean Type:
boolean
Force input to be eithertrue
orfalse
. Only for arguments.alias Type:
string
,array
Alternative name(eg. a short version). Only for arguments.hidden Type:
boolean
Specify if the input should be displayed in--help
. Only for arguments.type Type:
string
Type of the user input, can beinput
,confirm
,list
,rawlist
,expand
,checkbox
,password
,editor
. Only for prompt. Learn morechoices Type:
array
,function
Choices for the user can only be used for certaintype
s. Only for prompt. Learn morevalidate Type:
function
Receives user input as the first argument. Should returntrue
if input is valid orfalse
if input is invalid. Only for prompt.filter Type:
function
Receives user input as the first argument. Should return the filtered value. Only for prompt.when Type:
function
Receives the previous user input as the first argument. Should returntrue
if the prompt can be displayed. Only for prompt.pageSize Type:
number
The number of lines that will be rendered. Can only be used forlist
,rawList
,expand
orcheckbox
. Only for prompt.
Returns
Type: promise
Will be called when all the user input is received and parsed.
ctx
Type: object
An object containing the user input.
Example:
...
console.log(ctx.name);
// Logs name input to the console.
...
add(name, options, task)
Add a new task
Example:
...
add('my-task', (ctx, task) => {
// ctx = up to date user input
// `task` can be used to control the task
if (ctx.input === 'skip') {
task.skip('reason');
}
ctx.enableOther = true;
});
add('my-task-2', { }, (ctx, task) => {
if (ctx.input === 'skip') {
task.skip('reason');
}
});
...
name
Type: string
The name of your task. Will be used for logging.
options
Type: object
Options for listr
. Learn more
task
Type: function
You should do your stuff here.
run(ctx)
Execute all tasks.
ctx
Type: object
Custom context. Will be Object.assign
ed to the user input.
Examples
Basic
A simple
package.json
generator.
#!/usr/bin/env node
const { writeFileSync, mkdirSync } = require('fs');
const { join } = require('path');
const architected = require('architected');
architected({
config: {
name: 'basic-example'
},
input: {
path: {
message: 'Where your project should be',
default: process.cwd(),
forceCli: true
},
name: {
message: 'Whats the name',
type: 'input',
forceInput: true
},
description: {
message: 'Whats your project about',
type: 'input'
}
}
}).then((result) => {
const { run, add } = result;
add('generate package.json', (ctx, task) => {
ctx.pkg = `{
"name": "${ ctx.name }",
"description": "${ ctx.description }",
"version": "0.0.0",
"license": "MIT"
}`
});
add('create project directory', (ctx, task) => {
ctx.created = true;
try {
mkdirSync(join(ctx.path, ctx.name));
} catch (err) {
ctx.created = false;
throw new Error(`Could not create project dir\n${ err }`);
}
});
add('write package.json', { enabled: (ctx) => ctx.created }, (ctx, task) => {
try {
writeFileSync(join(ctx.path, ctx.name, 'package.json'), ctx.pkg);
} catch (err) {
throw new Error(`Could not create package.json\n${ err }`);
}
});
run().catch((err) => {
console.error(err);
})
}).catch((err) => {
console.error(err);
});
Observable
A simple node.js project boilerplate. Built using observables.
#!/usr/bin/env node
const { writeFileSync, mkdirSync } = require('fs');
const { join } = require('path');
const Observable = require('zen-observable');
const delay = require('delay'); // For a cool effect
const architected = require('architected');
architected({
config: {
name: 'observable-example'
},
input: {
path: {
message: 'Where your project should be',
default: process.cwd(),
forceCli: true
},
name: {
message: 'Whats the name',
type: 'input',
forceInput: true
},
description: {
message: 'Whats your project about',
type: 'input'
},
cli: {
message: 'Do you need a cli',
type: 'confirm',
default: false,
boolean: true
}
}
}).then((result) => {
const { run, add } = result;
add('generate files', (ctx, task) => (
new Observable(observer => {
delay(100)
.then(() => {
observer.next('Generating package.json');
ctx.pkg = `{
"name": "${ ctx.name }",
"description": "${ ctx.description }",
"version": "0.0.0",
"license": "MIT"${ ctx.cli ? ',\n "bin": "./cli.js"' : '' }
}`;
return delay(300);
}).then(() => {
observer.next('Generating index.js');
ctx.i = `module.exports = () => {
return {
name: '${ ctx.name }'
}
};`;
return delay(300);
}).then(() => {
if (ctx.cli) {
observer.next('Generating cli.js');
ctx.clijs = `const ${ ctx.name } = require('./');
${ ctx.name }();`;
}
observer.complete();
});
})
));
add('create project directory', (ctx, task) => {
ctx.created = true;
mkdirSync(join(ctx.path, ctx.name));
try {
} catch (err) {
ctx.created = false;
throw new Error(`Could not create project dir\n${ err }`);
}
});
add('write files', { enabled: (ctx) => ctx.created }, (ctx, task) => (
new Observable(observer => {
delay(0)
.then(() => {
observer.next('Write package.json');
writeFileSync(join(ctx.path, ctx.name, 'package.json'), ctx.pkg);
return delay(300);
}).then(() => {
observer.next('Write index.js');
writeFileSync(join(ctx.path, ctx.name, 'index.js'), ctx.i);
return delay(300);
}).then(() => {
if (ctx.cli) {
observer.next('Write cli.js');
writeFileSync(join(ctx.path, ctx.name, 'cli.js'), ctx.clijs);
}
observer.complete();
});
})
));
run().catch((err) => {
console.error(err);
})
}).catch((err) => {
console.error(err);
});
License
MIT © Tobias Herber