Giter Site home page Giter Site logo

cliui's Introduction

Yargs

Yargs be a node.js library fer hearties tryin' ter parse optstrings


ci NPM version js-standard-style Coverage Conventional Commits Slack

Description

Yargs helps you build interactive command line tools, by parsing arguments and generating an elegant user interface.

It gives you:

  • commands and (grouped) options (my-program.js serve --port=5000).
  • a dynamically generated help menu based on your arguments:
mocha [spec..]

Run tests with Mocha

Commands
  mocha inspect [spec..]  Run tests with Mocha                         [default]
  mocha init <path>       create a client-side Mocha setup at <path>

Rules & Behavior
  --allow-uncaught           Allow uncaught errors to propagate        [boolean]
  --async-only, -A           Require all tests to use a callback (async) or
                             return a Promise                          [boolean]
  • bash-completion shortcuts for commands and options.
  • and tons more.

Installation

Stable version:

npm i yargs

Bleeding edge version with the most recent features:

npm i yargs@next

Usage

Simple Example

#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const argv = yargs(hideBin(process.argv)).parse()

if (argv.ships > 3 && argv.distance < 53.5) {
  console.log('Plunder more riffiwobbles!')
} else {
  console.log('Retreat from the xupptumblers!')
}
$ ./plunder.js --ships=4 --distance=22
Plunder more riffiwobbles!

$ ./plunder.js --ships 12 --distance 98.7
Retreat from the xupptumblers!

Note: hideBin is a shorthand for process.argv.slice(2). It has the benefit that it takes into account variations in some environments, e.g., Electron.

Complex Example

#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')

yargs(hideBin(process.argv))
  .command('serve [port]', 'start the server', (yargs) => {
    return yargs
      .positional('port', {
        describe: 'port to bind on',
        default: 5000
      })
  }, (argv) => {
    if (argv.verbose) console.info(`start server on :${argv.port}`)
    serve(argv.port)
  })
  .option('verbose', {
    alias: 'v',
    type: 'boolean',
    description: 'Run with verbose logging'
  })
  .parse()

Run the example above with --help to see the help for the application.

Supported Platforms

TypeScript

yargs has type definitions at @types/yargs.

npm i @types/yargs --save-dev

See usage examples in docs.

Deno

As of v16, yargs supports Deno:

import yargs from 'https://deno.land/x/yargs/deno.ts'
import { Arguments } from 'https://deno.land/x/yargs/deno-types.ts'

yargs(Deno.args)
  .command('download <files...>', 'download a list of files', (yargs: any) => {
    return yargs.positional('files', {
      describe: 'a list of files to do something with'
    })
  }, (argv: Arguments) => {
    console.info(argv)
  })
  .strictCommands()
  .demandCommand(1)
  .parse()

ESM

As of v16,yargs supports ESM imports:

import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'

yargs(hideBin(process.argv))
  .command('curl <url>', 'fetch the contents of the URL', () => {}, (argv) => {
    console.info(argv)
  })
  .demandCommand(1)
  .parse()

Usage in Browser

See examples of using yargs in the browser in docs.

Community

Having problems? want to contribute? join our community slack.

Documentation

Table of Contents

Supported Node.js Versions

Libraries in this ecosystem make a best effort to track Node.js' release schedule. Here's a post on why we think this is important.

cliui's People

Contributors

bcoe avatar coreyfarrell avatar github-actions[bot] avatar greenkeeperio-bot avatar ljharb avatar maxrimue avatar minigod avatar mriedem avatar nexdrew avatar realityking avatar renovate[bot] avatar sbj42 avatar timaconner 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

cliui's Issues

Upgrade strip-ansi to 7.x

ansi-regex  5.0.0
Severity: high
Inefficient Regular Expression Complexity in chalk/ansi-regex - https://github.com/advisories/GHSA-93q8-gq69-wqmw
fix available via `npm audit fix`
node_modules/mocha/node_modules/ansi-regex

latest cliui is still on strip-ansi 6.0.1

"strip-ansi": "^6.0.1",
and 7.x is required https://github.com/chalk/strip-ansi/blob/dd40fa7ced678f14dfb43eb9b62b8e7313fb7011/package.json#L50

Upgrade dependency

Hello,

can you, please upgrade package strip-ansi to actual version because of vulnerability CVE-2021-3807. I tried make PR by myself but I ended on pure ESM problem.

If I can help to make this happened let me know.

Thanks
Jan Opravil

