[heft-lint-plugin] Lint files selected by ESLint flat config - #6006
Ian Clanton-Thuon (iclanton) wants to merge 5 commits into
Conversation
bca4d92 to
54eb97a
Compare
0cb1dd4 to
2f28a5b
Compare
|
|
||
| const nodeImportResolverPath = require.resolve('eslint-import-resolver-node'); | ||
|
|
||
| // These localCommonConfig rules require type information (i.e. the TypeScript program). They are grouped |
There was a problem hiding this comment.
These changes can probably all go away when @rushstack/eslint-config is published and pulled back in, right? I'm thinking we just make that its own PR and plan on doing this after the dependency of this project gets bumped.
There was a problem hiding this comment.
(COPILOT) Agreed — reverted the localTypeAwareRules split and the rig without-type-information wrappers out of this PR. I'll do them in a follow-up once @rushstack/eslint-config is published and this project's dependency is bumped, so the rig can consume the published typeAwareRules/helper directly. For now @rushstack/playwright-browser-tunnel is fixed inline in its own eslint.config.js.
There was a problem hiding this comment.
Can we do this cleanup?
There was a problem hiding this comment.
(COPILOT) The rig wiring is back now that @rushstack/eslint-config is published: the localTypeAwareRules split plus without-type-information wrappers in decoupled-local-node-rig/local-node-rig. Re: "Can we do this cleanup?" — could you confirm which cleanup you mean (e.g. the // TODO: Put back ... typescriptEslintPlugin at the top of this file)? Happy to take it on.
Use ESLint's native flat-config enumeration to find files outside the TypeScript program and lint them through the existing cache and reporting pipeline with a single ESLint instance. When a type-aware rule is applied to a file that is not part of the TypeScript program, emit actionable guidance to either exclude the file or lint it with a configuration that does not enable type-aware rules. Also fix the lint issues this surfaces in @rushstack/playwright-browser-tunnel's Playwright config and test fixture files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that @rushstack/eslint-config is published with the `flat/without-type-information` helper, group the rig's own type-aware rules (localCommonConfig) into a `localTypeAwareRules` set and expose a `without-type-information` helper from `decoupled-local-node-rig` and `local-node-rig` that disables type-aware parsing plus both the base profile's and the rig's type-aware rules. Use it in @rushstack/playwright-browser-tunnel to lint the Playwright config and test files, which are excluded from the TypeScript program. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
73af4b7 to
843e29b
Compare
Simplify the additional-file sort to a default lexicographic sort, note that the enumerator lints relative to `buildFolderPath` (its `cwd`), convert the type-info error helper to a loose function that takes the TypeScript file set and build folder as parameters, and empty the playwright-browser-tunnel change comment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback: - Remove the `additionalFiles` option and the extra-file generic from LinterBase; the base now exposes a neutral `getExtraSourceFilesToLintAsync` hook (default empty) that Eslint overrides to enumerate the files selected by the ESLint configuration. The base only deals with a generic `ISourceFileToLint` shape. - Thread the (project-folder-resolved) TypeScript file set into the enumeration as a parameter instead of reading it from a field, resolving the paths at the LintPlugin call site. - Make `ISourceFileToLint.version` optional (omit it for enumerated files) so the base computes the version from file contents, instead of passing an empty string. - Drop the redundant TypeScript-output-folder ignore patterns; emitted JavaScript is already excluded by the default-JavaScript-extension filter (and emit folders such as `lib-esm` cannot be derived from the compiler options anyway). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of blanket-ignoring ESLint's default JavaScript extensions (which also prevented authored `.js` files from being linted), discover the TypeScript output folders and ignore only those when enumerating additional files. - heft-typescript-plugin: expose `emitFolderPaths` on `IChangedFilesHookOptions` (the `outDir`/`declarationDir` plus any `additionalModuleKindsToEmit` folders, such as `lib-esm`, which are not part of the compiler options). - heft-lint-plugin: aggregate those folders from the accessor and ignore them in the additional-file enumerator, and remove the default-JavaScript-extension filter so that authored `.js` files selected by the ESLint configuration are linted. Update the eslint-9-test snapshot, which now lints `eslint.config.js` while still excluding the emitted `lib-commonjs`/`lib-esm` output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
The Heft lint plugin currently sends ESLint only the files from the TypeScript program. As a result, files selected exclusively by the ESLint flat config — for example configuration files, tests excluded from
tsconfig.json, or custom extensions such as Markdown or JSON — are never linted.This change uses ESLint's native flat-config enumeration to discover those files and lints them through the plugin's existing cache, fix, diagnostic, and SARIF pipeline with a single ESLint instance.
Details
For ESLint 9, the plugin creates a discovery-only ESLint instance and calls
lintFiles()with rules disabled to enumerate the files the flat config selects. TypeScript program roots and primary TypeScript emit directories are excluded from discovery. Extensions introduced by the flat config (Markdown, JSON, JSX, custom languages,.tsfiles outside the program, etc.) remain discoverable.A single ESLint instance lints both the program files and the discovered additional files. The injected TypeScript
Programis scoped (via afiles-limited override) to the program's own files, so additional files fall through to the flat config's own parser instead of failing to resolve against the program. Additional files are run through the existing per-file content/config cache and result reporting, and SARIF metadata is collected from that instance.When a type-aware rule would apply to a file that is not part of the TypeScript program (typescript-eslint cannot produce type information for it), the plugin reports an actionable error telling the user to either exclude the file from ESLint or lint it with a configuration that does not enable type-aware rules.
ESLint 8 and TSLint behavior is unchanged.
Adopting the pattern in this repo
@rushstack/eslint-config(published via #6026) exposes aflat/without-type-informationhelper that disables type-aware parsing and rules for a given set of files. This PR wires that helper through the repo's node rigs (decoupled-local-node-rigandlocal-node-rig, including the rig's ownlocalTypeAwareRulesgroup), and uses it in@rushstack/playwright-browser-tunnelto lint itsplaywright.config.tsandtests/**files — which are excluded from the TypeScript program — with only the non-type-aware rules. This also surfaces and fixes several previously-unlinted issues in those files (including a broken import in the test fixture).How it was tested
heft buildinheft-plugins/heft-lint-plugin(TypeScript + self-lint + API Extractor): passedheft test --cleaninbuild-tests/eslint-9-test: 1 passed, including a non-TypeScript custom-extension SARIF resultheft build --cleaninapps/playwright-browser-tunnel: passes, linting the Playwright config and test files with only the non-type-aware rules via the rig helperrush rebuildfor a decoupled-rig consumer (@rushstack/eslint-plugin): no lint regressions from the rig's type-aware rule splitrush change --verify