lint-staged: [BUG] No matching files on filenames with brackets

Description

This is related to Next.js new dynamic routes feature.

Steps to reproduce

  1. Use this configuration in package.json:
  …
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged --debug"
    }
  },
  "lint-staged": {
    "*.{js,css,json,md}": [
      "prettier --write",
      "git add"
    ],
    "*.js": [
      "npm run lint:eslint",
      "git add"
    ]
  …
  1. Try to commit a filename with brackets [].

Debug Logs

expand to view

husky > pre-commit (node v12.6.0)
2019-07-30T23:23:07.320Z lint-staged:bin Running `lint-staged@8.1.7`
2019-07-30T23:23:07.697Z lint-staged:find-bin Loaded package.json using `process.cwd()`
2019-07-30T23:23:07.847Z lint-staged Loading config using `cosmiconfig`
2019-07-30T23:23:07.852Z lint-staged Successfully loaded config from `OMMITED/package.json`:
{
  '*.{js,css,json,md}': [ 'prettier --write', 'git add' ],
  '*.js': [ 'npm run lint:eslint', 'git add' ]
}
2019-07-30T23:23:07.853Z lint-staged:cfg Normalizing config
2019-07-30T23:23:07.855Z lint-staged:cfg Validating config
Running lint-staged with the following config:
{
  linters: {
    '*.{js,css,json,md}': [
      'prettier --write',
      'git add'
    ],
    '*.js': [
      'npm run lint:eslint',
      'git add'
    ]
  },
  concurrent: true,
  chunkSize: 9007199254740991,
  globOptions: {
    matchBase: true,
    dot: true
  },
  ignore: [],
  subTaskConcurrency: 1,
  renderer: 'verbose',
  relative: false
}
2019-07-30T23:23:07.863Z lint-staged:run Running all linter scripts
2019-07-30T23:23:07.863Z lint-staged:run Resolved git directory to be `OMMITED`
2019-07-30T23:23:07.884Z lint-staged:run Loaded list of staged files in git:
[ 'services/enrola-webapp/pages/CRM/sales/[saleId]/index.js' ]
2019-07-30T23:23:07.884Z lint-staged:gen-tasks Generating linter tasks
2019-07-30T23:23:07.884Z lint-staged:cfg Normalizing config
2019-07-30T23:23:07.899Z lint-staged:gen-tasks Generated task: 
{
  pattern: '*.{js,css,json,md}',
  commands: [ 'prettier --write', 'git add' ],
  fileList: [
    'OMMITED/webapp/pages/CRM/sales/[saleId]/index.js'
  ]
}
2019-07-30T23:23:07.900Z lint-staged:gen-tasks Generated task: 
{
  pattern: '*.js',
  commands: [ 'npm run lint:eslint', 'git add' ],
  fileList: [
    'OMMITED/webapp/pages/CRM/sales/[saleId]/index.js'
  ]
}
Stashing changes... [started]
2019-07-30T23:23:07.935Z lint-staged:git Stashing files...
2019-07-30T23:23:07.935Z lint-staged:git Running git command [ 'write-tree' ]
2019-07-30T23:23:07.961Z lint-staged:git Running git command [ 'add', '.' ]
2019-07-30T23:23:07.984Z lint-staged:git Running git command [ 'write-tree' ]
2019-07-30T23:23:08.002Z lint-staged:git Running git command [ 'read-tree', '8abe2bba7ffe8916312b195969cc19039ca8658e' ]
2019-07-30T23:23:08.086Z lint-staged:git Running git command [ 'checkout-index', '-af' ]
2019-07-30T23:23:08.694Z lint-staged:git Done stashing files!
Stashing changes... [completed]
Running linters... [started]
Running tasks for *.{js,css,json,md} [started]
Running tasks for *.js [started]
2019-07-30T23:23:08.696Z lint-staged:make-cmd-tasks Creating listr tasks for commands [ 'prettier --write', 'git add' ]
2019-07-30T23:23:08.697Z lint-staged:find-bin Resolving binary for command `prettier --write`
2019-07-30T23:23:08.702Z lint-staged:find-bin Binary for `prettier --write` resolved to `OMMITED/node_modules/.bin/prettier`
2019-07-30T23:23:08.703Z lint-staged:task ✔  OS: darwin; File path chunking unnecessary
2019-07-30T23:23:08.703Z lint-staged:find-bin Resolving binary for command `git add`
2019-07-30T23:23:08.704Z lint-staged:find-bin Binary for `git add` resolved to `/usr/local/Cellar/git/2.22.0_1/libexec/git-core/git`
2019-07-30T23:23:08.704Z lint-staged:task ✔  OS: darwin; File path chunking unnecessary
2019-07-30T23:23:08.704Z lint-staged:make-cmd-tasks Creating listr tasks for commands [ 'npm run lint:eslint', 'git add' ]
2019-07-30T23:23:08.704Z lint-staged:find-bin Resolving binary for command `npm run lint:eslint`
2019-07-30T23:23:08.705Z lint-staged:find-bin Binary for `npm run lint:eslint` resolved to `/usr/local/bin/npm`
2019-07-30T23:23:08.705Z lint-staged:task ✔  OS: darwin; File path chunking unnecessary
2019-07-30T23:23:08.705Z lint-staged:find-bin Resolving binary for command `git add`
2019-07-30T23:23:08.705Z lint-staged:find-bin Resolving binary for `git` from cache
2019-07-30T23:23:08.705Z lint-staged:task ✔  OS: darwin; File path chunking unnecessary
prettier --write [started]
npm run lint:eslint [started]
2019-07-30T23:23:08.705Z lint-staged:task bin: OMMITED/node_modules/.bin/prettier
2019-07-30T23:23:08.706Z lint-staged:task args: [
  '--write',
  'OMMITED/webapp/pages/CRM/sales/[saleId]/index.js'
]
2019-07-30T23:23:08.706Z lint-staged:task opts: { reject: false }
2019-07-30T23:23:08.710Z lint-staged:task bin: /usr/local/bin/npm
2019-07-30T23:23:08.710Z lint-staged:task args: [
  'run',
  'lint:eslint',
  'OMMITED/webapp/pages/CRM/sales/[saleId]/index.js'
]
2019-07-30T23:23:08.710Z lint-staged:task opts: { reject: false }
prettier --write [failed]
→ 
Running tasks for *.{js,css,json,md} [failed]
→ 
npm run lint:eslint [completed]
git add [started]
2019-07-30T23:23:11.725Z lint-staged:task bin: /usr/local/Cellar/git/2.22.0_1/libexec/git-core/git
2019-07-30T23:23:11.725Z lint-staged:task args: [
  'add',
  'OMMITED/webapp/pages/CRM/sales/[saleId]/index.js'
]
2019-07-30T23:23:11.725Z lint-staged:task opts: { reject: false }
git add [completed]
Running tasks for *.js [completed]
Running linters... [failed]
Updating stash... [started]
Updating stash... [skipped]
→ Skipping stash update since some tasks exited with errors
Restoring local changes... [started]
2019-07-30T23:23:11.739Z lint-staged:git Restoring working copy
2019-07-30T23:23:11.739Z lint-staged:git Running git command [ 'read-tree', 'e0a3ad899b52438b4a0f11eadce45c90d21c1936' ]
2019-07-30T23:23:11.769Z lint-staged:git Running git command [ 'checkout-index', '-af' ]
2019-07-30T23:23:12.375Z lint-staged:git Restoring index
2019-07-30T23:23:12.376Z lint-staged:git Running git command [ 'read-tree', '8abe2bba7ffe8916312b195969cc19039ca8658e' ]
Restoring local changes... [completed]



✖ prettier --write found some errors. Please fix them and try committing again.

[error] No matching files. Patterns tried: OMMITED/webapp/pages/CRM/sales/[saleId]/index.js !**/node_modules/** !./node_modules/** !**/.{git,svn,hg}/** !./.{git,svn,hg}/**
husky > pre-commit hook failed (add --no-verify to bypass)


Environment

  • OS: macOS Mojave 10.14.5 (18F132)
  • Node.js: v8.15.0
  • lint-staged: 8.1.7

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 5
  • Comments: 27 (7 by maintainers)

Most upvoted comments

I found temp workaround: .lintstagedrc.js

const quote = require('shell-quote').quote;

module.exports = {
    '*.{js,jsx,ts,tsx}': filenames =>
        filenames.reduce((commands, filename) => {
            commands.push(quote(['prettier', '--write', filename]), quote(['git', 'add', filename]));

            return commands;
        }, [])
};

When its going to be fixed any idea

Thanks for the input. I’ll continue the discussion on the prettier repo.

Neither of above worked for us. We’ve found out that it’s possible to bypass this problem by wraping square brackets with square brackets (matcher of any char in seq).

lint-staged.config.js:

const escape = require('shell-quote').quote;
const isWin = process.platform === 'win32';

module.exports = {
	'**/*.{js,jsx,ts,tsx,json}': filenames => {
		const escapedFileNames = filenames
			// this will wrap all "[" "]" square brackets with another square brackets ([ => [[]) so [...customer].tsx will be processed to [[]...customer[]].tsx
			.map(filename => `"${isWin ? filename.replace(/\[|\]/g, '[$&]') : escape([filename])}"`)
			.join(' ');
		return [
			`prettier --with-node-modules --ignore-path='./.gitignore' --write ${escapedFileNames}`,
			`eslint --no-ignore --max-warnings=0 --fix ${filenames.map(f => `"${f}"`).join(' ')}`,
			`git add ${escapedFileNames}`
		];
	},
	'**/*.{json,md,mdx,css,html,yml,yaml,scss}': filenames => {
		const escapedFileNames = filenames
			.map(filename => `"${isWin ? filename.replace(/\[|\]/g, '[$&]') : escape([filename])}"`)
			.join(' ');
		return [
			`prettier --with-node-modules --ignore-path='./.gitignore' --write ${escapedFileNames}`,
			`git add ${escapedFileNames}`
		];
	}
};

