# ERB Lint [![Build Status](https://github.com/Shopify/erb_lint/workflows/Tests/badge.svg)](https://github.com/Shopify/erb_lint/actions) `erb_lint` is a tool to help lint your ERB or HTML files using the included linters or by writing your own. ## Requirements * Ruby 2.3.0+ - This is due to use of the safe navigation operator (`&.`) - This is also due to the use of the tilde-heredoc `<<~` syntax in some tests. ## Installation ```bash gem install erb_lint ``` ...or add the following to your `Gemfile` and run `bundle install`: ```ruby gem 'erb_lint', require: false ``` ## Configuration Create a `.erb_lint.yml` file in your project, with the following structure: ```yaml --- EnableDefaultLinters: true linters: ErbSafety: enabled: true better_html_config: .better-html.yml Rubocop: enabled: true rubocop_config: inherit_from: - .rubocop.yml ``` > [!TIP] > Creating an `.erb_lint.yml` config file is _not_ mandatory; **the tool works out of the box with default settings**. > > Please note that the two config files referenced in the examples above and below _must_ exist, or you will get an error. (Of course, you can omit the two config file references (i.e. the `better_html_config` key, and the `rubocop_config` section.) See below for linter-specific configuration options. ## Usage This gem provides a command-line interface which can be run like so: 1. Run `erb_lint [options]` if the gem is installed standalone. 2. Run `bundle exec erb_lint [options]` if the gem is installed as a Gemfile dependency for your app. For example, `erb_lint --lint-all --enable-all-linters` will run all available linters on all ERB files in the current directory or its descendants (`**/*.html{+*,}.erb`). If you want to change the glob & exclude that is used, you can configure it by adding it to your config file as follows: ```yaml --- glob: "**/*.{html,text,js}{+*,}.erb" exclude: - '**/vendor/**/*' - '**/node_modules/**/*' linters: ErbSafety: enabled: true better_html_config: .better-html.yml Rubocop: enabled: true rubocop_config: inherit_from: - .rubocop.yml ``` Make sure to add `**/` to exclude patterns; it matches the target files' absolute paths. ## Enable or disable default linters `EnableDefaultLinters`: enables or disables default linters. [Default linters](#linters) are enabled by default. ## Disable rule at offense-level You can disable a rule by placing a disable comment in the following format: Comment on offending lines ```.erb
<%# erb_lint:disable SelfClosingTag %> ``` To raise an error when there is a useless disable comment, enable `NoUnusedDisable`. To disable inline comments and report all offenses, set `--disable-inline-configs` option. ## Exclude You can specify the exclude patterns both of global and lint-local. ```yaml --- exclude: - '**/global-lib/**/*' linters: ErbSafety: exclude: - '**/local-lib/**/*' ``` ## Linters | Available Linters | Default | Description | | ------------------------------------------------ |:--------:|-------------| | [AllowedScriptType](#allowedscripttype) | Yes | prevents the addition of ` Allowed ✅ ``` Example configuration: ```yaml --- linters: ErbSafety: enabled: true better_html_config: .better-html.yml ``` Linter-Specific Option | Description -----------------------|--------------------------------------------------------- `better_html_config` | Name of the configuration file to use for `better-html`. Optional. Valid options and their defaults are described [in better-html's readme](https://github.com/Shopify/better-html#configuration). ### Rubocop Runs RuboCop on all ruby statements found in ERB templates. The RuboCop configuration that `erb_lint` uses can inherit from the configuration that the rest of your application uses. `erb_lint` can be configured independently however, as it will often be necessary to disable specific RuboCop rules that do not apply to ERB files. **Note**: Each ruby statement (between ERB tags `<% ... %>`) is parsed and analyzed independently of each other. Any rule that requires a broader context can trigger false positives (e.g. `Lint/UselessAssignment` will complaint for an assignment even if used in a subsequent ERB tag). Example configuration: ```yaml --- linters: Rubocop: enabled: true rubocop_config: inherit_from: - .rubocop.yml Layout/InitialIndentation: Enabled: false Layout/LineLength: Enabled: false Layout/TrailingEmptyLines: Enabled: false Layout/TrailingWhitespace: Enabled: false Naming/FileName: Enabled: false Style/FrozenStringLiteralComment: Enabled: false Lint/UselessAssignment: Enabled: false Rails/OutputSafety: Enabled: false ``` The cops disabled in the example configuration above provide a good starting point. Linter-Specific Option | Description -----------------------|--------------------------------------------------------- `rubocop_config` | A valid rubocop configuration hash. Mandatory when this cop is enabled. See [rubocop's manual entry on Configuration](http://rubocop.readthedocs.io/en/latest/configuration/) `only` | Only run cops listed in this array instead of all cops. `config_file_path` | A path to a valid rubocop configuration file. When this is provided, `rubocop_config` will be ignored. ### RequireInputAutocomplete This linter prevents the usage of certain types of HTML `` without an `autocomplete` argument: `color`, `date`, `datetime-local`, `email`, `month`, `number`, `password`, `range`, `search`, `tel`, `text`, `time`, `url`, or `week`. The HTML autocomplete helps users to complete filling in forms by using data stored in the browser. This is particularly useful for people with **motor disabilities** or **cognitive impairment** who may have difficulties filling out forms online. ``` Bad ❌ Good ✅ ``` ### RightTrim Trimming at the right of an ERB tag can be done with either `=%>` or `-%>`, this linter enforces one of these two styles. Example configuration: ```yaml --- linters: RightTrim: enabled: true enforced_style: '-' ``` Linter-Specific Option | Description -----------------------|--------------------------------------------------------- `enforced_style` | Which style to enforce, can be either `-` or `=`. Optional. Defaults to `-`. ### SpaceAroundErbTag Enforce a single space after `<%` and before `%>` in the ERB source. This linter ignores opening ERB tags (`<%`) that are followed by a newline, and closing ERB tags (`%>`) that are preceded by a newline. ```erb Bad ❌ <%foo%> <%=foo-%> Good ✅ <% foo %> <% foo %> ``` Example configuration: ```yaml --- linters: SpaceAroundErbTag: enabled: true ``` ### NoJavascriptTagHelper This linter prevents the usage of Rails' [`javascript_tag`](https://apidock.com/rails/ActionView/Helpers/JavaScriptHelper/javascript_tag) helper in ERB templates. The html parser used in this gem knows not to look for html tags within certain other tags like `script`, `style`, and others. The html parser does this to avoid confusing javascript expressions like `if (11)` for a malformed html tag. Using the `javascript_tag` in a ERB template prevents the parser from recognizing the change of parsing context and may fail or produce erroneous output as a result. ```erb Bad ❌ <%= javascript_tag(content, defer: true) %> Good ✅ Bad ❌ <%= javascript_tag do %> alert(1) <% end %> Good ✅ ``` The autocorrection rule adds `//` markers to the existing script, as this is the default behavior for `javascript_tag`. This can be disabled by changing the `correction_style` linter option from `cdata` to `plain`. Example configuration: ```yaml --- linters: NoJavascriptTagHelper: enabled: true correction_style: 'plain' ``` Linter-Specific Option | Description -----------------------|--------------------------------------------------------- `correction_style` | When configured with `cdata`, adds CDATA markers. When configured with `plain`, don't add makers. Defaults to `cdata`. ### RequireScriptNonce This linter prevents the usage of HTML ` Good ✅ ``` ``` Bad ❌ <%= javascript_tag do -%> alert(1) <% end -%> Good ✅ <%= javascript_tag nonce: true do -%> alert(1) <% end -%> ``` ``` Bad ❌ <%= javascript_include_tag "script" %> Good ✅ <%= javascript_include_tag "script", nonce: true %> ``` ``` Bad ❌ <%= javascript_pack_tag "script" %> Good ✅ <%= javascript_pack_tag "script", nonce: true %> ``` ### SelfClosingTag This linter enforces self closing tag styles for void elements. The void elements are `area`, `base`, `br`, `col`, `embed`, `hr`, `img`, `input`, `keygen`, `link`, `menuitem`, `meta`, `param`, `source`, `track`, and `wbr`. If `enforced_style` is set to `always` (XHTML style): ```erb Bad ❌ Good ✅ Some Image ``` If `enforced_style` is set to `never` (HTML5 style): ```erb Bad ❌
Good ✅ ``` Example configuration: ```yaml --- linters: SelfClosingTag: enabled: true enforced_style: 'always' ``` Linter-Specific Option | Description -----------------------|--------------------------------------------------------- `enforced_style` | If we should `always` or `never` expect self closing tags for void elements. Defaults to `never`. ### AllowedScriptType This linter prevent the addition of ` Good ✅ ``` By default, this linter allows the `type` attribute to be omitted, as the behavior in browsers is to consider `