@plugjs/plug 0.0.14 → 0.0.15

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 (212) hide show
  1. package/dist/async.cjs +20 -19
  2. package/dist/async.cjs.map +1 -1
  3. package/dist/async.d.ts +9 -9
  4. package/dist/async.mjs +18 -17
  5. package/dist/async.mjs.map +1 -1
  6. package/dist/build.cjs +144 -110
  7. package/dist/build.cjs.map +2 -2
  8. package/dist/build.d.ts +12 -56
  9. package/dist/build.mjs +146 -112
  10. package/dist/build.mjs.map +2 -2
  11. package/dist/files.cjs +2 -16
  12. package/dist/files.cjs.map +1 -1
  13. package/dist/files.d.ts +3 -10
  14. package/dist/files.mjs +3 -17
  15. package/dist/files.mjs.map +1 -1
  16. package/dist/fork.cjs +28 -40
  17. package/dist/fork.cjs.map +1 -1
  18. package/dist/fork.d.ts +6 -27
  19. package/dist/fork.mjs +29 -40
  20. package/dist/fork.mjs.map +1 -1
  21. package/dist/helpers.cjs +61 -63
  22. package/dist/helpers.cjs.map +2 -2
  23. package/dist/helpers.d.ts +15 -37
  24. package/dist/helpers.mjs +61 -64
  25. package/dist/helpers.mjs.map +2 -2
  26. package/dist/index.cjs +3 -2
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +9 -13
  29. package/dist/index.mjs +3 -2
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/log/colors.cjs +3 -1
  32. package/dist/log/colors.cjs.map +1 -1
  33. package/dist/log/colors.d.ts +2 -2
  34. package/dist/log/colors.mjs +3 -1
  35. package/dist/log/colors.mjs.map +1 -1
  36. package/dist/log/emit.d.ts +1 -1
  37. package/dist/log/logger.cjs +4 -0
  38. package/dist/log/logger.cjs.map +1 -1
  39. package/dist/log/logger.d.ts +4 -1
  40. package/dist/log/logger.mjs +4 -0
  41. package/dist/log/logger.mjs.map +1 -1
  42. package/dist/log/options.d.ts +1 -1
  43. package/dist/log/report.cjs +2 -11
  44. package/dist/log/report.cjs.map +1 -1
  45. package/dist/log/report.d.ts +36 -4
  46. package/dist/log/report.mjs +1 -10
  47. package/dist/log/report.mjs.map +1 -1
  48. package/dist/log.cjs +1 -1
  49. package/dist/log.cjs.map +1 -1
  50. package/dist/log.d.ts +6 -6
  51. package/dist/log.mjs +2 -2
  52. package/dist/log.mjs.map +1 -1
  53. package/dist/pipe.cjs +41 -34
  54. package/dist/pipe.cjs.map +1 -1
  55. package/dist/pipe.d.ts +149 -119
  56. package/dist/pipe.mjs +38 -32
  57. package/dist/pipe.mjs.map +1 -1
  58. package/dist/plugs/copy.cjs +15 -25
  59. package/dist/plugs/copy.cjs.map +2 -2
  60. package/dist/plugs/copy.d.ts +14 -13
  61. package/dist/plugs/copy.mjs +15 -17
  62. package/dist/plugs/copy.mjs.map +2 -2
  63. package/dist/plugs/coverage/analysis.d.ts +2 -2
  64. package/dist/plugs/coverage/report.cjs +1 -1
  65. package/dist/plugs/coverage/report.cjs.map +1 -1
  66. package/dist/plugs/coverage/report.d.ts +3 -3
  67. package/dist/plugs/coverage/report.mjs +1 -1
  68. package/dist/plugs/coverage/report.mjs.map +1 -1
  69. package/dist/plugs/coverage.cjs +19 -25
  70. package/dist/plugs/coverage.cjs.map +1 -1
  71. package/dist/plugs/coverage.d.ts +33 -30
  72. package/dist/plugs/coverage.mjs +20 -18
  73. package/dist/plugs/coverage.mjs.map +1 -1
  74. package/dist/plugs/debug.cjs +8 -37
  75. package/dist/plugs/debug.cjs.map +1 -1
  76. package/dist/plugs/debug.d.ts +4 -11
  77. package/dist/plugs/debug.mjs +24 -20
  78. package/dist/plugs/debug.mjs.map +1 -1
  79. package/dist/plugs/esbuild/fix-extensions.mjs +1 -1
  80. package/dist/plugs/esbuild/fix-extensions.mjs.map +1 -1
  81. package/dist/plugs/esbuild.cjs +14 -25
  82. package/dist/plugs/esbuild.cjs.map +1 -1
  83. package/dist/plugs/esbuild.d.ts +11 -16
  84. package/dist/plugs/esbuild.mjs +14 -17
  85. package/dist/plugs/esbuild.mjs.map +1 -1
  86. package/dist/plugs/eslint/runner.cjs +5 -6
  87. package/dist/plugs/eslint/runner.cjs.map +1 -1
  88. package/dist/plugs/eslint/runner.d.ts +6 -20
  89. package/dist/plugs/eslint/runner.mjs +6 -7
  90. package/dist/plugs/eslint/runner.mjs.map +1 -1
  91. package/dist/{task.cjs → plugs/eslint.cjs} +7 -24
  92. package/dist/plugs/eslint.cjs.map +6 -0
  93. package/dist/plugs/eslint.d.ts +34 -0
  94. package/dist/plugs/eslint.mjs +5 -0
  95. package/dist/plugs/eslint.mjs.map +6 -0
  96. package/dist/plugs/exec.cjs +20 -24
  97. package/dist/plugs/exec.cjs.map +1 -1
  98. package/dist/plugs/exec.d.ts +53 -53
  99. package/dist/plugs/exec.mjs +20 -23
  100. package/dist/plugs/exec.mjs.map +1 -1
  101. package/dist/plugs/filter.cjs +9 -19
  102. package/dist/plugs/filter.cjs.map +1 -1
  103. package/dist/plugs/filter.d.ts +21 -15
  104. package/dist/plugs/filter.mjs +10 -12
  105. package/dist/plugs/filter.mjs.map +1 -1
  106. package/dist/plugs/mocha/reporter.cjs +12 -6
  107. package/dist/plugs/mocha/reporter.cjs.map +1 -1
  108. package/dist/plugs/mocha/reporter.d.ts +0 -2
  109. package/dist/plugs/mocha/reporter.mjs +11 -4
  110. package/dist/plugs/mocha/reporter.mjs.map +1 -1
  111. package/dist/plugs/mocha/runner.cjs +4 -5
  112. package/dist/plugs/mocha/runner.cjs.map +1 -1
  113. package/dist/plugs/mocha/runner.d.ts +5 -31
  114. package/dist/plugs/mocha/runner.mjs +5 -6
  115. package/dist/plugs/mocha/runner.mjs.map +1 -1
  116. package/dist/plugs/mocha.cjs +22 -0
  117. package/dist/plugs/mocha.cjs.map +6 -0
  118. package/dist/plugs/mocha.d.ts +35 -0
  119. package/dist/plugs/mocha.mjs +5 -0
  120. package/dist/plugs/mocha.mjs.map +6 -0
  121. package/dist/plugs/rmf.cjs +4 -32
  122. package/dist/plugs/rmf.cjs.map +1 -1
  123. package/dist/plugs/rmf.d.ts +8 -12
  124. package/dist/plugs/rmf.mjs +25 -20
  125. package/dist/plugs/rmf.mjs.map +1 -1
  126. package/dist/plugs/tsc/compiler.d.ts +1 -1
  127. package/dist/plugs/tsc/options.d.ts +1 -1
  128. package/dist/plugs/tsc/report.d.ts +2 -2
  129. package/dist/plugs/tsc/runner.cjs +12 -11
  130. package/dist/plugs/tsc/runner.cjs.map +1 -1
  131. package/dist/plugs/tsc/runner.d.ts +4 -9
  132. package/dist/plugs/tsc/runner.mjs +12 -11
  133. package/dist/plugs/tsc/runner.mjs.map +1 -1
  134. package/dist/plugs/tsc.cjs +7 -0
  135. package/dist/plugs/tsc.cjs.map +6 -0
  136. package/dist/plugs/tsc.d.ts +36 -0
  137. package/dist/plugs/tsc.mjs +15 -0
  138. package/dist/plugs/tsc.mjs.map +6 -0
  139. package/dist/plugs.cjs +3 -5
  140. package/dist/plugs.cjs.map +1 -1
  141. package/dist/plugs.d.ts +10 -17
  142. package/dist/plugs.mjs +3 -5
  143. package/dist/plugs.mjs.map +1 -1
  144. package/dist/types.cjs +19 -0
  145. package/dist/types.cjs.map +6 -0
  146. package/dist/types.d.ts +72 -0
  147. package/dist/types.mjs +1 -0
  148. package/dist/types.mjs.map +6 -0
  149. package/dist/utils/caller.cjs +8 -11
  150. package/dist/utils/caller.cjs.map +2 -2
  151. package/dist/utils/caller.d.ts +2 -7
  152. package/dist/utils/caller.mjs +8 -11
  153. package/dist/utils/caller.mjs.map +2 -2
  154. package/dist/utils/options.cjs +4 -6
  155. package/dist/utils/options.cjs.map +1 -1
  156. package/dist/utils/options.d.ts +16 -15
  157. package/dist/utils/options.mjs +4 -6
  158. package/dist/utils/options.mjs.map +1 -1
  159. package/dist/utils/walk.d.ts +2 -2
  160. package/extra/cli.mjs +31 -20
  161. package/extra/ts-loader.mjs +6 -5
  162. package/package.json +6 -6
  163. package/src/async.ts +27 -19
  164. package/src/files.ts +6 -30
  165. package/src/fork.ts +35 -76
  166. package/src/helpers.ts +89 -101
  167. package/src/index.ts +10 -15
  168. package/src/log/colors.ts +4 -3
  169. package/src/log/emit.ts +4 -4
  170. package/src/log/logger.ts +12 -4
  171. package/src/log/options.ts +1 -1
  172. package/src/log/report.ts +8 -22
  173. package/src/log/spinner.ts +3 -3
  174. package/src/log.ts +9 -9
  175. package/src/paths.ts +1 -1
  176. package/src/pipe.ts +191 -178
  177. package/src/plugs/copy.ts +40 -31
  178. package/src/plugs/coverage/analysis.ts +4 -4
  179. package/src/plugs/coverage/report.ts +6 -5
  180. package/src/plugs/coverage.ts +64 -53
  181. package/src/plugs/debug.ts +22 -27
  182. package/src/plugs/esbuild/fix-extensions.ts +2 -2
  183. package/src/plugs/esbuild.ts +42 -46
  184. package/src/plugs/eslint/runner.ts +16 -31
  185. package/src/plugs/eslint.ts +42 -0
  186. package/src/plugs/exec.ts +93 -82
  187. package/src/plugs/filter.ts +42 -27
  188. package/src/plugs/mocha/reporter.ts +10 -5
  189. package/src/plugs/mocha/runner.ts +12 -38
  190. package/src/plugs/mocha.ts +41 -0
  191. package/src/plugs/rmf.ts +21 -25
  192. package/src/plugs/tsc/compiler.ts +1 -1
  193. package/src/plugs/tsc/options.ts +2 -2
  194. package/src/plugs/tsc/report.ts +2 -2
  195. package/src/plugs/tsc/runner.ts +24 -30
  196. package/src/plugs/tsc.ts +45 -0
  197. package/src/plugs.ts +10 -25
  198. package/src/types.ts +123 -0
  199. package/src/utils/caller.ts +11 -22
  200. package/src/utils/options.ts +49 -17
  201. package/src/utils/walk.ts +4 -4
  202. package/dist/run.cjs +0 -90
  203. package/dist/run.cjs.map +0 -6
  204. package/dist/run.d.ts +0 -89
  205. package/dist/run.mjs +0 -65
  206. package/dist/run.mjs.map +0 -6
  207. package/dist/task.cjs.map +0 -6
  208. package/dist/task.d.ts +0 -15
  209. package/dist/task.mjs +0 -14
  210. package/dist/task.mjs.map +0 -6
  211. package/src/run.ts +0 -159
  212. package/src/task.ts +0 -26
