@reasonabletech/eslint-config 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +89 -0
  3. package/dist/src/base-configs.d.ts +53 -0
  4. package/dist/src/base-configs.js +105 -0
  5. package/dist/src/custom-rules/architecture-patterns.d.ts +193 -0
  6. package/dist/src/custom-rules/architecture-patterns.js +344 -0
  7. package/dist/src/custom-rules/code-quality.d.ts +201 -0
  8. package/dist/src/custom-rules/code-quality.js +388 -0
  9. package/dist/src/custom-rules/error-handling.d.ts +103 -0
  10. package/dist/src/custom-rules/error-handling.js +349 -0
  11. package/dist/src/custom-rules/index.d.ts +79 -0
  12. package/dist/src/custom-rules/index.js +119 -0
  13. package/dist/src/custom-rules/null-undefined-checks.d.ts +20 -0
  14. package/dist/src/custom-rules/null-undefined-checks.js +153 -0
  15. package/dist/src/custom-rules/platform-conventions.d.ts +115 -0
  16. package/dist/src/custom-rules/platform-conventions.js +249 -0
  17. package/dist/src/custom-rules/test-quality.d.ts +38 -0
  18. package/dist/src/custom-rules/test-quality.js +68 -0
  19. package/dist/src/custom-rules/type-safety.d.ts +71 -0
  20. package/dist/src/custom-rules/type-safety.js +121 -0
  21. package/dist/src/custom-rules/ui-library-imports.d.ts +21 -0
  22. package/dist/src/custom-rules/ui-library-imports.js +31 -0
  23. package/dist/src/custom-rules/utils.d.ts +95 -0
  24. package/dist/src/custom-rules/utils.js +146 -0
  25. package/dist/src/index.d.ts +73 -0
  26. package/dist/src/index.js +80 -0
  27. package/dist/src/next/config.d.ts +26 -0
  28. package/dist/src/next/config.js +76 -0
  29. package/dist/src/next/ignores.d.ts +37 -0
  30. package/dist/src/next/ignores.js +69 -0
  31. package/dist/src/next/plugins.d.ts +44 -0
  32. package/dist/src/next/plugins.js +104 -0
  33. package/dist/src/next/rules.d.ts +39 -0
  34. package/dist/src/next/rules.js +48 -0
  35. package/dist/src/next/settings.d.ts +41 -0
  36. package/dist/src/next/settings.js +45 -0
  37. package/dist/src/next.d.ts +33 -0
  38. package/dist/src/next.js +74 -0
  39. package/dist/src/plugin.d.ts +48 -0
  40. package/dist/src/plugin.js +30 -0
  41. package/dist/src/react/config.d.ts +30 -0
  42. package/dist/src/react/config.js +40 -0
  43. package/dist/src/react/plugins.d.ts +24 -0
  44. package/dist/src/react/plugins.js +46 -0
  45. package/dist/src/react/rules.d.ts +30 -0
  46. package/dist/src/react/rules.js +35 -0
  47. package/dist/src/react.d.ts +27 -0
  48. package/dist/src/react.js +35 -0
  49. package/dist/src/shared/parser-options.d.ts +3 -0
  50. package/dist/src/shared/parser-options.js +19 -0
  51. package/dist/src/shared/plugin-utils.d.ts +8 -0
  52. package/dist/src/shared/plugin-utils.js +23 -0
  53. package/dist/src/shared/react-rules.d.ts +97 -0
  54. package/dist/src/shared/react-rules.js +126 -0
  55. package/dist/src/shared/strict-rules.d.ts +27 -0
  56. package/dist/src/shared/strict-rules.js +54 -0
  57. package/dist/src/shared-ignores.d.ts +15 -0
  58. package/dist/src/shared-ignores.js +68 -0
  59. package/dist/src/shared-rules.d.ts +29 -0
  60. package/dist/src/shared-rules.js +163 -0
  61. package/package.json +122 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # @reasonabletech/eslint-config
