lint-staged 16.1.6 → 16.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
- import chalk from 'chalk'
2
- import debug from 'debug'
3
1
  import spawn from 'nano-spawn'
4
2
  import pidtree from 'pidtree'
5
3
  import { parseArgsStringToArgv } from 'string-argv'
6
4
 
5
+ import { blackBright, red } from './colors.js'
6
+ import { createDebug } from './debug.js'
7
7
  import { error, info } from './figures.js'
8
8
  import { getInitialState } from './state.js'
9
9
  import { TaskError } from './symbols.js'
10
10
 
11
11
  const TASK_ERROR = 'lint-staged:taskError'
12
12
 
13
- const debugLog = debug('lint-staged:getSpawnedTask')
13
+ const debugLog = createDebug('lint-staged:getSpawnedTask')
14
14
 
15
15
  /** @type {(error: import('nano-spawn').SubprocessError) => string} */
16
16
  const getTag = (error) => {
@@ -27,13 +27,13 @@ const getTag = (error) => {
27
27
  */
28
28
  const handleOutput = (command, result, ctx, isError = false) => {
29
29
  if (result.output) {
30
- const outputTitle = isError ? chalk.redBright(`${error} ${command}:`) : `${info} ${command}:`
30
+ const outputTitle = isError ? red(`${error} ${command}:`) : `${info} ${command}:`
31
31
  const output = [...(ctx.quiet ? [] : ['', outputTitle]), result.output]
32
32
  ctx.output.push(output.join('\n'))
33
33
  } else if (isError) {
34
34
  // Show generic error when task had no output
35
35
  const tag = getTag(result)
36
- const message = chalk.redBright(`\n${error} ${command} failed without output (${tag}).`)
36
+ const message = red(`\n${error} ${command} failed without output (${tag}).`)
37
37
  if (!ctx.quiet) ctx.output.push(message)
38
38
  }
39
39
  }
@@ -108,13 +108,14 @@ export const makeErr = (command, error, ctx) => {
108
108
 
109
109
  handleOutput(command, error, ctx, true)
110
110
  const tag = getTag(error)
111
- return new Error(`${chalk.redBright(command)} ${chalk.dim(`[${tag}]`)}`)
111
+ return new Error(`${red(command)} ${blackBright(`[${tag}]`)}`)
112
112
  }
113
113
 
114
114
  /**
115
115
  * Returns the task function for the linter.
116
116
  *
117
117
  * @param {Object} options
118
+ * @param {boolean} [options.color]
118
119
  * @param {string} options.command — Linter task
119
120
  * @param {string} [options.cwd]
120
121
  * @param {String} options.topLevelDir - Current git repo top-level path
@@ -124,6 +125,7 @@ export const makeErr = (command, error, ctx) => {
124
125
  * @returns {() => Promise<Array<string>>}
125
126
  */
126
127
  export const getSpawnedTask = ({
128
+ color,
127
129
  command,
128
130
  cwd = process.cwd(),
129
131
  files,
@@ -141,6 +143,7 @@ export const getSpawnedTask = ({
141
143
  cwd: /^git(\.exe)?/i.test(cmd) ? topLevelDir : cwd,
142
144
  preferLocal: true,
143
145
  stdin: 'ignore',
146
+ env: color ? { FORCE_COLOR: 'true' } : { NO_COLOR: 'true' },
144
147
  }
145
148
 
146
149
  debugLog('Spawn options:', spawnOptions)
@@ -1,21 +1,21 @@
1
- import debug from 'debug'
2
-
1
+ import { createDebug } from './debug.js'
3
2
  import { getSpawnedTask } from './getSpawnedTask.js'
4
3
  import { configurationError } from './messages.js'
5
4
 
6
- const debugLog = debug('lint-staged:getSpawnedTasks')
5
+ const debugLog = createDebug('lint-staged:getSpawnedTasks')
7
6
 
8
7
  /**
9
8
  * Creates and returns an array of listr tasks which map to the given commands.
10
9
  *
11
10
  * @param {object} options
11
+ * @param {boolean} [options.color]
12
12
  * @param {Array<string|Function>|string|Function} options.commands
13
13
  * @param {string} options.cwd
14
14
  * @param {import('./getStagedFiles.js').StagedFile[]} options.files
15
15
  * @param {string} options.topLevelDir
16
16
  * @param {Boolean} verbose
17
17
  */
18
- export const getSpawnedTasks = async ({ commands, cwd, files, topLevelDir, verbose }) => {
18
+ export const getSpawnedTasks = async ({ color, commands, cwd, files, topLevelDir, verbose }) => {
19
19
  debugLog('Creating Listr tasks for commands %o', commands)
20
20
  const cmdTasks = []
21
21
 
@@ -45,7 +45,16 @@ export const getSpawnedTasks = async ({ commands, cwd, files, topLevelDir, verbo
45
45
  )
46
46
  }
47
47
 
48
- const task = getSpawnedTask({ command, cwd, files: filepaths, topLevelDir, isFn, verbose })
48
+ const task = getSpawnedTask({
49
+ color,
50
+ command,
51
+ cwd,
52
+ files: filepaths,
53
+ topLevelDir,
54
+ isFn,
55
+ verbose,
56
+ })
57
+
49
58
  cmdTasks.push({ title: command, command, task })
50
59
  }
51
60
  }
@@ -1,13 +1,14 @@
1
+ import crypto from 'node:crypto'
1
2
  import fs from 'node:fs/promises'
2
3
  import path from 'node:path'
3
4
 
4
- import debug from 'debug'
5
-
5
+ import { createDebug } from './debug.js'
6
6
  import { execGit } from './execGit.js'
7
7
  import { readFile, unlink, writeFile } from './file.js'
8
8
  import { getDiffCommand } from './getDiffCommand.js'
9
9
  import {
10
10
  ApplyEmptyCommitError,
11
+ ExitCodeError,
11
12
  GetBackupStashError,
12
13
  GitError,
13
14
  HideUnstagedChangesError,
@@ -16,7 +17,7 @@ import {
16
17
  RestoreUnstagedChangesError,
17
18
  } from './symbols.js'
18
19
 
19
- const debugLog = debug('lint-staged:GitWorkflow')
20
+ const debugLog = createDebug('lint-staged:GitWorkflow')
20
21
 
21
22
  const MERGE_HEAD = 'MERGE_HEAD'
22
23
  const MERGE_MODE = 'MERGE_MODE'
@@ -66,21 +67,32 @@ const handleError = (error, ctx, symbol) => {
66
67
  throw error
67
68
  }
68
69
 
70
+ const calculateSha256 = (input) => crypto.createHash('sha256').update(input, 'utf-8').digest('hex')
71
+
69
72
  export class GitWorkflow {
70
73
  /**
71
74
  * @param {Object} opts
72
75
  * @param {import('./getStagedFiles.js').StagedFile[][]} opts.matchedFileChunks
73
76
  */
74
- constructor({ allowEmpty, gitConfigDir, topLevelDir, matchedFileChunks, diff, diffFilter }) {
77
+ constructor({
78
+ allowEmpty,
79
+ diff,
80
+ diffFilter,
81
+ failOnChanges,
82
+ gitConfigDir,
83
+ matchedFileChunks,
84
+ topLevelDir,
85
+ }) {
75
86
  this.execGit = (args, options = {}) => execGit(args, { ...options, cwd: topLevelDir })
87
+ this.allowEmpty = allowEmpty
76
88
  this.deletedFiles = []
77
- this.gitConfigDir = gitConfigDir
78
- this.topLevelDir = topLevelDir
79
89
  this.diff = diff
80
90
  this.diffFilter = diffFilter
81
- this.allowEmpty = allowEmpty
91
+ this.gitConfigDir = gitConfigDir
92
+ this.failOnChanges = !!failOnChanges
82
93
  /** @type {import('./getStagedFiles.js').StagedFile[][]} */
83
94
  this.matchedFileChunks = matchedFileChunks
95
+ this.topLevelDir = topLevelDir
84
96
 
85
97
  /**
86
98
  * These three files hold state about an ongoing git merge
@@ -172,7 +184,7 @@ export class GitWorkflow {
172
184
  * Renames have special treatment, since the single status line includes
173
185
  * both the "from" and "to" filenames, where "from" is no longer on disk.
174
186
  */
175
- async getPartiallyStagedFiles() {
187
+ async getUnstagedFiles({ onlyPartial = false } = {}) {
176
188
  debugLog('Getting partially staged files...')
177
189
  const status = await this.execGit(['status', '-z'])
178
190
  /**
@@ -184,69 +196,85 @@ export class GitWorkflow {
184
196
  * renamed file, the file names are separated by a NUL character
185
197
  * (e.g. `to`\0`from`)
186
198
  */
187
- const partiallyStaged = status
199
+ const unstagedFiles = status
188
200
  // eslint-disable-next-line no-control-regex
189
201
  .split(/\x00(?=[ AMDRCU?!]{2} |$)/)
190
202
  .filter((line) => {
191
203
  const [index, workingTree] = line
192
- return index !== ' ' && workingTree !== ' ' && index !== '?' && workingTree !== '?'
204
+ const updatedInIndex = index !== ' ' && index !== '?'
205
+ const updatedInWorkingTree = workingTree !== ' ' && workingTree !== '?'
206
+
207
+ if (onlyPartial) {
208
+ return updatedInIndex && updatedInWorkingTree
209
+ }
210
+
211
+ return updatedInWorkingTree
193
212
  })
194
213
  .map((line) => line.slice(3)) // Remove first three letters (index, workingTree, and a whitespace)
195
- .filter(Boolean) // Filter empty string
196
- debugLog('Found partially staged files:', partiallyStaged)
197
- return partiallyStaged.length ? partiallyStaged : null
214
+ .filter(Boolean) // Filter empty strings
215
+ debugLog(`Found ${onlyPartial ? 'partially staged' : 'unstaged'} files:`, unstagedFiles)
216
+ return unstagedFiles.length ? unstagedFiles : null
198
217
  }
199
218
 
200
219
  /**
201
- * Create a diff of partially staged files and backup stash if enabled.
220
+ * Create a diff of unstaged or partially staged files and backup stash if enabled.
202
221
  */
203
222
  async prepare(ctx, task) {
204
223
  try {
205
224
  debugLog(task.title)
206
225
 
207
- // Get a list of files with both staged and unstaged changes.
208
- // Unstaged changes to these files should be hidden before the tasks run.
209
- this.partiallyStagedFiles = await this.getPartiallyStagedFiles()
210
-
211
- if (this.partiallyStagedFiles) {
212
- ctx.hasPartiallyStagedFiles = true
213
- const unstagedPatch = this.getHiddenFilepath(PATCH_UNSTAGED)
214
- ctx.unstagedPatch = unstagedPatch
215
- const files = processRenames(this.partiallyStagedFiles)
216
- await this.execGit(['diff', ...GIT_DIFF_ARGS, '--output', unstagedPatch, '--', ...files])
217
- } else {
218
- ctx.hasPartiallyStagedFiles = false
226
+ if (ctx.shouldBackup) {
227
+ // When backup is enabled, the revert will clear ongoing merge status.
228
+ await this.backupMergeStatus()
229
+
230
+ // Get a list of unstaged deleted files, because certain bugs might cause them to reappear:
231
+ // - in git versions =< 2.13.0 the `git stash --keep-index` option resurrects deleted files
232
+ // - git stash can't infer RD or MD states correctly, and will lose the deletion
233
+ this.deletedFiles = await this.getDeletedFiles()
234
+
235
+ // Save stash of all staged files.
236
+ // The `stash create` command creates a dangling commit without removing any files,
237
+ // and `stash store` saves it as an actual stash.
238
+ const stashHash = await this.execGit(['stash', 'create'])
239
+ ctx.backupHash = await this.execGit(['rev-parse', '--short', stashHash])
240
+ await this.execGit([
241
+ 'stash',
242
+ 'store',
243
+ '--quiet',
244
+ '--message',
245
+ `${STASH} (${ctx.backupHash})`,
246
+ ctx.backupHash,
247
+ ])
248
+
249
+ task.title = `Backed up original state in git stash (${ctx.backupHash})`
250
+ debugLog(task.title)
219
251
  }
220
252
 
221
- /**
222
- * If backup stash should be skipped, no need to continue
223
- */
224
- if (!ctx.shouldBackup) return
225
-
226
- // When backup is enabled, the revert will clear ongoing merge status.
227
- await this.backupMergeStatus()
228
-
229
- // Get a list of unstaged deleted files, because certain bugs might cause them to reappear:
230
- // - in git versions =< 2.13.0 the `git stash --keep-index` option resurrects deleted files
231
- // - git stash can't infer RD or MD states correctly, and will lose the deletion
232
- this.deletedFiles = await this.getDeletedFiles()
233
-
234
- // Save stash of all staged files.
235
- // The `stash create` command creates a dangling commit without removing any files,
236
- // and `stash store` saves it as an actual stash.
237
- const stashHash = await this.execGit(['stash', 'create'])
238
- ctx.backupHash = await this.execGit(['rev-parse', '--short', stashHash])
239
- await this.execGit([
240
- 'stash',
241
- 'store',
242
- '--quiet',
243
- '--message',
244
- `${STASH} (${ctx.backupHash})`,
245
- ctx.backupHash,
246
- ])
253
+ if (this.failOnChanges) {
254
+ debugLog(
255
+ 'Calculating SHA-256 hash of unstaged changes because "--fail-on-changes" was used...'
256
+ )
257
+ const diff = await this.execGit(['diff', '--patch', '--unified=0'])
258
+ this.unstagedDiffSha256 = calculateSha256(diff)
259
+ debugLog('SHA-256 hash of unstaged changes is %S', this.unstagedDiffSha256)
260
+ }
247
261
 
248
- task.title = `Backed up original state in git stash (${ctx.backupHash})`
249
- debugLog(task.title)
262
+ if (ctx.shouldHideUnstaged || ctx.shouldHidePartiallyStaged) {
263
+ // Unstaged changes to these files should be hidden before the tasks run.
264
+ this.unstagedFiles = await this.getUnstagedFiles({
265
+ onlyPartial: ctx.shouldHideUnstaged ? false : ctx.shouldHidePartiallyStaged,
266
+ })
267
+
268
+ if (this.unstagedFiles) {
269
+ ctx.hasFilesToHide = true
270
+ const unstagedPatch = this.getHiddenFilepath(PATCH_UNSTAGED)
271
+ ctx.unstagedPatch = unstagedPatch
272
+ const files = processRenames(this.unstagedFiles)
273
+ await this.execGit(['diff', ...GIT_DIFF_ARGS, '--output', unstagedPatch, '--', ...files])
274
+ } else {
275
+ ctx.hasFilesToHide = false
276
+ }
277
+ }
250
278
  } catch (error) {
251
279
  handleError(error, ctx)
252
280
  }
@@ -257,7 +285,7 @@ export class GitWorkflow {
257
285
  */
258
286
  async hideUnstagedChanges(ctx) {
259
287
  try {
260
- const files = processRenames(this.partiallyStagedFiles, false)
288
+ const files = processRenames(this.unstagedFiles, false)
261
289
  await this.execGit(['checkout', '--force', '--', ...files])
262
290
  } catch (error) {
263
291
  /**
@@ -273,6 +301,19 @@ export class GitWorkflow {
273
301
  * In case of a merge-conflict retry with 3-way merge.
274
302
  */
275
303
  async applyModifications(ctx) {
304
+ if (this.failOnChanges) {
305
+ debugLog(
306
+ 'Calculating SHA-256 hash of changes after tasks because "--fail-on-changes" was used...'
307
+ )
308
+ const diff = await this.execGit(['diff', '--patch', '--unified=0'])
309
+ const diffSha256 = calculateSha256(diff)
310
+ debugLog('SHA-256 hash of changes after tasks is %S', this.diffSha256)
311
+ if (this.unstagedDiffSha256 !== diffSha256) {
312
+ ctx.errors.add(ExitCodeError)
313
+ throw new Error('Tasks modified files and --fail-on-changes was used!')
314
+ }
315
+ }
316
+
276
317
  debugLog('Adding task modifications to index...')
277
318
 
278
319
  // `matchedFileChunks` includes staged files that lint-staged originally detected and matched against a task.
@@ -1,8 +1,8 @@
1
1
  import path from 'node:path'
2
2
 
3
- import debug from 'debug'
3
+ import { createDebug } from './debug.js'
4
4
 
5
- const debugLog = debug('lint-staged:groupFilesByConfig')
5
+ const debugLog = createDebug('lint-staged:groupFilesByConfig')
6
6
 
7
7
  /**
8
8
  * @typedef {import('./getStagedFiles.js').StagedFile} StagedFile
package/lib/index.d.ts CHANGED
@@ -32,6 +32,11 @@ export type Options = {
32
32
  * Path to single configuration file; disables automatic config file discovery when used
33
33
  */
34
34
  configPath?: string
35
+ /**
36
+ * Run all tasks to completion even if one fails
37
+ * @default false
38
+ */
39
+ continueOnError?: boolean
35
40
  /**
36
41
  * Working directory to run all tasks in, defaults to current working directory
37
42
  */
@@ -52,10 +57,25 @@ export type Options = {
52
57
  * @default "ACMR"
53
58
  */
54
59
  diffFilter?: string
60
+ /**
61
+ * Fail with exit code 1 when tasks modify tracked files
62
+ * @default false
63
+ */
64
+ failOnChanges?: true
55
65
  /**
56
66
  * Maximum argument string length, by default automatically detected
57
67
  */
58
68
  maxArgLength?: number
69
+ /**
70
+ * Whether to hide unstaged changes from partially staged files before running tasks
71
+ * @default true
72
+ */
73
+ hidePartiallyStaged?: boolean
74
+ /**
75
+ * Whether to hide all unstaged changes before running tasks
76
+ * @default false
77
+ */
78
+ hideUnstaged?: boolean
59
79
  /**
60
80
  * Disable lint-staged’s own console output
61
81
  * @default false
@@ -77,11 +97,6 @@ export type Options = {
77
97
  * @default true
78
98
  */
79
99
  stash?: boolean
80
- /**
81
- * Whether to hide unstaged changes from partially staged files before running tasks
82
- * @default true
83
- */
84
- hidePartiallyStaged?: boolean
85
100
  /**
86
101
  * Show task output even when tasks succeed; by default only failed output is shown
87
102
  * @default false
package/lib/index.js CHANGED
@@ -1,10 +1,11 @@
1
- import debugLib from 'debug'
2
-
1
+ import { SUPPORTS_COLOR } from './colors.js'
2
+ import { createDebug, enableDebug } from './debug.js'
3
3
  import { execGit } from './execGit.js'
4
4
  import {
5
5
  GIT_ERROR,
6
6
  NO_CONFIGURATION,
7
7
  PREVENTED_EMPTY_COMMIT,
8
+ PREVENTED_TASK_MODIFICATIONS,
8
9
  RESTORE_STASH_EXAMPLE,
9
10
  UNSTAGED_CHANGES_BACKUP_STASH_LOCATION,
10
11
  } from './messages.js'
@@ -14,6 +15,7 @@ import { cleanupSkipped } from './state.js'
14
15
  import {
15
16
  ApplyEmptyCommitError,
16
17
  ConfigNotFoundError,
18
+ ExitCodeError,
17
19
  GetBackupStashError,
18
20
  GitError,
19
21
  RestoreUnstagedChangesError,
@@ -21,7 +23,7 @@ import {
21
23
  import { validateOptions } from './validateOptions.js'
22
24
  import { getVersion } from './version.js'
23
25
 
24
- const debugLog = debugLib('lint-staged')
26
+ const debugLog = createDebug('lint-staged')
25
27
 
26
28
  /**
27
29
  * Get the maximum length of a command-line argument string based on current platform
@@ -49,13 +51,18 @@ const getMaxArgLength = () => {
49
51
  *
50
52
  * @param {object} options
51
53
  * @param {Object} [options.allowEmpty] - Allow empty commits when tasks revert all staged changes
54
+ * @param {Object} [options.color] - Enable ANSI colors in output
52
55
  * @param {boolean | number} [options.concurrent] - The number of tasks to run concurrently, or false to run tasks serially
53
56
  * @param {object} [options.config] - Object with configuration for programmatic API
54
57
  * @param {string} [options.configPath] - Path to configuration file
58
+ * @param {boolean} [options.continueOnError] - Run all tasks to completion even if one fails
55
59
  * @param {Object} [options.cwd] - Current working directory
56
60
  * @param {boolean} [options.debug] - Enable debug mode
57
61
  * @param {string} [options.diff] - Override the default "--staged" flag of "git diff" to get list of files
58
62
  * @param {string} [options.diffFilter] - Override the default "--diff-filter=ACMR" flag of "git diff" to get list of files
63
+ * @param {boolean} [options.failOnChanges] - Fail with exit code 1 when tasks modify tracked files
64
+ * @param {boolean} [options.hidePartiallyStaged] - Whether to hide unstaged changes from partially staged files before running tasks
65
+ * @param {boolean} [options.hideUnstaged] - Whether to hide all unstaged changes before running tasks
59
66
  * @param {number} [options.maxArgLength] - Maximum argument string length
60
67
  * @param {boolean} [options.quiet] - Disable lint-staged’s own console output
61
68
  * @param {boolean} [options.relative] - Pass relative filepaths to tasks
@@ -69,28 +76,32 @@ const getMaxArgLength = () => {
69
76
  const lintStaged = async (
70
77
  {
71
78
  allowEmpty = false,
79
+ color = SUPPORTS_COLOR,
72
80
  concurrent = true,
73
81
  config: configObject,
74
82
  configPath,
83
+ continueOnError = false,
75
84
  cwd,
76
85
  debug = false,
77
86
  diff,
78
87
  diffFilter,
88
+ failOnChanges = false,
89
+ hidePartiallyStaged = true,
90
+ hideUnstaged = false,
79
91
  maxArgLength = getMaxArgLength() / 2,
80
92
  quiet = false,
81
93
  relative = false,
82
94
  // Stashing should be disabled by default when the `diff` option is used
83
95
  stash = diff === undefined,
84
- // Cannot revert to original state without stash
85
- revert = stash,
86
- hidePartiallyStaged = true,
96
+ // Default to false when using failOnChanges; cannot revert to original state without stash
97
+ revert = !failOnChanges && !!stash,
87
98
  verbose = false,
88
99
  } = {},
89
100
  logger = console
90
101
  ) => {
91
102
  // Seemingly enable debug twice (also done in bin), so that it also works when using the Node.js API
92
103
  if (debug) {
93
- debugLib.enable('lint-staged*')
104
+ enableDebug(logger)
94
105
 
95
106
  debugLog(
96
107
  'Running `lint-staged@%s` on Node.js %s (%s)',
@@ -105,19 +116,23 @@ const lintStaged = async (
105
116
 
106
117
  const options = {
107
118
  allowEmpty,
119
+ color,
108
120
  concurrent,
109
121
  configObject,
110
122
  configPath,
123
+ continueOnError,
111
124
  cwd,
112
125
  debug,
113
126
  diff,
114
127
  diffFilter,
128
+ failOnChanges,
129
+ hidePartiallyStaged,
130
+ hideUnstaged,
115
131
  maxArgLength,
116
132
  quiet,
117
133
  relative,
118
134
  revert,
119
135
  stash,
120
- hidePartiallyStaged,
121
136
  verbose,
122
137
  }
123
138
 
@@ -140,6 +155,8 @@ const lintStaged = async (
140
155
  logger.error(NO_CONFIGURATION)
141
156
  } else if (ctx.errors.has(ApplyEmptyCommitError)) {
142
157
  logger.warn(PREVENTED_EMPTY_COMMIT)
158
+ } else if (ctx.errors.has(ExitCodeError)) {
159
+ logger.warn(PREVENTED_TASK_MODIFICATIONS)
143
160
  } else if (ctx.errors.has(RestoreUnstagedChangesError)) {
144
161
  logger.warn(UNSTAGED_CHANGES_BACKUP_STASH_LOCATION)
145
162
  logger.warn(ctx.unstagedPatch)
package/lib/loadConfig.js CHANGED
@@ -3,20 +3,15 @@
3
3
  import fs from 'node:fs/promises'
4
4
  import path from 'node:path'
5
5
 
6
- import debug from 'debug'
7
6
  import YAML from 'yaml'
8
7
 
9
- import {
10
- CONFIG_FILE_NAMES,
11
- CONFIG_NAME,
12
- PACKAGE_JSON_FILE,
13
- PACKAGE_YAML_FILES,
14
- } from './configFiles.js'
8
+ import { CONFIG_NAME, PACKAGE_JSON_FILE, PACKAGE_YAML_FILES } from './configFiles.js'
9
+ import { createDebug } from './debug.js'
15
10
  import { dynamicImport } from './dynamicImport.js'
16
11
  import { failedToLoadConfig } from './messages.js'
17
12
  import { resolveConfig } from './resolveConfig.js'
18
13
 
19
- const debugLog = debug('lint-staged:loadConfig')
14
+ const debugLog = createDebug('lint-staged:loadConfig')
20
15
 
21
16
  const jsonParse = (filePath, content) => {
22
17
  const isPackageFile = PACKAGE_JSON_FILE.includes(path.basename(filePath))
@@ -94,22 +89,11 @@ const loadConfigByExt = async (filepath) => {
94
89
  /**
95
90
  * @param {object} options
96
91
  * @param {string} [options.configPath] - Explicit path to a config file
97
- * @param {string} [options.cwd] - Current working directory
98
92
  */
99
- export const loadConfig = async ({ configPath, cwd }, logger) => {
93
+ export const loadConfig = async ({ configPath }, logger) => {
100
94
  try {
101
- let result
102
-
103
- if (configPath) {
104
- debugLog('Loading configuration from `%s`...', configPath)
105
- result = await loadConfigByExt(resolveConfig(configPath))
106
- } else {
107
- debugLog('Searching for configuration from `%s`...', cwd)
108
- const { lilconfig } = await import('lilconfig')
109
- const explorer = lilconfig(CONFIG_NAME, { searchPlaces: CONFIG_FILE_NAMES, loaders })
110
- result = await explorer.search(cwd)
111
- }
112
-
95
+ debugLog('Loading configuration from `%s`...', configPath)
96
+ const result = configPath ? await loadConfigByExt(resolveConfig(configPath)) : undefined
113
97
  if (!result) return {}
114
98
 
115
99
  // config is a promise when using the `dynamicImport` loader
package/lib/messages.js CHANGED
@@ -1,22 +1,21 @@
1
1
  import { inspect } from 'node:util'
2
2
 
3
- import chalk from 'chalk'
4
-
3
+ import { bold, red, yellow } from './colors.js'
5
4
  import { error, info, warning } from './figures.js'
6
5
 
7
6
  export const configurationError = (opt, helpMsg, value) =>
8
- `${chalk.redBright(`${error} Validation Error:`)}
7
+ `${red(`${error} Validation Error:`)}
9
8
 
10
- Invalid value for '${chalk.bold(opt)}': ${chalk.bold(inspect(value))}
9
+ Invalid value for '${bold(opt)}': ${bold(inspect(value))}
11
10
 
12
11
  ${helpMsg}`
13
12
 
14
- export const NOT_GIT_REPO = chalk.redBright(`${error} Current directory is not a git directory!`)
13
+ export const NOT_GIT_REPO = red(`${error} Current directory is not a git directory!`)
15
14
 
16
- export const FAILED_GET_STAGED_FILES = chalk.redBright(`${error} Failed to get staged files!`)
15
+ export const FAILED_GET_STAGED_FILES = red(`${error} Failed to get staged files!`)
17
16
 
18
17
  export const incorrectBraces = (before, after) =>
19
- chalk.yellow(
18
+ yellow(
20
19
  `${warning} Detected incorrect braces with only single value: \`${before}\`. Reformatted as: \`${after}\`
21
20
  `
22
21
  )
@@ -34,36 +33,36 @@ export const skippingBackup = (hasInitialCommit, diff) => {
34
33
  : (hasInitialCommit ? '`--no-stash` was used' : 'there’s no initial commit yet') +
35
34
  '. This might result in data loss'
36
35
 
37
- return chalk.yellow(`${warning} Skipping backup because ${reason}.\n`)
36
+ return yellow(`${warning} Skipping backup because ${reason}.\n`)
38
37
  }
39
38
 
40
- export const SKIPPING_HIDE_PARTIALLY_CHANGED = chalk.yellow(
39
+ export const SKIPPING_HIDE_PARTIALLY_CHANGED = yellow(
41
40
  `${warning} Skipping hiding unstaged changes from partially staged files because \`--no-hide-partially-staged\` was used.\n`
42
41
  )
43
42
 
44
- export const DEPRECATED_GIT_ADD = chalk.yellow(
43
+ export const DEPRECATED_GIT_ADD = yellow(
45
44
  `${warning} Some of your tasks use \`git add\` command. Please remove it from the config since all modifications made by tasks will be automatically added to the git commit index.
46
45
  `
47
46
  )
48
47
 
49
48
  export const TASK_ERROR = 'Skipped because of errors from tasks.'
50
49
 
50
+ export const PREVENTED_TASK_MODIFICATIONS = `\n${error} lint-staged failed because \`--fail-on-changes\` was used.`
51
+
51
52
  export const SKIPPED_GIT_ERROR = 'Skipped because of previous git error.'
52
53
 
53
- export const GIT_ERROR = `\n ${chalk.redBright(`${error} lint-staged failed due to a git error.`)}`
54
+ export const GIT_ERROR = `\n ${red(`${error} lint-staged failed due to a git error.`)}`
54
55
 
55
- export const invalidOption = (name, value, message) => `${chalk.redBright(
56
- `${error} Validation Error:`
57
- )}
56
+ export const invalidOption = (name, value, message) => `${red(`${error} Validation Error:`)}
58
57
 
59
- Invalid value for option '${chalk.bold(name)}': ${chalk.bold(value)}
58
+ Invalid value for option '${bold(name)}': ${bold(value)}
60
59
 
61
60
  ${message}
62
61
 
63
62
  See https://github.com/okonet/lint-staged#command-line-flags`
64
63
 
65
64
  export const PREVENTED_EMPTY_COMMIT = `
66
- ${chalk.yellow(`${warning} lint-staged prevented an empty git commit.
65
+ ${yellow(`${warning} lint-staged prevented an empty git commit.
67
66
  Use the --allow-empty option to continue, or check your task configuration`)}
68
67
  `
69
68
 
@@ -73,15 +72,15 @@ export const RESTORE_STASH_EXAMPLE = `Any lost modifications can be restored fro
73
72
  stash@{0}: automatic lint-staged backup
74
73
  > git stash apply --index stash@{0}`
75
74
 
76
- export const CONFIG_STDIN_ERROR = chalk.redBright(`${error} Failed to read config from stdin.`)
75
+ export const CONFIG_STDIN_ERROR = red(`${error} Failed to read config from stdin.`)
77
76
 
78
77
  export const failedToLoadConfig = (filepath) =>
79
- chalk.redBright(`${error} Failed to read config from file "${filepath}".`)
78
+ red(`${error} Failed to read config from file "${filepath}".`)
80
79
 
81
80
  export const failedToParseConfig = (
82
81
  filepath,
83
82
  error
84
- ) => `${chalk.redBright(`${error} Failed to parse config from file "${filepath}".`)}
83
+ ) => `${red(`${error} Failed to parse config from file "${filepath}".`)}
85
84
 
86
85
  ${error}
87
86