Giter VIP home page Giter VIP logo

angular-eslint's Introduction

angular-eslint-logo

Angular ESLint

Monorepo for all the tooling which enables ESLint to lint Angular projects

Build Status NPM Version GitHub license NPM Downloads Codecov Commitizen friendly


This project is made possible thanks to the continued hard work going into https://github.com/typescript-eslint/typescript-eslint, and brilliant work on the original TSLint rule implementations in https://github.com/mgechev/codelyzer.


Quick Start

  1. Follow the latest Getting Started guide on https://angular.io/ in order to install the Angular CLI

  2. Create a new Angular CLI workspace in the normal way, optionally using any of the supported command line arguments and following the interactive prompts:

ng new # --maybe --some --other --flags --here
  1. Change directory into your new workspace and then use the Angular CLI to add @angular-eslint/schematics.
ng add @angular-eslint/schematics

...and that's it!

As well as installing all relevant dependencies, the ng add command will automatically detect that you have a workspace with a single project in it, which does not have a linter configured yet. It can therefore go ahead and wire everything up for you!

You will also see that it added the following in your angular.json:

  "cli": {
    "schematicCollections": ["@angular-eslint/schematics"]
  }

Read the section on Using ESLint by default when generating new Projects within your Workspace to understand why this is useful.


Supported Angular CLI Versions

As of v12, we aligned the major version of @angular-eslint with Angular (and Angular CLI).

Therefore, as an example (because these versions may or may not exist yet when you read this):

NOTE: the exact minor and patch versions of each library represented here by x's do not need to match each other, just the first (major) number

For an understanding of Angular CLI version support prior to v12, please see ./docs/ANGULAR_VERSION_SUPPORT.md

Please do not open issues related to unsupported versions of the Angular CLI.


Supported ESLint Versions

See the specified peerDependency in any of our packages, such as the eslint-plugin: https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/package.json


Usage with Nx Monorepos

Nx leans on some, but not all of the packages from this project.

Specifically:

  • It does not use the builder to execute ESLint
  • It does not use the schematics to generate files and config, and is responsible for configuring ESLint via .eslintrc.json files in a way that makes sense for Nx workspaces.

We strongly recommend that you do not try and hand-craft setups with angular-eslint and Nx. It is easy to get things wrong.

  • If using Angular CLI, use the angular-eslint tooling as instructed below
  • If using Nx, defer to the Nx tooling itself to configure things for you, it has been designed and tested specifically for this purpose.

Issues specific to Nx's support of Angular + ESLint should be filed on the Nx repo: https://github.com/nrwl/nx


Packages included in this project

Please follow the links below for the packages you care about.

  • @angular-eslint/builder - An Angular CLI Builder which is used to execute ESLint on your Angular projects using standard commands such as ng lint

  • @angular-eslint/eslint-plugin - An ESLint-specific plugin that contains rules which are specific to Angular projects. It can be combined with any other ESLint plugins in the normal way.

  • @angular-eslint/eslint-plugin-template - An ESLint-specific plugin which, when used in conjunction with @angular-eslint/template-parser, allows for Angular template-specific linting rules to run.

  • @angular-eslint/schematics - Schematics which are used to add and update configuration files which are relevant for running ESLint on an Angular workspace.

  • @angular-eslint/template-parser - An ESLint-specific parser which leverages the @angular/compiler to allow for custom ESLint rules to be written which assert things about your Angular templates.

  • @angular-eslint/utils - Utilities which are helpful when writing and testing custom ESLint rules for Angular workspaces.


Package Versions

All of the packages are published with the same version number to make it easier to coordinate both releases and installations.

We publish a canary release on every successful merge to main, so you never need to wait for a new stable version to make use of any updates.

The latest version under the latest tag is:

NPM Version

The latest version under the canary tag (latest commit to main) is:

NPM Version

(Note: The only exception to the automated publishes described above is when we are in the final phases of creating the next major version of the libraries - e.g. going from 1.x.x to 2.x.x. During these periods, we manually publish canary releases until we are happy with the release and promote it to latest.)


Philosophy on lint rules which enforce code formatting concerns

Please see here for our philosophy on using a linter to enforce code formatting concerns: ./docs/FORMATTING_RULES.md

TL;DR - We will not be maintaining code formatting rules in this project, but you are very welcome to create them yourself using our tooling.


Adding ESLint configuration to an existing Angular CLI project which has no existing linter

NOTE: If you are looking for instructions on how to migrate a project which uses TSLint, please see the next section.

If you want to add ESLint configuration (a .eslintrc.json file and an applicable "lint" target in your angular.json) to an existing Angular CLI project which does not yet have a linter set up, you can invoke the following schematic:

ng g @angular-eslint/schematics:add-eslint-to-project {{YOUR_PROJECT_NAME_GOES_HERE}}

If you only have a single project in your Angular CLI workspace, the project name argument is optional


Migrating an Angular CLI project from Codelyzer and TSLint

Please see here for the legacy information around converting from Codelyzer and TSLint prior to version 16: ./docs/MIGRATING_FROM_TSLINT.md


Using ESLint by default when generating new Projects within your Workspace

Regardless of whether or not you added @angular-eslint to a brand new workspace, or you added it in order to convert a project within an existing workspace, it is likely that from now on you want any subsequent projects that you generate in your workspace to also use ESLint.

In order to achieve this, @angular-eslint provides a set of custom generator schematics which sit on top of the default ones that the Angular CLI provides. They provide all the standard Angular CLI options, but just handle adding ESLint related configuration for you in each case.

You can always invoke them directly by specifying the collection name as part of the generate command:

# To generate a new Angular app in the workspace using ESLint
ng g @angular-eslint/schematics:application
# To generate a new Angular library in the workspace using ESLint
ng g @angular-eslint/schematics:library

Or, alternatively, if you don't want to have to remember to set that collection prefix in front of the : every time, you can set the schematicCollections in your angular.json to start with @angular-eslint/schematics.

You can either do that by hand by adjusting the JSON, or by running the following Angular CLI command:

ng config cli.schematicCollections "[\"@angular-eslint/schematics\"]"

The final result in your angular.json will be something like this:

  "cli": {
    "schematicCollections": ["@angular-eslint/schematics"]
  }

Now your generate commands can just be:

# To generate a new Angular app in the workspace using ESLint (thanks to the schematicCollections set above)
ng g app
# To generate a new Angular library in the workspace using ESLint (thanks to the schematicCollections set above)
ng g lib

Notes on Supported ESLint Configuration File Types

We strongly recommend you stick to using .eslintrc.json.

This is not a constraint we force upon you, and you are more than welcome to use any of ESLint's supported file types for your ESLint config files, e.g. .eslintrc.js, .eslintrc.yml however please note that you will not receive any automated updates to your config from this toolset if you choose to use something other than .eslintrc.json. We will also only generate .eslintrc.json files from our code generators (which you could then convert yourself if you wanted to).

The reason for this is very simple - JSON is a format which is very easy to statically analyze and write transformations for and it is beyond the scope of this community-run project to provide multiple implementations of every possible migration for every possible ESLint configuration file type for every version we release.


Notes on ESLint Configuration Itself

It's important to understand up front that using Angular with ESLint is actually an advanced/complex use-case because of the nature of the files involved:

  • Angular projects use TypeScript files for source code
  • Angular projects use a custom/extended form of HTML for templates (be they inline or external HTML files)

The thing is: ESLint understands neither of these things out of the box.

Fortunately, however, ESLint has clearly defined points of extensibility that we can leverage to make this all work.

For detailed information about ESLint plugins, parsers etc please review the official ESLint documentation: https://eslint.org

The key principle of our configuration required for Angular projects is that we need to run different blocks of configuration for different file types/extensions. In other words, we don't want the same rules to apply on TypeScript files that we do on HTML/inline-templates.