Issue with Description Column not Rendering on Separate Line

I inadvertently created an argument description that turned out to be 37 characters long. When help is displayed, the description displays as follows:

--lts, -l Download 'Long Term Support' releases[boolean] [default: false]

Personally I think it would look better if the line had a line break inserted via the _renderInLine function in order to keep the description from running into the square bracket. If the description is 38 characters in length, it will render the type and default on a separate line.

A simple change to the _renderInLine function in index.ts, changing this code:

if (leadingWhitespace < targetTextWidth) {

to this:

if (leadingWhitespace < targetTextWidth + 1) {

allows the line to break if the description is the maximum width of the field.

Trying to get in touch regarding a security issue

Hey there!

I'd like to report a security issue but cannot find contact instructions on your repository.

If not a hassle, might you kindly add a SECURITY.md file with an email, or another contact method? GitHub recommends this best practice to ensure security issues are responsibly disclosed, and it would serve as a simple instruction for security researchers in the future.

Thank you for your consideration, and I look forward to hearing from you!

(cc @huntr-helper)

Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported.

We use cliui transitively through jest, which is a CJS module. Currently, when running jest in our project, we get the following error:

Error [ERR_REQUIRE_ESM]: require() of ES Module [...]/node_modules/string-width/index.js from [...]/node_modules/cliui/build/index.cjs not supported.

I believe this is because of these lines.
Instead string-width and string-ansi, string-width-cjs' and string-ansi-cjsshould be required. Those are already installed. However, the third dependencywrap-ansi` does not exist as a CJS dependency.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update actions/checkout action to v4
  • chore(deps): update actions/setup-node action to v4
  • chore(deps): update bcoe/release-please-action action to v4
  • chore(deps): update dependency eslint to v9
  • 🔐 Create all rate-limited PRs at once 🔐

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/ci.yaml
  • actions/checkout v1
  • actions/setup-node v1
  • actions/checkout v2
  • actions/setup-node v1
  • actions/checkout v2
  • actions/setup-node v1
  • actions/checkout v2
  • actions/setup-node v1
  • actions/checkout v2
  • actions/setup-node v1
  • denolib/setup-deno v2
.github/workflows/release-please.yml
  • bcoe/release-please-action v3
  • actions/checkout v2
  • actions/setup-node v1
  • actions/setup-node v1
npm
package.json
  • string-width ^4.2.0
  • strip-ansi ^6.0.1
  • wrap-ansi ^7.0.0
  • @types/node ^14.0.27
  • @typescript-eslint/eslint-plugin ^4.0.0
  • @typescript-eslint/parser ^4.0.0
  • c8 ^7.3.0
  • chai ^4.2.0
  • chalk ^4.1.0
  • cross-env ^7.0.2
  • eslint ^7.6.0
  • eslint-plugin-import ^2.22.0
  • eslint-plugin-node ^11.1.0
  • gts ^3.0.0
  • mocha ^10.0.0
  • rimraf ^3.0.2
  • rollup ^2.23.1
  • rollup-plugin-ts ^3.0.2
  • standardx ^7.0.0
  • typescript ^4.0.0
  • node >=12

  • Check this box to trigger a request for Renovate to run again on this repository

Wrapping logic seems to be weirdly different between ESM vs CJS versions

Example:

const cliuiCJS = require('cliui')
import('cliui').then(({ default: cliuiESM }) => {
  const uiCJS = cliuiCJS({})
  const uiESM = cliuiESM({})

  const text = `usage: git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]
               <tagname> [<commit> | <object>]
   or: git tag -d <tagname>...
   or: git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
               [--points-at <object>] [--column[=<options>] | --no-column]
               [--create-reflog] [--sort=<key>] [--format=<format>]
               [--merged <commit>] [--no-merged <commit>] [<pattern>...]
   or: git tag -v [--format=<format>] <tagname>...`

  console.error('~ ~ ~ ~ ~ ~ ~ ~ ~ ~')
  console.error('cjs')
  uiCJS.div({
    padding: [0, 0, 0, 0],
    text,
  })
  console.log(uiCJS.toString())
  console.error('~ ~ ~ ~ ~ ~ ~ ~ ~ ~')
  console.error('esm')
  uiESM.div({
    padding: [0, 0, 0, 0],
    text,
  })
  console.log(uiESM.toString())
})

/* output:
~ ~ ~ ~ ~ ~ ~ ~ ~ ~
cjs
usage: git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]
<tagname> [<commit> | <object>]
or: git tag -d <tagname>...
or: git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
[--points-at <object>] [--column[=<options>] | --no-column]
[--create-reflog] [--sort=<key>] [--format=<format>]
[--merged <commit>] [--no-merged <commit>] [<pattern>...]
or: git tag -v [--format=<format>] <tagname>...
~ ~ ~ ~ ~ ~ ~ ~ ~ ~
esm
usage: git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]

       <tagname> [<commit> | <object>]
   or: git tag -d <tagname>...
   or: git
 tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]

  [--points-at <object>] [--column[=<options>] | --no-column]
               [--
create-reflog] [--sort=<key>] [--format=<format>]
               [--merged <comm
it>] [--no-merged <commit>] [<pattern>...]
   or: git tag -v [--format=<format>]
 <tagname>...
 */

I'm not sure why, but the esm results seem to wrap at very confusing places, differently from the cjs version.

Consider including a note on the accessibility issues of wrapped text in columns

Since wrapped text doesn’t make sense for people using a screen reader, it might be a good idea to include a warning that it should only be used as an option, when possible. (Otherwise, you will be locking people who rely on screen readers out of using your app.)

Possible copy:

Warning: Using wrapped text in columns in command-line interfaces is inaccessible to people who rely on screen readers. Please consider making wrapped text an option that people opt into – perhaps by supplying a special flag – and ensure that your apps are usable by people of all abilities.

This is how I implemented it in my app:

Screenshot from 2020-11-18 16-43-35

More (thread): https://mastodon.ar.al/@aral/105231108540229990

Switch to wrap-ansi module

We are using yargs in gulp-cli and use chalk to color the descriptions. I noticed that things start to get messed up due to the wordwrap module that is utilized. I switched it out in my local install for wrap-ansi (by the chalk team) and it fixed the problem.

Testing issues with chalk@2

I've tested cliui against newer dependencies, upgrading chalk to 2.x causes a test failure:

  1) cliui
       layoutDSL
         ignores ansi escape codes when measuring padding:

      AssertionError: expected [ Array(9) ] to deeply equal [ Array(5) ]
      + expected - actual

       [
         "  |"
      -  "  "
         "  __|   __|  |   |   _ \\"
      -  "  "
         "  |    |     |   |   __/"
      -  "  "
         " \\__| _|    \\__,_| \\___|"
      -  " "
         "                         "
       ]

I've tested the following script:

const chalk = require('chalk');
console.log(JSON.stringify(chalk.blue('line 1\nline 2').split('\n'), null, 4));

Result from chalk@^1.1.2:

[
    "\u001b[34mline 1",
    "line 2\u001b[39m"
]

Result from chalk@^2.4.2:

[
    "\u001b[34mline 1\u001b[39m",
    "\u001b[34mline 2\u001b[39m"
]

So the big difference is that chalk@2 adds ansi codes to the start/end of each line. Upgrading wrap-ansi to the latest didn't fix the testing errors, it actually caused more errors though I'm unsure if this is due to an issue with wrap-ansi or with cliui.

Update to [email protected] for ansi-regex CVE-2021-3807

The latest version of cliui requires strip-ansi 6.0.0 which requires ansi-regex 5.0.0 which has a CVE against it:

https://nvd.nist.gov/vuln/detail/CVE-2021-3807

Update the cliui dependency on strip-ansi to 6.0.1 which requires ansi-regex 5.0.1 to resolve the vulnerability in this dependency chain:

https://github.com/chalk/strip-ansi/blob/v6.0.1/package.json#L47

I'm here because of this dependency chain:

├─┬ @carbon/[email protected]
│ └─┬ @carbon/[email protected]
│   └─┬ [email protected]
│     └─┬ [email protected]
│       └─┬ [email protected]
│         └── [email protected]

Updating to the latest @carbon/[email protected] does not resolve that issue.

This may be related to issues #106 and #110.

Support specifying trailing indents for `div` columns

Support for this would be required to implement yargs/yargs#1640.

The idea is to add support for trailing indents to the div function.

One possible API would be supporting an option multilineIndents for each column passed to div. That option would take an array of two numbers [leadingIndent, trailingIndent] with these meanings:

  • leadingIndent (number): how many spaces to add to the start of the first line in that column
  • trailingIndent (number): how many spaces to add to the start of each line after the first

Support Node 16 module resolution

Add "module": "node16", "moduleResolution": "node16" to your tsconfig.json.

source: Pure ESM package

Making the desired changes to my project for Node 16, results in the following error:

error TS2344: Type 'typeof import("/xxx/node_modules/.pnpm/[email protected]/node_modules/cliui/build/index")' does not satisfy the constraint '(...args: any) => any'.
  Type 'typeof import("/xxx/node_modules/.pnpm/[email protected]/node_modules/cliui/build/index")' provides no match for the signature '(...args: any): any'.

108 function descriptionList (ui: ReturnType<typeof cliui>, items: Descriptions): void {

Expose more final types

Though it is currently possibly to determine most types from the default export...

import cliui from 'cliui';

type UI = ReturnType<typeof cliui>;
type UIOptions = Parameters<typeof cliui>[0];

...these types are rather finicky. It would be great if more finalized types were exported from this package.

Release packages are missing index.js

Which results in an error: module not found for cliui.

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/adrian/Admin/HuMC/sites/perco-2020/node_modules/cliui/build/lib/index.js' imported from /home/adrian/Admin/HuMC/sites/perco-2020/node_modules/cliui/index.mjs
    at new NodeError (node:internal/errors:399:5)
    at finalizeResolution (node:internal/modules/esm/resolve:231:11)
    at moduleResolve (node:internal/modules/esm/resolve:850:10)
    at defaultResolve (node:internal/modules/esm/resolve:1058:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:835:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:416:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)
    at link (node:internal/modules/esm/module_job:75:36) {
  code: 'ERR_MODULE_NOT_FOUND'

Reinstate smart whitespace-based wrapping for ESM?

I've started migrating some of my personal projects to native ESM (not transpiled), and suddenly started noticing that string wrapping in the command-line help became "dumb", simply injecting \n at the column boundary. Digging into yargs and cliui, I found that the cliui index.mjs entrypoint is using some simple implementations for stripAnsi and wrap from lib/string-utils.ts, which contains a comment about being a minimal replacement for the older/existing CJS libraries.

Would it be possible to simply import those CJS libraries, even in an ESM context? I know this should work fine in Node.js, I'm not sure whether Deno adds additional restrictions. (But Deno appears to have its own entrypoint, so this may be a non-issue.)

Just for giggles, I hand-patched my local install in node_modules (for a yargs-using tool) so that cliui/index.mjs looked like:

import { cliui } from './build/lib/index.js'

import stringWidth from 'string-width';
import stripAnsi from 'strip-ansi';
import wrap from 'wrap-ansi';

export default function ui (opts) {
  return cliui(opts, {
    stringWidth,
    stripAnsi,
    wrap
  })
}

(basically, a naive merge of the existing wrapper and the TS/CJS index)... and it seemed to work perfectly (on Node.js v14.5.0), giving me pretty word-wrapping, and no weird clipping.

current

  -v, --verbose  Increase verbosity of console output, can be given multiple time
                 es to increase verbosity                                [count]

patched

  -v, --verbose  Increase verbosity of console output, can be given multiple
                 times to increase verbosity                             [count]

Is there any reason cliui can't simply leverage the existing width/ansi/wrap CJS libraries for ESM? I'm happy to provide this as a PR with updated ESM tests if that would help.

Difficult to tightly pack columns

It is difficult to tightly pack columns in cliui. It has a tendency to want to expand columns to fill the output width. Suppose I want the following output:

apple  one   red
banana two   green
cookie three blue

I might try this:

var out = cliui().div(
  'apple\nbanana\ncookie\n', ' one\n two\n three\n', ' red\n green\n blue\n'
).toString()

But when column widths are not specified and the text is small enough, the columns divide the entire width nearly evenly:

apple                      one                       red
banana                     two                       green
cookie                     three                     blue

I might try using the domain-specific language:

var out = cliui().div(
  'apple\nbanana\ncookie\n', ' one\n two\n three\n', ' red\n green\n blue\n'
).toString()

The DSL has a special case for packing the first column tightly, but it still distributes the remaining space evenly among the other columns:

apple  one                                  red
banana two                                  green
cookie three                                blue

As far as I can tell, the only way is to remove the padding and fully specify all column widths:

var out = cliui().div(
  {text: 'apple\nbanana\ncookie\n', width: 7},
  {text: 'one\ntwo\nthree\n', width: 6},
  {text: 'red\ngreen\nblue\n', width: 5}
).toString()

But that seems to defeat the purpose. One of the great things about cliui is that it can figure out the column widths for me.

There might be a trick that I'm missing. If there isn't, one way to resolve this would be to have the DSL do its special case packing for all columns, not just the first. Another way would be for columns in general to shrink to their longest row of content (after wrapping) when no width is specified (then the DSL wouldn't need its special case at all). That may result in a drastic change in behavior though, so it may be worth guarding that change behind either a cliui option or a column option.

Why does `wrap: false` disable the domain-specific language?

Setting wrap to false disables the domain-specific language. I see this is intentional as indicated in the test case ("does not apply DSL if wrap is false") and the code (index.js:26). But I don't understand the reason.

If I enable the DSL for wrap: false by removing the condition on line 26, the only test that fails is the one that confirms the DSL is disabled. The new output of that test is "Usage : $0twothree" which is actually what I would expect given my understanding of the documentation for wrap: false: "disable the wrapping of text in a column".

I would think that the wrap option would have no effect when the input doesn't need wrapping.

Seems like it should keep the DSL enabled when wrap is false. You could add a new option specifically to disable the DSL if there is a use case for that. Alternatively, you could mention the DSL thing in the wrap documentation.

referencing the cjs version instead of the esm version?

Check the code here

cliui/lib/cjs.ts

Lines 3 to 5 in af3145d

const stringWidth = require('string-width')
const stripAnsi = require('strip-ansi')
const wrap = require('wrap-ansi')

Should we require strip-ansi-cjs instead of strip-ansi?

Here are my errors

$ ts-node vspec.ts --input ../test_data --output out
/Users/ajc/hacking/proj/node_modules/ts-node/dist/index.js:851
            return old(m, filename);
                   ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/ajc/hacking/proj/node_modules/string-width/index.js from /Users/ajc/hacking/proj/node_modules/cliui/build/index.cjs not supported.
Instead change the require of index.js in /Users/ajc/hacking/proj/node_modules/cliui/build/index.cjs to a dynamic import() which is available in all CommonJS modules.

=> Found "[email protected]"
info Reasons this module exists
   - "yargs" depends on it
   - Hoisted from "yargs#cliui"
info Disk size without dependencies: "64KB"
info Disk size with unique dependencies: "348KB"
info Disk size with transitive dependencies: "552KB"
info Number of shared dependencies: 6
✨  Done in 0.12s.


=> Found "[email protected]"
info Has been hoisted to "yargs"
info This module exists because it's specified in "dependencies".
info Disk size without dependencies: "472KB"
info Disk size with unique dependencies: "1MB"
info Disk size with transitive dependencies: "1.31MB"
info Number of shared dependencies: 12

Should npm run script `check` run after `test`?

There are some minor benefits to having the lint check separate from the runtime tests, so that more of the GitHub Action checks complete and aren't blocked by lint issues. However, makes it easy to open a PR and push code that will fail on the lint check.

I noticed there is postest run script, which should presumably be posttest! Leaning towards enabling that as I tend to only fix one breakage at a time anyway.

"postest": "check",

Fixing that would render this line obsolete:

- run: npm run check

Add output example to the readme

Could you add an example or two of the expected output from the code into a block on the readme? IMHO, it's hard to visualize what the code does to someone viewing the module for the first time. You do give one, but you should probably show what the first example does as well.

Missing type declarations

Hi, my project uses TypeScript, but after importing this package I get the following error:
image
I can see that there are no .d.ts files in the build folder of the published package, even though the package is written in TypeScript. I haven´t been able to compile the code on my machine, so I cannot investigate this further.

Can you enable building the declarations?

cliui remove kleur colors (ESM project)

Hello 👋

The package cliui remove "some" colors when working with ESM. Everything is fine with CJS. I found the problem on a CLI project I just migrated and I couldn't understand why my colors were not working anymore.

I'm working on Windows 10 and Node.js v16


How to reproduce:

$ mkdir cliui_bug
$ cd cliui_bug
$ npm init -y
$ npm i kleur cliui -P
# Add type: module in package.json 

The index.js file

import kleur from "kleur";
import cliui from "cliui";
// const kleur = require("kleur");
// const cliui = require("cliui");

const { white, cyan, red } = kleur;

const ui = cliui();

const title = `${white().bold("name:")} ${cyan().bold("express")}`;
console.log(title);
ui.div(
  { text: title, width: 50 }
);
ui.div({ text: red("-------------------------------------------------------------------"), width: 70 });

console.log(ui.toString());

Output with ESM:
image

The title with cliui doesn't work. If you switch the project to CJS it will work as expected.

Best Regards,
Thomas

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.