From ec60ab07e796459b2ae5bcae23cdb36d8e8efaef Mon Sep 17 00:00:00 2001 From: Simon Boudrias Date: Thu, 25 Apr 2024 16:27:56 -0400 Subject: [PATCH] Chore(all): Stricter linting rules from unicorn --- .eslintrc.json | 10 +++++++++- packages/core/src/lib/Separator.mts | 2 +- packages/core/src/lib/pagination/lines.mts | 4 ++-- packages/core/src/lib/pagination/lines.test.mts | 2 +- packages/core/src/lib/screen-manager.mts | 2 +- packages/inquirer/examples/checkbox.js | 2 +- packages/inquirer/examples/long-list.js | 4 +++- packages/inquirer/examples/pizza.js | 2 +- packages/inquirer/lib/objects/choice.js | 7 ++----- packages/inquirer/lib/objects/separator.js | 2 +- packages/inquirer/lib/prompts/base.js | 9 ++++----- packages/inquirer/lib/prompts/checkbox.js | 7 ++----- packages/inquirer/lib/prompts/editor.js | 9 ++++----- packages/inquirer/lib/prompts/expand.js | 2 +- packages/inquirer/lib/prompts/input.js | 6 +----- packages/inquirer/lib/prompts/number.js | 2 +- packages/inquirer/lib/prompts/password.js | 11 +++++------ packages/inquirer/lib/prompts/rawlist.js | 10 +++------- packages/inquirer/lib/ui/bottom-bar.js | 2 +- packages/inquirer/lib/ui/prompt.js | 6 +----- packages/inquirer/lib/utils/events.js | 2 +- packages/inquirer/lib/utils/screen-manager.js | 2 +- packages/inquirer/test/specs/prompts/input.js | 2 +- packages/inquirer/test/specs/prompts/number.test.js | 2 +- packages/rawlist/src/index.mts | 2 +- packages/testing/src/index.mts | 2 +- 26 files changed, 51 insertions(+), 62 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 52fd93e40..77b4fdf9c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -50,11 +50,19 @@ "import/order": "error", "prettier/prettier": "error", "unicorn/better-regex": "error", + "unicorn/explicit-length-check": "error", "unicorn/no-abusive-eslint-disable": "error", + "unicorn/no-new-array": "error", + "unicorn/numeric-separators-style": "error", + "unicorn/prefer-at": "error", + "unicorn/prefer-includes": "error", "unicorn/prefer-module": "error", "unicorn/prefer-node-protocol": "error", + "unicorn/prefer-number-properties": "error", "unicorn/prefer-regexp-test": "error", - "unicorn/prefer-string-replace-all": "error" + "unicorn/prefer-spread": "error", + "unicorn/prefer-string-replace-all": "error", + "unicorn/prefer-ternary": "error" }, "overrides": [ { diff --git a/packages/core/src/lib/Separator.mts b/packages/core/src/lib/Separator.mts index 2520c4d25..a885904ed 100644 --- a/packages/core/src/lib/Separator.mts +++ b/packages/core/src/lib/Separator.mts @@ -7,7 +7,7 @@ import figures from '@inquirer/figures'; */ export class Separator { - readonly separator = chalk.dim(new Array(15).join(figures.line)); + readonly separator = chalk.dim(Array.from({ length: 15 }).join(figures.line)); readonly type = 'separator'; constructor(separator?: string) { diff --git a/packages/core/src/lib/pagination/lines.mts b/packages/core/src/lib/pagination/lines.mts index 448527cbb..f72ab8d6a 100644 --- a/packages/core/src/lib/pagination/lines.mts +++ b/packages/core/src/lib/pagination/lines.mts @@ -20,7 +20,7 @@ function split(content: string, width: number) { function rotate(count: number, items: readonly T[]): readonly T[] { const max = items.length; const offset = ((count % max) + max) % max; - return items.slice(offset).concat(items.slice(0, offset)); + return [...items.slice(offset), ...items.slice(0, offset)]; } /** @@ -58,7 +58,7 @@ export function lines({ const renderItemAt = (index: number) => split(renderItem(layoutsInPage[index]!), width); // Create a blank array of lines for the page - const pageBuffer = new Array(pageSize); + const pageBuffer = Array.from({ length: pageSize }); // Render the active item to decide the position const activeItem = renderItemAt(requested).slice(0, pageSize); diff --git a/packages/core/src/lib/pagination/lines.test.mts b/packages/core/src/lib/pagination/lines.test.mts index 11bd240f9..23843f3ac 100644 --- a/packages/core/src/lib/pagination/lines.test.mts +++ b/packages/core/src/lib/pagination/lines.test.mts @@ -19,7 +19,7 @@ describe('lines(...)', () => { isActive: boolean; index: number; }): string => - new Array(itemHeight) + Array.from({ length: itemHeight }) .fill(0) .map((_, i) => { if (i === 0) { diff --git a/packages/core/src/lib/screen-manager.mts b/packages/core/src/lib/screen-manager.mts index 4a7f9b6b0..ededc3f16 100644 --- a/packages/core/src/lib/screen-manager.mts +++ b/packages/core/src/lib/screen-manager.mts @@ -30,7 +30,7 @@ export default class ScreenManager { // rl.line (mainly because of the password prompt), so just rely on it's // length. let prompt = rawPromptLine; - if (this.rl.line.length) { + if (this.rl.line.length > 0) { prompt = prompt.slice(0, -this.rl.line.length); } diff --git a/packages/inquirer/examples/checkbox.js b/packages/inquirer/examples/checkbox.js index 4af267fdf..0953f4fca 100644 --- a/packages/inquirer/examples/checkbox.js +++ b/packages/inquirer/examples/checkbox.js @@ -55,7 +55,7 @@ inquirer }, ], validate(answer) { - if (answer.length < 1) { + if (answer.length === 0) { return 'You must choose at least one topping.'; } diff --git a/packages/inquirer/examples/long-list.js b/packages/inquirer/examples/long-list.js index 392c6e5e7..ff92cc0c6 100644 --- a/packages/inquirer/examples/long-list.js +++ b/packages/inquirer/examples/long-list.js @@ -4,7 +4,9 @@ import inquirer from '../lib/inquirer.js'; -const choices = Array.apply(0, new Array(26)).map((x, y) => String.fromCharCode(y + 65)); +const choices = Array.apply(0, Array.from({ length: 26 })).map((x, y) => + String.fromCharCode(y + 65), +); choices.push('Multiline option 1\n super cool feature \n more lines'); choices.push('Multiline option 2\n super cool feature \n more lines'); choices.push('Multiline option 3\n super cool feature \n more lines'); diff --git a/packages/inquirer/examples/pizza.js b/packages/inquirer/examples/pizza.js index 80365402b..780764e7f 100644 --- a/packages/inquirer/examples/pizza.js +++ b/packages/inquirer/examples/pizza.js @@ -44,7 +44,7 @@ const questions = [ name: 'quantity', message: 'How many do you need?', validate(value) { - const valid = !isNaN(parseFloat(value)); + const valid = !Number.isNaN(Number.parseFloat(value)); return valid || 'Please enter a number'; }, filter: Number, diff --git a/packages/inquirer/lib/objects/choice.js b/packages/inquirer/lib/objects/choice.js index f2e540800..f4ecb196f 100644 --- a/packages/inquirer/lib/objects/choice.js +++ b/packages/inquirer/lib/objects/choice.js @@ -26,10 +26,7 @@ export default class Choice { }); } - if (typeof val.disabled === 'function') { - this.disabled = val.disabled(answers); - } else { - this.disabled = val.disabled; - } + this.disabled = + typeof val.disabled === 'function' ? val.disabled(answers) : val.disabled; } } diff --git a/packages/inquirer/lib/objects/separator.js b/packages/inquirer/lib/objects/separator.js index 856be3016..add6eb8f9 100644 --- a/packages/inquirer/lib/objects/separator.js +++ b/packages/inquirer/lib/objects/separator.js @@ -11,7 +11,7 @@ import figures from '@inquirer/figures'; export default class Separator { constructor(line) { this.type = 'separator'; - this.line = chalk.dim(line || new Array(15).join(figures.line)); + this.line = chalk.dim(line || Array.from({ length: 15 }).join(figures.line)); } /** diff --git a/packages/inquirer/lib/prompts/base.js b/packages/inquirer/lib/prompts/base.js index 2716e96bb..19dada43f 100644 --- a/packages/inquirer/lib/prompts/base.js +++ b/packages/inquirer/lib/prompts/base.js @@ -166,11 +166,10 @@ export default class Prompt { this.status !== 'answered' ) { // If default password is supplied, hide it - if (this.opt.type === 'password') { - message += chalk.italic.dim('[hidden] '); - } else { - message += chalk.dim('(' + this.opt.default + ') '); - } + message += + this.opt.type === 'password' + ? chalk.italic.dim('[hidden] ') + : chalk.dim('(' + this.opt.default + ') '); } return message; diff --git a/packages/inquirer/lib/prompts/checkbox.js b/packages/inquirer/lib/prompts/checkbox.js index 85e36473f..bf292c6a0 100644 --- a/packages/inquirer/lib/prompts/checkbox.js +++ b/packages/inquirer/lib/prompts/checkbox.js @@ -248,11 +248,8 @@ function renderChoices(choices, pointer) { })`; } else { const line = getCheckbox(choice.checked) + ' ' + choice.name; - if (i - separatorOffset === pointer) { - output += chalk.cyan(figures.pointer + line); - } else { - output += ' ' + line; - } + output += + i - separatorOffset === pointer ? chalk.cyan(figures.pointer + line) : ' ' + line; } output += '\n'; diff --git a/packages/inquirer/lib/prompts/editor.js b/packages/inquirer/lib/prompts/editor.js index 88a3769b0..5276de2b1 100644 --- a/packages/inquirer/lib/prompts/editor.js +++ b/packages/inquirer/lib/prompts/editor.js @@ -54,11 +54,10 @@ export default class EditorPrompt extends Base { let bottomContent = ''; let message = this.getQuestion(); - if (this.status === 'answered') { - message += chalk.dim('Received'); - } else { - message += chalk.dim('Press to launch your preferred editor.'); - } + message += + this.status === 'answered' + ? chalk.dim('Received') + : chalk.dim('Press to launch your preferred editor.'); if (error) { bottomContent = chalk.red('>> ') + error; diff --git a/packages/inquirer/lib/prompts/expand.js b/packages/inquirer/lib/prompts/expand.js index 4a5e7f3a4..a85593b1b 100644 --- a/packages/inquirer/lib/prompts/expand.js +++ b/packages/inquirer/lib/prompts/expand.js @@ -209,7 +209,7 @@ export default class ExpandPrompt extends Base { ); } - if (errors.length) { + if (errors.length > 0) { throw new Error( 'Duplicate key error: `key` param must be unique. Duplicates: ' + [...new Set(errors)].join(','), diff --git a/packages/inquirer/lib/prompts/input.js b/packages/inquirer/lib/prompts/input.js index f25be3335..890d6fa24 100644 --- a/packages/inquirer/lib/prompts/input.js +++ b/packages/inquirer/lib/prompts/input.js @@ -47,11 +47,7 @@ export default class InputPrompt extends Base { const { transformer } = this.opt; const isFinal = this.status === 'answered'; - if (isFinal) { - appendContent = this.answer; - } else { - appendContent = this.rl.line; - } + appendContent = isFinal ? this.answer : this.rl.line; if (transformer) { message += transformer(appendContent, this.answers, { isFinal }); diff --git a/packages/inquirer/lib/prompts/number.js b/packages/inquirer/lib/prompts/number.js index 2e7104261..34c934d80 100644 --- a/packages/inquirer/lib/prompts/number.js +++ b/packages/inquirer/lib/prompts/number.js @@ -21,6 +21,6 @@ export default class NumberPrompt extends Input { } // If the input was invalid return the default value. - return this.opt.default == null ? NaN : this.opt.default; + return this.opt.default == null ? Number.NaN : this.opt.default; } } diff --git a/packages/inquirer/lib/prompts/password.js b/packages/inquirer/lib/prompts/password.js index cfcad80af..39f1aa421 100644 --- a/packages/inquirer/lib/prompts/password.js +++ b/packages/inquirer/lib/prompts/password.js @@ -14,7 +14,7 @@ function mask(input, maskChar) { return ''; } - return new Array(input.length + 1).join(maskChar); + return Array.from({ length: input.length + 1 }).join(maskChar); } export default class PasswordPrompt extends Base { @@ -55,11 +55,10 @@ export default class PasswordPrompt extends Base { let message = this.getQuestion(); let bottomContent = ''; - if (this.status === 'answered') { - message += this.getMaskedValue(this.answer); - } else { - message += this.getMaskedValue(this.rl.line || ''); - } + message += + this.status === 'answered' + ? this.getMaskedValue(this.answer) + : this.getMaskedValue(this.rl.line || ''); if (error) { bottomContent = '\n' + chalk.red('>> ') + error; diff --git a/packages/inquirer/lib/prompts/rawlist.js b/packages/inquirer/lib/prompts/rawlist.js index dbd705dda..be66d1c9f 100644 --- a/packages/inquirer/lib/prompts/rawlist.js +++ b/packages/inquirer/lib/prompts/rawlist.js @@ -150,17 +150,13 @@ export default class RawListPrompt extends Base { let index; if (this.lastKey === 'arrow') { - index = this.hiddenLine.length ? Number(this.hiddenLine) - 1 : 0; + index = this.hiddenLine.length > 0 ? Number(this.hiddenLine) - 1 : 0; } else { - index = this.rl.line.length ? Number(this.rl.line) - 1 : 0; + index = this.rl.line.length > 0 ? Number(this.rl.line) - 1 : 0; } this.lastKey = ''; - if (this.opt.choices.getChoice(index)) { - this.selected = index; - } else { - this.selected = undefined; - } + this.selected = this.opt.choices.getChoice(index) ? index : undefined; this.render(); } diff --git a/packages/inquirer/lib/ui/bottom-bar.js b/packages/inquirer/lib/ui/bottom-bar.js index de5e9c652..a6286c2d0 100644 --- a/packages/inquirer/lib/ui/bottom-bar.js +++ b/packages/inquirer/lib/ui/bottom-bar.js @@ -80,7 +80,7 @@ export default class BottomBar extends Base { this.height = msgLines.length; // Write message to screen and setPrompt to control backspace - this.rl.setPrompt(msgLines[msgLines.length - 1]); + this.rl.setPrompt(msgLines.at(-1)); if (this.rl.output.rows === 0 && this.rl.output.columns === 0) { /* When it's a tty through serial port there's no terminal info and the render will malfunction, diff --git a/packages/inquirer/lib/ui/prompt.js b/packages/inquirer/lib/ui/prompt.js index 7db4385f1..13b838908 100644 --- a/packages/inquirer/lib/ui/prompt.js +++ b/packages/inquirer/lib/ui/prompt.js @@ -23,11 +23,7 @@ export default class PromptUI extends Base { run(questions, answers) { // Keep global reference to the answers - if (_.isPlainObject(answers)) { - this.answers = { ...answers }; - } else { - this.answers = {}; - } + this.answers = _.isPlainObject(answers) ? { ...answers } : {}; // Make sure questions is an array. if (_.isPlainObject(questions)) { diff --git a/packages/inquirer/lib/utils/events.js b/packages/inquirer/lib/utils/events.js index c75cea97c..36b69b0d0 100644 --- a/packages/inquirer/lib/utils/events.js +++ b/packages/inquirer/lib/utils/events.js @@ -31,7 +31,7 @@ export default function (rl) { ), numberKey: keypress.pipe( - filter((e) => e.value && '123456789'.indexOf(e.value) >= 0), + filter((e) => e.value && '123456789'.includes(e.value)), map((e) => Number(e.value)), share(), ), diff --git a/packages/inquirer/lib/utils/screen-manager.js b/packages/inquirer/lib/utils/screen-manager.js index ae8cd358e..ad11b2138 100644 --- a/packages/inquirer/lib/utils/screen-manager.js +++ b/packages/inquirer/lib/utils/screen-manager.js @@ -67,7 +67,7 @@ export default class ScreenManager { // rl.line (mainly because of the password prompt), so just rely on it's // length. let prompt = rawPromptLine; - if (this.rl.line.length) { + if (this.rl.line.length > 0) { prompt = prompt.slice(0, -this.rl.line.length); } diff --git a/packages/inquirer/test/specs/prompts/input.js b/packages/inquirer/test/specs/prompts/input.js index 1dff6d2ae..a3b9cf5c1 100644 --- a/packages/inquirer/test/specs/prompts/input.js +++ b/packages/inquirer/test/specs/prompts/input.js @@ -36,7 +36,7 @@ describe('`input` prompt', () => { it('should apply the provided transform to the value', function (done) { this.fixture.transformer = function (value) { - return value.split('').reverse().join(''); + return [...value].reverse().join(''); }; const prompt = new Input(this.fixture, this.rl); diff --git a/packages/inquirer/test/specs/prompts/number.test.js b/packages/inquirer/test/specs/prompts/number.test.js index cf7646eed..5d67f6354 100644 --- a/packages/inquirer/test/specs/prompts/number.test.js +++ b/packages/inquirer/test/specs/prompts/number.test.js @@ -80,7 +80,7 @@ describe('`number` prompt', () => { it('should parse a float with no digits before the decimal', () => new Promise((done) => { number.run().then((answer) => { - expect(answer).toBeCloseTo(0.01264, ACCEPTABLE_ERROR); + expect(answer).toBeCloseTo(0.012_64, ACCEPTABLE_ERROR); done(); }); diff --git a/packages/rawlist/src/index.mts b/packages/rawlist/src/index.mts index c9304dab4..520ae23d5 100644 --- a/packages/rawlist/src/index.mts +++ b/packages/rawlist/src/index.mts @@ -44,7 +44,7 @@ export default createPrompt( if (isEnterKey(key)) { let selectedChoice; if (numberRegex.test(value)) { - const answer = parseInt(value, 10) - 1; + const answer = Number.parseInt(value, 10) - 1; selectedChoice = choices.filter(isSelectableChoice)[answer]; } else { const answer = value.toLowerCase(); diff --git a/packages/testing/src/index.mts b/packages/testing/src/index.mts index 961f6999a..888d792ab 100644 --- a/packages/testing/src/index.mts +++ b/packages/testing/src/index.mts @@ -33,7 +33,7 @@ class BufferedStream extends Stream.Writable { getLastChunk({ raw }: { raw?: boolean }): string { const chunks = raw ? this.#_rawChunks : this.#_chunks; - const lastChunk = chunks[chunks.length - 1]; + const lastChunk = chunks.at(-1); return lastChunk ?? ''; }