Skip to content

Commit

Permalink
feat: upgrades
Browse files Browse the repository at this point in the history
- cli: support cosmiconfig and --config flag
- core: better defaults
- yaro: fix single command mode and help output

Signed-off-by: Charlike Mike Reagent <[email protected]>
  • Loading branch information
tunnckoCore committed Feb 29, 2020
1 parent f9cbdf4 commit edd33d5
Show file tree
Hide file tree
Showing 13 changed files with 286 additions and 106 deletions.
5 changes: 0 additions & 5 deletions hela.config.js

This file was deleted.

5 changes: 5 additions & 0 deletions hela.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// 'use strict';

// const helaDev = require('@hela/dev');

// Object.assign(exports, helaDev);
3 changes: 2 additions & 1 deletion modules/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
},
"scripts": {},
"dependencies": {
"@hela/core": "^3.0.1"
"@hela/core": "^3.0.1",
"cosmiconfig": "^6.0.0"
},
"keywords": [
"tunnckocorehq",
Expand Down
147 changes: 76 additions & 71 deletions modules/cli/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,50 @@

'use strict';

const fs = require('fs');
const path = require('path');
const { hela, HelaError } = require('@hela/core');

const CWD = process.cwd();
const { hela, HelaError, utils } = require('@hela/core');
const { cosmiconfig } = require('cosmiconfig');

const { log } = console;

const argv = utils.parseArgv(process.argv.slice(2), {
default: {
cwd: process.cwd(),
showStack: false,
verbose: false,
},
});

const explorer = cosmiconfig('hela');
const prog = hela();

prog
.option('--cwd', 'some global flag')
.option('--showStack', 'Show more detailed info when errors', false);
.option('--cwd', 'some global flag', argv.cwd)
.option('--verbose', 'Print more verbose output', false)
.option('--showStack', 'Show more detailed info when errors', false)
.option('-c, --config', 'Path to config file', 'hela.config.js');

module.exports = async function main() {
const cfg = await getConfig('hela', { cwd: CWD });
const cfgPath = argv.c || argv.config;
const cfg = cfgPath ? await explorer.load(cfgPath) : await explorer.search();

if (!cfg || (cfg && !cfg.config)) {
throw new HelaError('No config or preset found');
if (!isValidConfig(cfg)) {
throw new HelaError('No config found or invalid. Try "--config" flag.');
}

const config = cfg.filepath.endsWith('.json')
? fromJson(cfg.config)
: cfg.config;

if (process.argv.includes('--verbose')) {
log('[info] hela: Loading config ->', path.relative(CWD, cfg.filepath));
if (argv.verbose) {
log('[info] hela: Loading ->', path.relative(argv.cwd, cfg.filepath));
}

if (!isValidConfig(config)) {
throw new HelaError('No config found or invalid');
let bypass = false;
if (cfg.filepath.endsWith('package.json')) {
const pkg = require(cfg.filepath);
cfg.config = fromJson(pkg.hela);
bypass = true;
}

prog.extendWith(config);
if (bypass || cfg.filepath.endsWith('.js') || cfg.filepath.endsWith('.cjs')) {
prog.extendWith(cfg.config);
}

return prog.parse();
};
Expand All @@ -50,14 +60,9 @@ function fromJson(config) {
);
}

return require(path.join(CWD, config));
return require(path.join(argv.cwd, config));
}

// config.extends / pkg.hela.extends
// TODOs:
// should try to load config package (like `@hela/dev`) up to homedir,
// and check if it is globally installed.
// hint: detect-installed, get-installed-path, find-up and etc
if (config && typeof config === 'object') {
if (config.cwd) {
if (!config.extends) {
Expand Down Expand Up @@ -87,49 +92,49 @@ function isObject(val) {
return val && typeof val === 'object' && Array.isArray(val) === false;
}

async function getConfig(name, { cwd } = {}) {
let cfg = await getPkg(cwd);

// ! suppport ESM config files, and/or the freaking .mjs
// ! in some wa without the `esm` package,
// ! because I assume that `hela` bundle will be even more huge
// ! it's freaking that Hela is 3x bigger than the whole Deno (~10mb)!
const jsConfigFiles = ['hela.config.js', '.helarc.js'];

if (!cfg) {
const filepath = jsConfigFiles
.map((x) => path.join(cwd, x))
.find((fp) => (fs.existsSync(fp) ? fp : false));

let config = null;

try {
config = require(filepath);
} catch (err) {
if (process.argv.includes('--verbose')) {
log('[error] hela: while loading config!', err.message || err);
}
config = null;
}

cfg = { config, filepath };
}

return cfg;
}

async function getPkg(cwd) {
let pkg = null;
const filepath = path.join(cwd, 'package.json');

try {
pkg = JSON.parse(await fs.promises.readFile(filepath, 'utf8'));
} catch (err) {
if (process.argv.includes('--verbose')) {
log('[error] hela: while loading config!', err.message || err);
}
return null;
}

return pkg.hela ? { config: pkg.hela, filepath } : null;
}
// async function getConfig(name, { cwd } = {}) {
// let cfg = await getPkg(cwd);

// // ! suppport ESM config files, and/or the freaking .mjs
// // ! in some wa without the `esm` package,
// // ! because I assume that `hela` bundle will be even more huge
// // ! it's freaking that Hela is 3x bigger than the whole Deno (~10mb)!
// const jsConfigFiles = ['hela.config.js', '.helarc.js'];

// if (!cfg) {
// const filepath = jsConfigFiles
// .map((x) => path.join(cwd, x))
// .find((fp) => (fs.existsSync(fp) ? fp : false));

// let config = null;

// try {
// config = require(filepath);
// } catch (err) {
// if (process.argv.includes('--verbose')) {
// log('[error] hela: while loading config!', err.message || err);
// }
// config = null;
// }

// cfg = { config, filepath };
// }

// return cfg;
// }

// async function getPkg(cwd) {
// let pkg = null;
// const filepath = path.join(cwd, 'package.json');

// try {
// pkg = JSON.parse(await fs.promises.readFile(filepath, 'utf8'));
// } catch (err) {
// if (process.argv.includes('--verbose')) {
// log('[error] hela: while loading config!', err.message || err);
// }
// return null;
// }

// return pkg.hela ? { config: pkg.hela, filepath } : null;
// }
4 changes: 4 additions & 0 deletions modules/core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ class HelaError extends Error {

class Hela extends Yaro {
constructor(progName = 'hela', options) {
if (progName && typeof progName === 'object') {
options = progName; // eslint-disable-line no-param-reassign
progName = 'hela'; // eslint-disable-line no-param-reassign
}
super(progName, {
defaultsToHelp: true,
allowUnknownFlags: true,
Expand Down
76 changes: 54 additions & 22 deletions modules/yaro/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ class Yaro {
...options,
};

if (
hasOwn(this.settings, 'defaultsToHelp') &&
this.settings.singleMode === true
) {
this.settings.defaultsToHelp = false;
this.settings.defaultCommand = '$$root';
}

this.programName = progName;
this.commands = new Map();
this.flags = new Map();
Expand All @@ -46,7 +54,7 @@ class Yaro {
}

command(rawName, description, config) {
if (this.settings.singleMode === true) {
if (this.settings.singleMode === true && !config.singleMode) {
throw new Error('in single mode cannot add commands');
}

Expand Down Expand Up @@ -113,12 +121,15 @@ class Yaro {
}

action(handler) {
const fn = (...args) => handler(...args);
const fn = (...args) => handler.apply(this, args);

if (!this.currentCommand && this.settings.singleMode === true) {
this.command('$$root', 'On single mode', { singleMode: true });
}
this.currentCommand.handler = fn;
this.__updateCommandsList();

return Object.assign(fn, this);
return this.settings.singleMode === true ? this : Object.assign(fn, this);
}

extendWith(inst) {
Expand Down Expand Up @@ -176,7 +187,7 @@ class Yaro {
const sections = this.buildHelpOutput(commandName);

if (typeof this.settings.helpHandler === 'function') {
this.settings.helpHandler(sections);
this.settings.helpHandler.call(this, sections);
return this;
}

Expand All @@ -190,7 +201,9 @@ class Yaro {

buildHelpOutput(commandName) {
const sections = [];
const commands = [...this.commands.values()];
const commands = [...this.commands.values()].filter(
(x) => x.commandName !== '$$root',
);

// it's general help, so include commands
if (!commandName) {
Expand All @@ -202,16 +215,18 @@ class Yaro {
}`,
});

sections.push(this.createSection('Commands', commands));

sections.push({
title: `For more info, run any command with the \`--help\` flag`,
body: commands
.slice(0, 2)
.map((cmd) => ` $ ${this.programName} ${cmd.commandName} --help`)
.filter(Boolean)
.join('\n'),
});
if (commands.length > 0) {
sections.push(this.createSection('Commands', commands));

sections.push({
title: `For more info, run any command with the \`--help\` flag`,
body: commands
.slice(0, 2)
.map((cmd) => ` $ ${this.programName} ${cmd.commandName} --help`)
.filter(Boolean)
.join('\n'),
});
}
} else {
const command = this.commands.get(commandName);
sections.push({
Expand Down Expand Up @@ -246,7 +261,7 @@ class Yaro {
? example
: (progName) => ` $ ${progName} ${example}`,
)
.map((exampleFn) => exampleFn(this.programName))
.map((exampleFn) => exampleFn.call(this, this.programName))
.join('\n'),
});
}
Expand All @@ -255,6 +270,12 @@ class Yaro {
}

parse(argv = processArgv, options = {}) {
// NOTE: it's in a single command mode but does not have `.action` defined,
// so we create noop one o uccessfully continue
if (!this.currentCommand && this.settings.singleMode === true) {
this.action(() => {});
}

this.settings = { ...this.settings, options };
this.result = this.__getResult(argv.slice(2));

Expand Down Expand Up @@ -297,7 +318,10 @@ class Yaro {
return res;
}

command.handler(...this.result.args.concat(this.result.flags, res));
command.handler.apply(
this,
this.result.args.concat(this.result.flags, res),
);
return res;
}

Expand Down Expand Up @@ -382,13 +406,20 @@ class Yaro {

createSection(title, arr) {
const longestName = findLongest(arr.map((x) => x.rawName || x));
const longestDesc = findLongest(arr.map((x) => x.description || x));
return {
title,
body: arr
.map(
(x) =>
` ${padRight(x.rawName, longestName.length)} ${x.description}`,
)
.map((x) => {
const def =
title === 'Flags' && x.config
? ` (default: ${JSON.stringify(x.config.default)})`
: '';
const name = padRight(x.rawName, longestName.length);
const desc = padRight(x.description, longestDesc.length);

return ` ${name} ${desc} ${def}`;
})
.join('\n'),
};
}
Expand All @@ -398,9 +429,10 @@ class Yaro {
const flag = {
rawName,
description,
config: { ...config },
};

if (config !== undefined) {
flag.config = flag.config || {};
flag.config.default = config;
}

Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@
"extends": [
"@tunnckocore"
]
},
"hela": {
"extends": "@hela/dev"
}
}
3 changes: 2 additions & 1 deletion packages/eslint/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
const mod = require('../src/index');

test('todo test for mod', () => {
expect(typeof mod).toStrictEqual('function');
expect(typeof mod).toStrictEqual('object');
expect(typeof mod.helaCommand).toStrictEqual('function');
});
Loading

0 comments on commit edd33d5

Please sign in to comment.