Support XO v1+#1819
Conversation
There was a problem hiding this comment.
Pull request overview
Adds XO v1+ (flat-config era) support to Knip’s XO plugin by expanding supported config filenames, distinguishing XO v0 vs v1+ behavior in tests/fixtures, and allowing ESLint config input extraction to be overridden for non-eslint.config.* flat configs.
Changes:
- Extend XO plugin config/entry globs to include
xo.config.{mjs,ts,cts,mts}and introduce XO-major-based flat/deprecated handling. - Add separate fixture + test coverage for XO v0 (
.xo-config.*/ deprecated config shape) vs XO v1+ (flatxo.config.*). - Update ESLint helper
getInputsto accept an optional “flat config override” flag (used by the XO plugin).
Reviewed changes
Copilot reviewed 10 out of 19 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/knip/src/plugins/xo/index.ts | Adds XO major-version detection and treats xo.config.* as flat-config inputs. |
| packages/knip/src/plugins/xo/types.ts | Broadens XO config typing to support both v0 deprecated configs and v1+ flat config items/arrays. |
| packages/knip/src/plugins/eslint/helpers.ts | Adds isFlatConfigOverride param to route non-eslint.config.* configs through flat/deprecated extraction. |
| packages/knip/test/plugins/xo.test.ts | Updates XO plugin test to assert unlisted deps from flat xo.config.{js,ts} fixtures. |
| packages/knip/test/plugins/xo-0.test.ts | Adds XO v0-specific test asserting deprecated .xo-config.* and package.json plugin resolution. |
| packages/knip/fixtures/plugins/xo/package.json | Updates fixture to XO ^3.0.2 and removes deprecated plugins field usage. |
| packages/knip/fixtures/plugins/xo/xo.config.js | Adds flat XO config file importing eslint-plugin-unused-imports (to be detected as unlisted). |
| packages/knip/fixtures/plugins/xo/xo.config.ts | Adds flat XO config file importing my-shared-config (to be detected as unlisted). |
| packages/knip/fixtures/plugins/xo/node_modules/my-shared-config/package.json | Adds dummy resolvable package for my-shared-config fixture import. |
| packages/knip/fixtures/plugins/xo/node_modules/my-shared-config/index.js | Provides the module content for my-shared-config. |
| packages/knip/fixtures/plugins/xo/node_modules/eslint-plugin-unused-imports/package.json | Adds dummy resolvable package for eslint-plugin-unused-imports fixture import. |
| packages/knip/fixtures/plugins/xo/node_modules/eslint-plugin-unused-imports/index.js | Provides the module content for eslint-plugin-unused-imports. |
| packages/knip/fixtures/plugins/xo-0/package.json | Adds XO v0 fixture manifest (XO ^0.60.0) with deprecated package.json config. |
| packages/knip/fixtures/plugins/xo-0/.xo-config.js | Adds XO v0 deprecated .xo-config.js fixture that references unused-imports. |
| packages/knip/fixtures/plugins/xo-0/xo.config.cjs | Adjusts XO v0 xo.config.cjs fixture to require my-shared-config. |
| packages/knip/fixtures/plugins/xo-0/node_modules/xo/package.json | Fixes dummy package name to xo for the XO v0 fixture environment. |
| packages/knip/fixtures/plugins/xo-0/node_modules/my-shared-config/package.json | Adds dummy resolvable package for the XO v0 fixture require. |
There was a problem hiding this comment.
renamed from packages/knip/fixtures/plugins/xo/package.json
| "plugins": [ | ||
| "eslint-comments" | ||
| ] |
There was a problem hiding this comment.
There was a problem hiding this comment.
Copied from packages/knip/fixtures/plugins/xo-0/xo.config.js and converted to flat config
There was a problem hiding this comment.
Copied from packages/knip/fixtures/plugins/xo-0/xo.config.ts and converted to flat config
| options: PluginOptions, | ||
| isFlatConfigOverride?: boolean | ||
| ): (Input | ConfigInput)[] => { | ||
| const { configFileName } = options; | ||
|
|
||
| if (extname(configFileName) === '.json' || !isFlatConfig(configFileName)) { | ||
| const isFlatConfigFile = | ||
| isFlatConfigOverride ?? (extname(configFileName) !== '.json' && isFlatConfig(configFileName)); | ||
|
|
||
| if (!isFlatConfigFile) { |
There was a problem hiding this comment.
This is a quick and dirty way to allow the XO plugin to determine whether the config is flat or deprecated. I didn’t spend much time on it, assuming that it would need to be discussed.
|
|
||
| const resolveConfig: ResolveConfig<XOConfig> = async (config, options) => { | ||
| const inputs = getInputs(config, options); | ||
| const xoVersion = options.manifest.getMajor('xo') ?? 3; |
There was a problem hiding this comment.
Falling back to the latest version to match behavior of the react email plugin
There was a problem hiding this comment.
Renamed from packages/knip/test/plugins/xo.test.ts
| assert(issues.unlisted['xo.config.js']['eslint-plugin-unused-imports']); | ||
| assert(issues.unlisted['xo.config.ts']['my-shared-config']); | ||
|
|
There was a problem hiding this comment.
-
eslint-plugin-unused-importschanges from unresolved to unlisted because it must be imported in flat config as opposed to referenced by string in deprecated config+ import unusedImports from 'eslint-plugin-unused-imports'; … - plugins: ['unused-imports'], + plugins: { + 'unused-imports': unusedImports, + }, …
-
Renamed
globtomy-shared-config -
Removed
package.jsonunresolved plugin check because XO v1+ only supports serializable values inpackage.json.xo, so there's nothing we can add topackage.json.xoto exercise Knip
|
Thanks for the PR! Would you mind if I add a commit and you can review that? I think we could simplify a bit here. |
|
Not at all! |
xo@1+ uses ESLint flat config: plugins are referenced via `import`, so they're already detected as entry-file imports. Resolve those configs from the AST (reusing the ESLint flat-config resolver) and skip loading them, gated on the installed xo major. xo@0 keeps the loaded eslintrc path. - Mirrors the ESLint plugin (isLoadConfig=false + resolveFromAST for flat) - Avoids spurious "Error loading xo.config.*" when a config spreads real plugins (executing them can throw, e.g. on an uninstalled peer) - Drops the getInputs override and the unused flat config type
|
There you go, let me know what you think. Imho it doesn't have to be all that perfect across each and every version of xo, as long as we grab entry points and dependencies properly. |
commit: |
|
Looks good to me |
|
🚀 This pull request is included in v6.22.0. See Release 6.22.0 for release notes. Using Knip in a commercial project? Please consider becoming a sponsor. |
Summary
configandentryto support XO v1+ config filesxofixture toxo-0and create newxofixture for XO v1+fixtures/plugins/xo-0/.xo-config.jstofixtures/plugins/xo/xo.config.jseslint-plugin-unused-importsbecause in eslint flat config, plugins can't be referenced by string, they must be importedfixtures/plugins/xo-0/xo.config.cjstofixtures/plugins/xo/xo.config.tsglobtomy-shared-configfor clarityXO config history
package.json,.xo-config.{js,cjs,json},xo.config.{js,cjs}package.json,xo.config.{js,cjs,mjs,ts,cts,mts}.xo-config.*package.json,xo.config.{js,mjs,ts,mts}xo.config.{cjs,cts}