lint-staged
Advanced tools
Comparing version 15.0.2 to 15.2.0
@@ -70,3 +70,23 @@ #!/usr/bin/env node | ||
'--no-stash', | ||
'disable the backup stash, and do not revert in case of errors' | ||
'disable the backup stash, and do not revert in case of errors. Implies "--no-hide-partially-staged".' | ||
) | ||
.default(false) | ||
.implies({ hidePartiallyStaged: false }) | ||
) | ||
/** | ||
* We don't want to show the `--hide-partially-staged` flag because it's on by default, and only show the | ||
* negatable flag `--no-hide-partially-staged` in stead. There seems to be a bug in Commander.js where | ||
* configuring only the latter won't actually set the default value. | ||
*/ | ||
cli | ||
.addOption( | ||
new Option('--hide-partially-staged', 'hide unstaged changes from partially staged files') | ||
.default(true) | ||
.hideHelp() | ||
) | ||
.addOption( | ||
new Option( | ||
'--no-hide-partially-staged', | ||
'disable hiding unstaged changes from partially staged files' | ||
).default(false) | ||
@@ -108,2 +128,3 @@ ) | ||
stash: !!cliOptions.stash, // commander inverts `no-<x>` flags to `!x` | ||
hidePartiallyStaged: !!cliOptions.hidePartiallyStaged, // commander inverts `no-<x>` flags to `!x` | ||
verbose: !!cliOptions.verbose, | ||
@@ -110,0 +131,0 @@ } |
@@ -80,2 +80,3 @@ import debug from 'debug' | ||
stash = diff === undefined, | ||
hidePartiallyStaged = stash, | ||
verbose = false, | ||
@@ -105,2 +106,3 @@ } = {}, | ||
stash, | ||
hidePartiallyStaged, | ||
verbose, | ||
@@ -107,0 +109,0 @@ } |
/** @typedef {import('./index').Logger} Logger */ | ||
import fs from 'node:fs/promises' | ||
import path from 'node:path' | ||
import debug from 'debug' | ||
import { lilconfig } from 'lilconfig' | ||
import YAML from 'yaml' | ||
@@ -9,31 +11,34 @@ | ||
import { resolveConfig } from './resolveConfig.js' | ||
import { | ||
CONFIG_FILE_NAMES, | ||
CONFIG_NAME, | ||
PACKAGE_JSON_FILE, | ||
PACKAGE_YAML_FILES, | ||
} from './configFiles.js' | ||
const debugLog = debug('lint-staged:loadConfig') | ||
const PACKAGE_JSON = 'package.json' | ||
const jsonParse = (filePath, content) => { | ||
const isPackageFile = PACKAGE_JSON_FILE.includes(path.basename(filePath)) | ||
try { | ||
const json = JSON.parse(content) | ||
return isPackageFile ? json[CONFIG_NAME] : json | ||
} catch (error) { | ||
if (path.basename(filePath) === PACKAGE_JSON_FILE) { | ||
debugLog('Ignoring invalid package file `%s` with content:\n%s', filePath, content) | ||
return undefined | ||
} | ||
/** | ||
* The list of files `lint-staged` will read configuration | ||
* from, in the declared order. | ||
*/ | ||
export const searchPlaces = [ | ||
PACKAGE_JSON, | ||
'.lintstagedrc', | ||
'.lintstagedrc.json', | ||
'.lintstagedrc.yaml', | ||
'.lintstagedrc.yml', | ||
'.lintstagedrc.mjs', | ||
'.lintstagedrc.js', | ||
'.lintstagedrc.cjs', | ||
'lint-staged.config.mjs', | ||
'lint-staged.config.js', | ||
'lint-staged.config.cjs', | ||
] | ||
throw error | ||
} | ||
} | ||
const jsonParse = (path, content) => { | ||
const yamlParse = (filePath, content) => { | ||
const isPackageFile = PACKAGE_YAML_FILES.includes(path.basename(filePath)) | ||
try { | ||
return JSON.parse(content) | ||
const yaml = YAML.parse(content) | ||
return isPackageFile ? yaml[CONFIG_NAME] : yaml | ||
} catch (error) { | ||
if (path.endsWith(PACKAGE_JSON)) { | ||
debugLog('Ignoring invalid package file `%s` with content:\n%s', path, content) | ||
if (isPackageFile) { | ||
debugLog('Ignoring invalid package file `%s` with content:\n%s', filePath, content) | ||
return undefined | ||
@@ -46,3 +51,3 @@ } | ||
const yamlParse = (path, content) => YAML.parse(content) | ||
const NO_EXT = 'noExt' | ||
@@ -62,7 +67,28 @@ /** | ||
'.yml': yamlParse, | ||
noExt: yamlParse, | ||
[NO_EXT]: yamlParse, | ||
} | ||
const explorer = lilconfig('lint-staged', { searchPlaces, loaders }) | ||
const readFile = async (filepath) => { | ||
const absolutePath = path.resolve(filepath) | ||
const file = await fs.readFile(absolutePath) | ||
return await file.toString() | ||
} | ||
const loadConfigByExt = async (filepath) => { | ||
filepath = path.resolve(filepath) | ||
const ext = path.extname(filepath) || NO_EXT | ||
const loader = loaders[ext] | ||
/** | ||
* No need to read file contents when loader only takes in the filepath argument | ||
* and reads itself; this is for `lilconfig` compatibility | ||
*/ | ||
const content = loader.length > 1 ? await readFile(filepath) : undefined | ||
return { | ||
config: await loader(filepath, content), | ||
filepath, | ||
} | ||
} | ||
/** | ||
@@ -75,16 +101,18 @@ * @param {object} options | ||
try { | ||
let result | ||
if (configPath) { | ||
debugLog('Loading configuration from `%s`...', configPath) | ||
result = await loadConfigByExt(resolveConfig(configPath)) | ||
} else { | ||
debugLog('Searching for configuration from `%s`...', cwd) | ||
const { lilconfig } = await import('lilconfig') | ||
const explorer = lilconfig(CONFIG_NAME, { searchPlaces: CONFIG_FILE_NAMES, loaders }) | ||
result = await explorer.search(cwd) | ||
} | ||
const result = await (configPath | ||
? explorer.load(resolveConfig(configPath)) | ||
: explorer.search(cwd)) | ||
if (!result) return {} | ||
// config is a promise when using the `dynamicImport` loader | ||
const config = await result.config | ||
const config = (await result.config) ?? null | ||
const filepath = result.filepath | ||
@@ -91,0 +119,0 @@ |
@@ -35,4 +35,4 @@ import { inspect } from 'node:util' | ||
: hasInitialCommit | ||
? '`--no-stash` was used' | ||
: 'there’s no initial commit yet' | ||
? '`--no-stash` was used' | ||
: 'there’s no initial commit yet' | ||
@@ -42,2 +42,15 @@ return chalk.yellow(`${warning} Skipping backup because ${reason}.\n`) | ||
export const skippingHidePartiallyStaged = (stash, diff) => { | ||
const reason = | ||
diff !== undefined | ||
? '`--diff` was used' | ||
: !stash | ||
? '`--no-stash` was used' | ||
: '`--no-hide-partially-staged` was used' | ||
return chalk.yellow( | ||
`${warning} Skipping hiding unstaged changes from partially staged files because ${reason}.\n` | ||
) | ||
} | ||
export const DEPRECATED_GIT_ADD = chalk.yellow( | ||
@@ -44,0 +57,0 @@ `${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. |
@@ -18,6 +18,15 @@ import fs from 'node:fs/promises' | ||
// Get the real path in case it's a symlink | ||
const defaultDir = normalizePath(await fs.realpath(path.join(gitDir, '.git'))) | ||
const defaultDir = path.join(gitDir, '.git') | ||
const stats = await fs.lstat(defaultDir) | ||
// If .git is a directory, use it | ||
if (stats.isDirectory()) return defaultDir | ||
if (stats.isDirectory()) { | ||
return defaultDir | ||
} | ||
// If .git is a symlink, return the real location | ||
if (stats.isSymbolicLink()) { | ||
return await fs.realpath(gitDir) | ||
} | ||
// Otherwise .git is a file containing path to real location | ||
@@ -37,6 +46,6 @@ const file = (await readFile(defaultDir)).toString() | ||
// the current working dir is inside the git top-level directory | ||
return normalizePath(cwd.substring(0, cwd.lastIndexOf(relativeDir))) | ||
return cwd.substring(0, cwd.lastIndexOf(relativeDir)) | ||
} else { | ||
// the current working dir is the top-level git directory | ||
return normalizePath(cwd) | ||
return cwd | ||
} | ||
@@ -61,3 +70,3 @@ } | ||
const gitRel = normalizePath(await execGit(['rev-parse', '--show-prefix'], { cwd })) | ||
const gitDir = determineGitDir(normalizePath(cwd), gitRel) | ||
const gitDir = normalizePath(determineGitDir(normalizePath(cwd), gitRel)) | ||
const gitConfigDir = normalizePath(await resolveGitConfigDir(gitDir)) | ||
@@ -64,0 +73,0 @@ |
@@ -25,2 +25,3 @@ /** @typedef {import('./index').Logger} Logger */ | ||
skippingBackup, | ||
skippingHidePartiallyStaged, | ||
} from './messages.js' | ||
@@ -34,3 +35,3 @@ import { normalizePath } from './normalizePath.js' | ||
getInitialState, | ||
hasPartiallyStagedFiles, | ||
shouldHidePartiallyStagedFiles, | ||
restoreOriginalStateEnabled, | ||
@@ -84,2 +85,3 @@ restoreOriginalStateSkipped, | ||
stash = diff === undefined, | ||
hidePartiallyStaged = stash, | ||
verbose = false, | ||
@@ -114,6 +116,11 @@ }, | ||
ctx.shouldBackup = hasInitialCommit && stash | ||
if (!ctx.shouldBackup) { | ||
if (!ctx.shouldBackup && !quiet) { | ||
logger.warn(skippingBackup(hasInitialCommit, diff)) | ||
} | ||
ctx.shouldHidePartiallyStaged = hidePartiallyStaged | ||
if (!ctx.shouldHidePartiallyStaged && !quiet) { | ||
logger.warn(skippingHidePartiallyStaged(hasInitialCommit && stash, diff)) | ||
} | ||
const files = await getStagedFiles({ cwd: gitDir, diff, diffFilter }) | ||
@@ -249,3 +256,3 @@ if (!files) { | ||
if (hasDeprecatedGitAdd) { | ||
if (hasDeprecatedGitAdd && !quiet) { | ||
logger.warn(DEPRECATED_GIT_ADD) | ||
@@ -288,3 +295,3 @@ } | ||
task: (ctx) => git.hideUnstagedChanges(ctx), | ||
enabled: hasPartiallyStagedFiles, | ||
enabled: shouldHidePartiallyStagedFiles, | ||
}, | ||
@@ -304,3 +311,3 @@ { | ||
task: (ctx) => git.restoreUnstagedChanges(ctx), | ||
enabled: hasPartiallyStagedFiles, | ||
enabled: shouldHidePartiallyStagedFiles, | ||
skip: restoreUnstagedChangesSkipped, | ||
@@ -307,0 +314,0 @@ }, |
@@ -8,6 +8,7 @@ /** @typedef {import('./index').Logger} Logger */ | ||
import { execGit } from './execGit.js' | ||
import { loadConfig, searchPlaces } from './loadConfig.js' | ||
import { loadConfig } from './loadConfig.js' | ||
import { normalizePath } from './normalizePath.js' | ||
import { parseGitZOutput } from './parseGitZOutput.js' | ||
import { validateConfig } from './validateConfig.js' | ||
import { CONFIG_FILE_NAMES } from './configFiles.js' | ||
@@ -19,3 +20,3 @@ const debugLog = debug('lint-staged:searchConfigs') | ||
const filterPossibleConfigFiles = (files) => | ||
files.filter((file) => searchPlaces.includes(path.basename(file))) | ||
files.filter((file) => CONFIG_FILE_NAMES.includes(path.basename(file))) | ||
@@ -22,0 +23,0 @@ const numberOfLevels = (file) => file.split('/').length |
@@ -15,2 +15,3 @@ import EventEmitter from 'events' | ||
shouldBackup: null, | ||
shouldHidePartiallyStaged: true, | ||
errors: new Set([]), | ||
@@ -22,3 +23,4 @@ events: new EventEmitter(), | ||
export const hasPartiallyStagedFiles = (ctx) => ctx.hasPartiallyStagedFiles | ||
export const shouldHidePartiallyStagedFiles = (ctx) => | ||
ctx.hasPartiallyStagedFiles && ctx.shouldHidePartiallyStaged | ||
@@ -25,0 +27,0 @@ export const applyModificationsSkipped = (ctx) => { |
{ | ||
"name": "lint-staged", | ||
"version": "15.0.2", | ||
"version": "15.2.0", | ||
"description": "Lint files staged by git", | ||
@@ -32,4 +32,4 @@ "license": "MIT", | ||
"lint": "eslint .", | ||
"test": "jest --coverage", | ||
"test:watch": "jest --watch", | ||
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --coverage", | ||
"test:watch": "npm run test -- --watch", | ||
"version": "npx changeset version", | ||
@@ -44,23 +44,19 @@ "postversion": "npm i --package-lock-only && git commit -am \"chore(changeset): release\"", | ||
"execa": "8.0.1", | ||
"lilconfig": "2.1.0", | ||
"listr2": "7.0.2", | ||
"lilconfig": "3.0.0", | ||
"listr2": "8.0.0", | ||
"micromatch": "4.0.5", | ||
"pidtree": "0.6.0", | ||
"string-argv": "0.3.2", | ||
"yaml": "2.3.3" | ||
"yaml": "2.3.4" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "7.23.2", | ||
"@babel/eslint-parser": "7.22.15", | ||
"@babel/preset-env": "7.23.2", | ||
"@changesets/changelog-github": "0.4.8", | ||
"@changesets/cli": "2.26.2", | ||
"@commitlint/cli": "17.8.0", | ||
"@commitlint/config-conventional": "17.8.0", | ||
"babel-jest": "29.7.0", | ||
"babel-plugin-transform-imports": "2.0.0", | ||
"@changesets/changelog-github": "0.5.0", | ||
"@changesets/cli": "2.27.1", | ||
"@commitlint/cli": "18.4.3", | ||
"@commitlint/config-conventional": "18.4.3", | ||
"consolemock": "1.1.0", | ||
"eslint": "8.51.0", | ||
"cross-env": "7.0.3", | ||
"eslint": "8.55.0", | ||
"eslint-config-prettier": "9.0.0", | ||
"eslint-plugin-import": "2.28.1", | ||
"eslint-plugin-import": "2.29.0", | ||
"eslint-plugin-node": "11.1.0", | ||
@@ -72,3 +68,3 @@ "eslint-plugin-prettier": "5.0.1", | ||
"mock-stdin": "1.0.0", | ||
"prettier": "3.0.3" | ||
"prettier": "3.1.0" | ||
}, | ||
@@ -75,0 +71,0 @@ "keywords": [ |
@@ -75,2 +75,6 @@ # 🚫💩 lint-staged [![Test & Release](https://github.com/okonet/lint-staged/actions/workflows/push.yml/badge.svg)](https://github.com/okonet/lint-staged/actions/workflows/push.yml) [![Publish](https://github.com/okonet/lint-staged/actions/workflows/tag.yml/badge.svg)](https://github.com/okonet/lint-staged/actions/workflows/tag.yml) [![npm version](https://badge.fury.io/js/lint-staged.svg)](https://badge.fury.io/js/lint-staged) [![Codecov](https://codecov.io/gh/okonet/lint-staged/branch/master/graph/badge.svg)](https://codecov.io/gh/okonet/lint-staged) | ||
#### v15 | ||
- Since `v15.0.0` _lint-staged_ no longer supports Node.js 16. Please upgrade your Node.js version to at least `18.12.0`. | ||
#### v14 | ||
@@ -83,2 +87,3 @@ | ||
- Since `v13.0.0` _lint-staged_ no longer supports Node.js 12. Please upgrade your Node.js version to at least `14.13.1`, or `16.0.0` onward. | ||
- Version `v13.3.0` was incorrectly released including code of version `v14.0.0`. This means the breaking changes of `v14` are also included in `v13.3.0`, the last `v13` version released | ||
@@ -117,3 +122,5 @@ #### v12 | ||
--max-arg-length [number] maximum length of the command-line argument string (default: 0) | ||
--no-stash disable the backup stash, and do not revert in case of errors | ||
--no-stash disable the backup stash, and do not revert in case of errors. Implies | ||
"--no-hide-partially-staged". | ||
--no-hide-partially-staged disable hiding unstaged changes from partially staged files | ||
-q, --quiet disable lint-staged’s own console output (default: false) | ||
@@ -141,3 +148,4 @@ -r, --relative pass relative filepaths to tasks (default: false) | ||
- **`--max-arg-length`**: long commands (a lot of files) are automatically split into multiple chunks when it detects the current shell cannot handle them. Use this flag to override the maximum length of the generated command string. | ||
- **`--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. Can be re-enabled with `--stash`. | ||
- **`--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. Can be re-enabled with `--stash`. This option also implies `--no-hide-partially-staged`. | ||
- **`--no-hide-partially-staged`**: By default, unstaged changes from partially staged files will be hidden. This option will disable this behavior and include all unstaged changes in partially staged files. Can be re-enabled with `--hide-partially-staged` | ||
- **`--quiet`**: Supress all CLI output, except from tasks. | ||
@@ -152,3 +160,3 @@ - **`--relative`**: Pass filepaths relative to `process.cwd()` (where `lint-staged` runs) to tasks. Default is `false`. | ||
- `lint-staged` object in your `package.json` | ||
- `lint-staged` object in your `package.json`, or [`package.yaml`](https://github.com/pnpm/pnpm/pull/1799) | ||
- `.lintstagedrc` file in JSON or YML format, or you can be explicit with the file extension: | ||
@@ -647,3 +655,3 @@ - `.lintstagedrc.json` | ||
### The output of commit hook looks weird (no colors, duplicate lines, …) | ||
### The output of commit hook looks weird (no colors, duplicate lines, verbose output on Windows, …) | ||
@@ -664,2 +672,17 @@ <details> | ||
If updating Git doesn't help, you can try to manually redirect the output in your Git hook; for example: | ||
```shell | ||
# .husky/pre-commit | ||
#!/usr/bin/env sh | ||
. "$(dirname -- "$0")/_/husky.sh" | ||
if sh -c ": >/dev/tty" >/dev/null 2>/dev/null; then exec >/dev/tty 2>&1; fi | ||
npx lint-staged | ||
``` | ||
Source: https://github.com/typicode/husky/issues/968#issuecomment-1176848345 | ||
</details> | ||
@@ -666,0 +689,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
119669
16
34
2069
950
+ Addedansi-escapes@7.0.0(transitive)
+ Addedansi-regex@6.1.0(transitive)
+ Addedcli-cursor@5.0.0(transitive)
+ Addedcli-truncate@4.0.0(transitive)
+ Addedemoji-regex@10.4.0(transitive)
+ Addedenvironment@1.1.0(transitive)
+ Addedget-east-asian-width@1.2.0(transitive)
+ Addedis-fullwidth-code-point@5.0.0(transitive)
+ Addedlilconfig@3.0.0(transitive)
+ Addedlistr2@8.0.0(transitive)
+ Addedlog-update@6.1.0(transitive)
+ Addedmimic-function@5.0.1(transitive)
+ Addedonetime@7.0.0(transitive)
+ Addedrestore-cursor@5.1.0(transitive)
+ Addedslice-ansi@7.1.0(transitive)
+ Addedstring-width@7.2.0(transitive)
+ Addedwrap-ansi@9.0.0(transitive)
+ Addedyaml@2.3.4(transitive)
- Removedansi-escapes@5.0.0(transitive)
- Removedansi-regex@6.0.1(transitive)
- Removedcli-cursor@4.0.0(transitive)
- Removedcli-truncate@3.1.0(transitive)
- Removedeastasianwidth@0.2.0(transitive)
- Removedemoji-regex@9.2.2(transitive)
- Removedlilconfig@2.1.0(transitive)
- Removedlistr2@7.0.2(transitive)
- Removedlog-update@5.0.1(transitive)
- Removedmimic-fn@2.1.0(transitive)
- Removedonetime@5.1.2(transitive)
- Removedrestore-cursor@4.0.0(transitive)
- Removedsignal-exit@3.0.7(transitive)
- Removedstring-width@5.1.2(transitive)
- Removedtype-fest@1.4.0(transitive)
- Removedwrap-ansi@8.1.0(transitive)
- Removedyaml@2.3.3(transitive)
Updatedlilconfig@3.0.0
Updatedlistr2@8.0.0
Updatedyaml@2.3.4