Thank you for your interest in contributing to the Stencil ESLint Plugin! This guide will help you get started with development, testing, and submitting contributions.
- Development Setup
- Project Structure
- Creating New Rules
- Testing
- Code Standards
- Submitting Changes
- Release Process
- Node.js: >=22.13.1 (for development)
- npm: Latest version recommended
- TypeScript: Knowledge of TypeScript is essential
- ESLint: Understanding of ESLint rule development
-
Fork and Clone
git clone https://github.com/YOUR_USERNAME/eslint-plugin.git cd eslint-plugin -
Install Dependencies
npm ci
-
Build the Project
npm run build
-
Run Tests
npm test -
Watch Mode for Development
npm run watch
src/
βββ configs/ # ESLint configuration presets
β βββ base.ts
β βββ recommended.ts
β βββ strict.ts
βββ rules/ # ESLint rule implementations
β βββ async-methods.ts
β βββ ban-default-true.ts
β βββ ...
βββ utils.ts # Shared utilities for rule development
βββ index.ts # Main plugin entry point
tests/
βββ rules/ # Rule test suites
β βββ async-methods/
β β βββ async-methods.test.ts
β β βββ async-methods.good.tsx # Valid code examples
β β βββ async-methods.wrong.tsx # Invalid code examples
β βββ ...
βββ rule-tester.ts # Shared test configuration
docs/ # Rule documentation
βββ async-methods.md
βββ ban-default-true.md
βββ ...
Create your rule file in src/rules/your-rule-name.ts:
import type { Rule } from 'eslint';
import { stencilComponentContext } from '../utils';
const rule: Rule.RuleModule = {
meta: {
docs: {
description: 'Brief description of what this rule does.',
category: 'Possible Errors', // or 'Best Practices', 'Stylistic Issues'
recommended: true // or false
},
schema: [], // JSON schema for rule options
type: 'problem', // 'problem', 'suggestion', or 'layout'
fixable: 'code' // Optional: 'code' or 'whitespace' if rule is auto-fixable
},
create(context): Rule.RuleListener {
const stencil = stencilComponentContext();
return {
...stencil.rules,
// Your rule logic here
'SelectorNode': (node: any) => {
if (!stencil.isComponent()) {
return;
}
// Rule implementation
context.report({
node,
message: 'Your error message here',
fix(fixer) {
// Optional: provide auto-fix
return fixer.replaceText(node, 'corrected code');
}
});
}
};
}
};
export default rule;Update src/rules/index.ts:
import yourRuleName from './your-rule-name';
export default {
// ... existing rules
'your-rule-name': yourRuleName,
};Update the appropriate config files in src/configs/ to include your rule:
base.ts- Essential rulesrecommended.ts- Recommended rulesstrict.ts- Strict rules
Create docs/your-rule-name.md with:
# your-rule-name
Brief description of the rule.
## Rule Details
Detailed explanation of what the rule checks for.
## Examples
### β Incorrect
```tsx
// Bad code example
```
### β
Correct
```tsx
// Good code example
```
## Options
If your rule accepts options, document them here.
## When Not To Use It
Explain scenarios where this rule might not be applicable.Add your rule to the "Supported Rules" section in README.md.
Each rule should have comprehensive tests in tests/rules/your-rule-name/:
your-rule-name.test.ts- Main test fileyour-rule-name.good.tsx- Valid code examplesyour-rule-name.wrong.tsx- Invalid code examplesyour-rule-name.output.tsx- Expected output after auto-fix (if applicable)
import path from 'node:path';
import fs from 'node:fs';
import { test } from 'vitest';
import { ruleTester } from '../rule-tester';
import rule from '../../../src/rules/your-rule-name';
test('your-rule-name', () => {
const files = {
good: path.resolve(__dirname, 'your-rule-name.good.tsx'),
wrong: path.resolve(__dirname, 'your-rule-name.wrong.tsx'),
output: path.resolve(__dirname, 'your-rule-name.output.tsx') // if fixable
};
ruleTester.run('your-rule-name', rule, {
valid: [
{
code: fs.readFileSync(files.good, 'utf8'),
filename: files.good
}
],
invalid: [
{
code: fs.readFileSync(files.wrong, 'utf8'),
filename: files.wrong,
errors: 1, // Expected number of errors
output: fs.readFileSync(files.output, 'utf8') // if fixable
}
]
});
});# Run all tests
npm test
# Run tests with coverage
npm test -- --coverage
# Run specific test
npm test -- async-methodsThe project enforces code coverage thresholds that must be maintained.
- Use strict TypeScript configuration
- Provide proper type annotations
- Use ESLint's type definitions from
@types/eslint
- Follow existing code patterns in the project
- Use meaningful variable and function names
- Add JSDoc comments for complex logic
- Use the Stencil utilities from
../utilswhen possible
- Use
stencilComponentContext()to ensure rules only apply to Stencil components - Leverage TypeScript's type checker for accurate analysis
- Consider Stencil decorators:
@Component,@Prop,@State,@Method,@Event,@Listen,@Watch,@Element
-
Create a Branch
git checkout -b feature/your-rule-name # or git checkout -b fix/issue-description -
Make Your Changes
- Implement your rule
- Add comprehensive tests
- Update documentation
- Ensure tests pass and coverage meets requirements
-
Commit Your Changes
git add . git commit -m "feat: add your-rule-name rule" # or git commit -m "fix: resolve issue with existing-rule"
-
Push and Create PR
git push origin feature/your-rule-name
β Required for all PRs:
- Tests pass (
npm test) - Code builds successfully (
npm run build) - New rules include comprehensive tests
- Documentation is updated (README.md, docs/, etc.)
- Code follows existing patterns and style
β For new rules:
- Rule implementation in
src/rules/ - Tests with good/wrong/output examples
- Documentation in
docs/ - Added to appropriate configs
- Added to README.md rule list
The project uses GitHub Actions for:
- Build & Test: Runs on Node.js 20, 22, 24 across Ubuntu and Windows
- Coverage: Ensures code coverage thresholds are met
- Automated Releases: Handles version bumping and npm publishing
Releases are handled through GitHub Actions and are restricted to maintainers.
- Patch (
1.0.1): Bug fixes and minor improvements - Minor (
1.1.0): New features, new rules - Major (
2.0.0): Breaking changes
-
Prepare Release
- Ensure all PRs are merged to
main - Verify all tests pass
- Review changelog and breaking changes
- Ensure all PRs are merged to
-
Trigger Release
- Go to GitHub Actions β "Release Eslint Stencil"
- Choose release type (patch/minor/major)
- Choose "no" for dev release (unless testing)
- Run workflow
-
Post-Release
- Verify npm package is published
- Check GitHub release is created
- Update any dependent projects
For testing purposes, maintainers can create dev releases:
- Set "devRelease" to "yes" in the workflow
- Creates a version like
1.1.0-dev.1677185104.7c87e34 - Published with
devtag on npm
- Issues: Check existing GitHub Issues
- Discord: Join our Discord community for questions and discussions
- ESLint Docs: ESLint Rule Guidelines
- Stencil Docs: Stencil Documentation
Your contributions help make Stencil development better for everyone. Whether it's a bug fix, new rule, or documentation improvement, every contribution is valued!
For questions about this contributing guide, please open an issue or discussion in the repository.