Skip to content

Commit 3f4c235

Browse files
authored
chore: add coderabbit and cursor rules (#272)
## Summary by CodeRabbit - **Documentation** - Added comprehensive documentation and configuration files outlining coding standards, best practices, and guidelines for TypeScript development, including naming conventions, error handling, property mutability, return types, and library installation. - Introduced rules for code structure, export practices, discriminated unions, enums, JSDoc usage, and more. - Provided clear examples and explanations to support consistent and maintainable code across the project. - **Chores** - Added a configuration file to enable and configure various code quality and review tools, linters, and integrations for automated code analysis and workflow enhancements.
1 parent 23e698a commit 3f4c235

16 files changed

+689
-0
lines changed

.coderabbit.yaml

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
language: en-US
2+
tone_instructions: ""
3+
early_access: false
4+
enable_free_tier: true
5+
reviews:
6+
profile: chill
7+
request_changes_workflow: true
8+
high_level_summary: true
9+
high_level_summary_placeholder: "@coderabbitai summary"
10+
high_level_summary_in_walkthrough: false
11+
auto_title_placeholder: "@coderabbitai"
12+
auto_title_instructions: ""
13+
review_status: true
14+
commit_status: true
15+
fail_commit_status: false
16+
collapse_walkthrough: false
17+
changed_files_summary: true
18+
sequence_diagrams: true
19+
assess_linked_issues: true
20+
related_issues: true
21+
related_prs: true
22+
suggested_labels: true
23+
auto_apply_labels: false
24+
suggested_reviewers: true
25+
auto_assign_reviewers: false
26+
poem: false
27+
labeling_instructions: []
28+
path_filters: []
29+
path_instructions: []
30+
abort_on_close: true
31+
disable_cache: false
32+
auto_review:
33+
enabled: true
34+
auto_incremental_review: true
35+
ignore_title_keywords:
36+
- WIP
37+
- chore(release)
38+
labels: []
39+
drafts: false
40+
base_branches: []
41+
finishing_touches:
42+
docstrings:
43+
enabled: true
44+
unit_tests:
45+
enabled: true
46+
tools:
47+
ast-grep:
48+
rule_dirs: []
49+
util_dirs: []
50+
essential_rules: true
51+
packages: []
52+
shellcheck:
53+
enabled: true
54+
ruff:
55+
enabled: true
56+
markdownlint:
57+
enabled: true
58+
github-checks:
59+
enabled: true
60+
timeout_ms: 90000
61+
languagetool:
62+
enabled: true
63+
enabled_rules: []
64+
disabled_rules: []
65+
enabled_categories: []
66+
disabled_categories: []
67+
enabled_only: false
68+
level: default
69+
biome:
70+
enabled: true
71+
hadolint:
72+
enabled: true
73+
swiftlint:
74+
enabled: true
75+
phpstan:
76+
enabled: true
77+
level: default
78+
golangci-lint:
79+
enabled: true
80+
yamllint:
81+
enabled: true
82+
gitleaks:
83+
enabled: true
84+
checkov:
85+
enabled: true
86+
detekt:
87+
enabled: true
88+
eslint:
89+
enabled: true
90+
rubocop:
91+
enabled: true
92+
buf:
93+
enabled: true
94+
regal:
95+
enabled: true
96+
actionlint:
97+
enabled: true
98+
pmd:
99+
enabled: true
100+
cppcheck:
101+
enabled: true
102+
semgrep:
103+
enabled: true
104+
circleci:
105+
enabled: true
106+
sqlfluff:
107+
enabled: true
108+
prismaLint:
109+
enabled: true
110+
oxc:
111+
enabled: true
112+
shopifyThemeCheck:
113+
enabled: true
114+
luacheck:
115+
enabled: true
116+
chat:
117+
auto_reply: true
118+
integrations:
119+
jira:
120+
usage: auto
121+
linear:
122+
usage: auto
123+
knowledge_base:
124+
opt_out: false
125+
web_search:
126+
enabled: true
127+
learnings:
128+
scope: auto
129+
issues:
130+
scope: auto
131+
jira:
132+
usage: auto
133+
project_keys: []
134+
linear:
135+
usage: auto
136+
team_keys: []
137+
pull_requests:
138+
scope: auto
139+
code_generation:
140+
docstrings:
141+
language: en-US
142+
path_instructions: []
143+
unit_tests:
144+
path_instructions: []
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
description: Any inside generic functions
3+
globs: **/*.ts,**/*.tsx
4+
alwaysApply: false
5+
---
6+
# Any inside generic functions
7+
8+
But when building generic functions, you may need to use any inside the function body.
9+
10+
This is because TypeScript often cannot match your runtime logic to the logic done inside your types.
11+
12+
One example:
13+
14+
```ts
15+
const youSayGoodbyeISayHello = <TInput extends 'goodbye' | 'hello'>(
16+
input: TInput,
17+
): TInput extends 'hello' ? 'goodbye' : 'hello' => {
18+
if (input === 'goodbye') {
19+
return 'hello'; // Error!
20+
}
21+
return 'goodbye'; // Error!
22+
};
23+
```
24+
25+
On the type level (and the runtime), this function returns `goodbye` when the input is `hello`.
26+
27+
There is no way to make this work concisely in TypeScript.
28+
29+
So using `any` is the most concise solution:
30+
31+
```ts
32+
const youSayGoodbyeISayHello = <TInput extends 'goodbye' | 'hello'>(
33+
input: TInput,
34+
): TInput extends 'hello' ? 'goodbye' : 'hello' => {
35+
if (input === 'goodbye') {
36+
return 'hello' as any;
37+
}
38+
return 'goodbye' as any;
39+
};
40+
```
41+
42+
Outside of generic functions, use `any` extremely sparingly.

.cursor/rules/default-exports.mdc

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
description: Default export
3+
globs: **/*.ts,**/*.tsx
4+
alwaysApply: false
5+
---
6+
# Default export
7+
8+
Unless explicitly required by the framework, do not use default exports.
9+
10+
```tsx
11+
// BAD
12+
export default function myFunction() {
13+
return <div>Hello</div>;
14+
}
15+
```
16+
17+
```tsx
18+
// GOOD
19+
export function myFunction() {
20+
return <div>Hello</div>;
21+
}
22+
```
23+
24+
Default exports create confusion from the importing file.
25+
26+
```ts
27+
// BAD
28+
import myFunction from './my-function';
29+
```
30+
31+
```ts
32+
// GOOD
33+
import { myFunction } from './my-function';
34+
```
35+
36+
There are certain situations where a framework may require a default export. For instance, Next.js requires a default export for pages.
37+
38+
```tsx
39+
// This is fine, if required by the framework
40+
export default function MyPage() {
41+
return <div>Hello</div>;
42+
}
43+
```

.cursor/rules/default-typescript.mdc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
description: Default Typescript
3+
globs: **/*.ts,**/*.tsx
4+
alwaysApply: false
5+
---
6+
# Default Typescript
7+
8+
## Key Principles
9+
10+
- Use TypeScript for all code. Prefer interfaces over types.
11+
- Follow the ESLint rules.
12+
- Use "function" keyword for pure functions.
13+
- File structure: Exported component, subcomponents, helpers, static content, types.
14+
- Avoid unnecessary curly braces in conditional statements.
15+
- For single-line statements in conditionals, omit curly braces.
16+
- Use concise, one-line syntax for simple conditional statements (e.g., if (condition) doSomething()).
17+
18+
## Error Handling and Validation
19+
20+
- Prioritize error handling and edge cases:
21+
- Handle errors and edge cases at the beginning of functions.
22+
- Use early returns for error conditions to avoid deeply nested if statements.
23+
- Place the happy path last in the function for improved readability.
24+
- Avoid unnecessary else statements; use if-return pattern instead.
25+
- Use guard clauses to handle preconditions and invalid states early.
26+
- Implement proper error logging and user-friendly error messages.
27+
- Consider using custom error types or error factories for consistent error handling.
28+
29+
## Security and Performance
30+
31+
- Implement proper error handling, user input validation, and secure coding practices.
32+
- Follow performance optimization techniques, such as reducing load times and improving rendering efficiency.
33+
34+
## Documentation
35+
36+
- Provide clear and concise comments for complex logic.
37+
- Use JSDoc comments for functions and components to improve IDE intellisense.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
description: Discriminated unions
3+
globs: **/*.ts,**/*.tsx
4+
alwaysApply: false
5+
---
6+
# Discriminated unions
7+
8+
Proactively use discriminated unions to model data that can be in one of a few different shapes.
9+
10+
For example, when sending events between environments:
11+
12+
```ts
13+
interface UserCreatedEvent {
14+
data: { email: string; id: string };
15+
type: 'user.created';
16+
}
17+
18+
interface UserDeletedEvent {
19+
data: { id: string };
20+
type: 'user.deleted';
21+
}
22+
23+
type Event = UserCreatedEvent | UserDeletedEvent;
24+
```
25+
26+
Use switch statements to handle the results of discriminated unions:
27+
28+
```ts
29+
const handleEvent = (event: Event) => {
30+
switch (event.type) {
31+
case 'user.created': {
32+
console.log(event.data.email);
33+
break;
34+
}
35+
case 'user.deleted': {
36+
console.log(event.data.id);
37+
break;
38+
}
39+
}
40+
};
41+
```
42+
43+
Use discriminated unions to prevent the 'bag of optionals' problem.
44+
45+
For example, when describing a fetching state:
46+
47+
```ts
48+
// BAD - allows impossible states
49+
interface FetchingState<TData> {
50+
data?: TData;
51+
error?: Error;
52+
status: 'error' | 'idle' | 'loading' | 'success';
53+
}
54+
55+
// GOOD - prevents impossible states
56+
type FetchingState<TData> =
57+
| { data: TData; status: 'success' }
58+
| { error: Error; status: 'error' }
59+
| { status: 'idle' }
60+
| { status: 'loading' };
61+
```

.cursor/rules/enums.mdc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
description: Enums
3+
globs: **/*.ts,**/*.tsx
4+
alwaysApply: false
5+
---
6+
# Enums
7+
8+
Do not introduce new enums into the codebase. Retain existing enums.
9+
10+
If you require enum-like behaviour, use an `as const` object:
11+
12+
```ts
13+
const backendToFrontendEnum = {
14+
md: 'MEDIUM',
15+
sm: 'SMALL',
16+
xs: 'EXTRA_SMALL',
17+
} as const;
18+
19+
type LowerCaseEnum = keyof typeof backendToFrontendEnum; // "xs" | "sm" | "md"
20+
21+
type UpperCaseEnum = (typeof backendToFrontendEnum)[LowerCaseEnum]; // "EXTRA_SMALL" | "SMALL" | "MEDIUM"
22+
```
23+
24+
Remember that numeric enums behave differently to string enums. Numeric enums produce a reverse mapping:
25+
26+
```ts
27+
enum Direction {
28+
Up,
29+
Down,
30+
Left,
31+
Right,
32+
}
33+
34+
const direction = Direction.Up; // 0
35+
const directionName = Direction[0]; // "Up"
36+
```
37+
38+
This means that the enum `Direction` above will have eight keys instead of four.
39+
40+
```ts
41+
enum Direction {
42+
Up,
43+
Down,
44+
Left,
45+
Right,
46+
}
47+
48+
Object.keys(Direction).length; // 8
49+
```

0 commit comments

Comments
 (0)