Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
coverage
test/oxlint/fixtures

4 changes: 2 additions & 2 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
uses: actions/checkout@v2

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}

Expand All @@ -41,6 +41,6 @@ jobs:
run: npm run ci

- name: Code Coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

custom eslint rule for egg RTFM questions

Compatible with both **ESLint** and **[oxlint](https://oxc.rs/)** (oxlint JS plugins support).

[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![Test coverage][codecov-image]][codecov-url]
Expand All @@ -24,6 +26,8 @@ custom eslint rule for egg RTFM questions

## Usage

### With ESLint

```bash
npm i eslint-plugin-eggache --save
```
Expand Down Expand Up @@ -54,6 +58,35 @@ By default it enable all the recommended rules, if you want to custom, just conf
}
```

### With oxlint

This plugin is compatible with [oxlint](https://oxc.rs/) (requires oxlint with JavaScript plugin support).

```bash
npm i eslint-plugin-eggache --save-dev
```

Add the plugin to your oxlint configuration:

```json
{
"plugins": ["eggache"],
"rules": {
"eggache/no-only-tests": "warn",
"eggache/no-override-exports": "error",
"eggache/no-unexpected-plugin-keys": "error"
}
}
```

Or use the recommended config:

```json
{
"extends": ["plugin:eggache/recommended"]
}
```

## Rules

### no-override-exports
Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
'use strict';

module.exports = {
meta: {
name: 'eslint-plugin-eggache',
version: '2.0.0',
},
rules: {
'no-only-tests': require('./lib/rules/no-only-tests'),
'no-override-exports': require('./lib/rules/no-override-exports'),
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/no-only-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ const defaultOptions = {

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallow .only blocks in tests',
category: 'Possible Errors',
recommended: true,
url: 'https://github.com/eggjs/eslint-plugin-eggache#no-only-tests',
},
fixable: true,
fixable: 'code',
schema: [
{
type: 'object',
Expand Down
1 change: 1 addition & 0 deletions lib/rules/no-override-exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const utils = require('../utils');

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Disallow override exports',
category: 'Possible Errors',
Expand Down
1 change: 1 addition & 0 deletions lib/rules/no-unexpected-plugin-keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const VALID_KEYS = [ 'enable', 'package', 'path', 'env' ];

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Disallow unexpected plugin keys in config/plugin.*.js',
category: 'Possible Errors',
Expand Down
15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
{
"name": "eslint-plugin-eggache",
"version": "2.0.0",
"description": "custom eslint rule for egg RTFM issues",
"dependencies": {},
"description": "custom eslint rule for egg RTFM issues, compatible with ESLint and oxlint",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin",
"oxlint",
"eggjs",
"egg"
],
"devDependencies": {
"egg-bin": "^5",
"egg-ci": "^2",
"eslint": "^8",
"eslint-config-egg": "^12"
"eslint-config-egg": "^12",
"oxlint": "^1.22.0"
},
"engines": {
"node": ">=14.17.0"
},
"scripts": {
"lint": "eslint .",
"test": "egg-bin test",
"test:oxlint": "oxlint --version && echo 'Oxlint tests are in test/oxlint/ - see test/oxlint/README.md for manual testing instructions'",
"cov": "egg-bin cov",
"ci": "npm run lint && npm run cov"
},
Expand Down
9 changes: 9 additions & 0 deletions test/oxlint/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"jsPlugins": ["eslint-plugin-eggache"],
"rules": {
"eggache/no-only-tests": "warn",
"eggache/no-override-exports": "error",
"eggache/no-unexpected-plugin-keys": "error"
}
}
97 changes: 97 additions & 0 deletions test/oxlint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Oxlint Integration Tests

This directory contains tests and fixtures to verify that `eslint-plugin-eggache` is compatible with oxlint's JavaScript plugin system.

## Structure

- `fixtures/` - Test files that should trigger linting violations
- `.oxlintrc.json` - Oxlint configuration for testing the plugin
- `oxlint.test.js` - Automated tests to verify plugin structure and compatibility

## Running Tests

The automated tests verify:
1. Plugin exports the required metadata for oxlint (`meta.name`, `meta.version`)
2. All rules have proper structure (`meta.type`, `meta.docs`, `create` function)
3. Plugin is compatible with ES module imports (required by oxlint)
4. Test fixtures and configuration files exist

Run the tests with:
```bash
npm test
```

## Manual Testing with Oxlint

Since oxlint's JavaScript plugin support is experimental and under active development, manual testing may be needed.

### Prerequisites

```bash
npm install oxlint --save-dev
```

### Method 1: Using npm package

1. Publish or link the package:
```bash
npm link
```

2. In a test project, link the plugin:
```bash
npm link eslint-plugin-eggache
```

3. Create `.oxlintrc.json`:
```json
{
"jsPlugins": ["eslint-plugin-eggache"],
"rules": {
"eggache/no-only-tests": "warn",
"eggache/no-override-exports": "error",
"eggache/no-unexpected-plugin-keys": "error"
}
}
```

4. Run oxlint:
```bash
npx oxlint .
```

### Method 2: Using absolute path

Create `.oxlintrc.json` with absolute path to the plugin:
```json
{
"jsPlugins": ["/absolute/path/to/eslint-plugin-eggache/index.js"],
"rules": {
"eslint-plugin-eggache/no-only-tests": "warn",
"eslint-plugin-eggache/no-override-exports": "error",
"eslint-plugin-eggache/no-unexpected-plugin-keys": "error"
}
}
```

### Testing with Fixtures

Test the plugin with the provided fixtures:

```bash
# Test no-only-tests rule
npx oxlint test/oxlint/fixtures/no-only-tests.js

