@plugjs/plug 0.0.1
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/LICENSE.md +211 -0
- package/NOTICE.md +13 -0
- package/README.md +7 -0
- package/dist/assert.cjs +72 -0
- package/dist/assert.cjs.map +6 -0
- package/dist/assert.mjs +41 -0
- package/dist/assert.mjs.map +6 -0
- package/dist/async.cjs +58 -0
- package/dist/async.cjs.map +6 -0
- package/dist/async.mjs +30 -0
- package/dist/async.mjs.map +6 -0
- package/dist/build.cjs +136 -0
- package/dist/build.cjs.map +6 -0
- package/dist/build.mjs +110 -0
- package/dist/build.mjs.map +6 -0
- package/dist/files.cjs +113 -0
- package/dist/files.cjs.map +6 -0
- package/dist/files.mjs +88 -0
- package/dist/files.mjs.map +6 -0
- package/dist/fork.cjs +177 -0
- package/dist/fork.cjs.map +6 -0
- package/dist/fork.mjs +151 -0
- package/dist/fork.mjs.map +6 -0
- package/dist/helpers.cjs +129 -0
- package/dist/helpers.cjs.map +6 -0
- package/dist/helpers.mjs +97 -0
- package/dist/helpers.mjs.map +6 -0
- package/dist/index.cjs +25 -0
- package/dist/index.cjs.map +6 -0
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +6 -0
- package/dist/log/colors.cjs +129 -0
- package/dist/log/colors.cjs.map +6 -0
- package/dist/log/colors.mjs +93 -0
- package/dist/log/colors.mjs.map +6 -0
- package/dist/log/emit.cjs +109 -0
- package/dist/log/emit.cjs.map +6 -0
- package/dist/log/emit.mjs +83 -0
- package/dist/log/emit.mjs.map +6 -0
- package/dist/log/levels.cjs +75 -0
- package/dist/log/levels.cjs.map +6 -0
- package/dist/log/levels.mjs +41 -0
- package/dist/log/levels.mjs.map +6 -0
- package/dist/log/logger.cjs +129 -0
- package/dist/log/logger.cjs.map +6 -0
- package/dist/log/logger.mjs +104 -0
- package/dist/log/logger.mjs.map +6 -0
- package/dist/log/options.cjs +149 -0
- package/dist/log/options.cjs.map +6 -0
- package/dist/log/options.mjs +124 -0
- package/dist/log/options.mjs.map +6 -0
- package/dist/log/report.cjs +284 -0
- package/dist/log/report.cjs.map +6 -0
- package/dist/log/report.mjs +259 -0
- package/dist/log/report.mjs.map +6 -0
- package/dist/log/spinner.cjs +83 -0
- package/dist/log/spinner.cjs.map +6 -0
- package/dist/log/spinner.mjs +57 -0
- package/dist/log/spinner.mjs.map +6 -0
- package/dist/log.cjs +71 -0
- package/dist/log.cjs.map +6 -0
- package/dist/log.mjs +45 -0
- package/dist/log.mjs.map +6 -0
- package/dist/paths.cjs +158 -0
- package/dist/paths.cjs.map +6 -0
- package/dist/paths.mjs +122 -0
- package/dist/paths.mjs.map +6 -0
- package/dist/pipe.cjs +71 -0
- package/dist/pipe.cjs.map +6 -0
- package/dist/pipe.mjs +44 -0
- package/dist/pipe.mjs.map +6 -0
- package/dist/plugs/copy.cjs +95 -0
- package/dist/plugs/copy.cjs.map +6 -0
- package/dist/plugs/copy.mjs +64 -0
- package/dist/plugs/copy.mjs.map +6 -0
- package/dist/plugs/coverage/analysis.cjs +229 -0
- package/dist/plugs/coverage/analysis.cjs.map +6 -0
- package/dist/plugs/coverage/analysis.mjs +202 -0
- package/dist/plugs/coverage/analysis.mjs.map +6 -0
- package/dist/plugs/coverage/report.cjs +215 -0
- package/dist/plugs/coverage/report.cjs.map +6 -0
- package/dist/plugs/coverage/report.mjs +200 -0
- package/dist/plugs/coverage/report.mjs.map +6 -0
- package/dist/plugs/coverage.cjs +142 -0
- package/dist/plugs/coverage.cjs.map +6 -0
- package/dist/plugs/coverage.mjs +117 -0
- package/dist/plugs/coverage.mjs.map +6 -0
- package/dist/plugs/debug.cjs +50 -0
- package/dist/plugs/debug.cjs.map +6 -0
- package/dist/plugs/debug.mjs +25 -0
- package/dist/plugs/debug.mjs.map +6 -0
- package/dist/plugs/esbuild/bundle-locals.cjs +51 -0
- package/dist/plugs/esbuild/bundle-locals.cjs.map +6 -0
- package/dist/plugs/esbuild/bundle-locals.mjs +26 -0
- package/dist/plugs/esbuild/bundle-locals.mjs.map +6 -0
- package/dist/plugs/esbuild/check-dependencies.cjs +140 -0
- package/dist/plugs/esbuild/check-dependencies.cjs.map +6 -0
- package/dist/plugs/esbuild/check-dependencies.mjs +115 -0
- package/dist/plugs/esbuild/check-dependencies.mjs.map +6 -0
- package/dist/plugs/esbuild/fix-extensions.cjs +91 -0
- package/dist/plugs/esbuild/fix-extensions.cjs.map +6 -0
- package/dist/plugs/esbuild/fix-extensions.mjs +60 -0
- package/dist/plugs/esbuild/fix-extensions.mjs.map +6 -0
- package/dist/plugs/esbuild.cjs +109 -0
- package/dist/plugs/esbuild.cjs.map +6 -0
- package/dist/plugs/esbuild.mjs +83 -0
- package/dist/plugs/esbuild.mjs.map +6 -0
- package/dist/plugs/eslint/runner.cjs +91 -0
- package/dist/plugs/eslint/runner.cjs.map +6 -0
- package/dist/plugs/eslint/runner.mjs +68 -0
- package/dist/plugs/eslint/runner.mjs.map +6 -0
- package/dist/plugs/exec.cjs +128 -0
- package/dist/plugs/exec.cjs.map +6 -0
- package/dist/plugs/exec.mjs +96 -0
- package/dist/plugs/exec.mjs.map +6 -0
- package/dist/plugs/filter.cjs +59 -0
- package/dist/plugs/filter.cjs.map +6 -0
- package/dist/plugs/filter.mjs +34 -0
- package/dist/plugs/filter.mjs.map +6 -0
- package/dist/plugs/mocha/reporter.cjs +140 -0
- package/dist/plugs/mocha/reporter.cjs.map +6 -0
- package/dist/plugs/mocha/reporter.mjs +107 -0
- package/dist/plugs/mocha/reporter.mjs.map +6 -0
- package/dist/plugs/mocha/runner.cjs +73 -0
- package/dist/plugs/mocha/runner.cjs.map +6 -0
- package/dist/plugs/mocha/runner.mjs +44 -0
- package/dist/plugs/mocha/runner.mjs.map +6 -0
- package/dist/plugs/tsc/compiler.cjs +74 -0
- package/dist/plugs/tsc/compiler.cjs.map +6 -0
- package/dist/plugs/tsc/compiler.mjs +43 -0
- package/dist/plugs/tsc/compiler.mjs.map +6 -0
- package/dist/plugs/tsc/options.cjs +82 -0
- package/dist/plugs/tsc/options.cjs.map +6 -0
- package/dist/plugs/tsc/options.mjs +51 -0
- package/dist/plugs/tsc/options.mjs.map +6 -0
- package/dist/plugs/tsc/report.cjs +90 -0
- package/dist/plugs/tsc/report.cjs.map +6 -0
- package/dist/plugs/tsc/report.mjs +59 -0
- package/dist/plugs/tsc/report.mjs.map +6 -0
- package/dist/plugs/tsc/runner.cjs +101 -0
- package/dist/plugs/tsc/runner.cjs.map +6 -0
- package/dist/plugs/tsc/runner.mjs +72 -0
- package/dist/plugs/tsc/runner.mjs.map +6 -0
- package/dist/plugs.cjs +31 -0
- package/dist/plugs.cjs.map +6 -0
- package/dist/plugs.mjs +13 -0
- package/dist/plugs.mjs.map +6 -0
- package/dist/run.cjs +95 -0
- package/dist/run.cjs.map +6 -0
- package/dist/run.mjs +70 -0
- package/dist/run.mjs.map +6 -0
- package/dist/task.cjs +39 -0
- package/dist/task.cjs.map +6 -0
- package/dist/task.mjs +14 -0
- package/dist/task.mjs.map +6 -0
- package/dist/utils/asyncfs.cjs +143 -0
- package/dist/utils/asyncfs.cjs.map +6 -0
- package/dist/utils/asyncfs.mjs +83 -0
- package/dist/utils/asyncfs.mjs.map +6 -0
- package/dist/utils/caller.cjs +59 -0
- package/dist/utils/caller.cjs.map +6 -0
- package/dist/utils/caller.mjs +34 -0
- package/dist/utils/caller.mjs.map +6 -0
- package/dist/utils/match.cjs +69 -0
- package/dist/utils/match.cjs.map +6 -0
- package/dist/utils/match.mjs +38 -0
- package/dist/utils/match.mjs.map +6 -0
- package/dist/utils/options.cjs +41 -0
- package/dist/utils/options.cjs.map +6 -0
- package/dist/utils/options.mjs +16 -0
- package/dist/utils/options.mjs.map +6 -0
- package/dist/utils/walk.cjs +104 -0
- package/dist/utils/walk.cjs.map +6 -0
- package/dist/utils/walk.mjs +79 -0
- package/dist/utils/walk.mjs.map +6 -0
- package/extra/cli.mjs +212 -0
- package/extra/ts-loader.mjs +214 -0
- package/extra/webassembly.d.ts +11 -0
- package/package.json +57 -0
- package/src/assert.ts +47 -0
- package/src/async.ts +50 -0
- package/src/files.ts +129 -0
- package/src/fork.ts +263 -0
- package/src/helpers.ts +145 -0
- package/src/index.ts +20 -0
- package/src/log/colors.ts +119 -0
- package/src/log/emit.ts +125 -0
- package/src/log/levels.ts +65 -0
- package/src/log/logger.ts +171 -0
- package/src/log/options.ts +199 -0
- package/src/log/report.ts +433 -0
- package/src/log/spinner.ts +70 -0
- package/src/log.ts +68 -0
- package/src/paths.ts +213 -0
- package/src/pipe.ts +231 -0
- package/src/plugs/copy.ts +113 -0
- package/src/plugs/coverage/analysis.ts +395 -0
- package/src/plugs/coverage/report.ts +337 -0
- package/src/plugs/coverage.ts +194 -0
- package/src/plugs/debug.ts +35 -0
- package/src/plugs/esbuild/bundle-locals.ts +33 -0
- package/src/plugs/esbuild/check-dependencies.ts +158 -0
- package/src/plugs/esbuild/fix-extensions.ts +108 -0
- package/src/plugs/esbuild.ts +128 -0
- package/src/plugs/eslint/runner.ts +112 -0
- package/src/plugs/exec.ts +215 -0
- package/src/plugs/filter.ts +56 -0
- package/src/plugs/mocha/reporter.ts +152 -0
- package/src/plugs/mocha/runner.ts +77 -0
- package/src/plugs/tsc/compiler.ts +66 -0
- package/src/plugs/tsc/options.ts +97 -0
- package/src/plugs/tsc/report.ts +74 -0
- package/src/plugs/tsc/runner.ts +100 -0
- package/src/plugs.ts +33 -0
- package/src/run.ts +160 -0
- package/src/task.ts +26 -0
- package/src/utils/asyncfs.ts +82 -0
- package/src/utils/caller.ts +45 -0
- package/src/utils/match.ts +286 -0
- package/src/utils/options.ts +22 -0
- package/src/utils/walk.ts +136 -0
- package/types/assert.d.ts +18 -0
- package/types/async.d.ts +20 -0
- package/types/build.d.ts +56 -0
- package/types/files.d.ts +44 -0
- package/types/fork.d.ts +57 -0
- package/types/helpers.d.ts +49 -0
- package/types/index.d.ts +14 -0
- package/types/log/colors.d.ts +25 -0
- package/types/log/emit.d.ts +14 -0
- package/types/log/levels.d.ts +52 -0
- package/types/log/logger.d.ts +31 -0
- package/types/log/options.d.ts +40 -0
- package/types/log/report.d.ts +64 -0
- package/types/log/spinner.d.ts +2 -0
- package/types/log.d.ts +10 -0
- package/types/paths.d.ts +76 -0
- package/types/pipe.d.ts +152 -0
- package/types/plugs/copy.d.ts +27 -0
- package/types/plugs/coverage/analysis.d.ts +104 -0
- package/types/plugs/coverage/report.d.ts +53 -0
- package/types/plugs/coverage.d.ts +46 -0
- package/types/plugs/debug.d.ts +14 -0
- package/types/plugs/esbuild/bundle-locals.d.ts +6 -0
- package/types/plugs/esbuild/check-dependencies.d.ts +12 -0
- package/types/plugs/esbuild/fix-extensions.d.ts +29 -0
- package/types/plugs/esbuild.d.ts +24 -0
- package/types/plugs/eslint/runner.d.ts +22 -0
- package/types/plugs/exec.d.ts +90 -0
- package/types/plugs/filter.d.ts +23 -0
- package/types/plugs/mocha/reporter.d.ts +8 -0
- package/types/plugs/mocha/runner.d.ts +34 -0
- package/types/plugs/tsc/compiler.d.ts +24 -0
- package/types/plugs/tsc/options.d.ts +8 -0
- package/types/plugs/tsc/report.d.ts +5 -0
- package/types/plugs/tsc/runner.d.ts +13 -0
- package/types/plugs.d.ts +16 -0
- package/types/run.d.ts +89 -0
- package/types/task.d.ts +15 -0
- package/types/utils/asyncfs.d.ts +37 -0
- package/types/utils/caller.d.ts +7 -0
- package/types/utils/match.d.ts +216 -0
- package/types/utils/options.d.ts +15 -0
- package/types/utils/walk.d.ts +28 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import reaadline from 'node:readline'
|
|
3
|
+
|
|
4
|
+
import { spawn, SpawnOptions } from 'node:child_process'
|
|
5
|
+
import { assert } from '../assert.js'
|
|
6
|
+
import { currentRun } from '../async.js'
|
|
7
|
+
import { Files } from '../files.js'
|
|
8
|
+
import { $p, logOptions } from '../log.js'
|
|
9
|
+
import { AbsolutePath, getCurrentWorkingDirectory, isDirectory } from '../paths.js'
|
|
10
|
+
import { install, Plug } from '../pipe.js'
|
|
11
|
+
import { Run } from '../run.js'
|
|
12
|
+
import { parseOptions, ParseOptions } from '../utils/options.js'
|
|
13
|
+
|
|
14
|
+
/** Options for executing scripts */
|
|
15
|
+
export interface ExecOptions {
|
|
16
|
+
/** Extra environment variables, or overrides for existing ones */
|
|
17
|
+
env?: Record<string, any>,
|
|
18
|
+
/** Whether to run in the context of a _shell_ or not */
|
|
19
|
+
shell?: string | boolean,
|
|
20
|
+
/**
|
|
21
|
+
* The current working directory of the process to execute.
|
|
22
|
+
*
|
|
23
|
+
* Defaults to the current {@link Files.directory | Files' directory} when
|
|
24
|
+
* used as a {@link Plug} or `process.cwd()` when used from {@link exec}.
|
|
25
|
+
*/
|
|
26
|
+
cwd?: string
|
|
27
|
+
/**
|
|
28
|
+
* When used as a {@link Plug}, the {@link Files} will be appended to the
|
|
29
|
+
* current arguments as _relative_ files (default) or _absolute_ (if false).
|
|
30
|
+
*/
|
|
31
|
+
relativePaths?: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Execute a shell command, adding to its _arguments_ the list of files from
|
|
36
|
+
* the current pipe (much like `xargs` does on Unix systems).
|
|
37
|
+
*
|
|
38
|
+
* This {@link Plug} returns the same {@link Files} it was given, so that
|
|
39
|
+
* executing a shell command doesn't interrupt a {@link Pipe}.
|
|
40
|
+
*
|
|
41
|
+
* For example:
|
|
42
|
+
*
|
|
43
|
+
* ```
|
|
44
|
+
* import { find, exec } from '@plugjs/plugjs'
|
|
45
|
+
*
|
|
46
|
+
* export default build({
|
|
47
|
+
* async runme() {
|
|
48
|
+
* find('*.ts', { directory: 'src' })
|
|
49
|
+
* .plug(new Exec('chmod', '755' }))
|
|
50
|
+
* .plug(new Exec('chown root:root', { shell: true }))
|
|
51
|
+
* },
|
|
52
|
+
* })
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export class Exec implements Plug<Files> {
|
|
56
|
+
private readonly _cmd: string
|
|
57
|
+
private readonly _args: readonly string[]
|
|
58
|
+
private readonly _options: ExecOptions
|
|
59
|
+
|
|
60
|
+
constructor(cmd: string, ...args: ParseOptions<ExecOptions>) {
|
|
61
|
+
const { params, options } = parseOptions(args, {})
|
|
62
|
+
this._cmd = cmd
|
|
63
|
+
this._args = params
|
|
64
|
+
this._options = options
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async pipe(files: Files, run: Run): Promise<Files> {
|
|
68
|
+
const { relativePaths = true, ...options } = this._options
|
|
69
|
+
|
|
70
|
+
if (! options.cwd) options.cwd = files.directory
|
|
71
|
+
|
|
72
|
+
// What to use as extra arguments? Relative or absolute paths?
|
|
73
|
+
const params = [ ...(relativePaths ? files : files.absolutePaths() ) ]
|
|
74
|
+
|
|
75
|
+
// In case of shell usage, each extra parameter (file) gets quoted!
|
|
76
|
+
if (options.shell) params.forEach((s, i, a) => a[i] = JSON.stringify(s))
|
|
77
|
+
|
|
78
|
+
// Run our child
|
|
79
|
+
await spawnChild(this._cmd, [ ...this._args, ...params ], options, run)
|
|
80
|
+
|
|
81
|
+
// Return our files
|
|
82
|
+
return files
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Execute a command and await for its result from within a task.
|
|
88
|
+
*
|
|
89
|
+
* For example:
|
|
90
|
+
*
|
|
91
|
+
* ```
|
|
92
|
+
* import { exec } from '@plugjs/plugjs'
|
|
93
|
+
*
|
|
94
|
+
* export default build({
|
|
95
|
+
* async runme() {
|
|
96
|
+
* await exec('ls', '-la', '/')
|
|
97
|
+
* },
|
|
98
|
+
* })
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
export function exec(cmd: string, ...args: ParseOptions<ExecOptions>): Promise<void> {
|
|
103
|
+
const run = currentRun()
|
|
104
|
+
assert(run, 'Unable to execute commands outside a running task')
|
|
105
|
+
|
|
106
|
+
const { params, options } = parseOptions(args, {})
|
|
107
|
+
return spawnChild(cmd, params, options, run)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/* ========================================================================== *
|
|
112
|
+
* INSTALLATION *
|
|
113
|
+
* ========================================================================== */
|
|
114
|
+
|
|
115
|
+
install('exec', Exec)
|
|
116
|
+
|
|
117
|
+
declare module '../pipe.js' {
|
|
118
|
+
export interface Pipe {
|
|
119
|
+
/**
|
|
120
|
+
* Execute a shell command, adding to its _arguments_ the list of files
|
|
121
|
+
* from the current pipe (much like `xargs` does on Unix systems).
|
|
122
|
+
*
|
|
123
|
+
* For example:
|
|
124
|
+
*
|
|
125
|
+
* ```
|
|
126
|
+
* import { find, exec } from '@plugjs/plugjs'
|
|
127
|
+
*
|
|
128
|
+
* export default build({
|
|
129
|
+
* async runme() {
|
|
130
|
+
* find('*.ts', { directory: 'src' })
|
|
131
|
+
* .exec('chmod', '755' })
|
|
132
|
+
* .exec('chown root:root', { shell: true })
|
|
133
|
+
* },
|
|
134
|
+
* })
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
exec: PipeExtension<typeof Exec>
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* ========================================================================== *
|
|
142
|
+
* INTERNALS *
|
|
143
|
+
* ========================================================================== */
|
|
144
|
+
|
|
145
|
+
async function spawnChild(
|
|
146
|
+
cmd: string,
|
|
147
|
+
args: readonly string[],
|
|
148
|
+
options: ExecOptions = {},
|
|
149
|
+
run: Run,
|
|
150
|
+
): Promise<void> {
|
|
151
|
+
const {
|
|
152
|
+
env = {}, // default empty environment
|
|
153
|
+
shell = false, // by default do not use a shell
|
|
154
|
+
cwd = undefined, // by default use "process.cwd()"
|
|
155
|
+
...extraOptions
|
|
156
|
+
} = options
|
|
157
|
+
|
|
158
|
+
const childCwd = cwd ? run.resolve(cwd) : getCurrentWorkingDirectory()
|
|
159
|
+
assert(isDirectory(childCwd), `Current working directory ${$p(childCwd)} does not exist`)
|
|
160
|
+
|
|
161
|
+
// Figure out the PATH environment variable
|
|
162
|
+
const childPaths: AbsolutePath[] = []
|
|
163
|
+
|
|
164
|
+
// The `.../node_modules/.bin` path relative to the current working dir */
|
|
165
|
+
const baseNodePath = run.resolve('@node_modules', '.bin')
|
|
166
|
+
if (isDirectory(baseNodePath)) childPaths.push(baseNodePath)
|
|
167
|
+
|
|
168
|
+
// The `.../node_bodules/.bin` path relative to the buildDir */
|
|
169
|
+
const buildNodePath = run.resolve('./node_modules', '.bin')
|
|
170
|
+
if (isDirectory(buildNodePath)) childPaths.push(buildNodePath)
|
|
171
|
+
|
|
172
|
+
// Any other paths either from `process.env` or `env` (which overrides it)
|
|
173
|
+
const extraPath = env.PATH || process.env.PATH
|
|
174
|
+
if (extraPath) childPaths.push(extraPath)
|
|
175
|
+
|
|
176
|
+
// Build our environment variables record
|
|
177
|
+
const PATH = childPaths.join(path.delimiter)
|
|
178
|
+
const __LOG_OPTIONS = JSON.stringify(logOptions.fork(run.taskName))
|
|
179
|
+
const childEnv = { ...process.env, ...env, PATH, __LOG_OPTIONS }
|
|
180
|
+
|
|
181
|
+
// Prepare the options for calling `spawn`
|
|
182
|
+
const childOptions: SpawnOptions = {
|
|
183
|
+
...extraOptions,
|
|
184
|
+
stdio: [ 'ignore', 'pipe', 'pipe' ],
|
|
185
|
+
cwd: childCwd,
|
|
186
|
+
env: childEnv,
|
|
187
|
+
shell,
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Spawn our subprocess and monitor its stdout/stderr
|
|
191
|
+
run.log.info('Executing', [ cmd, ...args ])
|
|
192
|
+
run.log.info('Execution options', childOptions)
|
|
193
|
+
const child = spawn(cmd, args, childOptions)
|
|
194
|
+
|
|
195
|
+
if (child.stdout) {
|
|
196
|
+
const out = reaadline.createInterface(child.stdout)
|
|
197
|
+
out.on('line', (line) => line ? run.log.notice(line) : run.log.notice('\u00a0'))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (child.stderr) {
|
|
201
|
+
const err = reaadline.createInterface(child.stderr)
|
|
202
|
+
err.on('line', (line) => line ? run.log.warn(line) : run.log.warn('\u00a0'))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Return our promise from the spawn events
|
|
206
|
+
return new Promise<void>((resolve, reject) => {
|
|
207
|
+
child.on('error', (error) => reject(error))
|
|
208
|
+
child.on('exit', (code, signal) => {
|
|
209
|
+
if (code === 0) return resolve()
|
|
210
|
+
if (signal) return reject(new Error(`Child process exited with signal ${signal}`))
|
|
211
|
+
if (code) return reject(new Error(`Child process exited with code ${code}`))
|
|
212
|
+
reject(new Error('Child process failed for an unknown reason'))
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Files } from '../files.js'
|
|
2
|
+
import { log } from '../log.js'
|
|
3
|
+
import { resolveRelativeChildPath } from '../paths.js'
|
|
4
|
+
import { install, Plug } from '../pipe.js'
|
|
5
|
+
import { Run } from '../run.js'
|
|
6
|
+
import { match, MatchOptions } from '../utils/match.js'
|
|
7
|
+
import { ParseOptions, parseOptions } from '../utils/options.js'
|
|
8
|
+
|
|
9
|
+
/** Options for filtering {@link Files}. */
|
|
10
|
+
export interface FilterOptions extends MatchOptions {
|
|
11
|
+
/** The base directory for filtering, and relativising the resulting files. */
|
|
12
|
+
directory?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Filter the current {@link Files} using globs. */
|
|
16
|
+
export class Filter implements Plug<Files> {
|
|
17
|
+
private readonly _globs: readonly [ string, ...readonly string[] ]
|
|
18
|
+
private readonly _options: FilterOptions
|
|
19
|
+
|
|
20
|
+
constructor(glob: string, ...args: ParseOptions<FilterOptions>) {
|
|
21
|
+
const { params, options } = parseOptions(args, {})
|
|
22
|
+
this._globs = [ glob, ...params ]
|
|
23
|
+
this._options = options
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pipe(files: Files, run: Run): Files {
|
|
27
|
+
const { directory, ...options } = this._options
|
|
28
|
+
|
|
29
|
+
const builder = run.files(directory || files.directory)
|
|
30
|
+
const matcher = match(this._globs, options)
|
|
31
|
+
|
|
32
|
+
for (const file of files.absolutePaths()) {
|
|
33
|
+
const relative = resolveRelativeChildPath(builder.directory, file)
|
|
34
|
+
if (relative && matcher(relative)) builder.add(relative)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const result = builder.build()
|
|
38
|
+
const discarded = files.length - result.length
|
|
39
|
+
log.debug('Filtered', result.length, 'files (discarded', discarded, 'files)')
|
|
40
|
+
|
|
41
|
+
return result
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* ========================================================================== *
|
|
46
|
+
* INSTALLATION *
|
|
47
|
+
* ========================================================================== */
|
|
48
|
+
|
|
49
|
+
install('filter', Filter)
|
|
50
|
+
|
|
51
|
+
declare module '../pipe.js' {
|
|
52
|
+
export interface Pipe {
|
|
53
|
+
/** Filter the current {@link Files} using globs. */
|
|
54
|
+
filter: PipeExtension<typeof Filter>
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import RealMocha from 'mocha' // Mocha types pollute the global scope!
|
|
2
|
+
|
|
3
|
+
import { AssertionError } from 'assert'
|
|
4
|
+
import { diffJson } from 'diff'
|
|
5
|
+
import { $blu, $grn, $gry, $ms, $red, $wht, $ylw, ERROR, Logger, NOTICE, WARN } from '../../log.js'
|
|
6
|
+
|
|
7
|
+
const _pending = '\u22EF' // middle ellipsis
|
|
8
|
+
const _success = '\u2714' // heavy check mark
|
|
9
|
+
const _failure = '\u2718' // heavy ballot x
|
|
10
|
+
const _details = '\u21B3' // downwards arrow with tip rightwards
|
|
11
|
+
|
|
12
|
+
/* ========================================================================== *
|
|
13
|
+
* LOGGER / REPORTER *
|
|
14
|
+
* ========================================================================== */
|
|
15
|
+
|
|
16
|
+
/** Symbol to inject `Logger` in reporter options */
|
|
17
|
+
export const logSymbol = Symbol()
|
|
18
|
+
/** Symbol to inject `Run` in reporter options */
|
|
19
|
+
export const runSymbol = Symbol()
|
|
20
|
+
|
|
21
|
+
export class PlugReporter extends RealMocha.reporters.Base {
|
|
22
|
+
constructor(runner: RealMocha.Runner, options: RealMocha.MochaOptions) {
|
|
23
|
+
super(runner, options)
|
|
24
|
+
|
|
25
|
+
const showDiff = !! options.diff
|
|
26
|
+
const log = options.reporterOptions[logSymbol] as Logger
|
|
27
|
+
const failures: RealMocha.Test[] = []
|
|
28
|
+
const rootSuite = runner.suite
|
|
29
|
+
|
|
30
|
+
// Enter a suite (increase indent)
|
|
31
|
+
runner.on('suite', (suite) => {
|
|
32
|
+
if (suite === rootSuite) return
|
|
33
|
+
log.notice('')
|
|
34
|
+
log.enter(NOTICE, `${$wht(suite.title)}`)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// Leave a suite (decrease indent)
|
|
38
|
+
runner.on('suite end', () => {
|
|
39
|
+
log.leave()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Enter a test (increase indent)
|
|
43
|
+
runner.on('test', (test) => {
|
|
44
|
+
log.enter(NOTICE, `${$blu(_pending)} ${test.title}`)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// Leave a test (handle warning/failures and decrease indent)
|
|
48
|
+
runner.on('test end', (test) => {
|
|
49
|
+
// TODO: slow!!!
|
|
50
|
+
if (test.isPassed()) {
|
|
51
|
+
log.leave(NOTICE, `${$grn(_success)} ${test.title}`)
|
|
52
|
+
} else if (test.isPending()) {
|
|
53
|
+
const tag = $gry('[') + $ylw('skipped') + $gry(']')
|
|
54
|
+
log.leave(WARN, `${$ylw(_pending)} ${test.title} ${tag}`)
|
|
55
|
+
} else if (test.isFailed()) {
|
|
56
|
+
const number = failures.push(test)
|
|
57
|
+
const tag = $gry('[') + $red('failed') + $gry('] [') + $red(number) + $gry(']')
|
|
58
|
+
log.leave(ERROR, `${$red(_failure)} ${test.title} ${tag}`)
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Mocha finished running, dump our report
|
|
63
|
+
runner.once('end', () => {
|
|
64
|
+
try {
|
|
65
|
+
// Each failure gets dumped individually
|
|
66
|
+
for (let i = 0; i < failures.length; i ++) {
|
|
67
|
+
log.notice('')
|
|
68
|
+
const failure = failures[i]
|
|
69
|
+
|
|
70
|
+
// The titles (from the suite, up to the test)
|
|
71
|
+
const titles = [ failure.title ]
|
|
72
|
+
for (let parent = failure.parent; parent; parent = parent?.parent) {
|
|
73
|
+
if (parent.parent) titles.unshift(parent.title)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Log out our titles (one per line, indented)
|
|
77
|
+
log.error(`${$gry('Failure [')}${$red(i + 1)}${$gry(']')}`)
|
|
78
|
+
titles.forEach((title, indent) => {
|
|
79
|
+
log.error(` ${''.padStart(indent * 4)}${$gry(_details)} ${$wht(title)}`)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// If we have an error, luckily this is an `Error` instance
|
|
83
|
+
if (failure.err) {
|
|
84
|
+
const message = `${failure.err}` // this is the message, can be multiple lines
|
|
85
|
+
const messageOrStack = failure.err.stack || `${failure.err}` // maybe a stack?
|
|
86
|
+
const messageIndex = messageOrStack.indexOf(message)
|
|
87
|
+
|
|
88
|
+
// Subtrack the message from the stack
|
|
89
|
+
const stack =
|
|
90
|
+
messageOrStack === message ? '' :
|
|
91
|
+
messageIndex < 0 ? messageOrStack :
|
|
92
|
+
messageOrStack.substring(messageIndex + message.length)
|
|
93
|
+
|
|
94
|
+
// Split and clean up stack lines
|
|
95
|
+
const stackLines = stack.split('\n')
|
|
96
|
+
.map((line) => line.trim())
|
|
97
|
+
.filter((line) => !! line)
|
|
98
|
+
|
|
99
|
+
// Output the message
|
|
100
|
+
log.enter(ERROR, '')
|
|
101
|
+
log.error($red(message))
|
|
102
|
+
|
|
103
|
+
// Should we diff?
|
|
104
|
+
if (showDiff && ('actual' in failure.err) && ('expected' in failure.err)) {
|
|
105
|
+
const err = failure.err as AssertionError
|
|
106
|
+
const actual =
|
|
107
|
+
err.actual === undefined ? '[undefined]' :
|
|
108
|
+
err.actual === null ? '[null]' :
|
|
109
|
+
err.actual
|
|
110
|
+
|
|
111
|
+
const expected =
|
|
112
|
+
err.expected === undefined ? '[undefined]' :
|
|
113
|
+
err.expected === null ? '[null]' :
|
|
114
|
+
err.expected
|
|
115
|
+
|
|
116
|
+
const changes = diffJson(actual as any, expected as any)
|
|
117
|
+
|
|
118
|
+
const diff = changes.map((change): string => {
|
|
119
|
+
if (change.removed) return $red(change.value)
|
|
120
|
+
if (change.added) return $grn(change.value)
|
|
121
|
+
return $gry(change.value)
|
|
122
|
+
}).join('')
|
|
123
|
+
|
|
124
|
+
log.enter(ERROR, `${$gry('diff')} ${$grn('expected')} ${$gry('/')} ${$red('actual')}`)
|
|
125
|
+
log.error(diff)
|
|
126
|
+
log.leave()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Dump our stack trace and leave
|
|
130
|
+
stackLines.forEach((line) => log.error(line))
|
|
131
|
+
log.leave()
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// If we have some statistics, then let's dump them out in pretty colors
|
|
136
|
+
if (runner.stats) {
|
|
137
|
+
log.notice('')
|
|
138
|
+
const { passes, pending, failures, duration = 0 } = runner.stats
|
|
139
|
+
const fmt = (n: number): string => n === 1 ? `${n} test` : `${n} tests`
|
|
140
|
+
if (passes) log.notice($grn(fmt(passes)), 'passing', $ms(duration))
|
|
141
|
+
if (pending) log.warn($ylw(fmt(pending)), 'pending')
|
|
142
|
+
if (failures) log.error($red(fmt(failures)), 'pending')
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Done...
|
|
146
|
+
log.notice('')
|
|
147
|
+
} catch (error) {
|
|
148
|
+
log.error('Error rendering Mocha report', error)
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import RealMocha from 'mocha' // Mocha types pollute the global scope!
|
|
2
|
+
|
|
3
|
+
import { failure } from '../../assert.js'
|
|
4
|
+
import { Files } from '../../files.js'
|
|
5
|
+
import { $wht, NOTICE } from '../../log.js'
|
|
6
|
+
import { Plug } from '../../pipe.js'
|
|
7
|
+
import { Run } from '../../run.js'
|
|
8
|
+
import { logSymbol, PlugReporter, runSymbol } from './reporter.js'
|
|
9
|
+
|
|
10
|
+
/** Options to construct our {@link Mocha} plug. */
|
|
11
|
+
export interface MochaOptions {
|
|
12
|
+
/** Specify the directory where coverage data will be saved */
|
|
13
|
+
coverageDir?: string,
|
|
14
|
+
/** Bail after first test failure? */
|
|
15
|
+
bail?: boolean,
|
|
16
|
+
/** Show diff on failure? */
|
|
17
|
+
diff?: boolean,
|
|
18
|
+
/** Report tests without running them? */
|
|
19
|
+
dryRun?: boolean,
|
|
20
|
+
/** Tests marked `only` fail the suite? */
|
|
21
|
+
forbidOnly?: boolean,
|
|
22
|
+
/** Pending tests fail the suite? */
|
|
23
|
+
forbidPending?: false,
|
|
24
|
+
/** Reporter name. */
|
|
25
|
+
reporter?: string
|
|
26
|
+
/** Options for the reporter */
|
|
27
|
+
reporterOptions?: Record<string, any>,
|
|
28
|
+
/** Number of times to retry failed tests. */
|
|
29
|
+
retries?: number,
|
|
30
|
+
/** Slow threshold value. */
|
|
31
|
+
slow?: number,
|
|
32
|
+
/** Timeout threshold value. */
|
|
33
|
+
timeout?: number,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Writes some info about the current {@link Files} being passed around. */
|
|
37
|
+
export default class Mocha implements Plug<undefined> {
|
|
38
|
+
constructor(private readonly _options: MochaOptions = {}) {}
|
|
39
|
+
|
|
40
|
+
async pipe(files: Files, run: Run): Promise<undefined> {
|
|
41
|
+
// Enter log here, so that log messages called when loading files get
|
|
42
|
+
// properly indented by our logger
|
|
43
|
+
run.log.notice('') // empty line
|
|
44
|
+
run.log.enter(NOTICE, $wht('Starting Mocha'))
|
|
45
|
+
|
|
46
|
+
// Create the mocha runner
|
|
47
|
+
const mocha = new RealMocha({
|
|
48
|
+
diff: true, // by defaut enable diffs
|
|
49
|
+
reporter: PlugReporter, // default to our reporter
|
|
50
|
+
...this._options, // override defaults with all other options
|
|
51
|
+
reporterOptions: {
|
|
52
|
+
...this._options.reporterOptions,
|
|
53
|
+
[logSymbol]: run.log, // always force a log
|
|
54
|
+
[runSymbol]: run, // always force a run
|
|
55
|
+
},
|
|
56
|
+
allowUncaught: false, // never allow uncaught exceptions
|
|
57
|
+
delay: false, // never delay running
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// Tell mocha about all our files
|
|
61
|
+
for (const file of files.absolutePaths()) mocha.addFile(file)
|
|
62
|
+
|
|
63
|
+
await mocha.loadFilesAsync()
|
|
64
|
+
|
|
65
|
+
// Run mocha!
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
try {
|
|
68
|
+
mocha.run((failures) => {
|
|
69
|
+
if (failures) reject(failure())
|
|
70
|
+
resolve(undefined)
|
|
71
|
+
})
|
|
72
|
+
} catch (error) {
|
|
73
|
+
reject(error)
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import ts from 'typescript' // TypeScript does NOT support ESM modules
|
|
2
|
+
|
|
3
|
+
import { AbsolutePath, resolveAbsolutePath } from '../../paths.js'
|
|
4
|
+
|
|
5
|
+
export class TypeScriptHost
|
|
6
|
+
implements ts.CompilerHost {
|
|
7
|
+
constructor(directory: AbsolutePath)
|
|
8
|
+
constructor(private readonly _directory: AbsolutePath) {}
|
|
9
|
+
|
|
10
|
+
/* ======================================================================== */
|
|
11
|
+
|
|
12
|
+
/** Get a source file parsing one of our virtual files */
|
|
13
|
+
getSourceFile(
|
|
14
|
+
fileName: string,
|
|
15
|
+
languageVersion: ts.ScriptTarget,
|
|
16
|
+
): ts.SourceFile | undefined {
|
|
17
|
+
const code = this.readFile(fileName)
|
|
18
|
+
return code ? ts.createSourceFile(fileName, code, languageVersion) : void 0
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Never write any files */
|
|
22
|
+
writeFile(fileName: string): void {
|
|
23
|
+
throw new Error(`Cowardly refusing to write "${fileName}"`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Get the default library associated with the given options */
|
|
27
|
+
getDefaultLibFileName(options: ts.CompilerOptions): string {
|
|
28
|
+
return ts.getDefaultLibFilePath(options)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Check for filesystem case sensitivity */
|
|
32
|
+
useCaseSensitiveFileNames(): boolean {
|
|
33
|
+
return ts.sys.useCaseSensitiveFileNames
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Check for the existence of a given file */
|
|
37
|
+
fileExists(fileName: string): boolean {
|
|
38
|
+
return ts.sys.fileExists(resolveAbsolutePath(this.getCurrentDirectory(), fileName))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Read the file if it exists, otherwise return undefined */
|
|
42
|
+
readFile(fileName: string): string | undefined {
|
|
43
|
+
return ts.sys.readFile(resolveAbsolutePath(this.getCurrentDirectory(), fileName))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Return the current working directory */
|
|
47
|
+
getCurrentDirectory(): AbsolutePath {
|
|
48
|
+
return this._directory
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Return the canonical name for the specified file */
|
|
52
|
+
getCanonicalFileName(fileName: string): string {
|
|
53
|
+
if (ts.sys.useCaseSensitiveFileNames) return fileName
|
|
54
|
+
|
|
55
|
+
// Lifted from TypeScript sources
|
|
56
|
+
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_. ]+/g
|
|
57
|
+
return fileNameLowerCaseRegExp.test(fileName) ?
|
|
58
|
+
fileName.replace(fileNameLowerCaseRegExp, (s) => s.toLowerCase()) :
|
|
59
|
+
fileName
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Return the new line sequence used by this platform */
|
|
63
|
+
getNewLine(): string {
|
|
64
|
+
return ts.sys.newLine
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import ts from 'typescript' // TypeScript does NOT support ESM modules
|
|
2
|
+
|
|
3
|
+
import { AbsolutePath, getAbsoluteParent, resolveAbsolutePath } from '../../paths.js'
|
|
4
|
+
import { readFile } from '../../utils/asyncfs.js'
|
|
5
|
+
|
|
6
|
+
/* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
export type CompilerOptionsAndDiagnostics = {
|
|
9
|
+
options: ts.CompilerOptions,
|
|
10
|
+
errors: readonly ts.Diagnostic[],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* ========================================================================== */
|
|
14
|
+
|
|
15
|
+
function mergeResults(
|
|
16
|
+
base: CompilerOptionsAndDiagnostics,
|
|
17
|
+
override: CompilerOptionsAndDiagnostics,
|
|
18
|
+
): CompilerOptionsAndDiagnostics {
|
|
19
|
+
return {
|
|
20
|
+
options: { ...base.options, ...override.options },
|
|
21
|
+
errors: [ ...base.errors, ...override.errors ],
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* ========================================================================== */
|
|
26
|
+
|
|
27
|
+
async function loadOptions(
|
|
28
|
+
file: AbsolutePath,
|
|
29
|
+
stack: AbsolutePath[] = [ file ],
|
|
30
|
+
): Promise<CompilerOptionsAndDiagnostics> {
|
|
31
|
+
const dir = getAbsoluteParent(file)
|
|
32
|
+
|
|
33
|
+
// Load up our config file and convert is wicked JSON
|
|
34
|
+
const data = await readFile(file, 'utf-8')
|
|
35
|
+
const { config, error } = ts.parseConfigFileTextToJson(file, data)
|
|
36
|
+
if (error) return { options: {}, errors: [ error ] }
|
|
37
|
+
|
|
38
|
+
// Parse up the configuration file as options
|
|
39
|
+
const { compilerOptions = {}, extends: extendsPath } = config
|
|
40
|
+
const result = ts.convertCompilerOptionsFromJson(compilerOptions, dir, file)
|
|
41
|
+
if (result.errors.length) return result
|
|
42
|
+
|
|
43
|
+
// If we don't extend, we can return our result
|
|
44
|
+
if (!extendsPath) return result
|
|
45
|
+
|
|
46
|
+
// Resolve the name of the file this config extends
|
|
47
|
+
const ext = resolveAbsolutePath(dir, extendsPath)
|
|
48
|
+
|
|
49
|
+
// Triple check that we are not recursively importing this file
|
|
50
|
+
if (stack.includes(ext)) {
|
|
51
|
+
return { options: {}, errors: [ {
|
|
52
|
+
messageText: `Circularity detected extending from "${ext}"`,
|
|
53
|
+
category: ts.DiagnosticCategory.Error,
|
|
54
|
+
code: 18000, // copied from typescript internals...
|
|
55
|
+
file: ts.createSourceFile(file, data, ts.ScriptTarget.JSON, false, ts.ScriptKind.JSON),
|
|
56
|
+
start: undefined,
|
|
57
|
+
length: undefined,
|
|
58
|
+
} ] }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Push our file in the stack and load recursively
|
|
62
|
+
return mergeResults(await loadOptions(ext, [ ...stack, ext ]), result)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ========================================================================== */
|
|
66
|
+
|
|
67
|
+
export async function getCompilerOptions(
|
|
68
|
+
file?: AbsolutePath,
|
|
69
|
+
): Promise<CompilerOptionsAndDiagnostics>
|
|
70
|
+
|
|
71
|
+
export async function getCompilerOptions(
|
|
72
|
+
file: AbsolutePath | undefined,
|
|
73
|
+
overrides: ts.CompilerOptions,
|
|
74
|
+
overridesFile: AbsolutePath,
|
|
75
|
+
): Promise<CompilerOptionsAndDiagnostics>
|
|
76
|
+
|
|
77
|
+
/** Load compiler options from a JSON file, and merge in the overrides */
|
|
78
|
+
export async function getCompilerOptions(
|
|
79
|
+
file?: AbsolutePath,
|
|
80
|
+
...override: [ ts.CompilerOptions, AbsolutePath ] | []
|
|
81
|
+
): Promise<CompilerOptionsAndDiagnostics> {
|
|
82
|
+
let result: CompilerOptionsAndDiagnostics = { options: ts.getDefaultCompilerOptions(), errors: [] }
|
|
83
|
+
|
|
84
|
+
// If we have a file to parse, load it, otherwise try "tsconfig.json"
|
|
85
|
+
if (file) result = mergeResults(result, await loadOptions(file))
|
|
86
|
+
|
|
87
|
+
// If we have overrides, merge them
|
|
88
|
+
if (override.length) {
|
|
89
|
+
const [ overrides, overridesFile ] = override
|
|
90
|
+
const overridesDir = getAbsoluteParent(overridesFile)
|
|
91
|
+
const options = ts.convertCompilerOptionsFromJson(overrides, overridesDir, overridesFile)
|
|
92
|
+
result = mergeResults(result, options)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Return all we have
|
|
96
|
+
return result
|
|
97
|
+
}
|