package/src/log.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { currentRun } from './async.js'
2
- import { getLogger, Log } from './log/logger.js'
3
- import { setupSpinner } from './log/spinner.js'
1
+ import { currentContext } from './async'
2
+ import { getLogger, Log } from './log/logger'
3
+ import { setupSpinner } from './log/spinner'
4
4
 
5
- export * from './log/colors.js'
6
- export * from './log/levels.js'
7
- export * from './log/logger.js'
8
- export * from './log/options.js'
9
- export * from './log/report.js'
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'
10
10
 
11
11
  /* ========================================================================== *
12
12
  * INITIALIZATION *
@@ -25,7 +25,7 @@ export type LogFunction = ((...args: [ any, ...any ]) => void) & Log
25
25
  /** Our logging function (defaulting to the `NOTICE` level) */
26
26
  export const log: LogFunction = ((): LogFunction => {
27
27
  /* Return either the current run's log, or the default task's logger */
28
- const logger = (): Log => (currentRun()?.log || getLogger())
28
+ const logger = (): Log => (currentContext()?.log || getLogger())
29
29
 
30
30
  /* Create a Logger wrapping the current logger */
31
31
  const wrapper: Log = {
package/src/paths.ts CHANGED
@@ -2,7 +2,7 @@ import { statSync } from 'node:fs'
2
2
  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
- import { assert } from './assert.js'
5
+ import { assert } from './assert'
6
6
 
7
7
  /** A _branded_ `string` representing an _absolute_ path name */
8
8
  export type AbsolutePath = string & { __brand_absolute_path: never }
package/src/pipe.ts CHANGED
@@ -1,195 +1,172 @@
1
- import { assert } from './assert.js'
2
- import { Files } from './files.js'
3
- import { Run } from './run.js'
1
+ import type { Files } from './files'
2
+ import { getLogger, Logger } from './log'
3
+ import { AbsolutePath, getAbsoluteParent, getCurrentWorkingDirectory, resolveAbsolutePath } from './paths'
4
4
 
5
- /**
6
- * The {@link Plug} interface describes an extension mechanism for our build.
7
- */
8
- export interface Plug<T extends Files | undefined> {
9
- pipe(files: Files, run: Run): T | Promise<T>
10
- }
5
+ import { ForkingPlug } from './fork'
6
+ import { sep } from 'path'
11
7
 
12
- /**
13
- * A type identifying a {@link Plug} as a `function`
14
- */
15
- export type PlugFunction<T extends Files | undefined> = Plug<T>['pipe']
8
+ /* ========================================================================== *
9
+ * PLUGS *
10
+ * ========================================================================== */
16
11
 
17
- /**
18
- * A {@link Pipe} represents a sequence of operations performed by
19
- * a series of {@link Plug | Plugs}.
20
- */
21
- export interface Pipe {
22
- /* Left empty, for definitions of installed plugs as extensions */
23
- }
12
+ /** A convenience type indicating what can be returned by a {@link Plug}. */
13
+ export type PlugResult = Files | undefined | void
24
14
 
25
15
  /**
26
- * The {@link Pipe} abstract class exposes the prototype upon which all
27
- * extension plugs will be installed on.
16
+ * The {@link Plug} interface describes _build plugin_.
17
+ *
18
+ * A {@link Plug} receives a {@link Files} instance in its input (for example
19
+ * a list of _source `.ts` files_) and optionally produces a possibly different
20
+ * list (for example the _compiled `.js` files_).
28
21
  */
29
- export abstract class Pipe implements Pipe {
30
- abstract plug(plug: Plug<Files> | PlugFunction<Files>): Pipe & Promise<Files>
31
- abstract plug(plug: Plug<undefined> | PlugFunction<undefined>): Promise<undefined>
22
+ export interface Plug<T extends PlugResult> {
23
+ pipe(files: Files, context: Context): T | Promise<T>
32
24
  }
33
25
 
26
+ /** A type identifying a {@link Plug} as a `function` */
27
+ export type PlugFunction<T extends PlugResult> = Plug<T>['pipe']
34
28
 
35
- /** Implementation of our {@link Pipe}. */
36
- export class PipeImpl<T extends Files | undefined> extends Pipe implements Promise<T> {
37
- readonly #promise: Promise<T>
38
- readonly #run: Run
29
+ /* ========================================================================== *
30
+ * PLUG CONTEXT *
31
+ * ========================================================================== */
39
32
 
40
- constructor(start: T | Promise<T>, run: Run) {
41
- super()
42
- this.#promise = Promise.resolve(start)
43
- this.#run = run
33
+ /**
34
+ * The {@link Context} class defines the context in which a {@link Plug}
35
+ * is invoked.
36
+ */
37
+ export class Context {
38
+ /** The directory of the file where the task was defined (convenience). */
39
+ public readonly buildDir: AbsolutePath
40
+ /** The {@link Logger} associated with this instance. */
41
+ public readonly log: Logger
42
+
43
+ constructor(
44
+ /** The absolute file name where the task was defined. */
45
+ public readonly buildFile: AbsolutePath,
46
+ /** The _name_ of the task associated with this {@link Context}. */
47
+ public readonly taskName: string,
48
+ ) {
49
+ this.buildDir = getAbsoluteParent(buildFile)
50
+ this.log = getLogger(taskName)
44
51
  }
45
52
 
46
- plug<T extends Files | undefined>(arg: Plug<T> | PlugFunction<T>): Pipe & Promise<T> {
47
- const plug = typeof arg === 'function' ? { pipe: arg } : arg
48
- const promise = this.#promise.then((files) => {
49
- assert(files, 'Pipe can not be further extended')
50
- return plug.pipe(files, this.#run)
51
- })
52
- return new PipeImpl(promise, this.#run)
53
- }
53
+ resolve(path: string, ...paths: string[]): AbsolutePath {
54
+ // Paths starting with "@" are relative to the build file directory
55
+ if (path && path.startsWith('@')) {
56
+ // We can have paths like "@/../foo/bar" or "@../foo/bar"... both are ok
57
+ const components = path.substring(1).split(sep).filter((s) => !!s)
58
+ return resolveAbsolutePath(this.buildDir, ...components, ...paths)
59
+ }
54
60
 
55
- then<T1 = T, T2 = never>(
56
- onfulfilled?: ((value: T) => T1 | PromiseLike<T1>) | null | undefined,
57
- onrejected?: ((reason: any) => T2 | PromiseLike<T2>) | null | undefined,
58
- ): Promise<T1 | T2> {
59
- return this.#promise.then(onfulfilled, onrejected)
60
- }
61
+ // No path? Resolve to the CWD!
62
+ if (! path) return getCurrentWorkingDirectory()
61
63
 
62
- catch<T0 = never>(
63
- onrejected?: ((reason: any) => T0 | PromiseLike<T0>) | null | undefined,
64
- ): Promise<T0 | T> {
65
- return this.#promise.catch(onrejected)
64
+ // For all the rest, normal resolution!
65
+ return resolveAbsolutePath(getCurrentWorkingDirectory(), path, ...paths)
66
66
  }
67
+ }
67
68
 
68
- finally(
69
- onfinally?: (() => void) | null | undefined,
70
- ): Promise<T> {
71
- return this.#promise.finally(onfinally)
72
- }
69
+ /* ========================================================================== *
70
+ * PIPES *
71
+ * ========================================================================== */
72
+
73
+ /**
74
+ * A class that will be extended by {@link Pipe} where {@link install} will
75
+ * add prototype properties from installed {@link Plug}s
76
+ */
77
+ abstract class PipeProto {
78
+ abstract plug(plug: Plug<PlugResult>): Pipe | Promise<undefined>
79
+ }
80
+
81
+ /**
82
+ * The {@link Pipe} abstract defines processing pipeline where multiple
83
+ * {@link Plug}s can transform lists of {@link Files}.
84
+ */
85
+ export abstract class Pipe extends PipeProto {
86
+ abstract plug(plug: Plug<Files>): Pipe
87
+ abstract plug(plug: PlugFunction<Files>): Pipe
88
+ abstract plug(plug: Plug<void | undefined>): Promise<undefined>
89
+ abstract plug(plug: PlugFunction<void | undefined>): Promise<undefined>
73
90
 
74
- [Symbol.toStringTag] = 'Pipe'
91
+ abstract run(): Promise<Files>
75
92
  }
76
93
 
77
94
  /* ========================================================================== *
78
- * PLUG INSTALLATION (INTERNAL) *
95
+ * PLUG INSTALLATION (NEW) *
79
96
  * ========================================================================== */
80
97
 
81
98
  /** The names which can be installed as direct plugs. */
82
- export type PlugName = string & Exclude<keyof Pipe, 'plug' | keyof Promise<Files>>
83
-
84
- /** A convenience type identifying a {@link Plug} constructor. */
85
- export type PlugConstructor = new (...args: any) => Plug<Files | undefined>
86
-
87
- /** Convert the resulting type of a {@link Plug} for use in a {@link Pipe} */
88
- type PlugReturnForPipe<T> =
89
- T extends Plug<infer R> ?
90
- R extends Files ?
91
- Promise<Files> & Pipe :
92
- R extends undefined ?
93
- Promise<undefined> :
94
- never :
95
- never
99
+ export type PlugName = string & Exclude<keyof Pipe, 'plug' | 'run'>
100
+
101
+ /** The parameters of the plug extension with the given name */
102
+ export type PipeParameters<Name extends PlugName> = PipeOverloads<Name>['args']
103
+
104
+ /** Extract arguments and return types from function overloads. */
105
+ type PipeOverloads<Name extends PlugName> =
106
+ Pipe[Name] extends {
107
+ (...args: infer A0): infer R0
108
+ (...args: infer A1): infer R1
109
+ (...args: infer A2): infer R2
110
+ (...args: infer A3): infer R3
111
+ (...args: infer A4): infer R4
112
+ } ?
113
+ | (R0 extends (Pipe | Promise<undefined>) ? { args: A0, ret: R0 } : never)
114
+ | (R1 extends (Pipe | Promise<undefined>) ? { args: A1, ret: R1 } : never)
115
+ | (R2 extends (Pipe | Promise<undefined>) ? { args: A2, ret: R2 } : never)
116
+ | (R3 extends (Pipe | Promise<undefined>) ? { args: A3, ret: R3 } : never)
117
+ | (R4 extends (Pipe | Promise<undefined>) ? { args: A4, ret: R4 } : never)
118
+ :
119
+ Pipe[Name] extends {
120
+ (...args: infer A0): infer R0
121
+ (...args: infer A1): infer R1
122
+ (...args: infer A2): infer R2
123
+ (...args: infer A3): infer R3
124
+ } ?
125
+ | (R0 extends (Pipe | Promise<undefined>) ? { args: A0, ret: R0 } : never)
126
+ | (R1 extends (Pipe | Promise<undefined>) ? { args: A1, ret: R1 } : never)
127
+ | (R2 extends (Pipe | Promise<undefined>) ? { args: A2, ret: R2 } : never)
128
+ | (R3 extends (Pipe | Promise<undefined>) ? { args: A3, ret: R3 } : never)
129
+ :
130
+ Pipe[Name] extends {
131
+ (...args: infer A0): infer R0
132
+ (...args: infer A1): infer R1
133
+ (...args: infer A2): infer R2
134
+ } ?
135
+ | (R0 extends (Pipe | Promise<undefined>) ? { args: A0, ret: R0 } : never)
136
+ | (R1 extends (Pipe | Promise<undefined>) ? { args: A1, ret: R1 } : never)
137
+ | (R2 extends (Pipe | Promise<undefined>) ? { args: A2, ret: R2 } : never)
138
+ :
139
+ Pipe[Name] extends {
140
+ (...args: infer A0): infer R0
141
+ (...args: infer A1): infer R1
142
+ } ?
143
+ | (R0 extends (Pipe | Promise<undefined>) ? { args: A0, ret: R0 } : never)
144
+ | (R1 extends (Pipe | Promise<undefined>) ? { args: A1, ret: R1 } : never)
145
+ :
146
+ Pipe[Name] extends {
147
+ (...args: infer A0): infer R0
148
+ } ?
149
+ | (R0 extends (Pipe | Promise<undefined>) ? { args: A0, ret: R0 } : never)
150
+ : never
151
+
152
+ /** The parameters of the plug extension with the given name */
153
+ type PipeResult<Name extends PlugName> = PipeOverloads<Name>['ret']
96
154
 
97
155
  /**
98
- * Map constructors into an array of all known overloads.
99
- *
100
- * This is a _royal_ pain in the ass, as we need to distinguish between
101
- * all possible number of overloads of a constructor... Limit to 5 of them!
102
- *
103
- * Also, the empty constructor (when specified in the overloads) will simply
104
- * match the first case (most overloads) and generate functions somewhat like
105
- *
106
- * (...args: unknown[]) => never
107
- * (...args: unknown[]) => never
108
- * (...args: unknown[]) => never
109
- * () => PlugReturnForPipe<R3>
110
- * (arg: Options) => PlugReturnForPipe<R4>
111
- *
112
- * Somehow inferring the result to `Function` or the right type and ANDing all
113
- * those together here doesn't work, so we create this array and we'll AND
114
- * all its members in the PipeExtension<...> type.
156
+ * A type defining the correct constructor for a {@link Plug}, inferring
157
+ * argument types and instance type from the definitions in {@link Pipe}.
115
158
  */
116
- type PlugConstructorOverloads<T extends PlugConstructor> =
117
- T extends {
118
- new (...args: infer A0): infer R0
119
- new (...args: infer A1): infer R1
120
- new (...args: infer A2): infer R2
121
- new (...args: infer A3): infer R3
122
- new (...args: infer A4): infer R4
123
- } ? [
124
- R0 extends Plug<Files | undefined> ? ((...args: A0) => PlugReturnForPipe<R0>) : Function,
125
- R1 extends Plug<Files | undefined> ? ((...args: A1) => PlugReturnForPipe<R1>) : Function,
126
- R2 extends Plug<Files | undefined> ? ((...args: A2) => PlugReturnForPipe<R2>) : Function,
127
- R3 extends Plug<Files | undefined> ? ((...args: A3) => PlugReturnForPipe<R3>) : Function,
128
- R4 extends Plug<Files | undefined> ? ((...args: A4) => PlugReturnForPipe<R4>) : Function,
129
- ] :
130
- T extends {
131
- new (...args: infer A0): infer R0
132
- new (...args: infer A1): infer R1
133
- new (...args: infer A2): infer R2
134
- new (...args: infer A3): infer R3
135
- } ? [
136
- R0 extends Plug<Files | undefined> ? (...args: A0) => PlugReturnForPipe<R0> : Function,
137
- R1 extends Plug<Files | undefined> ? (...args: A1) => PlugReturnForPipe<R1> : Function,
138
- R2 extends Plug<Files | undefined> ? (...args: A2) => PlugReturnForPipe<R2> : Function,
139
- R3 extends Plug<Files | undefined> ? (...args: A3) => PlugReturnForPipe<R3> : Function,
140
- ] :
141
- T extends {
142
- new (...args: infer A0): infer R0
143
- new (...args: infer A1): infer R1
144
- new (...args: infer A2): infer R2
145
- } ? [
146
- R0 extends Plug<Files | undefined> ? (...args: A0) => PlugReturnForPipe<R0> : Function,
147
- R1 extends Plug<Files | undefined> ? (...args: A1) => PlugReturnForPipe<R1> : Function,
148
- R2 extends Plug<Files | undefined> ? (...args: A2) => PlugReturnForPipe<R2> : Function,
149
- ] :
150
- T extends {
151
- new (...args: infer A0): infer R0
152
- new (...args: infer A1): infer R1
153
- } ? [
154
- R0 extends Plug<Files | undefined> ? (...args: A0) => PlugReturnForPipe<R0> : Function,
155
- R1 extends Plug<Files | undefined> ? (...args: A1) => PlugReturnForPipe<R1> : Function,
156
- ] :
157
- T extends {
158
- new (...args: infer A0): infer R0
159
- } ? [
160
- R0 extends Plug<Files | undefined> ? (...args: A0) => PlugReturnForPipe<R0> : Function,
161
- ] :
159
+ type PlugConstructor<Name extends PlugName> =
160
+ PipeResult<Name> extends Pipe ?
161
+ new (...args: PipeParameters<Name>) => Plug<Files> :
162
+ PipeResult<Name> extends Promise<undefined> ?
163
+ new (...args: PipeParameters<Name>) => Plug<void | undefined> :
164
+ PipeResult<Name> extends (Pipe | Promise<undefined>) ?
165
+ new (...args: PipeParameters<Name>) => Plug<Files | void | undefined> :
162
166
  never
163
167
 
164
168
  /**
165
- * A convenience type to easily annotate installed {@link Plug Plugs}.
166
- *
167
- * See also {@link install}.
168
- *
169
- * ```
170
- * export class Write implements Plug {
171
- * // ... the plug implementation lives here
172
- * }
173
- *
174
- * install('write', Write)
175
- *
176
- * declare module '../pipe' {
177
- * export interface Pipe {
178
- * write: PipeExtension<typeof Write>
179
- * }
180
- * }
181
- * ```
182
- */
183
- export type PipeExtension<T extends PlugConstructor, A = PlugConstructorOverloads<T>> =
184
- A extends readonly [ infer First, ...infer Rest ] ?
185
- First & PipeExtension<T, Rest> :
186
- A extends readonly [ infer Only ] ?
187
- Only :
188
- Function
189
-
190
- /**
191
- * Install a {@link Plug} into our {@link Pipe} prototype, and return a static
192
- * creator function for the {@link Plug} itself.
169
+ * Install a {@link Plug} into our {@link Pipe} prototype.
193
170
  *
194
171
  * This allows our shorthand syntax for well-defined plugs such as:
195
172
  *
@@ -202,30 +179,66 @@ export type PipeExtension<T extends PlugConstructor, A = PlugConstructorOverload
202
179
  * Use this alongside interface merging like:
203
180
  *
204
181
  * ```
205
- * export class Write implements Plug {
206
- * // ... the plug implementation lives here
207
- * }
208
- *
209
- * install('write', Write)
210
- *
211
- * declare module '../pipe' {
182
+ * declare module '@plugjs/plug/pipe' {
212
183
  * export interface Pipe {
213
- * write: PipeExtension<typeof Write>
184
+ * write(): Pipe
214
185
  * }
215
186
  * }
187
+ *
188
+ * install('write', class Write implements Plug {
189
+ * constructorg(...args: PipeParams<'write'>) {
190
+ * // here `args` is automatically inferred by whatever was declared above
191
+ * }
192
+ *
193
+ * // ... the plug implementation lives here
194
+ * })
216
195
  * ```
217
196
  */
218
- export function install<C extends PlugConstructor>(name: PlugName, ctor: C): void {
219
- /* This is quite hairy when it comes to types, so, just give up! :-P */
220
-
221
- function create(this: Pipe, ...args: any): Pipe & Promise<Files | undefined> {
197
+ export function install<
198
+ Name extends PlugName,
199
+ Ctor extends PlugConstructor<Name>,
200
+ >(name: Name, ctor: Ctor): void {
201
+ /* The function plugging the newly constructed plug in a pipe */
202
+ function plug(this: PipeProto, ...args: PipeParameters<Name>): Pipe | Promise<undefined> {
222
203
  // eslint-disable-next-line new-cap
223
- return this.plug(new ctor(...args) as any)
204
+ return this.plug(new ctor(...args))
224
205
  }
225
206
 
226
207
  /* Setup name so that stack traces look better */
227
- Object.defineProperty(create, 'name', { value: name })
208
+ Object.defineProperty(plug, 'name', { value: name })
228
209
 
229
210
  /* Inject the create function in the Pipe's prototype */
230
- Object.defineProperty(Pipe.prototype, name, { value: create })
211
+ Object.defineProperty(PipeProto.prototype, name, { value: plug })
212
+ }
213
+
214
+ /**
215
+ * Install a _forking_ {@link Plug} in the {@link Pipe}, in other words
216
+ * execute the plug in a separate process.
217
+ *
218
+ * As a contract, if the _last non-null_ parameter of the constructor is an
219
+ * object and contains the key `coverageDir`, the process will be forked with
220
+ * the approptiately resolved `NODE_V8_COVERAGE` environment variable.
221
+ *
222
+ * Also, forking plugs require some special attention:
223
+ *
224
+ * * plug functions are not supported, only classes implementing the
225
+ * {@link Plug} interface can be used with this.
226
+ *
227
+ * * the class itself _MUST_ be exported as the _default_ export for the
228
+ * `scriptFile` specified below. This is to simplify interoperability between
229
+ * CommonJS and ESM modules as we use dynamic `import(...)` statements.
230
+ */
231
+ export function installForking<Name extends PlugName>(
232
+ plugName: Name,
233
+ scriptFile: AbsolutePath,
234
+ ): void {
235
+ /** Extend out our ForkingPlug below */
236
+ const ctor = class extends ForkingPlug {
237
+ constructor(...args: any[]) {
238
+ super(scriptFile, args)
239
+ }
240
+ } as unknown as PlugConstructor<Name>
241
+
242
+ /** Install the plug in */
243
+ install(plugName, ctor)
231
244
  }
package/src/plugs/copy.ts CHANGED
@@ -1,10 +1,9 @@
1
- import { assert } from '../assert.js'
2
- import { Files } from '../files.js'
3
- import { $p } from '../log.js'
4
- import { assertAbsolutePath, getAbsoluteParent, resolveAbsolutePath } from '../paths.js'
5
- import { install, Plug } from '../pipe.js'
6
- import { Run } from '../run.js'
7
- import { chmod, copyFile, fsConstants, mkdir } from '../utils/asyncfs.js'
1
+ import { assert } from '../assert'
2
+ import { Files } from '../files'
3
+ import { $p } from '../log'
4
+ import { assertAbsolutePath, getAbsoluteParent, resolveAbsolutePath } from '../paths'
5
+ import { install, PipeParameters, Plug, Context } from '../pipe'
6
+ import { chmod, copyFile, fsConstants, mkdir } from '../utils/asyncfs'
8
7
 
9
8
  /** Options for copying files */
10
9
  export interface CopyOptions {
@@ -18,15 +17,37 @@ export interface CopyOptions {
18
17
  rename?: (relative: string) => string
19
18
  }
20
19
 
20
+ declare module '../pipe' {
21
+ export interface Pipe {
22
+ /**
23
+ * Copy the curent {@link Files} to a different directory
24
+ *
25
+ * @param directory The target directory where files will be copied to
26
+ */
27
+ copy(directory: string): Pipe
28
+ /**
29
+ * Copy the curent {@link Files} to a different directory
30
+ *
31
+ * @param directory The target directory where files will be copied to
32
+ * @param options Extra {@link CopyOptions | options} for the copy operation
33
+ */
34
+ copy(directory: string, options: CopyOptions): Pipe
35
+ }
36
+ }
37
+
38
+ /* ========================================================================== *
39
+ * INSTALLATION / IMPLEMENTATION *
40
+ * ========================================================================== */
41
+
21
42
  /** Copy the curent {@link Files} to a different directory */
22
- export class Copy implements Plug<Files> {
23
- constructor(directory: string, options?: CopyOptions)
43
+ install('copy', class Copy implements Plug<Files> {
44
+ constructor(...args: PipeParameters<'copy'>)
24
45
  constructor(
25
46
  private readonly _directory: string,
26
47
  private readonly _options: CopyOptions = {},
27
48
  ) {}
28
49
 
29
- async pipe(files: Files, run: Run): Promise<Files> {
50
+ async pipe(files: Files, context: Context): Promise<Files> {
30
51
  /* Destructure our options with some defaults and compute write flags */
31
52
  const { mode, dirMode, overwrite, rename = (s): string => s } = this._options
32
53
  const flags = overwrite ? fsConstants.COPYFILE_EXCL : 0
@@ -34,7 +55,8 @@ export class Copy implements Plug<Files> {
34
55
  const fmode = parseMode(mode)
35
56
 
36
57
  /* Our files builder for all written files */
37
- const builder = run.files(this._directory)
58
+ const directory = context.resolve(this._directory)
59
+ const builder = Files.builder(directory)
38
60
 
39
61
  /* Iterate through all the mappings of the source files */
40
62
  for (const [ relative, absolute ] of files.pathMappings()) {
@@ -44,7 +66,7 @@ export class Copy implements Plug<Files> {
44
66
 
45
67
  /* We never copy a file onto itself, but not fail either */
46
68
  if (target === absolute) {
47
- run.log.warn('Cowardly refusing to copy same file', $p(absolute))
69
+ context.log.warn('Cowardly refusing to copy same file', $p(absolute))
48
70
  continue
49
71
  }
50
72
 
@@ -56,44 +78,31 @@ export class Copy implements Plug<Files> {
56
78
  if (firstParent && (dmode !== undefined)) {
57
79
  assertAbsolutePath(firstParent)
58
80
  for (let dir = directory; ; dir = getAbsoluteParent(dir)) {
59
- run.log.trace(`Setting mode ${stringifyMode(dmode)} for directory`, $p(dir))
81
+ context.log.trace(`Setting mode ${stringifyMode(dmode)} for directory`, $p(dir))
60
82
  await chmod(dir, dmode)
61
83
  if (dir === firstParent) break
62
84
  }
63
85
  }
64
86
 
65
87
  /* Actually _copy_ the file */
66
- run.log.trace(`Copying "${$p(absolute)}" to "${$p(target)}"`)
88
+ context.log.trace(`Copying "${$p(absolute)}" to "${$p(target)}"`)
67
89
  await copyFile(absolute, target, flags)
68
90
 
69
91
  /* Set the mode, if we need to */
70
92
  if (fmode !== undefined) {
71
- run.log.trace(`Setting mode ${stringifyMode(fmode)} for file`, $p(target))
93
+ context.log.trace(`Setting mode ${stringifyMode(fmode)} for file`, $p(target))
72
94
  await chmod(target, fmode)
73
95
  }
74
96
 
75
97
  /* Record this file */
76
- builder.unchecked(relative)
98
+ builder.add(relative)
77
99
  }
78
100
 
79
101
  const result = builder.build()
80
- run.log.info('Copied', result.length, 'files to', $p(builder.directory))
102
+ context.log.info('Copied', result.length, 'files to', $p(builder.directory))
81
103
  return result
82
104
  }
83
- }
84
-
85
- /* ========================================================================== *
86
- * INSTALLATION *
87
- * ========================================================================== */
88
-
89
- install('copy', Copy)
90
-
91
- declare module '../pipe.js' {
92
- export interface Pipe {
93
- /** Copy the curent {@link Files} to a different directory */
94
- copy: PipeExtension<typeof Copy>
95
- }
96
- }
105
+ })
97
106
 
98
107
  /* ========================================================================== *
99
108
  * INTERNALS *
@@ -1,9 +1,9 @@
1
1
  import { fileURLToPath, pathToFileURL } from 'node:url'
2
2
  import { RawSourceMap, SourceMapConsumer } from 'source-map'
3
- import { assert } from '../../assert.js'
4
- import { $gry, $p, Logger } from '../../log.js'
5
- import { AbsolutePath } from '../../paths.js'
6
- import { readFile } from '../../utils/asyncfs.js'
3
+ import { assert } from '../../assert'
4
+ import { $gry, $p, Logger } from '../../log'
5
+ import { AbsolutePath } from '../../paths'
6
+ import { readFile } from '../../utils/asyncfs'
7
7
 
8
8
  /* ========================================================================== *
9
9
  * V8 COVERAGE TYPES *
@@ -1,5 +1,4 @@
1
1
 
2
- import { parse } from '@babel/parser'
3
2
  import {
4
3
  Comment, isDeclaration,
5
4
  isExportDeclaration,
@@ -13,11 +12,13 @@ import {
13
12
  Node,
14
13
  VISITOR_KEYS
15
14
  } from '@babel/types'
15
+
16
+ import { parse } from '@babel/parser'
16
17
  import { pathToFileURL } from 'node:url'
17
- import { $p, Logger } from '../../log.js'
18
- import { AbsolutePath } from '../../paths.js'
19
- import { readFile } from '../../utils/asyncfs.js'
20
- import { CoverageAnalyser } from './analysis.js'
18
+ import { $p, Logger } from '../../log'
19
+ import { AbsolutePath } from '../../paths'
20
+ import { readFile } from '../../utils/asyncfs'
21
+ import { CoverageAnalyser } from './analysis'
21
22
 
22
23
  /* ========================================================================== *
23
24
  * EXPORTED CONSTANTS AND TYPES *