Skip to content

Commit

Permalink
feat: Directive to Skip File Parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
jeengbe committed Apr 1, 2024
1 parent b67bec5 commit 2a34dff
Showing 1 changed file with 121 additions and 0 deletions.
121 changes: 121 additions & 0 deletions designs/2024-ignore-file-directive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
- Repo: eslint/eslint
- Start Date: 2024-04-01
- RFC PR:
- Authors: Jesper Engberg ([@jeengbe](https://github.com/jeengbe))

# Directive to Skip File Parsing

## Summary

A new `/* eslint-ignore-file */` directive that gives files the ability to ignore themselves.

## Motivation

The term "application developer" refers to the developer that embeds code generated by a third party over which they have little/no control in their project. "Library developer" refers to the developer who maintains the third-party tool that generates the code used by the application developer. Numbered lists in this document are meant to ease referencing and do not imply an order.


Many libraries that generate code generate code with leading `/* eslint-disable */` directives at the top of generated files. However, those files are still parsed and validated, which slows down the linting process needlessly. Potentially large and complex files are processed, even though their results are useless to the application developer. In the worst case, bugs in linting rules (see [this issue about a broken linting rule](https://github.com/eslint/eslint/issues/18022)) crash the entire ESLint process over artifacts an application developer has no control over. The problem is that `/* eslint-disable */` merely mutes linting results.

This directive will work alongside the `.eslintignore` file in that it too will indicate which file be parsed or not. It extends the concept of ignoring source files by allowing files (specifically generated files) to exclude themselves.

Lastly, library devlopers seldom actually mean "parse, but mute errors" when `/* eslint-disable */` is added at the top of files. While it the best option currently available, "completely skip this file" is actually meant.

To summarize:

1. Performance boost by not parsing unwanted files
2. Don't crash over code the application developer has no/limited control over
3. Does what leading `/* eslint-disable */` are meant to do

## Detailed Design

Please note that I am not familiar with the internals of ESLint and might make assumptions that are incorrect.

For any _source file_ (the root of an AST), if it contains a leading `/* eslint-ignore-file */` directive, skip parsing it. More concretely, the following pseudocode algorithm explains how to determine whether a file should be ignored or processed:

```
for line of source file:
if line (is not zero or more whitespace) and (does not start with zero or more whitespace + "/"):
parse file
if line is "/* eslint-ignore-file */":
skip file parsing
```

A more sophisticated algorithm may be chosen at a later point in the lifecycle of this RFC.

In practice, the imaginary

```ts
export declare function parseFile(filePath: string): AST;
```

needs to be replaced with:

```ts
export function parseFile(filePath: string): AST | null {
const fileContent = streamFileContent(filePath);

if (shouldIgnore(fileContent)) return null;
return parseFileImpl(fileContent.collectToString());
}

declare function parseFileImpl(fileContent: string): AST;
```

How the rest of the system deals with `null` results from parsing a source file is not in the scope of this RFC.

If an `/* eslint-ignore-file */` directive is encountered while parsing a file, a non-fatal error shall be raised, and the directive shall have no further effect.

## Documentation

TBD. The primary audience is a library author. The point **Drawbacks > Bardwards Compatibility** shall be highlighted.

## Drawbacks

1. Backwards Compatibility

Library authors will need to prefix their generated code with both `/* eslint-ignore-file */` and `/* eslint-disable */` directives in order to not break existing projects that have not upgraded their ESLint core to a version that supports the `/* eslint-ignore-file */` directive. Otherwise, updating libraries without updating ESLint accordingly will lead to possible linging errors on generated source files that were previously muted.

2. Primitive Parser

The algorithm described in the **Detailed Design** section is very limited because it does not parse source code. Instead, it directly scans the lines' content. A file containing the following source code is skipped, even though it seems like it shouldn't:

```ts

/* some comment */ statement;

/* eslint-ignore-file */
```

This is an intentional middleground between keeping the analysis as simple (and fast) as reasonable and correctness, which would require parsing read comments to some degree.

3. `.eslintignore` No Longer Authoritative

By extending how files can be ignored, it is no longer purely `.eslintignore` files that dictate which files are parsed or not.

## Backwards Compatibility Analysis

Other than what is highlighted in **Drawbacks > Bardwards Compatibility**, there are no backwards compatibility issues.

## Alternatives

1. As highlighted in **Motivation**, everything described in this RPC is functionally already possible with `.eslintignore` files.

2. `/* eslint-disable */` directives are a weaker alternative of what this RPC proposes.

## Open Questions

1. Allow `// eslint-ignore-file`? Is `// eslint-disable` allowed?

2. Is a more sophisticated algorithm worth it? It is not too difficult to construct a proper one, but that call is not up to me.

## Help Needed

I am unable to implement this in the code itself.

## Frequently Asked Questions

n/a

## Related Discussions

See [related GitHub Issue](https://github.com/eslint/eslint/issues/18028)

0 comments on commit 2a34dff

Please sign in to comment.