lint-staged: Doesn't work in angular/cli 7 project

Description

Linting does not work in an angular/cli 7 project

Steps to reproduce

Create a project with the angular cli 7. This is my config in project.json

  "lint-staged": {
    "linters": {
      "*.ts": "ng lint PROJECTNAME --files"
    },
    "relative": true
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },

Debug Logs

× ng lint PROJECTNAME --files found some errors. Please fix them and try committing again.
Linting "PROJECTNAME "...

Unknown option: 'src\app\myservice\my.service.ts'
``

### Environment

- **OS:** Windows 10
- **Node.js:** v10.13.0
- **`lint-staged`:** v8.1.0

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 2
  • Comments: 35 (3 by maintainers)

Commits related to this issue

Most upvoted comments

Hi @whiteblackkeys I realized late sorry for that. I changed to this and its working.

"lint-staged": { "linters": { "*.ts": [ "tslint --fix", "git add" ], "ignore": [ "**/dist/*.min.js" ] }, "relative": true },

@okonet I think this issue should be reopened 😃

We are having the same issue, we have a monorepo with different libs and apps so my workaround at the moment is to use tslint directly with specifying the tslint config for each project instead of using the angular cli:

"lint-staged": {
    "linters": {
      "libs/someLib/**/*.ts": "tslint -c libs/someLib/tslint.json",
       "apps/someApp/**/*.ts": "tslint -c apps/someApp/tslint.json"
    },
    "relative": true
  }

Seems to work not sure if I miss out on any important things which are provided by the angular cli.

@michaeljota I’m agree with you. But… this is angular and the angular team for this kind of issue is much less reactive than an open source project like lint-staged IMHO. And in fact I think we can wait a certain time before something happened on the angular side 😦

Well, for me it’s working. I have this with husky and it does lint as expected the committed files.

At least on Windows, the following works:

ng lint <project> --files "src\app\shared\shared.module.ts","src\app\menu\menu.component.ts"

By the way, if you repeat the --files option, @angular/cli handles it successfully as follows:

ng lint queue-mgmt-app --files "src\app\shared\shared.module.ts" --files "src\app\menu\menu.component.ts"
Option "files" was already specified with value ["src\\app\\shared\\shared.module.ts"]. The new value ["src\\app\\shared\\shared.module.ts","src\\app\\menu\\menu.component.ts"] will override it.

angular 7.2.1 lint --files require comma

i create bash script fix:

Bash script(lint.sh):

#!/bin/bash
PROJECT=$1
shift
SOURCES=$@
DESTINATIONS=""
DELIMITER=""
FIRST=1

for src in $SOURCES
do
    if [ "$FIRST" = 1 ]
    then
      DELIMITER=""
      FIRST=0
    else
      DELIMITER=","
    fi
    DESTINATIONS="$DESTINATIONS$DELIMITER${src}"
done

ng lint $PROJECT --fix --files $DESTINATIONS

.lintstagedrc

