Git Product home page Git Product logo

vorpal's Introduction

hey there


I'm the Co-Founder & CTO at MindCloud, a rapidly growing B2B startup in the integration space. I've been writing production software for 16 years with an emphasis on designing and building data-heavy platforms from the ground up.

You can follow me on Twitter.


I had fun building some original OSS projects in the past for the Node community:

  • Vorpal - Interactive CLI framework for Node
  • Cash - Cross-platform unix coreutils in Javascript
  • Vantage - Distributed, realtime CLI for live Node apps

vorpal's People

Contributors

adrieankhisbe avatar alansouzati avatar ccorcos avatar da70 avatar danielruf avatar dashlanebot avatar drewbrokke avatar dthree avatar e-jigsaw avatar eliperelman avatar fiatjaf avatar fredericgrati avatar hnordt avatar jackyjieliu avatar jeff-1amstudios avatar marcos-abreu avatar matt-oc avatar mdouglass avatar melonmanchan avatar michelypma avatar milesj avatar mvayngrib avatar naltun avatar oresoftware avatar postatum avatar prayagverma avatar ryangalamb avatar scotthovestadt avatar zakhenry avatar

Stargazers

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

Watchers

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

vorpal's Issues

Errors in actions are hidden

Can't trace errors while running commands in non-interactive shell

@dthree

Figured it out. .exec was intended to be programmatic, so it eats teh error and returns it in exec's callback.
.parse calls .exec, so it eats the error when invoked through .parse, but not otherwise.

#!/usr/bin/env node

var program = require('vorpal')();
var path = require('path');
var fs = require('fs');
var colors = require('colors');

var error = colors.bgRed.white.bold;

program.command('init [path]')
  .description('Creates dummy config in current dir or [path]')
  .action((args) => {
    var path = args.path || '';
    var configFile = path.join(process.cwd(), path, 'codecept.json');
    this.log(path);
    try {
      fs.writeFileSync(configFile, '{}')
    } catch (err) {
      this.log(error(`File can't be created at ${configFile}`));
      program.exit();
    }
    this.log(`Config created at ${configFile}`);
  });

program.parse(process.argv);

When showing vorpal from inside a callback ctrl-c twice does not exit

I'm running some async init code before I show vorpal and so ctrl-c twice no longer exits vorpal as I'm stuck in my callback. The idea here is that I only want to run vorpal if I can successfully connect to a database since all the vorpal commands are db related.

// basic setup
testConnection(function(err, result){
   if(!err){
        vorpal.show();
   }
});

Is there an event or callback I can listen for to know when vorpal exists? Right now hitting ctrl-c appears to be stopping vorpal but Node is sitting in my callback waiting for something. I realize I might also have this setup wrong.

If I add the following:

process.on('SIGINT', () => process.exit(2));

Then I can get my program to quit if I hti ctrl-c three times. Otherwise I have to kill -9 it.

Thanks!

Reading options beginning with a minus

Would it be possible to support reading options starting with a minus?

In commander.js, t -i -2 would assign -2 to args.options.i, whereas vorpal prints a friendly Missing required option. Showing Help:.
Tested on the same code as the other issue. -i or --index makes no difference.

var Vorpal = require('./../../lib/vorpal');

var vorpal = new Vorpal();

vorpal.command('t')
.option("-i, --index <index>")
.action(function (args, cb) {
  console.log(args.options.index);
  cb()
});

vorpal.delimiter('foo:').show();

Optional and required arguments

Hi, the issues just keep coming. I guess I'll have to take a look at the code soon and try to hack a pullrequest or two. I'm starting to feel bad for just posting these without trying to implement anything. Anyways, here we go:

vorpal.command('test <required> [optional]')

test foo works as expected: { options: {}, required: 'foo' }.
However:

vorpal.command('test [optional] <required>')

test foo results in Missing required argument. Showing Help:

It would be great if vorpal was smart enough to recognize that foo should be the value for <required>, not for [optional].

Prompt validation does not visualize the output (errors)

using inquirer a prompt with validate function should show the validate output, but with vorpal it is somehow omitted.

this.prompt([
    {
        type: 'input',
        name: 'test',
        message: 'Please type something different than `test` to see an error pop up... or type `test` to continue',
        validate: function (val) {
            if (val != 'test') {
                return "Please answer with the word test";
            }
            return true;
        }
    }
], function(answers) {
    console.log(answers);
});

in Inquirer you can see this work perfectly in the examples/input.js example. however the error gets lost somewhere in the process within vorpal I assume.

Help for sub-commands does not show options