# Test no-override-exports rule
npx oxlint test/oxlint/fixtures/no-override-exports.js

# Test no-unexpected-plugin-keys rule
npx oxlint test/oxlint/fixtures/no-unexpected-plugin-keys.js
```

## Notes

- Oxlint's JavaScript plugin support is experimental and not subject to semver
- Plugin loading behavior may change in future oxlint versions
- The plugin structure follows ESLint conventions which oxlint aims to be compatible with
- See https://oxc.rs/blog/2025-10-09-oxlint-js-plugins.html for more information
10 changes: 10 additions & 0 deletions test/oxlint/fixtures/no-only-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file should trigger the no-only-tests rule
describe.only('test suite', function() {
it('test case', function() {
// test code
});
});

it.only('another test', function() {
// test code
});
8 changes: 8 additions & 0 deletions test/oxlint/fixtures/no-override-exports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file should trigger the no-override-exports rule
exports.view = {};

module.exports = appInfo => {
const config = {};
config.keys = '123456';
return config;
};
6 changes: 6 additions & 0 deletions test/oxlint/fixtures/no-unexpected-plugin-keys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// This file should trigger the no-unexpected-plugin-keys rule
exports.test = {
enable: true,
package: 'egg-test',
someConfig: 'should not be here',
};
86 changes: 86 additions & 0 deletions test/oxlint/oxlint.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use strict';

const assert = require('assert');
const path = require('path');
const fs = require('fs');

describe('oxlint integration tests', () => {
const pluginPath = path.join(__dirname, '../../index.js');
const fixturesDir = path.join(__dirname, 'fixtures');
const configPath = path.join(__dirname, '.oxlintrc.json');

it('should export plugin metadata required by oxlint', () => {
const plugin = require('../../index.js');

// Check plugin structure
assert(plugin, 'Plugin should export an object');
assert(plugin.meta, 'Plugin should have meta field');
assert(plugin.meta.name, 'Plugin meta should have name');
assert(plugin.meta.version, 'Plugin meta should have version');
assert.strictEqual(plugin.meta.name, 'eslint-plugin-eggache', 'Plugin name should be correct');

// Check rules structure
assert(plugin.rules, 'Plugin should export rules');
assert(plugin.rules['no-only-tests'], 'Plugin should have no-only-tests rule');
assert(plugin.rules['no-override-exports'], 'Plugin should have no-override-exports rule');
assert(plugin.rules['no-unexpected-plugin-keys'], 'Plugin should have no-unexpected-plugin-keys rule');

// Check each rule has proper structure for oxlint
Object.keys(plugin.rules).forEach(ruleName => {
const rule = plugin.rules[ruleName];
assert(rule.meta, `Rule ${ruleName} should have meta`);
assert(rule.meta.type, `Rule ${ruleName} should have meta.type`);
assert(rule.meta.docs, `Rule ${ruleName} should have meta.docs`);
assert(rule.create, `Rule ${ruleName} should have create function`);
assert.strictEqual(typeof rule.create, 'function', `Rule ${ruleName} create should be a function`);
});
});

it('should have test fixtures for oxlint', () => {
// Verify fixtures exist
const fixtures = [
'no-only-tests.js',
'no-override-exports.js',
'no-unexpected-plugin-keys.js',
];

fixtures.forEach(fixture => {
const fixturePath = path.join(fixturesDir, fixture);
assert(fs.existsSync(fixturePath), `Fixture ${fixture} should exist`);
const content = fs.readFileSync(fixturePath, 'utf8');
assert(content.length > 0, `Fixture ${fixture} should have content`);
});
});

it('should have oxlint configuration file', () => {
assert(fs.existsSync(configPath), 'oxlint config should exist');
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
assert(config.jsPlugins, 'Config should have jsPlugins field');
assert(Array.isArray(config.jsPlugins), 'jsPlugins should be an array');
assert(config.rules, 'Config should have rules field');
assert(config.rules['eggache/no-only-tests'], 'Config should have eggache/no-only-tests rule');
assert(config.rules['eggache/no-override-exports'], 'Config should have eggache/no-override-exports rule');
assert(config.rules['eggache/no-unexpected-plugin-keys'], 'Config should have eggache/no-unexpected-plugin-keys rule');
});

it('should verify plugin is compatible with ES module imports', async () => {
// Test that the plugin can be imported as an ES module
// This is required for oxlint's JS plugin support
const { pathToFileURL } = require('url');
const pluginURL = pathToFileURL(pluginPath).href;

try {
// Dynamic import to test ES module compatibility
const imported = await import(pluginURL);
const plugin = imported.default || imported;

assert(plugin, 'Plugin should be importable as ES module');
assert(plugin.meta, 'Imported plugin should have meta');
assert(plugin.meta.name, 'Imported plugin should have name');
assert(plugin.rules, 'Imported plugin should have rules');
} catch (error) {
throw new Error(`Plugin is not compatible with ES module imports: ${error.message}`);
}
});
});

Loading