Giter VIP home page Giter VIP logo

hela3's People

Contributors

renovate-bot avatar renovate[bot] avatar tunnckocore avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

renovate-tests

hela3's Issues

add task for adding latest CONTRIBUTING.md

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.

Change what is exposed to each task

  • expose execa as exec
  • expose execa's shell as shell

would 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

Major: Rename presets to Shareable Configs

  • switch to use extends property in every config instead of presets
  • rename hela-preset-tunnckocore to hela-config-tunnckocore
  • update the hela readme
  • semver major

Basically we just mirror exactly the ESLint, except that rules is called tasks here, everything other is absolutely the same, including the resolving.

Integrate `sade`

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'));
}

add init task

that updates package.json scripts in cwd, so it is more easier to update old packages

CLI: fix silent errors

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.

example repos

Seems like an interesting project. Have any good example repos using this please?

(Maybe don't bother until after v3 is out....)

Load multiple presets and recursion

It's pretty easy to implement, currently is just Proof of Concept.

Resolution

  • if a preset has .presets and .tasks properties then merge the .tasks with the tasks of the given preset.
    • Not sure for the precedence.
  • if a preset has only .presets property, then Object.assign all of their tasks.
    • Precedence: from bottom to top.
  • otherwise treat preset as object of tasks (each preset is always an object with at least .tasks prop)

v3

  • asynchronous presets resolving - resolve-plugins (in work)
  • allow presets to be written in ES Modules
    • it will be available because resolve-plugins
  • allow sync/async task functions to return string/array
  • written in ESM, uses hela-config-tunnckocore@3
  • shell and exec to detect if NODE_ENV === "test" and return what is passed to them?
    • makes config testing easier

v3 major release

  • asynchronous preset/config loading
    • through resolve-plugins and plugins-resolver
  • integrated with Sade

Working implementation, and illustrative command/task config definition

hela v3:

Latest update. Couple of fixes and rethinkings.

  • release as monorepo

@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);
  });

add task for generating `.nycrc.json`

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)

looks like not support path with space

$ "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

Add build, pretest and posttest tasks

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))
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.