diff --git a/src/bin/help.ts b/src/bin/help.ts new file mode 100644 index 00000000..c90e4b27 --- /dev/null +++ b/src/bin/help.ts @@ -0,0 +1,103 @@ +import { format } from '../services/format.js'; +import { Write } from '../services/write.js'; + +const b = (text: string) => `${format(text).bold()}`; +const i = (text: string) => `${format(text).italic()}`; +const u = (text: string) => `${format(text).underline()}`; +const d = (text: string) => `${format(text).dim()}`; + +const options = i('[--options]'); +const option = i('[--option]'); +const paths = i('[paths]'); +const path = i('[path]'); +const bullet = d('●'); +const summary: [string, string][] = [ + ['--bun', 'Enforce tests to run through Bun.'], + ['--concurrency', 'Limit the number of tests running concurrently.'], + ['--config, -c', 'Specify a configuration file.'], + ['--debug, -d', 'Show detailed logs.'], + ['--deno', 'Enforce tests to run through Deno.'], + ['--denoAllow', 'Allow permissions for Deno.'], + ['--denoCjs', 'Support CommonJS in Deno.'], + ['--denoDeny', 'Deny permissions for Deno.'], + ['--enforce, -x', 'Validate options before running tests.'], + ['--envFile', 'Read and set an environment file.'], + ['--exclude', 'Exclude by path using Regex to match files.'], + ['--failFast', 'Stop tests at the first failure.'], + ['--filter', 'Filter by path using Regex to match files.'], + ['--help, -h', "Show Poku's CLI basic usage."], + ['--killPid', 'Terminate the specified processes.'], + ['--killPort', 'Terminate the specified ports.'], + ['--killRange', 'Terminate the specified port ranges.'], + ['--listFiles', 'Display all the files returned in the terminal.'], + ['--node', 'Enforce tests to run through Node.js.'], + ['--parallel, -p', 'Run tests files in parallel.'], + ['--platform', 'Enforce tests to run through a platform.'], + ['--quiet, -q', 'Run tests with no logs.'], + ['--version, -v', "Show Poku's installed version."], + ['--watch, -w', 'Watch for test events.'], + ['--watchInterval', 'Set an interval for watch events.'], +]; +const sortedSummary = summary.sort(([a], [b]) => a.localeCompare(b)); +const largeEndPad = (() => + Math.max(...summary.map(([start]) => start.length)))(); + +const header = ` +🐷 ${format(' Poku — CLI Usage ').bg('brightMagenta')} + +› ${u(b('Usage:'))} + + poku ${options} ${paths} + poku ${paths} ${options} + poku ${option} ${path} ${option} ${path} + +› ${u(b('Ensuring platforms:'))} + + poku ${b('--node')} ${options} ${paths} + poku ${b('--bun')} ${options} ${paths} + poku ${b('--deno')} ${options} ${paths} + +› ${u(b('Tips:'))} + + ${bullet} All CLI options use camel case pattern (e.g.: ${b('--failFast')}). + ${bullet} Use ${b('=')} to set an option value (e.g.: ${b('--concurrency=4')}). + ${bullet} If you're seeing this, ${u('feel special')} ✨ +`; + +const main = ` +🐽 ${format(' Poku — Options ').bg('brightMagenta')} + +› ${u(b('Summary:'))} + +${sortedSummary + .map( + ([command, description]) => + `${command.padEnd(largeEndPad)} ${d(description)}` + ) + .join('\n')} + +› ${u(b('Notes:'))} + + ${bullet} For Glob support, see: + ${u('https://poku.io/docs/documentation/poku/include-files#by-extending-glob-patterns-from-shell')} + + ${bullet} Avoid conflicts for environments with multiple platforms: + ${u('https://poku.io/docs/tutorials/cross-platform')} +`; + +const footer = ` +${b('Documentation:')} ${u('https://poku.io')} + +${bullet} ${b('Poku')} is made with ${b('love')} and ${b('care')} in every detail. +${bullet} Give him a ${b('star')} to show your support 🌟 +`; + +export const help = () => { + Write.hr(); + Write.log(header.trim()); + Write.hr(); + Write.log(main.trim()); + Write.hr(); + Write.log(footer.trim()); + Write.hr(); +}; diff --git a/src/bin/index.ts b/src/bin/index.ts index 184ec101..42257581 100644 --- a/src/bin/index.ts +++ b/src/bin/index.ts @@ -20,6 +20,14 @@ import { getConfigs } from '../parsers/options.js'; return; } + if (hasArg('help') || hasArg('h', '-')) { + const { help } = require('./help.js'); + + help(); + + return; + } + const enforce = hasArg('enforce') || hasArg('x', '-'); const configFile = getArg('config') || getArg('c', '-'); const defaultConfigs = await getConfigs(configFile); diff --git a/test/e2e/help.test.ts b/test/e2e/help.test.ts new file mode 100644 index 00000000..6bf5d2e7 --- /dev/null +++ b/test/e2e/help.test.ts @@ -0,0 +1,40 @@ +import { describe } from '../../src/modules/helpers/describe.js'; +import { it } from '../../src/modules/helpers/it/core.js'; +import { skip } from '../../src/modules/helpers/skip.js'; +import { assert } from '../../src/modules/essentials/assert.js'; +import { inspectPoku, isBuild } from '../__utils__/capture-cli.test.js'; +import { getRuntime } from '../../src/parsers/get-runtime.js'; + +const runtime = getRuntime(); + +if (isBuild || runtime === 'deno') skip(); + +describe('Help', async () => { + await it('--help', async () => { + const results = await inspectPoku('--help'); + + if (results.exitCode !== 0) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 0); + assert.match(results.stdout, /Poku — CLI Usage/); + assert.match(results.stdout, /Poku — Options/); + assert.match(results.stdout, /https:\/\/poku.io/); + }); + + await it('-h', async () => { + const results = await inspectPoku('-h'); + + if (results.exitCode !== 0) { + console.log(results.stdout); + console.log(results.stderr); + } + + assert.strictEqual(results.exitCode, 0); + assert.match(results.stdout, /Poku — CLI Usage/); + assert.match(results.stdout, /Poku — Options/); + assert.match(results.stdout, /https:\/\/poku.io/); + }); +});