Fix an incompatibility with `eslint-plugin-jsdoc`. It relies on properties of `context` being values rather than getters:
https://github.com/gajus/eslint-plugin-jsdoc/blob/26276d428631a2625575607cba7875dab6797091/src/buildForbidRuleDefinition.js#L86-L103
When `options` property is a getter, this code throws an error because it attempts to define a property with both `value` and `get` in its descriptor.
This PR replaces the `id` and `options` getters with value properties.
The getters were there to prevent the `Context` object from being mutated by rule code, and allow the object to be frozen, as it is in ESLint. But each rule gets its own `Context` object, so if it chooses to mutate it, it only harms itself, and can't impact other rules/plugins. In ESLint, trying to alter the frozen `Context` object would be a hard error, so it's doubtful that any ESLint plugins do this anyway.
This is no real downside to this change for us, so we might as well make the change, and fix `eslint-plugin-jsdoc` and any other plugins which may depend on ESLint's behavior here.
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'`
Supporting JS plugins in LSP requires that different workspaces have a different value for `Context#cwd`.
As a first step, prevent accessing `cwd` property, or calling `getCwd` method in `createOnce`. Later on, we can make `cwd` a dynamic property.
Revert #15447. It's easy to allow `Context#id` to be accessed in `createOnce` when running rule in Oxlint, but not possible to do in ESLint compat mode with current API, because `id` isn't a property of the rule, so `defineRule` doesn't know it.
We could support it by making `definePlugin` compulsory for ESLint interop, and get it to set `id` property on `Context` objects properly.
But that's a bit tricky, so just disable access for now. It's probably not very useful anyway - a rule should know what its own name is!
Follow-on after #15424. Fix the snapshots on Windows. I missed one slash!
Also, convert paths wrapped in quotes e.g. `file path: '/path/to/oxc/apps/oxlint/test/fixtures/blah/files/foo.js'`.
I've had to hack one fixture (`createOnce`) to get diagnostics to be printed in same order on all platforms. Otherwise they get printed out of order on Windows: https://github.com/oxc-project/oxc/actions/runs/19180329507/job/54835252163?pr=15451#step:8:419.
Presumably this is because on Windows the file path `D:\...` is sorted after `Cannot access`, whereas on Mac/Linux, file path `/` is sorted before `Cannot access`. However, I'm unclear why the prefixes `before hook:`, `after hook:` etc aren't included in sorting. If they were, this problem wouldn't arise.
Previously we blocked accessing `context.id` (rule name) in `createOnce`. There's no need to be so restrictive, as it's a static value, and not file-specific. Relax this restriction.
When replacing absolute paths in fixture snapshots, replace paths anywhere in the output, rather than only in certain specified patterns.
Additionally, introduce `<fixtures>` and `<fixture>` replacements to shorten paths in snapshots.
```diff
- File path: <root>/apps/oxlint/test/fixtures/fixture_name/files/1.js
+ File path: <fixture>/files/1.js
- File path: <root>/apps/oxlint/test/fixtures
+ File path: <fixtures>
```
This allows removing the `relativePath` helper function from some test plugins, outputting paths (e.g. `cwd`) anywhere, and generally will avoid problems with snapshots being system-dependent, and dependent on directory layout of fixtures.
Also, amend ESLint `stdout` output in snapshots to align all rule names, to reduce churn in snapshots, and avoid mismatches between local and CI (presumably due to differences in terminal width).
```diff
- filename: <fixture>/files/1.js define-plugin-plugin/create-once
- filename: <fixture>/files/long_filename.js define-plugin-plugin/create-once
- filename: <fixture>/files/very_long_filename.js define-plugin-plugin/create-once
+ filename: <fixture>/files/1.js define-plugin-plugin/create-once
+ filename: <fixture>/files/long_filename.js define-plugin-plugin/create-once
+ filename: <fixture>/files/very_long_filename.js define-plugin-plugin/create-once
```
If rule is defined using `createOnce`, and it returns an empty visitor (`before` / `after` hooks only), then don't run the hooks - the rule is a no-op.
Reason this is important is forward-compatibility with an optimization we could make where we calculate on Rust side whether AST contains any nodes that rules act on, and if it doesn't, skip calling into JS entirely. In that case, the `before` hook wouldn't run on those files.
We can't emulate that behavior entirely, but we can at least avoid users creating rules which *only* contain a `before` hook, and then finding that when we apply that optimization later on, it stops behaving as expected.
i.e. we make the `before` hook never be called for a rule defined like this:
```js
export default {
createOnce(context) {
return {
before() {
if (content.filename.endsWith('.tsx') {
context.report({ message: 'No TSX!', node: context.sourceCode.ast });
}
},
};
},
};
```
Add `loc` to all AST nodes.
`loc` is computed lazily, as it's quite an expensive operation - because it requires searching the source text for line breaks and building a translation table.
We can consider making `loc` a "real" property once we have a faster translation table built on Rust side.
Add `range` field to AST nodes, using the support for `range` in raw transfer added in #14319.
Use `range` field rather than `start` + `end` in nodes passed to `context.report` and fixer methods - for closer alignment with ESLint.
Add support for ESLint's `SourceCode` API. At present the only method on `SourceCode` is `getText`. More methods will be added in further PRs to follow.