From 0bdb32db76a7009ce863e365ca61c385c115a069 Mon Sep 17 00:00:00 2001 From: khai96_ Date: Wed, 31 Jan 2024 20:19:03 +0700 Subject: [PATCH] fix: typings --- lib/filename.js | 6 ++-- lib/index.js | 50 ++++++++++++++++----------------- lib/installer.js | 4 ++- lib/prompt.js | 3 ++ test/fixtures/tabtab-install.js | 3 +- test/installer.js | 5 ++-- test/log.js | 1 + test/tabtab-install.js | 8 ++++-- test/utils/index.js | 9 +++--- 9 files changed, 50 insertions(+), 39 deletions(-) diff --git a/lib/filename.js b/lib/filename.js index 91d18cc..7bfeaca 100644 --- a/lib/filename.js +++ b/lib/filename.js @@ -5,7 +5,7 @@ const { COMPLETION_FILE_EXT } = require('./constants'); * @param {String} shell * @returns {String} */ -const templateFileName = (shell = systemShell()) => { +const templateFileName = shell => { const ext = COMPLETION_FILE_EXT[shell]; if (!ext) { throw new Error(`Unsupported shell: ${shell}`); @@ -19,7 +19,7 @@ const templateFileName = (shell = systemShell()) => { * @param {String} shell * @returns {String} */ -const completionFileName = (name, shell = systemShell()) => { +const completionFileName = (name, shell) => { const ext = COMPLETION_FILE_EXT[shell]; if (!ext) { throw new Error(`Unsupported shell: ${shell}`); @@ -32,7 +32,7 @@ const completionFileName = (name, shell = systemShell()) => { * @param {String} shell * @returns {String} */ -const tabtabFileName = (shell = systemShell()) => { +const tabtabFileName = shell => { const ext = COMPLETION_FILE_EXT[shell]; if (!ext) { throw new Error(`Unsupported shell: ${shell}`); diff --git a/lib/index.js b/lib/index.js index d351ce3..03b8f84 100644 --- a/lib/index.js +++ b/lib/index.js @@ -13,7 +13,7 @@ const debug = tabtabDebug('tabtab'); * @param {String} options.name - The package configured for completion * @param {String} options.completer - The program the will act as the completer for the `name` program * @param {String} options.shell - * @returns {String} + * @returns {Promise.} */ const getCompletionScript = async ({ name, completer, shell }) => { if (!name) throw new TypeError('options.name is required'); @@ -29,10 +29,12 @@ const getCompletionScript = async ({ name, completer, shell }) => { * - SHELL (bash, zsh or fish) * - Path to shell script (with sensible defaults) * - * @param {Object} Options to use with namely `name` and `completer` - * + * @param {Object} options to use with namely `name` and `completer` + * @param {String} options.name + * @param {String} options.completer + * @param {String} options.shell */ -const install = async (options = { name: '', completer: '' }) => { +const install = async (options) => { const { name, completer } = options; if (!name) throw new TypeError('options.name is required'); if (!completer) throw new TypeError('options.completer is required'); @@ -142,21 +144,23 @@ const parseEnv = env => { }; }; +/** + * @typedef {Object} CompletionItem + * @property {String} name + * @property {String} [description] + */ + /** * Helper to normalize String and Objects with { name, description } when logging out. * - * @param {String|Object} item - Item to normalize + * @param {String|CompletionItem} item - Item to normalize + * @param {String} shell + * @returns {CompletionItem} normalized items */ -const completionItem = item => { +const completionItem = (item, shell) => { debug('completion item', item); - if (item.name || item.description) { - return { - name: item.name, - description: item.description || '' - }; - } - const shell = systemShell(); + if (typeof item === 'object') return item let name = item; let description = ''; @@ -175,12 +179,6 @@ const completionItem = item => { }; }; -/** - * @typedef {Object} CompletionItem - * @property {String} name - * @property {String} description - */ - /** * Main logging utility to pass completion items. * @@ -190,7 +188,7 @@ const completionItem = item => { * Bash needs in addition to filter out the args for the completion to work * (zsh, fish don't need this). * - * @param {Array.} args to log, Strings or Objects with name and + * @param {Array.} args to log, Strings or Objects with name and * description property. * @param {String} shell */ @@ -200,12 +198,12 @@ const log = (args, shell = systemShell()) => { } // Normalize arguments if there are some Objects { name, description } in them. - args = args.map(completionItem).map(item => { + let lines = args.map(item => completionItem(item, shell)).map(item => { const { name: rawName, description: rawDescription } = item; - const name = shell === 'zsh' ? rawName.replace(/:/g, '\\:') : rawName; + const name = shell === 'zsh' ? rawName?.replace(/:/g, '\\:') : rawName; const description = - shell === 'zsh' ? rawDescription.replace(/:/g, '\\:') : rawDescription; + shell === 'zsh' ? rawDescription?.replace(/:/g, '\\:') : rawDescription; let str = name; if (shell === 'zsh' && description) { @@ -219,11 +217,11 @@ const log = (args, shell = systemShell()) => { if (shell === 'bash') { const env = parseEnv(process.env); - args = args.filter(arg => arg.indexOf(env.last) === 0); + lines = lines.filter(arg => arg.indexOf(env.last) === 0); } - for (const arg of args) { - console.log(`${arg}`); + for (const line of lines) { + console.log(`${line}`); } }; diff --git a/lib/installer.js b/lib/installer.js index e26400c..0d3ccdc 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -109,11 +109,12 @@ const checkFilenameForLine = async (filename, line) => { filecontent = await readFile(untildify(filename), 'utf8'); } catch (err) { if (err.code !== 'ENOENT') { - return console.error( + console.error( 'Got an error while trying to read from %s file', filename, err ); + return false; } } @@ -128,6 +129,7 @@ const checkFilenameForLine = async (filename, line) => { * @param {String} options.filename - The file to modify. * @param {String} options.scriptname - The line to add sourcing this file. * @param {String} options.name - The package being configured. + * @param {String} options.shell */ const writeLineToFilename = ({ filename, scriptname, name, shell }) => ( resolve, diff --git a/lib/prompt.js b/lib/prompt.js index 1a729ff..06a9063 100644 --- a/lib/prompt.js +++ b/lib/prompt.js @@ -22,6 +22,7 @@ const prompt = async () => { const finalAnswers = {}; + // @ts-ignore const { shell } = await enquirer.prompt(questions); debug('answers', shell); @@ -30,6 +31,7 @@ const prompt = async () => { Object.assign(finalAnswers, { location, shell }); + // @ts-ignore const { locationOK } = await enquirer.prompt({ type: 'confirm', name: 'locationOK', @@ -42,6 +44,7 @@ const prompt = async () => { } // otherwise, ask for specific **absolute** path + // @ts-ignore const { userLocation } = await enquirer.prompt({ name: 'userLocation', message: 'Which path then ? Must be absolute.', diff --git a/test/fixtures/tabtab-install.js b/test/fixtures/tabtab-install.js index 3cf4f33..c898336 100644 --- a/test/fixtures/tabtab-install.js +++ b/test/fixtures/tabtab-install.js @@ -3,6 +3,7 @@ const tabtab = require('../..'); (async () => { await tabtab.install({ name: 'foo', - completer: 'foo-complete' + completer: 'foo-complete', + shell: 'bash', }); })(); diff --git a/test/installer.js b/test/installer.js index 333d0d9..1766e71 100644 --- a/test/installer.js +++ b/test/installer.js @@ -9,7 +9,8 @@ const { writeToShellConfig, writeToCompletionScript } = require('../lib/installer'); -const { COMPLETION_DIR, TABTAB_SCRIPT_NAME } = require('../lib/constants'); +const { COMPLETION_DIR } = require('../lib/constants'); +const { tabtabFileName } = require('../lib/filename'); const { rejects, setupSuiteForInstall } = require('./utils'); // For node 7 / 8 @@ -63,7 +64,7 @@ describe('installer', () => { const bashDir = untildify(path.join(COMPLETION_DIR, 'bash')); await mkdir(bashDir, { recursive: true }); // Make sure __tabtab.bash starts with empty content, it'll be restored by setupSuiteForInstall - await writeFile(path.join(bashDir, `${TABTAB_SCRIPT_NAME}.bash`), ''); + await writeFile(path.join(bashDir, tabtabFileName('bash')), ''); }); it('installs the necessary line into ~/.bashrc', () => diff --git a/test/log.js b/test/log.js index 4fbeec0..532698a 100644 --- a/test/log.js +++ b/test/log.js @@ -4,6 +4,7 @@ const tabtab = require('..'); describe('tabtab.log', () => { it('tabtab.log throws an Error in case args is not an Array', () => { assert.throws(() => { + // @ts-ignore tabtab.log('foo', 'bar'); }, /^Error: log: Invalid arguments, must be an array$/); }); diff --git a/test/tabtab-install.js b/test/tabtab-install.js index 5c93935..2a9aa41 100644 --- a/test/tabtab-install.js +++ b/test/tabtab-install.js @@ -6,7 +6,8 @@ const path = require('path'); const fs = require('fs'); const { promisify } = require('util'); const tabtab = require('..'); -const { COMPLETION_DIR, TABTAB_SCRIPT_NAME } = require('../lib/constants'); +const { COMPLETION_DIR } = require('../lib/constants'); +const { tabtabFileName } = require('../lib/filename'); const { rejects, setupSuiteForInstall } = require('./utils'); const readFile = promisify(fs.readFile); @@ -26,11 +27,13 @@ describe('tabtab.install()', () => { }); it('rejects on missing options', async () => { + // @ts-ignore await assert.rejects(async () => tabtab.install(), TypeError); }); it('rejects on missing name options', async () => { await assert.rejects( + // @ts-ignore async () => tabtab.install({}), /options\.name is required/ ); @@ -38,6 +41,7 @@ describe('tabtab.install()', () => { it('rejects on missing completer options', async () => { await assert.rejects( + // @ts-ignore async () => tabtab.install({ name: 'foo' }), /options\.completer is required/ ); @@ -55,7 +59,7 @@ describe('tabtab.install()', () => { const bashDir = untildify(path.join(COMPLETION_DIR, 'bash')); await mkdir(bashDir, { recursive: true }); // Make sure __tabtab.bash starts with empty content, it'll be restored by setupSuiteForInstall - await writeFile(path.join(bashDir, `${TABTAB_SCRIPT_NAME}.bash`), ''); + await writeFile(path.join(bashDir, tabtabFileName('bash')), ''); await tabtab.install({ name: 'foo', completer: 'foo', shell: 'bash' }); diff --git a/test/utils/index.js b/test/utils/index.js index fe9149c..f9f5603 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -2,7 +2,8 @@ const fs = require('fs'); const path = require('path'); const untildify = require('untildify'); const { promisify } = require('util'); -const { COMPLETION_DIR, TABTAB_SCRIPT_NAME } = require('../../lib/constants'); +const { COMPLETION_DIR } = require('../../lib/constants'); +const { tabtabFileName } = require('../../lib/filename'); const { exists } = require('../../lib/utils'); @@ -12,7 +13,7 @@ const readFile = promisify(fs.readFile); /** * Returns both { exists, content } * - * @param {filename} filename - The file to check and read + * @param {String} filename - The file to check and read */ const readIfExists = async filename => { /* eslint-disable no-return-await */ @@ -29,7 +30,7 @@ const readIfExists = async filename => { const afterWrites = (prevBashrc, prevScript) => async () => { const bashrc = untildify('~/.bashrc'); const tabtabScript = untildify( - path.join(COMPLETION_DIR, `${TABTAB_SCRIPT_NAME}.bash`) + path.join(COMPLETION_DIR, tabtabFileName('bash')) ); await writeFile(bashrc, prevBashrc); @@ -46,7 +47,7 @@ const afterWrites = (prevBashrc, prevScript) => async () => { const setupSuiteForInstall = async (shouldUseAfter = false) => { const files = {}; const hook = shouldUseAfter ? after : afterEach; - const tabtabScript = path.join(COMPLETION_DIR, `${TABTAB_SCRIPT_NAME}.bash`); + const tabtabScript = path.join(COMPLETION_DIR, tabtabFileName('bash')); before(async () => { const { exists: bashrcExists, content: bashrcContent } = await readIfExists(