if I ask help for a subcommand:

My-cli$ help user add

  Commands:

    user add [options]   Create a new admin user

if I change the command so it is a root level command:

My-cli$ help add-user

  Usage: add-user [options]


  Create a new admin user

  Options:

    --help                                output usage information
    -u <username>, --username <username>  the username for this user
    -p <password>, --password <password>  the password for this user

example for nesting if at all possible

Hi not sure if this even part of what Vorpal is all about, I did see the mode options, but what I wanted to know was

  1. Can I use Vorpal to make nested command sets. I''l try to explain. at the top level you might have commands some of which take you down into a new level, at which point you now have a new delimiter and a new set of commands, one of which might be .. to take you back up a level. I was looking for that kind of thing.
  2. If it would be possible could you point me in the right direction

vorpal exits if backgrounded in shell

The usual CTRL+Z does not seem to be working with vorpal in default config.
It does not like to be put in the background, restoring (via fg) exits.

Command names with capital letters

Adding a command with capital letters does not work.

Running it (either correctly written or in lowercase) yields Invalid Command. Showing Help:.
The help does include this:

fooBar                undefined

If forcing all-lowercase command names is intentional, a notification when an invalid command is added would be nice. If its unintentional: well, more stuff to fix =)

vorpal.command('fooBar')
  .action(function(args, cb) {
    this.log 'fooBar';
    cb();
});

* Not my actual code, please ignore js errors produced by my blissful, coffeescript-induced ignorance.

Using arrow functions

Trying out ES6 arrow functions with Vorpal, but the session normally available via this does not work of course:

vorpal
  .command('foo')
  .description('Outputs "bar".')
  .action((args, callback) => {
    this.log('bar'); // ReferenceError: log is not defined
    callback();
  });

Though what we be the best way to use vorpal with arrow functions?

BUG: Terminal breaks when input is too wide

When I input past the width of the terminal, my input (in this case random numbers) goes onto the next lines.

deliminator$: 12313131313123131313131313213213111111111231323344
1123132334
112313233
11231323
1123132
112313
11231
1123
112
11
1

Help for subcommands is difficult to read

My journey trying to read the help for my own subcommands:

app~$ help

  Commands:

    help [command]    Provides help for a given command.
    exit [options]    Exits instance of Vorpal.

  Command Groups:

    type *            2 sub-commands.
    record *          3 sub-commands.

app~$ record

  Command Groups:

    record add *  3 sub-commands.

app~$ help record

  Command Groups:

    record add *  3 sub-commands.


app~$ help record add

  Command Groups:

    record add *  3 sub-commands.


app~$ record help add

  Invalid Command. Showing Help:

  Commands:

    help [command]    Provides help for a given command.
    exit [options]    Exits instance of Vorpal.
    repl              Enters REPL mode.
    erase [options]   erases db

  Command Groups:

    type *            2 sub-commands.
    record *          3 sub-commands.

I still don't know how to do it, but perhaps vorpal shouldn't group the help for commands below a threshold? Maybe if the command group does not have more than 5 commands grouped than the help for them all will be shown on help? Perhaps this number is configurable? Or, better, we should have to group commands explicitly (or maybe we could ungroup explicitly)?

Bump inquirer version

[email protected] is about half the size, as they switched to "rx-lite" from the much larger rxjs package.
They have also "fixed" their lodash dependency, though that one is including the full librayr (now the bulk of the distribution size).

Input type 'password' shows characters while typing

Until the return key is pressed, all password characters are shown as plain text:

password: my-secret-password

After the return key was pressed, the characters are replaced with * symbols:

password: ******************

As a sensitive user, I would like my password to be already hidden while typing. * symbols should be shown from the very beginning.

Is there an option to achieve this?


Example code:

var vorpal = require('vorpal')();

vorpal
    .command('connect')
    .action(function (params, cb) {
        this.prompt([{
            type: 'password',
            name: 'password',
            message: 'password: '
        }], cb);
    });

vorpal.show();
vorpal.exec('connect');

Option function and default parameter is not executed

In source diving the arguments passed to command.option, it appears that it accepts a 3rd and 4th parameter for defining a function and default value for the option, but it appears that these aren't actually being executed. In this test case, I was unable to get a default value or have the function execute. Am I doing something wrong, or is this just not supported yet?

#! /usr/bin/env node

let Vorpal = require('vorpal');
let cli = new Vorpal();

cli
  .command('test')
  .description('A test')
  .option('--url <url>', 'Some url', function(val) { cli.log('VALUE!', value); }, 'http://some.url')
  .action(function(args, done) {
    this.log('URL:', args.options.url);
    done();
  });

