Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix process.argv propagation #341

Merged
merged 4 commits into from
Feb 2, 2021
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
11 changes: 11 additions & 0 deletions .changeset/modern-grapes-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'skuba': patch
---

**node, start:** Propagate `process.argv`

Passing command-line arguments into a script now works as expected:

```bash
yarn skuba node src/script.ts arg1 arg2 arg3
```
11 changes: 11 additions & 0 deletions .changeset/nasty-carpets-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'skuba': patch
---

**node:** Support Node.js inspector options when running a script

Passing an [inspector option](https://nodejs.org/en/docs/guides/debugging-getting-started/#command-line-options) for script debugging now works as expected:

```bash
yarn skuba node --inspect-brk src/script.ts
```
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@
"ts-node": "^9.1.1",
"ts-node-dev": "1.1.1",
"tsconfig-seek": "1.0.2",
"typescript": "4.1.3",
"yargs-parser": "^20.2.4"
"typescript": "4.1.3"
},
"peerDependencies": {
"@types/jest": ">= 25 < 27",
Expand Down
68 changes: 28 additions & 40 deletions src/cli/node.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,63 @@
import path from 'path';

import getPort from 'get-port';
import parse from 'yargs-parser';

import { unsafeMapYargs } from '../utils/args';
import { parseRunArgs } from '../utils/args';
import { createExec } from '../utils/exec';
import { isBabelFromManifest } from '../utils/manifest';
import { isIpPort } from '../utils/validation';

const parseArgs = () => {
const {
_: [entryPointArg],
...yargs
} = parse(process.argv.slice(2));

const entryPoint = typeof entryPointArg === 'string' ? entryPointArg : null;

const inspect = unsafeMapYargs({
inspect: yargs.inspect as unknown,
'inspect-brk': yargs['inspect-brk'] as unknown,
});

return {
entryPoint,
inspect,
port: Number(yargs.port) || undefined,
};
};

export const node = async () => {
const args = parseArgs();
const args = parseRunArgs(process.argv.slice(2));

const [availablePort, isBabel] = await Promise.all([
getPort(),
isBabelFromManifest(),
]);

const exec = createExec({
env: isBabel ? undefined : { __SKUBA_REGISTER_MODULE_ALIASES: '1' },
env: {
__SKUBA_ENTRY_POINT: args.entryPoint,
__SKUBA_PORT: String(isIpPort(args.port) ? args.port : availablePort),
__SKUBA_REGISTER_MODULE_ALIASES: isBabel ? '1' : undefined,
},
});

if (isBabel) {
return exec(
'babel-node',
...args.inspect,
...args.node,
'--extensions',
['.js', '.json', '.ts'].join(','),
'--require',
path.posix.join('skuba', 'lib', 'register'),
...(args.entryPoint === null
? []
: [
path.join(__dirname, '..', 'wrapper.js'),
args.entryPoint,
String(isIpPort(args.port) ? args.port : availablePort),
]),
...(args.entryPoint ? [path.join(__dirname, '..', 'wrapper.js')] : []),
...args.script,
);
}

if (args.entryPoint) {
// Run a script with plain `node` to support inspector options.
// https://github.com/TypeStrong/ts-node#programmatic
return exec(
'node',
...args.node,
'--require',
path.posix.join('skuba', 'lib', 'register'),
'--require',
path.posix.join('ts-node', 'register', 'transpile-only'),
path.join(__dirname, '..', 'wrapper'),
...args.script,
);
}

// REPL with `ts-node` to support import statements.
return exec(
'ts-node',
...args.inspect,
...args.node,
'--require',
path.posix.join('skuba', 'lib', 'register'),
'--transpile-only',
...(args.entryPoint === null
? []
: [
path.join(__dirname, '..', 'wrapper'),
args.entryPoint,
String(isIpPort(args.port) ? args.port : availablePort),
]),
...args.script,
);
};
50 changes: 17 additions & 33 deletions src/cli/start.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,42 @@
import path from 'path';

import getPort from 'get-port';
import parse from 'yargs-parser';

import { unsafeMapYargs } from '../utils/args';
import { parseRunArgs } from '../utils/args';
import { createExec } from '../utils/exec';
import {
getEntryPointFromManifest,
isBabelFromManifest,
} from '../utils/manifest';
import { isIpPort } from '../utils/validation';

const parseArgs = async () => {
const {
_: [entryPointArg],
...yargs
} = parse(process.argv.slice(2));

const entryPoint =
typeof entryPointArg === 'string'
? entryPointArg
: await getEntryPointFromManifest();

const inspect = unsafeMapYargs({
inspect: yargs.inspect as unknown,
'inspect-brk': yargs['inspect-brk'] as unknown,
});

return {
entryPoint,
inspect,
port: Number(yargs.port) || undefined,
};
};

export const start = async () => {
const [args, availablePort, isBabel] = await Promise.all([
parseArgs(),
parseRunArgs(process.argv.slice(2)),
getPort(),
isBabelFromManifest(),
]);

if (!args.entryPoint) {
args.entryPoint = await getEntryPointFromManifest();
}

const execProcess = createExec({
env: isBabel ? undefined : { __SKUBA_REGISTER_MODULE_ALIASES: '1' },
env: isBabel
? undefined
: {
__SKUBA_ENTRY_POINT: args.entryPoint,
__SKUBA_PORT: String(isIpPort(args.port) ? args.port : availablePort),
__SKUBA_REGISTER_MODULE_ALIASES: '1',
},
});

if (isBabel) {
return execProcess(
'nodemon',
'--ext',
['.js', '.json', '.ts'].join(','),
...args.inspect,
...args.node,
'--quiet',
'--exec',
'babel-node',
Expand All @@ -59,20 +45,18 @@ export const start = async () => {
'--require',
path.posix.join('skuba', 'lib', 'register'),
path.join(__dirname, '..', 'wrapper.js'),
args.entryPoint,
String(isIpPort(args.port) ? args.port : availablePort),
...args.script,
);
}

return execProcess(
'ts-node-dev',
...args.inspect,
...args.node,
'--require',
path.posix.join('skuba', 'lib', 'register'),
'--respawn',
'--transpile-only',
path.join(__dirname, '..', 'wrapper'),
args.entryPoint,
String(isIpPort(args.port) ? args.port : availablePort),
...args.script,
);
};
4 changes: 2 additions & 2 deletions src/skuba.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import path from 'path';

import { parseArgs } from './utils/args';
import { parseProcessArgs } from './utils/args';
import { COMMAND_DIR, COMMAND_SET, commandToModule } from './utils/command';
import { handleCliError } from './utils/error';
import { showHelp } from './utils/help';
Expand All @@ -21,7 +21,7 @@ import { showLogoAndVersionInfo } from './utils/logo';
import { hasProp } from './utils/validation';

const skuba = async () => {
const { commandName } = parseArgs(process.argv);
const { commandName } = parseProcessArgs(process.argv);

if (COMMAND_SET.has(commandName)) {
const moduleName = commandToModule(commandName);
Expand Down
64 changes: 44 additions & 20 deletions src/utils/args.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { parseArgs, unsafeMapYargs } from './args';
import { parseProcessArgs, parseRunArgs } from './args';

describe('parseArgs', () => {
describe('parseProcessArgs', () => {
it('parses a macOS command with args', () => {
const argv = [
'/usr/local/bin/node',
Expand All @@ -9,7 +9,7 @@ describe('parseArgs', () => {
'--xyz',
];

expect(parseArgs(argv)).toStrictEqual({
expect(parseProcessArgs(argv)).toStrictEqual({
commandName: 'start',
args: ['--xyz'],
});
Expand All @@ -22,7 +22,7 @@ describe('parseArgs', () => {
'start',
];

expect(parseArgs(argv)).toStrictEqual({
expect(parseProcessArgs(argv)).toStrictEqual({
commandName: 'start',
args: [],
});
Expand All @@ -36,7 +36,7 @@ describe('parseArgs', () => {
'--xyz',
];

expect(parseArgs(argv)).toStrictEqual({
expect(parseProcessArgs(argv)).toStrictEqual({
commandName: 'start',
args: ['--xyz'],
});
Expand All @@ -49,25 +49,49 @@ describe('parseArgs', () => {
'start',
];

expect(parseArgs(argv)).toStrictEqual({
expect(parseProcessArgs(argv)).toStrictEqual({
commandName: 'start',
args: [],
});
});
});

describe('unsafeMapYargs', () => {
it('maps an assortment of yargs', () =>
expect(
unsafeMapYargs({
a: 1,
b: '2',
c: true,
d: [3, '4'],
e: [],
f: false,
g: undefined,
h: null,
}),
).toEqual(['--a=1', '--b=2', '--c', '--d=3']));
describe('parseRunArgs', () => {
interface TestCase {
input: string;

entryPoint: string | undefined;
port: number | undefined;
node: string[];
script: string[];
}

test.each`
input | entryPoint | port | node | script
${''} | ${undefined} | ${undefined} | ${[]} | ${[]}
${'--inspect'} | ${undefined} | ${undefined} | ${['--inspect']} | ${[]}
${'--inspect=1234'} | ${undefined} | ${undefined} | ${['--inspect=1234']} | ${[]}
${'--inspect 1234'} | ${undefined} | ${undefined} | ${['--inspect=1234']} | ${[]}
${'--inspect 1234 listen.ts'} | ${'listen.ts'} | ${undefined} | ${['--inspect=1234']} | ${[]}
${'--inspect 1234 listen.ts --inspect 1234'} | ${'listen.ts'} | ${undefined} | ${['--inspect=1234']} | ${['--inspect', '1234']}
${'--inspect listen.ts'} | ${'listen.ts'} | ${undefined} | ${['--inspect']} | ${[]}
${'--inspect-brk'} | ${undefined} | ${undefined} | ${['--inspect-brk']} | ${[]}
${'--inspect-brk=1234'} | ${undefined} | ${undefined} | ${['--inspect-brk=1234']} | ${[]}
${'--inspect-brk 1234'} | ${undefined} | ${undefined} | ${['--inspect-brk=1234']} | ${[]}
${'--inspect-brk 1234 listen.ts'} | ${'listen.ts'} | ${undefined} | ${['--inspect-brk=1234']} | ${[]}
${'--inspect-brk 1234 listen.ts --inspect-brk 1234'} | ${'listen.ts'} | ${undefined} | ${['--inspect-brk=1234']} | ${['--inspect-brk', '1234']}
${'--inspect-brk listen.ts'} | ${'listen.ts'} | ${undefined} | ${['--inspect-brk']} | ${[]}
${'--port'} | ${undefined} | ${undefined} | ${[]} | ${[]}
${'--port=1234'} | ${undefined} | ${1234} | ${[]} | ${[]}
${'--port 1234'} | ${undefined} | ${1234} | ${[]} | ${[]}
${'--port 1234 listen.ts'} | ${'listen.ts'} | ${1234} | ${[]} | ${[]}
${'--port 1234 listen.ts --port 5678'} | ${'listen.ts'} | ${1234} | ${[]} | ${['--port', '5678']}
${'--port listen.ts'} | ${'listen.ts'} | ${undefined} | ${[]} | ${[]}
${'listen.ts'} | ${'listen.ts'} | ${undefined} | ${[]} | ${[]}
${'listen.ts --inspect'} | ${'listen.ts'} | ${undefined} | ${[]} | ${['--inspect']}
${'listen.ts --inspect-brk'} | ${'listen.ts'} | ${undefined} | ${[]} | ${['--inspect-brk']}
${'listen.ts --port 1234'} | ${'listen.ts'} | ${undefined} | ${[]} | ${['--port', '1234']}
`('$input', ({ input, ...expected }: TestCase) =>
expect(parseRunArgs(input.split(' '))).toEqual(expected),
);
});
Loading