Therefore, the critical part of our configuration is the "overrides" array:

{
  "overrides": [
    /**
     * -----------------------------------------------------
     * TYPESCRIPT FILES (COMPONENTS, SERVICES ETC) (.ts)
     * -----------------------------------------------------
     */
    {
      "files": ["*.ts"],

      // ... applies a special processor to extract inline Component templates
      // and treat them like HTML files
      "extends": ["plugin:@angular-eslint/template/process-inline-templates"]

      // ... other config specific to TypeScript files
    },

    /**
     * -----------------------------------------------------
     * COMPONENT TEMPLATES
     * -----------------------------------------------------
     */
    {
      "files": ["*.html"],
      // ... config specific to Angular Component templates
    }
  ]
}

By setting up our config in this way, we have complete control over what rules etc apply to what file types and our separate concerns remain clearer and easier to maintain.

Seriously, move (mostly) all configuration into overrides

Even though you may be more familiar with including ESLint rules, plugins etc at the top level of your config object, we strongly recommend only really having overrides (and a couple of other things like ignorePatterns, root etc) at the top level and including all plugins, rules etc within the relevant block in the overrides array.

Anything you apply at the top level will apply to ALL files, and as we've said above there is a really strict separation of concerns between source code and templates in Angular projects, so it is very rare that things apply to all files.

Let's take a look at full (but minimal), manual example of a config file (although we recommend deferring to the schematics for automatic config generation whenever possible):

.eslintrc.json

{
  "root": true,
  "ignorePatterns": ["projects/**/*"],
  "overrides": [
    {
      "files": ["*.ts"],
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@angular-eslint/recommended",
        // This is required if you use inline templates in Components
        "plugin:@angular-eslint/template/process-inline-templates"
      ],
      "rules": {
        /**
         * Any TypeScript source code (NOT TEMPLATE) related rules you wish to use/reconfigure over and above the
         * recommended set provided by the @angular-eslint project would go here.
         */
        "@angular-eslint/directive-selector": [
          "error",
          { "type": "attribute", "prefix": "app", "style": "camelCase" }
        ],
        "@angular-eslint/component-selector": [
          "error",
          { "type": "element", "prefix": "app", "style": "kebab-case" }
        ]
      }
    },
    {
      "files": ["*.html"],
      "extends": [
        "plugin:@angular-eslint/template/recommended",
        "plugin:@angular-eslint/template/accessibility"
      ],
      "rules": {
        /**
         * Any template/HTML related rules you wish to use/reconfigure over and above the
         * recommended set provided by the @angular-eslint project would go here.
         */
      }
    }
  ]
}

If I wanted to include other source code related rules extends etc, such as extending from eslint:recommended, then I would include that in the "extends": [] within the *.ts override block, NOT the root of the config object.

Premade configs provided by this project

We have several premade configs within this project which you can extend from (and indeed the configs generated by our schematics do just that). For more information about the configs, check out their READMEs

Going fully manual (not recommended)

Our premade configs handle the parser and plugins options for you behind the scenes so that your final config can be more concise.

If for some reason you wanted to not include any of the premade recommended configs, or you wanted to significantly customize your setup, a fully manual example with the right parsers and plugins wired up (but no actual rules activated) would look like this:

{
  "root": true,
  "ignorePatterns": ["projects/**/*"],
  "overrides": [
    {
      "files": ["*.ts"],
      "parser": "@typescript-eslint/parser",
      "plugins": ["@typescript-eslint", "@angular-eslint"],
      "rules": {}
    },
    {
      "files": ["*.html"],
      "parser": "@angular-eslint/template-parser",
      "plugins": ["@angular-eslint/template"],
      "rules": {}
    }
  ]
}

Our schematics already do the "right" thing for you automatically in this regard, but if you have to configure things manually for whatever reason, please always use the file based overrides as shown in all the examples above.


Notes for eslint-plugin-prettier users

Prettier is an awesome code formatter which can be used entirely independently of linting.

Some folks, however, like to apply prettier by using it inside of ESLint, using eslint-plugin-prettier. If this applies to you then you will want to read this section on how to apply it correctly for HTML templates. Make sure you read and fully understand the information above on the importance of "overrides" before reading this section.

If you choose to use eslint-plugin-prettier, please ensure that you are using version 4.1.0 or later, and apply the following configuration to ESLint and prettier:

.prettierrc

{
  "overrides": [
    {
      "files": "*.html",
      "options": {
        "parser": "angular"
      }
    }
  ]
}

.eslintrc.json

{
  "root": true,
  "ignorePatterns": ["projects/**/*"],
  "overrides": [
    {
      "files": ["*.ts"],
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@angular-eslint/recommended",
        "plugin:@angular-eslint/template/process-inline-templates",
        "plugin:prettier/recommended" // <--- here we inherit from the recommended setup from eslint-plugin-prettier for TS
      ],
      "rules": {}
    },
    {
      "files": ["*.html"],
      "extends": [
        "plugin:@angular-eslint/template/recommended",
        "plugin:prettier/recommended" // <--- here we inherit from the recommended setup from eslint-plugin-prettier for HTML
      ],
      "rules": {}
    }
  ]
}

With this setup, you have covered the following scenarios:

  • ESLint + prettier together work on Components with external templates (and all other source TS files)
  • ESLint + prettier together work on the external template HTML files themselves
  • ESLint + prettier together work on Components with inline templates

Linting HTML files and inline-templates with the VSCode extension for ESLint

If you use vscode-eslint, and want to lint HTML files and inline-templates on your Angular Components, you will need to make sure you add the following to your VSCode settings.json:

// ... more config

"eslint.options": {
  "extensions": [".ts", ".html"]
},

// ... more config

"eslint.validate": [
  "javascript",
  "javascriptreact",
  "typescript",
  "typescriptreact",
  "html"
],

// ... more config

Please see the following issue for more information: microsoft/vscode-eslint#922


Usage without Angular CLI Builder

If you're using this without the Angular CLI Builder don't forget to include .html as one of the file extensions when running the eslint CLI, otherwise templates will not be linted, e.g.:

eslint --ext .ts,.html .

Notes on performance

Background and understanding the trade-offs

As you have hopefully understood from the above section on ESLint configuration what we are dealing with here is a set of tools that were not designed and optimized for this specific use-case.

In software development we are permanently faced with trade-offs. In this case you can think about it this way:

On the one hand...

By using ESLint with Angular (both its TypeScript source code, and its HTML templates), we gain access to a truly massive ecosystem of existing rules, plugins and IDE extensions that we can instantly leverage on our projects.

On the other...

The tooling will never be as fast or memory efficient, or as easy to configure, as something which was purpose built for a narrower use-case and which, well, does less...

TSLint was more in the latter camp - it was purpose built for linting TypeScript source code (note, not HTML), and so it was (depending on the codebase) faster and more efficient at doing it - but it was hugely lacking in community support, features, plugins, rules etc...

As of v15, we generate the fastest possible lint config for you out of the box (rather than the most flexible lint config), but it is possible that you will need to leverage rules which require type information, and this requires extra consideration.

Please read this dedicated guide to fully understand lint performance and how it is impacted by rules requiring type information: ./docs/RULES_REQUIRING_TYPE_INFORMATION.md


Using eslint-disable comments in Angular templates

If you want to be able to use eslint-disable comments in your Angular templates you just need to ensure you are using:

  • @angular CLI tooling packages version 11.2.8 or higher
  • @angular-eslint tooling packages version 2.1.0 or higher

Make sure you are using valid HTML comments, i.e. <!-- this syntax -->, not the kind of comments you use in TypeScript code.

angular-eslint's People

Contributors

