Part of #18610.
Our intent is to move `definePlugin`, `defineRule`, and `eslintCompatPlugin` to a separate package `@oxlint/plugins` (plural to avoid confusion with naming convention for plugins `oxlint-plugin-xxx`).
So rename the current entry point which exports these functions from `oxlint/plugin` to `oxlint/plugins` (plural).
This is technically breaking (only for types), but custom plugins are experimental.
The ruletester/defineRule/definePlugin are re-exported but with a `@deprecated` tag which I think is a good enough trade off
I want to avoid users bringing in a ton of custom plugin code when doing `import { defineConfig } from 'oxlint'`
Rules' default options are serialized to JSON and then `JSON.parse`-ed again, to ensure they don't contain cyclic references.
In the process, `Infinity` was converted to `null` (because JSON can't encode `Infinity`). This broke one of `eslint-plugin-stylistic`'s rules, which has an option which defaults to `Infinity`.
Fix this by replacing `Infinity` with a placeholder string in `JSON.stringify` and then replacing it before `JSON.parse`.
Fixes#15631.
#16930 implemented options validation against `rule.meta.schema`, for the purpose of supporting default options added by schema. But it didn't actually do anything if validation failed.
Implement validation of options against schema, and pass any errors back to Rust to print.
ESLint has 2 different ways to define default options for a rule - `rule.meta.defaultOptions`, or `rule.meta.schema` containing a schema which defines default values.
We previously supported the former, but not the latter. This PR implements support for defining defaults via `rule.meta.schema`.
We compile the schema and apply it to options on JS side, using [`ajv`](https://www.npmjs.com/package/ajv), which is what ESLint uses. But this process only happens once before the start of linting, not once for every file, so the perf hit should be small.
This also prepares the way for validating options against the schema (#15631).
Small optimization to options merging. Treat rules which define `defaultOptions` as an empty array the same as those which provide no `defaultOptions` at all. This makes options merging take a faster path for these rules.
Closes#15630.
* #16170 added support for default options defined in the rule.
* #16215 added support for options defined in configs.
* #16217 implemented the logic for merging the 2 but only applied it in `RuleTester`.
Bring these elements together, and support merging default options from rule into options provided in config.
- Implements #14825
- Rebased #15822. Refactored. Pruned the slop. Tests passing.
### Big changes from the original approach
- [x] Options IDs are stored in their own arrays. This was laid out in
#16158. The original approach was to store `ruleId`-`optionId` pairs as
tuples in an array - several heap allocated objects and excessive
pointer indirection.
- [x] The rust code populates the options by calling a new JS callback
named `setupConfigs()`. I expect we would use this callback for more
plugin related data, including settings which are currently implemented
in a hacky way.
- [ ] Investigate a refactor to avoid requiring a mutable reference to
`ExternalPluginStore` everywhere.
<details>
<summary>
#### Smaller Changes
</summary>
- Removed the extra fixture ("working version"). There were no
meaningful changes compared to the first fixture. Probably slop.
</details>
---------
Co-authored-by: Peter Wagenet <peter@wagenet.us>
Co-authored-by: overlookmotel <theoverlookmotel@gmail.com>
A step towards #15630. Where a rule provides default options, pass them to `create` function as `context.options`.
We don't yet have full options support (#14825), so this is incomplete. Once user can provide options for rules in config, those options need to be merged with default options.
Initially, we should probably do that merging on JS side (borrowing ESLint's code), and then later on port it to Rust.