@plugjs/plug 0.0.26 → 0.1.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.
Files changed (270) hide show
  1. package/dist/{failure.cjs → asserts.cjs} +29 -9
  2. package/dist/asserts.cjs.map +6 -0
  3. package/dist/{failure.d.ts → asserts.d.ts} +4 -1
  4. package/dist/asserts.mjs +51 -0
  5. package/dist/asserts.mjs.map +6 -0
  6. package/dist/async.cjs +2 -2
  7. package/dist/async.cjs.map +1 -1
  8. package/dist/async.mjs +2 -2
  9. package/dist/async.mjs.map +1 -1
  10. package/dist/build.cjs +21 -30
  11. package/dist/build.cjs.map +1 -1
  12. package/dist/build.d.ts +2 -13
  13. package/dist/build.mjs +16 -24
  14. package/dist/build.mjs.map +1 -1
  15. package/dist/files.cjs +3 -3
  16. package/dist/files.cjs.map +1 -1
  17. package/dist/files.mjs +1 -1
  18. package/dist/files.mjs.map +1 -1
  19. package/dist/fork.cjs +35 -30
  20. package/dist/fork.cjs.map +1 -1
  21. package/dist/fork.d.ts +6 -3
  22. package/dist/fork.mjs +18 -13
  23. package/dist/fork.mjs.map +1 -1
  24. package/dist/{utils/asyncfs.cjs → fs.cjs} +6 -6
  25. package/dist/{utils/asyncfs.cjs.map → fs.cjs.map} +2 -2
  26. package/dist/{utils/asyncfs.d.ts → fs.d.ts} +1 -1
  27. package/dist/{utils/asyncfs.mjs → fs.mjs} +3 -3
  28. package/dist/{utils/asyncfs.mjs.map → fs.mjs.map} +2 -2
  29. package/dist/helpers.cjs +21 -14
  30. package/dist/helpers.cjs.map +1 -1
  31. package/dist/helpers.d.ts +24 -1
  32. package/dist/helpers.mjs +13 -7
  33. package/dist/helpers.mjs.map +1 -1
  34. package/dist/index.cjs +36 -6
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.ts +25 -8
  37. package/dist/index.mjs +20 -5
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/{log → logging}/colors.cjs +1 -1
  40. package/dist/{log → logging}/colors.cjs.map +1 -1
  41. package/dist/{log → logging}/colors.d.ts +0 -0
  42. package/dist/{log → logging}/colors.mjs +1 -1
  43. package/dist/{log → logging}/colors.mjs.map +1 -1
  44. package/dist/{log → logging}/emit.cjs +1 -2
  45. package/dist/{log → logging}/emit.cjs.map +2 -2
  46. package/dist/{log → logging}/emit.d.ts +0 -0
  47. package/dist/{log → logging}/emit.mjs +1 -2
  48. package/dist/{log → logging}/emit.mjs.map +2 -2
  49. package/dist/{log → logging}/levels.cjs +1 -1
  50. package/dist/{log → logging}/levels.cjs.map +1 -1
  51. package/dist/{log → logging}/levels.d.ts +0 -0
  52. package/dist/{log → logging}/levels.mjs +1 -1
  53. package/dist/{log → logging}/levels.mjs.map +1 -1
  54. package/dist/{log → logging}/logger.cjs +13 -7
  55. package/dist/logging/logger.cjs.map +6 -0
  56. package/dist/{log → logging}/logger.d.ts +0 -0
  57. package/dist/{log → logging}/logger.mjs +11 -5
  58. package/dist/logging/logger.mjs.map +6 -0
  59. package/dist/{log → logging}/options.cjs +12 -6
  60. package/dist/logging/options.cjs.map +6 -0
  61. package/dist/{log → logging}/options.d.ts +1 -1
  62. package/dist/{log → logging}/options.mjs +12 -6
  63. package/dist/logging/options.mjs.map +6 -0
  64. package/dist/{log → logging}/report.cjs +10 -9
  65. package/dist/{log → logging}/report.cjs.map +2 -2
  66. package/dist/{log → logging}/report.d.ts +0 -0
  67. package/dist/{log → logging}/report.mjs +7 -6
  68. package/dist/{log → logging}/report.mjs.map +2 -2
  69. package/dist/{log → logging}/spinner.cjs +1 -1
  70. package/dist/{log → logging}/spinner.cjs.map +1 -1
  71. package/dist/{log → logging}/spinner.d.ts +0 -0
  72. package/dist/{log → logging}/spinner.mjs +1 -1
  73. package/dist/{log → logging}/spinner.mjs.map +1 -1
  74. package/dist/{log.cjs → logging.cjs} +12 -12
  75. package/dist/{log.cjs.map → logging.cjs.map} +2 -2
  76. package/dist/{log.d.ts → logging.d.ts} +6 -6
  77. package/dist/{log.mjs → logging.mjs} +9 -9
  78. package/dist/{log.mjs.map → logging.mjs.map} +1 -1
  79. package/dist/paths.cjs +5 -5
  80. package/dist/paths.cjs.map +1 -1
  81. package/dist/paths.mjs +1 -1
  82. package/dist/pipe.cjs +10 -13
  83. package/dist/pipe.cjs.map +1 -1
  84. package/dist/pipe.d.ts +6 -12
  85. package/dist/pipe.mjs +6 -9
  86. package/dist/pipe.mjs.map +1 -1
  87. package/dist/plugs/copy.cjs +14 -14
  88. package/dist/plugs/copy.cjs.map +1 -1
  89. package/dist/plugs/copy.d.ts +1 -1
  90. package/dist/plugs/copy.mjs +3 -3
  91. package/dist/plugs/copy.mjs.map +1 -1
  92. package/dist/plugs/debug.cjs +7 -7
  93. package/dist/plugs/debug.cjs.map +1 -1
  94. package/dist/plugs/debug.d.ts +1 -1
  95. package/dist/plugs/debug.mjs +1 -1
  96. package/dist/plugs/edit.cjs +21 -0
  97. package/dist/plugs/edit.cjs.map +6 -0
  98. package/dist/plugs/edit.d.ts +7 -0
  99. package/dist/plugs/edit.mjs +29 -0
  100. package/dist/plugs/edit.mjs.map +6 -0
  101. package/dist/plugs/esbuild/fix-extensions.cjs +4 -4
  102. package/dist/plugs/esbuild/fix-extensions.cjs.map +1 -1
  103. package/dist/plugs/esbuild/fix-extensions.mjs +1 -1
  104. package/dist/plugs/esbuild/fix-extensions.mjs.map +1 -1
  105. package/dist/plugs/esbuild.cjs +19 -14
  106. package/dist/plugs/esbuild.cjs.map +1 -1
  107. package/dist/plugs/esbuild.d.ts +1 -1
  108. package/dist/plugs/esbuild.mjs +8 -3
  109. package/dist/plugs/esbuild.mjs.map +1 -1
  110. package/dist/plugs/exec.cjs +2 -82
  111. package/dist/plugs/exec.cjs.map +2 -2
  112. package/dist/plugs/exec.d.ts +6 -32
  113. package/dist/plugs/exec.mjs +2 -68
  114. package/dist/plugs/exec.mjs.map +1 -1
  115. package/dist/plugs/filter.d.ts +1 -1
  116. package/dist/plugs/rmf.cjs +5 -5
  117. package/dist/plugs/rmf.cjs.map +1 -1
  118. package/dist/plugs/rmf.d.ts +1 -1
  119. package/dist/plugs/rmf.mjs +2 -2
  120. package/dist/plugs/rmf.mjs.map +1 -1
  121. package/dist/plugs.cjs +1 -4
  122. package/dist/plugs.cjs.map +1 -1
  123. package/dist/plugs.d.ts +1 -4
  124. package/dist/plugs.mjs +1 -4
  125. package/dist/plugs.mjs.map +1 -1
  126. package/dist/types.d.ts +1 -1
  127. package/dist/utils/caller.cjs +8 -5
  128. package/dist/utils/caller.cjs.map +1 -1
  129. package/dist/utils/caller.mjs +6 -3
  130. package/dist/utils/caller.mjs.map +1 -1
  131. package/dist/utils/exec.cjs +102 -0
  132. package/dist/utils/exec.cjs.map +6 -0
  133. package/dist/utils/exec.d.ts +15 -0
  134. package/dist/utils/exec.mjs +71 -0
  135. package/dist/utils/exec.mjs.map +6 -0
  136. package/dist/utils/walk.cjs +7 -7
  137. package/dist/utils/walk.cjs.map +1 -1
  138. package/dist/utils/walk.mjs +2 -2
  139. package/dist/utils/walk.mjs.map +1 -1
  140. package/dist/{plugs/tsc.cjs → utils.cjs} +9 -7
  141. package/dist/utils.cjs.map +6 -0
  142. package/dist/utils.d.ts +4 -0
  143. package/dist/utils.mjs +6 -0
  144. package/dist/utils.mjs.map +6 -0
  145. package/extra/cli.mjs +26 -5
  146. package/extra/ts-loader.mjs +2 -2
  147. package/package.json +90 -15
  148. package/src/{assert.ts → asserts.ts} +36 -1
  149. package/src/async.ts +3 -1
  150. package/src/files.ts +1 -1
  151. package/src/fork.ts +19 -11
  152. package/src/{utils/asyncfs.ts → fs.ts} +1 -1
  153. package/src/helpers.ts +40 -8
  154. package/src/index.ts +30 -8
  155. package/src/{log → logging}/colors.ts +0 -0
  156. package/src/{log → logging}/emit.ts +0 -1
  157. package/src/{log → logging}/levels.ts +0 -0
  158. package/src/{log → logging}/logger.ts +13 -4
  159. package/src/{log → logging}/options.ts +11 -7
  160. package/src/{log → logging}/report.ts +10 -9
  161. package/src/{log → logging}/spinner.ts +0 -0
  162. package/src/{log.ts → logging.ts} +7 -7
  163. package/src/paths.ts +1 -1
  164. package/src/pipe.ts +13 -20
  165. package/src/plugs/copy.ts +4 -4
  166. package/src/plugs/debug.ts +2 -2
  167. package/src/plugs/edit.ts +34 -0
  168. package/src/plugs/esbuild/fix-extensions.ts +2 -2
  169. package/src/plugs/esbuild.ts +13 -7
  170. package/src/plugs/exec.ts +8 -129
  171. package/src/plugs/filter.ts +1 -1
  172. package/src/plugs/rmf.ts +3 -3
  173. package/src/plugs.ts +1 -13
  174. package/src/types.ts +1 -1
  175. package/src/utils/caller.ts +6 -3
  176. package/src/utils/exec.ts +112 -0
  177. package/src/utils/walk.ts +3 -3
  178. package/src/utils.ts +4 -0
  179. package/types/{webassembly.d.ts → plugjs.d.ts} +7 -1
  180. package/dist/assert.cjs +0 -52
  181. package/dist/assert.cjs.map +0 -6
  182. package/dist/assert.d.ts +0 -4
  183. package/dist/assert.mjs +0 -26
  184. package/dist/assert.mjs.map +0 -6
  185. package/dist/failure.cjs.map +0 -6
  186. package/dist/failure.mjs +0 -33
  187. package/dist/failure.mjs.map +0 -6
  188. package/dist/log/logger.cjs.map +0 -6
  189. package/dist/log/logger.mjs.map +0 -6
  190. package/dist/log/options.cjs.map +0 -6
  191. package/dist/log/options.mjs.map +0 -6
  192. package/dist/plugs/coverage/analysis.cjs +0 -234
  193. package/dist/plugs/coverage/analysis.cjs.map +0 -6
  194. package/dist/plugs/coverage/analysis.d.ts +0 -104
  195. package/dist/plugs/coverage/analysis.mjs +0 -207
  196. package/dist/plugs/coverage/analysis.mjs.map +0 -6
  197. package/dist/plugs/coverage/report.cjs +0 -218
  198. package/dist/plugs/coverage/report.cjs.map +0 -6
  199. package/dist/plugs/coverage/report.d.ts +0 -53
  200. package/dist/plugs/coverage/report.mjs +0 -203
  201. package/dist/plugs/coverage/report.mjs.map +0 -6
  202. package/dist/plugs/coverage.cjs +0 -137
  203. package/dist/plugs/coverage.cjs.map +0 -6
  204. package/dist/plugs/coverage.d.ts +0 -49
  205. package/dist/plugs/coverage.mjs +0 -120
  206. package/dist/plugs/coverage.mjs.map +0 -6
  207. package/dist/plugs/eslint/runner.cjs +0 -91
  208. package/dist/plugs/eslint/runner.cjs.map +0 -6
  209. package/dist/plugs/eslint/runner.d.ts +0 -8
  210. package/dist/plugs/eslint/runner.mjs +0 -68
  211. package/dist/plugs/eslint/runner.mjs.map +0 -6
  212. package/dist/plugs/eslint.cjs +0 -22
  213. package/dist/plugs/eslint.cjs.map +0 -6
  214. package/dist/plugs/eslint.d.ts +0 -34
  215. package/dist/plugs/eslint.mjs +0 -5
  216. package/dist/plugs/eslint.mjs.map +0 -6
  217. package/dist/plugs/mocha/reporter.cjs +0 -159
  218. package/dist/plugs/mocha/reporter.cjs.map +0 -6
  219. package/dist/plugs/mocha/reporter.d.ts +0 -6
  220. package/dist/plugs/mocha/reporter.mjs +0 -127
  221. package/dist/plugs/mocha/reporter.mjs.map +0 -6
  222. package/dist/plugs/mocha/runner.cjs +0 -82
  223. package/dist/plugs/mocha/runner.cjs.map +0 -6
  224. package/dist/plugs/mocha/runner.d.ts +0 -8
  225. package/dist/plugs/mocha/runner.mjs +0 -53
  226. package/dist/plugs/mocha/runner.mjs.map +0 -6
  227. package/dist/plugs/mocha.cjs +0 -22
  228. package/dist/plugs/mocha.cjs.map +0 -6
  229. package/dist/plugs/mocha.d.ts +0 -37
  230. package/dist/plugs/mocha.mjs +0 -5
  231. package/dist/plugs/mocha.mjs.map +0 -6
  232. package/dist/plugs/tsc/compiler.cjs +0 -74
  233. package/dist/plugs/tsc/compiler.cjs.map +0 -6
  234. package/dist/plugs/tsc/compiler.d.ts +0 -24
  235. package/dist/plugs/tsc/compiler.mjs +0 -43
  236. package/dist/plugs/tsc/compiler.mjs.map +0 -6
  237. package/dist/plugs/tsc/options.cjs +0 -82
  238. package/dist/plugs/tsc/options.cjs.map +0 -6
  239. package/dist/plugs/tsc/options.d.ts +0 -8
  240. package/dist/plugs/tsc/options.mjs +0 -51
  241. package/dist/plugs/tsc/options.mjs.map +0 -6
  242. package/dist/plugs/tsc/report.cjs +0 -90
  243. package/dist/plugs/tsc/report.cjs.map +0 -6
  244. package/dist/plugs/tsc/report.d.ts +0 -5
  245. package/dist/plugs/tsc/report.mjs +0 -59
  246. package/dist/plugs/tsc/report.mjs.map +0 -6
  247. package/dist/plugs/tsc/runner.cjs +0 -124
  248. package/dist/plugs/tsc/runner.cjs.map +0 -6
  249. package/dist/plugs/tsc/runner.d.ts +0 -8
  250. package/dist/plugs/tsc/runner.mjs +0 -95
  251. package/dist/plugs/tsc/runner.mjs.map +0 -6
  252. package/dist/plugs/tsc.cjs.map +0 -6
  253. package/dist/plugs/tsc.d.ts +0 -48
  254. package/dist/plugs/tsc.mjs +0 -5
  255. package/dist/plugs/tsc.mjs.map +0 -6
  256. package/src/failure.ts +0 -43
  257. package/src/plugs/coverage/analysis.ts +0 -400
  258. package/src/plugs/coverage/report.ts +0 -345
  259. package/src/plugs/coverage.ts +0 -213
  260. package/src/plugs/eslint/runner.ts +0 -100
  261. package/src/plugs/eslint.ts +0 -42
  262. package/src/plugs/mocha/reporter.ts +0 -178
  263. package/src/plugs/mocha/runner.ts +0 -66
  264. package/src/plugs/mocha.ts +0 -43
  265. package/src/plugs/tsc/compiler.ts +0 -68
  266. package/src/plugs/tsc/options.ts +0 -100
  267. package/src/plugs/tsc/report.ts +0 -77
  268. package/src/plugs/tsc/runner.ts +0 -133
  269. package/src/plugs/tsc.ts +0 -58
  270. package/types/globals.d.ts +0 -15