cli.parse(process.argv);
$ ./cli test
URL: undefined
$ ./cli test --url other.url
URL: other.url

Pressing tab to autocomplete in the middle of a string actually prints tab

If I start typing my command:
command-one param | command-two param

Then I go back and try to edit command-one and change it to command-three, put my cursor here:
com_ | command-two param

Then I hit tab, it actually prints tab. No autocomplete. I think the code doesn't even think about the cursor position. Is it possible to react to the cursor pos?

Error stack trace is hidden when using promises

The following just display a red Error: true instead of a full error logging

import vorpal from 'vorpal'

const program = vorpal()

program.command('foo')
  .action(function() {
  return Promise.reject(new Error('Bouu'))
})

program
  .delimiter(`jogabo:work$`)
  .show()

Inconsistencies when reading 0 as argument

The following code outputs 0 for the input t -index 0, but outputs undefined for the input t -i 0.

var Vorpal = require('./../../lib/vorpal');

var vorpal = new Vorpal();

vorpal.command('t')
.option("-i, --index <index>")
.action(function (args, cb) {
  console.log(args.options.index);
  cb()
});

vorpal.delimiter('foo:').show();

Inquirer.js' input types using odd-looking delimiter

It seems that Inquirer.js' input type renders rather strangely in Vorpal โ€“ lacking spacing and the green question mark:

screen shot 2015-11-23 at 16 53 00

As opposed to the following in Inquirer.js:

screen shot 2015-11-23 at 16 52 05

Repro case:

const prompt = function(object, callback) {
  object.prompt([
    {
      type: 'input',
      name: 'name',
      message: 'What is your name?',
      default: 'John Doe',
    },
    {
      type: 'list',
      name: 'list',
      message: 'What do cows drink?',
      choices: ['milk', 'water', 'applejuice'],
      default: 'water',
    }
  ], function(result) {
    callback();
  });
};

Using Vorpal:

const cli = require('vorpal')();
cli
  .command('test')
  .action(function(args, callback) {
    prompt(this, callback);
  });

cli.show();

Using Inquirer.js:

const inquirer = require('vorpal/node_modules/inquirer');
prompt(inquirer, function() {
  console.log(arguments);
});

Am unsure where this is going wrong, any ideas?

Fail fast when adding duplicate commands

Guess I'll just drown you in feedback then.

Duplicate commands sit in the background until invoked, silently overriding each other. I also got a crash because of that (I think), which I unfortunately did not manage to replicate.

Especially with functions like vorpal-use, the user should at least be notified when a duplicate command is added. I didn't look how you implemented aliases, but the same should be true there.

And at the very least, you'll save some devs debugging time.

.catch should not trigger on a command group

when not implementing a catch hook, typing in a command of a group gives you the help for it's subcommands.

if however you implement a catch hook, the catch hook is triggered instead.

I think it would still be useful to show the help for a command group, instead of triggering the catch.

CTRL+C twice won't exit process

In my tests I have to hit CTRL+C three times. If I move the process.exit() call into the keypress handler instead of _sigint, it works correctly on the second keypress.

Pass minimist options to command/options

๐Ÿ‘‹

Since you are using minimist to parse the command options you have to allow your users to pass minimist options as well.

For example I may want to pass {string: ['a', 'address']} for my connect command to indicate that the address option should be treated as string always:

app$ connect --address 0x890765a99f0c8a98415756df2d821093ad0d273f
{ options: { address: 7.822966968792672e+47 } }

I may want to be strict about each command option, that's why probably an options argument for the command function would be good.

expose rawParse to use minimist/commander

Vorpal could expose rawParse(process.argv, { command: true|false}) to run a string through minimist or commander. This may be a special case.

I have an existing app, it's just using minimist for cli arguments in the usual form (app.js --arg items), and I'm working on the interactive CLI via vorpal. Trying to reduce redundancy when I can.

I am still working out how best to switch between command line (single commands) and interactive command line. But that's a different issue.

Command remove does not work (_parent.commands is not accessible)

It seems as if the _parent attribute of a command is not passed on properly upon initialization? Is it enough to simply pass the exports-object to the newly created command?

console.log(this._parent) => [Function: Vorpal]


