Giter Club home page Giter Club logo

cliui's Introduction

cliui

ci NPM version Conventional Commits nycrc config on GitHub

easily create complex multi-column command-line-interfaces.

Example

const ui = require('cliui')()

ui.div('Usage: $0 [command] [options]')

ui.div({
  text: 'Options:',
  padding: [2, 0, 1, 0]
})

ui.div(
  {
    text: "-f, --file",
    width: 20,
    padding: [0, 4, 0, 4]
  },
  {
    text: "the file to load." +
      chalk.green("(if this description is long it wraps).")
    ,
    width: 20
  },
  {
    text: chalk.red("[required]"),
    align: 'right'
  }
)

console.log(ui.toString())

Deno/ESM Support

As of v7 cliui supports Deno and ESM:

import cliui from "https://deno.land/x/cliui/deno.ts";

const ui = cliui({})

ui.div('Usage: $0 [command] [options]')

ui.div({
  text: 'Options:',
  padding: [2, 0, 1, 0]
})

ui.div({
  text: "-f, --file",
  width: 20,
  padding: [0, 4, 0, 4]
})

console.log(ui.toString())

Layout DSL

cliui exposes a simple layout DSL:

If you create a single ui.div, passing a string rather than an object:

  • \n: characters will be interpreted as new rows.
  • \t: characters will be interpreted as new columns.
  • \s: characters will be interpreted as padding.

as an example...

var ui = require('./')({
  width: 60
})

ui.div(
  'Usage: node ./bin/foo.js\n' +
  '  <regex>\t  provide a regex\n' +
  '  <glob>\t  provide a glob\t [required]'
)

console.log(ui.toString())

will output:

Usage: node ./bin/foo.js
  <regex>  provide a regex
  <glob>   provide a glob          [required]

Methods

cliui = require('cliui')

cliui({width: integer})

Specify the maximum width of the UI being generated. If no width is provided, cliui will try to get the current window's width and use it, and if that doesn't work, width will be set to 80.

cliui({wrap: boolean})

Enable or disable the wrapping of text in a column.

cliui.div(column, column, column)

Create a row with any number of columns, a column can either be a string, or an object with the following options:

  • text: some text to place in the column.
  • width: the width of a column.
  • align: alignment, right or center.
  • padding: [top, right, bottom, left].
  • border: should a border be placed around the div?

cliui.span(column, column, column)

Similar to div, except the next row will be appended without a new line being created.

cliui.resetOutput()

Resets the UI elements of the current cliui instance, maintaining the values set for width and wrap.

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

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.

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?

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.

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.

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.

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.

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 {

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.

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.

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

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

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

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

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)

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

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'

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.

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

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.

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.

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.