@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
package/src/logging/logger.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatWithOptions } from 'node:util'
|
|
2
|
+
|
|
3
|
+
import { BuildFailure } from '../asserts'
|
|
2
4
|
import { emitColor, emitPlain } from './emit'
|
|
3
5
|
import { DEBUG, ERROR, INFO, NOTICE, TRACE, WARN } from './levels'
|
|
4
6
|
import { logOptions } from './options'
|
|
5
7
|
import { ReportImpl } from './report'
|
|
8
|
+
import { $gry } from './colors'
|
|
6
9
|
|
|
7
|
-
import type { LogEmitter } from './emit'
|
|
10
|
+
import type { LogEmitter, LogEmitterOptions } from './emit'
|
|
8
11
|
import type { LogLevel } from './levels'
|
|
9
12
|
import type { Report } from './report'
|
|
10
13
|
|
|
14
|
+
|
|
11
15
|
/* ========================================================================== */
|
|
12
16
|
|
|
13
17
|
/* Initial value of log colors, and subscribe to changes */
|
|
@@ -26,8 +30,6 @@ logOptions.on('changed', ({ defaultTaskName, colors, level }) => {
|
|
|
26
30
|
|
|
27
31
|
/** The basic interface giving access to log facilities. */
|
|
28
32
|
export interface Log {
|
|
29
|
-
/** The current {@link Logger} */
|
|
30
|
-
readonly logger: Logger
|
|
31
33
|
/** Log a `TRACE` message */
|
|
32
34
|
trace(...args: [ any, ...any ]): void
|
|
33
35
|
/** Log a `DEBUG` message */
|
|
@@ -45,7 +47,7 @@ export interface Log {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
/** A {@link Logger} extends the basic {@link Log} adding some state. */
|
|
48
|
-
export interface Logger extends
|
|
50
|
+
export interface Logger extends Log {
|
|
49
51
|
/** The current level for logging. */
|
|
50
52
|
level: LogLevel,
|
|
51
53
|
|
|
@@ -95,7 +97,7 @@ class LoggerImpl implements Logger {
|
|
|
95
97
|
|
|
96
98
|
// The `BuildFailure` is a bit special case
|
|
97
99
|
const params = args.filter((arg) => {
|
|
98
|
-
if (
|
|
100
|
+
if (arg instanceof BuildFailure) {
|
|
99
101
|
// Filter out any previously logged build failure and mark
|
|
100
102
|
if (_loggedFailures.has(arg)) return false
|
|
101
103
|
_loggedFailures.add(arg)
|
|
@@ -198,6 +200,57 @@ class LoggerImpl implements Logger {
|
|
|
198
200
|
}
|
|
199
201
|
|
|
200
202
|
report(title: string): Report {
|
|
201
|
-
|
|
203
|
+
const emitter: LogEmitter = (options: LogEmitterOptions, args: any) => {
|
|
204
|
+
if (this._stack.length) {
|
|
205
|
+
for (const { message, ...extras } of this._stack) {
|
|
206
|
+
this._emitter({ ...options, ...extras }, [ message ])
|
|
207
|
+
}
|
|
208
|
+
this._stack.splice(0)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let { indent = 0, prefix = '' } = options
|
|
212
|
+
prefix = this._indent ? $gry('| ') + prefix : prefix
|
|
213
|
+
indent += this._indent
|
|
214
|
+
this._emitter({ ...options, indent, prefix }, args)
|
|
215
|
+
}
|
|
216
|
+
return new ReportImpl(title, this._task, emitter)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* ========================================================================== */
|
|
221
|
+
|
|
222
|
+
/** Pattern to match ANSI expressions */
|
|
223
|
+
const ansiPattern = '[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]'
|
|
224
|
+
/** Regular expression matching ANSI */
|
|
225
|
+
const ansiRegExp = new RegExp(ansiPattern, 'g')
|
|
226
|
+
|
|
227
|
+
/** A test logger, writing to a buffer always _without_ colors */
|
|
228
|
+
export class TestLogger extends LoggerImpl {
|
|
229
|
+
private _lines: string[] = []
|
|
230
|
+
|
|
231
|
+
constructor() {
|
|
232
|
+
super('', (options: LogEmitterOptions, args: any[]): void => {
|
|
233
|
+
const { prefix = '', indent = 0 } = options
|
|
234
|
+
const linePrefix = ''.padStart(indent * 2) + prefix
|
|
235
|
+
|
|
236
|
+
/* Now for the normal logging of all our parameters */
|
|
237
|
+
formatWithOptions({ colors: false, breakLength: 120 }, ...args)
|
|
238
|
+
.split('\n').forEach((line) => {
|
|
239
|
+
const stripped = line.replaceAll(ansiRegExp, '')
|
|
240
|
+
this._lines.push(`${linePrefix}${stripped}`)
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Return the _current_ buffer for this instance */
|
|
246
|
+
get buffer(): string {
|
|
247
|
+
return this._lines.join('\n')
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Reset the buffer and return any previously buffered text */
|
|
251
|
+
reset(): string {
|
|
252
|
+
const buffer = this.buffer
|
|
253
|
+
this._lines = []
|
|
254
|
+
return buffer
|
|
202
255
|
}
|
|
203
256
|
}
|
package/src/logging/options.ts
CHANGED
|
@@ -96,7 +96,11 @@ class LogOptionsImpl extends EventEmitter implements LogOptions {
|
|
|
96
96
|
* and consumed by the `Exec` plug (which has no other way of communicating)
|
|
97
97
|
*/
|
|
98
98
|
const { fd, ...options } = JSON.parse(process.env.__LOG_OPTIONS || '{}')
|
|
99
|
-
if (fd)
|
|
99
|
+
if (fd) {
|
|
100
|
+
const output = new Socket({ fd, readable: false, writable: true }).unref()
|
|
101
|
+
process.on('beforeExit', () => this._output.end())
|
|
102
|
+
this._output = output
|
|
103
|
+
}
|
|
100
104
|
Object.assign(this, options)
|
|
101
105
|
}
|
|
102
106
|
|
package/src/logging.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { currentContext } from './async'
|
|
2
|
+
import { $gry, $wht } from './logging/colors'
|
|
2
3
|
import { getLogger } from './logging/logger'
|
|
3
4
|
import { setupSpinner } from './logging/spinner'
|
|
4
5
|
|
|
5
|
-
import type {
|
|
6
|
+
import type { Log, Logger } from './logging/logger'
|
|
6
7
|
|
|
7
8
|
export * from './logging/colors'
|
|
8
9
|
export * from './logging/github'
|
|
@@ -32,10 +33,6 @@ export const log: LogFunction = ((): LogFunction => {
|
|
|
32
33
|
|
|
33
34
|
/* Create a Logger wrapping the current logger */
|
|
34
35
|
const wrapper: Log = {
|
|
35
|
-
get logger() {
|
|
36
|
-
return logger()
|
|
37
|
-
},
|
|
38
|
-
|
|
39
36
|
trace(...args: [ any, ...any ]): void {
|
|
40
37
|
logger().trace(...args)
|
|
41
38
|
},
|
|
@@ -71,3 +68,21 @@ export const log: LogFunction = ((): LogFunction => {
|
|
|
71
68
|
/* Return our function, with added Logger implementation */
|
|
72
69
|
return Object.assign(log, wrapper)
|
|
73
70
|
})()
|
|
71
|
+
|
|
72
|
+
/* ========================================================================== *
|
|
73
|
+
* BANNER *
|
|
74
|
+
* ========================================================================== */
|
|
75
|
+
|
|
76
|
+
/** Print a nice _banner_ message on the log */
|
|
77
|
+
export function banner(message: string): void {
|
|
78
|
+
const padMessage = message.length > 60 ? message.length : 60
|
|
79
|
+
const padLines = padMessage + 2
|
|
80
|
+
|
|
81
|
+
log.notice([
|
|
82
|
+
'',
|
|
83
|
+
$gry(`\u2554${''.padStart(padLines, '\u2550')}\u2557`),
|
|
84
|
+
`${$gry('\u2551')} ${$wht(message.padEnd(padMessage, ' '))} ${$gry('\u2551')}`,
|
|
85
|
+
$gry(`\u255A${''.padStart(padLines, '\u2550')}\u255D`),
|
|
86
|
+
'',
|
|
87
|
+
].join('\n'))
|
|
88
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { $p } from '../logging/colors'
|
|
2
|
+
import { ForkingPlug, type ForkOptions } from '../fork'
|
|
3
|
+
import { requireFilename } from '../paths'
|
|
4
|
+
|
|
5
|
+
import type { Files } from '../files'
|
|
6
|
+
import type { Context, Plug } from '../pipe'
|
|
7
|
+
import type { Build } from '../types'
|
|
8
|
+
|
|
9
|
+
/** Writes some info about the current {@link Files} being passed around. */
|
|
10
|
+
export class RunBuildInternal implements Plug<void> {
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly _tasks: readonly string[],
|
|
13
|
+
private readonly _props: Readonly<Record<string, string>>,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
async pipe(files: Files, context: Context): Promise<void> {
|
|
17
|
+
const tasks = this._tasks.length === 0 ? [ 'default' ] : this._tasks
|
|
18
|
+
|
|
19
|
+
for (const file of files.absolutePaths()) {
|
|
20
|
+
// Import and check build file
|
|
21
|
+
let maybeBuild = await import(file)
|
|
22
|
+
while (maybeBuild) {
|
|
23
|
+
if (isBuild(maybeBuild)) break
|
|
24
|
+
maybeBuild = maybeBuild.default
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// We _need_ a build
|
|
28
|
+
if (! isBuild(maybeBuild)) {
|
|
29
|
+
context.log.fail(`File ${$p(file)} did not export a proper build`)
|
|
30
|
+
} else {
|
|
31
|
+
await maybeBuild[buildMarker](tasks, this._props)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Symbol indicating that an object is a {@link Build}. */
|
|
38
|
+
const buildMarker = Symbol.for('plugjs:isBuild')
|
|
39
|
+
|
|
40
|
+
/** Check if the specified build is actually a {@link Build} */
|
|
41
|
+
function isBuild(build: any): build is Build<Record<string, any>> & {
|
|
42
|
+
[buildMarker]: (
|
|
43
|
+
tasks: readonly string[],
|
|
44
|
+
props?: Record<string, string | undefined>,
|
|
45
|
+
) => Promise<void>
|
|
46
|
+
} {
|
|
47
|
+
return build && typeof build[buildMarker] === 'function'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class RunBuild extends ForkingPlug {
|
|
51
|
+
constructor(
|
|
52
|
+
tasks: readonly string[],
|
|
53
|
+
props: Readonly<Record<string, string>>,
|
|
54
|
+
options: ForkOptions,
|
|
55
|
+
) {
|
|
56
|
+
super(requireFilename(__fileurl), [ tasks, props, options ], RunBuildInternal.name)
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface State {
|
|
|
26
26
|
readonly tasks: Tasks
|
|
27
27
|
/** All _properties_ available in this {@link State} */
|
|
28
28
|
readonly props: Props
|
|
29
|
+
/** All _tasks_ that have failed in this {@link State} */
|
|
30
|
+
readonly fails: Set<Task>
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
/* ========================================================================== *
|
package/src/utils/exec.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
1
2
|
import path from 'node:path'
|
|
2
3
|
import readline from 'node:readline'
|
|
3
|
-
import { fork as forkProcess, spawn as spawnProcess } from 'node:child_process'
|
|
4
4
|
|
|
5
5
|
import { assert, BuildFailure } from '../asserts'
|
|
6
|
-
import { $p
|
|
6
|
+
import { $p } from '../logging'
|
|
7
7
|
import { getCurrentWorkingDirectory, resolveDirectory } from '../paths'
|
|
8
8
|
|
|
9
9
|
import type { SpawnOptions } from 'node:child_process'
|
|
@@ -16,8 +16,6 @@ export interface ExecChildOptions {
|
|
|
16
16
|
coverageDir?: string,
|
|
17
17
|
/** Extra environment variables, or overrides for existing ones */
|
|
18
18
|
env?: Record<string, any>,
|
|
19
|
-
/** Whether to _fork_ the process (argument is a javascript file) or not */
|
|
20
|
-
fork?: boolean,
|
|
21
19
|
/** Whether to run the command in a shell (optionally name the shell) */
|
|
22
20
|
shell?: string | boolean,
|
|
23
21
|
/** The current working directory of the process to execute. */
|
|
@@ -32,7 +30,6 @@ export async function execChild(
|
|
|
32
30
|
): Promise<void> {
|
|
33
31
|
const {
|
|
34
32
|
env = {}, // default empty environment
|
|
35
|
-
fork = false, // by default do not fork
|
|
36
33
|
shell = false, // by default do not use a shell
|
|
37
34
|
cwd = undefined, // by default use "process.cwd()"
|
|
38
35
|
coverageDir, // default "undefined" (pass throug from env)
|
|
@@ -42,9 +39,6 @@ export async function execChild(
|
|
|
42
39
|
const childCwd = cwd ? context.resolve(cwd) : getCurrentWorkingDirectory()
|
|
43
40
|
assert(resolveDirectory(childCwd), `Current working directory ${$p(childCwd)} does not exist`)
|
|
44
41
|
|
|
45
|
-
// Check for wrong fork/shell combination
|
|
46
|
-
assert(!(fork && shell), 'Options "fork" and "shell" can not coexist')
|
|
47
|
-
|
|
48
42
|
// Figure out the PATH environment variable
|
|
49
43
|
const childPaths: AbsolutePath[] = []
|
|
50
44
|
|
|
@@ -62,8 +56,7 @@ export async function execChild(
|
|
|
62
56
|
|
|
63
57
|
// Build our environment variables record
|
|
64
58
|
const PATH = childPaths.join(path.delimiter)
|
|
65
|
-
const
|
|
66
|
-
const childEnv: Record<string, string> = { ...process.env, ...env, ...logForkEnv, PATH }
|
|
59
|
+
const childEnv: Record<string, string> = { ...process.env, ...env, PATH }
|
|
67
60
|
|
|
68
61
|
// Instrument coverage directory if needed
|
|
69
62
|
if (coverageDir) childEnv.NODE_V8_COVERAGE = context.resolve(coverageDir)
|
|
@@ -71,19 +64,17 @@ export async function execChild(
|
|
|
71
64
|
// Prepare the options for calling `spawn`
|
|
72
65
|
const childOptions: SpawnOptions = {
|
|
73
66
|
...extraOptions,
|
|
74
|
-
stdio: [ 'ignore', 'pipe', 'pipe'
|
|
67
|
+
stdio: [ 'ignore', 'pipe', 'pipe' ],
|
|
75
68
|
cwd: childCwd,
|
|
76
69
|
env: childEnv,
|
|
77
70
|
shell,
|
|
78
71
|
}
|
|
79
72
|
|
|
80
73
|
// Spawn our subprocess and monitor its stdout/stderr
|
|
81
|
-
context.log.info(
|
|
74
|
+
context.log.info('Executing', [ cmd, ...args ])
|
|
82
75
|
context.log.debug('Child process options', childOptions)
|
|
83
76
|
|
|
84
|
-
const child =
|
|
85
|
-
forkProcess(cmd, args, childOptions) :
|
|
86
|
-
spawnProcess(cmd, args, childOptions)
|
|
77
|
+
const child = spawn(cmd, args, childOptions)
|
|
87
78
|
|
|
88
79
|
try {
|
|
89
80
|
context.log.info('Child process PID', child.pid)
|
|
@@ -99,11 +90,6 @@ export async function execChild(
|
|
|
99
90
|
const err = readline.createInterface(child.stderr)
|
|
100
91
|
err.on('line', (line) => context.log.warn(line ||'\u00a0'))
|
|
101
92
|
}
|
|
102
|
-
|
|
103
|
-
// Log output bypass
|
|
104
|
-
if (child.stdio[4]) {
|
|
105
|
-
child.stdio[4].on('data', (data) => logOptions.output.write(data))
|
|
106
|
-
}
|
|
107
93
|
} catch (error) {
|
|
108
94
|
// If something happens before returning our promise, kill the child...
|
|
109
95
|
child.kill()
|