@@ -2,7 +2,42 @@
2
2
  * BUILD FAILURES *
3
3
  * ========================================================================== */
4
4
 
5
- import { BuildFailure } from './failure'
5
+ /** A symbol marking {@link BuildFailure} instances */
6
+ const buildFailure = Symbol.for('plugjs:buildFailure')
7
+
8
+ /** Check if the specified argument is a {@link BuildFailure} */
9
+ export function isBuildFailure(arg: any): arg is BuildFailure {
10
+ return arg && arg[buildFailure] === buildFailure
11
+ }
12
+
13
+ /** A {@link BuildFailure} represents an error _already logged_ in our build. */
14
+ export class BuildFailure extends Error {
15
+ readonly errors!: readonly any[]
16
+
17
+ /** Construct a {@link BuildFailure} */
18
+ private constructor(message: string | undefined, errors: any[]) {
19
+ super(message || '')
20
+
21
+ /* Basic error setup, stack and marker */
22
+ Error.captureStackTrace(this, BuildFailure)
23
+ Object.defineProperties(this, {
24
+ 'errors': { value: Object.freeze([ ...errors ]) },
25
+ [buildFailure]: { value: buildFailure },
26
+ })
27
+ }
28
+
29
+ static fail(): BuildFailure {
30
+ return new BuildFailure(undefined, [])
31
+ }
32
+
33
+ static withMessage(message: string): BuildFailure {
34
+ return new BuildFailure(message || undefined, [])
35
+ }
36
+
37
+ static withErrors(errors: any[]): BuildFailure {
38
+ return new BuildFailure(undefined, errors)
39
+ }
40
+ }
6
41
 
