pax_global_header00006660000000000000000000000064137521030350014511gustar00rootroot0000000000000052 comment=57efcd2d1acdb0c8a6c9ee08f83719c0b60bf69b cliui-7.0.4/000077500000000000000000000000001375210303500126265ustar00rootroot00000000000000cliui-7.0.4/.coveralls.yml000066400000000000000000000000561375210303500154220ustar00rootroot00000000000000repo_token: NiRhyj91Z2vtgob6XdEAqs83rzNnbMZUu cliui-7.0.4/.eslintrc000066400000000000000000000007101375210303500144500ustar00rootroot00000000000000{ "overrides": [ { "files": "*.ts", "parser": "@typescript-eslint/parser", "rules": { "no-unused-vars": "off", "no-useless-constructor": "off", "@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/no-useless-constructor": "error" } } ], "parserOptions": { "ecmaVersion": 2018, "sourceType": "module" }, "plugins": [ "@typescript-eslint/eslint-plugin" ] } cliui-7.0.4/.github/000077500000000000000000000000001375210303500141665ustar00rootroot00000000000000cliui-7.0.4/.github/workflows/000077500000000000000000000000001375210303500162235ustar00rootroot00000000000000cliui-7.0.4/.github/workflows/ci.yaml000066400000000000000000000032231375210303500175020ustar00rootroot00000000000000on: push: branches: - master pull_request: types: [ assigned, opened, synchronize, reopened, labeled ] name: ci jobs: test: runs-on: ubuntu-latest strategy: matrix: node: [10, 12, 14] steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: node-version: ${{ matrix.node }} - run: node --version - run: npm install env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - run: npm test - run: npm run check windows: runs-on: windows-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: node-version: 12 - run: npm install env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - run: npm test coverage: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: node-version: 14 - run: npm install env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - run: npm test - run: npm run coverage esm: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: node-version: 14 - run: npm install - run: npm run test:esm deno: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: node-version: 14 - run: npm install - run: npm run compile - uses: denolib/setup-deno@v2 with: deno-version: v1.x - run: | deno --version deno test test/deno/cliui-test.ts cliui-7.0.4/.github/workflows/release-please.yml000066400000000000000000000032171375210303500216400ustar00rootroot00000000000000on: push: branches: - master name: release-please jobs: release-please: runs-on: ubuntu-latest steps: - uses: bcoe/release-please-action@v2.6.0 id: release with: token: ${{ secrets.GITHUB_TOKEN }} release-type: node package-name: cliui - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: node-version: 14 - run: npm install env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - run: npm run compile - name: push Deno release run: | git config user.name github-actions[bot] git config user.email 41898282+github-actions[bot]@users.noreply.github.com git remote add gh-token "https://${{ secrets.GITHUB_TOKEN}}@github.com/yargs/cliui.git" git checkout -b deno git add -f build git commit -a -m 'chore: ${{ steps.release.outputs.tag_name }} release' git push origin +deno git tag -a ${{ steps.release.outputs.tag_name }}-deno -m 'chore: ${{ steps.release.outputs.tag_name }} release' git push origin ${{ steps.release.outputs.tag_name }}-deno if: ${{ steps.release.outputs.release_created }} - uses: actions/setup-node@v1 with: node-version: 14 registry-url: 'https://external-dot-oss-automation.appspot.com/' if: ${{ steps.release.outputs.release_created }} - run: npm install if: ${{ steps.release.outputs.release_created }} - run: npm publish env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} if: ${{ steps.release.outputs.release_created }} cliui-7.0.4/.gitignore000066400000000000000000000001041375210303500146110ustar00rootroot00000000000000.DS_Store node_modules .nyc_output package-lock.json coverage build cliui-7.0.4/.nycrc000066400000000000000000000002431375210303500137440ustar00rootroot00000000000000{ "exclude": [ "build/test/**", "test/**" ], "reporter": [ "html", "text" ], "lines": 99.0, "branches": "95", "statements": "99.0" } cliui-7.0.4/CHANGELOG.md000066400000000000000000000074701375210303500144470ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. ### [7.0.4](https://www.github.com/yargs/cliui/compare/v7.0.3...v7.0.4) (2020-11-08) ### Bug Fixes * **deno:** import UIOptions from definitions ([#97](https://www.github.com/yargs/cliui/issues/97)) ([f04f343](https://www.github.com/yargs/cliui/commit/f04f3439bc78114c7e90f82ff56f5acf16268ea8)) ### [7.0.3](https://www.github.com/yargs/cliui/compare/v7.0.2...v7.0.3) (2020-10-16) ### Bug Fixes * **exports:** node 13.0 and 13.1 require the dotted object form _with_ a string fallback ([#93](https://www.github.com/yargs/cliui/issues/93)) ([eca16fc](https://www.github.com/yargs/cliui/commit/eca16fc05d26255df3280906c36d7f0e5b05c6e9)) ### [7.0.2](https://www.github.com/yargs/cliui/compare/v7.0.1...v7.0.2) (2020-10-14) ### Bug Fixes * **exports:** node 13.0-13.6 require a string fallback ([#91](https://www.github.com/yargs/cliui/issues/91)) ([b529d7e](https://www.github.com/yargs/cliui/commit/b529d7e432901af1af7848b23ed6cf634497d961)) ### [7.0.1](https://www.github.com/yargs/cliui/compare/v7.0.0...v7.0.1) (2020-08-16) ### Bug Fixes * **build:** main should be build/index.cjs ([dc29a3c](https://www.github.com/yargs/cliui/commit/dc29a3cc617a410aa850e06337b5954b04f2cb4d)) ## [7.0.0](https://www.github.com/yargs/cliui/compare/v6.0.0...v7.0.0) (2020-08-16) ### ⚠ BREAKING CHANGES * tsc/ESM/Deno support (#82) * modernize deps and build (#80) ### Build System * modernize deps and build ([#80](https://www.github.com/yargs/cliui/issues/80)) ([339d08d](https://www.github.com/yargs/cliui/commit/339d08dc71b15a3928aeab09042af94db2f43743)) ### Code Refactoring * tsc/ESM/Deno support ([#82](https://www.github.com/yargs/cliui/issues/82)) ([4b777a5](https://www.github.com/yargs/cliui/commit/4b777a5fe01c5d8958c6708695d6aab7dbe5706c)) ## [6.0.0](https://www.github.com/yargs/cliui/compare/v5.0.0...v6.0.0) (2019-11-10) ### ⚠ BREAKING CHANGES * update deps, drop Node 6 ### Code Refactoring * update deps, drop Node 6 ([62056df](https://www.github.com/yargs/cliui/commit/62056df)) ## [5.0.0](https://github.com/yargs/cliui/compare/v4.1.0...v5.0.0) (2019-04-10) ### Bug Fixes * Update wrap-ansi to fix compatibility with latest versions of chalk. ([#60](https://github.com/yargs/cliui/issues/60)) ([7bf79ae](https://github.com/yargs/cliui/commit/7bf79ae)) ### BREAKING CHANGES * Drop support for node < 6. ## [4.1.0](https://github.com/yargs/cliui/compare/v4.0.0...v4.1.0) (2018-04-23) ### Features * add resetOutput method ([#57](https://github.com/yargs/cliui/issues/57)) ([7246902](https://github.com/yargs/cliui/commit/7246902)) ## [4.0.0](https://github.com/yargs/cliui/compare/v3.2.0...v4.0.0) (2017-12-18) ### Bug Fixes * downgrades strip-ansi to version 3.0.1 ([#54](https://github.com/yargs/cliui/issues/54)) ([5764c46](https://github.com/yargs/cliui/commit/5764c46)) * set env variable FORCE_COLOR. ([#56](https://github.com/yargs/cliui/issues/56)) ([7350e36](https://github.com/yargs/cliui/commit/7350e36)) ### Chores * drop support for node < 4 ([#53](https://github.com/yargs/cliui/issues/53)) ([b105376](https://github.com/yargs/cliui/commit/b105376)) ### Features * add fallback for window width ([#45](https://github.com/yargs/cliui/issues/45)) ([d064922](https://github.com/yargs/cliui/commit/d064922)) ### BREAKING CHANGES * officially drop support for Node < 4 ## [3.2.0](https://github.com/yargs/cliui/compare/v3.1.2...v3.2.0) (2016-04-11) ### Bug Fixes * reduces tarball size ([acc6c33](https://github.com/yargs/cliui/commit/acc6c33)) ### Features * adds standard-version for release management ([ff84e32](https://github.com/yargs/cliui/commit/ff84e32)) cliui-7.0.4/LICENSE.txt000066400000000000000000000013331375210303500144510ustar00rootroot00000000000000Copyright (c) 2015, Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. cliui-7.0.4/README.md000066400000000000000000000056661375210303500141220ustar00rootroot00000000000000# cliui ![ci](https://github.com/yargs/cliui/workflows/ci/badge.svg) [![NPM version](https://img.shields.io/npm/v/cliui.svg)](https://www.npmjs.com/package/cliui) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) ![nycrc config on GitHub](https://img.shields.io/nycrc/yargs/cliui) easily create complex multi-column command-line-interfaces. ## Example ```js 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](https://github.com/denoland/deno) and [ESM](https://nodejs.org/api/esm.html#esm_ecmascript_modules): ```typescript 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...** ```js var ui = require('./')({ width: 60 }) ui.div( 'Usage: node ./bin/foo.js\n' + ' \t provide a regex\n' + ' \t provide a glob\t [required]' ) console.log(ui.toString()) ``` **will output:** ```shell Usage: node ./bin/foo.js provide a regex provide a glob [required] ``` ## Methods ```js 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-7.0.4/deno.ts000066400000000000000000000006101375210303500141200ustar00rootroot00000000000000// Bootstrap cliui with CommonJS dependencies: import { cliui, UI } from './build/lib/index.js' import type { UIOptions } from './build/lib/index.d.ts' import { wrap, stripAnsi } from './build/lib/string-utils.js' export default function ui (opts: UIOptions): UI { return cliui(opts, { stringWidth: (str: string) => { return [...str].length }, stripAnsi, wrap }) } cliui-7.0.4/index.mjs000066400000000000000000000004651375210303500144550ustar00rootroot00000000000000// Bootstrap cliui with CommonJS dependencies: import { cliui } from './build/lib/index.js' import { wrap, stripAnsi } from './build/lib/string-utils.js' export default function ui (opts) { return cliui(opts, { stringWidth: (str) => { return [...str].length }, stripAnsi, wrap }) } cliui-7.0.4/lib/000077500000000000000000000000001375210303500133745ustar00rootroot00000000000000cliui-7.0.4/lib/cjs.ts000066400000000000000000000005111375210303500145200ustar00rootroot00000000000000// Bootstrap cliui with CommonJS dependencies: import { cliui, UIOptions } from './index.js' const stringWidth = require('string-width') const stripAnsi = require('strip-ansi') const wrap = require('wrap-ansi') export default function ui (opts: UIOptions) { return cliui(opts, { stringWidth, stripAnsi, wrap }) } cliui-7.0.4/lib/index.ts000066400000000000000000000217741375210303500150660ustar00rootroot00000000000000'use strict' const align = { right: alignRight, center: alignCenter } const top = 0 const right = 1 const bottom = 2 const left = 3 export interface UIOptions { width: number; wrap?: boolean; rows?: string[]; } interface Column { text: string; width?: number; align?: 'right'|'left'|'center', padding: number[], border?: boolean; } interface ColumnArray extends Array { span: boolean; } interface Line { hidden?: boolean; text: string; span?: boolean; } interface Mixin { stringWidth: Function; stripAnsi: Function; wrap: Function; } export class UI { width: number; wrap: boolean; rows: ColumnArray[]; constructor (opts: UIOptions) { this.width = opts.width this.wrap = opts.wrap ?? true this.rows = [] } span (...args: ColumnArray) { const cols = this.div(...args) cols.span = true } resetOutput () { this.rows = [] } div (...args: (Column|string)[]): ColumnArray { if (args.length === 0) { this.div('') } if (this.wrap && this.shouldApplyLayoutDSL(...args) && typeof args[0] === 'string') { return this.applyLayoutDSL(args[0]) } const cols = args.map(arg => { if (typeof arg === 'string') { return this.colFromString(arg) } return arg }) as ColumnArray this.rows.push(cols) return cols } private shouldApplyLayoutDSL (...args: (Column|string)[]): boolean { return args.length === 1 && typeof args[0] === 'string' && /[\t\n]/.test(args[0]) } private applyLayoutDSL (str: string): ColumnArray { const rows = str.split('\n').map(row => row.split('\t')) let leftColumnWidth = 0 // simple heuristic for layout, make sure the // second column lines up along the left-hand. // don't allow the first column to take up more // than 50% of the screen. rows.forEach(columns => { if (columns.length > 1 && mixin.stringWidth(columns[0]) > leftColumnWidth) { leftColumnWidth = Math.min( Math.floor(this.width * 0.5), mixin.stringWidth(columns[0]) ) } }) // generate a table: // replacing ' ' with padding calculations. // using the algorithmically generated width. rows.forEach(columns => { this.div(...columns.map((r, i) => { return { text: r.trim(), padding: this.measurePadding(r), width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined } as Column })) }) return this.rows[this.rows.length - 1] } private colFromString (text: string): Column { return { text, padding: this.measurePadding(text) } } private measurePadding (str: string): number[] { // measure padding without ansi escape codes const noAnsi = mixin.stripAnsi(str) return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length] } toString (): string { const lines: Line[] = [] this.rows.forEach(row => { this.rowToString(row, lines) }) // don't display any lines with the // hidden flag set. return lines .filter(line => !line.hidden) .map(line => line.text) .join('\n') } rowToString (row: ColumnArray, lines: Line[]) { this.rasterize(row).forEach((rrow, r) => { let str = '' rrow.forEach((col: string, c: number) => { const { width } = row[c] // the width with padding. const wrapWidth = this.negatePadding(row[c]) // the width without padding. let ts = col // temporary string used during alignment/padding. if (wrapWidth > mixin.stringWidth(col)) { ts += ' '.repeat(wrapWidth - mixin.stringWidth(col)) } // align the string within its column. if (row[c].align && row[c].align !== 'left' && this.wrap) { const fn = align[(row[c].align as 'right'|'center')] ts = fn(ts, wrapWidth) if (mixin.stringWidth(ts) < wrapWidth) { ts += ' '.repeat((width || 0) - mixin.stringWidth(ts) - 1) } } // apply border and padding to string. const padding = row[c].padding || [0, 0, 0, 0] if (padding[left]) { str += ' '.repeat(padding[left]) } str += addBorder(row[c], ts, '| ') str += ts str += addBorder(row[c], ts, ' |') if (padding[right]) { str += ' '.repeat(padding[right]) } // if prior row is span, try to render the // current row on the prior line. if (r === 0 && lines.length > 0) { str = this.renderInline(str, lines[lines.length - 1]) } }) // remove trailing whitespace. lines.push({ text: str.replace(/ +$/, ''), span: row.span }) }) return lines } // if the full 'source' can render in // the target line, do so. private renderInline (source: string, previousLine: Line) { const match = source.match(/^ */) const leadingWhitespace = match ? match[0].length : 0 const target = previousLine.text const targetTextWidth = mixin.stringWidth(target.trimRight()) if (!previousLine.span) { return source } // if we're not applying wrapping logic, // just always append to the span. if (!this.wrap) { previousLine.hidden = true return target + source } if (leadingWhitespace < targetTextWidth) { return source } previousLine.hidden = true return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft() } private rasterize (row: ColumnArray) { const rrows: string[][] = [] const widths = this.columnWidths(row) let wrapped // word wrap all columns, and create // a data-structure that is easy to rasterize. row.forEach((col, c) => { // leave room for left and right padding. col.width = widths[c] if (this.wrap) { wrapped = mixin.wrap(col.text, this.negatePadding(col), { hard: true }).split('\n') } else { wrapped = col.text.split('\n') } if (col.border) { wrapped.unshift('.' + '-'.repeat(this.negatePadding(col) + 2) + '.') wrapped.push("'" + '-'.repeat(this.negatePadding(col) + 2) + "'") } // add top and bottom padding. if (col.padding) { wrapped.unshift(...new Array(col.padding[top] || 0).fill('')) wrapped.push(...new Array(col.padding[bottom] || 0).fill('')) } wrapped.forEach((str: string, r: number) => { if (!rrows[r]) { rrows.push([]) } const rrow = rrows[r] for (let i = 0; i < c; i++) { if (rrow[i] === undefined) { rrow.push('') } } rrow.push(str) }) }) return rrows } private negatePadding (col: Column) { let wrapWidth = col.width || 0 if (col.padding) { wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0) } if (col.border) { wrapWidth -= 4 } return wrapWidth } private columnWidths (row: ColumnArray) { if (!this.wrap) { return row.map(col => { return col.width || mixin.stringWidth(col.text) }) } let unset = row.length let remainingWidth = this.width // column widths can be set in config. const widths = row.map(col => { if (col.width) { unset-- remainingWidth -= col.width return col.width } return undefined }) // any unset widths should be calculated. const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0 return widths.map((w, i) => { if (w === undefined) { return Math.max(unsetWidth, _minWidth(row[i])) } return w }) } } function addBorder (col: Column, ts: string, style: string) { if (col.border) { if (/[.']-+[.']/.test(ts)) { return '' } if (ts.trim().length !== 0) { return style } return ' ' } return '' } // calculates the minimum width of // a column, based on padding preferences. function _minWidth (col: Column) { const padding = col.padding || [] const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0) if (col.border) { return minWidth + 4 } return minWidth } function getWindowWidth (): number { /* istanbul ignore next: depends on terminal */ if (typeof process === 'object' && process.stdout && process.stdout.columns) { return process.stdout.columns } return 80 } function alignRight (str: string, width: number): string { str = str.trim() const strWidth = mixin.stringWidth(str) if (strWidth < width) { return ' '.repeat(width - strWidth) + str } return str } function alignCenter (str: string, width: number): string { str = str.trim() const strWidth = mixin.stringWidth(str) /* istanbul ignore next */ if (strWidth >= width) { return str } return ' '.repeat((width - strWidth) >> 1) + str } let mixin: Mixin export function cliui (opts: Partial, _mixin: Mixin) { mixin = _mixin return new UI({ width: opts?.width || getWindowWidth(), wrap: opts?.wrap }) } cliui-7.0.4/lib/string-utils.ts000066400000000000000000000017331375210303500164140ustar00rootroot00000000000000// Minimal replacement for ansi string helpers "wrap-ansi" and "strip-ansi". // to facilitate ESM and Deno modules. // TODO: look at porting https://www.npmjs.com/package/wrap-ansi to ESM. // The npm application // Copyright (c) npm, Inc. and Contributors // Licensed on the terms of The Artistic License 2.0 // See: https://github.com/npm/cli/blob/4c65cd952bc8627811735bea76b9b110cc4fc80e/lib/utils/ansi-trim.js const ansi = new RegExp('\x1b(?:\\[(?:\\d+[ABCDEFGJKSTm]|\\d+;\\d+[Hfm]|' + '\\d+;\\d+;\\d+m|6n|s|u|\\?25[lh])|\\w)', 'g') export function stripAnsi (str: string) { return str.replace(ansi, '') } export function wrap (str: string, width: number) { const [start, end] = str.match(ansi) || ['', ''] str = stripAnsi(str) let wrapped = '' for (let i = 0; i < str.length; i++) { if (i !== 0 && (i % width) === 0) { wrapped += '\n' } wrapped += str.charAt(i) } if (start && end) { wrapped = `${start}${wrapped}${end}` } return wrapped } cliui-7.0.4/package.json000066400000000000000000000037571375210303500151300ustar00rootroot00000000000000{ "name": "cliui", "version": "7.0.4", "description": "easily create complex multi-column command-line-interfaces", "main": "build/index.cjs", "exports": { ".": [ { "import": "./index.mjs", "require": "./build/index.cjs" }, "./build/index.cjs" ] }, "type": "module", "module": "./index.mjs", "scripts": { "check": "standardx '**/*.ts' && standardx '**/*.js' && standardx '**/*.cjs'", "fix": "standardx --fix '**/*.ts' && standardx --fix '**/*.js' && standardx --fix '**/*.cjs'", "pretest": "rimraf build && tsc -p tsconfig.test.json && cross-env NODE_ENV=test npm run build:cjs", "test": "c8 mocha ./test/*.cjs", "test:esm": "c8 mocha ./test/esm/cliui-test.mjs", "postest": "check", "coverage": "c8 report --check-coverage", "precompile": "rimraf build", "compile": "tsc", "postcompile": "npm run build:cjs", "build:cjs": "rollup -c", "prepare": "npm run compile" }, "repository": "yargs/cliui", "standard": { "ignore": [ "**/example/**" ], "globals": [ "it" ] }, "keywords": [ "cli", "command-line", "layout", "design", "console", "wrap", "table" ], "author": "Ben Coe ", "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" }, "devDependencies": { "@types/node": "^14.0.27", "@typescript-eslint/eslint-plugin": "^4.0.0", "@typescript-eslint/parser": "^4.0.0", "@wessberg/rollup-plugin-ts": "^1.3.2", "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": "^8.1.1", "rimraf": "^3.0.2", "rollup": "^2.23.1", "standardx": "^7.0.0", "typescript": "^4.0.0" }, "files": [ "build", "index.mjs", "!*.d.ts" ], "engine": { "node": ">=10" } } cliui-7.0.4/renovate.json000066400000000000000000000001601375210303500153410ustar00rootroot00000000000000{ "extends": [ "config:base" ], "pinVersions": false, "rebaseStalePrs": true, "gitAuthor": null } cliui-7.0.4/rollup.config.js000066400000000000000000000004431375210303500157460ustar00rootroot00000000000000import ts from '@wessberg/rollup-plugin-ts' const output = { format: 'cjs', file: './build/index.cjs', exports: 'default' } if (process.env.NODE_ENV === 'test') output.sourcemap = true export default { input: './lib/cjs.ts', output, plugins: [ ts({ /* options */ }) ] } cliui-7.0.4/screenshot.png000066400000000000000000000435151375210303500155210ustar00rootroot00000000000000PNG  IHDR86YPiCCPICC ProfileX YgTsQrs .IP"D FDD@" (*@{}s<[]]TuOT-djll$ @Tt^੆''`F"XH@d O/2[kǿ?Ə0j巧ilF_Q StpҐ&gC8n?Pi@Oq7M(=:넿埸ѣ̚Y HZ@ ԲOM, na&ZIǿ9[F'\V#}R2__PBg@8ヶLcbia!pPZ# }MeuF{Q#QY \j>L|\r H%p`o@>087 6¨(: l;A&@8 P΃Khmpo{0" Dp |"( j1GCBh$نBr$R\D#{H?yL!_(QNTFQE hMA3h ZC[}1:Gg11aܘ`#c4,rkcŦǁ)is6Rq{qGpUz\!nO zxk>O;?G  2mnz [ { G uVB?a0K$ D#J'f[7$&IdA!EIŤfi ŠȐ̐PaQрэ1q'c c-c'sƯLLLLLLaLiL%L2bZ ɦd_ry? BHS(>x~J52Blȼy# 1Fb,,Ӭ ҬTTRCllllQl{βcd'KgWq`8*9:9p8e899s9sppsipypm*5ʍqKs[sGrq_#cēS33+kě[(9__>58~y~g$c9QAyA݂BBBBڅÅ D8D։5-K;)#(.#..^'BQBG"XPMbFRD^rdT!;R2Ҟ{IOXˤ<n-}$Gӑ;*'kʇʗ* Z a G讉^SfHhXJ[N)]GeIe|;?U4U"U*Uڨ6~QW P+U{NQPߡޠYCA#HMM{=mZZ4Z)mIm?2!N':wu&;tt.}Wԏ??VfmʵcTD;nP̐jXnH(фq9&*&4&zM[03Ksvsw##!53[-[VVVCB366m:lɶGl_Q{Rc 'N7 NΥo]T]qpzu-홻{{GǼAQ/e^ü|>>}fכ/ZW7wp̆-m&MM~~grꬿLiFSAA& OLN n~<|>1LJgd])/z4{tDtGp̖Xz6li㐸 q ;A6aw«uߓ<.oa;Y>9;y""VրmĶjHj;ޤYUdAJo~Z6PqI&ͼf敖[!6=kjiy;wZmwzN׵Z5>|pGWOmfo?~tA'CCOL>|y8qxYs/GG_ʽUkޏǍ/xKy[,}Xs?84T$0a_'^菌7?.cXݸ›·k޶LLORW>zZ}zCǀOl8ͼ ϗ_ER<ѹ:4S&qi/IAQIBcvf `Me;1ʭC?"$.^$MX3Y)&iMYk9?d5&Upbjk}45s*<}m-@`Qq>$K!+5kswh-v;gduL v1[okgcҦ" 6Ae[Cp: pU>Zi@#FӦO46:v}{GRg;GV;ֵ~B\p量;%["/@l'hFp ^| A0Eeke(c+ŷ?)0 ,T+\!R*Z,V(')(E6.-w\>Nj"84|WQZzAWHKOQjuyFf&ҦfŠ b )Q;G{}.Gk'^w.nۼl_T†6ekɁAg7,EȝQѸΘݱƱ7м]-$qmHR-7RSl۵+U6unG{Zΐt]2A=cYrRj#!/@DA L:L:S:~q'5˕+d+Nf;XPg9{j=tIϕWq6x_/kjߔkloqX[sˎbwLu`r\C#{qagE/_2JϝLen>jo=@3=s kH' nS PZD H0"@hLy Ȇ9 `d aG#!`>؉* ?0 K! U0#k' #B'H DO*'8?"Eɦ|dvcnN>+`:n~CS˅k;S+7ɟ%*0&x\_XAm"@q 3Ryґ2 r 7SLUUUTQ}vV=[#TFKIK{Eހ~Nuw {'M̀9s$+5 ٖN^1کй]s  _ *=6m r #4pBt@f ZSFB]▋)km!6^a{nOaνA^?(xQR"zDئ'*(V8R;z䕍ט6mhQh鴸[M{?$^ZMeNw~e!G⣥?cWWd45{ k T nDAaEV^8TCi b62\. [7KC.="+ћxdL* eg(`fctf4#.3 oV Vul-]/`f+[>f^nz>gJA#q|afIHJ)}@&XDNJ]HRbVfWaS%.MitiҺݥL>ZuaF4P/SK3]s KKM֩6'm88;E=[{ >|l/Xt5'd~yANE "EU$x% R?|]gV\c觔|TAW ~Mktv]"Vm67)06f;:ep}j@НQ1 -&^8=)!9pʴ䝃KnR&G{gPZU_2ƣgkYnXztWSs}u/^:ttu{RCv􍾛-ZSmeqwn܋=sk!'+;|0:}{>Nz{cGO3G?B秾~]0]Ac`QsdROV VJx dX~YY* ++++0x@ks^Q4iTXtXML:com.adobe.xmp 568 157 9\-IDATx XSW4Q~Y -N/N;G4LεpNw^{=-3N9X=u`Zi ALh:nԠDMlI;N`zxkb D+)ѪfCF9$,\,P@^E^N7D,H &pahkh5uF0y/^>A"|P,ʼ#i{殆CF?:ޱ@ƛQm11emf {sbbrV(?~WzG͛YTۉ@H1y)-KZT;곏YI2m!!s+;&M%% bvr\uc% @` oAy.CcoQNܺ·23s*yu//yVQumMe [8%IZۚ*>a)'(%5+#Uh Nء(di/jZkFUGio@ x9*u +2 ~u4Wtal-r^**+)ipu]y Y.QST'ai-S %{g7޷gc+4mkIZkh i.1֮ 7<+-3r)*И(@ܬ5E@I.-չ%i9E6֒9BM7g;>P}2srxy]|-3cҞzn!̺ <^%!+z9m {GG @n<lZh֚LiJnNd:>vRm3ԀF>FESE9/ĉ$W)"^gaK)WwNj}Z*i\b< l}T@>[IJSSO"\A„-*.s>j1Ӳ/7ҩ?d3NRXOYZXHKTZN}@4GnJQܡO^SϥP Pjeq~Dz}6*0:M5Yye c:h|@ t9  0q!U;btCɝG&ERN['Xrږ3\F[51Rp ӑ}ZmKF[-ndєg6@)"^k⵲uVӨJ-ӆ*iNGH3ޯB^MJAqir6Q해rࠎҚ8G%ύs c4\n#n} `>=3 ֲB+V[Kn5| S9fJ $5j)7+zyqt5gȉdTs݋/qNH/u۹Q/+*ީ[\Ҕ[6f2OBݛ7[g6o#[S9H'F=ŦzPRa="u8 ,(J TA -Ox>!o> f`l|Zg͆p1>!~ Tܞjjt\1iD~J\,ijGoȭRy%lK٧mZ5ME4׳4q';Je^1: LKZķV tI錒%/{YRzκ=e::XE~%s7H;)t&FݡONs>A 3 g 6l>.L3svz;X8ݙ琽 %A,U\rBVCDk٦-vxHѣǭUth7Zj\әuY yC]Fְlh\Rҧ!,0)khӞ8sK9*]F {mkVs ] R'{heݭex=m|~h5w5n"k|]!-PVǨYw[ٮ7P RsOvu̶50xn͟ ?fhRu F%ZoB@8\ib9|甔:_ЗP[XU >(鼎{Ӓ!+]&ry~g95RﱝV)=) ;!F}Ϲ&dxk@W8\Q5%\&` sTZk OgYpgʩ.pZs{T{R ym+j-ֹmqnKpT}ϼƝtN-7FGc/@&0b v6ھ6m&xrZxl6n4>]o-Z]Zn₟~<Y,p]Yz{{-aLة#)Hx07aZ+㭋˻Q $<46:{ @ Ցo_[YֺK׃Wz-5f4&Y*~z-XD:=*CdHKGMxA Q@ "Pj?~zך-/O&aWoo\뺤?I]qI]G6o>3';z!D? xx'.%d3Jo=zXX:X*dmݚ1CE@@`rTqs8.}nD6vUNJܗdw? \ EbȖe6 -ܐcܪ#KtPp s  ,{N m{g[jIl\n0xiQop@@@` (@@G,?@D QE/K*\  QpT   DUDB8@%  %GQ  .8p "?@D QE/K*\  QpT   DUDB8@%  %GQ  .8p "?@D QE/K*\  QpT   DUDB8@%  %GQ  .8p "?@D QE/K*\  QpT   DUDB8@%  %GQ  .8p "?@D QE/K*\  QpT  +AƈY[lJJ,ct24l&Lp4餸UV[w !1 㒥Uv>=zi\nxsן}[nHƶz:#%b%q㙫H3klk˕3 ŷ lnK`;z ]v/Bp<U狛i3?2-V L ߚn8@[Õ+ xyE Lr i XESLi T:5TCȦo,.c*mQSTaTǷ]#6"UӻZt㧵Ÿhk`?(](}tT(-t \bL~luSm7zg撎CU܆;}:@+K{QӢ]7"A[ *ڱCu1d= xџvԈHo|R"O˒~Yک>֘e/`u?8h^ܢm$i/.P;ScR(1)B"fELKI[8|ɻM'.RP+/Y㢽A؎1iO=b^A1mw昞@SF-H*i7̮3]UQ嬗oU_q98f\)opw[ i9E6֒9^X6EyiJ7h:wD]i_*Lcisψ`:Vͅ_O9re: o11'sX;L.g:εS]NeXtu7'l'N~779ed[?H~TtvJwhq8ݷ1k阖JRz輇ƨ?1˵Sh|ڣR]TS[{bߒ{ JVS]HlatVwf'zS[6ڎԮ3]&5 MҵTr!ԂHcU׶t!nz(5z2eM?Up5J4 {t0ޥ~݇uWڙ+\o8d,c5n1#B 27M`no՞6mGu>59eժ{zUthB }JRӓtBN Q6ͳ8#mvykr HSRSSń̑?J0npB*+S I-Tk5*3nvIcDy|f:V>2uAWrdK+G;:Ȍ䒪9n_X,%/,wK(Ɇ%>{SRg'Sȥ3P2]yOH[83H3 pݑG˗[נ/2ٱJ }~~,~څqO)w}ͼu$O:'UF7v\6l=6/I'݌OHNb4C/w/'.U9*KWu\KVuT.;ݫc1@WOevA ]vGeE_K-,Ii/{c\FQӼ#uK-FiWz(OgZB^t/Ä4pɼ q`9Ɗy[";7mnSŃKH?DfBhV*廬^/BGC)i&4 ۏdo4.5Vq ZZIBI~#jyOr4Lb%  M .k׿rpkďO|kUp]MTQW-x嵏4d+BX6&%T9g )+YtB}&7,I;v.G(:FCZ8u^sxcXZ~\I(fѩ&FůGpf׎/FT&iR|N~@9Е! (m<~FUB7K$];Z4aaJ.~eyOi;*)R_et߇l}>G &;wTk&}DW"" nԢֹXY{q{5 h+肋g*K6)\)ݹκÑkg;\'6IwT1Z]ߩh*||g3u`[ӣmq//+} ,irckufD4|gc؁jD7!ͬ4)Y|ZXͣY_p͒~uכ)Ip ַ>2›){Hʒ oEu: +* *XS|{r씤d@G{-;+OhYQ %1 wσ/̈H.XJ}<>y8nۄfJ {k6Q%d[4DM~M5)/[,/ɄQ&0eǚq$S6X?+nQT=*ܘ  w:J   Q烫  m  Up>wUGJ7k+]:&hZDl!cX j* ਢRC%'|vă :L|V_+V*}DrFqB%d(!G%1NjH];#o.U$>6 |xB2%a<1"E8Ma(]|2Ĩdl}쩓k{:˵yNӧfsUbZצ}wi{&nk_$E׼#{z 5'9d{z ?>Vp w\`t NOxiOE nSm9b>ps9{tud!ON' 9FLpTCA:QʷvΧSW{Wd(~׹d@sW|/ݽ5pU0ZȜ/ٜ֟ܲ#?ykf'o%;qt#O>k&+?]:tp_o-]ص0Kz &m^xH&L3ۘ~e=@ G\yzKu\>gNn,SeZ0ߏq9 @ Ln93IFuSZM 9kW ~~'ʂ-L]{|{}ͫSh4W`R2򾏶>uKxxޭs4t 4yZ {H [>* {N+8|ߋܥYnOm:؀|9 zATvEQݣ+n>>9Q=G["@`R@jRUƸvtYLq닛C7N߸%W}I^kn菶R/b\}g;CՅTW$Q/O+ι;ϋi|X3J'7YÀp_|ظm: Mi4'A*Jn;uplw醓b Ls $%%;5Y/N:{=?G+׿~H+zƙO>S? $_joJ]yO7ij/"YjrŚ4mfH%7ؤӒe~}x$I*D~&$cVI7sɤ~{d'LILK'_A8(@`W} $0E4m0)3.MF L*._x-NWB$KGb,`ůIlc"B@`">N}#K@8/&W  i  0*Q 28"r@@FEjTؐ"0^;kN,rƂXP 2+׿Ww<7t|v;~~YC pG-T_R6]E7 QkD3l'C8>Kԃ_ݎj0FQOz y|kTie@!p;Z;m)'c~Ķ @mT菎JW^Zf6Nt-͢w7x9qzƉ 6L.vTb@ " x|C]i?oSTmT/i¥)5df%q"{ΪLLnH,<3ƉR  {#g$8qE mxϪy9d9 9=.¤9nH6B-Xi\am Iܶ7ryW%MVbGam,a~6~\tgў3f]`#̍sf5XOu?B_8q'Ɖ'rт nᓜnR J`f\uAaso646s[!Χj?U C vŰ|zҧ9~mv&1Ɖ5G~ߓpHYjrnro֍`M.*O~=:H\n;J46I:Эd7*f>Uo >A`\ ǵP6 =w*O_,eQoh6NKE}BILCraLQMZ  0 QMʅi  0QMZ  0 Q\1oYc[]޽k~FO 5Mc ;fCB߇SC[p"?h uQ%IENDB`cliui-7.0.4/test/000077500000000000000000000000001375210303500136055ustar00rootroot00000000000000cliui-7.0.4/test/cliui.cjs000066400000000000000000000315531375210303500154220ustar00rootroot00000000000000'use strict' /* global describe, it */ require('chai').should() // Force chalk to enable color, if it's disabled the test fails. process.env.FORCE_COLOR = 1 const chalk = require('chalk') const cliui = require('../build/index.cjs') const stripAnsi = require('strip-ansi') describe('cliui', () => { describe('resetOutput', () => { it('should set lines to empty', () => { const ui = cliui() ui.div('i am a value that would be in a line') ui.resetOutput() ui.toString().length.should.be.equal(0) }) }) describe('div', () => { it("wraps text at 'width' if a single column is given", () => { const ui = cliui({ width: 10 }) ui.div('i am a string that should be wrapped') ui.toString().split('\n').forEach(row => { row.length.should.be.lte(10) }) }) it('evenly divides text across columns if multiple columns are given', () => { const ui = cliui({ width: 40 }) ui.div( { text: 'i am a string that should be wrapped', width: 15 }, 'i am a second string that should be wrapped', 'i am a third string that should be wrapped' ) // total width of all columns is <= // the width cliui is initialized with. ui.toString().split('\n').forEach(row => { row.length.should.be.lte(40) }) // it should wrap each column appropriately. const expected = [ 'i am a string i am a i am a third', 'that should be second string that', 'wrapped string that should be', ' should be wrapped', ' wrapped' ] ui.toString().split('\n').should.eql(expected) }) it('allows for a blank row to be appended', () => { const ui = cliui({ width: 40 }) ui.div() // it should wrap each column appropriately. const expected = [''] ui.toString().split('\n').should.eql(expected) }) }) describe('_columnWidths', () => { it('uses same width for each column by default', () => { const ui = cliui({ width: 40 }) const widths = ui.columnWidths([{}, {}, {}]) widths[0].should.equal(13) widths[1].should.equal(13) widths[2].should.equal(13) }) it('divides width over remaining columns if first column has width specified', () => { const ui = cliui({ width: 40 }) const widths = ui.columnWidths([{ width: 20 }, {}, {}]) widths[0].should.equal(20) widths[1].should.equal(10) widths[2].should.equal(10) }) it('divides width over remaining columns if middle column has width specified', () => { const ui = cliui({ width: 40 }) const widths = ui.columnWidths([{}, { width: 10 }, {}]) widths[0].should.equal(15) widths[1].should.equal(10) widths[2].should.equal(15) }) it('keeps track of remaining width if multiple columns have width specified', () => { const ui = cliui({ width: 40 }) const widths = ui.columnWidths([{ width: 20 }, { width: 12 }, {}]) widths[0].should.equal(20) widths[1].should.equal(12) widths[2].should.equal(8) }) it('uses a sane default if impossible widths are specified', () => { const ui = cliui({ width: 40 }) const widths = ui.columnWidths([{ width: 30 }, { width: 30 }, { padding: [0, 2, 0, 1] }]) widths[0].should.equal(30) widths[1].should.equal(30) widths[2].should.equal(4) }) }) describe('alignment', () => { it('allows a column to be right aligned', () => { const ui = cliui({ width: 40 }) ui.div( 'i am a string', { text: 'i am a second string', align: 'right' }, 'i am a third string that should be wrapped' ) // it should right-align the second column. const expected = [ 'i am a stringi am a secondi am a third', ' stringstring that', ' should be', ' wrapped' ] ui.toString().split('\n').should.eql(expected) }) it('allows a column to be center aligned', () => { const ui = cliui({ width: 60 }) ui.div( 'i am a string', { text: 'i am a second string', align: 'center', padding: [0, 2, 0, 2] }, 'i am a third string that should be wrapped' ) // it should right-align the second column. const expected = [ 'i am a string i am a second i am a third string', ' string that should be', ' wrapped' ] ui.toString().split('\n').should.eql(expected) }) }) describe('padding', () => { it('handles left/right padding', () => { const ui = cliui({ width: 40 }) ui.div( { text: 'i have padding on my left', padding: [0, 0, 0, 4] }, { text: 'i have padding on my right', padding: [0, 2, 0, 0], align: 'center' }, { text: 'i have no padding', padding: [0, 0, 0, 0] } ) // it should add left/right padding to columns. const expected = [ ' i have i have i have no', ' padding padding on padding', ' on my my right', ' left' ] ui.toString().split('\n').should.eql(expected) }) it('handles top/bottom padding', () => { const ui = cliui({ width: 40 }) ui.div( 'i am a string', { text: 'i am a second string', padding: [2, 0, 0, 0] }, { text: 'i am a third string that should be wrapped', padding: [0, 0, 1, 0] } ) // it should add top/bottom padding to second // and third columns. const expected = [ 'i am a string i am a third', ' string that', ' i am a secondshould be', ' string wrapped', '' ] ui.toString().split('\n').should.eql(expected) }) it('preserves leading whitespace as padding', () => { const ui = cliui() ui.div(' LEADING WHITESPACE') ui.div('\u001b[34m with ansi\u001b[39m') const expected = [ ' LEADING WHITESPACE', ' with ansi' ] ui.toString().split('\n').map(l => stripAnsi(l)).should.eql(expected) }) }) describe('border', () => { it('allows a border to be placed around a div', () => { const ui = cliui({ width: 40 }) ui.div( { text: 'i am a first string', padding: [0, 0, 0, 0], border: true }, { text: 'i am a second string', padding: [1, 0, 0, 0], border: true } ) const expected = [ '.------------------.', '| i am a first |.------------------.', '| string || i am a second |', "'------------------'| string |", " '------------------'" ] ui.toString().split('\n').should.eql(expected) }) }) describe('wrap', () => { it('allows wordwrap to be disabled', () => { const ui = cliui({ wrap: false }) ui.div( { text: 'i am a string', padding: [0, 1, 0, 0] }, { text: 'i am a second string', padding: [0, 2, 0, 0] }, { text: 'i am a third string that should not be wrapped', padding: [0, 0, 0, 2] } ) ui.toString().should.equal('i am a string i am a second string i am a third string that should not be wrapped') }) }) describe('span', () => { it('appends the next row to the end of the prior row if it fits', () => { const ui = cliui({ width: 40 }) ui.span( { text: 'i am a string that will be wrapped', width: 30 } ) ui.div( { text: ' [required] [default: 99]', align: 'right' } ) const expected = [ 'i am a string that will be', 'wrapped [required] [default: 99]' ] ui.toString().split('\n').should.eql(expected) }) it('does not append the string if it does not fit on the prior row', () => { const ui = cliui({ width: 40 }) ui.span( { text: 'i am a string that will be wrapped', width: 30 } ) ui.div( { text: 'i am a second row', align: 'left' } ) const expected = [ 'i am a string that will be', 'wrapped', 'i am a second row' ] ui.toString().split('\n').should.eql(expected) }) it('always appends text to prior span if wrap is disabled', () => { const ui = cliui({ wrap: false, width: 40 }) ui.span( { text: 'i am a string that will be wrapped', width: 30 } ) ui.div( { text: 'i am a second row', align: 'left', padding: [0, 0, 0, 3] } ) ui.div('a third line') const expected = [ 'i am a string that will be wrapped i am a second row', 'a third line' ] ui.toString().split('\n').should.eql(expected) }) it('appends to prior line appropriately when strings contain ansi escape codes', () => { const ui = cliui({ width: 40 }) ui.span( { text: chalk.green('i am a string that will be wrapped'), width: 30 } ) ui.div( { text: chalk.blue(' [required] [default: 99]'), align: 'right' } ) const expected = [ 'i am a string that will be', 'wrapped [required] [default: 99]' ] ui.toString().split('\n').map(l => stripAnsi(l)).should.eql(expected) }) }) describe('layoutDSL', () => { it('turns tab into multiple columns', () => { const ui = cliui({ width: 60 }) ui.div( ' \tmy awesome regex\n \tanother row\t a third column' ) const expected = [ ' my awesome regex', ' another row a third column' ] ui.toString().split('\n').should.eql(expected) }) it('turns newline into multiple rows', () => { const ui = cliui({ width: 40 }) ui.div( 'Usage: $0\n \t my awesome regex\n \t my awesome glob\t [required]' ) const expected = [ 'Usage: $0', ' my awesome regex', ' my awesome [required]', ' glob' ] ui.toString().split('\n').should.eql(expected) }) it('aligns rows appropriately when they contain ansi escape codes', () => { const ui = cliui({ width: 40 }) ui.div( ' \t ' + chalk.red('my awesome regex') + '\t [regex]\n ' + chalk.blue('') + '\t my awesome glob\t [required]' ) const expected = [ ' my awesome [regex]', ' regex', ' my awesome [required]', ' glob' ] ui.toString().split('\n').map(l => stripAnsi(l)).should.eql(expected) }) it('ignores ansi escape codes when measuring padding', () => { // Forcefully enable color-codes for this test const { enabled, level } = chalk chalk.enabled = true chalk.level = 1 const ui = cliui({ width: 25 }) // using figlet font 'Shadow' rendering of text 'true' here ui.div( chalk.blue(' | \n __| __| | | _ \\ \n | | | | __/ \n \\__| _| \\__,_| \\___| \n ') ) // relevant part is first line - leading whitespace should be preserved as left padding const expected = [ ' |', ' __| __| | | _ \\', ' | | | | __/', ' \\__| _| \\__,_| \\___|', ' ' ] ui.toString().split('\n').map(l => stripAnsi(l)).should.eql(expected) chalk.enabled = enabled chalk.level = level }) it('correctly handles lack of ansi escape codes when measuring padding', () => { const ui = cliui({ width: 25 }) // using figlet font 'Shadow' rendering of text 'true' here ui.div( ' | \n __| __| | | _ \\ \n | | | | __/ \n \\__| _| \\__,_| \\___| \n ' ) // The difference const expected = [ ' |', ' __| __| | | _ \\', ' | | | | __/', ' \\__| _| \\__,_| \\___|', '' ] ui.toString().split('\n').map(l => stripAnsi(l)).should.eql(expected) }) it('does not apply DSL if wrap is false', () => { const ui = cliui({ width: 40, wrap: false }) ui.div( 'Usage: $0\ttwo\tthree' ) ui.toString().should.eql('Usage: $0\ttwo\tthree') }) }) }) cliui-7.0.4/test/deno/000077500000000000000000000000001375210303500145325ustar00rootroot00000000000000cliui-7.0.4/test/deno/cliui-test.ts000066400000000000000000000025331375210303500171670ustar00rootroot00000000000000/* global Deno */ import { assert, assertEquals } from 'https://deno.land/std/testing/asserts.ts' import cliui from '../../deno.ts' Deno.test("wraps text at 'width' if a single column is given", () => { const ui = cliui({ width: 10 }) ui.div('i am a string that should be wrapped') ui.toString().split('\n').forEach((row: string) => { assert(row.length <= 10) }) }) Deno.test('evenly divides text across columns if multiple columns are given', () => { const ui = cliui({ width: 40 }) ui.div( { text: 'i am a string that should be wrapped', width: 15 }, 'i am a second string that should be wrapped', 'i am a third string that should be wrapped' ) // total width of all columns is <= // the width cliui is initialized with. ui.toString().split('\n').forEach((row: string) => { assert(row.length <= 40) }) // it should wrap each column appropriately. // TODO: we should flesh out the Deno and ESM implementation // such that it spreads words out over multiple columns appropriately: const expected = [ 'i am a string ti am a seconi am a third', 'hat should be wd string tha string that', 'rapped t should be should be w', ' wrapped rapped' ] ui.toString().split('\n').forEach((line: string, i: number) => { assertEquals(line, expected[i]) }) }) cliui-7.0.4/test/esm/000077500000000000000000000000001375210303500143715ustar00rootroot00000000000000cliui-7.0.4/test/esm/cliui-test.mjs000066400000000000000000000025311375210303500171670ustar00rootroot00000000000000import {ok as assert, strictEqual} from 'assert' import cliui from '../../index.mjs' describe('ESM', () => { it("wraps text at 'width' if a single column is given", () => { const ui = cliui({ width: 10 }) ui.div('i am a string that should be wrapped') ui.toString().split('\n').forEach((row) => { assert(row.length <= 10) }) }) it('evenly divides text across columns if multiple columns are given', () => { const ui = cliui({ width: 40 }) ui.div( { text: 'i am a string that should be wrapped', width: 15 }, 'i am a second string that should be wrapped', 'i am a third string that should be wrapped' ) // total width of all columns is <= // the width cliui is initialized with. ui.toString().split('\n').forEach((row) => { assert(row.length <= 40) }) // it should wrap each column appropriately. // TODO: we should flesh out the Deno and ESM implementation // such that it spreads words out over multiple columns appropriately: const expected = [ 'i am a string ti am a seconi am a third', 'hat should be wd string tha string that', 'rapped t should be should be w', ' wrapped rapped' ] ui.toString().split('\n').forEach((line, i) => { strictEqual(line, expected[i]) }) }) })cliui-7.0.4/tsconfig.json000066400000000000000000000004651375210303500153420ustar00rootroot00000000000000{ "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "outDir": "build", "rootDir": ".", "sourceMap": false, "target": "es2017", "moduleResolution": "node", "module": "es2015" }, "include": [ "lib/**/*.ts" ], "exclude": [ "lib/cjs.ts" ] }cliui-7.0.4/tsconfig.test.json000066400000000000000000000001241375210303500163100ustar00rootroot00000000000000{ "extends": "./tsconfig.json", "compilerOptions": { "sourceMap": true } }