eslint-plugin-lexmata
v1.3.0
Published
ESLint Plugin for all Lexmata.ai projects
Maintainers
Readme
eslint-plugin-lexmata
An ESLint plugin for all Lexmata.ai projects that enforces TypeScript code quality standards with a focus on explicit visibility declarations and consistent class member ordering.
Features
- 🔒 Explicit Public Methods: Enforces explicit
publicdeclarations on class methods - 📋 Member Ordering: Enforces a consistent ordering of class members
- 🏷️ Private Member Prefix: Enforces underscore prefix on private class members (not functions)
- ⚡ Angular Signals: Prefers Angular signals over RxJS observables when appropriate
- 🔧 Auto-fixable: All rules provide automatic fixes
- 📦 TypeScript Ready: Built specifically for TypeScript projects
- ⚡ Zero Configuration: Works out of the box with recommended config
Installation
npm install --save-dev eslint-plugin-lexmataor with pnpm:
pnpm add -D eslint-plugin-lexmataor with yarn:
yarn add --dev eslint-plugin-lexmataQuick Start
Add the plugin to your ESLint configuration:
ESLint v9+ (Flat Config)
import lexmataPlugin from 'eslint-plugin-lexmata';
export default [
{
plugins: {
'lexmata': lexmataPlugin
},
rules: {
'lexmata/explicit-public-methods': 'error',
'lexmata/member-ordering': 'error',
'lexmata/private-member-prefix': 'error',
'lexmata/prefer-angular-signals': 'error'
}
}
];ESLint v8 (Legacy Config)
{
"plugins": ["lexmata"],
"rules": {
"lexmata/explicit-public-methods": "error",
"lexmata/member-ordering": "error",
"lexmata/private-member-prefix": "error",
"lexmata/prefer-angular-signals": "error"
}
}Using Recommended Configuration
import lexmataPlugin from 'eslint-plugin-lexmata';
export default [
lexmataPlugin.configs.recommended
];Rules
lexmata/explicit-public-methods
Enforces explicit public declarations on class methods to improve code clarity and consistency.
❌ Incorrect
class Example {
method() { // Missing explicit 'public'
return 'hello';
}
getValue() { // Missing explicit 'public'
return this.value;
}
}✅ Correct
class Example {
public method() {
return 'hello';
}
public getValue() {
return this.value;
}
private privateMethod() { // Private methods are allowed without 'public'
return 'private';
}
protected protectedMethod() { // Protected methods are allowed
return 'protected';
}
#privateField() { // Private fields are allowed
return 'private field';
}
}lexmata/member-ordering
Enforces a specific ordering of class members to improve code organization and readability.
Required Order
- Public properties
- Protected properties
- Private properties
- Constructor
- Public getters/setters
- Public methods
- Protected methods
- Private methods
- Private fields (using
#syntax)
❌ Incorrect
class Example {
constructor() {} // Constructor should come after properties
private prop1: string; // Private property in wrong position
method1() {} // Missing 'public' and wrong position
protected method2() {} // Wrong position
get value() {} // Missing 'public' and wrong position
public prop2: string; // Public property in wrong position
}✅ Correct
class Example {
public prop2: string; // Public properties first
protected prop3: string; // Protected properties
private prop1: string; // Private properties
constructor() {} // Constructor after properties
public get value() { // Public getters/setters
return this._value;
}
public set value(v: string) {
this._value = v;
}
public method1() {} // Public methods
public method2() {}
protected method3() {} // Protected methods
private method4() {} // Private methods
#privateField: string; // Private fields last
}lexmata/private-member-prefix
Enforces underscore prefix on private class members (properties and fields) to improve code clarity and distinguish them from public members. This rule only applies to private members that are not functions.
❌ Incorrect
class Example {
private property: string;
private field = 'value';
private number: number = 42;
}✅ Correct
class Example {
private _property: string;
private _field = 'value';
private _number: number = 42;
// Methods are not affected by this rule
private method() {}
private _privateMethod() {}
}lexmata/prefer-angular-signals
Encourages the use of Angular signals (signal, computed, effect) over RxJS observables and BehaviorSubjects, except when dealing with Angular resources that still use RxJS (like HttpClient, Router, FormControl).
❌ Incorrect
import { BehaviorSubject, of, from } from 'rxjs';
class Example {
private data = new BehaviorSubject('initial');
getData() {
return of('data');
}
ngOnInit() {
this.data.subscribe(value => {
console.log(value);
});
}
}✅ Correct
import { signal, computed, effect } from '@angular/core';
class Example {
private _data = signal('initial');
private _computed = computed(() => this._data() + ' processed');
constructor() {
effect(() => {
console.log(this._data());
});
}
}Angular Resources Exception
The rule allows RxJS usage when dealing with Angular resources that still use RxJS:
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { FormControl } from '@angular/forms';
class Service {
constructor(private http: HttpClient, private route: ActivatedRoute) {}
// ✅ Allowed - HttpClient still uses RxJS
getData() {
return this.http.get('/api/data');
}
// ✅ Allowed - Router still uses RxJS
ngOnInit() {
this.route.params.subscribe(params => {
console.log(params);
});
}
// ✅ Allowed - FormControl still uses RxJS
control = new FormControl('');
ngOnInit() {
this.control.valueChanges.subscribe(value => {
console.log(value);
});
}
}Configuration Options
All rules currently have no configuration options and work with their default behavior. They are designed to be zero-configuration for consistent code style across Lexmata.ai projects.
Auto-fixing
All rules support ESLint's --fix option:
eslint --fix your-file.tsThe rules will automatically:
- Add missing
publicdeclarations - Reorder class members according to the specified order
- Add underscore prefixes to private members
- Convert BehaviorSubject to signal() where appropriate
- Maintain proper indentation and formatting
Development
Prerequisites
- Node.js 16+
- pnpm (recommended) or npm
Setup
# Clone the repository
git clone <repository-url>
cd eslint-plugin-lexmata
# Install dependencies
pnpm install
# Build the plugin
pnpm run build
# Run tests
pnpm test
# Run linting
pnpm run lintProject Structure
eslint-plugin-lexmata/
├── src/
│ ├── index.ts # Plugin entry point
│ └── rules/
│ ├── explicit-public-methods.ts
│ ├── member-ordering.ts
│ ├── private-member-prefix.ts
│ └── prefer-angular-signals.ts
├── tests/
│ └── rules/
│ ├── explicit-public-methods.test.ts
│ ├── member-ordering.test.ts
│ ├── private-member-prefix.test.ts
│ └── prefer-angular-signals.test.ts
├── dist/ # Built output (generated)
├── package.json
├── tsconfig.json
├── jest.config.js
└── eslint.config.jsAvailable Scripts
pnpm run build- Compile TypeScript to JavaScriptpnpm test- Run Jest testspnpm run lint- Run ESLint on source codepnpm run prepare- Build before publishing (runs automatically)
Testing
The plugin uses Jest with TypeScript support and the official @typescript-eslint/rule-tester for testing ESLint rules.
pnpm testTests cover:
- Valid code examples that should pass
- Invalid code examples that should fail
- Auto-fix functionality
- Edge cases and error conditions
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for your changes
- Ensure all tests pass (
pnpm test) - Ensure linting passes (
pnpm run lint) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Peer Dependencies
- ESLint >= 8.0.0
Dependencies
@typescript-eslint/utils^8.15.0
License
ISC License - see the LICENSE.md file for details.
Changelog
v1.3.0
- Added
lexmata/prefer-angular-signalsrule to encourage Angular signals over RxJS observables - Supports auto-fix for BehaviorSubject to signal() conversion
- Excludes Angular resources that still use RxJS (HttpClient, Router, FormControl)
- Updated documentation with Angular signals examples
v1.2.0
- Added
lexmata/private-member-prefixrule to enforce underscore prefix on private class members (not functions) - Full auto-fix support for the new rule
- Updated documentation and examples
v1.1.1
- Current stable release
- Includes
explicit-public-methodsandmember-orderingrules - Full auto-fix support
- TypeScript support
Support
For issues, feature requests, or questions:
- Create an issue in the repository
- Contact: Joseph Quinn [email protected]
Made with ❤️ by the Lexmata.ai team
