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

Created on 22 Nov 2018  路  34Comments  路  Source: okonet/lint-staged

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: 'srcappmyservicemy.service.ts'
``

Environment

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

Most helpful comment

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 },

All 34 comments

@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?

I still have to test it a bit more in deep, but it seems working, thanks @musicEnfanthen

nope, sorry it doesn't work:

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

Unknown option: 'srcappmymodule....ts'

@okonet I'm with @whiteblackkeys here, this does not work. :/

@okonet I think this issue should be reopened :)

I can confirm the same issue with "@angular/cli": "^7.1.2" on:

Environment

  • OS: High Sierra 10.13.6
  • Node.js: v10.14.1
  • lint-staged: v8.1.0

Hello, FYI I'm currently working on a PR to permit a kind of file argument which could be optional for lint-staged. Because now, with ng cli >= v7 we should use something like ng lint myProjectName --files myFile1.ts --files myFile2.ts so if we add an option named file argument for example and add for each path file the file argument (in this case --file) it should work correctly. I begin the code. If you have any suggestion or better idea @okonet let me know :)

@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. :/

@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 :(

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.

At this time I use my fork, if you want a fast workaround please check https://github.com/ovh/cds/blob/master/ui/package.json#L113 :)

Thanks @Phil147

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", "...

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

@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

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.

Does not work for me on Windows with [email protected] and @angular/[email protected] [email protected]

Unknown option: 'src\app...'
Unknown option: 'src\app...'
...

@Phil147 's workaround works for me. Thanks

hmmm, don't know what's happening, but if I run a git commit using the configuration of @saiprasad2595 it changes (and corrupts) my tsconfig.json file, removing all the double quotes:

{ compileOnSave: false, compilerOptions: { baseUrl: './', outDir: './dist/out-tsc', sourceMap: true, declaration: false, module: 'es2015', moduleResolution: 'node', noUnusedLocals: true, noImplicitAny: false, noImplicitThis: true, emitDecoratorMetadata: true, experimentalDecorators: true, importHelpers: true, target: 'es5', typeRoots: [ 'node_modules/@types' ], lib: [ 'es2018', 'dom' ] } };

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.

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 },

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"
],

With latest you can declare a function to be able to pass the arguments as you want. Personally, I use npm scripts, so I just return the array of commands ignoring the file arguments.

module.exports = {
  '*.{ts,js,html}': () => ['npm run lint']
};

In package.json

{
  ...
  "scripts": {
    ...
    "lint": "ng lint",
    ...
  }
}

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

This is my use case, you can transforms the arguments as Angular expect them to be. Something like

module.exports = {
  '*.{ts,js,html}': (files) => [`ng lint <project> --files "${files.join('","')}"`]
};

@okonet

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?

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. 0. `>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.
2. `>ng lint --files src/app/app.module.ts,src/app/shared/shared.module.ts` - comma between files
Linting "project"...
All files pass linting.
3. `>ng lint --files=["src/app/app.module.ts","src/app/shared/shared.module.ts"]` - an array
Linting "project"...
All files pass linting.
wtf? 4. `>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 5. `>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

@AndreiShostik Disagree. My example does work as intended and does check all the files that you pass along. Indeed, the files option is undocumented, but it does works with comma-separated values. I've been using that since the first time I post it, and it has been working ever since.

I just saw that in your example you are not passing along the project name. That's required for --files to work I think.

ng lint --files src/app/app.module.ts,src/app/shared/shared.module.ts

should be:

ng lint {{the name of your project according to the angular.json file}} --files src/app/app.module.ts,src/app/shared/shared.module.ts

@michaeljota if you have several projects you have to set a project from that list explicitly (actually no, one more undocumented option from angular-cli) but if you have only one project angular-cli use it by default so actually you don't need to set it at all. just check. and I've tried also the example which you provided but didn't include it in the list above because I'm not a QA to list everything just check it for yourself before disagree.

comma doesn't work:
>ng lint project --files src\app\app.module.ts,src\app\shared\shared.module.ts

Linting "project"...
All files pass linting.

or in that way it doesn't matter:
>ng lint project --files=src\app\app.module.ts,src\app\shared\shared.module.ts

Linting "project"...
All files pass linting.

but a duplication of --file is:
>ng lint project --files src\app\app.module.ts --files src\app\shared\shared.module.ts

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.
Linting "project"...
no-use-before-declare is deprecated. Since TypeScript 2.9. Please use the built-in compiler checks instead.

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

you can take a look another comment on a related angular-cli issue - https://github.com/angular/angular-cli/issues/7612#issuecomment-455802617

@AndreiShostik In a fresh new CLI application, you will have two projects always, one is your app, and the other one is the app configuration to e2e testing with Protractor. Unless you have removed the other one, you should pass along. I won't argue against you, because I KNOW this works. I've been using that since July, and it does work.

If it is not working for you, it's most probably that you have a misconfiguration somewhere between your project and your lint configuration. But, that's fine man, it's a workaround for you. But is definitively not a real solution.

@michaeljota I don't want to argue with you either but from @angular/cli 8+ version you do have only one project by default - https://blog.ninja-squad.com/2019/05/29/angular-cli-8.0/#project-layout-change

in your example you are just hiding existed lint issues so that's why I have provided examples with output and really asked you to recheck them in different ways to be 100% sure. I even provided you another comment with the same issue - https://github.com/angular/angular-cli/issues/7612#issuecomment-455802617 - and you think that it is a workaround only for me, really? just try. prove not only with your words.

probably something got wrong from angular-cli 8+ version I don't even want to investigate what's wrong and waste my time on that holey implementation.

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

timche picture timche  路  5Comments

yoannmoinet picture yoannmoinet  路  8Comments

jitenderchand1 picture jitenderchand1  路  3Comments

okonet picture okonet  路  6Comments

thedamon picture thedamon  路  3Comments