7
42
  /** Await and assert that all specified promises were fulfilled */
8
43
  export async function assertPromises<T>(promises: (T | Promise<T>)[]): Promise<T[]> {
package/src/async.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks'
2
2
 
3
+ import { assert } from './asserts'
4
+
3
5
  import type { Context } from './pipe'
4
6
 
5
7
 
@@ -40,7 +42,7 @@ export function currentContext(): Context | undefined {
40
42
  */
41
43
  export function requireContext(): Context {
42
44
  const context = storage.getStore()
43
- if (! context) throw new Error('Unable to retrieve current context')
45
+ assert(context, 'Unable to retrieve current context')
44
46
  return context
45
47
  }
46
48
 
package/src/files.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import { mkdir, writeFile } from './fs'
1
2
  import { assertRelativeChildPath, getAbsoluteParent, resolveAbsolutePath } from './paths'
2
- import { mkdir, writeFile } from './utils/asyncfs'
3
3
 
4
4
  import type { AbsolutePath } from './paths'
5
5
 
package/src/fork.ts CHANGED
@@ -1,14 +1,13 @@
1
1
  import { fork } from 'node:child_process'
2
2
 
3
- import { assert } from './assert'
3
+ import { assert, BuildFailure } from './asserts'
4
4
  import { runAsync } from './async'
5
- import { BuildFailure } from './failure'
6
5
  import { Files } from './files'
7
- import { $gry, $p, logOptions } from './log'
6
+ import { $gry, $p, logOptions } from './logging'
8
7
  import { requireFilename, resolveFile } from './paths'
9
8
  import { Context, install } from './pipe'
10
9
 
11
- import type { LogOptions } from './log'
10
+ import type { LogOptions } from './logging'
12
11
  import type { AbsolutePath } from './paths'
13
12
  import type { Plug, PlugName, PlugResult } from './pipe'
14
13
 
@@ -16,6 +15,8 @@ import type { Plug, PlugName, PlugResult } from './pipe'
16
15
  export interface ForkData {
17
16
  /** Script name for the Plug to execute */
18
17
  scriptFile: AbsolutePath,
18
+ /** Export name in the script for the Plug to execute */
19
+ exportName: string,
19
20
  /** Plug constructor arguments */
20
21
  constructorArgs: any[],
21
22
  /** Task name (for logs) */
@@ -48,11 +49,13 @@ export abstract class ForkingPlug implements Plug<PlugResult> {
48
49
  constructor(
49
50
  private readonly _scriptFile: AbsolutePath,
50
51
  private readonly _arguments: any[],
52
+ private readonly _exportName: string,
51
53
  ) {}
52
54
 
53
55
  pipe(files: Files, context: Context): Promise<PlugResult> {
54
56
  const message: ForkData = {
55
57
  scriptFile: this._scriptFile,
58
+ exportName: this._exportName,
56
59
  constructorArgs: this._arguments,
57
60
  taskName: context.taskName,
58
61
  buildFile: context.buildFile,
@@ -167,6 +170,7 @@ if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
167
170
 
168
171
  const {
169
172
  scriptFile,
173
+ exportName,
170
174
  constructorArgs,
171
175
  taskName,
172
176
  buildFile,
@@ -189,12 +193,15 @@ if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
189
193
  const script = await import(scriptFile)
190
194
 
191
195
  /* Figure out the constructor, in the "default" chain */
192
- let Ctor = script
193
- while (Ctor && (typeof Ctor !== 'function')) Ctor = Ctor.default
194
-
195
- /* Check that we have a proper constructor */
196
- assert(typeof Ctor === 'function',
197
- `Script ${$p(scriptFile)} does not export a default constructor`)
196
+ let Ctor
197
+ if (exportName === 'default') {
198
+ Ctor = script
199
+ while (Ctor && (typeof Ctor !== 'function')) Ctor = Ctor.default
200
+ assert(typeof Ctor === 'function', `Script ${$p(scriptFile)} does not export a default constructor`)
201
+ } else {
202
+ Ctor = script[exportName]
203
+ assert(typeof Ctor === 'function', `Script ${$p(scriptFile)} does not export "${exportName}"`)
204
+ }
198
205
 
199
206
  /* Create the Plug instance and our Files instance */
200
207
  const plug = new Ctor(...constructorArgs) as Plug<PlugResult>
@@ -250,11 +257,12 @@ if ((process.argv[1] === requireFilename(__fileurl)) && (process.send)) {
250
257
  export function installForking<Name extends PlugName>(
251
258
  plugName: Name,
252
259
  scriptFile: AbsolutePath,
260
+ exportName: string = 'default',
253
261
  ): void {
254
262
  /** Extend out our ForkingPlug below */
255
263
  const ctor = class extends ForkingPlug {
256
264
  constructor(...args: any[]) {
257
- super(scriptFile, args)
265
+ super(scriptFile, args, exportName)
258
266
  }
259
267
  }
260
268
 
@@ -1,5 +1,5 @@
1
- import { constants } from 'node:fs'
2
1
  import fsp from 'node:fs/promises'
2
+ import { constants } from 'node:fs'
3
3
 
4
4
  type FsPromises = typeof fsp
5
5
 
package/src/helpers.ts CHANGED
@@ -1,14 +1,17 @@
1
- import { assert, assertPromises } from './assert'
1
+ import { assert, assertPromises } from './asserts'
2
2
  import { requireContext } from './async'
3
3
  import { Files } from './files'
4
- import { $p, log } from './log'
4
+ import { rm } from './fs'
5
+ import { $p, log } from './logging'
5
6
  import { commonPath, getCurrentWorkingDirectory, resolveDirectory, resolveFile } from './paths'
6
- import { Pipe } from './pipe'
7
- import { rm } from './utils/asyncfs'
7
+ import { PipeImpl } from './pipe'
8
+ import { execChild } from './utils/exec'
8
9
  import { parseOptions } from './utils/options'
9
10
  import { walk } from './utils/walk'
10
11
 
12
+ import type { Pipe } from './index'
11
13
  import type { AbsolutePath } from './paths'
14
+ import type { ExecChildOptions } from './utils/exec'
12
15
  import type { ParseOptions } from './utils/options'
13
16
  import type { WalkOptions } from './utils/walk'
14
17
 
@@ -35,7 +38,7 @@ export function find(...args: ParseOptions<FindOptions>): Pipe {
35
38
  const { params: globs, options } = parseOptions(args, {})
36
39
 
37
40
  const context = requireContext()
38
- return new Pipe(context, Promise.resolve().then(async () => {
41
+ return new PipeImpl(context, Promise.resolve().then(async () => {
39
42
  const directory = options.directory ?
40
43
  context.resolve(options.directory) :
41
44
  getCurrentWorkingDirectory()
@@ -88,7 +91,7 @@ export async function rmrf(directory: string): Promise<void> {
88
91
  */
89
92
  export function merge(pipes: (Pipe | Files | Promise<Files>)[]): Pipe {
90
93
  const context = requireContext()
91
- return new Pipe(context, Promise.resolve().then(async () => {
94
+ return new PipeImpl(context, Promise.resolve().then(async () => {
92
95
  // No pipes? Just send off an empty pipe...
93
96
  if (pipes.length === 0) return Files.builder(getCurrentWorkingDirectory()).build()
94
97
 
@@ -97,7 +100,7 @@ export function merge(pipes: (Pipe | Files | Promise<Files>)[]): Pipe {
97
100
 
98
101
  // Find the common directory between all the Files instances
99
102
  const [ firstDir, ...otherDirs ] = results.map((f) => f.directory)
100
- const directory = commonPath(firstDir, ...otherDirs)
103
+ const directory = commonPath(firstDir!, ...otherDirs)
101
104
 
102
105
  // Build our new files instance merging all the results
103
106
  return Files.builder(directory).merge(...results).build()
@@ -121,7 +124,7 @@ export function merge(pipes: (Pipe | Files | Promise<Files>)[]): Pipe {
121
124
  export function noop(): Pipe {
122
125
  const context = requireContext()
123
126
  const files = new Files(getCurrentWorkingDirectory())
124
- return new Pipe(context, Promise.resolve(files))
127
+ return new PipeImpl(context, Promise.resolve(files))
125
128
  }
126
129
 
127
130
  /**
@@ -155,3 +158,32 @@ export function isDirectory(...paths: [ string, ...string[] ]): AbsolutePath | u
155
158
  const path = requireContext().resolve(...paths)
156
159
  return resolveDirectory(path)
157
160
  }
161
+
162
+ /**
163
+ * Execute a command and await for its result from within a task.
164
+ *
165
+ * For example:
166
+ *
167
+ * ```
168
+ * import { exec } from '@plugjs/plugjs'
169
+ *
170
+ * export default build({
171
+ * async runme() {
172
+ * await exec('ls', '-la', '/')
173
+ * // or similarly letting the shell interpret the command
174
+ * await exec('ls -la /', { shell: true })
175
+ * },
176
+ * })
177
+ * ```
178
+ *
179
+ * @param cmd The command to execute
180
+ * @param args Any additional argument for the command to execute
181
+ * @param options Extra {@link ExecChildOptions | options} for process execution
182
+ */
183
+ export function exec(
184
+ cmd: string,
185
+ ...args: [ ...args: string[] ] | [ ...args: string[], options: ExecChildOptions ]
186
+ ): Promise<void> {
187
+ const { params, options } = parseOptions(args)
188
+ return execChild(cmd, params, options, requireContext())
189
+ }
package/src/index.ts CHANGED
@@ -1,18 +1,40 @@
1
1
  // Reference our extra "webassembly" type fix here. As we're using esbuild
2
2
  // everywhere, we want our dependants to have this type known...
3
- /// <reference path="../types/webassembly.d.ts" />
3
+ /// <reference path="../types/plugjs.d.ts" />
4
4
 
5
- export type { AbsolutePath } from './paths'
6
- export type { Files, FilesBuilder } from './files'
5
+ // This is a main constituent of our build system!
6
+ import type { Files } from './files'
7
+ import type { Plug, PlugFunction } from './pipe'
7
8
 
8
- export { BuildFailure } from './failure'
9
- export type { Pipe } from './pipe'
9
+ /**
10
+ * The {@link Pipe} interface defines a processing pipeline where multiple
11
+ * {@link Plug}s can transform lists of {@link Files}.
12
+ */
13
+ export interface Pipe extends Promise<Files> {
14
+ plug(plug: Plug<Files>): Pipe
15
+ plug(plug: PlugFunction<Files>): Pipe
16
+ plug(plug: Plug<void | undefined>): Promise<undefined>
17
+ plug(plug: PlugFunction<void | undefined>): Promise<undefined>
18
+ plug(plug: Plug<Files | void | undefined>): Pipe | Promise<undefined>
19
+ plug(plug: PlugFunction<Files | void | undefined>): Pipe | Promise<undefined>
20
+ }
21
+
22
+ // Submodule exports (our package.json exports)
23
+ export * as asserts from './asserts'
24
+ export * as files from './files'
25
+ export * as fork from './fork'
26
+ export * as fs from './fs'
27
+ export * as logging from './logging'
28
+ export * as paths from './paths'
29
+ export * as pipe from './pipe'
30
+ export * as utils from './utils'
31
+
32
+ // Individual utilities
33
+ export { log } from './logging'
34
+ export { assert } from './asserts'
10
35
 
11
36
  // Our minimal exports
12
- export * from './assert'
13
37
  export * from './build'
14
- export * from './fork'
15
38
  export * from './helpers'
16
- export * from './log'
17
39
  export * from './plugs'
18
40
  export * from './types'
File without changes
@@ -120,7 +120,6 @@ export const emitPlain: LogEmitter = (options: LogEmitterOptions, args: any[]):
120
120
 
121
121
  /* Write each individual line out */
122
122
  for (const line of message.split('\n')) {
123
- _output.write(zapSpinner)
124
123
  _output.write(linePrefix)
125
124
  _output.write(line)
126
125
  _output.write('\n')
File without changes
@@ -1,4 +1,4 @@
1
- import { BuildFailure, isBuildFailure } from '../failure'
1
+ import { BuildFailure, isBuildFailure } from '../asserts'
2
2
  import { emitColor, emitPlain } from './emit'
3
3
  import { DEBUG, ERROR, INFO, NOTICE, TRACE, WARN } from './levels'
4
4
  import { logOptions } from './options'
@@ -74,6 +74,8 @@ export function getLogger(task: string = _defaultTaskName): Logger {
74
74
 
75
75
  /** Cache of loggers by task-name. */
76
76
  const _loggers = new Map<string, Logger>()
77
+ /** Weak set of already logged build failures */
78
+ const _loggedFailures = new WeakSet<BuildFailure>()
77
79
 
78
80
  /** Default implementation of the {@link Logger} interface. */
79
81
  class LoggerImpl implements Logger {
@@ -93,14 +95,21 @@ class LoggerImpl implements Logger {
93
95
  const params = args.filter((arg) => {
94
96
  if (isBuildFailure(arg)) {
95
97
  // Filter out any previously logged build failure and mark
96
- if (arg.logged) return false
97
- arg.logged = true
98
+ if (_loggedFailures.has(arg)) return false
99
+ _loggedFailures.add(arg)
98
100
 
99
101
  // If the build failure has any root cause, log those
100
102
  arg.errors.forEach((error) => this._emit(level, [ error ]))
101
103
 
102
104
  // Log this only if it has a message
103
- return !! arg.message
105
+ if (! arg.message) return false
106
+
107
+ // Log the full error (with stack) if the _default_ level is DEBUG
108
+ if (_level < INFO) return true
109
+
110
+ // Log only the message in other cases
111
+ this._emit(level, [ arg.message ])
112
+ return false
104
113
  } else {
105
114
  return true
106
115
  }
@@ -2,9 +2,9 @@ import { EventEmitter } from 'node:events'
2
2
 
3
3
  import { getLevelNumber, NOTICE } from './levels'
4
4
 
5
- import type { LogLevel, LogLevelString } from './levels'
6
5
  import type { Writable } from 'node:stream'
7
6
  import type { InspectOptions } from 'node:util'
7
+ import type { LogLevel, LogLevelString } from './levels'
8
8
 
9
9
  /* ========================================================================== */
10
10
 
@@ -54,8 +54,10 @@ class LogOptionsImpl extends EventEmitter implements LogOptions {
54
54
  private _output: Writable = process.stderr
55
55
  private _level: LogLevel = NOTICE
56
56
  private _colors = (<NodeJS.WriteStream> this._output).isTTY
57
+ private _colorsSet = false // have colors been set manually?
57
58
  private _spinner = true // by default, the spinner is enabled
58
59
  private _lineLength = (<NodeJS.WriteStream> this._output).columns || 80
60
+ private _lineLengthSet = false // has line length been set manually?
59
61
  private _showSources = true // by default, always show source snippets
60
62
  private _inspectOptions: InspectOptions = {}
61
63
  private _defaultTaskName = ''
@@ -70,10 +72,10 @@ class LogOptionsImpl extends EventEmitter implements LogOptions {
70
72
  this._level = getLevelNumber(process.env.LOG_LEVEL as LogLevelString)
71
73
  }
72
74
 
73
- /* If the `LOG_COLOR` variable is specified, it should be `true` or `false` */
74
- if (process.env.LOG_COLOR) {
75
- if (process.env.LOG_COLOR.toLowerCase() === 'true') this.colors = true
76
- if (process.env.LOG_COLOR.toLowerCase() === 'false') this.colors = false
75
+ /* If the `LOG_COLORS` variable is specified, it should be `true` or `false` */
76
+ if (process.env.LOG_COLORS) {
77
+ if (process.env.LOG_COLORS.toLowerCase() === 'true') this.colors = true
78
+ if (process.env.LOG_COLORS.toLowerCase() === 'false') this.colors = false
77
79
  // Other values don't change the value of `options.colors`
78
80
  }
79
81
 
@@ -106,8 +108,8 @@ class LogOptionsImpl extends EventEmitter implements LogOptions {
106
108
 
107
109
  set output(output: Writable) {
108
110
  this._output = output
109
- this._colors = !! (<NodeJS.WriteStream> output).isTTY
110
- this._lineLength = (<NodeJS.WriteStream> output).columns
111
+ if (! this._colorsSet) this._colors = !! (<NodeJS.WriteStream> output).isTTY
112
+ if (! this._lineLengthSet) this._lineLength = (<NodeJS.WriteStream> output).columns
111
113
  this._notifyListeners()
112
114
  }
113
115
 
@@ -126,6 +128,7 @@ class LogOptionsImpl extends EventEmitter implements LogOptions {
126
128
 
127
129
  set colors(color: boolean) {
128
130
  this._colors = color
131
+ this._colorsSet = true
129
132
  this._notifyListeners()
130
133
  }
131
134
 
@@ -144,6 +147,7 @@ class LogOptionsImpl extends EventEmitter implements LogOptions {
144
147
 
145
148
  set lineLength(lineLength: number) {
146
149
  this._lineLength = lineLength
150
+ this._lineLengthSet = true
147
151
  this._notifyListeners()
148
152
  }
149
153
 
@@ -1,5 +1,5 @@
1
- import { BuildFailure } from '../failure'
2
- import { readFile } from '../utils/asyncfs'
1
+ import { BuildFailure } from '../asserts'
2
+ import { readFile } from '../fs'
3
3
  import { $blu, $cyn, $gry, $red, $und, $wht, $ylw } from './colors'
4
4
  import { ERROR, NOTICE, WARN } from './levels'
5
5
  import { logOptions } from './options'
@@ -336,7 +336,7 @@ export class ReportImpl implements Report {
336
336
 
337
337
  /* Iterate through all our [file,reports] tuple */
338
338
  for (let f = 0; f < entries.length; f ++) {
339
- const { file, records, annotation } = entries[f]
339
+ const { file, records, annotation } = entries[f]!
340
340
  const source = file && file != nul && this._sources.get(file)
341
341
 
342
342
  if ((f === 0) || entries[f - 1]?.records.length) {
@@ -358,7 +358,7 @@ export class ReportImpl implements Report {
358
358
 
359
359
  /* Now get each message and do our magic */
360
360
  for (let r = 0; r < records.length; r ++) {
361
- const { level, messages, tags, line, column, length = 1 } = records[r]
361
+ const { level, messages, tags, line, column, length = 1 } = records[r]!
362
362
 
363
363
  /* Prefix includes line and column */
364
364
  let pfx: string
@@ -382,13 +382,13 @@ export class ReportImpl implements Report {
382
382
 
383
383
  /* Print out our messages, one by one */
384
384
  if (messages.length === 1) {
385
- this._emitter({ ...options, level }, [ $gry(pfx), messages[0].padEnd(mPad), tag ])
385
+ this._emitter({ ...options, level }, [ $gry(pfx), messages[0]!.padEnd(mPad), tag ])
386
386
  } else {
387
387
  for (let m = 0; m < messages.length; m ++) {
388
388
  if (! m) { // first line
389
389
  this._emitter({ ...options, level }, [ $gry(pfx), messages[m] ])
390
390
  } else if (m === messages.length - 1) { // last line
391
- this._emitter({ ...options, level, prefix }, [ messages[m].padEnd(mPad), tag ])
391
+ this._emitter({ ...options, level, prefix }, [ messages[m]!.padEnd(mPad), tag ])
392
392
  } else { // in between lines
393
393
  this._emitter({ ...options, level, prefix }, [ messages[m] ])
394
394
  }
@@ -400,9 +400,10 @@ export class ReportImpl implements Report {
400
400
  if (column) {
401
401
  const $col = level === NOTICE ? $blu : level === WARN ? $ylw : $red
402
402
  const offset = column - 1
403
- const head = $gry(source[line - 1].substring(0, offset))
404
- const body = $und($col(source[line - 1].substring(offset, offset + length)))
405
- const tail = $gry(source[line - 1].substring(offset + length))
403
+ const text = source[line - 1] || ''
404
+ const head = $gry(text.substring(0, offset))
405
+ const body = $und($col(text.substring(offset, offset + length)))
406
+ const tail = $gry(text.substring(offset + length))
406
407
 
407
408
  this._emitter({ ...options, level, prefix }, [ $gry(`| ${head}${body}${tail}`) ])
408
409
  } else {
File without changes
@@ -1,12 +1,12 @@
1
1
  import { currentContext } from './async'
2
- import { getLogger, type Log } from './log/logger'
3
- import { setupSpinner } from './log/spinner'
2
+ import { getLogger, type Log } from './logging/logger'
3
+ import { setupSpinner } from './logging/spinner'
4
4
 
5
- export * from './log/colors'
6
- export * from './log/levels'
7
- export * from './log/logger'
8
- export * from './log/options'
9
- export * from './log/report'
5
+ export * from './logging/colors'
6
+ export * from './logging/levels'
7
+ export * from './logging/logger'
8
+ export * from './logging/options'
9
+ export * from './logging/report'
10
10
 
11
11
  /* ========================================================================== *
12
12
  * INITIALIZATION *
package/src/paths.ts CHANGED
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module'
3
3
  import { dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from 'node:path'
4
4
  import { fileURLToPath, pathToFileURL } from 'node:url'
5
5
 
6
- import { assert } from './assert'
6
+ import { assert } from './asserts'
7
7
 
8
8
  /** A _branded_ `string` representing an _absolute_ path name */
9
9
  export type AbsolutePath = string & { __brand_absolute_path: never }
package/src/pipe.ts CHANGED
@@ -1,13 +1,14 @@
1
1
  import { sep } from 'node:path'
2
2
 
3
- import { assert, assertPromises } from './assert'
4
- import { getLogger } from './log'
3
+ import { assert, assertPromises } from './asserts'
4
+ import { getLogger } from './logging'
5
5
  import { getAbsoluteParent, getCurrentWorkingDirectory, resolveAbsolutePath } from './paths'
6
6
 
7
7
  import type { Files } from './files'
8
- import type { Logger } from './log'
8
+ import type { Logger } from './logging'
9
9
  import type { AbsolutePath } from './paths'
10
10
  import type { Result } from './types'
11
+ import type { Pipe } from './index'
11
12
 
12
13
  /* ========================================================================== *
13
14
  * PLUGS *
@@ -138,27 +139,19 @@ export class ContextPromises {
138
139
  }
139
140
  }
140
141
 
141
- /**
142
- * A class that will be extended by {@link Pipe} where {@link install} will
143
- * add prototype properties from installed {@link Plug}s
144
- */
145
- abstract class PipeProto {
146
- abstract plug(plug: Plug<PlugResult>): Pipe | Promise<undefined>
142
+ /** The default implementation of the {@link Pipe} interface. */
143
+ export interface PipeImpl extends Pipe {
144
+ // used simply for merging types
147
145
  }
148
146
 
149
- /**
150
- * The {@link Pipe} class defines processing pipeline where multiple
151
- * {@link Plug}s can transform lists of {@link Files}.
152
- */
153
- export class Pipe extends PipeProto implements Promise<Files> {
147
+ /** The default implementation of the {@link Pipe} interface. */
148
+ export class PipeImpl implements Pipe {
154
149
  readonly [Symbol.toStringTag] = 'Pipe'
155
150
 
156
151
  constructor(
157
152
  private readonly _context: Context,
158
153
  private readonly _promise: Promise<Result>,
159
154
  ) {
160
- super()
161
-
162
155
  // New "Pipe", remember the promise!
163
156
  ContextPromises.get(_context).hot(_promise)
164
157
  }
@@ -218,7 +211,7 @@ export class Pipe extends PipeProto implements Promise<Files> {
218
211
  ContextPromises.get(this._context).cold(this._promise)
219
212
 
220
213
  // Create and return the new Pipe
221
- return new Pipe(this._context, this._promise.then(async (result) => {
214
+ return new PipeImpl(this._context, this._promise.then(async (result) => {
222
215
  assert(result, 'Unable to extend pipe')
223
216
  const result2 = await plug.pipe(result, this._context)
224
217
  return result2 || undefined
@@ -335,14 +328,14 @@ export function install<
335
328
  Ctor extends PlugConstructor<Name>,
336
329
  >(name: Name, ctor: Ctor): void {
337
330
  /* The function plugging the newly constructed plug in a pipe */
338
- function plug(this: PipeProto, ...args: PipeParameters<Name>): Pipe | Promise<undefined> {
331
+ function plug(this: PipeImpl, ...args: PipeParameters<Name>): Pipe | Promise<undefined> {
339
332
  // eslint-disable-next-line new-cap
340
- return this.plug(new ctor(...args))
333
+ return this.plug(new ctor(...args) as any)
341
334
  }
342
335
 
343
336
  /* Setup name so that stack traces look better */
344
337
  Object.defineProperty(plug, 'name', { value: name })
345
338
 
346
339
  /* Inject the create function in the Pipe's prototype */
347
- Object.defineProperty(PipeProto.prototype, name, { value: plug })
340
+ void Object.defineProperty(PipeImpl.prototype, name, { value: plug })
348
341
  }
package/src/plugs/copy.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { assert } from '../assert'
1
+ import { assert } from '../asserts'
2
2
  import { Files } from '../files'
3
- import { $p } from '../log'
3
+ import { chmod, copyFile, fsConstants, mkdir } from '../fs'
4
+ import { $p } from '../logging'
4
5
  import { assertAbsolutePath, getAbsoluteParent, resolveAbsolutePath } from '../paths'
5
6
  import { install } from '../pipe'
6
- import { chmod, copyFile, fsConstants, mkdir } from '../utils/asyncfs'
7
7
 
8
8
  import type { Context, PipeParameters, Plug } from '../pipe'
9
9
 
@@ -19,7 +19,7 @@ export interface CopyOptions {
19
19
  rename?: (relative: string) => string
20
20
  }
21
21
 
22
- declare module '../pipe' {
22
+ declare module '../index' {
23
23
  export interface Pipe {
24
24
  /**
25
25
  * Copy the curent {@link Files} to a different directory
@@ -1,10 +1,10 @@
1
- import { $gry, $p, $und, $ylw } from '../log'
1
+ import { $gry, $p, $und, $ylw } from '../logging'
2
2
  import { install } from '../pipe'
3
3
 
4
4
  import type { Files } from '../files'
5
5
  import type { Context, PipeParameters, Plug } from '../pipe'
6
6
 
7
- declare module '../pipe' {
7
+ declare module '../index' {
8
8
  export interface Pipe {
9
9
  /** Log some info about the current {@link Files} being passed around. */
10
10
  debug(title?: string): Pipe
@@ -0,0 +1,34 @@
1
+ import { readFile, writeFile } from '../fs'
2
+ import { install } from '../pipe'
3
+
4
+ import type { Files } from '../files'
5
+ import type { PipeParameters, Plug } from '../pipe'
6
+
7
+ declare module '../index' {
8
+ export interface Pipe {
9
+ /** Edits the content of all files in a pipeline. */
10
+ edit(callback: (content: string) => string | void | Promise<string | void>): Pipe
11
+ }
12
+ }
13
+
14
+ /* ========================================================================== *
15
+ * INSTALLATION / IMPLEMENTATION *
16
+ * ========================================================================== */
17
+
18
+ /** Edits the content of all files in a pipeline. */
19
+ install('edit', class Edit implements Plug<Files> {
20
+ private readonly _callback: (content: string) => string | void | Promise<string | void>
21
+
22
+ constructor(...args: PipeParameters<'edit'>) {
23
+ this._callback = args[0]
24
+ }
25
+
26
+ async pipe(files: Files): Promise<Files> {
27
+ for (const file of files.absolutePaths()) {
28
+ const data = await readFile(file, 'utf-8')
29
+ const edited = await this._callback(data)
30
+ if (edited !== undefined) await writeFile(file, edited, 'utf-8')
31
+ }
32
+ return files
33
+ }
34
+ })