Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
![Build](https://img.shields.io/github/actions/workflow/status/LexBorisoff/package-scripts/release.yml)
![NPM Version](https://img.shields.io/npm/v/package-scripts)

CLI to interactively select and run package scripts using any package manager.
CLI to interactively select and run package scripts using a package manager of your choice.

- [Installation](#installation)
- [Usage](#usage)
Expand Down Expand Up @@ -114,7 +114,7 @@ There are cases when the CLI will run a matched script without displaying the se
- When a single argument is provided that matches a script **_exactly_** even if there are other scripts containing that argument in their names.
- When a single script is matched based on the provided arguments.

> 💡 The `--select` option can override this behavior and force the display of the selection menu.
> 💡 The `--interactive` option can override this behavior and show the interactive selection menu.

For example:

Expand Down
71 changes: 41 additions & 30 deletions src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,25 @@ enum Option {
Pnpm = 'pnpm',
Yarn = 'yarn',
Bun = 'bun',
Select = 'select',
Interactive = 'interactive',
First = 'first',
Default = 'default',
Which = 'which',
Rename = 'rename',
}

function noConflict(itself: Option, ...other: Option[]): Option[] {
const alias: Partial<Record<Option, string | readonly string[]>> = {
[Option.Npm]: 'n',
[Option.Pnpm]: 'p',
[Option.Yarn]: 'y',
[Option.Bun]: 'b',
[Option.Interactive]: 'i',
[Option.First]: 'f',
[Option.Default]: 'd',
[Option.Which]: 'w',
};

function noConflictWith(itself: Option, ...other: Option[]): Option[] {
return Object.values(Option).filter(
(option) => option !== itself && !other.includes(option),
);
Expand All @@ -38,67 +49,67 @@ const parsed = yargs(hideBin(process.argv))
.scriptName(getConfigData().command)
.usage(`Usage: $0 [ARG...] [OPTION...]`)
.usage(`Interactively select and run scripts using any package manager`)
.option('npm', {
.option(Option.Npm, {
type: 'boolean',
description: desc.runWith('npm'),
alias: 'n',
alias: alias[Option.Npm],
group: group.script,
conflicts: noConflict(Option.Npm, Option.Select),
conflicts: noConflictWith(Option.Npm, Option.Interactive),
})
.option('pnpm', {
.option(Option.Pnpm, {
type: 'boolean',
description: desc.runWith('pnpm'),
alias: 'p',
alias: alias[Option.Pnpm],
group: group.script,
conflicts: noConflict(Option.Pnpm, Option.Select),
conflicts: noConflictWith(Option.Pnpm, Option.Interactive),
})
.option('yarn', {
.option(Option.Yarn, {
type: 'boolean',
description: desc.runWith('yarn'),
group: group.script,
alias: 'y',
conflicts: noConflict(Option.Yarn, Option.Select),
alias: alias[Option.Yarn],
conflicts: noConflictWith(Option.Yarn, Option.Interactive),
})
.option('bun', {
.option(Option.Bun, {
type: 'boolean',
description: desc.runWith('bun'),
group: group.script,
alias: 'b',
conflicts: noConflict(Option.Bun, Option.Select),
alias: alias[Option.Bun],
conflicts: noConflictWith(Option.Bun, Option.Interactive),
})
.option('select', {
.option(Option.Interactive, {
type: 'boolean',
description: 'Prompt selection if a single script is matched',
alias: 's',
description: 'Interactive script selection',
alias: alias[Option.Interactive],
group: group.script,
conflicts: ['first', 'default', 'which'],
conflicts: [Option.First, Option.Default, Option.Which],
})
.option('first', {
.option(Option.First, {
type: 'boolean',
description: 'Pick the first matched script without prompt',
alias: 'f',
description: 'Run the first matched script',
alias: alias[Option.First],
group: group.script,
conflicts: ['select', 'default', 'which'],
conflicts: [Option.Interactive, Option.Default, Option.Which],
})
.option('default', {
.option(Option.Default, {
type: 'string',
description: 'Set the default package manager',
alias: 'd',
alias: alias[Option.Default],
group: group.packageManager,
conflicts: noConflict(Option.Default),
conflicts: noConflictWith(Option.Default),
})
.option('which', {
.option(Option.Which, {
type: 'boolean',
description: 'Show which package which is currently used',
alias: 'w',
alias: alias[Option.Which],
group: group.packageManager,
conflicts: noConflict(Option.Which),
conflicts: noConflictWith(Option.Which),
})
.option('rename', {
.option(Option.Rename, {
type: 'string',
description: 'Rename the command',
group: group.config,
conflicts: noConflict(Option.Rename),
conflicts: noConflictWith(Option.Rename),
})
.help()
.version(PACKAGE_VERSION)
Expand Down
4 changes: 2 additions & 2 deletions src/select-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getArgs } from './utils/get-args.js';
import { getPackageJson } from './utils/get-package-json.js';
import { logger } from './utils/logger.js';

const { first, select } = args;
const { first, interactive } = args;
const { commandArgs: _ } = getArgs();

function getMatchFn(script: string) {
Expand Down Expand Up @@ -64,7 +64,7 @@ export async function selectScript(): Promise<string | undefined> {
return matchedScripts.at(0)?.value;
}

if (!select) {
if (!interactive) {
// find an exact script name match
if (_.length === 1) {
const [matchValue] = _;
Expand Down