Skip to content

Commit 36833a1

Browse files
committed
init linters
1 parent 5668c37 commit 36833a1

105 files changed

Lines changed: 23061 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: '20'
19+
cache: 'npm'
20+
21+
- name: Install dependencies
22+
run: npm ci
23+
24+
- name: Run tests
25+
run: npm test
26+
27+
lint-examples:
28+
runs-on: ubuntu-latest
29+
strategy:
30+
matrix:
31+
example: [typescript-project, frontend-project]
32+
steps:
33+
- uses: actions/checkout@v4
34+
35+
- name: Setup Node.js
36+
uses: actions/setup-node@v4
37+
with:
38+
node-version: '20'
39+
cache: 'npm'
40+
41+
- name: Install root dependencies
42+
run: npm ci
43+
44+
- name: Install example dependencies
45+
run: npm ci
46+
working-directory: examples/${{ matrix.example }}
47+
48+
- name: Lint example
49+
run: npm run lint
50+
working-directory: examples/${{ matrix.example }}

.gitignore

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
dist/
6+
build/
7+
8+
# Coverage
9+
coverage/
10+
11+
# IDE
12+
.idea/
13+
.vscode/
14+
*.swp
15+
*.swo
16+
17+
# OS
18+
.DS_Store
19+
Thumbs.db
20+
21+
# Logs
22+
*.log
23+
npm-debug.log*
24+
25+
# Environment
26+
.env
27+
.env.local
28+
29+
# Package manager locks (optional - remove if you want to commit them)
30+
# package-lock.json
31+
# yarn.lock

