just-scripts 2.4.2 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +85 -2
- package/CHANGELOG.md +27 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/index.js.map +1 -1
- package/lib/interfaces/PackageJson.d.ts +16 -0
- package/lib/interfaces/PackageJson.d.ts.map +1 -0
- package/lib/interfaces/PackageJson.js +3 -0
- package/lib/interfaces/PackageJson.js.map +1 -0
- package/lib/tasks/eslintTask.d.ts.map +1 -1
- package/lib/tasks/eslintTask.js +6 -7
- package/lib/tasks/eslintTask.js.map +1 -1
- package/lib/tasks/jestTask.d.ts +8 -0
- package/lib/tasks/jestTask.d.ts.map +1 -1
- package/lib/tasks/jestTask.js +10 -11
- package/lib/tasks/jestTask.js.map +1 -1
- package/lib/tasks/nodeExecTask.d.ts +22 -8
- package/lib/tasks/nodeExecTask.d.ts.map +1 -1
- package/lib/tasks/nodeExecTask.js +17 -11
- package/lib/tasks/nodeExecTask.js.map +1 -1
- package/lib/tasks/prettierTask.d.ts +1 -0
- package/lib/tasks/prettierTask.d.ts.map +1 -1
- package/lib/tasks/prettierTask.js +9 -23
- package/lib/tasks/prettierTask.js.map +1 -1
- package/lib/tasks/tscTask.d.ts.map +1 -1
- package/lib/tasks/tscTask.js +21 -39
- package/lib/tasks/tscTask.js.map +1 -1
- package/lib/tasks/tslintTask.d.ts.map +1 -1
- package/lib/tasks/tslintTask.js +7 -8
- package/lib/tasks/tslintTask.js.map +1 -1
- package/lib/tasks/webpackCliInitTask.js +2 -1
- package/lib/tasks/webpackCliInitTask.js.map +1 -1
- package/lib/tasks/webpackCliTask.js +3 -3
- package/lib/tasks/webpackCliTask.js.map +1 -1
- package/lib/tasks/webpackDevServerTask.d.ts.map +1 -1
- package/lib/tasks/webpackDevServerTask.js +3 -3
- package/lib/tasks/webpackDevServerTask.js.map +1 -1
- package/lib/utils/exec.d.ts +37 -0
- package/lib/utils/exec.d.ts.map +1 -0
- package/lib/utils/exec.js +107 -0
- package/lib/utils/exec.js.map +1 -0
- package/lib/utils/index.d.ts +5 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +19 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/mergePackageJson.d.ts +20 -0
- package/lib/utils/mergePackageJson.d.ts.map +1 -0
- package/lib/utils/mergePackageJson.js +61 -0
- package/lib/utils/mergePackageJson.js.map +1 -0
- package/lib/utils/paths.d.ts +13 -0
- package/lib/utils/paths.d.ts.map +1 -0
- package/lib/utils/paths.js +26 -0
- package/lib/utils/paths.js.map +1 -0
- package/lib/utils/readPackageJson.d.ts +8 -0
- package/lib/utils/readPackageJson.d.ts.map +1 -0
- package/lib/utils/readPackageJson.js +19 -0
- package/lib/utils/readPackageJson.js.map +1 -0
- package/package.json +4 -3
- package/src/index.ts +1 -1
- package/src/interfaces/PackageJson.ts +16 -0
- package/src/tasks/eslintTask.ts +7 -6
- package/src/tasks/jestTask.ts +18 -9
- package/src/tasks/nodeExecTask.ts +34 -18
- package/src/tasks/prettierTask.ts +9 -26
- package/src/tasks/tscTask.ts +21 -44
- package/src/tasks/tslintTask.ts +8 -7
- package/src/tasks/webpackCliInitTask.ts +1 -1
- package/src/tasks/webpackCliTask.ts +2 -2
- package/src/tasks/webpackDevServerTask.ts +3 -3
- package/src/utils/exec.ts +112 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/mergePackageJson.ts +64 -0
- package/src/utils/paths.ts +26 -0
- package/src/utils/readPackageJson.ts +16 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "just-scripts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Just Stack Scripts",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": {
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"chalk": "^4.0.0",
|
|
31
|
+
"cross-spawn": "^7.0.6",
|
|
31
32
|
"diff-match-patch": "1.0.5",
|
|
32
33
|
"fs-extra": "^11.0.0",
|
|
33
34
|
"glob": "^7.1.3",
|
|
34
|
-
"just-
|
|
35
|
-
"just-task": ">=1.12.0 <2.0.0",
|
|
35
|
+
"just-task": "^1.13.0",
|
|
36
36
|
"prompts": "^2.4.0",
|
|
37
37
|
"run-parallel-limit": "^1.0.6",
|
|
38
38
|
"semver": "^7.0.0",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"webpack-merge": "^5.7.3"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
+
"@types/cross-spawn": "^6.0.6",
|
|
43
44
|
"@types/diff-match-patch": "^1.0.32",
|
|
44
45
|
"@types/glob": "^7.2.0",
|
|
45
46
|
"@types/prompts": "^2.4.2",
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface Dependencies {
|
|
2
|
+
[key: string]: string;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface PackageJson {
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
dependencies?: Dependencies;
|
|
9
|
+
devDependencies?: Dependencies;
|
|
10
|
+
keywords?: string;
|
|
11
|
+
just?: {
|
|
12
|
+
/** Stack that the package is tracking */
|
|
13
|
+
stack?: string;
|
|
14
|
+
};
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
package/src/tasks/eslintTask.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolve,
|
|
2
|
-
import {
|
|
1
|
+
import { resolve, resolveCwd, TaskFunction } from 'just-task';
|
|
2
|
+
import { logNodeCommand, spawn } from '../utils';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -70,7 +70,7 @@ export function eslintTask(options: EsLintTaskOptions = {}): TaskFunction {
|
|
|
70
70
|
eslintCmd,
|
|
71
71
|
...(files ? files : ['.']),
|
|
72
72
|
...['--ext', extensions ? extensions : '.js,.jsx,.ts,.tsx'],
|
|
73
|
-
...(noEslintRc ? '--no-eslintrc' : []),
|
|
73
|
+
...(noEslintRc ? ['--no-eslintrc'] : []),
|
|
74
74
|
...(eslintConfigPath ? ['--config', eslintConfigPath] : []),
|
|
75
75
|
...(eslintIgnorePath ? ['--ignore-path', eslintIgnorePath] : []),
|
|
76
76
|
...(resolvePluginsPath ? ['--resolve-plugins-relative-to', resolvePluginsPath] : []),
|
|
@@ -95,10 +95,11 @@ export function eslintTask(options: EsLintTaskOptions = {}): TaskFunction {
|
|
|
95
95
|
env.ESLINT_USE_FLAT_CONFIG = JSON.stringify(useFlatConfig);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
logNodeCommand(eslintArgs);
|
|
99
99
|
return spawn(process.execPath, eslintArgs, { stdio: 'inherit', env });
|
|
100
|
-
} else {
|
|
101
|
-
return Promise.resolve();
|
|
102
100
|
}
|
|
101
|
+
|
|
102
|
+
// undertaker apparently requires returning a promise, async function, or function that calls done()
|
|
103
|
+
return Promise.resolve();
|
|
103
104
|
};
|
|
104
105
|
}
|
package/src/tasks/jestTask.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve, logger, resolveCwd, TaskFunction, argv } from 'just-task';
|
|
2
|
-
import { spawn,
|
|
2
|
+
import { spawn, readPackageJson, logNodeCommand } from '../utils';
|
|
3
3
|
import { existsSync } from 'fs';
|
|
4
4
|
import * as supportsColor from 'supports-color';
|
|
5
5
|
|
|
@@ -14,7 +14,15 @@ export interface JestTaskOptions {
|
|
|
14
14
|
passWithNoTests?: boolean;
|
|
15
15
|
clearCache?: boolean;
|
|
16
16
|
silent?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* This is not available in jest 30+
|
|
19
|
+
* Consider updating to jest 30 and using testPathPatterns (plural) instead.
|
|
20
|
+
*/
|
|
17
21
|
testPathPattern?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Compatible with jest 30+ only
|
|
24
|
+
*/
|
|
25
|
+
testPathPatterns?: string;
|
|
18
26
|
testNamePattern?: string;
|
|
19
27
|
// The maximum number of workers to use in jest for parallel test execution
|
|
20
28
|
maxWorkers?: number;
|
|
@@ -54,7 +62,6 @@ export function jestTask(options: JestTaskOptions = {}): TaskFunction {
|
|
|
54
62
|
|
|
55
63
|
if ((configFileExists || packageConfigExists) && jestCmd) {
|
|
56
64
|
logger.info(`Running Jest`);
|
|
57
|
-
const cmd = process.execPath;
|
|
58
65
|
|
|
59
66
|
const positional = argv()._.slice(1);
|
|
60
67
|
|
|
@@ -71,20 +78,22 @@ export function jestTask(options: JestTaskOptions = {}): TaskFunction {
|
|
|
71
78
|
...(options.watch ? ['--watch'] : []),
|
|
72
79
|
...(options.silent ? ['--silent'] : []),
|
|
73
80
|
...(options.testPathPattern ? ['--testPathPattern', options.testPathPattern] : []),
|
|
81
|
+
...(options.testPathPatterns ? ['--testPathPatterns', options.testPathPatterns] : []),
|
|
74
82
|
...(options.testNamePattern ? ['--testNamePattern', options.testNamePattern] : []),
|
|
75
|
-
...(options.maxWorkers ? ['--maxWorkers', options.maxWorkers]: []),
|
|
76
|
-
...(options.u || options.updateSnapshot ? ['--updateSnapshot'] : [
|
|
83
|
+
...(options.maxWorkers ? ['--maxWorkers', `${options.maxWorkers}`] : []),
|
|
84
|
+
...(options.u || options.updateSnapshot ? ['--updateSnapshot'] : []),
|
|
77
85
|
// Only include the positional args if `options._` wasn't specified
|
|
78
86
|
// (to avoid possibly including them twice)
|
|
79
87
|
...(options._ || positional),
|
|
80
88
|
].filter(arg => !!arg) as string[];
|
|
81
89
|
|
|
82
|
-
|
|
90
|
+
logNodeCommand(args);
|
|
83
91
|
|
|
84
|
-
return spawn(
|
|
85
|
-
} else {
|
|
86
|
-
logger.warn('no jest configuration found, skipping jest');
|
|
87
|
-
return Promise.resolve();
|
|
92
|
+
return spawn(process.execPath, args, { stdio: 'inherit', env: options.env });
|
|
88
93
|
}
|
|
94
|
+
|
|
95
|
+
logger.warn('no jest configuration found, skipping jest');
|
|
96
|
+
// undertaker apparently requires returning a promise, async function, or function that calls done()
|
|
97
|
+
return Promise.resolve();
|
|
89
98
|
};
|
|
90
99
|
}
|
|
@@ -1,42 +1,56 @@
|
|
|
1
1
|
import { SpawnOptions } from 'child_process';
|
|
2
|
-
import { spawn } from '
|
|
2
|
+
import { spawn } from '../utils';
|
|
3
3
|
import { logger, TaskFunction } from 'just-task';
|
|
4
4
|
import { resolveCwd, _tryResolve } from 'just-task/lib/resolve';
|
|
5
5
|
import { getTsNodeEnv } from '../typescript/getTsNodeEnv';
|
|
6
6
|
|
|
7
7
|
export interface NodeExecTaskOptions {
|
|
8
8
|
/**
|
|
9
|
-
* Arguments to be passed into a spawn call
|
|
10
|
-
*
|
|
9
|
+
* Arguments to be passed into a spawn call, including the script path to execute.
|
|
10
|
+
* The script path should be **absolute** to prevent unpredictable resolution.
|
|
11
|
+
*
|
|
12
|
+
* **WARNING: If `options.shell` is enabled, do not pass unsanitized user input as `args`.
|
|
13
|
+
* Any input containing shell metacharacters may be used to trigger arbitrary command execution.**
|
|
11
14
|
*/
|
|
12
|
-
args
|
|
15
|
+
args: string[];
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
|
-
* Environment variables to be passed to the
|
|
18
|
+
* Environment variables to be passed to the spawned process.
|
|
19
|
+
* Defaults to `process.env`.
|
|
16
20
|
*/
|
|
17
21
|
env?: NodeJS.ProcessEnv;
|
|
18
22
|
|
|
19
23
|
/**
|
|
20
|
-
*
|
|
24
|
+
* Whether to use `ts-node` to execute the script
|
|
21
25
|
*/
|
|
22
26
|
enableTypeScript?: boolean;
|
|
23
27
|
|
|
24
28
|
/**
|
|
25
|
-
*
|
|
29
|
+
* tsconfig file path to pass to `ts-node`
|
|
26
30
|
*/
|
|
27
31
|
tsconfig?: string;
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
|
-
*
|
|
34
|
+
* Whether to use `transpileOnly` mode for `ts-node`
|
|
31
35
|
*/
|
|
32
36
|
transpileOnly?: boolean;
|
|
33
37
|
|
|
34
38
|
/**
|
|
35
|
-
* Custom spawn options
|
|
39
|
+
* Custom spawn options.
|
|
40
|
+
*
|
|
41
|
+
* **WARNING: If the `shell` option is enabled, do not pass unsanitized user input as `args`.
|
|
42
|
+
* Any input containing shell metacharacters may be used to trigger arbitrary command execution.**
|
|
36
43
|
*/
|
|
37
44
|
spawnOptions?: SpawnOptions;
|
|
38
45
|
}
|
|
39
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Create a task to execute a command in a new process.
|
|
49
|
+
* Uses `cross-spawn` to avoid issues with spaces in arguments, but does not do any additional escaping.
|
|
50
|
+
*
|
|
51
|
+
* **WARNING: If the `shell` option is enabled, do not pass unsanitized user input to this task.
|
|
52
|
+
* Any input containing shell metacharacters may be used to trigger arbitrary command execution.**
|
|
53
|
+
*/
|
|
40
54
|
export function nodeExecTask(options: NodeExecTaskOptions): TaskFunction {
|
|
41
55
|
return function () {
|
|
42
56
|
const { spawnOptions, enableTypeScript, tsconfig, transpileOnly } = options;
|
|
@@ -44,17 +58,19 @@ export function nodeExecTask(options: NodeExecTaskOptions): TaskFunction {
|
|
|
44
58
|
const tsNodeRegister = resolveCwd('ts-node/register');
|
|
45
59
|
const nodeExecPath = process.execPath;
|
|
46
60
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
const args = [...(options.args || [])];
|
|
62
|
+
// Preserve the default behavior of inheriting process.env if no options are specified
|
|
63
|
+
let env = options.env ? { ...options.env } : { ...process.env };
|
|
64
|
+
const isTS = enableTypeScript && tsNodeRegister;
|
|
51
65
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
if (isTS) {
|
|
67
|
+
args.unshift('-r', tsNodeRegister);
|
|
68
|
+
|
|
69
|
+
env = { ...env, ...getTsNodeEnv(tsconfig, transpileOnly) };
|
|
56
70
|
}
|
|
57
71
|
|
|
58
|
-
|
|
72
|
+
logger.info([`Executing${isTS ? ' [TS]' : ''}:`, nodeExecPath, ...args].join(' '));
|
|
73
|
+
|
|
74
|
+
return spawn(nodeExecPath, args, { stdio: 'inherit', env, ...spawnOptions });
|
|
59
75
|
};
|
|
60
76
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logger, resolve, TaskFunction } from 'just-task';
|
|
2
|
-
import { spawn } from '
|
|
2
|
+
import { logNodeCommand, spawn } from '../utils';
|
|
3
3
|
import { splitArrayIntoChunks } from '../arrayUtils/splitArrayIntoChunks';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { arrayify } from '../arrayUtils/arrayify';
|
|
@@ -16,10 +16,12 @@ export interface PrettierTaskOptions {
|
|
|
16
16
|
files?: string[] | string;
|
|
17
17
|
ignorePath?: string;
|
|
18
18
|
configPath?: string;
|
|
19
|
+
check?: boolean;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export function prettierTask(options: PrettierTaskOptions = {}): TaskFunction {
|
|
22
|
-
|
|
23
|
+
// check v2 or v3 path
|
|
24
|
+
const prettierBin = resolve('prettier/bin-prettier.js') || resolve('prettier/bin/prettier.cjs');
|
|
23
25
|
|
|
24
26
|
if (prettierBin) {
|
|
25
27
|
return function prettier() {
|
|
@@ -32,38 +34,19 @@ export function prettierTask(options: PrettierTaskOptions = {}): TaskFunction {
|
|
|
32
34
|
options.files || path.resolve(process.cwd(), '**', '*.{ts,tsx,js,jsx,json,scss,html,yml,md}'),
|
|
33
35
|
),
|
|
34
36
|
},
|
|
35
|
-
check:
|
|
37
|
+
check: !!options.check,
|
|
36
38
|
});
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
// undertaker apparently requires returning a promise, async function, or function that calls done()
|
|
43
|
+
return async () => {
|
|
41
44
|
logger.warn('Prettier is not available, ignoring this task');
|
|
42
45
|
};
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export function prettierCheckTask(options: PrettierTaskOptions = {}): TaskFunction {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (prettierBin) {
|
|
49
|
-
return function prettierCheck() {
|
|
50
|
-
return runPrettierAsync({
|
|
51
|
-
prettierBin,
|
|
52
|
-
...{ configPath: options.configPath || undefined },
|
|
53
|
-
...{ ignorePath: options.ignorePath || undefined },
|
|
54
|
-
...{
|
|
55
|
-
files: arrayify(
|
|
56
|
-
options.files || path.resolve(process.cwd(), '**', '*.{ts,tsx,js,jsx,json,scss,html,yml,md}'),
|
|
57
|
-
),
|
|
58
|
-
},
|
|
59
|
-
check: true,
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return function () {
|
|
65
|
-
logger.warn('Prettier is not available, ignoring this task');
|
|
66
|
-
};
|
|
49
|
+
return prettierTask({ ...options, check: true });
|
|
67
50
|
}
|
|
68
51
|
|
|
69
52
|
function runPrettierAsync(context: PrettierContext) {
|
|
@@ -81,7 +64,7 @@ function runPrettierAsync(context: PrettierContext) {
|
|
|
81
64
|
...chunk,
|
|
82
65
|
];
|
|
83
66
|
|
|
84
|
-
|
|
67
|
+
logNodeCommand(prettierArgs);
|
|
85
68
|
|
|
86
69
|
return finishPromise.then(() => spawn(process.execPath, prettierArgs, { stdio: 'inherit' }));
|
|
87
70
|
}, Promise.resolve());
|
package/src/tasks/tscTask.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { resolve, logger, resolveCwd, TaskFunction } from 'just-task';
|
|
3
|
-
import {
|
|
3
|
+
import { logNodeCommand, spawn } from '../utils';
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
|
|
6
6
|
export type TscTaskOptions = { [key in keyof ts.CompilerOptions]?: string | boolean | string[] } & {
|
|
@@ -25,9 +25,8 @@ export function tscTask(options: TscTaskOptions = {}): TaskFunction {
|
|
|
25
25
|
logger.info(`Running ${tscCmd} with ${options.project || options.build}`);
|
|
26
26
|
|
|
27
27
|
const args = argsFromOptions(tscCmd, options);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return exec(cmd);
|
|
28
|
+
logNodeCommand(args);
|
|
29
|
+
return spawn(process.execPath, args, { stdio: 'inherit' });
|
|
31
30
|
}
|
|
32
31
|
return Promise.resolve();
|
|
33
32
|
};
|
|
@@ -37,25 +36,7 @@ export function tscTask(options: TscTaskOptions = {}): TaskFunction {
|
|
|
37
36
|
* Returns a task that runs the TSC CLI in watch mode.
|
|
38
37
|
*/
|
|
39
38
|
export function tscWatchTask(options: TscTaskOptions = {}): TaskFunction {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (!tscCmd) {
|
|
43
|
-
throw new Error('cannot find tsc');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return function tscWatch() {
|
|
47
|
-
options = { ...options, ...getProjectOrBuildOptions(options) };
|
|
48
|
-
|
|
49
|
-
if (isValidProject(options)) {
|
|
50
|
-
logger.info(`Running ${tscCmd} with ${options.project || options.build} in watch mode`);
|
|
51
|
-
|
|
52
|
-
const args = argsFromOptions(tscCmd, options);
|
|
53
|
-
const cmd = [...args, '--watch'];
|
|
54
|
-
logger.info(encodeArgs(cmd).join(' '));
|
|
55
|
-
return spawn(process.execPath, cmd, { stdio: 'inherit' });
|
|
56
|
-
}
|
|
57
|
-
return Promise.resolve();
|
|
58
|
-
};
|
|
39
|
+
return tscTask({ ...options, watch: true });
|
|
59
40
|
}
|
|
60
41
|
|
|
61
42
|
/**
|
|
@@ -81,9 +62,7 @@ function isValidProject(options: TscTaskOptions) {
|
|
|
81
62
|
(typeof options.project === 'string' && fs.existsSync(options.project)) ||
|
|
82
63
|
(typeof options.build === 'string' && fs.existsSync(options.build)) ||
|
|
83
64
|
(Array.isArray(options.build) &&
|
|
84
|
-
options.build.
|
|
85
|
-
return currentIsValid && typeof buildPath === 'string' && fs.existsSync(buildPath);
|
|
86
|
-
}, true as boolean))
|
|
65
|
+
options.build.every(buildPath => typeof buildPath === 'string' && fs.existsSync(buildPath)))
|
|
87
66
|
);
|
|
88
67
|
}
|
|
89
68
|
|
|
@@ -91,23 +70,21 @@ function isValidProject(options: TscTaskOptions) {
|
|
|
91
70
|
* Returns an array of CLI arguments for TSC given the `options`.
|
|
92
71
|
*/
|
|
93
72
|
function argsFromOptions(tscCmd: string, options: TscTaskOptions): string[] {
|
|
94
|
-
const { nodeArgs, ...rest } = options;
|
|
73
|
+
const { nodeArgs, build, ...rest } = options;
|
|
74
|
+
|
|
75
|
+
const args = [...(nodeArgs || []), tscCmd];
|
|
76
|
+
// --build must be the first arg if specified
|
|
77
|
+
const argEntries = [...(build !== undefined ? [['build', build]] : []), ...Object.entries(rest)];
|
|
78
|
+
|
|
79
|
+
for (const [option, optionValue] of argEntries) {
|
|
80
|
+
if (typeof optionValue === 'string') {
|
|
81
|
+
args.push('--' + option, optionValue);
|
|
82
|
+
} else if (typeof optionValue === 'boolean' && optionValue) {
|
|
83
|
+
args.push('--' + option);
|
|
84
|
+
} else if (Array.isArray(optionValue)) {
|
|
85
|
+
args.push('--' + option, ...optionValue);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
95
88
|
|
|
96
|
-
return
|
|
97
|
-
...(nodeArgs ? nodeArgs : []),
|
|
98
|
-
...Object.keys(rest).reduce(
|
|
99
|
-
(currentArgs, option) => {
|
|
100
|
-
const optionValue = options[option];
|
|
101
|
-
if (typeof optionValue === 'string') {
|
|
102
|
-
return currentArgs.concat(['--' + option, optionValue]);
|
|
103
|
-
} else if (typeof optionValue === 'boolean' && optionValue) {
|
|
104
|
-
return currentArgs.concat(['--' + option]);
|
|
105
|
-
} else if (Array.isArray(optionValue)) {
|
|
106
|
-
return currentArgs.concat(['--' + option, ...optionValue]);
|
|
107
|
-
}
|
|
108
|
-
return currentArgs;
|
|
109
|
-
},
|
|
110
|
-
[tscCmd],
|
|
111
|
-
),
|
|
112
|
-
];
|
|
89
|
+
return args;
|
|
113
90
|
}
|
package/src/tasks/tslintTask.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolve, logger, resolveCwd, TaskFunction } from 'just-task';
|
|
2
|
-
import { exec, encodeArgs } from 'just-scripts-utils';
|
|
3
2
|
import * as path from 'path';
|
|
4
3
|
import * as fs from 'fs';
|
|
4
|
+
import { logNodeCommand, spawn } from '../utils';
|
|
5
5
|
|
|
6
6
|
export interface TsLintTaskOptions {
|
|
7
7
|
config?: string;
|
|
@@ -12,7 +12,7 @@ export interface TsLintTaskOptions {
|
|
|
12
12
|
export function tslintTask(options: TsLintTaskOptions = {}): TaskFunction {
|
|
13
13
|
const projectFile = options.project || resolveCwd('./tsconfig.json');
|
|
14
14
|
|
|
15
|
-
return function tslint() {
|
|
15
|
+
return async function tslint() {
|
|
16
16
|
const tslintCmd = resolve('tslint/lib/tslintCli.js');
|
|
17
17
|
|
|
18
18
|
if (projectFile && tslintCmd && fs.existsSync(projectFile)) {
|
|
@@ -31,11 +31,12 @@ export function tslintTask(options: TsLintTaskOptions = {}): TaskFunction {
|
|
|
31
31
|
args.push('--fix');
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
return
|
|
37
|
-
} else {
|
|
38
|
-
return Promise.resolve();
|
|
34
|
+
const allArgs = [tslintCmd, ...args];
|
|
35
|
+
logNodeCommand(allArgs);
|
|
36
|
+
return spawn(process.execPath, allArgs, { stdio: 'inherit' });
|
|
39
37
|
}
|
|
38
|
+
|
|
39
|
+
// undertaker apparently requires returning a promise, async function, or function that calls done()
|
|
40
|
+
return Promise.resolve();
|
|
40
41
|
};
|
|
41
42
|
}
|
|
@@ -9,7 +9,7 @@ import { tryRequire } from '../tryRequire';
|
|
|
9
9
|
*/
|
|
10
10
|
export function webpackCliInitTask(customScaffold?: string, auto = false): TaskFunction {
|
|
11
11
|
return function webpackCli() {
|
|
12
|
-
const init = tryRequire('@webpack-cli/init')
|
|
12
|
+
const init = tryRequire('@webpack-cli/init')?.default;
|
|
13
13
|
if (!init) {
|
|
14
14
|
logger.warn('webpack-cli init requires three dependencies: @webpack-cli/init (preferred - as a devDependency)');
|
|
15
15
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logger, TaskFunction, resolve } from 'just-task';
|
|
2
|
-
import { spawn } from '
|
|
2
|
+
import { logNodeCommand, spawn } from '../utils';
|
|
3
3
|
import { getTsNodeEnv } from '../typescript/getTsNodeEnv';
|
|
4
4
|
import { findWebpackConfig } from '../webpack/findWebpackConfig';
|
|
5
5
|
|
|
@@ -67,7 +67,7 @@ export function webpackCliTask(options: WebpackCliTaskOptions = {}): TaskFunctio
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
logNodeCommand(args);
|
|
71
71
|
|
|
72
72
|
return spawn(process.execPath, args, { stdio: 'inherit', env: options.env });
|
|
73
73
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// // WARNING: Careful about add more imports - only import types from webpack
|
|
2
2
|
import { Configuration } from 'webpack';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { logNodeCommand, spawn } from '../utils';
|
|
4
|
+
import { resolve, resolveCwd, TaskFunction } from 'just-task';
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import { WebpackCliTaskOptions } from './webpackCliTask';
|
|
@@ -93,7 +93,7 @@ export function webpackDevServerTask(options: WebpackDevServerTaskOptions = {}):
|
|
|
93
93
|
args = [...args, ...options.webpackCliArgs];
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
logNodeCommand(args);
|
|
97
97
|
return spawn(process.execPath, args, { stdio: 'inherit', env: options.env });
|
|
98
98
|
};
|
|
99
99
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as cp from 'child_process';
|
|
2
|
+
import { spawn as crossSpawn } from 'cross-spawn';
|
|
3
|
+
import { logger } from 'just-task';
|
|
4
|
+
|
|
5
|
+
// `exec` and `execSync` were removed due to security issues (keeping filename for history)
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated This prevents issues from spaces in args, but does NOT escape shell metacharacters.
|
|
9
|
+
* For full escaping, consider a library such as `shell-quote` instead. (Note that `spawn` and tasks
|
|
10
|
+
* from this package now use `cross-spawn` which escapes spaces internally.)
|
|
11
|
+
*/
|
|
12
|
+
export function encodeArgs(cmdArgs: string[]): string[] {
|
|
13
|
+
return quoteSpaces(cmdArgs);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Quote arguments containing spaces. Note that this does NOT do any other escaping!
|
|
18
|
+
* For more complete escaping, consider a library such as `shell-quote`, or use safer APIs which
|
|
19
|
+
* don't require escaping. (Note that `spawn` from this package now uses `cross-spawn` which
|
|
20
|
+
* escapes spaces internally.)
|
|
21
|
+
*/
|
|
22
|
+
function quoteSpaces(cmdArgs: string[]): string[] {
|
|
23
|
+
// Taken from https://github.com/xxorax/node-shell-escape/blob/master/shell-escape.js
|
|
24
|
+
// However, we needed to use double quotes because that's the norm in more platforms
|
|
25
|
+
if (!cmdArgs) {
|
|
26
|
+
return cmdArgs;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return cmdArgs.map(arg => {
|
|
30
|
+
if (/[^\w/:=-]/.test(arg)) {
|
|
31
|
+
arg = `"${arg.replace(/"/g, '"\\"')}"`;
|
|
32
|
+
arg = arg.replace(/^(?:"")+/g, '').replace(/\\"""/g, '\\"');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return arg;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Log `Running: <process.execPath> <...args>`
|
|
41
|
+
*/
|
|
42
|
+
export function logNodeCommand(...args: (string | string[])[]): void {
|
|
43
|
+
logger.info(`Running: ${process.execPath} ${quoteSpaces(args.flat()).join(' ')}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Execute a command in a new process. Uses `cross-spawn` to avoid issues with spaces in arguments,
|
|
48
|
+
* but does not do any additional escaping. (For further enhancements, consider using the `execa`
|
|
49
|
+
* library instead.)
|
|
50
|
+
*
|
|
51
|
+
* **WARNING: If the `shell` option is enabled, do not pass unsanitized user input to this function.
|
|
52
|
+
* Any input containing shell metacharacters may be used to trigger arbitrary command execution.**
|
|
53
|
+
*
|
|
54
|
+
* @param cmd Command to execute
|
|
55
|
+
* @param args Args for the command. Quoting spaces is handled internally by `cross-spawn`.
|
|
56
|
+
* @param opts Normal spawn options plus stdout/stderr for piping output. (To inherit stdio from the
|
|
57
|
+
* parent process, just use `stdio: 'inherit'` instead.)
|
|
58
|
+
*
|
|
59
|
+
* @returns Promise which will settle when the command completes. If the promise is rejected, the error will
|
|
60
|
+
* include the child process's exit code (`error.code`) or signal (`error.signal`) if relevant.
|
|
61
|
+
* The returned promise also has a `child` property with the spawned `ChildProcess` instance.
|
|
62
|
+
*
|
|
63
|
+
* @deprecated This function is not recommended for use outside the `just-scripts` package.
|
|
64
|
+
* Instead, consider a more mature, purpose-specific library such as `execa` or `nano-spawn`.
|
|
65
|
+
*/
|
|
66
|
+
export function spawn(
|
|
67
|
+
cmd: string,
|
|
68
|
+
args: ReadonlyArray<string> = [],
|
|
69
|
+
opts: cp.SpawnOptions & { stdout?: NodeJS.WritableStream; stderr?: NodeJS.WritableStream } = {},
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
let child: cp.ChildProcess;
|
|
73
|
+
try {
|
|
74
|
+
child = crossSpawn(cmd, args, opts);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
reject(error);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const onExit = (code: number | null, signal: NodeJS.Signals | null): void => {
|
|
81
|
+
child.off('error', onError);
|
|
82
|
+
if (code) {
|
|
83
|
+
const error = new Error('Command failed: ' + [cmd, ...args].join(' '));
|
|
84
|
+
(error as any).code = code;
|
|
85
|
+
reject(error);
|
|
86
|
+
} else if (signal) {
|
|
87
|
+
const error = new Error(`Command terminated by signal ${signal}: ` + [cmd, ...args].join(' '));
|
|
88
|
+
(error as any).signal = signal;
|
|
89
|
+
reject(error);
|
|
90
|
+
} else {
|
|
91
|
+
resolve();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Some error circumstances may fire 'error' rather than 'exit'
|
|
96
|
+
// https://nodejs.org/docs/latest/api/child_process.html#event-error
|
|
97
|
+
const onError = (error: Error): void => {
|
|
98
|
+
reject(error);
|
|
99
|
+
child.off('exit', onExit);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
child.on('exit', onExit);
|
|
103
|
+
child.on('error', onError);
|
|
104
|
+
|
|
105
|
+
if (opts.stdout) {
|
|
106
|
+
child.stdout?.pipe(opts.stdout);
|
|
107
|
+
}
|
|
108
|
+
if (opts.stderr) {
|
|
109
|
+
child.stderr?.pipe(opts.stderr);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|