@plugjs/plug 0.1.3 → 0.2.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/README.md +2 -2
- package/cli/plug.mjs +1397 -0
- package/cli/ts-loader.mjs +273 -0
- package/cli/tsrun.mjs +136 -0
- package/dist/asserts.cjs +6 -3
- package/dist/asserts.cjs.map +1 -1
- package/dist/asserts.d.ts +2 -2
- package/dist/asserts.mjs +6 -3
- package/dist/asserts.mjs.map +1 -1
- package/dist/build.cjs +39 -28
- package/dist/build.cjs.map +2 -2
- package/dist/build.mjs +39 -28
- package/dist/build.mjs.map +2 -2
- package/dist/files.cjs +9 -0
- package/dist/files.cjs.map +1 -1
- package/dist/files.d.ts +2 -2
- package/dist/files.mjs +9 -0
- package/dist/files.mjs.map +1 -1
- package/dist/fork.cjs +12 -10
- package/dist/fork.cjs.map +2 -2
- package/dist/fork.mjs +12 -10
- package/dist/fork.mjs.map +2 -2
- package/dist/fs.cjs +11 -4
- package/dist/fs.cjs.map +1 -1
- package/dist/fs.mjs +7 -4
- package/dist/fs.mjs.map +1 -1
- package/dist/helpers.cjs +5 -2
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.mjs +5 -2
- package/dist/helpers.mjs.map +1 -1
- package/dist/index.cjs +9 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.mjs +4 -1
- package/dist/index.mjs.map +1 -1
- package/dist/logging/levels.cjs.map +1 -1
- package/dist/logging/levels.mjs.map +1 -1
- package/dist/logging/logger.cjs +1 -1
- package/dist/logging/logger.cjs.map +1 -1
- package/dist/logging/logger.mjs +1 -1
- package/dist/logging/logger.mjs.map +1 -1
- package/dist/logging/options.cjs +5 -0
- package/dist/logging/options.cjs.map +1 -1
- package/dist/logging/options.mjs +5 -0
- package/dist/logging/options.mjs.map +1 -1
- package/dist/logging/report.cjs.map +1 -1
- package/dist/logging/report.mjs.map +1 -1
- package/dist/logging/spinner.cjs +12 -0
- package/dist/logging/spinner.cjs.map +1 -1
- package/dist/logging/spinner.mjs +12 -0
- package/dist/logging/spinner.mjs.map +1 -1
- package/dist/paths.cjs.map +1 -1
- package/dist/paths.mjs.map +1 -1
- package/dist/pipe.cjs +34 -0
- package/dist/pipe.cjs.map +1 -1
- package/dist/pipe.mjs +34 -0
- package/dist/pipe.mjs.map +1 -1
- package/dist/plugs/debug.cjs.map +1 -1
- package/dist/plugs/debug.mjs.map +1 -1
- package/dist/plugs/edit.cjs +1 -1
- package/dist/plugs/edit.cjs.map +1 -1
- package/dist/plugs/edit.d.ts +2 -2
- package/dist/plugs/edit.mjs +1 -1
- package/dist/plugs/edit.mjs.map +1 -1
- package/dist/plugs/esbuild/fix-extensions.cjs +4 -0
- package/dist/plugs/esbuild/fix-extensions.cjs.map +1 -1
- package/dist/plugs/esbuild/fix-extensions.mjs.map +1 -1
- package/dist/plugs/esbuild.cjs +6 -2
- package/dist/plugs/esbuild.cjs.map +1 -1
- package/dist/plugs/esbuild.mjs +6 -2
- package/dist/plugs/esbuild.mjs.map +1 -1
- package/dist/plugs/exec.cjs.map +1 -1
- package/dist/plugs/exec.mjs.map +1 -1
- package/dist/plugs/exports.cjs +122 -0
- package/dist/plugs/exports.cjs.map +6 -0
- package/dist/plugs/exports.d.ts +17 -0
- package/dist/plugs/exports.mjs +105 -0
- package/dist/plugs/exports.mjs.map +6 -0
- package/dist/plugs/filter.cjs.map +1 -1
- package/dist/plugs/filter.mjs.map +1 -1
- package/dist/plugs.cjs +1 -0
- package/dist/plugs.cjs.map +1 -1
- package/dist/plugs.d.ts +1 -0
- package/dist/plugs.mjs +1 -0
- package/dist/plugs.mjs.map +1 -1
- package/dist/types.d.ts +7 -5
- package/dist/utils/exec.cjs +9 -0
- package/dist/utils/exec.cjs.map +1 -1
- package/dist/utils/exec.mjs +5 -0
- package/dist/utils/exec.mjs.map +1 -1
- package/dist/utils/match.cjs +5 -0
- package/dist/utils/match.cjs.map +1 -1
- package/dist/utils/match.mjs +1 -0
- package/dist/utils/match.mjs.map +1 -1
- package/dist/utils/options.cjs.map +1 -1
- package/dist/utils/options.mjs.map +1 -1
- package/dist/utils/walk.cjs.map +1 -1
- package/dist/utils/walk.mjs.map +1 -1
- package/extra/plug.mts +373 -0
- package/extra/ts-loader.mts +545 -0
- package/extra/tsrun.mts +64 -0
- package/extra/utils.ts +168 -0
- package/package.json +9 -19
- package/src/asserts.ts +7 -4
- package/src/build.ts +49 -22
- package/src/files.ts +2 -2
- package/src/fork.ts +9 -8
- package/src/helpers.ts +6 -2
- package/src/index.ts +5 -1
- package/src/logging/logger.ts +1 -1
- package/src/plugs/edit.ts +4 -3
- package/src/plugs/esbuild.ts +0 -1
- package/src/plugs/exports.ts +175 -0
- package/src/plugs.ts +1 -0
- package/src/types.ts +9 -7
- package/types/plugjs.d.ts +0 -2
- package/LICENSE.md +0 -211
- package/NOTICE.md +0 -13
- package/extra/cli.mjs +0 -1356
- package/extra/ts-loader.mjs +0 -223
package/extra/utils.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import _childProcess from 'node:child_process'
|
|
3
|
+
import _fs from 'node:fs'
|
|
4
|
+
import _path from 'node:path'
|
|
5
|
+
import _url from 'node:url'
|
|
6
|
+
import _util from 'node:util'
|
|
7
|
+
|
|
8
|
+
/* ========================================================================== *
|
|
9
|
+
* PRETTY COLORS *
|
|
10
|
+
* ========================================================================== */
|
|
11
|
+
|
|
12
|
+
export const $rst = process.stdout.isTTY ? '\u001b[0m' : '' // reset all colors to default
|
|
13
|
+
export const $und = process.stdout.isTTY ? '\u001b[4m' : '' // underline on
|
|
14
|
+
export const $gry = process.stdout.isTTY ? '\u001b[38;5;240m' : '' // somewhat gray
|
|
15
|
+
export const $blu = process.stdout.isTTY ? '\u001b[38;5;69m' : '' // brighter blue
|
|
16
|
+
export const $wht = process.stdout.isTTY ? '\u001b[1;38;5;255m' : '' // full-bright white
|
|
17
|
+
export const $tsk = process.stdout.isTTY ? '\u001b[38;5;141m' : '' // the color for tasks (purple)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/* ========================================================================== *
|
|
21
|
+
* PACKAGE VERSION *
|
|
22
|
+
* ========================================================================== */
|
|
23
|
+
|
|
24
|
+
export function version(): string {
|
|
25
|
+
const debug = _util.debuglog('plug:cli')
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const thisFile = _url.fileURLToPath(import.meta.url)
|
|
29
|
+
const packageFile = _path.resolve(thisFile, '..', '..', 'package.json')
|
|
30
|
+
const packageData = _fs.readFileSync(packageFile, 'utf-8')
|
|
31
|
+
return JSON.parse(packageData).version || '(unknown)'
|
|
32
|
+
} catch (error) {
|
|
33
|
+
debug('Error parsing version:', error)
|
|
34
|
+
return '(error)'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* ========================================================================== *
|
|
39
|
+
* TS LOADER FORCE TYPE *
|
|
40
|
+
* ========================================================================== */
|
|
41
|
+
|
|
42
|
+
function forceType(type: 'commonjs' | 'module'): void {
|
|
43
|
+
const debug = _util.debuglog('plug:cli')
|
|
44
|
+
|
|
45
|
+
const tsLoaderMarker = Symbol.for('plugjs:tsLoader')
|
|
46
|
+
|
|
47
|
+
if (!(tsLoaderMarker in globalThis)) {
|
|
48
|
+
throw new Error('TypeScript Loader not available')
|
|
49
|
+
}
|
|
50
|
+
debug(`Forcing type to "${type}"`)
|
|
51
|
+
;(globalThis as any)[tsLoaderMarker] = type
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
/* ========================================================================== *
|
|
56
|
+
* FILES UTILITIES *
|
|
57
|
+
* ========================================================================== */
|
|
58
|
+
|
|
59
|
+
/* Returns a boolean indicating whether the specified file exists or not */
|
|
60
|
+
export function isFile(path: string): boolean {
|
|
61
|
+
try {
|
|
62
|
+
return _fs.statSync(path).isFile()
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Returns a boolean indicating whether the specified directory exists or not */
|
|
69
|
+
export function isDirectory(path: string): boolean {
|
|
70
|
+
try {
|
|
71
|
+
return _fs.statSync(path).isDirectory()
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/* ========================================================================== *
|
|
79
|
+
* MAIN ENTRY POINT *
|
|
80
|
+
* ========================================================================== */
|
|
81
|
+
export function main(callback: (args: string[]) => void | Promise<void>): void {
|
|
82
|
+
const debug = _util.debuglog('plug:cli')
|
|
83
|
+
|
|
84
|
+
/* Check for source maps and typescript support */
|
|
85
|
+
const sourceMapsEnabled = process.execArgv.indexOf('--enable-source-maps') >= 0
|
|
86
|
+
|
|
87
|
+
/* Check if our `ts-loader` loader is enabled */
|
|
88
|
+
const tsLoaderMarker = Symbol.for('plugjs:tsLoader')
|
|
89
|
+
const typeScriptEnabled = (globalThis as any)[tsLoaderMarker]
|
|
90
|
+
|
|
91
|
+
/* Some debugging if needed */
|
|
92
|
+
debug('SourceMaps enabled =', sourceMapsEnabled)
|
|
93
|
+
debug('TypeScript enabled =', typeScriptEnabled || false)
|
|
94
|
+
|
|
95
|
+
/* If both source maps and typescript are on, run! */
|
|
96
|
+
if (sourceMapsEnabled && typeScriptEnabled) {
|
|
97
|
+
const args = process.argv.slice(2).filter((arg: string): string | void => {
|
|
98
|
+
if (arg === '--force-esm') {
|
|
99
|
+
return forceType('module')
|
|
100
|
+
} else if (arg === '--force-cjs') {
|
|
101
|
+
return forceType('commonjs')
|
|
102
|
+
} else {
|
|
103
|
+
return arg
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
Promise.resolve().then(() => callback(args)).catch(console.error)
|
|
109
|
+
} else {
|
|
110
|
+
const script = _url.fileURLToPath(import.meta.url)
|
|
111
|
+
|
|
112
|
+
/* Fork out ourselves with new options */
|
|
113
|
+
const execArgv = [ ...process.execArgv ]
|
|
114
|
+
|
|
115
|
+
/* Enable source maps if not done already */
|
|
116
|
+
if (! sourceMapsEnabled) execArgv.push('--enable-source-maps')
|
|
117
|
+
|
|
118
|
+
/* Enable our ESM TypeScript loader if not done already */
|
|
119
|
+
if (! typeScriptEnabled) {
|
|
120
|
+
const directory = _path.dirname(script)
|
|
121
|
+
const extension = _path.extname(script) // .mts or .mjs
|
|
122
|
+
const loader = _path.resolve(directory, `ts-loader${extension}`)
|
|
123
|
+
execArgv.push(`--experimental-loader=${loader}`, '--no-warnings')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/*
|
|
127
|
+
* It seems that setting "type" as "module" in "package.json" creates some
|
|
128
|
+
* problems when the module is being imported from a "commonjs" one.
|
|
129
|
+
*
|
|
130
|
+
* TypeScript _incorrectly_ says (regardless of how we set up our conditional
|
|
131
|
+
* exports) that we must use dynamic imports:
|
|
132
|
+
*
|
|
133
|
+
* Module '@plugjs/plug' cannot be imported using this construct. The
|
|
134
|
+
* specifier only resolves to an ES module, which cannot be imported
|
|
135
|
+
* synchronously. Use dynamic import instead.
|
|
136
|
+
* TS(1471)
|
|
137
|
+
*
|
|
138
|
+
* So for now our only option is to leave "type" as "commonjs", and for those
|
|
139
|
+
* brave souls willing to force ESM irregardless of what's in "package.json",
|
|
140
|
+
* we allow the "--force-esm" option, and instruct `ts-loader` that the
|
|
141
|
+
* current directory (and subdirs) will transpile as ESM always.
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
/* Fork ourselves! */
|
|
145
|
+
const child = _childProcess.fork(script, [ ...process.argv.slice(2) ], {
|
|
146
|
+
stdio: [ 'inherit', 'inherit', 'inherit', 'ipc' ],
|
|
147
|
+
execArgv,
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
/* Monitor child process... */
|
|
151
|
+
child.on('error', (error) => {
|
|
152
|
+
console.log('Error respawning CLI', error)
|
|
153
|
+
process.exit(1)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
child.on('exit', (code, signal) => {
|
|
157
|
+
if (signal) {
|
|
158
|
+
console.log(`CLI process exited with signal ${signal}`)
|
|
159
|
+
process.exit(1)
|
|
160
|
+
} else if (typeof code !== 'number') {
|
|
161
|
+
console.log('CLI process failed for an unknown reason')
|
|
162
|
+
process.exit(1)
|
|
163
|
+
} else {
|
|
164
|
+
process.exit(code)
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plugjs/plug",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -98,37 +98,27 @@
|
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
100
|
"bin": {
|
|
101
|
-
"plug": "./
|
|
101
|
+
"plug": "./cli/plug.mjs",
|
|
102
|
+
"tsrun": "./cli/tsrun.mjs"
|
|
102
103
|
},
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
"build": "./bootstrap.sh && ./extra/cli.mjs",
|
|
106
|
-
"dev": "./extra/cli.mjs -w ./src -w ./test"
|
|
107
|
-
},
|
|
108
|
-
"author": "",
|
|
109
|
-
"license": "ISC",
|
|
104
|
+
"author": "Juit Developers <developers@juit.com>",
|
|
105
|
+
"license": "Apache-2.0",
|
|
110
106
|
"dependencies": {
|
|
111
107
|
"@types/node": "<19",
|
|
112
|
-
"esbuild": "^0.
|
|
108
|
+
"esbuild": "^0.17.10",
|
|
113
109
|
"picomatch": "^2.3.1",
|
|
114
|
-
"typescript": "^4.9.
|
|
110
|
+
"typescript": "^4.9.5"
|
|
115
111
|
},
|
|
116
112
|
"devDependencies": {
|
|
117
|
-
"@plugjs/cov8": "^0.1.2",
|
|
118
|
-
"@plugjs/eslint": "^0.1.2",
|
|
119
|
-
"@plugjs/eslint-plugin": "^0.1.1",
|
|
120
|
-
"@plugjs/jasmine": "^0.1.2",
|
|
121
|
-
"@plugjs/typescript": "^0.1.2",
|
|
122
113
|
"@types/picomatch": "^2.3.0",
|
|
123
114
|
"@types/yargs-parser": "^21.0.0",
|
|
124
|
-
"chai": "^4.3.7",
|
|
125
|
-
"chai-as-promised": "^7.1.1",
|
|
126
115
|
"yargs-parser": "^21.1.1"
|
|
127
116
|
},
|
|
128
117
|
"files": [
|
|
129
118
|
"*.md",
|
|
119
|
+
"cli/",
|
|
130
120
|
"dist/",
|
|
131
|
-
"extra
|
|
121
|
+
"extra/",
|
|
132
122
|
"src/",
|
|
133
123
|
"types/"
|
|
134
124
|
]
|
package/src/asserts.ts
CHANGED
|
@@ -12,17 +12,20 @@ export function isBuildFailure(arg: any): arg is BuildFailure {
|
|
|
12
12
|
|
|
13
13
|
/** A {@link BuildFailure} represents an error _already logged_ in our build. */
|
|
14
14
|
export class BuildFailure extends Error {
|
|
15
|
-
readonly errors
|
|
15
|
+
readonly errors?: readonly any[] | undefined
|
|
16
16
|
|
|
17
17
|
/** Construct a {@link BuildFailure} */
|
|
18
|
-
|
|
18
|
+
constructor(message?: string | undefined, errors: any[] = []) {
|
|
19
19
|
super(message || '')
|
|
20
20
|
|
|
21
|
-
/* Basic error setup
|
|
21
|
+
/* Basic error setup: stack and errors */
|
|
22
22
|
Error.captureStackTrace(this, BuildFailure)
|
|
23
|
+
if (errors.length) this.errors = Object.freeze([ ...errors ])
|
|
24
|
+
|
|
25
|
+
/* Other properties: marker and name */
|
|
23
26
|
Object.defineProperties(this, {
|
|
24
|
-
'errors': { value: Object.freeze([ ...errors ]) },
|
|
25
27
|
[buildFailure]: { value: buildFailure },
|
|
28
|
+
'name': { value: 'BuildFailure' },
|
|
26
29
|
})
|
|
27
30
|
}
|
|
28
31
|
|
package/src/build.ts
CHANGED
|
@@ -23,30 +23,40 @@ import type {
|
|
|
23
23
|
* TASK *
|
|
24
24
|
* ========================================================================== */
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
public readonly buildFile: AbsolutePath,
|
|
29
|
-
public readonly tasks: Tasks,
|
|
30
|
-
public readonly props: Props,
|
|
31
|
-
private readonly _def: TaskDef,
|
|
32
|
-
) {}
|
|
26
|
+
/** Symbol indicating that an object is a {@link Task} */
|
|
27
|
+
const taskMarker = Symbol.for('plugjs:isTask')
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
/** Type guard for {@link Tasks} */
|
|
30
|
+
function isTask(something: any): something is Task {
|
|
31
|
+
return something[taskMarker] === true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Create a new {@link Task} instance */
|
|
35
|
+
function makeTask(
|
|
36
|
+
buildFile: AbsolutePath,
|
|
37
|
+
tasks: Tasks,
|
|
38
|
+
props: Props,
|
|
39
|
+
_def: TaskDef,
|
|
40
|
+
_name: string,
|
|
41
|
+
): Task {
|
|
42
|
+
/* Invoke the task, checking call stack, caches, and merging builds */
|
|
43
|
+
function invoke(state: State, taskName: string): Promise<Result> {
|
|
44
|
+
assert(! state.stack.includes(task), `Recursion detected calling ${$t(taskName)}`)
|
|
36
45
|
|
|
37
46
|
/* Check cache */
|
|
38
|
-
const cached = state.cache.get(
|
|
47
|
+
const cached = state.cache.get(task)
|
|
39
48
|
if (cached) return cached
|
|
40
49
|
|
|
41
50
|
/* Create new substate merging sibling tasks/props and adding this to the stack */
|
|
42
|
-
const props: Record<string, string> = Object.assign({},
|
|
43
|
-
const tasks: Record<string, Task> = Object.assign({},
|
|
44
|
-
const stack = [ ...state.stack,
|
|
51
|
+
const props: Record<string, string> = Object.assign({}, task.props, state.props)
|
|
52
|
+
const tasks: Record<string, Task> = Object.assign({}, task.tasks, state.tasks)
|
|
53
|
+
const stack = [ ...state.stack, task ]
|
|
45
54
|
const cache = state.cache
|
|
46
55
|
|
|
47
56
|
/* Create run context and build */
|
|
48
|
-
const context = new Context(
|
|
57
|
+
const context = new Context(task.buildFile, taskName)
|
|
49
58
|
|
|
59
|
+
/* The build (the `this` value calling the definition) is a proxy */
|
|
50
60
|
const build = new Proxy({}, {
|
|
51
61
|
get(_: any, name: string): void | string | (() => Pipe) {
|
|
52
62
|
// Tasks first, props might come also from environment
|
|
@@ -68,18 +78,35 @@ class TaskImpl implements Task {
|
|
|
68
78
|
|
|
69
79
|
/* Run asynchronously in an asynchronous context */
|
|
70
80
|
const promise = runAsync(context, taskName, async () => {
|
|
71
|
-
return await
|
|
81
|
+
return await _def.call(build) || undefined
|
|
72
82
|
}).then((result) => {
|
|
73
|
-
|
|
83
|
+
const level = taskName.startsWith('_') ? 'info' : 'notice'
|
|
84
|
+
context.log[level](`Success ${$ms(Date.now() - now)}`)
|
|
74
85
|
return result
|
|
75
86
|
}).catch((error) => {
|
|
76
87
|
throw context.log.fail(`Failure ${$ms(Date.now() - now)}`, error)
|
|
77
88
|
}).finally(() => ContextPromises.wait(context))
|
|
78
89
|
|
|
79
90
|
/* Cache the resulting promise and return it */
|
|
80
|
-
cache.set(
|
|
91
|
+
cache.set(task, promise)
|
|
81
92
|
return promise
|
|
82
93
|
}
|
|
94
|
+
|
|
95
|
+
/* Create the new Task. The function will simply create an empty state */
|
|
96
|
+
const task: Task = Object.assign((overrideProps: Props = {}) => {
|
|
97
|
+
const state: State = {
|
|
98
|
+
cache: new Map<Task, Promise<Result>>(),
|
|
99
|
+
stack: [] as Task[],
|
|
100
|
+
props: Object.assign({}, props, overrideProps),
|
|
101
|
+
tasks: tasks,
|
|
102
|
+
}
|
|
103
|
+
return invoke(state, _name)
|
|
104
|
+
}, { buildFile, tasks, props, invoke })
|
|
105
|
+
|
|
106
|
+
/* Assign the task's marker and name and return it */
|
|
107
|
+
Object.defineProperty(task, taskMarker, { value: true })
|
|
108
|
+
Object.defineProperty(task, 'name', { value: _name })
|
|
109
|
+
return task
|
|
83
110
|
}
|
|
84
111
|
|
|
85
112
|
/* ========================================================================== *
|
|
@@ -100,13 +127,13 @@ export function build<
|
|
|
100
127
|
/* Iterate through all definition extracting properties and tasks */
|
|
101
128
|
for (const [ key, val ] of Object.entries(def)) {
|
|
102
129
|
let len = 0
|
|
103
|
-
if (
|
|
130
|
+
if (isTask(val)) { // this goes first, tasks _are_ functions!
|
|
131
|
+
tasks[key] = val
|
|
132
|
+
len = key.length
|
|
133
|
+
} else if (typeof val === 'string') {
|
|
104
134
|
props[key] = val
|
|
105
135
|
} else if (typeof val === 'function') {
|
|
106
|
-
tasks[key] =
|
|
107
|
-
len = key.length
|
|
108
|
-
} else if (val instanceof TaskImpl) {
|
|
109
|
-
tasks[key] = val
|
|
136
|
+
tasks[key] = makeTask(buildFile, tasks, props, val, key)
|
|
110
137
|
len = key.length
|
|
111
138
|
}
|
|
112
139
|
|
package/src/files.ts
CHANGED
|
@@ -31,8 +31,8 @@ export interface FilesBuilder {
|
|
|
31
31
|
* identifying some _files_ rooted in a given _directory_.
|
|
32
32
|
*/
|
|
33
33
|
export class Files {
|
|
34
|
-
readonly _directory: AbsolutePath
|
|
35
|
-
readonly _files: string[]
|
|
34
|
+
private readonly _directory: AbsolutePath
|
|
35
|
+
private readonly _files: string[]
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Create a new {@link Files} instance rooted in the specified `directory`
|
package/src/fork.ts
CHANGED
|
@@ -53,7 +53,7 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
53
53
|
) {}
|
|
54
54
|
|
|
55
55
|
pipe(files: Files, context: Context): Promise<PlugResult> {
|
|
56
|
-
const
|
|
56
|
+
const request: ForkData = {
|
|
57
57
|
scriptFile: this._scriptFile,
|
|
58
58
|
exportName: this._exportName,
|
|
59
59
|
constructorArgs: this._arguments,
|
|
@@ -93,7 +93,7 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
93
93
|
/* Return a promise from the child process events */
|
|
94
94
|
let done = false // this will be fixed up in "finally" below
|
|
95
95
|
return new Promise<PlugResult>((resolve, reject) => {
|
|
96
|
-
let
|
|
96
|
+
let response: ForkResult | undefined = undefined
|
|
97
97
|
|
|
98
98
|
child.on('error', (error) => {
|
|
99
99
|
context.log.error('Child process error', error)
|
|
@@ -102,7 +102,7 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
102
102
|
|
|
103
103
|
child.on('message', (message: ForkResult) => {
|
|
104
104
|
context.log.debug('Message from child process', message)
|
|
105
|
-
|
|
105
|
+
response = message
|
|
106
106
|
})
|
|
107
107
|
|
|
108
108
|
child.on('exit', (code, signal) => {
|
|
@@ -112,23 +112,23 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
|
|
|
112
112
|
} else if (code !== 0) {
|
|
113
113
|
context.log.error(`Child process exited with code ${code}`, $gry(`(pid=${child.pid})`))
|
|
114
114
|
return done || reject(BuildFailure.fail())
|
|
115
|
-
} else if (!
|
|
115
|
+
} else if (! response) {
|
|
116
116
|
context.log.error('Child process exited with no result', $gry(`(pid=${child.pid})`))
|
|
117
117
|
return done || reject(BuildFailure.fail())
|
|
118
|
-
} else if (
|
|
118
|
+
} else if (response.failed) {
|
|
119
119
|
// definitely logged on the child side
|
|
120
120
|
return done || reject(BuildFailure.fail())
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/* We definitely have a successful result! */
|
|
124
|
-
return done || resolve(
|
|
125
|
-
Files.builder(
|
|
124
|
+
return done || resolve(response.filesDir && response.filesList ?
|
|
125
|
+
Files.builder(response.filesDir).add(...response.filesList).build() :
|
|
126
126
|
undefined)
|
|
127
127
|
})
|
|
128
128
|
|
|
129
129
|
/* After the handlers have been setup, send the message */
|
|
130
130
|
try {
|
|
131
|
-
const result = child.send(
|
|
131
|
+
const result = child.send(request, (error) => {
|
|
132
132
|
if (error) {
|
|
133
133
|
context.log.error('Error sending message to child process (callback failure)', error)
|
|
134
134
|
reject(BuildFailure.fail())
|
|
@@ -200,6 +200,7 @@ if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
|
|
|
200
200
|
assert(typeof Ctor === 'function', `Script ${$p(scriptFile)} does not export a default constructor`)
|
|
201
201
|
} else {
|
|
202
202
|
Ctor = script[exportName]
|
|
203
|
+
if ((! Ctor) && (script.default)) Ctor = script.default[exportName]
|
|
203
204
|
assert(typeof Ctor === 'function', `Script ${$p(scriptFile)} does not export "${exportName}"`)
|
|
204
205
|
}
|
|
205
206
|
|
package/src/helpers.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { mkdtempSync } from 'node:fs'
|
|
1
2
|
import { tmpdir } from 'node:os'
|
|
2
3
|
import { join } from 'node:path'
|
|
3
|
-
import { mkdtempSync } from 'node:fs'
|
|
4
4
|
|
|
5
5
|
import { assert, assertPromises } from './asserts'
|
|
6
6
|
import { requireContext } from './async'
|
|
@@ -101,7 +101,11 @@ export function merge(pipes: (Pipe | Files | Promise<Files>)[]): Pipe {
|
|
|
101
101
|
if (pipes.length === 0) return Files.builder(getCurrentWorkingDirectory()).build()
|
|
102
102
|
|
|
103
103
|
// Await for all pipes / files / files promises
|
|
104
|
-
const
|
|
104
|
+
const awaited = await assertPromises<Files>(pipes)
|
|
105
|
+
const results = awaited.filter((result) => result.length)
|
|
106
|
+
|
|
107
|
+
// No files in anything to be merged? Again send off an empty pipe...
|
|
108
|
+
if (results.length === 0) return Files.builder(getCurrentWorkingDirectory()).build()
|
|
105
109
|
|
|
106
110
|
// Find the common directory between all the Files instances
|
|
107
111
|
const [ firstDir, ...otherDirs ] = results.map((f) => f.directory)
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
import type { Files } from './files'
|
|
7
7
|
import type { Plug, PlugFunction } from './pipe'
|
|
8
8
|
|
|
9
|
+
export { Files } from './files'
|
|
10
|
+
export type { AbsolutePath } from './paths'
|
|
11
|
+
export type { Plug, PlugFunction } from './pipe'
|
|
12
|
+
|
|
9
13
|
/**
|
|
10
14
|
* The {@link Pipe} interface defines a processing pipeline where multiple
|
|
11
15
|
* {@link Plug}s can transform lists of {@link Files}.
|
|
@@ -31,7 +35,7 @@ export * as utils from './utils'
|
|
|
31
35
|
|
|
32
36
|
// Individual utilities
|
|
33
37
|
export { log, $ms, $p, $t, $blu, $cyn, $grn, $gry, $mgt, $red, $und, $wht, $ylw } from './logging'
|
|
34
|
-
export { assert, fail } from './asserts'
|
|
38
|
+
export { assert, fail, BuildFailure } from './asserts'
|
|
35
39
|
|
|
36
40
|
// Our minimal exports
|
|
37
41
|
export * from './build'
|
package/src/logging/logger.ts
CHANGED
|
@@ -99,7 +99,7 @@ class LoggerImpl implements Logger {
|
|
|
99
99
|
_loggedFailures.add(arg)
|
|
100
100
|
|
|
101
101
|
// If the build failure has any root cause, log those
|
|
102
|
-
arg.errors
|
|
102
|
+
arg.errors?.forEach((error) => this._emit(level, [ error ]))
|
|
103
103
|
|
|
104
104
|
// Log this only if it has a message
|
|
105
105
|
if (! arg.message) return false
|
package/src/plugs/edit.ts
CHANGED
|
@@ -2,12 +2,13 @@ import { readFile, writeFile } from '../fs'
|
|
|
2
2
|
import { install } from '../pipe'
|
|
3
3
|
|
|
4
4
|
import type { Files } from '../files'
|
|
5
|
+
import type { AbsolutePath } from '../paths'
|
|
5
6
|
import type { PipeParameters, Plug } from '../pipe'
|
|
6
7
|
|
|
7
8
|
declare module '../index' {
|
|
8
9
|
export interface Pipe {
|
|
9
10
|
/** Edits the content of all files in a pipeline. */
|
|
10
|
-
edit(callback: (content: string) => string | void | Promise<string | void>): Pipe
|
|
11
|
+
edit(callback: (content: string, fileName: AbsolutePath) => string | void | Promise<string | void>): Pipe
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -17,7 +18,7 @@ declare module '../index' {
|
|
|
17
18
|
|
|
18
19
|
/** Edits the content of all files in a pipeline. */
|
|
19
20
|
install('edit', class Edit implements Plug<Files> {
|
|
20
|
-
private readonly _callback: (content: string) => string | void | Promise<string | void>
|
|
21
|
+
private readonly _callback: (content: string, fileName: AbsolutePath) => string | void | Promise<string | void>
|
|
21
22
|
|
|
22
23
|
constructor(...args: PipeParameters<'edit'>) {
|
|
23
24
|
this._callback = args[0]
|
|
@@ -26,7 +27,7 @@ install('edit', class Edit implements Plug<Files> {
|
|
|
26
27
|
async pipe(files: Files): Promise<Files> {
|
|
27
28
|
for (const file of files.absolutePaths()) {
|
|
28
29
|
const data = await readFile(file, 'utf-8')
|
|
29
|
-
const edited = await this._callback(data)
|
|
30
|
+
const edited = await this._callback(data, file)
|
|
30
31
|
if (edited !== undefined) await writeFile(file, edited, 'utf-8')
|
|
31
32
|
}
|
|
32
33
|
return files
|