abaran30 avatar alan-agius4 avatar alexanderfsp avatar andrefilimono avatar arturovt avatar csvn avatar dependabot[bot] avatar estevezluis avatar gavinwu1991 avatar gsarciotto avatar jameshenry avatar jounqin avatar json-derulo avatar kmcs avatar kuzivany avatar mattlewis92 avatar mbriand-lucca avatar nathan-xiao1 avatar nzacca avatar paulotokimatu avatar pmccloghrylaing avatar rafaelss95 avatar reduckted avatar renovate[bot] avatar res42 avatar sandikbarr avatar sfabriece avatar sonallux avatar timdeschryver avatar wkoza avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-eslint's Issues

NPM package does not link to repository

Hi there! I noticed that the NPM releases for the packages here don't link back to the code repository. For example: @angular-eslint/eslint-plugin does not have any repository information on the right sidebar. This would be beneficial as it adds nice statistics to the NPM page, and allows dependency-update bots like dependabot or greenkeeper to automatically pull information into the pull requests they create.

I believe this would be fixed by adding the repository key to the package.json. By example, Babel does something similar in their monrepo and it works perfectly on the NPM page.

Add missing rules to index

The following rules have already been completed but are missing from the index:

  • directive-class-suffix
  • no-forward-ref
  • relative-url-prefix
  • use-injectable-provided-in

I will add these and update the readme.

ng lint without a specified project throws out of memory

While working in a nrwl monorepo, running ng lint on a single project, e.g. ng lint myProject, works fine for every project in the repo.

However, if ng lint is ran without a specified project, e.g. ng lint, and thus linting all projects, out of memory exceptions are throw.

Seems to me like the memory consumpted by eslint and most probably @typescript-eslint is not released when the linting of a project is finished before starting to lint the next project.

Enhancement: Add ability to hide warnings from the output (a quiet option)

Eslint provides a --quiet option that results in only errors being output. I'm sure some will say that you should just fix your warnings, but when conditions like "having ignored files" result in warnings, it'd be awfully nice to be able to hide those when looking for the error that's preventing your build from succeeding.

Type-check rules cause errors when using `ng lint`

Steps to reproduce

  1. Run the commands

    ng new sample-application
    ng add @angular-eslint/schematics
    
  2. Change angular.json's projects:sample-app:architect:lint property to:

    "lint": {
      "builder": "@angular-eslint/builder:lint",
      "options": {
        "eslintConfig": ".eslintrc.js",
        "tsConfig": [
          "tsconfig.app.json",
          "tsconfig.spec.json",
          "e2e/tsconfig.json"
        ],
        "exclude": ["**/node_modules/**"]
      }
    },
  3. Create a .eslintrc.js file with:

    module.exports = {
      extends: [
        // comment this next line out to see no errors occur
        "plugin:@typescript-eslint/recommended-requiring-type-checking",
        "plugin:@angular-eslint/recommended",
      ],
      plugins: ["@typescript-eslint", "@angular-eslint"],
    };
  4. Run the command

    ng lint
    

Output

An unhandled exception occurred: Error while loading rule '@typescript-eslint/await-thenable': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
Occurred while linting 

Other notes

I created a repository to reproduce this issue. It can be found here: https://github.com/delasteve/eslint-angular-issue-sample-repo

I'm also trying to figure out if this next error is an angular-eslint issue or something else. If you swap the order of the extends array so that plugin:@angular-eslint/recommended is first, you will receive the following error:

D:\development\sample-app\src\app\app.component.html
  0:0  error  Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: src\app\app.component.html.
The extension for the file (.html) is non-standard. You should add "parserOptions.extraFileExtensions" to your config

Schema validation failed

Hi!

When I'm running validation using the command ng lint, I'm always getting the following error message although the linting itself goes without errors:

Linting "app"...
All files pass linting.

Schema validation failed with the following errors:
  Data path "" should have required property 'eslintConfig'.

The lint section has the following content:

        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "eslintConfig": ".eslintrc.json",
            "tsConfig": [
              "tsconfig.app.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }

Packages:

Angular version: `9.1.7`
 "@angular-eslint/builder": "0.0.1-alpha.32",
 "@angular-eslint/eslint-plugin": "0.0.1-alpha.32",
 "@angular-eslint/eslint-plugin-template": "0.0.1-alpha.32",
 "@angular-eslint/schematics": "0.0.1-alpha.32",
 "@angular-eslint/template-parser": "0.0.1-alpha.32",
 "@typescript-eslint/eslint-plugin": "2.31.0",
 "@typescript-eslint/parser": "2.31.0"

Schema validation failed with the following errors: Data path ".builders['lint']" should have required property 'class'

Hello,

I'm trying to migrate from TSLint over to ESLint but I'm getting the following error on ng lint:

Schema validation failed with the following errors: Data path ".builders['lint']" should have required property 'class'.
Error: Schema validation failed with the following errors: Data path ".builders['lint']" should have required property 'class'.

I've installed dependencies like so: ng add @angular-eslint/schematics

My package.json:

dependencies: {
 ...
 "@angular/core": "7.0.2"
 ...
},
devDependencies: {
 ...
 "@angular/compiler-cli": "7.2.4",
 "eslint": "^7.6.0",
 "@angular-eslint/builder": "0.1.0-beta.1",
 "@angular-eslint/eslint-plugin": "0.1.0-beta.1",
 "@angular-eslint/eslint-plugin-template": "0.1.0-beta.1",
 "@angular-eslint/schematics": "0.1.0-beta.1",
 "@angular-eslint/template-parser": "0.1.0-beta.1",
 "@typescript-eslint/eslint-plugin": "3.9.0",
 "@typescript-eslint/parser": "3.9.0"
 ...
}

My .eslintrc.js:

module.exports = {
  env: { browser: true, es6: true, node: true },
  parser: '@typescript-eslint/parser',
  parserOptions: { sourceType: 'module' },
  plugins: ['@angular-eslint/eslint-plugin', '@angular-eslint/eslint-plugin-template', '@typescript-eslint'],
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
  rules: {}
};

My angular.json:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "myApp": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": {
        "build": {},
        "serve": {},
        "extract-i18n": {},
        "test": {},
        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "eslintConfig": ".eslintrc.js",
            "tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"],
            "exclude": []
          }
        },
        "server": {}
      }
    }
  },
  "defaultProject": "myApp",
  "schematics": {
    "@schematics/angular:component": {
      "prefix": "app",
      "styleext": "scss"
    },
    "@schematics/angular:directive": {
      "prefix": "app"
    }
  }
}

ESLint works fine when I run via npm npx eslint PATH-TO-FILE.

Thanks!

ng lint crashes after adding TS indent rule

ngular-eslint version: 0.0.1-alpha.32
angular version: 9.1.9

I realize that adding the following indent rule causes linting to crash: '@typescript-eslint/indent': ['error', 4],. Removing the rule, everything works as expected. I also realize deleting the content of the html root component results in the linter working as expected.

eslint config: https://github.com/crafton/angular-eslint-test/blob/master/.eslintrc.js
offending html: https://github.com/crafton/angular-eslint-test/blob/master/projects/external-config-tester/src/app/app.component.html

Steps to reproduce:

  1. Check out: https://github.com/crafton/angular-eslint-test
  2. Run npm run lint or ng lint

Is this a bug or have I configured something incorrectly?

Appreciate the work you're doing here!!

The name of the class X should end with the suffix Component

I totally agree with that rule and it is really important but I prefer a slightly different style.

In my app every component that is used within anything is named xx.component.ts and mostly shared (through a shared module) and isolated. Then I have components that are "pages", those are entry components for routes and are unique. This has a few benefits, the first is that I can see way faster that this is either a component or just a page that holds components, it is more readable and separates those from each other when I include them in a module.

TL;DR: I would like to add my own style; xx.page.ts must end with "Page" and xxx.component.ts must end with "Component".