This is not a simple issue to fix because of cross-platform support requirements. Ideally I would like to solve this by wrapping filepath arguments inside quotes. Unfortunately I can’t estimate a timeline, because I’m not sure how to fix it yet.

@okonet maybe a special command to scape characters? Imagine something like this on package-json

  "lint-staged": {
    "--escape *.{js,jsx}": [
      "prettier --write",
      "git add"
    ],
    "*.{js,jsx}": [
      "npm run lint:eslint",
      "git add"
    ]

the --escape is basically saying to escape any special characters before giving it to prettier, but I’m afraid this would work for prettier --write but will fail for git add.

Or maybe:

  "lint-staged": {
    "*.{js,jsx}": [
      "--escape",
      "prettier --write",
      "npm run lint:eslint"
      "git add"
    ]

In this case, the --escape on the command chain would just be saying to escape the input before the next command.

Just brainstorming. The former could open doors for some other commands. I fixed my problem by following the suggestion in https://github.com/okonet/lint-staged/issues/676#issuecomment-553598068

Hello there! I’m currently using workaround like this.

.lintstagedrc.js

const escape = require('shell-quote').quote

function listQuote(filenames) {
  return filenames.map((filename) => `'${filename}'`)
}

function listEscape(filenames) {
  return filenames.map((filename) => escape([filename]))
}

module.exports = {
  '**/*.{js,ts,tsx}': (filenames) => [
    `eslint --fix ${listQuote(filenames).join(' ')}`,
    `prettier --write ${listQuote(listEscape(filenames)).join(' ')}`,
    `git add ${listQuote(filenames).join(' ')}`,
  ],
}

Main problem is… Prettier need escapes and quotes filenames, but eslint and git add are not.

And, using these commands for all staged files are cause massive cli logs. I just want to use like 'lint-stagedfield onpackage.json`, so I wrote workaround above.