tunnckocore / hela3 Goto Github PK
View Code? Open in Web Editor NEW:icecream: Powerful software development experience. :sparkles:
Home Page: https://tunnckocore.com
License: Mozilla Public License 2.0
:icecream: Powerful software development experience. :sparkles:
Home Page: https://tunnckocore.com
License: Mozilla Public License 2.0
Add task that cleans everything, including npm prune
and npm install
so we can prevent us from errors such as rollup/rollup#1528.
something like this would be possible
// `prog` is `sade` instance
export async function commit({ prog, shell, argv }) {
return prog
.usage()
.example()
.option('--coverage, --cov', 'Run with coverage', true)
.option('--check', 'Run with checking threshold coverage', true)
.option('--build, -b', 'Run with build step', true)
.action((opts) => shell('node test/index.js'));
}
When task fails, it exits with 0
.
execa
as exec
shell
as shellwould be release as patch
(fix) version. that's violation of the SemVer, but i hope no one use hela
yet ;d v1 will come when write the docs, api and tests
that updates package.json
scripts in cwd, so it is more easier to update old packages
Basically, pretest
replaces first found dest
with src
from the test.js
file, and posttest
does the opposite.
pretest.js
const { shell } = require('execa')
module.exports = ({ app }) => {
shell("sed -i 's/src/dest/' test.js").catch(er => app.emit('error', er))
}
use execa's .shell
intentionally, because we should pass a string to sed
posttest.js
const { shell } = require('execa')
module.exports = ({ app }) => {
shell("sed -i 's/dest/src/' test.js").catch(er => app.emit('error', er))
}
resolve-plugins
and plugins-resolver
Working implementation, and illustrative command/task config definition
hela v3:
Latest update. Couple of fixes and rethinkings.
@hela/core
import process from 'process';
import execa from 'execa-pro';
import sade from 'sade';
// the `dargs` from latest `gitcommit`
// externalize to `darks/darcks` - does opposite of `mri` parser
import dargs from './dargs'; // eslint-disable-line import/extensions, import/no-unresolved
const defaultOptions = {
stdio: 'inherit',
env: process.env,
};
/**
* Executes improved version of [execa][] `.shell` method.
*
* @param {string|string[]} cmd
* @param {object} [opts]
* @public
*/
export function shell(cmd, opts) {
const options = Object.assign({}, defaultOptions, opts);
return execa.shell(cmd, options);
}
/**
* Executes improved version of [execa][] `.exec` method.
*
* @param {string|string[]} cmd
* @param {object} [opts]
* @public
*/
export function exec(cmd, opts) {
const options = Object.assign({}, defaultOptions, opts);
return execa.exec(cmd, options);
}
/**
*
* @param {object} [options]
* @public
*/
export function hela(options) {
const prog = sade('hela').version('3.0.0');
const opts = Object.assign(defaultOptions, options, { lazy: true });
return Object.assign(prog, {
/**
* Define some function that will be called,
* when no commands are given.
* Allows bypassing the `No command specified.` error,
* instead for example show the help output.
* https://github.com/lukeed/sade/blob/987ffa974626e281de7ff0b9eaa63acadb2a134e/lib/index.js#L128-L130
*
* @param {Function} fn
*/
commandless(fn) {
const k = '__default__';
const KEY = '__DEF__';
prog.default = prog.curr = KEY; // eslint-disable-line no-multi-assign
prog.tree[KEY] = Object.assign({}, prog.tree[k]);
prog.tree[KEY].usage = '';
prog.tree[KEY].handler = async () => fn();
return prog;
},
/**
* Action that will be done when command is called.
*
* @param {Function} fn
* @public
*/
action(fn) {
const name = prog.curr || '__default__';
const task = prog.tree[name];
const stringActionWrapper = (cmd) => (...args) => {
const argv = args[args.length - 1];
const dargsOptions = Object.assign({ allowExtraFlags: true }, task);
const flags = `${dargs(argv, dargsOptions).join(' ')}`;
return shell(`${cmd} ${flags}`, opts);
};
if (typeof fn === 'function') {
task.handler = async function fnc(...args) {
const result = fn(...args);
if (typeof result === 'string') {
return stringActionWrapper(result)(...args);
}
// Specific & intentional case.
// 1. Allows directly calling execa.shell
// without passing the flags passed to hela task.
// 2. Runs the commands in series.
if (Array.isArray(result)) {
return shell(result, opts);
}
return result;
};
}
if (typeof fn === 'string') {
task.handler = stringActionWrapper(fn);
}
if (Array.isArray(fn)) {
fn.forEach((func) => {
prog.action(func);
});
}
// Friendlier error message.
task.handler.command = () => {
throw new Error('You cannot chain more after the `.action` call');
};
// Metadata about that specific task.
task.handler.getMeta = () => task;
return task.handler;
},
/**
* Start the magic. Parse input commands and flags,
* give them the corresponding command and its action function.
*
* @returns {Promise}
* @public
* @async
*/
async listen() {
const result = prog.parse(process.argv, opts);
const { args, name, handler } = result;
try {
return handler(...args);
} catch (err) {
err.commandArgv = args[args.length - 1];
err.commandArgs = args;
err.commandName = name;
throw err;
}
},
});
}
@hela/cli
/* eslint-disable import/extensions, import/no-unresolved */
import { hela } from './index';
const cli = hela();
/**
* Hela's CLI options and commands
*/
cli.commandless(() => cli.help());
cli.option('--show-stack', 'Show error stack trace when command fail', false);
/**
* TODO: loading of tasks/presets/config files
*
* @returns {Promise}
*/
async function main() {
const configModule = await import('./echo-preset');
const preset = Object.assign({}, configModule);
if (preset.default && typeof preset.default === 'function') {
const meta = preset.default.getMeta();
const taskName = meta.usage.split(' ')[0];
preset[taskName] = preset.default;
delete preset.default;
}
const tasks = Object.keys(preset).reduce((acc, name) => {
acc[name] = preset[name].getMeta();
return acc;
}, {});
cli.tree = Object.assign({}, cli.tree, tasks);
return cli.listen();
}
main()
.then(() => {
// This is a CLI file, so please.
// eslint-disable-next-line unicorn/no-process-exit
process.exit(0);
})
.catch((err) => {
console.error('Error task:', err.commandName);
if (err.commandArgv && !err.commandArgv['show-stack']) {
console.error('Error message:', err.name, err.message);
} else {
console.error('Error stack:', err.stack);
}
// This is a CLI file, so please.
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
});
download latest CONTRIBUTING.md file from the tunnckoCore/contributing, not the README.md. The contributing.md file is that file that would be included to each repo. The readme is the extended version which will have most changes in future.
extends
property in every config instead of presets
hela-preset-tunnckocore
to hela-config-tunnckocore
hela
readmeBasically we just mirror exactly the ESLint, except that rules
is called tasks
here, everything other is absolutely the same, including the resolving.
It's pretty easy to implement, currently is just Proof of Concept.
.presets
and .tasks
properties then merge the .tasks
with the tasks of the given preset.
.presets
property, then Object.assign all of their tasks.
.tasks
prop)resolve-plugins
(in work)resolve-plugins
shell
and exec
to detect if NODE_ENV === "test"
and return what is passed to them?
when tests are ready, just set everything to 100
so from this
.nycrc.json
{
"check-coverage": true,
"statements": 0,
"functions": 0,
"branches": 0,
"lines": 0
}
to this one
{
"check-coverage": true,
"statements": 100,
"functions": 100,
"branches": 100,
"lines": 100
}
Intentionally removing it from package.json. It is just very easy to update these files or directly replace them with fs.create*stream
, instead of getting package.json, checking if exist, then update it, then write the new package.json (in which may appear diffs because formatting)
Seems like an interesting project. Have any good example repos using this please?
(Maybe don't bother until after v3 is out....)
Allow loading from file, folder, json and etc. Basically when tunnckoCore/ideas#46 is released. This will allow presets
too :)
Incorrect handling of onerror
. For example, when nyc check-coverage
fails that coverage is below some threshold it exits with 0
error code. And actually not only this case.
$ "D:\Users\Documents\The Project\nodejs-test\parse-function\node_modules\.bin\hela" build:node
'"D:\Users\Documents\The"' 不是內部或外部命令、可執行的程式或批次檔。
ERR! Error: spawn D:\Users\Documents\The ENOENT
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.