lint-staged 11.0.1 → 11.1.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.
package/README.md CHANGED
@@ -71,7 +71,7 @@ Options:
71
71
  tasks serially (default: true)
72
72
  -q, --quiet disable lint-staged’s own console output (default: false)
73
73
  -r, --relative pass relative filepaths to tasks (default: false)
74
- -x, --shell skip parsing of tasks for better shell support (default:
74
+ -x, --shell <path> skip parsing of tasks for better shell support (default:
75
75
  false)
76
76
  -v, --verbose show task output even when tasks succeed; by default only
77
77
  failed output is shown (default: false)
@@ -90,7 +90,7 @@ Options:
90
90
  - **`--no-stash`**: By default a backup stash will be created before running the tasks, and all task modifications will be reverted in case of an error. This option will disable creating the stash, and instead leave all modifications in the index when aborting the commit.
91
91
  - **`--quiet`**: Supress all CLI output, except from tasks.
92
92
  - **`--relative`**: Pass filepaths relative to `process.cwd()` (where `lint-staged` runs) to tasks. Default is `false`.
93
- - **`--shell`**: By default linter commands will be parsed for speed and security. This has the side-effect that regular shell scripts might not work as expected. You can skip parsing of commands with this option.
93
+ - **`--shell`**: By default linter commands will be parsed for speed and security. This has the side-effect that regular shell scripts might not work as expected. You can skip parsing of commands with this option. To use a specific shell, use a path like `--shell "/bin/bash"`.
94
94
  - **`--verbose`**: Show task output even when tasks succeed. By default only failed output is shown.
95
95
 
96
96
  ## Configuration
@@ -42,7 +42,7 @@ cmdline
42
42
  )
43
43
  .option('-q, --quiet', 'disable lint-staged’s own console output', false)
44
44
  .option('-r, --relative', 'pass relative filepaths to tasks', false)
