1 | 'use strict'
|
2 |
|
3 | const { redBright, dim } = require('chalk')
|
4 | const execa = require('execa')
|
5 | const debug = require('debug')('lint-staged:task')
|
6 | const { parseArgsStringToArgv } = require('string-argv')
|
7 | const { error, info } = require('log-symbols')
|
8 |
|
9 | const { getInitialState } = require('./state')
|
10 | const { TaskError } = require('./symbols')
|
11 |
|
12 | const getTag = ({ code, killed, signal }) => signal || (killed && 'KILLED') || code || 'FAILED'
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | const handleOutput = (command, result, ctx, isError = false) => {
|
28 | const { stderr, stdout } = result
|
29 | const hasOutput = !!stderr || !!stdout
|
30 |
|
31 | if (hasOutput) {
|
32 | const outputTitle = isError ? redBright(`${error} ${command}:`) : `${info} ${command}:`
|
33 | const output = []
|
34 | .concat(ctx.quiet ? [] : ['', outputTitle])
|
35 | .concat(stderr ? stderr : [])
|
36 | .concat(stdout ? stdout : [])
|
37 | ctx.output.push(output.join('\n'))
|
38 | } else if (isError) {
|
39 |
|
40 | const tag = getTag(result)
|
41 | const message = redBright(`\n${error} ${command} failed without output (${tag}).`)
|
42 | if (!ctx.quiet) ctx.output.push(message)
|
43 | }
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | const makeErr = (command, result, ctx) => {
|
60 | ctx.errors.add(TaskError)
|
61 | handleOutput(command, result, ctx, true)
|
62 | const tag = getTag(result)
|
63 | return new Error(`${redBright(command)} ${dim(`[${tag}]`)}`)
|
64 | }
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 | module.exports = function resolveTaskFn({
|
80 | command,
|
81 | files,
|
82 | gitDir,
|
83 | isFn,
|
84 | relative,
|
85 | shell = false,
|
86 | verbose = false,
|
87 | }) {
|
88 | const [cmd, ...args] = parseArgsStringToArgv(command)
|
89 | debug('cmd:', cmd)
|
90 | debug('args:', args)
|
91 |
|
92 | const execaOptions = { preferLocal: true, reject: false, shell }
|
93 | if (relative) {
|
94 | execaOptions.cwd = process.cwd()
|
95 | } else if (/^git(\.exe)?/i.test(cmd) && gitDir !== process.cwd()) {
|
96 |
|
97 |
|
98 | execaOptions.cwd = gitDir
|
99 | }
|
100 | debug('execaOptions:', execaOptions)
|
101 |
|
102 | return async (ctx = getInitialState()) => {
|
103 | const result = await (shell
|
104 | ? execa.command(isFn ? command : `${command} ${files.join(' ')}`, execaOptions)
|
105 | : execa(cmd, isFn ? args : args.concat(files), execaOptions))
|
106 |
|
107 | if (result.failed || result.killed || result.signal != null) {
|
108 | throw makeErr(command, result, ctx)
|
109 | }
|
110 |
|
111 | if (verbose) {
|
112 | handleOutput(command, result, ctx)
|
113 | }
|
114 | }
|
115 | }
|