console.log(this._parent.toString()) => function Vorpal() {
 if (!(this instanceof Vorpal)) {
   return new Vorpal();
 }  // Program version
 // Exposed through vorpal.version(str);
 this._version = '';  // Registered vorpal.command commands and
 // their options.
 this.commands = [];  // Queue of IP requests, executed async, in sync.
 this._queue = [];  // Current command being executed.
 this._command = undefined;  // Expose UI.
 this.ui = ui;  // Expose chalk as a convenience.
 this.chalk = chalk;  // Expose lodash as a convenience.
 this.lodash = _;  // Exposed through vorpal.delimiter(str).
 this._delimiter = 'local@' + String(os.hostname()).split('.')[0] + '~$ ';
 ui.setDelimiter(this._delimiter);  // Placeholder for vantage server. If vantage
 // is used, this will be over-written.
 this.server = {
   sessions: []
 };  // Whether all stdout is being hooked through a function.
 this._hooked = false;  // Expose common utilities, like padding.
 this.util = VorpalUtil;  this.Session = Session;  // Active vorpal server session.
 this.session = new this.Session({
   local: true,
   user: 'local',
   parent: this,
   delimiter: this._delimiter
 });  this._init();
 return this;
}

Should intended behavior when initializing the command be something like:

var cmd = new Command(cmdName, this)

instead of:

var cmd = new Command(cmdName, exports);

This would allow the parent object attributes to be properly accessible to the Command-object. Ran into this kink while attempting to implement duplicate alias detection.

Switching between instances will exit

In one of your examples, you demonstrated how to switch between multiple instances.

function switch(vorpal) {
  vorpal.command('switch <instance>')
    .action(function (args, cb) {
      instances[args.instance].show();
    });
  return vorpal;
}

var instances = {
  'a': new Vorpal().use(switch).delimiter('a:'),
  'b': new Vorpal().use(switch).delimiter('b:'),
  'c': new Vorpal().use(switch).delimiter('c:'),
}

Using version 1.4.0, it does work on first ''switch'', but switching again to the same instance will exit.

$ node switcher.js
a: switch a
a: switch a
$

How to validate command arguments?

If I have a command that looks like:

command-name [strategy]

If strategy can only be "insert", "update", or "upsert", for example, how do I use Vorpal to validate it?

Required options do not throw error

I'm using Vorpal with the reduced test case below:

'use strict';

let cli = require('vorpal')();

cli
  .command('test')
  .description('reduced test case')
  .option('--required <val>', 'Should be a required value')
  .action(function(c) {
    console.log(c.options.required);
  });

cli.parse(process.argv);
node index test

This command's action should not execute using the given command, as no --required value was specified. According to the current source in lib/util.js:199, missing required options shows a message in the console along with help. This does not happen.

Hitting CTRL+C while in Inquirer prompt breaks everything

The output looks like this:

(^C again to quit)
function (str) {
  if (str === undefined) {
    return this._delimiter;
  }
  this._delimiter = String(str).trim() + ' ';
  if (this.isLocal()) {
    this.parent.ui.refresh();
  } else {
    this.parent._send('vantage-delimiter-downstream', 'downstream', {value: str, sessionId: this.id});
  }
  return this;
}
_

You can still type but nothing happens. Only way to recover is hitting CTRL+C again.

Handle double quotation marks arguments as literal strings

When passing arguments (or option values) surrounded with double quotes it should handle the input as literal strings and not split by any whitespace, nor should it parse it.

vorpal
  .command('say <text>')
  .option('-n, --name <nm>')
  .action(function (args, cb) {
    this.log((args.options.name ? args.options.name + ': ' : '') + args.text)
    cb()
  })
node~$ say "Hello World"
Hello World
node~$ say 'Innovation distinguishes between a leader and a follower.' --name 'Steve Jobs'
Steve Jobs: Innovation distinguishes between a leader and a follower.

Currently only single quotation marks are supported. I would also propose quotation marks to be optional (both individually and collectively)

After executing command I am getting this issue(not using vorpal prompt)

vorpal
    .command('connect [username] [password]')
    .description('Connect to server.')
    .action(function (args, callback) {
        setTimeout(function () {
            // deleting options key from args
            delete args.options;

            var context = domain.create();

            // error handling in domain
            context.on('error', errorHandler);

            // running the connect in domain
            context.run(function() {
                console.log("Arguments : ", args);
            });
        }, 0);
    });

vorpal
    .delimiter('hdb$')
    .show();