45
- .option('-x, --shell', 'skip parsing of tasks for better shell support', false)
45
+ .option('-x, --shell <path>', 'skip parsing of tasks for better shell support', false)
46
46
  .option(
47
47
  '-v, --verbose',
48
48
  'show task output even when tasks succeed; by default only failed output is shown',
@@ -85,7 +85,7 @@ const options = {
85
85
  stash: !!cmdlineOptions.stash, // commander inverts `no-<x>` flags to `!x`
86
86
  quiet: !!cmdlineOptions.quiet,
87
87
  relative: !!cmdlineOptions.relative,
88
- shell: !!cmdlineOptions.shell,
88
+ shell: cmdlineOptions.shell /* Either a boolean or a string pointing to the shell */,
89
89
  verbose: !!cmdlineOptions.verbose,
90
90
  }
91
91
 
package/lib/index.js CHANGED
@@ -8,13 +8,18 @@ const stringifyObject = require('stringify-object')
8
8
  const { PREVENTED_EMPTY_COMMIT, GIT_ERROR, RESTORE_STASH_EXAMPLE } = require('./messages')
9
9
  const printTaskOutput = require('./printTaskOutput')
10
10
  const runAll = require('./runAll')
11
- const { ApplyEmptyCommitError, GetBackupStashError, GitError } = require('./symbols')
11
+ const {
12
+ ApplyEmptyCommitError,
13
+ ConfigNotFoundError,
14
+ GetBackupStashError,
15
+ GitError,
16
+ InvalidOptionsError,
17
+ } = require('./symbols')
12
18
  const formatConfig = require('./formatConfig')
13
19
  const validateConfig = require('./validateConfig')
20
+ const validateOptions = require('./validateOptions')
14
21
 
15
- const errConfigNotFound = new Error('Config could not be found')
16
-
17
- function resolveConfig(configPath) {
22
+ const resolveConfig = (configPath) => {
18
23
  try {
19
24
  return require.resolve(configPath)
20
25
  } catch {
@@ -22,7 +27,7 @@ function resolveConfig(configPath) {
22
27
  }
23
28
  }
24
29
 
25
- function loadConfig(configPath) {
30
+ const loadConfig = (configPath) => {
26
31
  const explorer = cosmiconfig('lint-staged', {
27
32
  searchPlaces: [
28
33
  'package.json',
@@ -56,14 +61,14 @@ function loadConfig(configPath) {
56
61
  * @param {number} [options.maxArgLength] - Maximum argument string length
57
62
  * @param {boolean} [options.quiet] - Disable lint-staged’s own console output
58
63
  * @param {boolean} [options.relative] - Pass relative filepaths to tasks
59
- * @param {boolean} [options.shell] - Skip parsing of tasks for better shell support
64
+ * @param {boolean|string} [options.shell] - Skip parsing of tasks for better shell support
60
65
  * @param {boolean} [options.stash] - Enable the backup stash, and revert in case of errors
61
66
  * @param {boolean} [options.verbose] - Show task output even when tasks succeed; by default only failed output is shown
62
67
  * @param {Logger} [logger]
63
68
  *
64
69
  * @returns {Promise<boolean>} Promise of whether the linting passed or failed
65
70
  */
66
- module.exports = async function lintStaged(
71
+ const lintStaged = async (
67
72
  {
68
73
  allowEmpty = false,
69
74
  concurrent = true,
@@ -79,20 +84,27 @@ module.exports = async function lintStaged(
79
84
  verbose = false,
80
85
  } = {},
81
86
  logger = console
82
- ) {
87
+ ) => {
83
88
  try {
89
+ await validateOptions({ shell }, logger)
90
+
84
91
  debugLog('Loading config using `cosmiconfig`')
85
92
 
86
93
  const resolved = configObject
87
94
  ? { config: configObject, filepath: '(input)' }
88
95
  : await loadConfig(configPath)
89
- if (resolved == null) throw errConfigNotFound
96
+
97
+ if (resolved == null) {
98
+ throw ConfigNotFoundError
99
+ }
90
100
 
91
101
  debugLog('Successfully loaded config from `%s`:\n%O', resolved.filepath, resolved.config)
102
+
92
103
  // resolved.config is the parsed configuration object
93
104
  // resolved.filepath is the path to the config file that was found
94
105
  const formattedConfig = formatConfig(resolved.config)
95
106
  const config = validateConfig(formattedConfig)
107
+
96
108
  if (debug) {
97
109
  // Log using logger to be able to test through `consolemock`.
98
110
  logger.log('Running lint-staged with the following config:')
@@ -148,7 +160,13 @@ module.exports = async function lintStaged(
148
160
  throw runAllError
149
161
  }
150
162
  } catch (lintStagedError) {
151
- if (lintStagedError === errConfigNotFound) {
163
+ /** throw early because `validateOptions` options contains own logging */
164
+ if (lintStagedError === InvalidOptionsError) {
165
+ throw InvalidOptionsError
166
+ }
167
+
168
+ /** @todo move logging to `validateConfig` and remove this try/catch block */
169
+ if (lintStagedError === ConfigNotFoundError) {
152
170
  logger.error(`${lintStagedError.message}.`)
153
171
  } else {
154
172
  // It was probably a parsing error
@@ -168,3 +186,5 @@ module.exports = async function lintStaged(
168
186
  throw lintStagedError
169
187
  }
170
188
  }
189
+
190
+ module.exports = lintStaged
package/lib/messages.js CHANGED
@@ -27,6 +27,14 @@ const SKIPPED_GIT_ERROR = 'Skipped because of previous git error.'
27
27
 
28
28
  const GIT_ERROR = `\n ${error} ${chalk.red(`lint-staged failed due to a git error.`)}`
29
29
 
30
+ const invalidOption = (name, value, message) => `${chalk.redBright(`${error} Validation Error:`)}
31
+
32
+ Invalid value for option ${chalk.bold(name)}: ${chalk.bold(value)}
33
+
34
+ ${message}
35
+
36
+ See https://github.com/okonet/lint-staged#command-line-flags`
37
+
30
38
  const PREVENTED_EMPTY_COMMIT = `
31
39
  ${warning} ${chalk.yellow(`lint-staged prevented an empty git commit.
32
40
  Use the --allow-empty option to continue, or check your task configuration`)}
@@ -42,16 +50,17 @@ const RESTORE_STASH_EXAMPLE = ` Any lost modifications can be restored from a g
42
50
  const CONFIG_STDIN_ERROR = 'Error: Could not read config from stdin.'
43
51
 
44
52
  module.exports = {
45
- NOT_GIT_REPO,
53
+ CONFIG_STDIN_ERROR,
54
+ DEPRECATED_GIT_ADD,
46
55
  FAILED_GET_STAGED_FILES,
56
+ GIT_ERROR,
57
+ invalidOption,
47
58
  NO_STAGED_FILES,
48
59
  NO_TASKS,
49
- skippingBackup,
50
- DEPRECATED_GIT_ADD,
51
- TASK_ERROR,
52
- SKIPPED_GIT_ERROR,
53
- GIT_ERROR,
60
+ NOT_GIT_REPO,
54
61
  PREVENTED_EMPTY_COMMIT,
55
62
  RESTORE_STASH_EXAMPLE,
56
- CONFIG_STDIN_ERROR,
63
+ SKIPPED_GIT_ERROR,
64
+ skippingBackup,
65
+ TASK_ERROR,
57
66
  }
package/lib/symbols.js CHANGED
@@ -1,11 +1,13 @@
1
1
  'use strict'
2
2
 
3
3
  const ApplyEmptyCommitError = Symbol('ApplyEmptyCommitError')
4
+ const ConfigNotFoundError = new Error('Config could not be found')
4
5
  const GetBackupStashError = Symbol('GetBackupStashError')
5
6
  const GetStagedFilesError = Symbol('GetStagedFilesError')
6
7
  const GitError = Symbol('GitError')
7
8
  const GitRepoError = Symbol('GitRepoError')
8
9
  const HideUnstagedChangesError = Symbol('HideUnstagedChangesError')
10
+ const InvalidOptionsError = new Error('Invalid Options')
9
11
  const RestoreMergeStatusError = Symbol('RestoreMergeStatusError')
10
12
  const RestoreOriginalStateError = Symbol('RestoreOriginalStateError')
11
13
  const RestoreUnstagedChangesError = Symbol('RestoreUnstagedChangesError')
@@ -13,10 +15,12 @@ const TaskError = Symbol('TaskError')
13
15
 
14
16
  module.exports = {
15
17
  ApplyEmptyCommitError,
18
+ ConfigNotFoundError,
16
19
  GetBackupStashError,
17
20
  GetStagedFilesError,
18
21
  GitError,
19
22
  GitRepoError,
23
+ InvalidOptionsError,
20
24
  HideUnstagedChangesError,
21
25
  RestoreMergeStatusError,
22
26
  RestoreOriginalStateError,
@@ -0,0 +1,31 @@
1
+ const { promises: fs, constants } = require('fs')
2
+
3
+ const { invalidOption } = require('./messages')
4
+ const { InvalidOptionsError } = require('./symbols')
5
+
6
+ const debug = require('debug')('lint-staged:options')
7
+
8
+ /**
9
+ * Validate lint-staged options, either from the Node.js API or the command line flags.
10
+ * @param {*} options
11
+ * @param {boolean|string} [options.shell] - Skip parsing of tasks for better shell support
12
+ *
13
+ * @throws {InvalidOptionsError}
14
+ */
15
+ const validateOptions = async (options = {}, logger) => {
16
+ debug('Validating options...')
17
+
18
+ /** Ensure the passed shell option is executable */
19
+ if (typeof options.shell === 'string') {
20
+ try {
21
+ await fs.access(options.shell, constants.X_OK)
22
+ } catch (error) {
23
+ logger.error(invalidOption('shell', options.shell, error.message))
24
+ throw InvalidOptionsError
25
+ }
26
+ }
27
+
28
+ debug('Validated options!')
29
+ }
30
+
31
+ module.exports = validateOptions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-staged",
3
- "version": "11.0.1",
3
+ "version": "11.1.0",
4
4
  "description": "Lint files staged by git",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/okonet/lint-staged",