2
+
3
+ ## [Unreleased]
4
+
5
+ Initial release preparation. See [README.md](./README.md) for usage.
6
+
7
+ ---
8
+
9
+ *Changelog entries are automatically generated from [changesets](https://github.com/changesets/changesets) on release.*
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @reasonabletech/eslint-config
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@reasonabletech/eslint-config.svg)](https://www.npmjs.com/package/@reasonabletech/eslint-config)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@reasonabletech/eslint-config.svg)](https://www.npmjs.com/package/@reasonabletech/eslint-config)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
7
+
8
+ `@reasonabletech/eslint-config` provides opinionated, type-aware ESLint flat configs for TypeScript, React, and Next.js projects. Type-aware linting runs ESLint rules that require a TypeScript project reference — these rules catch issues like unsafe `any` assignments and incorrect promise handling that non-type-aware rules miss.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pnpm add -D @reasonabletech/eslint-config eslint typescript
14
+ ```
15
+
16
+ ## Peer Dependencies
17
+
18
+ | Dependency | Version | Required |
19
+ | ---------- | --------- | -------- |
20
+ | eslint | >= 9.0 | Yes |
21
+ | typescript | >= 5.0 | Yes |
22
+
23
+ This package uses ESLint flat config format (introduced in ESLint 9.0) and requires TypeScript 5.0+ for type-aware linting. Legacy `.eslintrc` configuration is not supported.
24
+
25
+ ## Exported Entry Points
26
+
27
+ | Import Path | Purpose | Main Exports |
28
+ | ------------------------------------- | -------------------------- | ---------------------------------------------------- |
29
+ | `@reasonabletech/eslint-config` | TypeScript baseline config | `createTypeAwareConfig`, `sharedReactComponentRules` |
30
+ | `@reasonabletech/eslint-config/react` | React project config | `createTypeAwareReactConfig` |
31
+ | `@reasonabletech/eslint-config/next` | Next.js project config | `createTypeAwareNextConfig` |
32
+
33
+ ## Usage
34
+
35
+ ### TypeScript Project
36
+
37
+ ```ts
38
+ // eslint.config.mjs
39
+ import { createTypeAwareConfig } from "@reasonabletech/eslint-config";
40
+
41
+ export default createTypeAwareConfig(import.meta.dirname);
42
+ ```
43
+
44
+ ### React Project
45
+
46
+ ```ts
47
+ // eslint.config.mjs
48
+ import { createTypeAwareReactConfig } from "@reasonabletech/eslint-config/react";
49
+
50
+ export default createTypeAwareReactConfig(import.meta.dirname);
51
+ ```
52
+
53
+ ### Next.js Project
54
+
55
+ ```ts
56
+ // eslint.config.mjs
57
+ import { createTypeAwareNextConfig } from "@reasonabletech/eslint-config/next";
58
+
59
+ export default createTypeAwareNextConfig(import.meta.dirname);
60
+ ```
61
+
62
+ ### Customize Rules for Your Project
63
+
64
+ ```ts
65
+ // eslint.config.mjs
66
+ import { createTypeAwareConfig } from "@reasonabletech/eslint-config";
67
+
68
+ export default [
69
+ ...createTypeAwareConfig(import.meta.dirname),
70
+ {
71
+ rules: {
72
+ "@typescript-eslint/no-unused-vars": "warn",
73
+ },
74
+ },
75
+ ];
76
+ ```
77
+
78
+ ## Changelog
79
+
80
+ See [CHANGELOG.md](./CHANGELOG.md) for release history.
81
+
82
+ This package follows [Semantic Versioning](https://semver.org/). Breaking changes are documented with migration guides when applicable.
83
+
84
+ ## Additional References
85
+
86
+ - [Usage Guide](./docs/guides/usage-guide.md)
87
+ - [Package Docs](./docs/index.md)
88
+ - [API Reference](./docs/reference/api-reference.md)
89
+ - [Architecture](./docs/concepts/architecture.md)
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Base ESLint Configuration Builders - Foundation for consistent linting across the monorepo
3
+ *
4
+ * This module provides the core configuration builders used to create consistent ESLint
5
+ * configurations across all projects in the monorepo. It combines shared rules,
6
+ * ignore patterns, and TypeScript configurations into reusable base configurations
7
+ * that ensure consistency while reducing code duplication.
8
+ *
9
+ * The implementation follows several architectural principles:
10
+ * - Centralized base configuration to ensure consistency across all projects
11
+ * - Separation of concerns between basic and type-aware configurations
12
+ * - Modular composition using shared rules and ignore patterns
13
+ * - TypeScript-first approach with comprehensive type checking capabilities
14
+ * - Extensible design that supports framework-specific customizations
15
+ * Base ESLint configuration builders for the monorepo
16
+ * @author ReasonableTech Team
17
+ * @since 0.1.0
18
+ */
19
+ import type { Linter } from "eslint";
20
+ /**
21
+ * Creates a comprehensive type-aware ESLint configuration with TypeScript project analysis.
22
+ *
23
+ * This function generates the recommended ESLint configuration for all projects.
24
+ * It includes all base rules plus advanced type-aware rules that leverage TypeScript's
25
+ * type system to catch subtle bugs, unsafe operations, and logical inconsistencies
26
+ * that would be missed by syntax-only analysis. This is essential for AI-generated
27
+ * code safety and maintaining high code quality standards.
28
+ *
29
+ * The configuration includes:
30
+ * - JavaScript and TypeScript recommended rules
31
+ * - Prettier compatibility layer
32
+ * - TypeScript type-aware analysis rules
33
+ * - Comprehensive ignore patterns for build outputs and generated files
34
+ * - Strict type safety rules optimized for AI-generated code
35
+ * @param projectDir - The absolute path to the directory containing the TypeScript project.
36
+ * This is used to configure TypeScript's project references for type checking.
37
+ * @returns Array of ESLint configuration objects with full type-aware analysis enabled
38
+ * @example
39
+ * ```typescript
40
+ * import { createTypeAwareBaseConfig } from './base-configs.js';
41
+ *
42
+ * // For a standard project
43
+ * const config = createTypeAwareBaseConfig(import.meta.dirname);
44
+ *
45
+ * // For framework-specific projects, extend the base
46
+ * const reactConfig = [
47
+ * ...createTypeAwareBaseConfig(import.meta.dirname),
48
+ * // React-specific configurations
49
+ * ];
50
+ * ```
51
+ */
52
+ export declare function createTypeAwareBaseConfig(projectDir: string): Linter.Config[];
53
+ //# sourceMappingURL=base-configs.d.ts.map
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Base ESLint Configuration Builders - Foundation for consistent linting across the monorepo
3
+ *
4
+ * This module provides the core configuration builders used to create consistent ESLint
5
+ * configurations across all projects in the monorepo. It combines shared rules,
6
+ * ignore patterns, and TypeScript configurations into reusable base configurations
7
+ * that ensure consistency while reducing code duplication.
8
+ *
9
+ * The implementation follows several architectural principles:
10
+ * - Centralized base configuration to ensure consistency across all projects
11
+ * - Separation of concerns between basic and type-aware configurations
12
+ * - Modular composition using shared rules and ignore patterns
13
+ * - TypeScript-first approach with comprehensive type checking capabilities
14
+ * - Extensible design that supports framework-specific customizations
15
+ * Base ESLint configuration builders for the monorepo
16
+ * @author ReasonableTech Team
17
+ * @since 0.1.0
18
+ */
19
+ import js from "@eslint/js";
20
+ import eslintConfigPrettier from "eslint-config-prettier";
21
+ import jsdoc from "eslint-plugin-jsdoc";
22
+ import { configs as tsConfigs } from "typescript-eslint";
23
+ import { defineConfig, globalIgnores } from "eslint/config";
24
+ import { reasonableTechPlugin } from "./plugin.js";
25
+ import { sharedIgnores } from "./shared-ignores.js";
26
+ import { baseRules, typeAwareRules } from "./shared-rules.js";
27
+ import { createPlatformRulePreset } from "./custom-rules/index.js";
28
+ import { createNoTypeofInExpectRules } from "./custom-rules/test-quality.js";
29
+ /**
30
+ * Creates a comprehensive type-aware ESLint configuration with TypeScript project analysis.
31
+ *
32
+ * This function generates the recommended ESLint configuration for all projects.
33
+ * It includes all base rules plus advanced type-aware rules that leverage TypeScript's
34
+ * type system to catch subtle bugs, unsafe operations, and logical inconsistencies
35
+ * that would be missed by syntax-only analysis. This is essential for AI-generated
36
+ * code safety and maintaining high code quality standards.
37
+ *
38
+ * The configuration includes:
39
+ * - JavaScript and TypeScript recommended rules
40
+ * - Prettier compatibility layer
41
+ * - TypeScript type-aware analysis rules
42
+ * - Comprehensive ignore patterns for build outputs and generated files
43
+ * - Strict type safety rules optimized for AI-generated code
44
+ * @param projectDir - The absolute path to the directory containing the TypeScript project.
45
+ * This is used to configure TypeScript's project references for type checking.
46
+ * @returns Array of ESLint configuration objects with full type-aware analysis enabled
47
+ * @example
48
+ * ```typescript
49
+ * import { createTypeAwareBaseConfig } from './base-configs.js';
50
+ *
51
+ * // For a standard project
52
+ * const config = createTypeAwareBaseConfig(import.meta.dirname);
53
+ *
54
+ * // For framework-specific projects, extend the base
55
+ * const reactConfig = [
56
+ * ...createTypeAwareBaseConfig(import.meta.dirname),
57
+ * // React-specific configurations
58
+ * ];
59
+ * ```
60
+ */
61
+ export function createTypeAwareBaseConfig(projectDir) {
62
+ return defineConfig(js.configs.recommended, eslintConfigPrettier, jsdoc.configs["flat/recommended-typescript"], ...tsConfigs.recommendedTypeChecked, {
63
+ languageOptions: {
64
+ parserOptions: {
65
+ // projectService auto-discovers the correct tsconfig for each file and
66
+ // creates in-memory projects for files outside any tsconfig. This
67
+ // eliminates the need for separate .tsconfig.typeaware-tests.json files
68
+ // and the RT_ESLINT_PROJECT env var override.
69
+ projectService: true,
70
+ tsconfigRootDir: projectDir,
71
+ },
72
+ },
73
+ }, {
74
+ plugins: {
75
+ // Cast required: typescript-eslint's RuleModule types are structurally
76
+ // incompatible with @eslint/core's Plugin type used by defineConfig().
77
+ // The plugin works correctly at runtime; this is purely a type mismatch
78
+ // between the two type ecosystems.
79
+ "@reasonabletech": reasonableTechPlugin,
80
+ },
81
+ }, {
82
+ // Report unused ESLint disable directives across all projects
83
+ linterOptions: {
84
+ reportUnusedDisableDirectives: "error",
85
+ },
86
+ }, globalIgnores([...sharedIgnores, "**/*.mjs", "**/vitest.config.mts"]), {
87
+ rules: {
88
+ ...baseRules,
89
+ ...typeAwareRules,
90
+ ...createPlatformRulePreset(),
91
+ },
92
+ }, {
93
+ // Test-quality rules applied specifically to test files.
94
+ // These ban low-value patterns that AI agents use to inflate coverage
95
+ // without verifying real behaviour.
96
+ files: [
97
+ "**/*.test.ts",
98
+ "**/*.test.tsx",
99
+ "**/tests/**/*.ts",
100
+ "**/tests/**/*.tsx",
101
+ ],
102
+ rules: createNoTypeofInExpectRules(),
103
+ });
104
+ }
105
+ //# sourceMappingURL=base-configs.js.map
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Architecture pattern rules for the platform
3
+ *
4
+ * These rules enforce architectural best practices and prevent common
5
+ * anti-patterns in service design and dependency injection.
6
+ */
7
+ import { ESLintUtils } from "@typescript-eslint/utils";
8
+ import type { Linter } from "eslint";
9
+ /**
10
+ * Configuration options for architecture pattern rules
11
+ */
12
+ export interface ArchitecturePatternRuleOptions {
13
+ /** Base URL for documentation references */
14
+ docBaseUrl?: string;
15
+ /** Whether to enforce individual dependency injection (default: true) */
16
+ enforceIndividualDependencies?: boolean;
17
+ }
18
+ /**
19
+ * Custom ESLint rule that prevents bundling service dependencies into objects
20
+ *
21
+ * This rule prevents the anti-pattern of wrapping service dependencies in
22
+ * container objects. The pattern itself is wrong - it doesn't matter if you
23
+ * bundle 1 service or 10 services, wrapping them breaks dependency injection.
24
+ *
25
+ * **Core Principle**: Services should receive dependencies as direct constructor
26
+ * parameters, not wrapped in objects. This makes dependencies explicit, improves
27
+ * testability, and prevents tight coupling.
28
+ *
29
+ * Detection is naming-based: interfaces and type aliases whose names end with
30
+ * "Dependencies" or "Deps" are flagged regardless of their contents.
31
+ *
32
+ * ❌ FORBIDDEN (ANY "*Dependencies" or "*Deps" naming):
33
+ * ```typescript
34
+ * // Wrong: Even ONE service wrapped is bad
35
+ * interface AuthDependencies {
36
+ * apiKeyService: ApiKeyService;
37
+ * }
38
+ * function initializeAuth(deps: AuthDependencies) {
39
+ * // Creates indirection, hides dependency
40
+ * }
41
+ *
42
+ * // Wrong: Multiple services bundled
43
+ * interface ServiceDeps {
44
+ * logger: Logger;
45
+ * database: Database;
46
+ * cache: Cache;
47
+ * }
48
+ * class MyService {
49
+ * constructor(private deps: ServiceDeps) {
50
+ * // Tight coupling to the bundle structure
51
+ * }
52
+ * }
53
+ * ```
54
+ *
55
+ * ✅ CORRECT (direct parameter injection):
56
+ * ```typescript
57
+ * // Right: Direct parameter
58
+ * function initializeAuth(apiKeyService: ApiKeyService) {
59
+ * // Dependency is explicit and visible
60
+ * }
61
+ *
62
+ * // Right: Individual injection
63
+ * class MyService {
64
+ * constructor(
65
+ * private readonly logger: Logger,
66
+ * private readonly database: Database,
67
+ * private readonly cache: Cache,
68
+ * ) {
69
+ * // Each dependency is explicit and independently injectable
70
+ * }
71
+ * }
72
+ * ```
73
+ *
74
+ * **Why this matters**:
75
+ * - Bundling hides which dependencies are actually used
76
+ * - Makes mocking harder (must mock entire bundle)
77
+ * - Creates coupling to the bundle structure
78
+ * - Prevents partial initialization for testing
79
+ * - Use naming like "*Config" or "*Options" for true configuration data (not services)
80
+ */
81
+ export declare const noDependencyBundlingRule: ESLintUtils.RuleModule<"dependencyBundle", [{
82
+ docBaseUrl: string;
83
+ }], unknown, ESLintUtils.RuleListener> & {
84
+ name: string;
85
+ };
86
+ /**
87
+ * Custom ESLint rule that prevents creating service dependencies inside constructors
88
+ *
89
+ * This rule detects `new PascalCase()` expressions inside class constructors and
90
+ * reports them as violations, since services should receive dependencies via
91
+ * constructor parameters rather than creating them internally.
92
+ *
93
+ * **Exceptions**:
94
+ * - Built-in constructors (Map, Set, Date, Error, etc.) are allowed because
95
+ * they are standard data structures, not service dependencies.
96
+ * - `new` expressions inside default parameter values (AssignmentPattern) are
97
+ * allowed because the dependency CAN still be injected — the `new` only runs
98
+ * when no argument is provided.
99
+ * @example
100
+ * ```typescript
101
+ * // ❌ FORBIDDEN: creating a dependency inside a constructor
102
+ * class UserService {
103
+ * constructor(config: Config) {
104
+ * this.db = new Database(config); // Violation
105
+ * }
106
+ * }
107
+ *
108
+ * // ✅ CORRECT: built-in constructors are fine
109
+ * class CacheService {
110
+ * constructor() {
111
+ * this.cache = new Map();
112
+ * }
113
+ * }
114
+ *
115
+ * // ✅ CORRECT: default parameter values are fine
116
+ * class UserService {
117
+ * constructor(private db: Database = new Database()) {}
118
+ * }
119
+ * ```
120
+ */
121
+ export declare const noConstructorInstantiationRule: ESLintUtils.RuleModule<"constructorInstantiation", [], unknown, ESLintUtils.RuleListener> & {
122
+ name: string;
123
+ };
124
+ /**
125
+ * Creates rules that prevent wrapping service dependencies in container objects
126
+ *
127
+ * Uses the `@reasonabletech/no-dependency-bundling` custom rule which detects
128
+ * naming patterns (*Dependencies, *Deps) on interfaces and type aliases.
129
+ * @param options Configuration options for architecture pattern rules
130
+ * @returns ESLint rules that prevent dependency bundling
131
+ */
132
+ export declare function createDependencyBundlingRules(options?: ArchitecturePatternRuleOptions): Linter.RulesRecord;
133
+ /**
134
+ * Creates rules that enforce dependency injection patterns
135
+ *
136
+ * These rules prevent services from creating their own dependencies
137
+ * or using singleton patterns, enforcing proper dependency injection.
138
+ *
139
+ * Uses `no-restricted-syntax` to ban `getInstance()` singletons and the
140
+ * `@reasonabletech/no-constructor-instantiation` custom rule to detect
141
+ * `new` expressions inside constructors (with built-in and default-param
142
+ * exceptions).
143
+ *
144
+ * ❌ FORBIDDEN:
145
+ * ```typescript
146
+ * export class UserService {
147
+ * static getInstance() { return instance; } // Singleton
148
+ *
149
+ * constructor(config: Config) {
150
+ * this.db = new Database(config); // Creates own dependency
151
+ * }
152
+ * }
153
+ * ```
154
+ *
155
+ * ✅ CORRECT:
156
+ * ```typescript
157
+ * export class UserService {
158
+ * constructor(
159
+ * private db: Database, // Injected dependency
160
+ * private config: Config,
161
+ * ) {}
162
+ * }
163
+ * ```
164
+ * @param _options Configuration options for architecture pattern rules (reserved for future use)
165
+ * @returns ESLint rules that enforce dependency injection
166
+ */
167
+ export declare function createDependencyInjectionRules(_options?: ArchitecturePatternRuleOptions): Linter.RulesRecord;
168
+ /**
169
+ * Creates rules that enforce proper service architecture patterns
170
+ *
171
+ * Enforces patterns like:
172
+ * - Individual dependency injection (no god objects)
173
+ * - Required dependencies must be required constructor parameters
174
+ * - Services should accept dependencies, not create them
175
+ * @param options Configuration options for architecture pattern rules
176
+ * @returns ESLint rules that enforce service architecture patterns
177
+ */
178
+ export declare function createServiceArchitectureRules(options?: ArchitecturePatternRuleOptions): Linter.RulesRecord;
179
+ /**
180
+ * Creates a complete set of architecture pattern rules
181
+ *
182
+ * This is the main function that combines all architecture pattern rules
183
+ * into a single configuration object.
184
+ * @param options Configuration options for architecture pattern rules
185
+ * @returns Complete set of architecture pattern ESLint rules
186
+ */
187
+ export declare function createArchitecturePatternRules(options?: ArchitecturePatternRuleOptions): Linter.RulesRecord;
188
+ /**
189
+ * Preset for platform architecture pattern rules
190
+ * @returns ESLint rules configured for platform projects
191
+ */
192
+ export declare function createPlatformArchitecturePatternRules(): Linter.RulesRecord;
193
+ //# sourceMappingURL=architecture-patterns.d.ts.map