<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Flint | Blog</title><description/><link>https://flint.fyi/</link><language>en</language><item><title>What Flint Does Differently</title><link>https://flint.fyi/blog/what-flint-does-differently/</link><guid isPermaLink="true">https://flint.fyi/blog/what-flint-does-differently/</guid><description>Flint is an experimental linter. It intentionally revisits many of the core design decisions from other popular web linters. This post covers the categories of changes and each high-level change&apos;s hypothesis.

</description><pubDate>Fri, 02 Jan 2026 14:59:23 GMT</pubDate><content:encoded>&lt;p&gt;Flint is an experimental linter.
It intentionally revisits many of the core design decisions from other popular web linters.
Those design decisions generally fall into three categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#architecture&quot;&gt;Architecture&lt;/a&gt;&lt;/strong&gt;: how the core linter and its rules are structured and designed to be run&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#developer-experience&quot;&gt;Developer Experience&lt;/a&gt;&lt;/strong&gt;: how rule authors will create rules that users experience&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#ecosystem&quot;&gt;Ecosystem&lt;/a&gt;&lt;/strong&gt;: standardizing users and plugins around Flint, while still encouraging userland experimentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;https://flint.fyi/blog/introducing-flint&quot;&gt;Introducing Flint&lt;/a&gt; for an overview of “hybrid linting” and Flint’s general experimental hypotheses.
For a detailed breakdown of how Flint differs from other popular linters, read on!&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;How the core linter and its rules are structured and designed to be run.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;&lt;h3 id=&quot;hybrid-core&quot;&gt;Hybrid Core&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint is a &lt;em&gt;hybrid linter&lt;/em&gt;: its core is written in TypeScript, but language-specific plugins are free to use native-speed linting.
We believe this will allow Flint to stay approachable, while still using native speed code to remove most of the traditional slow bottlenecks of web linting.&lt;/p&gt;
&lt;aside aria-label=&quot;Tip&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Tip&lt;/p&gt;&lt;div&gt;&lt;p&gt;See more details on this point in &lt;a href=&quot;https://flint.fyi/blog/introducing-flint#hybrid-linting&quot;&gt;Introducing Flint &gt; Hybrid Linting&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;typescript-for-type-awareness&quot;&gt;TypeScript for Type Awareness&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint will use the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/typescript-native-port&quot;&gt;typescript-go port&lt;/a&gt; for fast type-checking.
This follows the same broad path as &lt;a href=&quot;https://voidzero.dev/posts/announcing-oxlint-type-aware-linting&quot;&gt;Oxlint’s type-aware linting&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;An alternate strategy would have been &lt;a href=&quot;https://biomejs.dev/blog/vercel-partners-biome-type-inference&quot;&gt;Biome’s custom type inference engine&lt;/a&gt;.
Flint’s hypothesis is that the cost of re-implementing and maintaining a type inference engine is long-term greater than that of integrating with typescript-go.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;type-aware-always&quot;&gt;Type-Aware, Always&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint does not mark a distinction between type-aware rules vs.
untyped rules.
Any rule may use any sort of cross-file information such as types.&lt;/p&gt;
&lt;p&gt;This is in contrast to &lt;a href=&quot;https://typescript-eslint.io/getting-started/typed-linting&quot;&gt;typescript-eslint’s opt-in typed linting&lt;/a&gt;.
Flint’s hypothesis is that the divide between untyped core rules and typed plugin rules is painful for the ecosystem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Core rules are less powerful than they could be&lt;/li&gt;
&lt;li&gt;Custom rules have to choose between being fast and easy to set up vs.
slower and type-aware&lt;/li&gt;
&lt;li&gt;Even if the core architecture supported typed rules, it’d be extra work to make separate code paths&lt;/li&gt;
&lt;li&gt;Users now have to keep track of &gt;=1 extra concept while configuring their linter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given Flint’s hybrid core, typed linting should be significantly faster and much easier to set up than in ESLint.
Removing typed linting’s downsides simplifies the linting story:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Core rules don’t need to be duplicated by plugins to add in typed linting support&lt;/li&gt;
&lt;li&gt;Custom rules are simpler to write for not having to make decisions around types&lt;/li&gt;
&lt;li&gt;The core linter architecture can be optimized for type-checked linting performance&lt;/li&gt;
&lt;li&gt;Users no longer need to care about concepts like typed linting while configuring their linter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In building type awareness into the core runtime, Flint will by necessity also need to support stateful languages like TypeScript.
This will solve the common &lt;a href=&quot;https://github.com/microsoft/vscode-eslint/issues/1774&quot;&gt;“ESLint does not re-compute cross-file information on file changes” issue for editors&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;built-in-typescript-support&quot;&gt;Built-In TypeScript Support&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint provides TypeScript support out-of-the-box, the way Biome, Deno lint, Oxlint, and other recent linters all do.
We believe there is a strong correlation between users who will want to lint their code and those whose projects are worth the overhead of TypeScript.
By making TypeScript first-class in Flint -and even making the JS/TS plugin prioritize TS- we believe this makes for a smoother user experience for most users.&lt;/p&gt;
&lt;p&gt;This is in contrast to ESLint, which delegates to typescript-eslint for TypeScript support.
Although it is valuable to have a JavaScript-first linter in the ecosystem, Flint does not need to fill that space.
Using a separate project for TypeScript support -let alone adding in concepts like “extension rules”- is confusing for users and inconvenient to work with for both maintainers and users.&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;built-in-typescript-extensibility&quot;&gt;Built-In TypeScript Extensibility&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;For many users, TypeScript is not the final “superset of JavaScript” language.
Astro, Svelte, Vue, and other languages add to TypeScript syntax and can even completely replace it at times.
However, no existing mainstream linter provides full API hooks for plugins to add their languages into TypeScript.&lt;/p&gt;
&lt;p&gt;Flint provides full extensibility for TypeScript out-of-the-box.
Extension languages will be able to register themselves and patch Flint’s TypeScript language runtime as needed.
Flint’s Vue plugin, for example, will be able to support fully typed &lt;code dir=&quot;auto&quot;&gt;*.vue&lt;/code&gt; imports and JS expressions in &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;template&gt;&lt;/code&gt;s by integrating the &lt;a href=&quot;https://github.com/vuejs/language-tools&quot;&gt;official Vue Language Tools&lt;/a&gt; with Flint’s &lt;a href=&quot;https://volarjs.dev&quot;&gt;Volar.js&lt;/a&gt;-powered TypeScript extensibility APIs.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;cross-file-caching&quot;&gt;Cross File Caching&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The ability to only run linting on impacted files after a small change should theoretically be a great performance win for linting.
Most changes in real-world projects only impact a small set of files.
However, lint result caching is unusable for many large users of linting today:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESLint’s cache does not support cross-file information such as types&lt;/li&gt;
&lt;li&gt;Native speed linters such as Biome and Oxlint run so quickly (prior to introducing typed linting) that a cache is not generally worthwhile&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint allows languages to describe the dependents and dependencies of files, and appropriately invalidates caches on detected file changes.
When a cache is present, Flint will only re-run lint rules on files that are changed since last run - and accounts for transitive dependency impacts.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;core-common-languages&quot;&gt;Core Common Languages&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Building in TypeScript support is a great start, but linting is useful for more than just JavaScript and TypeScript.
ESLint plugins exist for basically every language that web repositories use.
We believe a modern web linter should encourage applying the same developer assistance and quality checks to all the languages in a project.&lt;/p&gt;
&lt;p&gt;Flint additionally provides linting for JSON, Markdown, and YAML out-of-the-box.
No additional plugins needed.
Some other linters are already moving in this direction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://biomejs.dev/internals/language-support&quot;&gt;Biome supports a plethora of frontend languages&lt;/a&gt; with &lt;a href=&quot;https://github.com/biomejs/biome/issues/2365&quot; title=&quot;Biome issue#2365 YAML support&quot;&gt;YAML support planned&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ESLint: already provides &lt;a href=&quot;https://github.com/eslint/json&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;@eslint/json&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/eslint/markdown&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;@eslint/markdown&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s core architecture is completely agnostic of any specific language.
Each language provides its own parser, type information services, and any other language-specific hooks.
Users are, of course, still able to write their own plugins for other languages.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;focused-language-plugins&quot;&gt;Focused Language Plugins&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint will additionally provide first-party &lt;em&gt;plugins&lt;/em&gt; for common languages: CSS, JSX, Vue, and so on.
These languages aren’t necessary for all users of Flint and so aren’t provided by the top-level &lt;code dir=&quot;auto&quot;&gt;flint&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;But, similar to the core common languages, they’re used by enough users to be prioritized.
Flint aims to provide a consistent and high quality user experience for these languages by building them in the Flint project.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;formatting-coordination&quot;&gt;Formatting Coordination&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://typescript-eslint.io/users/what-about-formatting/#formatters-vs-linters&quot;&gt;Formatters are not linters&lt;/a&gt;.
Two separate tools should be used for those two separate concerns.
However, &lt;em&gt;configuring&lt;/em&gt; two tools is cumbersome for users - especially given that the list of files you’d want to &lt;em&gt;format&lt;/em&gt; is almost always roughly the same as the list of files to &lt;em&gt;lint&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;One of the biggest reasons users move to Biome is that it performs both &lt;em&gt;formatting&lt;/em&gt; and &lt;em&gt;linting&lt;/em&gt; with a single &lt;code dir=&quot;auto&quot;&gt;devDependency&lt;/code&gt; and configuration file.
In doing so, they provide a much easier setup and maintenance story, as well as sidestep many common ESLint misconfigurations that lead to performance issues.&lt;/p&gt;
&lt;p&gt;Flint embraces the Biome approach of having one tool &lt;em&gt;coordinate&lt;/em&gt; others.
Flint will automatically run &lt;a href=&quot;https://prettier.io&quot;&gt;Prettier&lt;/a&gt; on linted files to format them after linting.&lt;/p&gt;
&lt;aside aria-label=&quot;Tip&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Tip&lt;/p&gt;&lt;div&gt;&lt;p&gt;See more details on this point in &lt;a href=&quot;https://flint.fyi/blog/introducing-flint#tooling-coordination&quot;&gt;Introducing Flint &gt; Tooling Coordination&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;language-diagnostics-coordination&quot;&gt;Language Diagnostics Coordination&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;As with formatting, most users generally run &lt;em&gt;type checking&lt;/em&gt; on roughly the same set of files as linting.
But most web projects that employ both linting and type checking run them separately in CI.
Projects typically either run them in parallel across two workflows or in series within the same workflow.
That’s inefficient and slow.&lt;/p&gt;
&lt;p&gt;The root problem is that projects typically don’t connect the type information generated by type checking (&lt;code dir=&quot;auto&quot;&gt;tsc&lt;/code&gt;) to typed linting in ESLint.
Projects effectively run a full type-check twice: once with &lt;code dir=&quot;auto&quot;&gt;tsc&lt;/code&gt; and once with typed linting.&lt;/p&gt;
&lt;p&gt;Flint will additionally re-use TypeScript information from typed linting to report type errors (“diagnostics”) on linted files.
This is the equivalent of &lt;a href=&quot;https://oxc.rs/docs/guide/usage/linter/type-aware.html#type-checking-diagnostics&quot;&gt;Oxlint’s &lt;code dir=&quot;auto&quot;&gt;--type-check&lt;/code&gt; flag&lt;/a&gt;.&lt;/p&gt;
&lt;aside aria-label=&quot;Tip&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Tip&lt;/p&gt;&lt;div&gt;&lt;p&gt;See more details on this point in &lt;a href=&quot;https://flint.fyi/blog/introducing-flint#tooling-coordination&quot;&gt;Introducing Flint &gt; Tooling Coordination&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;embeddable-by-design&quot;&gt;Embeddable by Design&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;In addition to running tools such as TypeScript within Flint, Flint will be made to be run as part of other tools.
Its APIs will allow providing core primitives such as a virtual file system and existing TypeScript services.
That way, Flint can be embeddable within other tools for other workflow styles.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;rich-cross-file-fixes&quot;&gt;Rich Cross File Fixes&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;A linter is in many ways the best codemod platform for many kinds of migrations.
It allows you to define a granular, testable set of migration rules, and then keep them enforced over time so developers don’t add regressions.&lt;/p&gt;
&lt;p&gt;The “one file at a time” model of most of today’s linters doesn’t lend itself well to all the operations a codemod might need.
Rules may need to make fixes or suggestions to files other than the one being linted.&lt;/p&gt;
&lt;p&gt;Flint will provide a rich system for rule fixes and suggestions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The ability to indicate changes to files other than the one being linted&lt;/li&gt;
&lt;li&gt;Other file system operations, such as renames and permissions changes&lt;/li&gt;
&lt;li&gt;Targeting specific fixes and/or suggestions programmatically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s hypothesis is that providing rich fixes and suggestions will allow the linter to be used as a full codemod platform via deterministic lint rules.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;developer-experience&quot;&gt;Developer Experience&lt;/h2&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;How rule authors will create rules that users experience.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;&lt;h3 id=&quot;only-errors&quot;&gt;Only Errors&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;All mainstream web linters today allow configuring rules as &lt;em&gt;errors&lt;/em&gt; or &lt;em&gt;warnings&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Errors&lt;/em&gt; are generally visualized with red squigglies and fail builds&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Warnings&lt;/em&gt; are generally visualized with yellow squigglies and don’t fail builds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Warnings are intended to be for transient indicators during migrations, for lower-impact reports, or when rules aren’t certain about issues.
However, that delineation is often not worthwhile in practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Warnings tend to live forever in codebases, which trains developers to ignore lint reports.&lt;/li&gt;
&lt;li&gt;Using the same red color and terminology for &lt;em&gt;lint&lt;/em&gt; errors and &lt;em&gt;type-checking&lt;/em&gt; errors is confusing.
&lt;ul&gt;
&lt;li&gt;Some developers prefer &lt;a href=&quot;https://github.com/microsoft/vscode-eslint/pull/1164&quot;&gt;VS Code’s &lt;code dir=&quot;auto&quot;&gt;eslint.rules.customizations&lt;/code&gt;&lt;/a&gt; to visualize lint errors with yellow squigglies, so as to not conflict with TypeScript’s red squigglies.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If a problem can’t be determined with certainty, it either should be suppressed using an inline config comment with an explanation, or not turned into a lint rule at all!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We believe warnings are a bad fit for the migration use case.
Tools like &lt;a href=&quot;https://github.com/IanVS/eslint-nibble&quot;&gt;eslint-nibble&lt;/a&gt; and ESLint’s new &lt;a href=&quot;https://eslint.org/docs/latest/use/suppressions&quot;&gt;Bulk Suppressions&lt;/a&gt; provide a more comprehensive experience.&lt;/p&gt;
&lt;p&gt;Flint does not allow changing rule report severities.
All lint rule reports are treated as lint errors and will be visualized with the same non-red color -e.g.
yellow or orange- squigglies in errors.
Gradual onboardings of new rules or rule options are a separately managed feature akin to ESLint’s bulk suppressions.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;comprehensive-rule-reports&quot;&gt;Comprehensive Rule Reports&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Rule reports are the entry point for most developers who experience a linter.
The little red or yellow squiggly in an editor that shows rule text on hover is how developers learn about the report.&lt;/p&gt;
&lt;p&gt;If that message includes too little text, people won’t understand the report.
Too much text, and they won’t read any of it.
Many rules’ reports have too much conceptual complexity or too many important nuances to fit in a brief hover message.&lt;/p&gt;
&lt;p&gt;Linters today generally provide two pieces of information with reports:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ID/name, linked to the rule’s online documentation&lt;/li&gt;
&lt;li&gt;Text description of the rule report&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oxlint reports may additionally provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Additional contextual text to explain the report&lt;/li&gt;
&lt;li&gt;Related spans to highlight in the CLI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint leans into Oxlint-style detailed rule reports.
Its rules include rich metadata explaining the details of rule reports.
Flint’s CLI will display the appropriate amount of information depending on how it is being run.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;interactive-and-watch-cli-modes&quot;&gt;Interactive and Watch CLI Modes&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Linter CLIs can be run in drastically different use cases.&lt;/p&gt;
&lt;p&gt;When you have a lot of tooling complaints in many files, it can be useful to get a full list of them on the CLI.
It can also be useful to update that list of reports as you fix them.&lt;/p&gt;
&lt;p&gt;Alternately, if you’re focusing on fixing a tricky rule report, it can be helpful to have rich detailed output for the report in question.
You might want to only have one file’s worth of reports at a time, though, to not be overwhelmed with many reports.&lt;/p&gt;
&lt;p&gt;Flint provides two CLI flags modifiers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;--interactive&lt;/code&gt;: to provide a user-controllable focused view of one report at a time&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;--watch&lt;/code&gt;: re-lints files as they change, similar to &lt;code dir=&quot;auto&quot;&gt;tsc --watch&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those two flags can be combined as needed depending on how the user is running Flint.
For example, when running in CI you would likely want neither flag.
Using both flags locally would provide a nice focused view on one lint report at a time:&lt;/p&gt;
&lt;img alt=&quot;Dark mode view of the Flint terminal in --interactive --watch mode, showing 1 file&amp;#x27;s ts/forInArrays violation with details out of 4 files.&quot; src=&quot;https://flint.fyi/screenshots/flint-interactive-dark.webp&quot;&gt;
&lt;img alt=&quot;Light mode view of the Flint terminal in --interactive --watch mode, showing 1 file&amp;#x27;s ts/forInArrays violation with details out of 4 files.&quot; src=&quot;https://flint.fyi/screenshots/flint-interactive-light.webp&quot;&gt;
&lt;div&gt;&lt;h3 id=&quot;comprehensive-rule-documentation&quot;&gt;Comprehensive Rule Documentation&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The next step for many developers who receive a lint report is the rule’s documentation page.
The docs sites for most linters today standardize some level of the following information for rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High-level ID/name and description&lt;/li&gt;
&lt;li&gt;High-level metadata, such as which config(s) include the rule and whether it requires type information&lt;/li&gt;
&lt;li&gt;Longer description of the rule&lt;/li&gt;
&lt;li&gt;Examples of configuring the rule, as well as its options if they exist&lt;/li&gt;
&lt;li&gt;When &lt;em&gt;not&lt;/em&gt; to use the rule&lt;/li&gt;
&lt;li&gt;Links to the rule’s source code, test code, and any related other documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s documentation standardizes &lt;em&gt;all&lt;/em&gt; of those points on each of its docs pages.
Its internal tooling will enforce those sections all be filled out for each rule.
Flint will also provide tooling that will allow third-party plugin websites to do the same.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;standardized-rule-metadata&quot;&gt;Standardized Rule Metadata&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Users like naming and stylistic standardization.
Without consistent patterns, it becomes much more difficult to remember how things work consistently.
Rule names, option names, option value defaults, and other strings users need to think of when using a linter are easier to remember when they’re consistent.&lt;/p&gt;
&lt;p&gt;Unfortunately, no mainstream linter today is consistent with its choices — even internally.
Community plugins often make very different and inconsistent choices as well.
This lack of standardization is painful for users.&lt;/p&gt;
&lt;p&gt;Flint standardizes the following common metadata points for all its provided plugins and rules…&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;standardized-plugin-categories&quot;&gt;Standardized Plugin Categories&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;From a technical perspective, lint rules can generally be split into the following three categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Formatting&lt;/strong&gt;: Rules that don’t change the AST &lt;em&gt;(not implemented in Flint)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stylistic&lt;/strong&gt;: Rules that change the AST but don’t change code logic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logical&lt;/strong&gt;: Rules that change code logic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those categories are useful for surfacing to developers why a rule would -or wouldn’t- be useful.
Many developers also treat reports differently based on which category they fall into.&lt;/p&gt;
&lt;p&gt;Flint’s core plugins separate their primary suggested presets into &lt;code dir=&quot;auto&quot;&gt;logical&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;stylistic&lt;/code&gt;.
Third-party plugins are encouraged -but not required- to use those categories as well.&lt;/p&gt;
&lt;p&gt;That split between &lt;code dir=&quot;auto&quot;&gt;logical&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;stylistic&lt;/code&gt; allows developers to react to the metadata in their own tooling.
For example, developers might want to use an equivalent of &lt;code dir=&quot;auto&quot;&gt;eslint.rules.customizations&lt;/code&gt; to downgrade stylistic rules to blue info squigglies instead of yellow in the future planned Flint VS Code extension:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;linter.rules.customizations&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;&quot;category&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;stylistic&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;severity&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h4 id=&quot;standardized-rule-messages&quot;&gt;Standardized Rule Messages&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;The text of rule messages in mainstream linters today is often inconsistent across rules, even within the same linter or plugin.
Older rules tend to have assertive and curt messages, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-console&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-console&lt;/code&gt;&lt;/a&gt;: &lt;code dir=&quot;auto&quot;&gt;Unexpected console statement.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-empty&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-empty&lt;/code&gt;&lt;/a&gt;: &lt;code dir=&quot;auto&quot;&gt;Empty block statement.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Newer or more recently updated rule messages tend to be more descriptive and speak to the actual problems the rules detect, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-useless-assignment&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-loss-of-precision&lt;/code&gt;&lt;/a&gt;: &lt;code dir=&quot;auto&quot;&gt;This number literal will lose precision at runtime.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-useless-assignment&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-useless-assignment&lt;/code&gt;&lt;/a&gt;: &lt;code dir=&quot;auto&quot;&gt;This assigned value is not used in subsequent statements.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In practice, users don’t generally react well to curt messages.
They can feel like the linter is saying that something is &lt;em&gt;absolutely wrong&lt;/em&gt;, even though most lint rules are sometimes wrong.
There’s a reason why many linters put &lt;em&gt;“When Not To Use”&lt;/em&gt; sections in their rule documentation pages.&lt;/p&gt;
&lt;p&gt;All rule messages in the Flint project will have consistent phrasing describing the actual problem(s) being reported.
Rules will attempt to never be curt or overly prescriptive about what the user “should” do.&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;standardized-rule-names&quot;&gt;Standardized Rule Names&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;Rule names have to make several choices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abbreviation:
&lt;ul&gt;
&lt;li&gt;Abbreviated: &lt;a href=&quot;https://eslint.org/docs/latest/rules/no-cond-assign&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-cond-assign&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://eslint.org/docs/latest/rules/no-const-assign&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-const-assign&lt;/code&gt;&lt;/a&gt; / &lt;a href=&quot;https://biomejs.dev/linter/rules/no-const-assign&quot;&gt;noConstAssign&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unabbreviated: &lt;a href=&quot;https://eslint.org/docs/latest/rules/no-constant-binary-expression&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-constant-binary-expression&lt;/code&gt;&lt;/a&gt; / &lt;a href=&quot;https://next.biomejs.dev/linter/rules/no-constant-binary-expression&quot;&gt;noConstantBinaryExpression&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Prefixes:
&lt;ul&gt;
&lt;li&gt;Definitive: &lt;code dir=&quot;auto&quot;&gt;@typescript-eslint/ban-ts-comment&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;no-await-in-loop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Loose: &lt;code dir=&quot;auto&quot;&gt;@typescript-eslint/restrict-plus-operands&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;prefer-const&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;No prefix: &lt;code dir=&quot;auto&quot;&gt;array-callback-return&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;constructor-super&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Singularity:
&lt;ul&gt;
&lt;li&gt;Singular: &lt;code dir=&quot;auto&quot;&gt;default-case-last&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;for-direction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Plural: &lt;code dir=&quot;auto&quot;&gt;no-magic-numbers&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;require-atomic-updates&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inconsistent answers to each of those choices lead to user confusion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abbreviation:
&lt;ul&gt;
&lt;li&gt;Memorizing many abbreviations is annoying at best and confusing at worst&lt;/li&gt;
&lt;li&gt;Some words abbreviate to different meanings, such as “constant” and “const”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Prefixes:
&lt;ul&gt;
&lt;li&gt;Alphabetical sorting of rules places them similarly prefixed rules together, weirdly&lt;/li&gt;
&lt;li&gt;Many rules have dropped their prefix after adding an option to invert behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Singularity: just one character difference can be particularly difficult to memorize&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Flint, core rule names will attempt to make one choice for each of those naming options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abbreviation: no abbreviation, so users won’t have to memorize dozens of abbreviations&lt;/li&gt;
&lt;li&gt;Prefixes: no prefixes; the rules would be named for the behavior or syntax they target&lt;/li&gt;
&lt;li&gt;Singularity: always plural, as that’s how one would describe what rules target&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint reworks names to be consistent and fully typed out.
Here are some reworked names from Flint’s TypeScript plugin:&lt;/p&gt;

































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Current Rule Name&lt;/th&gt;&lt;th&gt;Reworked Rule Name&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/array-callback-return&quot;&gt;array-callback-return&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;arrayCallbackReturns&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/ban-ts-comment&quot;&gt;ban-ts-comment&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;typescriptCommentDirectives&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/constructor-super&quot;&gt;constructor-super&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;constructorSuper&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/default-case-last&quot;&gt;default-case-last&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;defaultCaseLast&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/for-direction&quot;&gt;for-direction&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;forLoopDirections&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-await-in-loop&quot;&gt;no-await-in-loop&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;loopAwaits&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-cond-assign&quot;&gt;no-cond-assign&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;conditionalAssignments&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-const-assign&quot;&gt;no-const-assign&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;constAssignments&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-constant-binary-expression&quot;&gt;no-constant-binary-expression&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;constantBinaryExpressions&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises&quot;&gt;no-floating-promises&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;floatingPromises&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-magic-numbers&quot;&gt;no-magic-numbers&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;magicNumbers&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/prefer-const&quot;&gt;prefer-const&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;constVariables&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/require-atomic-updates&quot;&gt;require-atomic-updates&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;atomicUpdates&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/restrict-plus-operands&quot;&gt;restrict-plus-operands&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;plusOperands&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Flint also includes the rule name as a required field in its metadata (unlike ESLint).
That way, downstream tooling such as documentation generators and unit testers can rely on it.&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;standardized-rule-options&quot;&gt;Standardized Rule Options&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;Rule options have to make an even broader, deeper set of choices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Format:
&lt;ul&gt;
&lt;li&gt;Array: &lt;a href=&quot;https://typescript-eslint.io/rules/array-type&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;array-type&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://eslint.vuejs.org/rules/no-restricted-component-names&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-restricted-component-names&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Object with keys for option names: …almost all other rules&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Name:
&lt;ul&gt;
&lt;li&gt;Plurality:
&lt;ul&gt;
&lt;li&gt;Singular: &lt;a href=&quot;https://eslint.org/docs/latest/rules/no-implicit-coercion#options&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-implicit-coercion&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;boolean&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Plural: &lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#checkthenables&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-floating-promises&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;checkThenables&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Prefix:
&lt;ul&gt;
&lt;li&gt;Turning off checks:
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;allow*&lt;/code&gt;: &lt;a href=&quot;https://eslint.org/docs/latest/rules/getter-return#options&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;getter-return&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;allowImplicit&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;ignore*&lt;/code&gt;: &lt;a href=&quot;https://eslint.style/rules/js/no-trailing-spaces#ignorecomments&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-trailing-spaces&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;ignoreComments&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;skip*&lt;/code&gt;: &lt;a href=&quot;https://eslint.style/rules/js/no-trailing-spaces#skipblanklines&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-trailing-spaces&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;skipBlankLines&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Turning on checks:
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;check*&lt;/code&gt;: &lt;a href=&quot;https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prevent-abbreviations.md#checkproperties&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;prevent-abbreviations&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;checkProperties&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;enforce*&lt;/code&gt;: &lt;a href=&quot;https://eslint.org/docs/latest/rules/accessor-pairs#enforceforclassmembers&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;accessor-pairs&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;enforceForClassMembers&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;include*&lt;/code&gt;: &lt;a href=&quot;https://eslint.org/docs/latest/rules/no-duplicate-imports#options&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-duplicate-imports&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;includeExports&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;require*&lt;/code&gt;: &lt;a href=&quot;https://eslint.style/rules/js/arrow-parens#requireforblockbody&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;arrow-parens&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;requireForBlockBody&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Value defaults:
&lt;ul&gt;
&lt;li&gt;Boolean values:
&lt;ul&gt;
&lt;li&gt;Off-by-default: &lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#ignoreiife&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-floating-promises&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;ignoreIIFE&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On-by-default: &lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#ignorevoid&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-floating-promises&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;ignoreVoid&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Multi-values:
&lt;ul&gt;
&lt;li&gt;Empty by default: &lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#allowforknownsafecalls&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-floating-promises&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;allowForKnownSafeCalls&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Starting set: &lt;a href=&quot;https://typescript-eslint.io/rules/restrict-template-expressions#allow&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;restrict-template-expressions&lt;/code&gt; &gt; &lt;code dir=&quot;auto&quot;&gt;allow&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What a list!&lt;/p&gt;
&lt;p&gt;Flint’s rules attempt to set a convention of making the same choice consistently for their options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Format: an object with keys for option names&lt;/li&gt;
&lt;li&gt;Name:
&lt;ul&gt;
&lt;li&gt;Plurality: always plural, as that’s how one would describe what rule options target&lt;/li&gt;
&lt;li&gt;Prefix:
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;allow*&lt;/code&gt; for options that add in an array of values&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;check*&lt;/code&gt; for options that turn on a check&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;ignore*&lt;/code&gt; for options that turn off a check&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Value defaults:
&lt;ul&gt;
&lt;li&gt;Boolean values: off-by-default, for simpler truthiness concepts&lt;/li&gt;
&lt;li&gt;Multi-values: empty by default, so specifying values doesn’t remove defaults
&lt;ul&gt;
&lt;li&gt;If a value is important to include by default, it should be hardcoded on&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some rule options from Flint’s TypeScript plugin:&lt;/p&gt;





































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Current Name&lt;/th&gt;&lt;th&gt;Reworked Name&lt;/th&gt;&lt;th&gt;Current Default&lt;/th&gt;&lt;th&gt;Reworked Default&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;(&lt;a href=&quot;https://typescript-eslint.io/rules/array-type&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;array-type&lt;/code&gt;&lt;/a&gt;)&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;style&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;&apos;array&apos;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;(&lt;a href=&quot;https://eslint.vuejs.org/rules/no-restricted-component-names#options&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;no-restricted-component-names&lt;/code&gt;&lt;/a&gt;)&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;names&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/restrict-template-expressions#allow&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;allow&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[{ ... }]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#allowforknownsafecalls&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;allowForKnownSafeCalls&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/getter-return#options&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;allowImplicit&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ignoreImplicit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-implicit-coercion#options&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;boolean&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;booleans&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;true&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prevent-abbreviations.md#checkproperties&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;checkProperties&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#checkthenables&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;checkThenables&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/accessor-pairs#enforceforclassmembers&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;enforceForClassMembers&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ignoreClassMembers&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;true&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.style/rules/js/no-trailing-spaces#ignorecomments&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;ignoreComments&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#ignoreiife&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;ignoreIIFE&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://typescript-eslint.io/rules/no-floating-promises#ignorevoid&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;ignoreVoid&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;true&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.org/docs/latest/rules/no-duplicate-imports#options&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;includeExports&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;checkExports&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.style/rules/js/arrow-parens#requireforblockbody&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;requireForBlockBody&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;checkBlockBodies&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://eslint.style/rules/js/no-trailing-spaces#skipblanklines&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;skipBlankLines&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ignoreBlankLines&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;(same)&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Flint will also sort rule options alphabetically in their docs pages.
Users should be able to O(log(N)) scan a docs page for a rule option.
Not O(n) search through some arbitrary order.&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;standardized-specifiers&quot;&gt;Standardized Specifiers&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;Some rules allow specifying types or values in their options.
For example, &lt;a href=&quot;https://typescript-eslint.io/rules/no-restricted-types&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;@typescript-eslint/no-restricted-types&lt;/code&gt;&lt;/a&gt; allows specifying types in its &lt;code dir=&quot;auto&quot;&gt;types&lt;/code&gt; option:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;@typescript-eslint/no-restricted-types&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&quot;types&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&quot;SomeType&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Don&apos;t use SomeType because it is unsafe.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The problem with using plain strings to target names is that they are ambiguous.
In the example, &lt;em&gt;any&lt;/em&gt; type named &lt;code dir=&quot;auto&quot;&gt;SomeType&lt;/code&gt; would be restricted, even if it is a different type than the one the user intended.&lt;/p&gt;
&lt;p&gt;Over in typescript-eslint, we developed a &lt;a href=&quot;https://typescript-eslint.io/packages/type-utils/type-or-value-specifier&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;TypeOrValueSpecifier&lt;/code&gt; format&lt;/a&gt; for specifying types or values in options.
It allows users to specify not just the name but also the source -global, package, etc.- of a type or value.
Here’s how that would look for specifying &lt;code dir=&quot;auto&quot;&gt;SomeType&lt;/code&gt; from a specific file:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;@typescript-eslint/no-restricted-types&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&quot;types&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&quot;message&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Don&apos;t use SomeType because it is unsafe.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&quot;type&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;from&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;name&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;SomeType&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&quot;path&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;./src/legacy-types.ts&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Rules implemented in the Flint project will only ever use the &lt;code dir=&quot;auto&quot;&gt;TypeOrValueSpecifier&lt;/code&gt; format to specify types or values.
Plugins will be strongly encouraged to use the format instead of ambiguous strings.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;typed-rules-and-options&quot;&gt;Typed Rules and Options&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;One of the biggest points of user pain with all linter configuration systems today is that &lt;em&gt;rules and their options are not type-checked&lt;/em&gt;.
They’re only validated at runtime.
Mainstream linters today have you specify rules as properties of an object, where their string key is their plugin name and rule name, and their value is their severity and any options:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;my-plugin/some-rule&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, { &lt;/span&gt;&lt;span&gt;&quot;option&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; }]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Those string keys have no associated types in config files.
Linters themselves can validate rule options, such as &lt;a href=&quot;https://eslint.org/docs/latest/extend/custom-rules#options-schemas&quot;&gt;ESLint’s options schemas&lt;/a&gt;, but those don’t translate to TypeScript types.
You don’t get editor intellisense while authoring; instead, you have to use &lt;a href=&quot;https://www.npmjs.com/package/@eslint/config-inspector&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;@eslint/config-inspector&lt;/code&gt;&lt;/a&gt; or run your config to know whether you’ve mistyped the name of a rule or an option.&lt;/p&gt;
&lt;p&gt;Flint’s rules will take a more modern approach.
They will allow &lt;a href=&quot;https://standardschema.dev&quot;&gt;Standard Schema&lt;/a&gt; descriptions for rule options, which enables the use of TypeScript-friendly schema validation libraries such as &lt;a href=&quot;https://zod.dev&quot;&gt;Zod&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;src/rules/someRule.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { typescriptLanguage } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;@flint/typescript-language&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { z } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;zod&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export const &lt;/span&gt;&lt;span&gt;someRule&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;typescriptLanguage&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createRule&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;options: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;option: &lt;/span&gt;&lt;span&gt;z&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;setup&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;flint.config.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { defineConfig, ts } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;flint&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { someRule } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;./src/rules/someRule.ts&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;defineConfig&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;use: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;files: ts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;files&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;rules: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;someRule&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;option: &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Hooray!&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As a result, Flint’s configurations are &lt;em&gt;fully typed&lt;/em&gt;.
Users receive IntelliSense as they type plugin rules, and all those settings can be type checked.
Config values can additionally be verified at runtime by the schema validation library.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;typed-plugin-settings&quot;&gt;Typed Plugin Settings&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;An even less type-safe part of many current linters’ config systems is the &lt;a href=&quot;https://eslint.org/docs/latest/use/configure/configuration-files#configuring-shared-settings&quot;&gt;shared &lt;code dir=&quot;auto&quot;&gt;settings&lt;/code&gt; object&lt;/a&gt;.
You can put whatever you want in there, and any plugin may read from it.&lt;/p&gt;
&lt;p&gt;In theory, cross-plugin shared settings can be used for related plugins, while plugin-specific settings are by convention namespaced under their name.
In practice, there are approximately zero plugins in common use that share settings with each other.&lt;/p&gt;
&lt;p&gt;Flint will also allow plugins to define their own settings with Standard Schema types.
They will be type-safe and validated similarly to plugin rules.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;typed-configuration-files&quot;&gt;Typed Configuration Files&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint’s hypothesis for configuration files is that it’s possible to have a full JavaScript configuration system without confusing users over subtle edge cases.
Flint’s configs will be fully type-safe (including lint rules and their options) and will support workspace configurations.
Parsing, processing, and other edge case hazards will be handled for users behind-the-scenes.&lt;/p&gt;
&lt;aside aria-label=&quot;Tip&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Tip&lt;/p&gt;&lt;div&gt;&lt;p&gt;See more details on this point in &lt;a href=&quot;https://flint.fyi/blog/introducing-flint#streamlined-rich-configuration&quot;&gt;Introducing Flint &gt; Streamlined Rich Configuration&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;inline-snapshot-unit-tests&quot;&gt;Inline Snapshot Unit Tests&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://eslint.org/docs/latest/integrate/nodejs-api#ruletester&quot;&gt;ESLint’s &lt;code dir=&quot;auto&quot;&gt;RuleTester&lt;/code&gt;&lt;/a&gt; (and &lt;a href=&quot;https://typescript-eslint.io/packages/rule-tester&quot;&gt;typescript-eslint’s &lt;code dir=&quot;auto&quot;&gt;RuleTester&lt;/code&gt; extension&lt;/a&gt;) provide APIs for clear, succinct descriptions of many isolated test cases at once.
They’re a step forward from the old &lt;a href=&quot;https://palantir.github.io/tslint/develop/testing-rules&quot;&gt;TSLint &lt;code dir=&quot;auto&quot;&gt;*.ts.lint&lt;/code&gt; test files&lt;/a&gt; that put all test cases into one big file namespace.&lt;/p&gt;
&lt;p&gt;However, they do come with downsides around their &lt;code dir=&quot;auto&quot;&gt;errors&lt;/code&gt; array format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It doesn’t show the full error message, just the data used to create it
&lt;ul&gt;
&lt;li&gt;Not managing long messages is nice, but text formatting issues can more easily sneak in&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Specifying location data as 0-4 of &lt;code dir=&quot;auto&quot;&gt;column&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;endColumn&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;line&lt;/code&gt;, and/or &lt;code dir=&quot;auto&quot;&gt;endLine&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Adding new cases and updating tests for rule changes is cumbersome&lt;/li&gt;
&lt;li&gt;Tests tend to be inconsistent about how much location data they include&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint will provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code dir=&quot;auto&quot;&gt;RuleTester&lt;/code&gt; equivalent that defines rule reports in an inline string snapshot&lt;/li&gt;
&lt;li&gt;First-party plugins for at least Vitest that auto-fix report snapshots to match the current rule reports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s an example of Flint’s &lt;code dir=&quot;auto&quot;&gt;RuleTester&lt;/code&gt; in practice:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;forInArrays.test.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; rule &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;./forInArrays.ts&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { ruleTester } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;./ruleTester.ts&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;ruleTester&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;describe&lt;/span&gt;&lt;span&gt;(rule, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;invalid: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;code: &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;declare const array: string[];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for (const i in array) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;snapshot: &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;declare const array: string[];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for (const i in array) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;For-in loops over arrays have surprising behavior that often leads to bugs.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;valid: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;declare const array: string[];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for (const i of array) {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;ecosystem&quot;&gt;Ecosystem&lt;/h2&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Standardizing users and plugins around Flint, while still encouraging userland experimentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;&lt;h3 id=&quot;shared-glossary&quot;&gt;Shared Glossary&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Many important linting terms have inconsistent usage or even definitions in the wild today.
For example, &lt;em&gt;“stylistic”&lt;/em&gt; can alternately refer to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/docs/latest/use/core-concepts/glossary#stylistic-rule&quot;&gt;Stylistic (Rule)&lt;/a&gt;: The category of lint rules that enforce formatting, naming conventions, or consistent usage of equivalent syntaxes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.style&quot;&gt;ESLint Stylistic&lt;/a&gt;: The plugin that ESLint’s formatting rules were migrated to, along with some non-formatting stylistic rules&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typescript-eslint.io/users/configs#stylistic&quot;&gt;typescript-eslint’s stylistic shared configs&lt;/a&gt;, which enforce consistent usage of equivalent syntaxes, as well as general TypeScript best practices that don’t impact program logic&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other ambiguous terms include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“Config”&lt;/em&gt;: a shared config, or a configuration file?&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Format”&lt;/em&gt;: formatting rules, or a formatter like Prettier, or code to prints ESLint reports?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is hard to keep straight even for people who work on linters.
Now imagine how confusing this all is for someone new to linting, and/or who doesn’t care much about their linter.&lt;/p&gt;
&lt;p&gt;Flint continues the &lt;a href=&quot;https://eslint.org/docs/latest/use/core-concepts/glossary&quot;&gt;ESLint Glossary&lt;/a&gt; work by defining single recommended terms for all the shared linting concepts.
You can find the Flint glossary on &lt;a href=&quot;https://flint.fyi/glossary&quot;&gt;Glossary&lt;/a&gt;.
It includes definitions for common linting terms as well as what other common linters use in comparison.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;common-core-rules&quot;&gt;Common Core Rules&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint’s approach for plugins is that all rules which apply to a super-majority of users of the linter should be built in the core project.
In doing so, the plugins both become more easily discoverable and will have a much more consistent look and feel for users.&lt;/p&gt;
&lt;p&gt;To support that larger effort, the Flint project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Establishes three tiers of project plugins:
&lt;ul&gt;
&lt;li&gt;“Core”: Plugins applicable to any project using their language (JavaScript/TypeScript, JSON, Markdown, YAML)&lt;/li&gt;
&lt;li&gt;“Focused”: Plugins for larger projects or styles that are applicable to many (but not all) likely Flint users&lt;/li&gt;
&lt;li&gt;“Incubator”: Area-specific plugins that should eventually exist under community governance&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Keeps a list of over 1,000 popular lint rules for reference, with rules categorized into Flint’s plugins&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s hypothesis for plugins is that by taking that comprehensive, holistic approach, users of Flint will be able to easily turn on more comprehensive, powerful linting by default - without needing to deep dive into the plugin ecosystem.
You can find the full list of plugins and rules in &lt;a href=&quot;https://flint.fyi/rules&quot;&gt;Rules&lt;/a&gt;.&lt;/p&gt;
&lt;aside aria-label=&quot;Tip&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Tip&lt;/p&gt;&lt;div&gt;&lt;p&gt;See more details on this point in &lt;a href=&quot;https://flint.fyi/blog/introducing-flint#thorough-provided-plugins&quot;&gt;Introducing Flint &gt; Thorough Provided Plugins&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;community-organization&quot;&gt;Community Organization&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/eslint-community&quot;&gt;ESLint Community organization&lt;/a&gt; is wonderful.
It serves a great need for housing high-applicability, high-value community projects that are not able to be part of ESLint core.
It’s a kind of “next step” for finding plugins outside of ESLint core — not quite “first party”, and not an external “third party”.&lt;/p&gt;
&lt;p&gt;Flint will lean into having an equivalent community organization.
That organization would have guidelines for inclusion, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Actively supporting new core linter minor versions soon after release&lt;/li&gt;
&lt;li&gt;Adherence to the shared linting glossary&lt;/li&gt;
&lt;li&gt;Documenting all configs, rules, and rule options&lt;/li&gt;
&lt;li&gt;Timely (re-)triaging of issues and pull requests&lt;/li&gt;
&lt;li&gt;Numerous consuming projects and weekly downloads&lt;/li&gt;
&lt;li&gt;Not being specific to any one userland metaframework&lt;/li&gt;
&lt;li&gt;Providing metadata alongside the &lt;code dir=&quot;auto&quot;&gt;package.json&lt;/code&gt; such as:
&lt;ul&gt;
&lt;li&gt;Names of any dependencies the plugin is directly for (e.g.
&lt;code dir=&quot;auto&quot;&gt;&quot;lodash&quot;&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;&quot;react&quot;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Text of when to use the plugin and each of its configs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of Flint’s “incubator” plugins are intended to eventually grow into those community projects.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;plugin-registry&quot;&gt;Plugin Registry&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;A linter’s ecosystem will always include a fair share of third-party plugins.
Finding the right third-party linter plugins for a project today is a pain.
ESLint does not yet have a centralized listing or one canonical approach users should take.
Power users of ESLint often follow a strategy like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Search &lt;a href=&quot;https://github.com/dustinspecker/awesome-eslint&quot;&gt;dustinspecker/awesome-eslint&lt;/a&gt; for plugins that seem relevant to the project&lt;/li&gt;
&lt;li&gt;For each dependency the project relies upon, search online for “eslint plugin” and that dependency name&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s a slow, unreliable process.
Determining which plugins are popular or still actively maintained is time-consuming.&lt;/p&gt;
&lt;p&gt;The Flint project will create a centralized plugin registry of popular userland plugins.
It will have similar guidelines for inclusion as the community organization, but with more lenient numbers, and allowing framework-specific plugins.
The registry will automatically update plugin metadata such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How recently the plugin was updated&lt;/li&gt;
&lt;li&gt;How many open issues exist that haven’t been interacted with by a maintainer&lt;/li&gt;
&lt;li&gt;The latest version of the linter that the plugin formally supports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Plugins that get too out-of-date on any of those metrics will be marked as such in the UI.
That will allow users to filter and search for plugins that are, say, actively maintained and support the latest version of the linter.&lt;/p&gt;
&lt;p&gt;The registry will be exposed to users in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API: allowing tooling to be built using known plugin metadata, such as…&lt;/li&gt;
&lt;li&gt;Website: allowing users to search on that metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Essentially, this will be a tailored &lt;em&gt;npm for linter plugins&lt;/em&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;config-initializer&quot;&gt;Config Initializer&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Every mainstream linter comes with some kind of configuration file initialization CLI: &lt;a href=&quot;https://eslint.org/docs/latest/use/getting-started#quick-start&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;@eslint/config&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://biomejs.dev/guides/getting-started/#configuration&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;biome init&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://oxc.rs/docs/guide/usage/linter/cli.html#basic-configuration&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;oxlint --init&lt;/code&gt;&lt;/a&gt;, etc.
Good!
Initialization CLIs help users get started quickly and with confidence their configuration is correct.&lt;/p&gt;
&lt;p&gt;Flint will build on these existing initializers by using plugin data from the centralized plugin registry to make the setup experience dynamic.
When run in a project with existing dependencies, it will offer to add the plugins for those dependencies into the created configuration.
It will also offer the user an input to provide dependency names they want to search on plugins for.&lt;/p&gt;
&lt;p&gt;It will use a templating system like &lt;a href=&quot;https://www.create.bingo/engines/stratum/about&quot;&gt;Bingo’s Stratum&lt;/a&gt; so plugins can define how they add to a config file.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;compatibility-layers&quot;&gt;Compatibility Layers&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Although Flint is building in most popular existing lint rules into its core project, many users have their own custom ESLint plugins and rules.
Flint will need to provide a compatibility layer that will allow you to use those plugins and rules natively via a Flint configuration file.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://eslint.org/blog/2024/05/eslint-compatibility-utilities&quot;&gt;ESLint’s compatibility utilities&lt;/a&gt; and &lt;a href=&quot;https://github.com/typescript-eslint/eslint-plugin-tslint&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;eslint-plugin-tslint&lt;/code&gt;&lt;/a&gt; are good references of prior art for compatibility layers.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;configuration-migration&quot;&gt;Configuration Migration&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint will also provide and recommend using an automated migrator that converts configs in other linters to their closest canonical equivalent in Flint.&lt;/p&gt;
&lt;p&gt;ESLint configurations in particular tend to be more complex than other linters’ because ESLint requires configuring edge cases such as parser and plugin options.
However, we believe most users configure ESLint in relatively common, straightforward ways.
The Flint configuration migrator will create “best effort” configurations that capture the perceived &lt;em&gt;intent&lt;/em&gt; of existing configurations.&lt;/p&gt;
&lt;p&gt;Flint’s configuration migrator will also provide flags for whether to adopt practices recommended by the new linter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding any plugins from the &lt;a href=&quot;#plugin-registry&quot;&gt;plugin registry&lt;/a&gt; relevant to existing project dependencies&lt;/li&gt;
&lt;li&gt;Enabling the linter’s gradual onboardings system for rules previously set to warn&lt;/li&gt;
&lt;li&gt;If formatting rules were used, remove them and instead &lt;a href=&quot;#formatting-coordination&quot;&gt;coordinate a formatter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using the recommended configs from the linter and any enabled plugins&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those flags will allow the migration tool to be used as more than just a single-shot utility.
The migrator will also help users migrate to best practices and more powerful linter configurations.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://eslint.org/docs/latest/use/configure/migration-guide#migrate-your-config-file&quot;&gt;ESLint’s configuration migrator&lt;/a&gt; and &lt;a href=&quot;https://github.com/typescript-eslint/tslint-to-eslint-config&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;tslint-to-eslint-config&lt;/code&gt;&lt;/a&gt; are a good references of prior art for migration tooling.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;As of January 2026, Flint is still an early-stage prototype.
Many but not all of the features in this post have not yet been built.&lt;/p&gt;
&lt;p&gt;If you’re interested in helping build out a new experimental linter, we’d love to have you join us.
At the very least, see &lt;a href=&quot;https://flint.fyi/about&quot;&gt;About&lt;/a&gt; for how to get started using Flint as a user.
Trying out the project and telling us about your experience on the &lt;a href=&quot;https://flint.fyi/discord&quot;&gt;Flint Discord&lt;/a&gt; would be immensely helpful.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/flint-fyi/flint/issues&quot;&gt;GitHub issue tracker&lt;/a&gt; is where you can find our list of upcoming work.
See our &lt;a href=&quot;https://github.com/flint-fyi/flint/blob/main/.github/CONTRIBUTING.md&quot;&gt;Contributing guide&lt;/a&gt; for how to find issues that you can get started on.
Feel free to ask for help if you’re new and unsure.
We’re happy to assist you.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;supporting-flint-financially&quot;&gt;Supporting Flint Financially&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint can receive donations on its &lt;a href=&quot;https://opencollective.com/flintfyi&quot;&gt;Open Collective&lt;/a&gt;.
Your financial support will allow us to pay our volunteer contributors and maintainers to tackle more Flint work.
As thanks, we’ll put you under a sponsors list on the &lt;a href=&quot;https://flint.fyi/&quot;&gt;flint.fyi homepage&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The points in this post are reframed equivalents to the original thought experiments by Josh Goldberg:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshuakgoldberg.com/blog/hybrid-linters-the-best-of-both-worlds&quot;&gt;Hybrid Linters: The Best of Both Worlds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshuakgoldberg.com/blog/if-i-wrote-a-linter-part-1-architecture&quot;&gt;If I Wrote a Linter, Part 1: Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshuakgoldberg.com/blog/if-i-wrote-a-linter-part-2-developer-experience&quot;&gt;If I Wrote a Linter, Part 2: Developer Experience&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshuakgoldberg.com/blog/if-i-wrote-a-linter-part-3-ecosystem&quot;&gt;If I Wrote a Linter, Part 3: Ecosystem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshuakgoldberg.com/blog/if-i-wrote-a-linter-part-4-summary&quot;&gt;If I Wrote a Linter, Part 4: Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>Introducing Flint</title><link>https://flint.fyi/blog/introducing-flint/</link><guid isPermaLink="true">https://flint.fyi/blog/introducing-flint/</guid><description>ESLint has been the leading web ecosystem linter for a decade. Its dominance is being challenged by new native speed linters such as Biome and Oxlint that implement blazing fast linting using native speed languages. Even TypeScript&apos;s source is being ported from TypeScript to Go. Yet, this Flint project -a new, experimental linter- is implemented in TypeScript rather than Go or Rust. Why does Flint exist when there are so many other linters already, and why is it implemented the way it is?

</description><pubDate>Tue, 30 Dec 2025 14:59:23 GMT</pubDate><content:encoded>&lt;p&gt;ESLint has been the leading web ecosystem linter for a decade.
Its dominance is being challenged by new native speed linters such as Biome and Oxlint that implement blazing fast linting using native speed languages.
Even TypeScript’s source is being ported from TypeScript to Go.
Yet, this Flint project -a new, experimental linter- is implemented in TypeScript rather than Go or Rust.&lt;/p&gt;
&lt;p&gt;Why does Flint exist when there are so many other linters already, and why is it implemented the way it is?&lt;/p&gt;
&lt;p&gt;Trust us: Flint serves a real purpose, and we’re excited to explain it.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-great-flint-experiment&quot;&gt;The Great Flint Experiment&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Flint is an experimental linter made to validate several hypotheses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#hybrid-linting&quot;&gt;Hybrid linting&lt;/a&gt;&lt;/strong&gt;: optimizing for approachability while still delivering high-speed performance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#streamlined-rich-configuration&quot;&gt;Streamlined rich configuration&lt;/a&gt;&lt;/strong&gt;: finding a dynamic JS/TS config system that doesn’t confuse users&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#thorough-provided-plugins&quot;&gt;Thorough documentation and plugins&lt;/a&gt;&lt;/strong&gt;: standardizing common user needs in the core project&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#tooling-coordination&quot;&gt;Tooling coordination&lt;/a&gt;&lt;/strong&gt;: saving user CI complexity and repeat work by coordinating and deduplicating tasks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of those hypotheses is a separate bet that we believe will show the best way for a modern linter to be positioned.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;hybrid-linting&quot;&gt;Hybrid Linting&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint is a &lt;em&gt;hybrid linter&lt;/em&gt;: its core is written in TypeScript, but language-specific plugins are free to use native-speed linting.
Hybrid linting is an intentional architecture choice meant to bring the best of both worlds from the two other common linter architectures in use today.&lt;/p&gt;
&lt;p&gt;To recap, most other linters fall into either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pure JavaScript (i.e. &lt;a href=&quot;https://eslint.org&quot;&gt;ESLint&lt;/a&gt;): written wholly in JavaScript and/or TypeScript, optimizing for developer approachability&lt;/li&gt;
&lt;li&gt;Native Speed (e.g. &lt;a href=&quot;https://biomejs.dev&quot;&gt;Biome&lt;/a&gt;, &lt;a href=&quot;https://docs.deno.com/runtime/reference/cli/lint&quot;&gt;deno lint&lt;/a&gt;, &lt;a href=&quot;https://oxc.rs/docs/guide/usage/linter&quot;&gt;Oxlint&lt;/a&gt;): written in native speed languages such as Go or Rust, optimizing for performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pure JavaScript linters’ approachability comes with big benefits for onboarding developers to become linting and static analysis power users.
The downside of JS/TS speed linters is their performance: they slow down tremendously when running on many thousands of files.&lt;/p&gt;
&lt;p&gt;Native speed linters are able to optimize for performance and run many tens of times faster than traditional pure JavaScript linters.
However, most web developers only have time to learn JavaScript and/or TypeScript.
Contributing to linters and lint rules written in other languages is much less approachable for them.&lt;/p&gt;
&lt;p&gt;With Flint, we’re writing a new TypeScript linter core with the following performance optimizations for significant speed improvements over traditional JavaScript linters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Although Flint’s core and lint rules are in TypeScript, it will delegate to native speed parsing and type checking (e.g. typescript-go) — which are the most common performance bottlenecks for linters&lt;/li&gt;
&lt;li&gt;Flint’s caching recognizes cross-file dependencies, allowing it to reuse cached results from unchanged files between runs&lt;/li&gt;
&lt;li&gt;Adopting more modern techniques such as &lt;a href=&quot;https://oxc.rs/docs/guide/usage/linter/js-plugins#why-is-the-alternative-api-faster&quot;&gt;Oxlint’s &lt;code dir=&quot;auto&quot;&gt;createOnce&lt;/code&gt; API&lt;/a&gt; will yield further memory and time improvements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s hypothesis for performance is that by adopting those techniques, we can have the approachability of a traditional JavaScript linter with most of the performance of a native speed linter.&lt;/p&gt;
&lt;aside aria-label=&quot;Note&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Note&lt;/p&gt;&lt;div&gt;&lt;p&gt;See &lt;a href=&quot;https://www.joshuakgoldberg.com/blog/hybrid-linters-the-best-of-both-worlds&quot;&gt;Hybrid Linters: The Best of Both Worlds&lt;/a&gt; for more details on the reasoning, benefits, and drawbacks of hybrid linters.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;streamlined-rich-configuration&quot;&gt;Streamlined Rich Configuration&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Most linters today fall into two classifications of linter configs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct JSON (&lt;a href=&quot;https://biomejs.dev/linter/#configure-the-linter&quot;&gt;Biome&lt;/a&gt;, &lt;a href=&quot;https://docs.deno.com/runtime/fundamentals/configuration/#linting&quot;&gt;Deno&lt;/a&gt;, &lt;a href=&quot;https://oxc.rs/docs/guide/usage/linter/config.html&quot;&gt;Oxlint&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Full JavaScript (ESLint: &lt;a href=&quot;https://eslint.org/docs/latest/use/configure/configuration-files-deprecated&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;.eslintrc.js&lt;/code&gt; (deprecated)&lt;/a&gt;, &lt;a href=&quot;https://eslint.org/docs/latest/use/configure/configuration-files&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;eslint.config.js&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Direct JSON is a nice and straightforward “walled garden” that shines in small projects.
But it tends to fall apart at scale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON doesn’t benefit from full TypeScript-style types, even with editor extensions&lt;/li&gt;
&lt;li&gt;Not being able to use native ESM imports means adding plugin support introduces a new loader system for users to learn&lt;/li&gt;
&lt;li&gt;Similarly, composing or extending configs together adds additional new complexity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Full JavaScript configurations such as ESLint’s bring much more power by leaning into native JavaScript semantics.
They can receive TypeScript types and even be written in TypeScript.
Native ESM exports and imports allow them to compose plugins and each other.&lt;/p&gt;
&lt;p&gt;However, many users are wary of JavaScript configurations because of bad experiences working with ESLint’s current “flat config” approach.
Flat config leaned directly into being “just” JavaScript, but contains many edge cases that have tripped up recent adopters.
ESLint’s configs also include concepts such as parsers and processors that add complexity and more edge case hazards.&lt;/p&gt;
&lt;p&gt;Flint’s hypothesis for configuration files is that it’s possible to have a full JavaScript configuration system without confusing users over subtle edge cases.
Flint’s configs will be fully type-safe -including lint rules and their options- and will support workspace configurations.
Parsing, processing, and other edge case hazards will be handled for users behind-the-scenes.&lt;/p&gt;
&lt;aside aria-label=&quot;Note&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Note&lt;/p&gt;&lt;div&gt;&lt;p&gt;See &lt;a href=&quot;https://flint.fyi/configuration&quot;&gt;Configuration&lt;/a&gt; for documentation explaining the Flint config system.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;thorough-provided-plugins&quot;&gt;Thorough Provided Plugins&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Other mainstream linters today only build a limited subset of lint rules into their core projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ESLint: only bundles a limited set of rules specifically for JavaScript; plugins such as for regular expressions or TypeScript support are separate projects&lt;/li&gt;
&lt;li&gt;Biome, Oxlint, etc.: bundle many more common rules into their projects, but have not holistically looked through the full ESLint ecosystem for reference&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ESLint’s “lean core” approach is great for encouraging ecosystem experimentation of new rules.
But once a rule is known to be stable and popular, keeping it out of the core project makes it less discoverable for users.&lt;/p&gt;
&lt;p&gt;The core rules bundling from linters like Biome and Oxlint is a step in the right direction, but in our opinion doesn’t go far enough:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Their JSON-based configuration systems make it difficult to explicitly determine which categories of rules are enabled&lt;/li&gt;
&lt;li&gt;Their rules still aren’t a full representation of all the various ecosystem rules that ESLint users have created&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s approach for plugins is that all rules which apply to a super-majority of users of the linter should be built in the core project.
By being created as part of the core project, the plugins both become more easily discoverable and will have a much more consistent look and feel for users.&lt;/p&gt;
&lt;p&gt;To fully support that larger effort, the Flint project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Establishes three tiers of project plugins:
&lt;ul&gt;
&lt;li&gt;“Core”: Plugins applicable to any project using their language (JavaScript/TypeScript, JSON, Markdown, YAML)&lt;/li&gt;
&lt;li&gt;“Focused”: Plugins for large areas of projects or code styles that are applicable to many, but not all, likely Flint users&lt;/li&gt;
&lt;li&gt;“Incubator”: Area-specific plugins that should exist under community governance, but don’t yet have that dedicated team&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Keeps a list of over 1,000 popular lint rules for reference, with rules that will be implemented categorized into Flint’s plugins&lt;/li&gt;
&lt;li&gt;Maintains a shared glossary for terms to be standardized across those plugins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s hypothesis for plugins is that by taking that comprehensive, holistic approach, users of Flint will be able to easily turn on more comprehensive, powerful linting by default - without needing to deep dive into the plugin ecosystem.&lt;/p&gt;
&lt;aside aria-label=&quot;Tip&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Tip&lt;/p&gt;&lt;div&gt;&lt;p&gt;For more information on Flint’s plugins, see:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flint.fyi/glossary&quot;&gt;Glossary&lt;/a&gt;: for the common linting terms as used by Flint, and compared to other linters&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flint.fyi/rules&quot;&gt;Rules&lt;/a&gt;: to see the provided plugins and rules to be (or not to be) implemented in them&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h3 id=&quot;tooling-coordination&quot;&gt;Tooling Coordination&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Modern web projects are able to use a plethora of tools: formatters, a variety of linters, type-checkers, and more.
Each of those tools often ends up being either its own workflow in CI and/or a step in a larger CI job.
Repositories have to choose: how much tooling power do they want, at the cost of CI time and configuration complexity?&lt;/p&gt;
&lt;p&gt;Modern linters such as Biome’s and Oxlint have proven there is user benefit in integrating multiple tools for users.
Flint aims to reduce complexity and user pain in three ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flint’s APIs allow for project-aware lint rules that can take on complex tasks like import cycle analysis and unused code detection&lt;/li&gt;
&lt;li&gt;Flint coordinates a formatter (&lt;a href=&quot;https://prettier.io&quot;&gt;Prettier&lt;/a&gt;) out-of-the-box, running on all files being linted&lt;/li&gt;
&lt;li&gt;Flint allows languages to surface “diagnostics” such as TypeScript’s type errors as part of linting as well&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flint’s hypothesis is that by providing one centralized place to coordinate all those tasks, users’ repositories will become simpler and benefit from faster and less complex CI workflows.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-flint-project&quot;&gt;The Flint Project&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The goal of the Flint project is to &lt;em&gt;test its hypotheses&lt;/em&gt;.
Flint is run by a set of independent volunteer maintainers as a fully open source project.
We are not associated with any one company, and not pressured by funding to achieve any level of adoption in industry.&lt;/p&gt;
&lt;p&gt;The best case scenario would be that all of Flint’s hypotheses would be shown to be correct.
As in, Flint’s choices do lead to a linter that is fast by default, straightforward to configure, and useful for users.
In that case we’ll transition Flint to a full open source project to stand alongside other web linters.&lt;/p&gt;
&lt;p&gt;Another success case would be that some or all of the hypothesis are proven wrong.
In that case we’ll feel more confident that traditional linters such as ESLint and/or native speed linters such as Biome and Oxlint are the way to go.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;current-status&quot;&gt;Current Status&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint is very early stage.
Many features have not yet been implemented.&lt;/p&gt;
&lt;p&gt;Don’t expect Flint to be ready to alpha test for several months from now, at the earliest.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;getting-involved&quot;&gt;Getting Involved&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;If you’re interested in helping build out a new experimental linter, we’d love to have you join us.
At the very least, see &lt;a href=&quot;https://flint.fyi/about&quot;&gt;About&lt;/a&gt; for how to get started using Flint as a user.
Trying out the project and telling us about your experience on the &lt;a href=&quot;https://flint.fyi/discord&quot;&gt;Flint Discord&lt;/a&gt; would be immensely helpful.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/flint-fyi/flint/issues&quot;&gt;GitHub issue tracker&lt;/a&gt; is where you can find our list of upcoming work.
See our &lt;a href=&quot;https://github.com/flint-fyi/flint/blob/main/.github/CONTRIBUTING.md&quot;&gt;Contributing guide&lt;/a&gt; for how to find issues that you can get started on.
Feel free to ask for help if you’re new and unsure.
We’re happy to assist you.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;supporting-flint-financially&quot;&gt;Supporting Flint Financially&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Flint can receive donations on its &lt;a href=&quot;https://opencollective.com/flintfyi&quot;&gt;Open Collective&lt;/a&gt;.
Your financial support will allow us to pay our volunteer contributors and maintainers to tackle more Flint work.
As thanks, we’ll put you under a sponsors list on the &lt;a href=&quot;https://flint.fyi/&quot;&gt;flint.fyi homepage&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;See &lt;a href=&quot;https://flint.fyi/blog/what-flint-does-differently&quot;&gt;What Flint Does Differently&lt;/a&gt; for a full list of all the changes Flint makes to the linter status quo.&lt;/p&gt;</content:encoded></item></channel></rss>