@plugjs/plug 0.3.5 → 0.4.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/dist/asserts.cjs +9 -11
- package/dist/asserts.cjs.map +1 -1
- package/dist/asserts.d.ts +1 -2
- package/dist/asserts.mjs +8 -9
- package/dist/asserts.mjs.map +1 -1
- package/dist/build.cjs +29 -5
- package/dist/build.cjs.map +1 -1
- package/dist/build.d.ts +4 -0
- package/dist/build.mjs +27 -5
- package/dist/build.mjs.map +1 -1
- package/dist/cli.d.mts +12 -0
- package/dist/cli.mjs +266 -0
- package/dist/cli.mjs.map +6 -0
- package/dist/fork.cjs +30 -12
- package/dist/fork.cjs.map +1 -1
- package/dist/fork.d.ts +10 -0
- package/dist/fork.mjs +31 -13
- package/dist/fork.mjs.map +1 -1
- package/dist/helpers.cjs +30 -10
- package/dist/helpers.cjs.map +2 -2
- package/dist/helpers.d.ts +12 -0
- package/dist/helpers.mjs +35 -11
- package/dist/helpers.mjs.map +2 -2
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.mjs +4 -1
- package/dist/index.mjs.map +1 -1
- package/dist/logging/emit.cjs +4 -4
- package/dist/logging/emit.cjs.map +1 -1
- package/dist/logging/emit.mjs +4 -4
- package/dist/logging/emit.mjs.map +1 -1
- package/dist/logging/logger.cjs +43 -2
- package/dist/logging/logger.cjs.map +1 -1
- package/dist/logging/logger.d.ts +36 -3
- package/dist/logging/logger.mjs +43 -3
- package/dist/logging/logger.mjs.map +1 -1
- package/dist/logging/options.cjs +5 -2
- package/dist/logging/options.cjs.map +1 -1
- package/dist/logging/options.mjs +5 -2
- package/dist/logging/options.mjs.map +1 -1
- package/dist/logging.cjs +14 -3
- package/dist/logging.cjs.map +1 -1
- package/dist/logging.d.ts +2 -0
- package/dist/logging.mjs +13 -3
- package/dist/logging.mjs.map +1 -1
- package/dist/plugs/build.cjs +66 -0
- package/dist/plugs/build.cjs.map +6 -0
- package/dist/plugs/build.d.ts +13 -0
- package/dist/plugs/build.mjs +40 -0
- package/dist/plugs/build.mjs.map +6 -0
- package/dist/types.d.ts +2 -0
- package/dist/utils/exec.cjs +5 -12
- package/dist/utils/exec.cjs.map +2 -2
- package/dist/utils/exec.d.ts +0 -2
- package/dist/utils/exec.mjs +6 -13
- package/dist/utils/exec.mjs.map +1 -1
- package/package.json +7 -9
- package/src/asserts.ts +9 -11
- package/src/build.ts +33 -4
- package/{extra/plug.mts → src/cli.mts} +115 -141
- package/src/fork.ts +42 -16
- package/src/helpers.ts +53 -1
- package/src/index.ts +2 -1
- package/src/logging/emit.ts +4 -4
- package/src/logging/logger.ts +60 -7
- package/src/logging/options.ts +5 -1
- package/src/logging.ts +20 -5
- package/src/plugs/build.ts +58 -0
- package/src/types.ts +2 -0
- package/src/utils/exec.ts +6 -20
- package/cli/plug.mjs +0 -1385
- package/cli/ts-loader.mjs +0 -275
- package/cli/tsrun.mjs +0 -1204
- package/extra/ts-loader.mts +0 -546
- package/extra/tsrun.mts +0 -127
- package/extra/utils.ts +0 -150
|
@@ -2,52 +2,81 @@
|
|
|
2
2
|
/* eslint-disable no-console */
|
|
3
3
|
|
|
4
4
|
import _fs from 'node:fs'
|
|
5
|
-
import _path from 'node:path'
|
|
6
5
|
|
|
7
|
-
import
|
|
6
|
+
import { main, yargsParser } from '@plugjs/tsrun'
|
|
8
7
|
|
|
9
|
-
import {
|
|
8
|
+
import { BuildFailure } from './asserts'
|
|
9
|
+
import { invokeTasks, isBuild } from './build'
|
|
10
|
+
import { $blu, $gry, $p, $red, $t, $und, $wht } from './logging/colors'
|
|
11
|
+
import { getCurrentWorkingDirectory, resolveDirectory, resolveFile, resolveAbsolutePath } from './paths'
|
|
10
12
|
|
|
11
|
-
import type {
|
|
12
|
-
import type { Build } from '../src/index.js'
|
|
13
|
+
import type { AbsolutePath } from './paths'
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
/* Extra colors */
|
|
16
|
+
const $bnd = (s: string): string => $blu($und(s))
|
|
17
|
+
const $gnd = (s: string): string => $gry($und(s))
|
|
18
|
+
const $wnd = (s: string): string => $wht($und(s))
|
|
19
|
+
|
|
20
|
+
/** Version injected by esbuild, defaulted in case of dynamic transpilation */
|
|
21
|
+
const version = typeof __version === 'string' ? __version : '0.0.0-dev'
|
|
22
|
+
declare const __version: string | undefined
|
|
16
23
|
|
|
17
24
|
/* ========================================================================== *
|
|
18
|
-
*
|
|
19
|
-
* BUILD INSPECTION *
|
|
20
|
-
* ========================================================================== *
|
|
25
|
+
* HELP SCREEN *
|
|
21
26
|
* ========================================================================== */
|
|
22
27
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
28
|
+
/** Show help screen */
|
|
29
|
+
function help(): void {
|
|
30
|
+
console.log(`${$bnd('Usage:')}
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
const buildFailure = Symbol.for('plugjs:buildFailure')
|
|
32
|
+
${$wht('plugjs')} ${$gry('[')}--options${$gry('] [... ')}prop=val${$gry(' ...] [... ')}task${$gry(' ...]')}
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
function isBuild(build: any): build is Build<Record<string, any>> & {
|
|
31
|
-
[buildMarker]: (tasks: string[], props?: Record<string, string | undefined>) => Promise<void>
|
|
32
|
-
} {
|
|
33
|
-
return build && typeof build[buildMarker] === 'function'
|
|
34
|
-
}
|
|
34
|
+
${$bnd('Options:')}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
36
|
+
${$wht(`-f --file ${$gnd('file')}`)} Specify the build file to use (default ${$wnd('./build.ts')})
|
|
37
|
+
${$wht(`-w --watch ${$gnd('dir')}`)} Watch for changes on the specified directory and run
|
|
38
|
+
${$wht('-v --verbose')} Increase logging verbosity
|
|
39
|
+
${$wht('-q --quiet')} Decrease logging verbosity
|
|
40
|
+
${$wht('-c --colors')} Force colorful output (use ${$wnd('--no-colors')} to force plain text)
|
|
41
|
+
${$wht('-l --list')} Only list the tasks defined by the build, nothing more!
|
|
42
|
+
${$wht('-h --help')} Help! You're reading it now!
|
|
43
|
+
${$wht(' --version')} Version! This one: ${version}!
|
|
44
|
+
|
|
45
|
+
${$bnd('Properties:')}
|
|
46
|
+
|
|
47
|
+
Any argument in the format ${$wnd('key=value')} will be interpeted as a property to
|
|
48
|
+
be injected in the build process (e.g. ${$wnd('mode=production')}).
|
|
49
|
+
|
|
50
|
+
${$bnd('Tasks:')}
|
|
40
51
|
|
|
52
|
+
Any other argument will be treated as a task name. If no task names are
|
|
53
|
+
specified, the ${$t('default')} task will be executed.
|
|
41
54
|
|
|
55
|
+
${$bnd('Watch Mode:')}
|
|
56
|
+
|
|
57
|
+
The ${$wnd('--watch')} option can be specified multiple times, and each single
|
|
58
|
+
directory specified will be watched for changes. Note that Plug's own
|
|
59
|
+
watch mode is incredibly basic, for more complex scenarios use something
|
|
60
|
+
more advanced like nodemon ${$gry('(')}${$gnd('https://www.npmjs.com/package/nodemon')}${$gry(')')}.
|
|
61
|
+
|
|
62
|
+
${$bnd('TypeScript module format:')}
|
|
63
|
+
|
|
64
|
+
Normally our TypeScript loader will transpile ${$wnd('.ts')} files to the type
|
|
65
|
+
specified in ${$wnd('package.json')}, either ${$wnd('commonjs')} (the default) or ${$wnd('module')}.
|
|
66
|
+
|
|
67
|
+
To force a specific module format use one of the following flags:
|
|
68
|
+
|
|
69
|
+
${$wht('--force-esm')} Force transpilation of ${$wnd('.ts')} files to EcmaScript modules
|
|
70
|
+
${$wht('--force-cjs')} Force transpilation of ${$wnd('.ts')} files to CommonJS modules
|
|
71
|
+
`)
|
|
72
|
+
}
|
|
42
73
|
/* ========================================================================== *
|
|
43
|
-
* ========================================================================== *
|
|
44
74
|
* PARSE COMMAND LINE ARGUMENTS *
|
|
45
|
-
* ========================================================================== *
|
|
46
75
|
* ========================================================================== */
|
|
47
76
|
|
|
48
77
|
/* Parsed and normalised command line options */
|
|
49
78
|
interface CommandLineOptions {
|
|
50
|
-
buildFile:
|
|
79
|
+
buildFile: AbsolutePath,
|
|
51
80
|
watchDirs: string[],
|
|
52
81
|
tasks: string[],
|
|
53
82
|
props: Record<string, string>
|
|
@@ -57,7 +86,7 @@ interface CommandLineOptions {
|
|
|
57
86
|
/** Parse `perocess.argv` and return our normalised command line options */
|
|
58
87
|
export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
59
88
|
/* Yargs-parse our arguments */
|
|
60
|
-
const parsed =
|
|
89
|
+
const parsed = yargsParser(args, {
|
|
61
90
|
configuration: {
|
|
62
91
|
'camel-case-expansion': false,
|
|
63
92
|
'strip-aliased': true,
|
|
@@ -91,7 +120,6 @@ export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
|
91
120
|
let colors: boolean | undefined = undefined
|
|
92
121
|
let file: string | undefined = undefined
|
|
93
122
|
let listOnly = false
|
|
94
|
-
let help = false
|
|
95
123
|
|
|
96
124
|
/* Switcharoo on arguments */
|
|
97
125
|
for (const [ key, value ] of Object.entries(parsed)) {
|
|
@@ -123,69 +151,19 @@ export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
|
123
151
|
listOnly = !! value
|
|
124
152
|
break
|
|
125
153
|
case 'help':
|
|
126
|
-
help
|
|
154
|
+
help()
|
|
155
|
+
process.exit(0)
|
|
127
156
|
break
|
|
128
157
|
case 'version':
|
|
129
|
-
console.log(`
|
|
158
|
+
console.log(`PlugJS ${$gry('ver.')} ${$wnd(version)}`)
|
|
130
159
|
process.exit(0)
|
|
131
160
|
break
|
|
132
161
|
default:
|
|
133
|
-
console.log(`Unsupported option
|
|
162
|
+
console.log(`Unsupported option ${$wnd(key)} (try ${$wnd('--help')})`)
|
|
134
163
|
process.exit(1)
|
|
135
164
|
}
|
|
136
165
|
}
|
|
137
166
|
|
|
138
|
-
/* ======================================================================== *
|
|
139
|
-
* HELP OR NOT *
|
|
140
|
-
* ======================================================================== */
|
|
141
|
-
|
|
142
|
-
/* If help, end here! */
|
|
143
|
-
if (help) {
|
|
144
|
-
console.log(`${$blu}${$und}Usage:${$rst}
|
|
145
|
-
|
|
146
|
-
${$wht}plugjs${$rst} ${$gry}[${$rst}--options${$gry}] [...${$rst}prop=val${$gry}] [...${$rst}tasks${$gry}]${$rst}
|
|
147
|
-
|
|
148
|
-
${$blu}${$und}Options:${$rst}
|
|
149
|
-
|
|
150
|
-
${$wht}-f --file ${$gry}${$und}file${$rst} Specify the build file to use (default "./build.[ts/js/...]")
|
|
151
|
-
${$wht}-w --watch ${$gry}${$und}dir${$rst} Watch for changes on the specified directory and run build
|
|
152
|
-
${$wht}-v --verbose${$rst} Increase logging verbosity
|
|
153
|
-
${$wht}-q --quiet${$rst} Decrease logging verbosity
|
|
154
|
-
${$wht}-c --colors${$rst} Force colorful output (use "--no-colors" to force plain text)
|
|
155
|
-
${$wht}-l --list${$rst} Only list the tasks defined by the build, nothing more!
|
|
156
|
-
${$wht}-h --help${$rst} Help! You're reading it now!
|
|
157
|
-
${$wht} --version${$rst} Version! This one: ${__version}!
|
|
158
|
-
|
|
159
|
-
${$blu}${$und}Properties:${$rst}
|
|
160
|
-
|
|
161
|
-
Any argument in the format "key=value" will be interpeted as a property to
|
|
162
|
-
be injected in the build process (e.g. "mode=production").
|
|
163
|
-
|
|
164
|
-
${$blu}${$und}Tasks:${$rst}
|
|
165
|
-
|
|
166
|
-
Any other argument will be treated as a task name. If no task names are
|
|
167
|
-
specified, the "default" task will be executed.
|
|
168
|
-
|
|
169
|
-
${$blu}${$und}Watch Mode:${$rst}
|
|
170
|
-
|
|
171
|
-
The "-w" option can be specified multiple times, and each single directory
|
|
172
|
-
specified will be watched for changes. Please note that Plug's own watch
|
|
173
|
-
mode is incredibly basic, for more complex scenarios use something more
|
|
174
|
-
advanced like nodemon (https://www.npmjs.com/package/nodemon).
|
|
175
|
-
|
|
176
|
-
${$blu}${$und}TypeScript module format:${$rst}
|
|
177
|
-
|
|
178
|
-
Normally our TypeScript loader will transpile ".ts" files to the "type"
|
|
179
|
-
specified in "package.json", either "commonjs" (the default) or "module".
|
|
180
|
-
|
|
181
|
-
To force a specific module format we can use one of the following flags:
|
|
182
|
-
|
|
183
|
-
${$wht}--force-esm ${$rst} Force transpilation of ".ts" files to EcmaScript modules
|
|
184
|
-
${$wht}--force-cjs ${$rst} Force transpilation of ".ts" files to CommonJS modules
|
|
185
|
-
`)
|
|
186
|
-
process.exit(0)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
167
|
/* ======================================================================== *
|
|
190
168
|
* LOG OPTIONS AS ENVIRONMENT VARIABLES *
|
|
191
169
|
* ======================================================================== */
|
|
@@ -208,13 +186,14 @@ export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
|
208
186
|
* ======================================================================== */
|
|
209
187
|
|
|
210
188
|
/* Find our build file */
|
|
189
|
+
const cwd = getCurrentWorkingDirectory()
|
|
211
190
|
const exts = [ 'ts', 'mts', 'mjs', 'js', 'mjs', 'cjs' ]
|
|
212
191
|
|
|
213
|
-
let buildFile:
|
|
192
|
+
let buildFile: AbsolutePath | undefined = undefined
|
|
214
193
|
|
|
215
194
|
if (file) {
|
|
216
|
-
const absolute =
|
|
217
|
-
if (!
|
|
195
|
+
const absolute = resolveFile(cwd, file)
|
|
196
|
+
if (! absolute) {
|
|
218
197
|
console.log(`Specified build file "${file}" was not found`)
|
|
219
198
|
process.exit(1)
|
|
220
199
|
} else {
|
|
@@ -222,8 +201,8 @@ export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
|
222
201
|
}
|
|
223
202
|
} else {
|
|
224
203
|
for (const ext of exts) {
|
|
225
|
-
const absolute =
|
|
226
|
-
if (!
|
|
204
|
+
const absolute = resolveFile(cwd, `build.${ext}`)
|
|
205
|
+
if (! absolute) continue
|
|
227
206
|
buildFile = absolute
|
|
228
207
|
break
|
|
229
208
|
}
|
|
@@ -231,7 +210,7 @@ export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
|
231
210
|
|
|
232
211
|
/* Final check */
|
|
233
212
|
if (! buildFile) {
|
|
234
|
-
console.log(
|
|
213
|
+
console.log(`${$red('Unable to find build file')} ${$wht(`./build.[${exts.join('|')}]`)}`)
|
|
235
214
|
process.exit(1)
|
|
236
215
|
}
|
|
237
216
|
|
|
@@ -240,9 +219,10 @@ export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
|
240
219
|
* ======================================================================== */
|
|
241
220
|
|
|
242
221
|
watchDirs.forEach((watchDir) => {
|
|
243
|
-
const absolute =
|
|
244
|
-
if (!
|
|
245
|
-
|
|
222
|
+
const absolute = resolveDirectory(cwd, watchDir)
|
|
223
|
+
if (! absolute) {
|
|
224
|
+
const path = resolveAbsolutePath(cwd, watchDir)
|
|
225
|
+
console.log(`Specified watch directory "${$p(path)}" was not found`)
|
|
246
226
|
process.exit(1)
|
|
247
227
|
} else {
|
|
248
228
|
watchDir = absolute
|
|
@@ -257,21 +237,10 @@ export function parseCommandLine(args: string[]): CommandLineOptions {
|
|
|
257
237
|
}
|
|
258
238
|
|
|
259
239
|
/* ========================================================================== *
|
|
260
|
-
* ========================================================================== *
|
|
261
240
|
* MAIN ENTRY POINT *
|
|
262
|
-
* ========================================================================== *
|
|
263
241
|
* ========================================================================== */
|
|
264
242
|
|
|
265
|
-
|
|
266
|
-
* ========================================================================== *
|
|
267
|
-
* PROCESS SETUP *
|
|
268
|
-
* ========================================================================== *
|
|
269
|
-
* ========================================================================== */
|
|
270
|
-
|
|
271
|
-
/* eslint-disable no-console */
|
|
272
|
-
|
|
273
|
-
/* We have everyhing we need to start our asynchronous main! */
|
|
274
|
-
main(async (args: string[]): Promise<void> => {
|
|
243
|
+
main(import.meta.url, async (args: string[]): Promise<void> => {
|
|
275
244
|
// Parse and destructure command line
|
|
276
245
|
const {
|
|
277
246
|
buildFile,
|
|
@@ -293,13 +262,13 @@ main(async (args: string[]): Promise<void> => {
|
|
|
293
262
|
|
|
294
263
|
// We _need_ a build
|
|
295
264
|
if (! isBuild(maybeBuild)) {
|
|
296
|
-
console.log('Build file did not export a proper build')
|
|
265
|
+
console.log($red('Build file did not export a proper build'))
|
|
297
266
|
console.log()
|
|
298
267
|
console.log('- If using CommonJS export your build as "module.exports"')
|
|
299
|
-
console.log(
|
|
268
|
+
console.log(` e.g.: ${$wht('module.exports = build({ ... })')}`)
|
|
300
269
|
console.log()
|
|
301
270
|
console.log('- If using ESM modules export your build as "default"')
|
|
302
|
-
console.log(
|
|
271
|
+
console.log(` e.g.: ${$wht('export default build({ ... })')}`)
|
|
303
272
|
console.log()
|
|
304
273
|
process.exit(1)
|
|
305
274
|
}
|
|
@@ -315,20 +284,18 @@ main(async (args: string[]): Promise<void> => {
|
|
|
315
284
|
(typeof value === 'string' ? propNames : taskNames).push(key)
|
|
316
285
|
}
|
|
317
286
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
console.log(`\n${$gry}Outline of ${$wht}${buildFileName}${$rst}`)
|
|
287
|
+
console.log(`\n${$gry('Outline of')} ${$p(buildFile)}`)
|
|
321
288
|
|
|
322
289
|
console.log('\nKnown tasks:\n')
|
|
323
290
|
for (const taskName of taskNames.sort()) {
|
|
324
|
-
console.log(` ${$gry
|
|
291
|
+
console.log(` ${$gry('\u25a0')} ${$t(taskName)}`)
|
|
325
292
|
}
|
|
326
293
|
|
|
327
294
|
console.log('\nKnown properties:\n')
|
|
328
295
|
for (const propName of propNames.sort()) {
|
|
329
296
|
const value = build[propName] ?
|
|
330
|
-
` ${$gry
|
|
331
|
-
console.log(` ${$gry
|
|
297
|
+
` ${$gry('(default')} ${$und(build[propName])}${$gry(')')}` : ''
|
|
298
|
+
console.log(` ${$gry('\u25a1')} ${$blu(propName)}${value}`)
|
|
332
299
|
}
|
|
333
300
|
|
|
334
301
|
console.log()
|
|
@@ -337,40 +304,47 @@ main(async (args: string[]): Promise<void> => {
|
|
|
337
304
|
|
|
338
305
|
// Watch directories
|
|
339
306
|
if (watchDirs.length) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
console.log(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
307
|
+
return new Promise((_, reject) => {
|
|
308
|
+
// filesystems change trigger a new run after 250 ms a change is detected,
|
|
309
|
+
// in order to give time to editors to save a bunch of files open and
|
|
310
|
+
// modified at the same time...
|
|
311
|
+
let timeout: NodeJS.Timeout | undefined = undefined
|
|
312
|
+
|
|
313
|
+
// our runner executed by the timeout
|
|
314
|
+
const runme = (): void => {
|
|
315
|
+
invokeTasks(build, tasks, props)
|
|
316
|
+
.then(() => {
|
|
317
|
+
console.log(`\n${$gry('Watching for files change...')}\n`)
|
|
318
|
+
}, (error) => {
|
|
319
|
+
if (error instanceof BuildFailure) {
|
|
320
|
+
console.log(`\n${$gry('Watching for files change...')}\n`)
|
|
321
|
+
} else {
|
|
322
|
+
watchers.forEach((watcher) => watcher.close())
|
|
323
|
+
reject(error)
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
.finally(() => {
|
|
327
|
+
timeout = undefined
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// watch all directories and trigger a run after 250 milliseconds
|
|
332
|
+
const watchers = watchDirs.map((watchDir) => {
|
|
333
|
+
return _fs.watch(watchDir, { recursive: true }, () => {
|
|
334
|
+
if (! timeout) timeout = setTimeout(runme, 250)
|
|
335
|
+
})
|
|
362
336
|
})
|
|
363
|
-
})
|
|
364
337
|
|
|
365
|
-
|
|
366
|
-
|
|
338
|
+
// start a build immediately on first run
|
|
339
|
+
runme()
|
|
340
|
+
})
|
|
367
341
|
}
|
|
368
342
|
|
|
369
343
|
// Normal build (no list, no watchers)
|
|
370
344
|
try {
|
|
371
|
-
await build
|
|
345
|
+
await invokeTasks(build, tasks, props)
|
|
372
346
|
} catch (error) {
|
|
373
|
-
if (!
|
|
374
|
-
process.
|
|
347
|
+
if (!(error instanceof BuildFailure)) console.log(error)
|
|
348
|
+
process.exitCode = 1
|
|
375
349
|
}
|
|
376
350
|
})
|
package/src/fork.ts
CHANGED
|
@@ -3,13 +3,24 @@ import { fork } from 'node:child_process'
|
|
|
3
3
|
import { assert, BuildFailure } from './asserts'
|
|
4
4
|
import { runAsync } from './async'
|
|
5
5
|
import { Files } from './files'
|
|
6
|
-
import { $gry, $p, logOptions } from './logging'
|
|
6
|
+
import { $gry, $p, $red, logOptions } from './logging'
|
|
7
7
|
import { requireFilename, resolveFile } from './paths'
|
|
8
8
|
import { Context, install } from './pipe'
|
|
9
9
|
|
|
10
10
|
import type { AbsolutePath } from './paths'
|
|
11
11
|
import type { Plug, PlugName, PlugResult } from './pipe'
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Options accepted by {@link ForkingPlug}'s instrumenting how the process
|
|
15
|
+
* will be spawned (environment variables to be passed to the child process).
|
|
16
|
+
*/
|
|
17
|
+
export interface ForkOptions {
|
|
18
|
+
/** The directory where coverage data will be saved */
|
|
19
|
+
coverageDir?: string,
|
|
20
|
+
/** Force the specified module type when dynamically transpiling TypeScript */
|
|
21
|
+
forceModule?: 'commonjs' | 'module'
|
|
22
|
+
}
|
|
23
|
+
|
|
13
24
|
/** Fork data, from parent to child process */
|
|
14
25
|
export interface ForkData {
|
|
15
26
|
/** Script name for the Plug to execute */
|
|
@@ -75,6 +86,10 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
75
86
|
const dir = env.NODE_V8_COVERAGE = context.resolve(this._arguments[i].coverageDir)
|
|
76
87
|
context.log.debug('Forked process will produce coverage in', $p(dir))
|
|
77
88
|
}
|
|
89
|
+
if (typeof this._arguments[i].forceModule === 'string') {
|
|
90
|
+
const force = env.__TS_LOADER_FORCE_TYPE = this._arguments[i].forceModule
|
|
91
|
+
context.log.debug('Forked process will force module type as', $p(force))
|
|
92
|
+
}
|
|
78
93
|
}
|
|
79
94
|
}
|
|
80
95
|
|
|
@@ -97,24 +112,24 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
97
112
|
let response: ForkResult | undefined = undefined
|
|
98
113
|
|
|
99
114
|
child.on('error', (error) => {
|
|
100
|
-
context.log.error('
|
|
115
|
+
context.log.error('Forked plug process error', error)
|
|
101
116
|
return done || reject(BuildFailure.fail())
|
|
102
117
|
})
|
|
103
118
|
|
|
104
119
|
child.on('message', (message: ForkResult) => {
|
|
105
|
-
context.log.debug('Message from
|
|
120
|
+
context.log.debug('Message from forked plug process with PID', child.pid, message)
|
|
106
121
|
response = message
|
|
107
122
|
})
|
|
108
123
|
|
|
109
124
|
child.on('exit', (code, signal) => {
|
|
110
125
|
if (signal) {
|
|
111
|
-
context.log.error(`
|
|
126
|
+
context.log.error(`Forked plug process exited with signal ${signal}`, $gry(`(pid=${child.pid})`))
|
|
112
127
|
return done || reject(BuildFailure.fail())
|
|
113
128
|
} else if (code !== 0) {
|
|
114
|
-
context.log.error(`
|
|
129
|
+
context.log.error(`Forked plug process exited with code ${code}`, $gry(`(pid=${child.pid})`))
|
|
115
130
|
return done || reject(BuildFailure.fail())
|
|
116
131
|
} else if (! response) {
|
|
117
|
-
context.log.error('
|
|
132
|
+
context.log.error('Forked plug process exited with no result', $gry(`(pid=${child.pid})`))
|
|
118
133
|
return done || reject(BuildFailure.fail())
|
|
119
134
|
} else if (response.failed) {
|
|
120
135
|
// definitely logged on the child side
|
|
@@ -131,16 +146,16 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
131
146
|
try {
|
|
132
147
|
const result = child.send(request, (error) => {
|
|
133
148
|
if (error) {
|
|
134
|
-
context.log.error('Error sending message to
|
|
149
|
+
context.log.error('Error sending message to forked plug process (callback failure)', error)
|
|
135
150
|
reject(BuildFailure.fail())
|
|
136
151
|
}
|
|
137
152
|
})
|
|
138
153
|
if (! result) {
|
|
139
|
-
context.log.error('Error sending message to
|
|
154
|
+
context.log.error('Error sending message to forked plug process (send returned false)')
|
|
140
155
|
reject(BuildFailure.fail())
|
|
141
156
|
}
|
|
142
157
|
} catch (error) {
|
|
143
|
-
context.log.error('Error sending message to
|
|
158
|
+
context.log.error('Error sending message to forked plug process (exception caught)', error)
|
|
144
159
|
reject(BuildFailure.fail())
|
|
145
160
|
}
|
|
146
161
|
}).finally(() => done = true)
|
|
@@ -158,6 +173,16 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
158
173
|
* for the message and respond once the plug returns _something_!
|
|
159
174
|
*/
|
|
160
175
|
if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
|
|
176
|
+
/* Unhandled exceptions and graceful termination */
|
|
177
|
+
process.on('uncaughtException', (error, origin) => {
|
|
178
|
+
// eslint-disable-next-line no-console
|
|
179
|
+
console.error(
|
|
180
|
+
$red('\n= UNCAUGHT EXCEPTION ========================================='),
|
|
181
|
+
`\nError (${origin}):`, error,
|
|
182
|
+
`\nNode.js ${process.version} (pid=${process.pid})\n`)
|
|
183
|
+
process.nextTick(() => process.exit(3))
|
|
184
|
+
})
|
|
185
|
+
|
|
161
186
|
/* If we haven't processed our message in 5 seconds, fail _badly_ */
|
|
162
187
|
const timeout = setTimeout(() => {
|
|
163
188
|
// eslint-disable-next-line no-console
|
|
@@ -228,6 +253,14 @@ if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
|
|
|
228
253
|
promise.then(() => {
|
|
229
254
|
context.log.debug('Forked plug exiting')
|
|
230
255
|
process.disconnect()
|
|
256
|
+
process.exitCode = 0
|
|
257
|
+
}, (error) => {
|
|
258
|
+
// eslint-disable-next-line no-console
|
|
259
|
+
console.log('\n\nError sending message back to parent process', error)
|
|
260
|
+
process.exitCode = 1
|
|
261
|
+
}).finally(() => {
|
|
262
|
+
/* Flush and end our log output */
|
|
263
|
+
logOptions.output.end()
|
|
231
264
|
|
|
232
265
|
/* Set a timeout _forcefully_ killing the process in 5 seconds */
|
|
233
266
|
setTimeout(() => {
|
|
@@ -235,13 +268,6 @@ if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
|
|
|
235
268
|
console.log('\n\nProcess %d for %s did not exit in 5 seconds', process.pid, exportName)
|
|
236
269
|
process.exit(2)
|
|
237
270
|
}, 5000).unref()
|
|
238
|
-
|
|
239
|
-
/* Set the process exit code and let node exit gracefully */
|
|
240
|
-
process.exitCode = 0
|
|
241
|
-
}, (error) => {
|
|
242
|
-
// eslint-disable-next-line no-console
|
|
243
|
-
console.log('\n\nError sending message back to parent process', error)
|
|
244
|
-
process.exit(1)
|
|
245
271
|
})
|
|
246
272
|
})
|
|
247
273
|
}
|
package/src/helpers.ts
CHANGED
|
@@ -7,14 +7,23 @@ import { requireContext } from './async'
|
|
|
7
7
|
import { Files } from './files'
|
|
8
8
|
import { rm } from './fs'
|
|
9
9
|
import { $p, log } from './logging'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
commonPath,
|
|
12
|
+
getAbsoluteParent,
|
|
13
|
+
getCurrentWorkingDirectory,
|
|
14
|
+
resolveDirectory,
|
|
15
|
+
resolveFile,
|
|
16
|
+
} from './paths'
|
|
11
17
|
import { PipeImpl } from './pipe'
|
|
18
|
+
import { RunBuild } from './plugs/build'
|
|
12
19
|
import { execChild } from './utils/exec'
|
|
13
20
|
import { parseOptions } from './utils/options'
|
|
14
21
|
import { walk } from './utils/walk'
|
|
15
22
|
|
|
23
|
+
import type { ForkOptions } from './fork'
|
|
16
24
|
import type { Pipe } from './index'
|
|
17
25
|
import type { AbsolutePath } from './paths'
|
|
26
|
+
import type { Context } from './pipe'
|
|
18
27
|
import type { ExecChildOptions } from './utils/exec'
|
|
19
28
|
import type { ParseOptions } from './utils/options'
|
|
20
29
|
import type { WalkOptions } from './utils/walk'
|
|
@@ -29,6 +38,11 @@ export interface FindOptions extends WalkOptions {
|
|
|
29
38
|
directory?: string
|
|
30
39
|
}
|
|
31
40
|
|
|
41
|
+
/** Return the current execution {@link Context} */
|
|
42
|
+
export function context(): Context {
|
|
43
|
+
return requireContext()
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
/** Find files in the current directory using the specified _glob_. */
|
|
33
47
|
export function find(glob: string): Pipe
|
|
34
48
|
/** Find files in the current directory using the specified _globs_. */
|
|
@@ -56,6 +70,44 @@ export function find(...args: ParseOptions<FindOptions>): Pipe {
|
|
|
56
70
|
}))
|
|
57
71
|
}
|
|
58
72
|
|
|
73
|
+
export type InvokeBuildOptions = ForkOptions & Record<string, string>
|
|
74
|
+
export type InvokeBuildTasks = string | [ string, ...string[] ]
|
|
75
|
+
|
|
76
|
+
export function invokeBuild(buildFile: string): Promise<void>
|
|
77
|
+
export function invokeBuild(buildFile: string, task: string): Promise<void>
|
|
78
|
+
export function invokeBuild(buildFile: string, task: string, options: InvokeBuildOptions): Promise<void>
|
|
79
|
+
export function invokeBuild(buildFile: string, tasks: [ string, ...string[] ]): Promise<void>
|
|
80
|
+
export function invokeBuild(buildFile: string, tasks: [ string, ...string[] ], options: InvokeBuildOptions): Promise<void>
|
|
81
|
+
export function invokeBuild(buildFile: string, options: InvokeBuildOptions): Promise<void>
|
|
82
|
+
export async function invokeBuild(
|
|
83
|
+
buildFile: string,
|
|
84
|
+
tasksOrOptions?: string | [ string, ...string[] ] | InvokeBuildOptions,
|
|
85
|
+
maybeOptions?: InvokeBuildOptions,
|
|
86
|
+
): Promise<void> {
|
|
87
|
+
const [ tasks, options = {} ] =
|
|
88
|
+
typeof tasksOrOptions === 'string' ?
|
|
89
|
+
[ [ tasksOrOptions ], maybeOptions ] :
|
|
90
|
+
Array.isArray(tasksOrOptions) ?
|
|
91
|
+
[ tasksOrOptions, maybeOptions ] :
|
|
92
|
+
typeof tasksOrOptions === 'object' ?
|
|
93
|
+
[ [ 'default' ], tasksOrOptions ] :
|
|
94
|
+
[ [ 'default' ], {} ]
|
|
95
|
+
|
|
96
|
+
if (tasks.length === 0) tasks.push('default')
|
|
97
|
+
|
|
98
|
+
const { coverageDir, forceModule, ...props } = options
|
|
99
|
+
const forkOptions = { coverageDir, forceModule }
|
|
100
|
+
|
|
101
|
+
const context = requireContext()
|
|
102
|
+
const file = context.resolve(buildFile)
|
|
103
|
+
const dir = getAbsoluteParent(file)
|
|
104
|
+
const files = Files.builder(dir).add(file).build()
|
|
105
|
+
|
|
106
|
+
return new RunBuild(tasks, props, forkOptions)
|
|
107
|
+
.pipe(files, context)
|
|
108
|
+
.then(() => void 0)
|
|
109
|
+
}
|
|
110
|
+
|
|
59
111
|
/**
|
|
60
112
|
* Recursively remove the specified directory _**(use with care)**_.
|
|
61
113
|
*/
|
package/src/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface Pipe extends Promise<Files> {
|
|
|
28
28
|
|
|
29
29
|
// Submodule exports (our package.json exports)
|
|
30
30
|
export * as asserts from './asserts'
|
|
31
|
+
export * as async from './async'
|
|
31
32
|
export * as files from './files'
|
|
32
33
|
export * as fork from './fork'
|
|
33
34
|
export * as fs from './fs'
|
|
@@ -37,7 +38,7 @@ export * as pipe from './pipe'
|
|
|
37
38
|
export * as utils from './utils'
|
|
38
39
|
|
|
39
40
|
// Individual utilities
|
|
40
|
-
export { log, $ms, $p, $t, $blu, $cyn, $grn, $gry, $mgt, $red, $und, $wht, $ylw } from './logging'
|
|
41
|
+
export { banner, log, $ms, $p, $t, $blu, $cyn, $grn, $gry, $mgt, $red, $und, $wht, $ylw } from './logging'
|
|
41
42
|
export { assert, fail, BuildFailure } from './asserts'
|
|
42
43
|
|
|
43
44
|
// Our minimal exports
|
package/src/logging/emit.ts
CHANGED
|
@@ -42,8 +42,8 @@ export type LogEmitter = (options: LogEmitterOptions, args: any[]) => void
|
|
|
42
42
|
|
|
43
43
|
/** Emit in full colors! */
|
|
44
44
|
export const emitColor: LogEmitter = (options: LogEmitterOptions, args: any[]): void => {
|
|
45
|
-
const { taskName, level, prefix, indent } = options
|
|
46
|
-
const logPrefix =
|
|
45
|
+
const { taskName, level, prefix = '', indent = 0 } = options
|
|
46
|
+
const logPrefix = ''.padStart(indent * _indentSize) + prefix
|
|
47
47
|
|
|
48
48
|
/* Prefixes, to prepend at the beginning of each line */
|
|
49
49
|
const prefixes: string[] = []
|
|
@@ -85,8 +85,8 @@ export const emitColor: LogEmitter = (options: LogEmitterOptions, args: any[]):
|
|
|
85
85
|
|
|
86
86
|
/** Emit in plain text! (no colors) */
|
|
87
87
|
export const emitPlain: LogEmitter = (options: LogEmitterOptions, args: any[]): void => {
|
|
88
|
-
const { taskName, level, prefix, indent } = options
|
|
89
|
-
const logPrefix =
|
|
88
|
+
const { taskName, level, prefix = '', indent = 0 } = options
|
|
89
|
+
const logPrefix = ''.padStart(indent * _indentSize) + prefix
|
|
90
90
|
|
|
91
91
|
const prefixes: string[] = []
|
|
92
92
|
|