Skip to content

Commit 71e42b2

Browse files
VdustRclaude
andauthored
docs: add contributing guide and CLAUDE.md (#32)
* docs: add contributing guide and CLAUDE.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: add changeset Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: improve command descriptions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent eddf769 commit 71e42b2

File tree

3 files changed

+132
-5
lines changed

3 files changed

+132
-5
lines changed

.changeset/docs-contributing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@vp-tw/eslint-config": patch
3+
---
4+
5+
Add contributing guide and CLAUDE.md

CLAUDE.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# ESLint Config Development Guide
2+
3+
## Architecture
4+
5+
```
6+
packages/eslint-config/src/
7+
├── vdustr.ts # Main entry point, orchestrates all configs
8+
├── configs/ # Optional feature configs (emotion, mdx, prettier, etc.)
9+
├── extends/ # Extensions for antfu configs (react, yaml, etc.)
10+
├── lib/ # Dynamic import wrappers for optional dependencies
11+
├── utils/ # Shared utilities (mergeConfig, extendsConfig, etc.)
12+
└── types.ts # Type definitions
13+
```
14+
15+
## Key Patterns
16+
17+
### Dynamic Imports for Optional Dependencies
18+
19+
Optional ESLint plugins must use dynamic imports to avoid loading when disabled:
20+
21+
```typescript
22+
// src/lib/eslint-react.ts
23+
import type EslintReact from "@eslint-react/eslint-plugin";
24+
import { interopDefault } from "@antfu/eslint-config";
25+
26+
// IMPORTANT: Explicit return type required to avoid TS2742 build errors
27+
const eslintReact = (): Promise<typeof EslintReact> =>
28+
interopDefault(import("@eslint-react/eslint-plugin"));
29+
30+
export { eslintReact };
31+
```
32+
33+
**Why explicit types?** Without them, TypeScript cannot infer types referencing internal modules (e.g., `@eslint-react/shared`), causing TS2742 errors during `unbuild`.
34+
35+
### extendsConfig Pattern
36+
37+
Use `extendsConfig` to extend antfu's configs conditionally:
38+
39+
```typescript
40+
extendsConfig(composer, "antfu/react/rules", async (config) => {
41+
// Only executes if "antfu/react/rules" exists
42+
const plugin = await importPlugin();
43+
return [config, modifiedConfig];
44+
});
45+
```
46+
47+
### Config Structure
48+
49+
- `configs/` - Standalone configs that use `config.append()`, return arrays
50+
- `extends/` - Modify existing antfu configs via `extendsConfig()`
51+
- `lib/` - Dynamic import wrappers, always require explicit return types
52+
53+
## Commands
54+
55+
```bash
56+
pnpm build # Build @vp-tw/eslint-config (in packages/eslint-config)
57+
pnpm test # Run tests for @vp-tw/eslint-config
58+
pnpm run checkTypes # Type check entire workspace (root)
59+
pnpm lint # Lint entire workspace (root)
60+
```
61+
62+
## Release
63+
64+
Managed by changesets. CI auto-publishes on main branch merge.
65+
66+
```bash
67+
pnpm changeset # Create changeset (interactive)
68+
# Or manually create .changeset/<name>.md
69+
```
70+
71+
## Common Issues
72+
73+
### TS2742: Inferred type cannot be named
74+
75+
**Cause:** Dynamic import returns type referencing internal module.
76+
**Fix:** Add explicit return type annotation.
77+
78+
```typescript
79+
// Bad - causes TS2742
80+
const fn = () => interopDefault(import("pkg"));
81+
82+
// Good
83+
const fn = (): Promise<(typeof import("pkg"))["default"]> => interopDefault(import("pkg"));
84+
```
85+
86+
### Feature not loading when enabled
87+
88+
Check `vdustr.ts` for conditional logic. Features disabled by default need explicit enable check:
89+
90+
```typescript
91+
const reactEnabled = Boolean(antfuOptions?.react ?? false);
92+
if (reactEnabled) {
93+
react(config, vpOptions?.extends?.react);
94+
}
95+
```

README.md

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,43 @@ export default vdustr({
8585

8686
Automatically sorts keys in `pnpm-workspace.yaml` alphabetically using `yaml/sort-keys` rule.
8787

88-
## Release
88+
## Contributing
89+
90+
### Development
91+
92+
```bash
93+
pnpm install # Install dependencies
94+
pnpm build # Build @vp-tw/eslint-config (in packages/eslint-config)
95+
pnpm test # Run tests for @vp-tw/eslint-config
96+
pnpm run checkTypes # Type check entire workspace
97+
pnpm lint # Lint entire workspace
98+
```
99+
100+
### Release
101+
102+
Managed by [changesets](https://github.com/changesets/changesets). CI auto-publishes when merged to main.
89103

90104
```bash
91-
pnpm -w v:patch # or
92-
pnpm -w v:minor # or
93-
pnpm -w v:major
105+
pnpm changeset # Create changeset interactively
106+
```
107+
108+
### Adding Dynamic Import Wrappers
109+
110+
When adding support for optional ESLint plugins, create a wrapper in `src/lib/`:
94111

95-
pnpm -r publish
112+
```typescript
113+
// src/lib/my-plugin.ts
114+
import type MyPlugin from "eslint-plugin-my";
115+
import { interopDefault } from "@antfu/eslint-config";
116+
117+
// Explicit return type required to avoid TS2742 build errors
118+
const myPlugin = (): Promise<typeof MyPlugin> => interopDefault(import("eslint-plugin-my"));
119+
120+
export { myPlugin };
96121
```
97122

123+
See [CLAUDE.md](./CLAUDE.md) for detailed architecture and patterns.
124+
98125
## License
99126

100127
MIT © ViPro <vdustr@gmail.com> (<http://vdustr.dev>)

0 commit comments

Comments
 (0)