Fixes#19971.
Implement `sourceCode.markVariableAsUsed`.
It has some shortcomings at present - it does mark vars as used, so any other JS plugins can see that, but it doesn't communicate this info back to Rust side, so `no-unused-vars` doesn't act on it. But at least it doesn't cause a crash with "unimplemented" error.
The remaining issue is tracked in #20350.
Add `ecmaFeatures` property to `context.languageOptions.parserOptions`, with `globalReturn` and `impliedStrict` properties.
In normal operation, these are set according to the source type. In conformance build, they can be overridden by config.
TS-ESLint's scope manager has a bug with `CatchClause`s: https://github.com/typescript-eslint/typescript-eslint/issues/11981
```js
try {
throw new Error("Oops");
} catch ({ message }) {}
```
ESLint has the `name` property of the `def` for the `message` binding as the `message` `Identifier` node, but TS-ESLint has it as the `ObjectPattern` `{ message }`.
Work around this bug by fixing any `CatchClause` scopes after TS-ESLint has produced the scope tree.
Closes#16862.
In conformance tests, support `globalReturn` and `impliedStrict` options. This fixes ~40 failing tests.
This PR does not add these options to actually linter, because Oxlint doesn't provide a way to set these options through config.
Ideally, we *would* support these options in `RuleTester` in `eslintCompat` mode, but that would add extra code to the main linter implementation. We can do that when we move `RuleTester` into its own package.
Set `globalReturn` and `impliedStrict` options passed to TS-ESLint scope manager, dependent on source type. In particular, set `globalReturn: true` for CommonJS files. This adds an extra function scope above the global scope.
Pure refactor. Simplify initialization of `analyzeOptions` passed to TS-ESLint scope analyzer. Also fill in all the options, and order properties in same order as the `AnalyzeOptions` type.
Overhaul how variables in the global scope are set up.
* Create globals according to `env` and `globals` from config - previously we always used a standard "esnext" set.
* Remove the patch to `@typescript-eslint/scope-manager`. Instead do what ESLint does and patch up the global scope programmatically after TS-ESLint has produced the scope tree.
* Set `writable` property for global variables according to config.
This still isn't quite correct. There are many subtleties to this and I haven't got to the bottom of it all. But this PR fixes 500 conformance tests, so it's a large step in the right direction.
I haven't added more tests in this PR, because I'm not actually sure what behavior is correct, and what still needs to be fixed. Once all the conformance tests related to globals (which is most of the remaining failing ones) are fixed, we'll have the full picture and can add more tests.
Only alters comments.
* Make sure all `// @ts-expect-error` comments include "TODO" where it's an issue we need to fix.
* Format all the "TODO" comments consistently.
Rename assertion functions to clarify that they're not "real" assertions which we can rely on for validating input, and are only for compile-time testing or debug assertions.
`typeAssertIs` is not a great name, but I couldn't come up with anything better. `debugAssertIs` would be not be accurate, as it'd imply that in debug builds in performs an actual assertion, which it doesn't.
In any case, we should replace `typeAssertIs` with specialized assertion functions which do actually perform runtime assertions in debug builds (e.g. `typeAssertIs<Fix>()` -> `debugAssertIsFix()`).
Pure refactor. Split up `plugins/utils.ts` into 3 files in `utils` directory.
Most importantly, assertion functions are by themselves in an `asserts.ts` file. This paves the way for the next PR (#15946).
Adapted from #15868. Enable `strictNullChecks` in TSConfig for `apps/oxlint`.
Rather than using `!` all over the place, I've added a function `assertIsNonNull`, which performs the same function. Idea is that we can later on produce a debug build where `assertIsNonNull` does an actual runtime assertion (rather than just a TS `asserts`) that the value is not `null` or `undefined`. We can use the debug build in tests, and catch any logic errors.
Unfortunately, TypeScript doesn't seem able to track side effects, so there seems to be no way to tell it "after calling `initAst()`, `ast` is always non-null". Don't want to switch to a having a `getAst` function which returns a non-null value, as that'd introduce unnecessary temp vars, and function calls, on hot paths. So this seems to be the best we can do without incurring runtime cost.
Remove an unnecessary check. `name` property of `Identifier` is always a string, so no need to check it. If user cooks up a fake AST node to pass to the message, they may get a weird error, but they deserve it!
Add `Context#markVariableAsUsed` method. It's unimplemented at present, so just throws an error saying "unimplemented". But that's better for user than "TypeError: context.markVariableAsUsed is not a function", and having the stub in codebase reminds us we need to implement it.
Follow on after #14890. Pure refactor. Just shorten code but compacting `if` statements to a single line. Also move type import to after "real" imports.
Follow-on after #14890. Small optimizations to `ScopeManager`.
* Remove temp vars.
* Test vars with `=== null` or `=== undefined` instead of `!`.
* Avoid reading out of bounds of arrays.
* Get length of array once before loop, rather than on each turn of loop.
Also add comments about potential future optimizations.
Follow-on after #14890.
That PR implemented `ScopeManager` class. Instead of a class, which an instance of is created for each file, use a singleton object, with the underlying TS-ESLint scope manager stored in a top-level var. Methods/getters of `SCOPE_MANAGER` lazily initialize the TS-ESLint scope manager as required, and cache it.
This pattern is the same as we use for `SourceCode`, enabled by the fact that only 1 file is linted at a time. This has several advantages:
1. Reduce object creation - less GC pressure.
2. Property accesses don't need to go up prototype chain, as they would for instances of a class.
3. No need for private properties, which are somewhat expensive to access.
Export AST types directly from `oxlint` package, instead of depending on `@oxc-project/types`. This enables altering the types to reflect that `range` field is always present on AST node in Oxlint's AST (#14354).