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 = {
config: {
name: 'my cli app'
},
input: {
name: {
message: 'A short description',
default: 'My default',
type: 'input'
}
},
commands: {
name: {
message: 'A short description',
hidden: false
}
}
}
architected(config).then((result) => {
const { run, add } = result;
add('my first task', (ctx, task) => {
});
add('my second task', (ctx, task) => {
});
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;
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 to true
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 either true
or false
.
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 be input
, confirm
, list
, rawlist
, expand
, checkbox
, password
, editor
.
Only for prompt.
Learn more
-
choices
Type: array
, function
Choices for the user can only be used for certain type
s.
Only for prompt.
Learn more
-
validate
Type: function
Receives user input as the first argument. Should return true
if input is valid or false
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 return true
if the prompt can be displayed.
Only for prompt.
-
pageSize
Type: number
The number of lines that will be rendered. Can only be used for list
, rawList
, expand
or checkbox
.
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);
...
add(name, [options], task)
Add a new task
Example:
...
add('my-task', (ctx, 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.
Learn more
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');
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