Provide something like `plugin:prettier/recommended` to enable all rules

Would be great to have support for recommended rules like prettier or typescript-eslint does it.

{
  "extends": [
    "eslint:recommended",
    "plugin:prettier/recommended"
  ],
  "env": {
    "browser": true,
    "es6": true,
    "serviceworker": true
  },
  "ignorePatterns": [
    "node_modules",
    "scripts",
    "cypress"
  ],
  "overrides": [
    {
      "files": [
        "*.ts"
      ],
      "parser": "@typescript-eslint/parser",
      "parserOptions": {
        "project": "tsconfig.json",
        "sourceType": "module",
        "ecmaVersion": 2020
      },
      "plugins": [
        "@typescript-eslint",
        "@angular-eslint"
      ],
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/eslint-recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking",
        "plugin:@angular-eslint/recommended", // ← like this
        "plugin:prettier/recommended",
        "prettier/@typescript-eslint"
      ],
      "rules": {
        "@typescript-eslint/camelcase": "off",
        "@typescript-eslint/unbound-method": "off",
        "@typescript-eslint/interface-name-prefix": "off",
        "@typescript-eslint/no-misused-promises": [
          "error",
          {
            "checksVoidReturn": false
          }
        ],
        "@typescript-eslint/explicit-function-return-type": "off",
        "@typescript-eslint/no-explicit-any": "off",
        "no-case-declarations": "off"
      }
    },
    {
      "files": [
        "*.component.html"
      ],
      "parser": "@angular-eslint/template-parser",
      "plugins": [
        "@angular-eslint/template"
      ]
    }
  ]
}

Compatibility with @typescript-eslint rules

Some rules will complain about :

