Closes#19746.
Add `oxlint-plugin-eslint` plugin which exports all ESLint's built-in rules as a JS plugin which can be used with Oxlint.
The code for rules is lazy-loaded on first use, so just using the plugin doesn't load the code for all the rules, only the ones which the user actually uses. However, the `meta` property of each rule is provided eagerly, so that `registerPlugin` in Oxlint can load the plugin without triggering the getters which lazy-load rule code.
All ESLint's rule code is bundled into this plugin package, so the package has no dependencies. This has a few advantages:
1. We control the version of ESLint which the rules are taken from.
2. Avoids "works on my machine" unreproducible bug reports due to differing ESLint versions.
3. Avoids relying on ESLint's `eslint/use-at-your-own-risk` export, which could change without warning.
At present, the plugin contains *all* ESLint's rules, including ones which are natively implemented in Oxlint.
We might choose to scale it back to include only the rules which Oxlint doesn't natively implement. But then we need to consider what happens when we implement more rules in future: Do they disappear from this package without warning? Would that be considered a breaking change? If it would, how long do we keep them in this package?
I propose that in the interests of getting this useful feature released without having to decide all these issues, we just go with it as is for now. JS plugins are not yet stable, so at present we can still make changes later on if we need to, without breaking any promises.
#18824 added `@oxlint/plugins` package. The files in `npm/oxlint-plugins` were generated by the build script `apps/oxlint/scripts/build.ts`.
Instead, populate `npm/oxlint-plugins` in the release CI workflow, just before the package is published.
Alternative to #18796. Part of #18610.
## Overview
Add `@oxlint/plugins` package.
`@oxlint/plugins` package has no dependency on `oxlint`, which solves the problem raised in https://github.com/oxc-project/oxc/pull/18796#discussion_r2751286894, and is also what we wanted in the end anyway. We don't actually want plugins packages to have to depend on `oxlint`.
## Differences from other Oxc packages
This package is different from all our other packages, in that it's intended to work not only with Oxlint's ecosystem, but also with ESLint's ecosystem.
`@oxlint/plugins` will be a *runtime* dependency of plugin packages that the community create, and they may want their plugin to be compatible with both Oxlint and ESLint - this package provides the `eslintCompatPlugin` function for exactly this purpose.
Our aim is to allow plugin authors to migrate from ESLint's `create` API to Oxlint's `createOnce` API with minimum friction, and without breaking changes for their users:
1. Their plugin should remain compatible with ESLint.
2. They do not need to alter the versions of NodeJS they support (no change to `engines` field in `package.json`).
3. They can continue to publish their plugin as a CommonJS package, if that's the format they currently use.
## Package composition
Due to these requirements, the make-up of `@oxlint/plugins` is different from our other packages:
### Dual Format
This package is in "dual package" format, with both ESM and CommonJS entry points.
### Older NodeJS versions support
This package supports NodeJS versions back to v12.22.0.
https://github.com/oxc-project/oxc/blob/9938dc476f8533b7011af03cdbac328b0d00d344/npm/oxlint-plugins/package.json#L40-L42
This matches `engines` field in all ESLint 8.x.x releases:
* 8.0.0: https://www.npmjs.com/package/eslint/v/8.0.0?activeTab=code
* 8.57.1: https://www.npmjs.com/package/eslint/v/8.57.1?activeTab=code
Therefore, `@oxlint/plugins` can be used by any plugin which supports ESLint 8 or later.
Note: Download counts for ESLint 8 are still roughly equal to ESLint 9, even though v9 was released 2 years ago.
#### Notes
* Changing `target` in TSDown to `"node12"` does not result in any changes to built files. See 3rd commit in this PR.
* `exports` field in `package.json` is supported (without experimental flag) from NodeJS v12.17.0 + v14.0.0.
* `.cjs` file extension supported from NodeJS v12.0.0.
## Building the package
This PR adds 2 extra builds to TSDown config, which generate the files for the package. `build.ts` script moves the files into `npm/oxlint-plugins` directory.
Later on, we'll move the logic for moving the files into the CI release workflow, so we don't need to check the generated build files into Git.
## `@oxlint/plugins-dev`
In #18610 we decided to also add an `@oxlint/plugins-dev` to contain `RuleTester`, so we can move that out of `oxlint` package. This PR *does not* add that package. I've skipped that for now as (a) it's trickier and (b) it's much less important.
#15921 added a debug build for Oxlint, and various PRs since have tweaked it. However, I now realize there's little point in generating *both* a release build and debug build.
Just create one build, and use env var `DEBUG` to control whether it has debug assertions included in it or not.
`pnpm run build` produces release build with no debug assertions, `pnpm run build-test` includes the asserts. I've verified that both do what they're meant to.
#15946 means we can now simplify the TSDown build config.
Previously we had to have 2 separate builds for `index.ts` and `cli.ts`, to avoid `assert*` functions ending up in a shared chunk, and not getting removed by minifier. Now that problem is solved, so we can switch to a single build with 2 entry points.
TSDown does create a small extra chunk for its `__toESM` and `__commonJSMin` functions, but I think that's fine.
Annoyingly it doesn't seem to be possible to tell TSDown to generate `.d.ts` files only for the `index.js` chunk, so have to delete this pointless files in build script.
The point of all this is that `RuleTester` needs to use a ton of code from `plugins.ts`, and we wouldn't want all that code duplicated in both `index` and `plugins` chunks (especially once we're bundling TS-ESlint's parser #15861). Now that code will be shared between the two entry points in a shared chunk, not duplicated.
Generate a debug build, in addition to the normal release build.
In the debug build, `DEBUG` global is defined as `true` and `assertIsNonNull` does a runtime assertion. In release build, `DEBUG === false` and minifier removes debug-only code.
Run the tests in debug mode.
Debug build is generated in a separate directory from `dist`, so is *not* included in NPM package.
Bundle the deserializer. Originally it wasn't bundled at my request, so that source maps wouldn't be required for debugging. But it's turning out that we have no problems in the deserializer - our problems are elsewhere!