Vorpal Prompt error: TypeError: Cannot read property 'setRawMode' of null
at ReadStream.setRawMode (tty.js:67:15)
at Interface._setRawMode (readline.js:177:23)
at new Interface (readline.js:137:10)
at Object.exports.createInterface (readline.js:39:10)
at Object.Interface.createInterface (/home/users/my-cli/node_modules/vorpal/node_modules/inquirer/node_modules/readline2/index.js:34:21)
at module.exports (/home/users/my-cli/node_modules/vorpal/node_modules/inquirer/lib/ui/baseUI.js:14:30)
at new module.exports (/home/users/my-cli/node_modules/vorpal/node_modules/inquirer/lib/ui/prompt.js:15:8)
at Object.promptModule as prompt
at Object.ui.prompt (/home/users/my-cli/node_modules/vorpal/lib/ui.js:171:25)
at EventEmitter.vorpal._prompt (/home/users/my-cli/node_modules/vorpal/lib/vorpal.js:528:15)
at EventEmitter. (/home/users/my-cli/node_modules/vorpal/lib/vorpal.js:542:12)
at callback (/home/users/my-cli/node_modules/vorpal/lib/vorpal.js:705:22)
at /home/users/my-cli/node_modules/vorpal/lib/vorpal.js:824:7
at EventEmitter._commandSetCallback (/home/users/my-cli/node_modules/vorpal/lib/session.js:455:5)
at EventEmitter.session.completeCommand (/home/users/my-cli/node_modules/vorpal/lib/session.js:519:12)
at onCompletion (/home/users/my-cli/node_modules/vorpal/lib/session.js:465:10)

Please let me know if I am doing something wrong in this.

Align error-message in code with the documentation

An error message related to the correct command argument sequence does not reflect the documentation: "Put the required arguments first, and variadic in the back.". (See also gitter chat on Dec 29, 2015, 18:36 CET).

Thanks!

options containing hyphens unrecognized

Options containing a hyphen, e.g. vorpal.command('t').option('a-b') are not added to args.options when given in the cli.

May I ask why vorpal doesn't simply wrap commander for command-parsing? I love what vorpal does, but this seems like reinventing the wheel - unless there's an obvious factor I'm missing...

Feature request: History after exit

I'd like the history to persist after exiting the shell, so if you re-enter the shell you can hit up arrow to see your previous command. Would you accept this as a PR with a toggle to turn it off? I'm thinking of using the temp dir to persist it (temporarily).

Better argument parsing

There are a few types of arguments that can't be parsed in the REPL. For example, it's impossible to pass a JSON object.

I would like the argument parser to accommodate the following arguments:

command-name not-quoted
command-name '{"hello": "world"}`
command-name `{"hello": "little quotes 'hi' in here"}`

I'm working on code to do this. I don't think it's actually that complicated. Do you agree with the spec?

strange "Vorpal Prompt error"

I have this pretty small vorpal app: https://github.com/fiatjaf/fieldbook-cli/tree/b3083a70b3ce12f137c7cb22cbe145eb9b9fce6c. The first command, auth, triggers the creation of new commands (through vorpal.emit() and vorpal.on()), and it goes correctly, but then this bizarre error appears:

fiatjaf@spooner ~/c/fieldbook-cli> 
./bin/executable.js auth --book 564a28s4dsc43200ce3215 --key key-1 --password 7734277-9dALvv70RL2342154v70ZQu
fieldbook~$ 
using book 564a28s4dsc43200ce3215.
Vorpal Prompt error: [Error: using book 564a28s4dsc43200ce3215.]

Which is strange, because my code is not calling .prompt twice.

I put a dummy error (this EXIT() function) on vorpal code to get the complete stack trace for the exact moment the error is triggered, and got the following:

fieldbook~$ 
using book 564a28s4dsc43200ce3215.
Vorpal Prompt error: [Error: using book 564a28s4dsc43200ce3215.]


/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/ui.js:191
      EXIT()
      ^

ReferenceError: EXIT is not defined
    at Object.ui.prompt (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/ui.js:191:7)
    at EventEmitter.vorpal.prompt (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/vorpal.js:488:17)
    at EventEmitter.session.prompt (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/session.js:143:22)
    at CommandInstance.prompt (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/command-instance.js:76:25)
    at CommandInstance.<anonymous> (/home/fiatjaf/comp/fieldbook-cli/index.js:114:14)
    at EventEmitter.session.execCommandSet (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/session.js:479:24)
    at EventEmitter.vorpal._exec (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/vorpal.js:826:18)
    at EventEmitter.vorpal._execQueueItem (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/vorpal.js:639:10)
    at EventEmitter.vorpal._queueHandler (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/vorpal.js:623:10)
    at EventEmitter.vorpal.exec (/home/fiatjaf/comp/fieldbook-cli/node_modules/vorpal/lib/vorpal.js:598:10)

I don't understand it.

Context for repl mode

How about having context for repl mode , the way we can attach context with account nodejs repl

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.