Skip to content

Commit

Permalink
feat(cli): support camelCase flags (deprecate kebab-case flags) (#688)
Browse files Browse the repository at this point in the history
* feat: support camel case flags

* ci: add E2E tests

* ci: fix build tests

* ci: fix Bun tests

* ci: add unit tests

* chore: remove all kebab options

* chore: remove all kebab options

* docs: update docs to camel case flags
  • Loading branch information
wellwelwel authored Aug 19, 2024
1 parent 85b6b3b commit 203fb45
Show file tree
Hide file tree
Showing 28 changed files with 300 additions and 86 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
"test:parallel": "tsx src/bin/index.ts -p test/unit test/integration test/e2e",
"test:bun:sequential": "bun src/bin/index.ts --bun test/unit test/integration test/e2e",
"test:bun:parallel": "bun src/bin/index.ts --bun -p test/unit test/integration test/e2e",
"test:deno:sequential": "tsx src/bin/index.ts --deno --deno-allow=all test/unit test/integration test/e2e",
"test:deno:parallel": "tsx src/bin/index.ts --deno --deno-allow=all -p test/unit test/integration test/e2e",
"test:deno:sequential": "tsx src/bin/index.ts --deno --denoAllow=all test/unit test/integration test/e2e",
"test:deno:parallel": "tsx src/bin/index.ts --deno --denoAllow=all -p test/unit test/integration test/e2e",
"pretest:c8": "tsx tools/build/c8-file.ts",
"test:c8": "c8 --experimental-monocart tsx test/c8.test.ts",
"posttest:c8": "rm -rf ./.nycrc.json",
Expand Down
22 changes: 11 additions & 11 deletions src/bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,27 @@ import { getConfigs } from '../parsers/options.js';
const platform = getArg('platform');
const filter = getArg('filter') ?? defaultConfigs?.filter;
const exclude = getArg('exclude') ?? defaultConfigs?.exclude;
const killPort = getArg('kill-port');
const killRange = getArg('kill-range');
const killPID = getArg('kill-pid');
const killPort = getArg('killport');
const killRange = getArg('killrange');
const killPID = getArg('killpid');
/* c8 ignore start */ // Deno
const denoAllow = argToArray('deno-allow') ?? defaultConfigs?.deno?.allow;
const denoDeny = argToArray('deno-deny') ?? defaultConfigs?.deno?.deny;
const denoAllow = argToArray('denoallow') ?? defaultConfigs?.deno?.allow;
const denoDeny = argToArray('denodeny') ?? defaultConfigs?.deno?.deny;
const denoCJS =
getArg('deno-cjs')
getArg('denocjs')
?.split(',')
.map((a) => a.trim())
.filter((a) => a) ||
hasArg('deno-cjs') ||
hasArg('denocjs') ||
defaultConfigs?.deno?.cjs;
/* c8 ignore stop */
const parallel =
hasArg('parallel') || hasArg('p', '-') || defaultConfigs?.parallel;
const quiet = hasArg('quiet') || hasArg('q', '-') || defaultConfigs?.quiet;
const debug = hasArg('debug') || hasArg('d', '-') || defaultConfigs?.debug;
const failFast = hasArg('fail-fast') || defaultConfigs?.failFast;
const failFast = hasArg('failfast') || defaultConfigs?.failFast;
const watchMode = hasArg('watch') || hasArg('w', '-');
const hasEnvFile = hasArg('env-file');
const hasEnvFile = hasArg('envfile');
const concurrency = (() => {
if (!(parallel || defaultConfigs?.parallel)) {
return undefined;
Expand All @@ -74,7 +74,7 @@ import { getConfigs } from '../parsers/options.js';
states.isSinglePath = true;
}

if (hasArg('list-files')) {
if (hasArg('listfiles')) {
const { listFiles } = require('../modules/helpers/list-files.js');

const files: string[] = [];
Expand Down Expand Up @@ -141,7 +141,7 @@ import { getConfigs } from '../parsers/options.js';
/* c8 ignore stop */

if (hasEnvFile || defaultConfigs?.envFile) {
const envFilePath = getArg('env-file') ?? defaultConfigs?.envFile;
const envFilePath = getArg('envfile') ?? defaultConfigs?.envFile;

tasks.push(envFile(envFilePath));
}
Expand Down
2 changes: 1 addition & 1 deletion src/bin/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const startWatch = async (dirs: string[], options: Configs) => {

const watchers: Set<Watcher> = new Set();
const executing = new Set<string>();
const interval = Number(getArg('watch-interval')) || 1500;
const interval = Number(getArg('watchinterval')) || 1500;

const setIsRunning = (value: boolean) => {
isRunning = value;
Expand Down
11 changes: 7 additions & 4 deletions src/parsers/get-arg.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { argv } from 'node:process';
import { toDynamicCase } from './to-dynamic-case.js';

const [, , ...processArgs] = argv;
const regexQuotes = /''|""/;

const processedArgs = processArgs.map(toDynamicCase);

export const getArg = (
arg: string,
prefix = '--',
baseArgs = processArgs
baseArgs = processedArgs
): string | undefined => {
const argPattern = `${prefix}${arg}=`;
const argValue = baseArgs.find((a) => a.startsWith(argPattern));
Expand All @@ -21,7 +24,7 @@ export const getArg = (
export const hasArg = (
arg: string,
prefix = '--',
baseArgs = processArgs
baseArgs = processedArgs
): boolean => {
const argPattern = `${prefix}${arg}`;

Expand All @@ -30,7 +33,7 @@ export const hasArg = (

export const getPaths = (
prefix = '--',
baseArgs = processArgs
baseArgs = processedArgs
): string[] | undefined => {
let hasPaths = false;
const paths: string[] = [];
Expand All @@ -51,7 +54,7 @@ export const getPaths = (
export const argToArray = (
arg: string,
prefix = '--',
baseArgs = processArgs
baseArgs = processedArgs
) => {
const hasArgument = hasArg(arg, prefix, baseArgs);
if (!hasArgument) {
Expand Down
19 changes: 19 additions & 0 deletions src/parsers/to-dynamic-case.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const regex = /-/g;

export const toDynamicCase = (str: string) => {
// Short flags
if (str[1] !== '-') {
return str;
}

const [flag, ...args] = str.slice(2).split('=');
const dynamicCase = flag.toLowerCase().replace(regex, '');

let processArg = `--${dynamicCase}`;

if (args.length > 0) {
processArg += `=${args.join('=')}`;
}

return processArg;
};
4 changes: 2 additions & 2 deletions src/services/run-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const runTests = async (
if (showLogs) {
Write.hr();
Write.log(
` ${format('ℹ').fail()} ${format('fail-fast').bold()} is enabled`
` ${format('ℹ').fail()} ${format('failFast').bold()} is enabled`
);
}

Expand Down Expand Up @@ -116,7 +116,7 @@ export const runTestsParallel = async (
process.exitCode = 1;

throw new Error(
` ${format('ℹ').fail()} ${format('fail-fast').bold()} is enabled`
` ${format('ℹ').fail()} ${format('failFast').bold()} is enabled`
);
}

Expand Down
Empty file.
8 changes: 4 additions & 4 deletions test/c8.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ test(async () => {
await it('Sequential + Options (Just Touch)', async () => {
const results = await inspectPoku(
isWindows
? '--concurrency=4 --platform=node --fail-fast --debug --exclude=".bak" --kill-port=4000 --kill-range="4000-4001" test/integration/import.test.ts --filter=".test.|.spec."'
: '--concurrency=4 --platform=node --fail-fast --debug --exclude=.bak --kill-port=4000 --kill-range=4000-4001 test/integration/import.test.ts --filter=.test.|.spec.'
? '--concurrency=4 --platform=node --failFast --debug --exclude=".bak" --killPort=4000 --killRange="4000-4001" test/integration/import.test.ts --filter=".test.|.spec."'
: '--concurrency=4 --platform=node --failFast --debug --exclude=.bak --killPort=4000 --killRange=4000-4001 test/integration/import.test.ts --filter=.test.|.spec.'
);

console.log(results.stdout);
Expand All @@ -65,8 +65,8 @@ test(async () => {
await it('Parallel + Options (Just Touch)', async () => {
const results = await inspectPoku(
isWindows
? '--parallel --concurrency=4 --platform=node --fail-fast --debug --exclude=".bak" --kill-port=4000 --kill-range="4000-4001" test/integration/import.test.ts --filter=".test.|.spec."'
: '--parallel --concurrency=4 --platform=node --fail-fast --debug --exclude=.bak --kill-port=4000 --kill-range=4000-4001 test/integration/import.test.ts --filter=.test.|.spec.'
? '--parallel --concurrency=4 --platform=node --failFast --debug --exclude=".bak" --killPort=4000 --killRange="4000-4001" test/integration/import.test.ts --filter=".test.|.spec."'
: '--parallel --concurrency=4 --platform=node --failFast --debug --exclude=.bak --killPort=4000 --killRange=4000-4001 test/integration/import.test.ts --filter=.test.|.spec.'
);

console.log(results.stdout);
Expand Down
67 changes: 67 additions & 0 deletions test/e2e/cli-flags.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { describe } from '../../src/modules/helpers/describe.js';
import { it } from '../../src/modules/helpers/it/core.js';
import { assert } from '../../src/modules/essentials/assert.js';
import { inspectPoku, isBuild } from '../__utils__/capture-cli.test.js';
import { skip } from '../../src/modules/helpers/skip.js';

if (isBuild) {
skip();
}

describe('CLI Flags', async () => {
await it('Short flags', async () => {
const output = await inspectPoku('-d -p', {
cwd: 'test/__fixtures__/e2e/no-tests',
});

assert.strictEqual(output.exitCode, 0, 'Exit Code needs to be 0');
assert(
/debug(.+)?:(.+)?true/.test(output.stdout),
'CLI needs to able "debug"'
);
assert(
/parallel(.+)?:(.+)?true/.test(output.stdout),
'CLI needs to able "parallel"'
);
});

await it('Kebab flags', async () => {
const output = await inspectPoku('--debug --fail-fast --deno-cjs=js,cjs', {
cwd: 'test/__fixtures__/e2e/no-tests',
});

assert.strictEqual(output.exitCode, 0, 'Exit Code needs to be 0');
assert(
/debug(.+)?:(.+)?true/.test(output.stdout),
'CLI needs to able "debug"'
);
assert(
/failFast(.+)?:(.+)?true/.test(output.stdout),
'CLI needs to able "failFast"'
);
assert(
/cjs(.+)?:(.+)?js(.+)?cjs/.test(output.stdout),
'CLI needs to able "Deno CJS Pollyfill"'
);
});

await it('Camel flags', async () => {
const output = await inspectPoku('--debug --failFast --denoCjs=js,cjs', {
cwd: 'test/__fixtures__/e2e/no-tests',
});

assert.strictEqual(output.exitCode, 0, 'Exit Code needs to be 0');
assert(
/debug(.+)?:(.+)?true/.test(output.stdout),
'CLI needs to able "debug"'
);
assert(
/failFast(.+)?:(.+)?true/.test(output.stdout),
'CLI needs to able "failFast"'
);
assert(
/cjs(.+)?:(.+)?js(.+)?cjs/.test(output.stdout),
'CLI needs to able "Deno CJS Pollyfill"'
);
});
});
4 changes: 2 additions & 2 deletions test/e2e/env-file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ if (isBuild) {

describe('.env File', async () => {
await it('CLI Env Variables Propagation (default)', async () => {
const results = await inspectPoku('--env-file', {
const results = await inspectPoku('--envFile', {
env: {
...process.env,
MY_VAR: 'Poku',
Expand All @@ -30,7 +30,7 @@ describe('.env File', async () => {

await it('CLI Env Variables Propagation (custom)', async () => {
const results = await inspectPoku(
isWindows ? '--env-file=".env.test"' : '--env-file=.env.test',
isWindows ? '--envFile=".env.test"' : '--envFile=.env.test',
{
env: {
...process.env,
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/fail-fast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Fast Fast', async () => {
}

assert.strictEqual(results.exitCode, 1, 'Failed');
assert.match(results.stderr, /fail-fast/, 'Fail Fast is enabled');
assert.match(results.stderr, /failFast/, 'Fail Fast is enabled');
assert.match(results.stdout, /FAIL › 1/, 'Needs to fail 1');
});

Expand All @@ -36,7 +36,7 @@ describe('Fast Fast', async () => {
}

assert.strictEqual(results.exitCode, 1, 'Failed');
assert.match(results.stdout, /fail-fast/, 'Fail Fast is enabled');
assert.match(results.stdout, /failFast/, 'Fail Fast is enabled');
assert.match(results.stdout, /FAIL › 1/, 'Needs to fail 1');
});
});
2 changes: 1 addition & 1 deletion test/e2e/watch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const saveFileUnchanged = async (filename: string) => {
};

describe('Watch Mode', async () => {
const watcher = watchCLI('--watch-interval=500', {
const watcher = watchCLI('--watchInterval=500', {
cwd: 'test/__fixtures__/e2e/watch',
});

Expand Down
60 changes: 60 additions & 0 deletions test/unit/dynamic-cases.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { describe } from '../../src/modules/helpers/describe.js';
import { it } from '../../src/modules/helpers/it/core.js';
import { assert } from '../../src/modules/essentials/assert.js';
import { toDynamicCase } from '../../src/parsers/to-dynamic-case.js';

describe('Dynamic Flag Cases', () => {
it('General', () => {
assert.strictEqual(toDynamicCase('-d'), '-d', 'Short Flag (lower)');
assert.strictEqual(toDynamicCase('-D'), '-D', 'Short Flag (upper)');
assert.strictEqual(toDynamicCase('--debug'), '--debug', 'Single Word');
});

it('Kebab Case', () => {
assert.strictEqual(toDynamicCase('--fast-fail'), '--fastfail', 'Two Words');
assert.strictEqual(
toDynamicCase('--fast-fail-test'),
'--fastfailtest',
'Multiple Words'
);
assert.strictEqual(
toDynamicCase('--fast-fail=test'),
'--fastfail=test',
'Arg'
);
assert.strictEqual(
toDynamicCase('--fast-fail=test-Test'),
'--fastfail=test-Test',
'Kebab Arg'
);
assert.strictEqual(
toDynamicCase('--fast-fail="test-Test=test-Test"'),
'--fastfail="test-Test=test-Test"',
'Deep Args'
);
});

it('Camel Case', () => {
assert.strictEqual(toDynamicCase('--fastFail'), '--fastfail', 'Two Words');
assert.strictEqual(
toDynamicCase('--fastFailTest'),
'--fastfailtest',
'Multiple Words'
);
assert.strictEqual(
toDynamicCase('--fastFail=test'),
'--fastfail=test',
'Arg'
);
assert.strictEqual(
toDynamicCase('--fastFail=testTest'),
'--fastfail=testTest',
'Camel Arg'
);
assert.strictEqual(
toDynamicCase('--fastFail="testTest=testTest"'),
'--fastfail="testTest=testTest"',
'Deep Args'
);
});
});
Loading

0 comments on commit 203fb45

Please sign in to comment.