-
Notifications
You must be signed in to change notification settings - Fork 2
/
commands.js
408 lines (319 loc) · 14.8 KB
/
commands.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
// @ts-check
const path = require('path')
const fs = require('fs')
const {showName} = require('../scripts/name.js')
const config = require('../config/getUserConfig.js')
const {exec} = require('../scripts/exec.js')
// TODO read CLI options from a project's lume.config too.
let cli
module.exports.setCli = function (_cli) {
cli = _cli
}
let opts
module.exports.setOpts = function (options) {
opts = options
}
exports.showName = showName
// We use these so that no matter if we are running in a Yarn or Npm env (which
// set PATH differently), we'll always be able to run the needed bins by relying
// on Node.js module lookup algo (calling them directly might fail if they are
// not in PATH)
const tscBin = path.resolve(require.resolve('typescript'), '..', '..', 'bin', 'tsc')
const gulpBin = path.resolve(require.resolve('gulp'), '..', 'bin', 'gulp.js')
const babelBin = path.resolve(require.resolve('@babel/cli'), '..', 'bin', 'babel.js')
const prettierBin = path.resolve(require.resolve('prettier'), '..', 'bin', 'prettier.cjs')
exports.build = build
async function build({skipClean = false, noFailOnError = opts.noFail} = {}) {
if (opts.verbose) console.log(`===> Running the "build" command.\n`)
await Promise.all([
showName(),
copyAssets(),
(async function () {
if (!skipClean) await clean()
const builtTs = await buildTs({noFailOnError})
if (!builtTs) {
console.log('No sources to build.')
return
}
})(),
])
if (opts.verbose) console.log(`===> Done running the "build" command.\n`)
}
exports.clean = clean
async function clean() {
if (opts.verbose) console.log(`===> Running the "clean" command.\n`)
const rmrf = require('rimraf')
const {promisify} = require('util')
await exec(`node ${tscBin} --build --clean`)
await Promise.all([promisify(rmrf)('dist'), promisify(rmrf)('tsconfig.tsbuildinfo')])
if (opts.verbose) console.log(`===> Done running the "clean" command.\n`)
}
exports.dev = dev
async function dev() {
if (opts.verbose) console.log(`===> Running the "dev" command.\n`)
// Skip cleaning in dev mode, makes things easier like not breaking an
// active type check process or webpack build.
await build({skipClean: true, noFailOnError: true})
const promises = []
promises.push(watchTs())
await Promise.all(promises)
if (opts.verbose) console.log(`===> Done running the "dev" command.\n`)
}
exports.copyAssets = copyAssets
async function copyAssets() {
if (opts.verbose) console.log(`===> Running the "copyAssets" command.\n`)
await exec(`node ${gulpBin} --cwd ${process.cwd()} --gulpfile ./node_modules/@lume/cli/config/gulpfile.js copyAssets`)
if (opts.verbose) console.log(`===> Done running the "copyAssets" command.\n`)
}
exports.buildTs = buildTs
async function buildTs({babelConfig = undefined, tsConfig2 = undefined, noFailOnError = opts.noFail} = {}) {
if (opts.verbose) console.log(`===> Running the "buildTs" command.\n`)
const start = performance.now()
const fs = require('fs')
// If babelConfig is not undefined, it means we're building using babel for testing decorator configs.
// TODO we need to use babel to compile JSX expressions.
if (!babelConfig) {
try {
// TODO If there's no user tsconfig fall back to cli's tsconfig. We
// might need to temporarily write it to the project root.
await fs.promises.access(path.resolve(process.cwd(), 'tsconfig.json'))
} catch (e) {
console.log('No tsconfig file found. Skipping TypeScript build.')
if (opts.verbose) console.log(`===> Done running the "buildTs" command.\n`)
// Don't try to run TypeScript build if no tsconfig.json file is present.
return false
}
const {tsProjectReferenceMode} = require('../config/getUserConfig')
// The use of tsConfig2 here is namely to test @lume/element and
// @lume/variable decorators with TypeScript useDefineForClassFields
// true and false to ensure they work in both cases.
let file = 'tsconfig.json'
if (tsConfig2) file = 'tsconfig2.json'
const tsCliOptions = cli.rawArgs.join(' ').split(' -- ')[1]
const command = `node ${tscBin} ${tsProjectReferenceMode ? '--build --incremental' : '-p'} ./${file} ${
tsCliOptions ?? ''
} ${noFailOnError ? '|| echo ""' : ''}`
if (opts.verbose) console.log(`=====> Running \`${command}\`.\n`)
await exec(command)
} else {
const command = `node ${babelBin} --config-file ${babelConfig} --extensions .ts,.tsx src --out-dir ./dist`
if (opts.verbose) console.log(`=====> Running \`${command}\`.\n`)
// This is used while testing with all the possible Babel decorator
// configs (namely for @lume/element and @lume/variable).
await exec(command)
}
const end = performance.now()
if (opts.verbose) console.log(`===> Done running the "buildTs" command. (${Math.round(end - start)}ms) \n`)
return true
}
// TODO Project Reference mode for watch mode?
exports.watchTs = watchTs
async function watchTs() {
const tsCliOptions = cli.rawArgs.join(' ').split(' -- ')[1]
const command = `node ${tscBin} -p ./tsconfig.json --watch ${tsCliOptions ?? ''}`
if (opts.verbose) {
console.log(`===> Running the "watchTs" command.\n`)
console.log(`=====> Running \`${command}\`.\n`)
}
await exec(command)
if (opts.verbose) console.log(`===> Done running the "watchTs" command.\n`)
}
// TODO Project Reference mode while type checking?
exports.typecheck = typecheck
async function typecheck() {
const tsCliOptions = cli.rawArgs.join(' ').split(' -- ')[1]
const command = `node ${tscBin} -p ./tsconfig.json --noEmit ${tsCliOptions ?? ''}`
if (opts.verbose) {
console.log(`===> Running the "typecheck" command.\n`)
console.log(`=====> Running \`${command}\`\n`)
}
await exec(command)
if (opts.verbose) console.log(`===> Done running the "typecheck" command.\n`)
}
// TODO Project Reference mode while type checking in watch mode?
exports.typecheckWatch = typecheckWatch
async function typecheckWatch() {
const tsCliOptions = cli.rawArgs.join(' ').split(' -- ')[1]
const command = `node ${tscBin} -p ./tsconfig.json --noEmit --watch ${tsCliOptions ?? ''}`
if (opts.verbose) {
console.log(`===> Running the "typecheckWatch" command.\n`)
console.log(`=====> Running \`${command}\`\n`)
}
await exec(command)
if (opts.verbose) console.log(`===> Done running the "typecheckWatch" command.\n`)
}
exports.test = test
async function test() {
if (opts.verbose) console.log(`===> Running the "test" command.\n`)
// This option was made mainly with @lume/variable and @lume/element, to
// test the code with all TypeScript and Babel decorator configs.
const {testWithAllTSAndBabelDecoratorBuildConfigurations} = require('../config/getUserConfig')
// FIXME This is a mess, but it works: the build() step here runs
// buildTs(), but then we also redundantly run buildTs() here after.
await Promise.all([build(), prettierCheck()])
const karmaCommand = `node ${path.resolve(__dirname, '..', 'scripts', 'run-karma-tests.js')}`
if (testWithAllTSAndBabelDecoratorBuildConfigurations) {
let builtTs = false
console.log(`=====> Running the permutations of decorator test builds.\n`)
builtTs = await buildTs({babelConfig: './node_modules/@lume/cli/config/babel.decorator-config.1.js'})
if (!builtTs) return console.log('No sources found, skipping tests.')
await exec(karmaCommand, {env: {DECORATOR_CAUSES_NONWRITABLE_ERROR: 'true'}})
builtTs = await buildTs({babelConfig: './node_modules/@lume/cli/config/babel.decorator-config.2.js'})
if (!builtTs) return console.log('No sources found, skipping tests.')
await exec(karmaCommand, {env: {DECORATOR_CAUSES_NONWRITABLE_ERROR: 'true'}})
builtTs = await buildTs({babelConfig: './node_modules/@lume/cli/config/babel.decorator-config.3.js'})
if (!builtTs) return console.log('No sources found, skipping tests.')
await exec(karmaCommand)
builtTs = await buildTs({babelConfig: './node_modules/@lume/cli/config/babel.decorator-config.4.js'})
if (!builtTs) return console.log('No sources found, skipping tests.')
await exec(karmaCommand)
// TODO The tsConfig2 option here requires the dependent app to have a
// tsconfig2.json file. The CLI should not require any tsconfig files,
// they should be optional. We should look for those files, and fall
// back to files here in the CLI.
builtTs = await buildTs({tsConfig2: true})
if (!builtTs) return console.log('No sources found, skipping tests.')
await exec(karmaCommand)
}
const builtTs = await buildTs()
// TODO if sources found, but no test files, also skip instead of error.
if (!builtTs) return console.log('No sources found, skipping tests.')
await exec(karmaCommand)
if (opts.verbose) console.log(`===> Done running the "test" command.\n`)
}
exports.testDebug = testDebug
async function testDebug() {
if (opts.verbose) console.log(`===> Running the "testDebug" command.\n`)
const [builtTs] = await Promise.all([buildTs(), showName()])
// TODO if sources found, but no tests files, also skip instead of error.
if (!builtTs) return console.log('No sources found, skipping tests.')
const karmaCommand = path.resolve(__dirname, '..', 'scripts', 'run-karma-tests.sh')
await exec(karmaCommand, {env: {KARMA_DEBUG: 'true'}})
if (opts.verbose) console.log(`===> Done running the "testDebug" command.\n`)
}
exports.releasePre = releasePre
async function releasePre() {
if (opts.verbose) console.log(`===> Running the "releasePre" command.\n`)
const command = path.resolve(__dirname, '..', 'scripts', 'release-pre.sh')
if (opts.verbose) console.log(`=====> Running \`${command}\`.\n`)
await exec(command)
if (opts.verbose) console.log(`===> Done running the "releasePre" command.\n`)
}
exports.releasePatch = releasePatch
async function releasePatch() {
if (opts.verbose) console.log(`===> Running the "releasePatch" command.\n`)
await releasePre()
await exec('npm version --no-workspaces patch -m v%s')
if (opts.verbose) console.log(`===> Done running the "releasePatch" command.\n`)
}
exports.releaseMinor = releaseMinor
async function releaseMinor() {
if (opts.verbose) console.log(`===> Running the "releaseMinor" command.\n`)
await releasePre()
await exec('npm version --no-workspaces minor -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseMinor" command.\n`)
}
exports.releaseMajor = releaseMajor
async function releaseMajor() {
if (opts.verbose) console.log(`===> Running the "releaseMajor" command.\n`)
await releasePre()
await exec('npm version --no-workspaces major -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseMajor" command.\n`)
}
exports.releaseAlphaMajor = releaseAlphaMajor
async function releaseAlphaMajor() {
if (opts.verbose) console.log(`===> Running the "releaseAlphaMajor" command.\n`)
await releasePre()
await exec('npm version --no-workspaces premajor --preid alpha -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseAlphaMajor" command.\n`)
}
exports.releaseAlphaMinor = releaseAlphaMinor
async function releaseAlphaMinor() {
if (opts.verbose) console.log(`===> Running the "releaseAlphaMinor" command.\n`)
await releasePre()
await exec('npm version --no-workspaces preminor --preid alpha -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseAlphaMinor" command.\n`)
}
exports.releaseAlphaPatch = releaseAlphaPatch
async function releaseAlphaPatch() {
if (opts.verbose) console.log(`===> Running the "releaseAlphaPatch" command.\n`)
await releasePre()
await exec('npm version --no-workspaces prepatch --preid alpha -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseAlphaPatch" command.\n`)
}
exports.releaseBetaMajor = releaseBetaMajor
async function releaseBetaMajor() {
if (opts.verbose) console.log(`===> Running the "releaseBetaMajor" command.\n`)
await releasePre()
await exec('npm version --no-workspaces premajor --preid beta -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseBetaMajor" command.\n`)
}
exports.releaseBetaMinor = releaseBetaMinor
async function releaseBetaMinor() {
if (opts.verbose) console.log(`===> Running the "releaseBetaMinor" command.\n`)
await releasePre()
await exec('npm version --no-workspaces preminor --preid beta -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseBetaMinor" command.\n`)
}
exports.releaseBetaPatch = releaseBetaPatch
async function releaseBetaPatch() {
if (opts.verbose) console.log(`===> Running the "releaseBetaPatch" command.\n`)
await releasePre()
await exec('npm version --no-workspaces prepatch --preid beta -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseBetaPatch" command.\n`)
}
exports.releaseAlpha = releaseAlpha
async function releaseAlpha() {
if (opts.verbose) console.log(`===> Running the "releaseAlpha" command.\n`)
await releasePre()
await exec('npm version --no-workspaces prerelease --preid alpha -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseAlpha" command.\n`)
}
exports.releaseBeta = releaseBeta
async function releaseBeta() {
if (opts.verbose) console.log(`===> Running the "releaseBeta" command.\n`)
await releasePre()
await exec('npm version --no-workspaces prerelease --preid beta -m v%s')
if (opts.verbose) console.log(`===> Done running the "releaseBeta" command.\n`)
}
exports.versionHook = versionHook
async function versionHook() {
if (opts.verbose) console.log(`===> Running the "versionHook" command.\n`)
await exec('./node_modules/@lume/cli/scripts/version.sh')
if (opts.verbose) console.log(`===> Done running the "versionHook" command.\n`)
}
exports.postVersionHook = postVersionHook
async function postVersionHook() {
if (opts.verbose) console.log(`===> Running the "postVersionHook" command.\n`)
await exec('./node_modules/@lume/cli/scripts/postversion.sh')
if (opts.verbose) console.log(`===> Done running the "postVersionHook" command.\n`)
}
const prettierConfig =
'--config ' +
(fs.existsSync('.prettierrc.js')
? '.prettierrc.js'
: fs.existsSync('.prettierrc.cjs')
? '.prettierrc.cjs'
: './node_modules/@lume/cli/.prettierrc.js')
const prettierIgnore =
'--ignore-path ' +
(config.prettierIgnorePath ??
(fs.existsSync('.prettierignore') ? '.prettierignore' : './node_modules/@lume/cli/.prettierignore'))
// Check formatting of all supported file types in the project.
const prettierFiles = process.cwd()
exports.prettier = prettier
async function prettier() {
if (opts.verbose) console.log(`===> Running the "prettier" command.\n`)
const command = `node ${prettierBin} ${prettierConfig} ${prettierIgnore} --write ${prettierFiles}`
if (opts.verbose) console.log(`=====> Running \`${command}\`\n`)
await exec(command)
if (opts.verbose) console.log(`===> Done running the "prettier" command.\n`)
}
exports.prettierCheck = prettierCheck
async function prettierCheck() {
if (opts.verbose) console.log(`===> Running the "prettierCheck" command.\n`)
const command = `node ${prettierBin} ${prettierConfig} ${prettierIgnore} --check ${prettierFiles}`
if (opts.verbose) console.log(`=====> Running \`${command}\`\n`)
await exec(command)
if (opts.verbose) console.log(`===> Done running the "prettierCheck" command.\n`)
}