Skip to content

Commit

Permalink
feat(plugins): add plugin for xo config (#621)
Browse files Browse the repository at this point in the history
* feat(plugins): add plugin for xo config

Adds a plugin for [xo](https://github.com/xojs/xo#config). Essentially its an opinionated wrapper
around eslint with a bunch of bundled rules and plugins, and the config object is just the eslint
config object with some extra options. So to keep it consistent with the eslint plugin and avoid
duplication I've just used the eslint helper to parse out any additional eslint plugins that have
been added in the xo config.

* Add xo bin

---------

Co-authored-by: Lars Kappert <lars@webpro.nl>
  • Loading branch information
bbeesley and webpro committed May 7, 2024
1 parent 79cf631 commit 96f91df
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 0 deletions.
9 changes: 9 additions & 0 deletions packages/knip/fixtures/plugins/xo/.xo-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
space: true,
prettier: true,
plugins: ['unused-imports'],
parserOptions: {emitDecoratorMetadata: true},
rules: {
'func-names': ['error', 'always'],
},
};
Empty file.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions packages/knip/fixtures/plugins/xo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@fixtures/xo",
"scripts": {
"test": "xo"
},
"devDependencies": {
"xo": "^0.24.0"
},
"xo": {
"space": true,
"plugins": ["eslint-comments"]
}
}
8 changes: 8 additions & 0 deletions packages/knip/fixtures/plugins/xo/xo-config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const mySharedConfig = require('glob');

module.exports = {
...mySharedConfig,
rules: {
'func-names': 'off',
},
};
4 changes: 4 additions & 0 deletions packages/knip/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@
"title": "wrangler plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/wrangler/README.md)",
"$ref": "#/definitions/plugin"
},
"xo": {
"title": "xo plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/xo/README.md)",
"$ref": "#/definitions/plugin"
},
"yorkie": {
"title": "yorkie plugin configuration (https://github.com/webpro/knip/blob/main/src/plugins/yorkie/README.md)",
"$ref": "#/definitions/plugin"
Expand Down
1 change: 1 addition & 0 deletions packages/knip/src/ConfigurationValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const pluginsSchema = z.object({
webpack: pluginSchema,
wireit: pluginSchema,
wrangler: pluginSchema,
xo: pluginSchema,
yorkie: pluginSchema,
});

Expand Down
1 change: 1 addition & 0 deletions packages/knip/src/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,4 @@ export { default as webpack } from './webpack/index.js';
export { default as wireit } from './wireit/index.js';
export { default as wrangler } from './wrangler/index.js';
export { default as yorkie } from './yorkie/index.js';
export { default as xo } from './xo/index.js';
34 changes: 34 additions & 0 deletions packages/knip/src/plugins/xo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { EnablerPatterns } from '#p/types/config.js';
import type { IsPluginEnabled, Plugin, ResolveConfig } from '#p/types/plugins.js';
import { hasDependency } from '#p/util/plugin.js';
import { getDependenciesDeep } from '../eslint/helpers.js';
import type { XOConfig } from './types.js';

// link to xo docs: https://github.com/xojs/xo#config

const title = 'xo';

const enablers: EnablerPatterns = ['xo'];

const isEnabled: IsPluginEnabled = ({ dependencies, config }) =>
hasDependency(dependencies, enablers) || 'xo' in config;

const packageJsonPath = 'xo';
const config: string[] = ['{.,}xo-config.{js,cjs,json,}', 'package.json'];

const entry: string[] = ['{.,}xo-config.{js,cjs}'];

const resolveConfig: ResolveConfig<XOConfig> = async (config, options) => {
const dependencies = await getDependenciesDeep(config, options);
return [...dependencies];
};

export default {
title,
enablers,
isEnabled,
packageJsonPath,
entry,
config,
resolveConfig,
} satisfies Plugin;
13 changes: 13 additions & 0 deletions packages/knip/src/plugins/xo/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ESLintConfig } from '../eslint/types.js';

export type XOConfig = ESLintConfig & {
envs?: string[] | undefined;
globals?: string[] | undefined;
ignores?: string[] | undefined;
nodeVersion?: string | boolean | undefined;
prettier?: boolean | undefined;
printConfig?: string | undefined;
semicolon?: boolean | undefined;
space?: boolean | number | undefined;
webpack?: boolean | object | undefined;
};
26 changes: 26 additions & 0 deletions packages/knip/test/plugins/xo.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { test } from 'bun:test';
import assert from 'node:assert/strict';
import { main } from '../../src/index.js';
import { resolve } from '../../src/util/path.js';
import baseArguments from '../helpers/baseArguments.js';
import baseCounters from '../helpers/baseCounters.js';

const cwd = resolve('fixtures/plugins/xo');

test('Find dependencies with the xo plugin', async () => {
const { issues, counters } = await main({
...baseArguments,
cwd,
});

assert(issues.unlisted['.xo-config.js']['eslint-plugin-unused-imports']);
assert(issues.unlisted['xo-config.cjs']['glob']);
assert(issues.unlisted['package.json']['eslint-plugin-eslint-comments']);

assert.deepEqual(counters, {
...baseCounters,
processed: 2,
unlisted: 3,
total: 2,
});
});

0 comments on commit 96f91df

Please sign in to comment.