README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# @factory/eslint-plugin
2+
3+
An open-source ESLint plugin showcasing how agent-native organizations use custom lint rules to drive AI coding agents toward better results.
4+
5+
## About This Project
6+
7+
This codebase is forked from what is used internally at [Factory](https://factory.ai) and has been altered to be more generic. We are sharing this as requested by the developer community and to showcase an example of what an agent-native organization does with custom lint rules to improve agent output quality.
8+
9+
**All code in this repository is fully AI-generated.**
10+
11+
To learn more about our approach:
12+
- [Using Linters to Direct Agents](https://factory.ai/news/using-linters-to-direct-agents)
13+
- [Agent Readiness](https://factory.ai/news/agent-readiness)
14+
15+
## How to Use This Repository
16+
17+
**Our recommendation is NOT to simply import this package.** Instead, take the ideas from these rules and build your own set of custom lint rules tailored to your codebase, tech stack, and conventions.
18+
19+
We have included comprehensive markdown documentation for each rule (in `rules/<rule-name>/README.md`) that makes it easy for any AI agent to parse and adapt to your custom tech stack or framework.
20+
21+
> **Note:** This repository is not planned to be actively maintained or updated. It is designed for sharing and inspiration only.
22+
23+
## Available Configurations
24+
25+
| Config | Use Case | Description |
26+
|--------|----------|-------------|
27+
| `plugin:@factory/base` | Base | Core TypeScript/JavaScript rules |
28+
| `plugin:@factory/recommended` | Packages/Libraries | Base + Factory plugin rules |
29+
| `plugin:@factory/frontend` | React/Vite apps | Recommended + React/JSX rules |
30+
| `plugin:@factory/backend` | Backend apps | Recommended + backend constraints |
31+
32+
### Configuration Hierarchy
33+
34+
```mermaid
35+
graph TD
36+
A[base] --> B[recommended]
37+
B --> C[frontend]
38+
B --> D[backend]
39+
```
40+
41+
## Factory Plugin Rules
42+
43+
This plugin includes custom rules that enforce code organization and best practices:
44+
45+
### File Organization
46+
- `@factory/enum-file-organization` - Enums must live in `enums.ts` files
47+
- `@factory/types-file-organization` - Type definitions must live in `types.ts` files
48+
- `@factory/constants-file-organization` - Constants must live in `constants.ts` files
49+
- `@factory/errors-file-organization` - Error classes must live in `errors.ts` files
50+
- `@factory/test-utils-organization` - Test utilities must live under `test-utils/`
51+
- `@factory/test-file-location` - Test files must be colocated with source files
52+
53+
### Naming & Exports
54+
- `@factory/filename-match-export` - Filenames must match exported components/functions
55+
- `@factory/no-exported-function-expressions` - Prefer function declarations for exports
56+
- `@factory/no-exported-string-union-types` - Prefer enums over string union types
57+
58+
### Testing
59+
- `@factory/require-test-files` - TypeScript files must have corresponding test files
60+
- `@factory/require-tsx-test-stories-files` - TSX files need test and story files
61+
- `@factory/jest-mock-absolute-paths` - Jest mocks must use absolute paths
62+
- `@factory/jest-mock-require-actual` - Jest mocks must include `jest.requireActual()`
63+
- `@factory/no-unstable-mock-module` - Disallow `unstable_mockModule`
64+
65+
### Logging
66+
- `@factory/structured-logging` - Enforce structured logging patterns
67+
- `@factory/no-log-exception-with-throw` - No logging exceptions before throwing
68+
69+
### API Routes (Next.js/Express)
70+
- `@factory/require-route-middleware` - Route files must use middleware
71+
- `@factory/require-v0-route-handle-middleware` - v0 routes need specific middleware
72+
- `@factory/require-v0-strict-schemas` - v0 routes need strict schema validation
73+
74+
### React
75+
- `@factory/no-dynamic-styled-components` - No dynamic styled-components
76+
- `@factory/no-plain-html-text-elements` - No plain text in HTML elements
77+
- `@factory/no-use-effect-in-hooks` - Restrict useEffect in custom hooks
78+
- `@factory/restrict-tsx-components` - Enforce component patterns
79+
80+
## Installation
81+
82+
```bash
83+
npm install @factory/eslint-plugin eslint --save-dev
84+
```
85+
86+
## Quick Start
87+
88+
Create an `.eslintrc.js` file in your project root:
89+
90+
### For TypeScript packages/libraries
91+
92+
```js
93+
module.exports = {
94+
root: true,
95+
plugins: ['@factory'],
96+
extends: ['plugin:@factory/recommended'],
97+
};
98+
```
99+
100+
### For frontend applications (React/Vite)
101+
102+
```js
103+
module.exports = {
104+
root: true,
105+
plugins: ['@factory'],
106+
extends: ['plugin:@factory/frontend'],
107+
};
108+
```
109+
110+
### For backend applications
111+
112+
```js
113+
module.exports = {
114+
root: true,
115+
plugins: ['@factory'],
116+
extends: ['plugin:@factory/backend'],
117+
};
118+
```
119+
120+
## License
121+
122+
MIT

configs/backend.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
// Config for apps/* that are not Next.js
4+
const factoryConfig = require('./recommended.js');
5+
6+
module.exports = {
7+
...factoryConfig,
8+
plugins: [...(factoryConfig.plugins || []), 'no-relative-import-paths'],
9+
rules: {
10+
...factoryConfig.rules,
11+
'@factory/jest-mock-absolute-paths': 'error',
12+
'no-relative-import-paths/no-relative-import-paths': [
13+
'error',
14+
{ allowSameFolder: false, rootDir: 'src', prefix: '@' },
15+
],
16+
},
17+
};

configs/base.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
module.exports = {
2+
parser: '@typescript-eslint/parser',
3+
globals: {
4+
NodeJS: true,
5+
FileSystemFileHandle: true,
6+
FileSystemHandle: true,
7+
FileSystemDirectoryHandle: true,
8+
FileSystemPermissionMode: true,
9+
FileSystemHandlePermissionDescriptor: true,
10+
FileSystemWritableFileStream: true,
11+
globalThis: 'readonly',
12+
},
13+
extends: [
14+
'eslint-config-airbnb-base',
15+
'plugin:jest/recommended',
16+
'prettier',
17+
],
18+
parserOptions: {
19+
ecmaVersion: 'latest',
20+
sourceType: 'module',
21+
},
22+
settings: {
23+
'import/resolver': {
24+
typescript: {
25+
project: true,
26+
},
27+
node: {
28+
project: true,
29+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
30+
},
31+
},
32+
},
33+
ignorePatterns: ['build/**/*', 'dist/**/*', 'coverage/**/*'],
34+
plugins: [
35+
'@typescript-eslint',
36+
'eslint-comments',
37+
'unused-imports',
38+
'no-barrel-files',
39+
],
40+
rules: {
41+
// TypeScript rules
42+
'@typescript-eslint/no-empty-object-type': 'error',
43+
'@typescript-eslint/no-explicit-any': 'error',
44+
'@typescript-eslint/no-require-imports': 'error',
45+
// Handled by "unused-imports/no-unused-vars" instead.
46+
'@typescript-eslint/no-unused-vars': 'off',
47+
'@typescript-eslint/no-floating-promises': 'error',
48+
'no-barrel-files/no-barrel-files': 'error',
49+
// Import rules
50+
'import/extensions': [
51+
'error',
52+
'never',
53+
{
54+
json: 'always',
55+
},
56+
],
57+
'import/named': 'error',
58+
'import/no-cycle': 'error',
59+
'import/no-extraneous-dependencies': [
60+
'error',
61+
{
62+
devDependencies: true,
63+
packageDir: ['.', '../..'], // Include the workspace root package.json
64+
},
65+
],
66+
'import/no-default-export': 'error',
67+
'import/no-unresolved': [
68+
'error',
69+
{
70+
ignore: ['^@factory/'],
71+
},
72+
],
73+
'import/order': [
74+
'error',
75+
{
76+
groups: [
77+
'builtin',
78+
'external',
79+
'internal',
80+
['parent', 'sibling'],
81+
'index',
82+
'type',
83+
],
84+
pathGroups: [
85+
{
86+
pattern: '@/**',
87+
group: 'parent',
88+
},
89+
],
90+
distinctGroup: false,
91+
'newlines-between': 'always',
92+
alphabetize: {
93+
order: 'asc',
94+
caseInsensitive: true,
95+
},
96+
},
97+
],
98+
'eslint-comments/no-unused-disable': 'error',
99+
'no-void': [
100+
'error',
101+
{
102+
allowAsStatement: true,
103+
},
104+
],
105+
'unused-imports/no-unused-imports': 'error',
106+
'unused-imports/no-unused-vars': [
107+
'error',
108+
{
109+
vars: 'all',
110+
varsIgnorePattern: '^_',
111+
args: 'after-used',
112+
argsIgnorePattern: '^_',
113+
ignoreRestSiblings: false,
114+
caughtErrorsIgnorePattern: '^_',
115+
},
116+
],
117+
'prefer-arrow-callback': ['error', { allowNamedFunctions: true }],
118+
// General rules
119+
'class-methods-use-this': 'error',
120+
'default-case': 'error',
121+
'no-console': 'error',
122+
'no-constant-condition': [
123+
'error',
124+
{
125+
checkLoops: false,
126+
},
127+
],
128+
'no-param-reassign': [
129+
'error',
130+
{
131+
props: false,
132+
},
133+
],
134+
'no-restricted-globals': 'error',
135+
'no-promise-executor-return': 'error',
136+
'prefer-promise-reject-errors': 'error',
137+
'jest/expect-expect': 'error',
138+
// Covered by unused-imports
139+
'no-unused-vars': 'off',
140+
},
141+
};

0 commit comments

Comments
 (0)