...
  "src/app/**/*.ts": [
    "sh lint.sh PROJECTNAME", "...

@okonet It is great that PR #534 provides relative path options to use lint-staged with ng lint but pointing to the PR is not pretty helpful for this issue.

I run into the same issue here like @whiteblackkeys with exactly the same setup as described in the README section.

I don’t know why, but after a bunch of failing tests, this worked:

"*.ts": "ng lint PROJECTNAME -- --files"

See the extra double dashes. Without these dashes, ng lint seems to resolve the filenames exposed by lint-staged as another option flag.

@whiteblackkeys could you try and confirm?

guys, please, avoid angular-cli hidden issues.

tldr; the only one workable solutions with ng lint is a enumeration of files with --files option: >ng lint --files src/app/app.module.ts --files src/app/shared/shared.module.ts and relative path only! you can use the example below. but better to use tslint directly it is really much faster. once again I convinced that angular-cli sucks


@michaeljota please be careful with your solution it just runs linting without actually checking like in option 2. in the example below.

if you really-really want to use ng lint there is the correct workaround:

const path = require('path');

module.exports = {
  "**/*.ts": (absolutePaths) => {
    const cwd = process.cwd();
    const relativePaths = absolutePaths.map(file => path.relative(cwd, file));

    return [
      `ng -- lint --files ${relativePaths.join(' --files ')}`,
      "git add"
    ];
  }
};

>lint-staged -d

× ng -- lint --files src\app\app.module.ts --files src\app\shared\shared.module.ts found some errors. Please fix them and try committing again.
Linting "project-gaia"...

ERROR: src/app/app.module.ts:1:31 - " should be '
ERROR: src/app/shared/shared.module.ts:1:40 - " should be '

Option "files" was already specified with value ["src\\app\\app.module.ts"]. The new value ["src\\app\\app.module.ts","src\\app\\shared\\shared.module.ts"] will override it.
no-use-before-declare is deprecated. Since TypeScript 2.9. Please use the built-in compiler checks instead.
Lint errors found in the listed files.
click it to see an investigation process...

investigation process:

https://angular.io/cli/lint#options - no info about how to use --files https://github.com/angular/angular-cli/wiki/lint - the same no info

no matter how are you sending files via --files parameter it doesn’t work properly in most cases.

  1. >ng lint shows me errors which I need:
ERROR: src/app/app.module.ts:1:10 - " should be '
ERROR: src/app/shared/shared.module.ts:1:20 - " should be '
  1. >ng lint --files src/app/app.module.ts src/app/shared/shared.module.ts - a space between files
An unhandled exception occurred: Project 'src/app/shared/shared.module.ts' does not support the 'lint' target.
See "angular-errors.log" for further details.
  1. >ng lint --files src/app/app.module.ts,src/app/shared/shared.module.ts - comma between files
Linting "project"...
All files pass linting.
  1. >ng lint --files=["src/app/app.module.ts","src/app/shared/shared.module.ts"] - an array
Linting "project"...
All files pass linting.

wtf?

  1. >ng lint project --files "src/app/app.module.ts" "src/app/shared/shared.module.ts" - let’s add a project maybe this will work
Unknown option: 'src/app/shared/shared.module.ts'

ugh, c`mon

  1. >ng lint project --files "D:/project/src/app/app.module.ts" --files "D:/project/src/app/shared/shared.module.ts" - maybe project and absolute paths?
Option "files" was already specified with value ["D:/project/src/app/app.module.ts"]. The new value ["D:/project/src/app/app.module.ts","D:/project/src/app/shared/shared.module.ts"] will ove
rride it.
Linting "project"...
An unhandled exception occurred: File "D:\\project\\src\\app\\app.module.ts" is not part of a TypeScript project 'tsconfig.app.json,tsconfig.spec.json,e2e/tsconfig.json'.
See "angular-errors.log" for further details.

ah, f*** off angular-cli…


and as I already said using tslint directly is much faster: >lint-staged -d | gnomon --medium=5 --high=10 --real-time=false

`tslint ${absolutePaths.join(' ')}`,

   Total   1.5285s

`tslint -p tsconfig.app.json ${absolutePaths.join(' ')}`,

     Total   6.1689s

`ng -- lint --files ${relativePaths.join(' --files ')}`,

     Total   11.5465s

Just happen anyone who looking around and insisted to use Angular CLI, @elunic just created ng-lint-staged to support Angular CLI’s “files” arguments. Thanks to him.

@michaeljota that worked for me

Ok. This is a working example of how to do this with the new feature of lint staged.

module.exports = {
  '*.{ts,js}'(files) {
    // You should get the relative paths of the files, and then, filter for those included in your project sourceRoot
    const relativeFiles = getRelativePaths(files).filter((file) => file.includes(<sourceRoot>));

    if (relativeFiles.length === 0) {
      // Angular will throw if there are not files passed as an argument.
      return [];
    }

    return [`ng lint <project name> --files=${relativeFiles.join(',')}`];
  }
}

With this you will only lint the staged files, or the list of files provided by lint-staged.

@okonet @whiteblackkeys Do you find this solution acceptable?

But this makes the usage of lint-staged pointless. You could just use husky for that.

Using tslint directly works well for me. Thanks @saiprasad2595.

I tried ng-lint-staged and that worked, but the ng lint command is really slow for me (~8s). Using tslint directly is much faster (~800ms). As this is a pre-commit hook 8 seconds is way too long.

"src/**/*.ts": [
  "tslint --fix",
  "git add"
],

@eggp @okon3 comma-separated files did not work for me, so modified the script as follows:

#!/bin/bash

PROJECT=$1
shift
SOURCES=$@
DESTINATIONS=""
DELIMITER=""

for src in $SOURCES
do
    DELIMITER=" --files "
    DESTINATIONS="$DESTINATIONS$DELIMITER${src}"
done

ng lint $PROJECT $DESTINATIONS

Are you sure about the comma? If I run ng lint MY_PROJECT--ts-config src/tsconfig.app.json --files src\app\dynam\states\reducers\ReportsPageLayoutState.ts,src\app\dynam\states\AppEvents.ts it tells me All files pass linting

but if I run (note the multiple --files argument) ng lint MY_PROJECT--ts-config src/tsconfig.app.json --files src\app\dynam\states\reducers\ReportsPageLayoutState.ts --files src\app\dynam\states\AppEvents.ts it correctly tells me there are errors

ERROR: MY_FOLDER/src/app/dynam/states/AppEvents.ts[44, 89]: comment must start with a space
ERROR: MY_FOLDER/src/app/dynam/states/reducers/ReportsPageLayoutState.ts[20, 40]: comment must start with a space

@bnjjj I open an issue in Angular about that angular/angular-cli#13078. I think that is actually Angular the one who is broken, but, I guess we have to find a way to workaround that limitation. 😕