Error while loading rule '@typescript-eslint/prefer-includes': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.```
I'm wondering if it's possible to have both working while using angular-eslint parser

Definition for rule '@angular-eslint/template/i18n' was not found

Using 0.2.0-beta.1 and following the latest README update I have added that new i18n option but this gives me the below error.

  1:1  error  Definition for rule '@angular-eslint/template/i18n' was not found  @angular-eslint/template/i18n
.eslintrc.js
const path = require('path')

module.exports = {
  root: true,
  plugins: ['tsdoc'],
  extends: [
    'eslint:recommended',
    'prettier/@typescript-eslint',
    'plugin:@typescript-eslint/recommended',
    'plugin:@angular-eslint/recommended',
    'plugin:prettier/recommended', // always last
  ],
  parserOptions: {
    tsconfigRootDir: path.resolve(__dirname, '..'),
    project: 'tsconfig.base.json',
    sourceType: 'module',
    ecmaVersion: 2020,
  },
  env: {
    es6: true,
    browser: true,
    webextensions: true,
    serviceworker: true,
  },
  ignorePatterns: ['.eslintrc.js'],
  rules: {
    'tsdoc/syntax': 'warn',
    // @typescript-eslint
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/explicit-module-boundary-types': [
      'warn',
      {
        allowedNames: [
          'ngOnInit',
          'ngDoCheck',
          'ngOnChanges',
          'ngAfterContentInit',
          'ngAfterViewInit',
          'ngAfterViewChecked',
          'ngAfterContentChecked',
          'ngOnDestroy',
        ],
      },
    ],
    // @angular-eslint
    '@angular-eslint/no-input-rename': 'off',
  },
  overrides: [
    {
      files: ['*.component.html', '*.page.html'],
      parser: '@angular-eslint/template-parser',
      plugins: ['@angular-eslint/template'],
      rules: {
        '@angular-eslint/template/banana-in-a-box': 'error',
        '@angular-eslint/template/cyclomatic-complexity': 'error',
        '@angular-eslint/template/no-call-expression': 'error',
        '@angular-eslint/template/no-negated-async': 'error',
        '@angular-eslint/template/i18n': [
          'error',
          {
            checkId: false,
            checkText: true,
            checkAttributes: true,
            ignoreAttributes: ['field', 'identifier'],
          },
        ],
      },
    },
  ],
}

Crash when running ng lint

version: "0.0.1-alpha.23"

> cat /private/var/folders/qx/l6dzbht15fj_s89bxrv7x7740000gp/T/ng-JaEvnr/angular-errors.log

[error] TypeError: Cannot read property 'range' of undefined
    at /path/to/angular_project/node_modules/@angular-eslint/eslint-plugin-template/dist/index.js:1:1353
    at Array.map (<anonymous>)
    at postprocess (/path/to/angular_project/node_modules/@angular-eslint/eslint-plugin-template/dist/index.js:1:1156)
    at Linter._verifyWithProcessor (/path/to/angular_project/node_modules/eslint/lib/linter/linter.js:1311:16)
    at Linter._verifyWithConfigArray (/path/to/angular_project/node_modules/eslint/lib/linter/linter.js:1248:25)
    at Linter.verify (/path/to/angular_project/node_modules/eslint/lib/linter/linter.js:1210:25)
    at Linter.verifyAndFix (/path/to/angular_project/node_modules/eslint/lib/linter/linter.js:1400:29)
    at verifyText (/path/to/angular_project/node_modules/eslint/lib/cli-engine/cli-engine.js:230:48)
    at CLIEngine.executeOnFiles (/path/to/angular_project/node_modules/eslint/lib/cli-engine/cli-engine.js:798:28)
    at _lint (/path/to/angular_project/node_modules/@angular-eslint/builder/dist/index.js:1:4477)

1.0.0

The tooling in this monorepo has been working pretty well for a while now and is already downloaded a lot.

Updated to three items now that ESLint 7 and typescript-eslint 3 are out

Update 2: Please see #86 (comment) for a brief update on my personal situation, I cannot comment on the current availability of my co-contributors

Update 3 (Oct 2, 2020): Upgraded to latest Angular 10.1 and TypeScript 4

In my view, we can promote this tooling to 1.0.0 once we have the following two three items in place:


  • Update to Angular 10, ESLint 7.x, TypeScript 3.9 and typescript-eslint 3.x

    • Done as of v0.1.0-beta.1

  • Update to Angular 10.1, TypeScript 4 and typescript-eslint 4.x

    • Done as of v0.5.0-beta.1

- [ ] Finalize recommended config
- There is an initial recommended config in place as of v0.0.1-alpha.32 (https://github.com/angular-eslint/angular-eslint/blob/master/packages/eslint-plugin/src/configs/recommended.json) which is mostly a reflection of what is in the tslint.json that currently ships with the Angular CLI.
- @mgechev I would be grateful for your input on this one so that we capture yours and the rest of the Angular Team's latest and greatest recommendations

Update: this is not actually required for v1.0 as we will initially be focused on converting existing configs


Linting fails with "@angular-eslint/eslint-plugin-template currently only supports 1 Component per file" after upgrading to alpha.28

Linting suddenly fails after upgrading to alpha.28 with @angular-eslint/eslint-plugin-template currently only supports 1 Component per file.

I am suspecting something here https://github.com/angular-eslint/angular-eslint/blob/master/packages/eslint-plugin-template/src/processors.ts#L46.

This componentDecoratorNodes.push(decorator); command might need to go inside the curly brackets.

Issues with rule validation of component- and directive-selector

I have these rule configs in my .eslintrc.json:

"@angular-eslint/directive-selector": [
  "error",
  {
    "type:": "attribute",
    "prefix": "gsh",
    "style": "camelCase"
  }
],
"@angular-eslint/component-selector": [
  "error",
  {
    "type:": "element",
    "prefix": "gsh",
    "style": "kebab-case"
  }
]

When I run ng lint, I get this error:

An unhandled exception occurred: --config:
        Configuration for rule "@angular-eslint/directive-selector" is invalid:
        Value {"type:":"attribute","prefix":"myapp","style":"camelCase"} should NOT have additional properties.

I tried various variations of my config and even compared to the validation in the rule definition but couldn't figure out what I'm doing wrong. Please help πŸ˜…

schema: [
{
type: 'object',
properties: {
type: {
oneOf: [
{ type: 'string' },
{
type: 'array',
items: {
enum: [OPTION_TYPE_ELEMENT, OPTION_TYPE_ATTRIBUTE],
},
},
],
},
prefix: {
oneOf: [{ type: 'string' }, { type: 'array' }],
},
style: {
type: 'string',
enum: [OPTION_STYLE_CAMEL_CASE, OPTION_STYLE_KEBAB_CASE],
},
},
additionalProperties: false,
},
],

How to lint multiple angular libraries?

Hi, how can I setup multiple projects?
For me it's only linting the main app, the projects inside projects folder don't seem to be linting properly.

Here's my structure.

library
β”œβ”€β”€ .eslintrc.json
β”œβ”€β”€ angular.json
β”œβ”€β”€ ...
└─┬ projects
  └─┬ myproj
    β”œβ”€β”€ ...
    β”œβ”€β”€ tsconfig.lib.json
    └── .eslintrc.json
└─┬ src
  β”œβ”€β”€ app
  β”œβ”€β”€ ...
  β”œβ”€β”€ tsconfig.app.json

And here's my angular.json file:
Internal project:

"myproj": {
    "root": "projects/myproj",
    "sourceRoot": "projects/myproj/src",
    "projectType": "library",
    "prefix": "myproj",
    "schematics": {
        "@schematics/angular:component": {
            "style": "scss"
        }
    },
    "architect": {
        "build": {...},
        "test": {...},
        "lint": {
            "builder": "@angular-eslint/builder:lint",
            "options": {
                "eslintConfig": "projects/myproj/.eslintrc.json",
                "tsConfig": [
                    "projects/myproj/tsconfig.lib.json",
                    "projects/myproj/tsconfig.spec.json"
                ],
                "exclude": [
                    "**/node_modules/**",
                    "projects/myproj/schematics/**"
                ]
            }
        }
    }
}

Main app:

"lint": {
    "builder": "@angular-eslint/builder:lint",
    "options": {
        "eslintConfig": ".eslintrc.json",
        "tsConfig": [
            "src/tsconfig.app.json",
            "src/tsconfig.spec.json"
        ],
        "exclude": [
            "**/node_modules/**"
        ]
    }
}

When I run ng lint I get errors from the main app, but not from the project. Even if I run ng lint myproj I get no errors, only the warnings of the excluded files, which tells me it is loading the proper .eslintrc.json file. I even tried to change the names of the files to confirm and it is loading the correct .estlinrc.json. The problem is that it doesn't lint the files inside the project only the main app.

Any ideas on what I'm doing wrong here?

eslint-disable does not work in Angular templates

The following code in a template has no effect.

I can see where the disable directive is processed in es-lint and I don't think it can be re-used for templates. I think this will need to be re-implemented in the parser in this project. Any pointers, clues or ideas about where and how you want to achieve this?

Project logo

This is going to be the future of codelyzer.

Feel free to post logo suggestions here. It'll be great if we can make it recognizable - something similar, but perhaps more modern than the official codelyzer logo:

Logo

Missing module @typescript-eslint

I'm getting an error after running the schematic ng add @angular-eslint/schematics:

npm ERR! code ENOENT
npm ERR! syscall rename
npm ERR! path D:\Projects\simulator\ui\node_modules\@typescript-eslint\experimental-utils\node_modules\eslint-scope
npm ERR! dest D:\Projects\simulator\ui\node_modules\@typescript-eslint\experimental-utils\node_modules\.eslint-scope.DELETE
npm ERR! errno -4058
npm ERR! enoent ENOENT: no such file or directory, rename 'D:\Projects\simulator\ui\node_modules\@typescript-eslint\experimental-utils\node_modules\eslint-scope' -> 'D:\Projects\simulator\ui\node_modules\@typescript-eslint\experimental-utils\node_modules\.eslint-scope.DELETE'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\marti\AppData\Roaming\npm-cache\_logs\2020-03-25T09_47_26_897Z-debug.log
Package install failed, see above.

Which is probably because @typescript-eslint isn't installed. There is no reference to this in the readme either.

After running npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin @typescript-eslint/typescript-estree it worked.

I'm not sure whether it should be part of the schematic or whether I missed something installing the project, but something is missing somewhere...

[rule-request]: Warn on empty lifecycle hooks

Empty lifecycle hooks can have some performance implications without bringing any benefits. Since the runtime will process them we'll get:

  • Slower processing time
  • Larger memory consumption
@Component({... })
export class AppComponent implements OnInit {
  // This should warn
  ngOnInit() {}
}

Rule proposal: template/no-variable-assignment

This rule should report if an Angular template contains property assignments to template variables.

Currently, there's no equivalent of such a rule in codelyzer, but is something we can consider adding to the CLI.

Update Readme

Please update the readme to include more information.
Maybe the current status, the estimated first release, what needs to be done, how people can test existing lints, ...

"@angular-eslint/utils" package is not available on npm

The package @angular-eslint/utils is used in the tests of the eslint-plugin, but when I run npm install, I get an error that the package is not available on npm.

I have searched for it manually on npm and couldn't find it.

Was it recently deleted or is it marked as a private package? πŸ€”

It is a dev dependency.

  "devDependencies": {
    "@angular-eslint/utils": "^0.0.1-alpha.32"
  },

Parsing error: '>' expected in .html files

When I run eslint using your builder I get following error in HTML files:

Parsing error: '>' expected

I don't like example configuration:

https://github.com/angular-eslint/angular-eslint/blob/master/packages/integration-tests/fixtures/angular-cli-workspace/.eslintrc.js

Why do you use overrides for everything?

Is it somehow possible to extend this configuration and use it in my project?

I have

Then I have

Now I created

  • angular configuration with your amazing plugin and I wanted to extend my typescript eslint configuration. However, I can't make it work with HTML files.

What am I missing? πŸ™‚ πŸ™ To me, extensibility is important because I want to share basic eslint and typescript rules across all node.js, react, react-native and angular projects.

My current solution is replacing lint command with eslint --ext .ts src but this way I don't lint HTML files at all.

edit: I know I can lint files using .ts,.html my workaround is ignoring HTML files altogether. πŸ™‚

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Has anyone experience this issue?

Ran command: npm run lint

Configuration in Package.json:
"lint": "ng lint",

<--- Last few GCs --->
 f[30872:00000248EB096DB0]    66390 ms: Mark-sweep 2045.1 (2057.5) -> 2042.0 (2060.5) MB, 137.2 / 0.0 ms  (+ 445.3 ms in 101 steps since start of marking, biggest step 9.1 ms, walltime since start of marking 616 ms) (average mu = 0.166, current mu = 0.054) [30872:00000248EB096DB0]    67007 ms: Mark-sweep 2048.5 (2061.0) -> 2043.0 (2058.8) MB, 133.3 / 0.0 ms  (+ 427.1 ms in 94 steps since start of marking, biggest step 8.8 ms, walltime since start of marking 617 ms) (average mu = 0.131, current mu = 0.092) f

<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 00007FF63BF76C4D]
Security context: 0x0014822008d1 <JSObject>
    1: declareSymbol(aka declareSymbol) [000000AB0E81C299] [C:MyApp\node_modules\typescript\lib\typescript.js:~31012] [pc=00000213B6473474](this=0x02727f5404b1 <undefined>,0x00d90be6bd01 <Map map = 00000133FB4C09D9>,0x02727f5404b1 <undefined>,0x01bd2e47db99 <NodeObject map = 0000007D4C5195C9>,1,111551...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Writing Node.js report to file: report.20200804.070337.30872.0.001.json
Node.js report completed
 1: 00007FF63B36D1EF napi_wrap+113103
 2: 00007FF63B30CA66 public: bool __cdecl v8::base::CPU::has_sse(void)const __ptr64+64982
 3: 00007FF63B30D8F3 public: bool __cdecl v8::base::CPU::has_sse(void)const __ptr64+68707
 4: 00007FF63BB29BBE private: void __cdecl v8::Isolate::ReportExternalAllocationLimitReached(void) __ptr64+94
 5: 00007FF63BB11C91 public: class v8::SharedArrayBuffer::Contents __cdecl v8::SharedArrayBuffer::Externalize(void) __ptr64+833
 6: 00007FF63B9DE1EC public: static void __cdecl v8::internal::Heap::EphemeronKeyWriteBarrierFromCode(unsigned __int64,unsigned __int64,class v8::internal::Isolate * __ptr64)+1436
 7: 00007FF63B9E9420 public: void __cdecl v8::internal::Heap::ProtectUnprotectedMemoryChunks(void) __ptr64+1312
 8: 00007FF63B9E5F44 public: static bool __cdecl v8::internal::Heap::PageFlagsAreConsistent(class v8::internal::HeapObject)+3204
 9: 00007FF63B9DB743 public: bool __cdecl v8::internal::Heap::CollectGarbage(enum v8::internal::AllocationSpace,enum v8::internal::GarbageCollectionReason,enum v8::GCCallbackFlags) __ptr64+1283
10: 00007FF63B9D9DB4 public: void __cdecl v8::internal::Heap::AddRetainedMap(class v8::internal::Handle<class v8::internal::Map>) __ptr64+2452
11: 00007FF63B9FAFBD public: class v8::internal::Handle<class v8::internal::HeapObject> __cdecl v8::internal::Factory::NewFillerObject(int,bool,enum v8::internal::AllocationType,enum v8::internal::AllocationOrigin) __ptr64+61
12: 00007FF63B7616FF public: class v8::internal::interpreter::JumpTableTargetOffsets::iterator & __ptr64 __cdecl v8::internal::interpreter::JumpTableTargetOffsets::iterator::operator=(class v8::internal::interpreter::JumpTableTargetOffsets::iterator && __ptr64) __ptr64+1295
13: 00007FF63BF76C4D public: virtual bool __cdecl v8::internal::SetupIsolateDelegate::SetupHeap(class v8::internal::Heap * __ptr64) __ptr64+546637
14: 00000213B6473474

Improper fix for @angular-eslint/template/banana-in-a-box failes in conjuntion with lint-staged but works on CLI

When applying the rule '@angular-eslint/template/banana-in-a-box': "error" it works fine when eslint is called from the CLI

But for some reason when lint-staged runs the same script using node spawn, it fails with

  0:0  error  Parsing error: Template parse errors:
Parser Error: Unexpected token '=' at column 13 in [(locationId)=$event]

HTML

 <div ([ngModel])="locationId">

This gets auto fixed just fine using eslint --fix but fails with the error above on lint-staged, even though behind the scenes all it does it call the same command.

What it appears to do is incorrectly apply the "fix" to locationId instead of ngModel, . It temporarily becomes

<div ([ngModel])="(locationId)"></div>

And then upon the second pass validation after the fix, it throws off the parser. I cannot understand why, any ideas?

Performance too slow - seems to run eslint for each file instead of whole project

When I run eslint directly, it completes in 30 seconds. If I run with esw -w, it picks up file changes and returns within a few seconds.

When I run with ng lint, it takes over 20 minutes to complete. The output seems to indicate eslint is run separately for each file. This is due to the problem report after each file. When I run eslint directly, I get 1 problem report for the entire project.

I thought it might just be due to my migrating from tslint and the many problems still detected, but I've cleaned all the problems and ng lint still takes an insane amount of time. We have a few hundred .ts files, which is plenty but not crazy.

If this is due to a misconfiguration, please let me know. It's all company files so it will take some work to create a working example. Looking at the code, it appears to executeOnFiles one file at a time instead of all of the files.

Also, why does the angular.json config get its own exclude list? Why not at least prefer what's already in .eslintrc?

Thanks!

Document usage without `ng lint`

Some projects may be using this without Angular CLI, would be worth noting in the docs to remember to add .component.html file extension option to the eslint command, in the same vein as the existing notes regarding vscode-eslint usage:

eslint --config .eslintrc.js --ext .ts,.component.html

Had quite a bit of a head scratcher moment wondering why adding template rules configuration didn't actually do anything. πŸ˜…

Linting the .eslintrc.js file itself

Also a bit of a question, but perhaps the .eslintrc.js itself should also be linted itself instead of only linting just the project files. Any thoughts about this?

Package "@angular-eslint/builder" has an incompatible peer dependency to "@angular-devkit/build-angular" (requires "~0.900.2", would install "0.1000.1").

  1. run - ng update @angular/cli (v10)
  2. Result:
    Package "@angular-eslint/builder" has an incompatible peer dependency to "@angular-devkit/build-angular" (requires "~0.900.2", would install "0.1000.1").
    Γ— Migration failed: Incompatible peer dependencies found.
    Peer dependency warnings when installing dependencies means that those dependencies might not work correctly together.
    You can use the '--force' option to ignore incompatible peer dependencies and instead address these warnings later.

Can you update "@angular-devkit/build-angular to 0.1000.0 + version ? it will fix issue related with Angular 10 migrations?

Suggestion/ Feature Request: Plugin for SonarQube

Just a feature request to make a SonarQube plugin for this, so that it can be used for generating reports that can be visualized on Sonar Server.
Please let me know if it is in plans or ways to integrate in Sonar Rules set :)

inline template temp file created by angular-eslint causes error when prettier is also used

Context

setup with angular-eslint and prettier, with eslint config having:

  extends: [
    'plugin:prettier/recommended',
    'plugin:@angular-eslint/recommended',
  ],

package.json has prettier related modules:

    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-prettier": "^3.1.4",
    "prettier": "2.0.5",

Angular component with inline template, in file : ...\test\libs\ui\components\src\lib\icons\inline-icon.component.ts

@Component({
  selector: 'hc-inline-icon',
  template: ` <ng-content></ng-content> `,
  styles: [],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InlineIconComponent {
}

Error

An unhandled exception occurred: ENOTDIR: not a directory, scandir '....\test\libs\ui\components\src\lib\icons\inline-icon.component.ts'
Occurred while linting ....\test\libs\ui\components\src\lib\icons\inline-icon.component.ts\1_inline-template.component.html:3

[error] Error: ENOTDIR: not a directory, scandir '...\test\libs\ui\components\src\lib\icons\inline-icon.component.ts'
Occurred while linting ...\test\libs\ui\components\src\lib\icons\inline-icon.component.ts\1_inline-template.component.html:3
    at Object.readdirSync (fs.js:876:3)
    at traverseFolder (...\test\node_modules\prettier\index.js:21298:20)
    at findRoot (...\test\node_modules\prettier\index.js:21314:10)
    at maybeParse (...\test\node_modules\prettier\index.js:21338:16)
    at editorconfigSyncNoCache (...\test\node_modules\prettier\index.js:21352:33)
    at editorconfigSyncNoCache (...\test\node_modules\prettier\index.js:16864:26)
    at _resolveConfig (...\test\node_modules\prettier\index.js:24281:68)
    at Function.resolveConfig.sync (...\test\node_modules\prettier\index.js:24308:42)
    at Program (...\test\node_modules\eslint-plugin-prettier\eslint-plugin-prettier.js:174:40)
    at ...\test\node_modules\eslint\lib\linter\safe-emitter.js:45:58

Expected behavior

It should be possible to combine angular-eslint with any other eslint extensions, including prettier.

Workaround

  1. Remove prettier - unacceptable
  2. Just do not use inline templates - not cool :-)

extract-inline-html parser can hang due to regexp catastrophic backtracking

If you configure an override for *.component.ts files to use the extract-inline-html parser like so:

{
    "files": [
        "*.component.ts"
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "sourceType": "module"
    },
    "plugins": [
        "@angular-eslint/template"
    ],
    "processor": "@angular-eslint/template/extract-inline-html"
}

And if it encounters a component with some poor formatting (try adding a couple spaces or a tab before the ending of the @Component attribute like this):

@Component({
    selector: 'widget',
    templateUrl: './widget.component.html',
    styleUrls: ['./widget.component.scss']
  }) <-- space before the curly brace here

The linting will never complete because the regex here hangs. So unfortunately the ng lint execution will just sit there without any sort of error ever occurring.

Parsing error

since v23, many *.ts files throw
0:0 error Parsing error: Cannot read property 'start' of undefined

Templates: Support eslint-disable comments

I tried to use VS Code's fix/suggest on a template error and the following comment was added to the html template:
// eslint-disable-next-line @angular-eslint/template/banana-in-a-box
This is obviously supposed to be:
<!-- eslint-disable-next-line @angular-eslint/template/banana-in-a-box -->

Having a quick look at the source of both this project and es-lint itself I am struggling to see where this functionality comes from. Can anyone fix or point me in the right direction to fix?

Running yarn to install dependencies fail

When I try to run yarn, it fails with the following failure:

lerna ERR! yarn run build exited 1 in '@angular-eslint/template-parser'
lerna WARN complete Waiting for 3 child processes to exit. CTRL-C to exit immediately.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
lerna ERR! yarn install --mutex network:42424 --non-interactive exited 1 in '@angular-eslint/angular-eslint'

[rule request]: `no-empty-module-metadata`

Hello!
In the process of review pull requests in my team we are very often pay attention to empty module metadata (such as "imports" or "providers" from the examples below):

@NgModule({
   imports: [],
   declarations: [SomeComponent],
   exports: [SomeComponent]
})

or

TestBed.configureTestingModule({
   declarations: [TestComponent],
   providers: []
})

I created plugin which checks empty module metadata for ngModule and TestBed.configureTestingModule and throws an error, if module metadata empty.
Plugin contains two rules: for ngModule and for TestBed.configureTestingModule. Also there is an opportunity to add fields to ignore list if for some reason they not needed to be checked.

Π’ut it doesn’t look like a project-specific thing. Most likely, in many projects reviewers focus on empty (unnecessary) fields as on stylistic Issue. Considering that the project uses angular-eslint, I decided to propose the idea of such rules.

If you are interested, I can open pull request.

"no-negated-async" rule is not exported

Hi, it seems the no-negated-async rule is not being exported from eslint-plugin-template. This causes the following error:

Definition for rule '@angular-eslint/template/no-negated-async' was not found.eslint(@angular-eslint/template/no-negated-async)

It appears the fix could be to just add the export to index.ts

  import processors from './processors';
  import bananaInABox, {
    RULE_NAME as bananaInABoxRuleName,
  } from './rules/banana-in-a-box';
+ import noNegatedAsync, {
+  RULE_NAME as noNegatedAsyncRuleName
+ } from './rules/no-negated-async';

  export default {
    processors,
    rules: {
      [bananaInABoxRuleName]: bananaInABox,
+     [noNegatedAsyncRuleName]: noNegatedAsync
    },
  };

I've rebuilt the project with the above additions and the error is gone.

Edit: Link to file https://github.com/angular-eslint/angular-eslint/blob/master/packages/eslint-plugin-template/src/index.ts

Parser error while linting an empty HTML file

Repro

module.exports = {
  overrides: [
    {
      files: ['*.component.html'],
      parser: '@angular-eslint/template-parser',
      plugins: ['@angular-eslint/template'],
      rules: {
        '@angular-eslint/template/banana-in-a-box': 'error',
      },
    },
  ],
};

And an empty HTML file src/app/app.component.html.

Expected Result
Do not throw an error after running eslint src/app/app.component.html.

Actual Result

/home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html
  0:0  error  Parsing error: Cannot read property 'start' of undefined

Additional Info
There's no error when I add some content to the file. Linting also works fine after adding some invalid code:

<div ([foo])="test"></div>
/home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html
  1:6  error  Invalid binding syntax. Use [(expr)] instead  @angular-eslint/template/banana-in-a-box

βœ– 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

Addtional output of eslint src/app/app.component.html --debug:

Details
  eslint:cli CLI args: [ 'src/app/app.component.html', '--debug' ] +0ms
  eslint:cli Running on files +4ms
  eslint:config-array-factory Loading JSON config file: /home/gebsh/Projects/tests/eslint/test-eslint/package.json +0ms
  eslint:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/node_modules/*', '/bower_components/*' ], basePath: '/home/gebsh/Projects/tests/eslint/test-eslint', loose: false } ] +0ms
  eslint:ignore-pattern   processed: { basePath: '/home/gebsh/Projects/tests/eslint/test-eslint', patterns: [ '/node_modules/*', '/bower_components/*' ] } +2ms
  eslint:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/node_modules/*', '/bower_components/*' ], basePath: '/home/gebsh/Projects/tests/eslint/test-eslint', loose: false } ] +0ms
  eslint:ignore-pattern   processed: { basePath: '/home/gebsh/Projects/tests/eslint/test-eslint', patterns: [ '/node_modules/*', '/bower_components/*' ] } +1ms
  eslint:file-enumerator Start to iterate files: [ 'src/app/app.component.html' ] +0ms
  eslint:file-enumerator File: /home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html +1ms
  eslint:cascading-config-array-factory Load config files for /home/gebsh/Projects/tests/eslint/test-eslint/src/app. +0ms
  eslint:cascading-config-array-factory No cache found: /home/gebsh/Projects/tests/eslint/test-eslint/src/app. +0ms
  eslint:config-array-factory Config file not found on /home/gebsh/Projects/tests/eslint/test-eslint/src/app +4ms
  eslint:cascading-config-array-factory No cache found: /home/gebsh/Projects/tests/eslint/test-eslint/src. +0ms
  eslint:config-array-factory Config file not found on /home/gebsh/Projects/tests/eslint/test-eslint/src +0ms
  eslint:cascading-config-array-factory No cache found: /home/gebsh/Projects/tests/eslint/test-eslint. +0ms
  eslint:config-array-factory Loading JS config file: /home/gebsh/Projects/tests/eslint/test-eslint/.eslintrc.js +0ms
  eslint:config-array-factory Config file found: /home/gebsh/Projects/tests/eslint/test-eslint/.eslintrc.js +1ms
  eslint:config-array-factory Loading parser "@angular-eslint/template-parser" from /home/gebsh/Projects/tests/eslint/test-eslint/.eslintrc.js +2ms
  eslint:config-array-factory Loaded: @angular-eslint/[email protected] (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/@angular-eslint/template-parser/dist/index.js) +0ms
  eslint:config-array-factory Loading plugin "@angular-eslint/template" from /home/gebsh/Projects/tests/eslint/test-eslint/.eslintrc.js +63ms
  eslint:config-array-factory Loaded: @angular-eslint/[email protected] (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/@angular-eslint/eslint-plugin-template/dist/index.js) +1ms
  eslint:config-array-factory Plugin /home/gebsh/Projects/tests/eslint/test-eslint/node_modules/@angular-eslint/eslint-plugin-template/dist/index.js loaded in: 221ms +221ms
  eslint:cascading-config-array-factory No cache found: /home/gebsh/Projects/tests/eslint. +288ms
  eslint:config-array-factory Loading package.json config file: /home/gebsh/Projects/tests/eslint/package.json +0ms
  eslint:config-array-factory Loading JSON config file: /home/gebsh/Projects/tests/eslint/package.json +0ms
  eslint:config-array-factory Error reading package.json file: /home/gebsh/Projects/tests/eslint/package.json +0ms
  eslint:config-array-factory Config file not found on /home/gebsh/Projects/tests/eslint +0ms
  eslint:cascading-config-array-factory No cache found: /home/gebsh/Projects/tests. +1ms
  eslint:config-array-factory Config file not found on /home/gebsh/Projects/tests +1ms
  eslint:cascading-config-array-factory No cache found: /home/gebsh/Projects. +0ms
  eslint:config-array-factory Config file not found on /home/gebsh/Projects +0ms
  eslint:cascading-config-array-factory No cache found: /home/gebsh. +0ms
  eslint:cascading-config-array-factory Stop traversing because of considered root. +0ms
  eslint:cascading-config-array-factory Configuration was determined: ConfigArray(3) [ { name: 'DefaultIgnorePattern', filePath: '', criteria: null, env: undefined, globals: undefined, ignorePattern: IgnorePattern { patterns: [Array], basePath: '/home/gebsh/Projects/tests/eslint/test-eslint', loose: false }, noInlineConfig: undefined, parser: undefined, parserOptions: undefined, plugins: undefined, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: undefined, settings: undefined }, { name: '.eslintrc.js', filePath: '/home/gebsh/Projects/tests/eslint/test-eslint/.eslintrc.js', criteria: null, env: undefined, globals: undefined, ignorePattern: undefined, noInlineConfig: undefined, parser: undefined, parserOptions: undefined, plugins: undefined, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: undefined, settings: undefined }, { name: '.eslintrc.js#overrides[0]', filePath: '/home/gebsh/Projects/tests/eslint/test-eslint/.eslintrc.js', criteria: { includes: [Array], excludes: null, basePath: '/home/gebsh/Projects/tests/eslint/test-eslint' }, env: undefined, globals: undefined, ignorePattern: undefined, noInlineConfig: undefined, parser: { error: null, filePath: '/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/@angular-eslint/template-parser/dist/index.js', id: '@angular-eslint/template-parser', importerName: '.eslintrc.js#overrides[0]', importerPath: '/home/gebsh/Projects/tests/eslint/test-eslint/.eslintrc.js' }, parserOptions: undefined, plugins: { '@angular-eslint/template': [Object] }, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: { '@angular-eslint/template/banana-in-a-box': 'error' }, settings: undefined } ] on /home/gebsh/Projects/tests/eslint/test-eslint/src/app +1ms
  eslint:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/node_modules/*', '/bower_components/*' ], basePath: '/home/gebsh/Projects/tests/eslint/test-eslint', loose: false } ] +293ms
  eslint:ignore-pattern   processed: { basePath: '/home/gebsh/Projects/tests/eslint/test-eslint', patterns: [ '/node_modules/*', '/bower_components/*' ] } +0ms
  eslint:ignore-pattern Check {
  filePath: '/home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html',
  dot: false,
  relativePath: 'src/app/app.component.html',
  result: false
} +0ms
  eslint:cli-engine Lint /home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html +0ms
  eslint:linter Linting code for /home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html (pass 1) +0ms
  eslint:linter Verify +0ms
  eslint:linter With ConfigArray: /home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html +0ms
  eslint:linter Parsing error: Cannot read property 'start' of undefined
  eslint:linter TypeError: Cannot read property 'start' of undefined
    at Object.f [as parseForESLint] (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/@angular-eslint/template-parser/dist/index.js:1:1944)
    at parse (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/linter/linter.js:640:22)
    at Linter._verifyWithoutProcessors (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/linter/linter.js:1111:33)
    at Linter._verifyWithConfigArray (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/linter/linter.js:1255:21)
    at Linter.verify (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/linter/linter.js:1210:25)
    at Linter.verifyAndFix (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/linter/linter.js:1400:29)
    at verifyText (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/cli-engine/cli-engine.js:230:48)
    at CLIEngine.executeOnFiles (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/cli-engine/cli-engine.js:798:28)
    at Object.execute (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/lib/cli.js:212:111)
    at Object.<anonymous> (/home/gebsh/Projects/tests/eslint/test-eslint/node_modules/eslint/bin/eslint.js:107:28) +3ms
  eslint:linter Generating fixed text for /home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html (pass 1) +0ms
  eslint:source-code-fixer Applying fixes +0ms
  eslint:source-code-fixer shouldFix parameter was false, not attempting fixes +0ms
  eslint:file-enumerator Complete iterating files: ["src/app/app.component.html"] +296ms
  eslint:cli-engine Linting complete in: 297ms +3ms

/home/gebsh/Projects/tests/eslint/test-eslint/src/app/app.component.html
  0:0  error  Parsing error: Cannot read property 'start' of undefined

βœ– 1 problem (1 error, 0 warnings)

Versions

package version
@angular-eslint/builder 0.0.1-alpha.27
@angular-eslint/eslint-plugin 0.0.1-alpha.27
@angular-eslint/eslint-plugin-template 0.0.1-alpha.27
@angular-eslint/template-parser 0.0.1-alpha.27
TypeScript 3.8.3
ESLint 6.8.0
node 13.12.0
npm 6.14.4

Angular 10 solution style tsconfig.json incompatibility

Steps to reproduce:

  1. Clean install of Angular 10 project: ng new ng-eslint-test-project
  2. Add angular-eslint: ng add @angular-eslint/schematics
  3. Add .eslintrc.js file:
module.exports = {
  extends: ['plugin:@angular-eslint/recommended'],
};
  1. Update angular.json:
        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "eslintConfig": ".eslintrc.js",
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "e2e/tsconfig.json"
            ],
            "exclude": ["**/node_modules/**"]
          }
        },

Now running ng lint produces an error for each .ts file:

ng-eslint-test-project/src/app/app.component.ts
  0:0  error  Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: src/app/app.component.ts.
The file must be included in at least one of the projects provided

βœ– 1 problem (1 error, 0 warnings)

Version info

ng --version gives:

Angular CLI: 10.0.3
Node: 13.13.0
OS: darwin x64

Angular: 10.0.4
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.1000.3
@angular-devkit/build-angular     0.1000.3
@angular-devkit/build-optimizer   0.1000.3
@angular-devkit/build-webpack     0.1000.3
@angular-devkit/core              10.0.3
@angular-devkit/schematics        10.0.3
@angular/cli                      10.0.3
@ngtools/webpack                  10.0.3
@schematics/angular               10.0.3
@schematics/update                0.1000.3
rxjs                              6.5.5
typescript                        3.9.7
webpack                           4.43.0

Workaround:

If you search for "Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser." you end up in the documentation. The recommendation there is to create a separate tsconfig.eslint.json.

Create one in the root:

{
  "extends": "./tsconfig.base.json",
  "include": ["src/**/*.ts", "e2e/**/*.ts"]
}

Override parsing of *.ts files with this file by editing .eslintrc.js:

module.exports = {
  extends: ['plugin:@angular-eslint/recommended'],
  overrides: [
    {
      files: ['*.ts'],
      parser: '@typescript-eslint/parser',
      parserOptions: {
        project: ['tsconfig.eslint.json'],
        ecmaVersion: 2020,
        sourceType: 'module',
      },
    },
  ]
};

Rule proposal: Performance conformance

  • Making sure that external css are preloaded to unblock css
  • Blocking sync scripts before framework scripts

We can detect script tags and link rel="stylesheet in templates and index.html and make sure they have the correct loading strategy.

For example, if in index.html we have blocking scripts before the framework/app scripts we'll delay rendering significantly. If the blocking scripts are inside of component template, it's not as critical (potentially?), so we need to discuss further.

cc @prateekbh

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.