@activatus/code-standards 0.0.0-stage → 2.0.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 (183) hide show
  1. package/README.md +200 -2
  2. package/docs/Guides/_category_.json +4 -0
  3. package/docs/Guides/component-library-workflow.md +182 -0
  4. package/docs/Guides/migrating.md +144 -0
  5. package/docs/Guides/setup.md +130 -0
  6. package/docs/Standards/_category_.json +4 -0
  7. package/docs/Standards/agent-skills.md +125 -0
  8. package/docs/Standards/agent-specs.md +89 -0
  9. package/docs/Standards/branch-naming.md +66 -0
  10. package/docs/Standards/conventional-commits.md +189 -0
  11. package/docs/Standards/direnv.mdx +249 -0
  12. package/docs/Standards/documentation.md +311 -0
  13. package/docs/Standards/editorconfig.md +72 -0
  14. package/docs/Standards/eslint.md +709 -0
  15. package/docs/Standards/human-readable-names.md +234 -0
  16. package/docs/Standards/lint-errors.md +139 -0
  17. package/docs/Standards/prettier.md +97 -0
  18. package/docs/Standards/readable-code.md +540 -0
  19. package/docs/Standards/stylelint.md +178 -0
  20. package/docs/Standards/styling.md +284 -0
  21. package/docs/Standards/tech-stack.md +156 -0
  22. package/docs/Structure/_category_.json +4 -0
  23. package/docs/Structure/api-routes.md +118 -0
  24. package/docs/Structure/component-organization.md +519 -0
  25. package/docs/Structure/folder-structure.md +353 -0
  26. package/docs/Structure/import-organization.md +158 -0
  27. package/docs/Structure/naming-conventions.md +336 -0
  28. package/docs/design-system-components.md +117 -0
  29. package/docs/intro.md +46 -0
  30. package/docs/ontology.md +132 -0
  31. package/docs/templates.mdx +419 -0
  32. package/docs/version-history.md +211 -0
  33. package/package.json +56 -3
  34. package/static/templates/.commitlintrc.json +3 -0
  35. package/static/templates/.editorconfig +28 -0
  36. package/static/templates/.envrc +25 -0
  37. package/static/templates/.nvmrc +1 -0
  38. package/static/templates/AGENTS.md +160 -0
  39. package/static/templates/decision-doc.md +19 -0
  40. package/static/templates/docs/ai/agent-harness.md +17 -0
  41. package/static/templates/docs/ai/agents.md +17 -0
  42. package/static/templates/docs/ai/architecture.md +17 -0
  43. package/static/templates/docs/ai/context.md +17 -0
  44. package/static/templates/docs/ai/model-routing.md +17 -0
  45. package/static/templates/docs/ai/models.md +17 -0
  46. package/static/templates/docs/ai/retrieval.md +17 -0
  47. package/static/templates/docs/ai/tools.md +17 -0
  48. package/static/templates/docs/architecture/authentication.md +17 -0
  49. package/static/templates/docs/architecture/backend.md +17 -0
  50. package/static/templates/docs/architecture/background-jobs.md +17 -0
  51. package/static/templates/docs/architecture/backups.md +17 -0
  52. package/static/templates/docs/architecture/caching.md +17 -0
  53. package/static/templates/docs/architecture/ci-cd.md +17 -0
  54. package/static/templates/docs/architecture/disaster-recovery.md +17 -0
  55. package/static/templates/docs/architecture/environments.md +17 -0
  56. package/static/templates/docs/architecture/frontend.md +17 -0
  57. package/static/templates/docs/architecture/hosting.md +17 -0
  58. package/static/templates/docs/architecture/observability.md +17 -0
  59. package/static/templates/docs/architecture/realtime.md +17 -0
  60. package/static/templates/docs/architecture/search.md +17 -0
  61. package/static/templates/docs/architecture/services.md +17 -0
  62. package/static/templates/docs/architecture/state-management.md +17 -0
  63. package/static/templates/docs/architecture/storage.md +17 -0
  64. package/static/templates/docs/architecture/system.md +17 -0
  65. package/static/templates/docs/business/buying-trigger.md +17 -0
  66. package/static/templates/docs/business/customer-value.md +17 -0
  67. package/static/templates/docs/business/customer.md +17 -0
  68. package/static/templates/docs/business/defensibility.md +17 -0
  69. package/static/templates/docs/business/growth.md +17 -0
  70. package/static/templates/docs/business/pricing.md +17 -0
  71. package/static/templates/docs/business/revenue-model.md +17 -0
  72. package/static/templates/docs/business/unit-economics.md +17 -0
  73. package/static/templates/docs/data/analytics.md +17 -0
  74. package/static/templates/docs/data/audit.md +17 -0
  75. package/static/templates/docs/data/database.md +17 -0
  76. package/static/templates/docs/data/indexing.md +17 -0
  77. package/static/templates/docs/data/migrations.md +17 -0
  78. package/static/templates/docs/data/model.md +17 -0
  79. package/static/templates/docs/data/retention.md +17 -0
  80. package/static/templates/docs/data/schema.md +17 -0
  81. package/static/templates/docs/deployment/approval.md +17 -0
  82. package/static/templates/docs/deployment/live-verification.md +17 -0
  83. package/static/templates/docs/deployment/process.md +17 -0
  84. package/static/templates/docs/deployment/rollback.md +17 -0
  85. package/static/templates/docs/design/design-system.md +17 -0
  86. package/static/templates/docs/design/errors.md +17 -0
  87. package/static/templates/docs/design/feedback.md +17 -0
  88. package/static/templates/docs/design/interactions.md +17 -0
  89. package/static/templates/docs/design/layout.md +17 -0
  90. package/static/templates/docs/design/navigation.md +17 -0
  91. package/static/templates/docs/design/principles.md +17 -0
  92. package/static/templates/docs/design/responsive.md +17 -0
  93. package/static/templates/docs/development/branching.md +17 -0
  94. package/static/templates/docs/development/code-quality.md +17 -0
  95. package/static/templates/docs/development/coding-standards.md +17 -0
  96. package/static/templates/docs/development/commits.md +17 -0
  97. package/static/templates/docs/development/merge-strategy.md +17 -0
  98. package/static/templates/docs/development/process.md +17 -0
  99. package/static/templates/docs/development/pull-requests.md +17 -0
  100. package/static/templates/docs/experience/accessibility.md +17 -0
  101. package/static/templates/docs/experience/aha-moment.md +17 -0
  102. package/static/templates/docs/experience/anti-experience.md +17 -0
  103. package/static/templates/docs/experience/friction.md +17 -0
  104. package/static/templates/docs/experience/outcomes.md +17 -0
  105. package/static/templates/docs/experience/principles.md +17 -0
  106. package/static/templates/docs/experience/retention.md +17 -0
  107. package/static/templates/docs/experience/sharing.md +17 -0
  108. package/static/templates/docs/overview/how-it-works.md +17 -0
  109. package/static/templates/docs/overview/what-is-it.md +17 -0
  110. package/static/templates/docs/overview/writing-docs.md +16 -0
  111. package/static/templates/docs/pitch/alternatives.md +17 -0
  112. package/static/templates/docs/pitch/assumptions.md +17 -0
  113. package/static/templates/docs/pitch/audience.md +17 -0
  114. package/static/templates/docs/pitch/concept.md +17 -0
  115. package/static/templates/docs/pitch/differentiators.md +17 -0
  116. package/static/templates/docs/pitch/outcomes.md +17 -0
  117. package/static/templates/docs/pitch/problem.md +17 -0
  118. package/static/templates/docs/pitch/product-market-fit.md +17 -0
  119. package/static/templates/docs/pitch/success-criteria.md +17 -0
  120. package/static/templates/docs/pitch/validation.md +17 -0
  121. package/static/templates/docs/pitch/value-proposition.md +17 -0
  122. package/static/templates/docs/pitch/vision.md +17 -0
  123. package/static/templates/docs/scope/core.md +17 -0
  124. package/static/templates/docs/scope/exclusions.md +17 -0
  125. package/static/templates/docs/scope/future.md +17 -0
  126. package/static/templates/docs/scope/launch.md +17 -0
  127. package/static/templates/docs/scope/post-launch.md +17 -0
  128. package/static/templates/docs/scope/priorities.md +17 -0
  129. package/static/templates/docs/scope/quality-bar.md +17 -0
  130. package/static/templates/docs/security/audit.md +17 -0
  131. package/static/templates/docs/security/data-access.md +17 -0
  132. package/static/templates/docs/security/logging.md +17 -0
  133. package/static/templates/docs/security/privacy.md +17 -0
  134. package/static/templates/docs/security/secrets.md +17 -0
  135. package/static/templates/docs/security/threat-model.md +17 -0
  136. package/static/templates/docs/testing/end-to-end.md +17 -0
  137. package/static/templates/docs/testing/integration.md +17 -0
  138. package/static/templates/docs/testing/regression.md +17 -0
  139. package/static/templates/docs/testing/security.md +17 -0
  140. package/static/templates/docs/testing/strategy.md +17 -0
  141. package/static/templates/docs/testing/test-data.md +17 -0
  142. package/static/templates/docs/testing/unit.md +17 -0
  143. package/static/templates/docs/uat/checks.md +17 -0
  144. package/static/templates/docs/uat/strategy.md +17 -0
  145. package/static/templates/docs/users/permissions.md +17 -0
  146. package/static/templates/docs/users/roles.md +17 -0
  147. package/static/templates/docs/users/user-types.md +17 -0
  148. package/static/templates/docs/workflows/assignment.md +17 -0
  149. package/static/templates/docs/workflows/bugfix.md +17 -0
  150. package/static/templates/docs/workflows/dependencies.md +17 -0
  151. package/static/templates/docs/workflows/deployment.md +17 -0
  152. package/static/templates/docs/workflows/development.md +17 -0
  153. package/static/templates/docs/workflows/planning.md +17 -0
  154. package/static/templates/docs/workflows/review.md +17 -0
  155. package/static/templates/docs/workflows/uat.md +17 -0
  156. package/static/templates/docsSite/docusaurus.config.ts +119 -0
  157. package/static/templates/docsSite/gitignore.txt +3 -0
  158. package/static/templates/docsSite/package.json.txt +42 -0
  159. package/static/templates/docsSite/pnpm-workspace.yaml +2 -0
  160. package/static/templates/docsSite/sidebars.ts +8 -0
  161. package/static/templates/docsSite/src/css/custom.css +1 -0
  162. package/static/templates/docsSite/src/pages/index.tsx +9 -0
  163. package/static/templates/docsSite/static/images/logo.svg +4 -0
  164. package/static/templates/docsSite/tsconfig.json +7 -0
  165. package/static/templates/eslint/base/eslint.config.mjs +79 -0
  166. package/static/templates/eslint/nextjs/eslint.config.mjs +137 -0
  167. package/static/templates/eslint/react/eslint.config.mjs +138 -0
  168. package/static/templates/eslint/typescript/eslint.config.mjs +126 -0
  169. package/static/templates/globals.css +16 -0
  170. package/static/templates/husky/commit-msg +1 -0
  171. package/static/templates/husky/pre-commit +1 -0
  172. package/static/templates/next.config.mjs +18 -0
  173. package/static/templates/prettier.config.js +17 -0
  174. package/static/templates/skills/codeReview.md +31 -0
  175. package/static/templates/skills/format.md +18 -0
  176. package/static/templates/skills/lint.md +21 -0
  177. package/static/templates/skills/lintFix.md +24 -0
  178. package/static/templates/skills/securityAudit.md +28 -0
  179. package/static/templates/skills/test.md +24 -0
  180. package/static/templates/skills/typescript.md +28 -0
  181. package/static/templates/skills/updateLayout.md +20 -0
  182. package/static/templates/stylelint/css/stylelint.config.mjs +28 -0
  183. package/static/templates/stylelint/scss/stylelint.config.mjs +10 -0
@@ -0,0 +1,234 @@
1
+ ---
2
+ sidebar_position: -1
3
+ sidebar_label: "Human-Readable Names"
4
+ ---
5
+
6
+ # Human-Readable Names
7
+
8
+ **Every name we write is made of whole words a person can read out loud.** Variables, function parameters, props, types, constants, form fields, files, folders, routes, database columns, scripts and environment variables — everything. No shortened words, no single letters, no numbered names — not even for a loop counter or an event handler.
9
+
10
+ Anyone reading the code should never have to guess what a name stands for.
11
+
12
+ This applies to everyone writing code, **including AI agents**. An agent copies the examples it sees, so every example in these standards follows this rule too.
13
+
14
+ ## Never / Always
15
+
16
+ | Never | Always |
17
+ | -------------------------- | ---------------------------------------------- |
18
+ | `btn`, `msg`, `val` | `button`, `message`, `value` |
19
+ | `(e) =>`, `(item, i) =>` | `(event) =>`, `(item, index) =>` |
20
+ | `acc` in a `reduce` | `runningTotal` — what it actually holds |
21
+ | `args`, `params` (our own) | `commandArguments`, `searchFilters` |
22
+ | `inputRef` | `inputReference` |
23
+ | `inputRef` | `inputReference` |
24
+ | `cwd` (our own variable) | `workingDirectory` |
25
+ | `deps`, `repo`, `env` | `dependencies`, `repository`, `environment` |
26
+ | `timeoutMs` | `timeoutMilliseconds` |
27
+ | `MAX_RETRY_ATTEMPTS` | `MAXIMUM_RETRY_ATTEMPTS` |
28
+ | `size: "sm" \| "lg"` | `size: "small" \| "large"` |
29
+ | `<T>` | `<ItemType>` |
30
+ | `name="email1"` | `name="emailAddress"` |
31
+ | `helpers.ts`, `misc.ts` | `formatCurrency.ts` — named after what it does |
32
+ | `lib/` | `library/` |
33
+ | `helpers/`, `utilities/` | `utils/` |
34
+ | `useAuth`, `authStore` | `useAuthentication`, `authenticationStore` |
35
+ | `STRIPE_SK` | `STRIPE_SECRET_KEY` |
36
+
37
+ ## Where it applies
38
+
39
+ Everything that has a name:
40
+
41
+ | Thing | ✅ Human-readable | ❌ Not |
42
+ | ------------------------------- | ---------------------------------------------------- | ------------------------------------------------- |
43
+ | **Folders** | `accountSettings/`, `invoiceTable/` | `acctSet/`, `misc/`, `stuff/`, `new/` |
44
+ | **Files** | `formatCurrency.ts`, `InvoiceTable.tsx` | `fmtCur.ts`, `utils2.ts`, `helpers.ts`, `temp.ts` |
45
+ | **Components** | `InvoiceTable`, `SubmitButton` | `Tbl`, `Comp1`, `MyComponent`, `Wrapper2` |
46
+ | **Component props** | `isDisabled`, `onUserSelect`, `invoiceTotal` | `dis`, `cb`, `val`, `data` |
47
+ | **Variables** | `userEmailAddress`, `activeUsers` | `addr`, `x`, `temp`, `data`, `res`, `obj` |
48
+ | **Functions** | `calculateOrderTotal`, `sendWelcomeEmail` | `calc`, `doIt`, `process`, `handle` |
49
+ | **Event handlers** | `handleSearchTextChange` | `onChg`, `handler`, `fn` |
50
+ | **Booleans** | `isLoading`, `hasPermission`, `canDelete` | `loading`, `flag`, `ok`, `chk` |
51
+ | **Constants** | `MAXIMUM_RETRY_ATTEMPTS`, `RETRY_DELAY_MILLISECONDS` | `MAX`, `N`, `DELAY` |
52
+ | **Types** | `UserType`, `InvoiceStatusType`, `ButtonProps` | `U`, `Data`, `IProps`, `Obj` |
53
+ | **Generic type parameters** | `<ItemType>`, `<ResponseType>` | `<T>`, `<K, V>` |
54
+ | **Union and enum values** | `"processing" \| "shipped" \| "cancelled"` | `"p" \| "s"`, `1 \| 2 \| 3` |
55
+ | **Form fields** | `name="emailAddress"`, `name="companyName"` | `name="email1"`, `name="fld3"`, `name="q"` |
56
+ | **CSS Module classes** | `.primaryButton`, `.invoiceRow` | `.pb`, `.btn2`, `.wrapper3` |
57
+ | **CSS variables** | `--color-brand-primary` | `--c1`, `--blue2` |
58
+ | **Database tables and columns** | `draft_ticket`, `created_at`, `invoice_total` | `dt`, `col1`, `amt`, `flag` |
59
+ | **API routes** | `/api/calendar-events` | `/api/ce`, `/api/data`, `/api/v2x` |
60
+ | **Environment variables** | `STRIPE_SECRET_KEY`, `DOCS_URL` | `SK`, `KEY2`, `URL_1` |
61
+ | **Test names** | `it("adds a thousands separator")` | `it("works")`, `it("test 1")` |
62
+ | **Branches** | `feat/invoice-export` | `fix/stuff`, `toms-branch` |
63
+ | **Doc files** | `architecture/background-jobs.md` | `arch/bg.md`, `notes2.md` |
64
+ | **Error messages** | `"Enter an email address"` | `"Invalid input"`, `"Error 42"` |
65
+
66
+ The words come from the [Ontology](/ontology) wherever it has a term: reusable functions are in `utils/`, never `helpers/` or `utilities/`. A project's own ontology adds its product words: in Launchpad, a Draft Ticket is `draftTicket`, never `pendingTicket`. The casing comes from [Naming Conventions](/Structure/naming-conventions).
67
+
68
+ ---
69
+
70
+ ## Form fields
71
+
72
+ Form fields are where names slip most, and where they matter most: a field's name travels through the whole system.
73
+
74
+ **One field, one name, everywhere it goes.** The same words name the input, the form's data, the API request, the type and the database column:
75
+
76
+ | Where | Name |
77
+ | ------------------------------- | ---------------------- |
78
+ | Input `name` and `id` | `emailAddress` |
79
+ | Form data and validation schema | `emailAddress` |
80
+ | API request body | `emailAddress` |
81
+ | Type property | `emailAddress: string` |
82
+ | Database column | `email_address` |
83
+
84
+ ```tsx
85
+ // ✅ Good
86
+ <label htmlFor="emailAddress">Email address</label>
87
+ <input id="emailAddress" name="emailAddress" type="email" />
88
+
89
+ <label htmlFor="billingFrequency">Billing frequency</label>
90
+ <select id="billingFrequency" name="billingFrequency">
91
+ <option value="monthly">Monthly</option>
92
+ <option value="yearly">Yearly</option>
93
+ </select>
94
+ ```
95
+
96
+ ```tsx
97
+ // ❌ Bad
98
+ <input id="f3" name="email1" placeholder="Email" />
99
+
100
+ <select name="freq">
101
+ <option value="1">Monthly</option>
102
+ <option value="2">Yearly</option>
103
+ </select>
104
+ ```
105
+
106
+ - **`name` and `id` are full words**, and match each other.
107
+ - **Every field has a visible `<label>`** in plain English. A placeholder is never the label.
108
+ - **Option values are words**, not numbers: `value="monthly"`, not `value="1"`.
109
+ - **Buttons with only an icon get an `aria-label`** that says what they do: `aria-label="Delete invoice"`.
110
+ - **Validation messages name the field and say what to do**: "Enter an email address", not "Required".
111
+
112
+ ---
113
+
114
+ ## `id` is a word
115
+
116
+ **`id` is its own word. Never write it out as `identifier`.**
117
+
118
+ | Where | Write |
119
+ | ---------------------- | ------------------------------- |
120
+ | A property or variable | `id`, `userId`, `draftTicketId` |
121
+ | A list of them | `userIds` |
122
+ | A constant | `DEFAULT_PROJECT_ID` |
123
+ | A database column | `user_id` |
124
+
125
+ - **Case it as a word**: `userId`, never `userID`.
126
+ - **`identifier` means something else.** Use it only when an outside system has a separate field with that name. Linear has both: `id` is its hidden unique code, and `identifier` is the readable `ACT-73`. Writing `identifier` for an `id` would mix the two up.
127
+
128
+ ## Dictionary
129
+
130
+ Some short names are not abbreviations. They are the word people actually say, and the long form would only make the name harder to read. **These are dictionary words, and stay short:**
131
+
132
+ | Word | Means | Example names |
133
+ | ---------------------------- | ------------------------------------------ | ------------------------------------------------- |
134
+ | `id` | A unique id | `userId`, `user_id`, `DEFAULT_PROJECT_ID` |
135
+ | `docs` | A project's documentation | `docs/`, `docsSite/`, `DOCS_URL`, `pnpm docs:dev` |
136
+ | `props` | The values a component takes | `props`, `ButtonProps` |
137
+ | `utils` | Reusable functions that are not components | `utils/`, `utils/formatCurrency/` |
138
+ | `app` | The application | `app/`, `appName` |
139
+ | `url` | A web address | `imageUrl`, `DOCS_URL` |
140
+ | `api` | An application programming interface | `api/`, `apiResponse` |
141
+ | `uat` | User acceptance testing | `uatEnvironment` |
142
+ | `pdf`, `html`, `css`, `json` | File formats | `invoicePdf`, `htmlContent`, `globals.css` |
143
+ | `readme` | A project's README file | `readmeContent` |
144
+
145
+ **Case them as words** in camelCase and PascalCase: `imageUrl`, `apiResponse`, `docsSite` — never `imageURL` or `APIResponse`.
146
+
147
+ **This list is the only back door.** A short name not on it gets written out in full. If people say the long form out loud — "environment", "repository", "application" — write the long form.
148
+
149
+ ### Adding a word to the dictionary
150
+
151
+ When a short name feels like a dictionary word, don't just use it — add it here first:
152
+
153
+ 1. **Ask:** would a non-developer say this word out loud, and know what it means? `docs`: yes. `env`, `repo`, `btn`: no.
154
+ 2. **Add a row** to the table above, in the same pull request as the code that uses it.
155
+ 3. **If ESLint flags the word**, add it to `replacements` in the `unicorn/name-replacements` rule of the [ESLint config](/Standards/eslint), so the linter agrees: `replacements: { docs: false, props: false, utils: false }`.
156
+
157
+ The list is the record. If a word is not on it, it is not a dictionary word yet.
158
+
159
+ ---
160
+
161
+ ## Third-party names
162
+
163
+ **This rule is for the names we write.** It does not cover names that come from someone else's code — a package, a framework, an outside service. Those stay exactly as they are: everyone knows them by that name, their docs use that name, and renaming them breaks the code. Use them as they are where they touch the outside, then **give the value a full-word name as soon as it comes into our code**.
164
+
165
+ | From | Examples |
166
+ | ------------------------- | ----------------------------------------------------------------------------------------------------------- |
167
+ | An outside service's data | Linear's `id`, `identifier` and `pageInfo` |
168
+ | Node and library options | `cwd` in `execFile`, `process.env`, `stdout`, `argv` |
169
+ | React | `ref`, `children`, `useRef`, `useEffect` |
170
+ | shadcn/ui | the `cn` class-name function, and the component files it generates |
171
+ | Next.js | the `app/` folder, `params`, `searchParams`, `LayoutProps`, `generateMetadata` |
172
+ | HTML and CSS | `href`, `src`, `alt`, `tabIndex`, Tailwind classes like `text-sm` |
173
+ | Tools | `node_modules`, `.env.local`, Docusaurus's `src/pages`, Storybook's `args`, the `dev` and `prepare` scripts |
174
+ | A project's own ontology | Its decided product terms, such as Launchpad's `dev_agent` |
175
+
176
+ ```ts
177
+ // ✅ Good — the option keeps its third-party name; our value gets a full-word name
178
+ const workingDirectory = process.cwd();
179
+ const commandArguments = ["lint", "--fix"];
180
+
181
+ execFile("pnpm", commandArguments, { cwd: workingDirectory });
182
+ ```
183
+
184
+ ```ts
185
+ // ❌ Bad — renaming the third-party option breaks the call: execFile ignores "workingDirectory"
186
+ execFile("pnpm", commandArguments, { workingDirectory });
187
+
188
+ // ❌ Bad — the third-party name leaks into our own code
189
+ const cwd = process.cwd();
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Examples in code
195
+
196
+ ```ts
197
+ // ✅ Good
198
+ const userEmailAddress = user.email;
199
+ const isSubmitButtonDisabled = !isFormValid;
200
+
201
+ const calculateOrderTotal = (orderItems: OrderItemType[]) => {
202
+ return orderItems.reduce(
203
+ (runningTotal, orderItem) => runningTotal + orderItem.price,
204
+ 0,
205
+ );
206
+ };
207
+
208
+ users.map((user) => user.name);
209
+ ```
210
+
211
+ ```ts
212
+ // ❌ Bad
213
+ const addr = user.email;
214
+ const btnDis = !valid;
215
+
216
+ const calc = (arr: OrderItemType[]) => {
217
+ return arr.reduce((acc, i) => acc + i.price, 0);
218
+ };
219
+
220
+ users.map((u) => u.name);
221
+ ```
222
+
223
+ ---
224
+
225
+ ## How it is checked
226
+
227
+ | Names | Checked by |
228
+ | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
229
+ | Variables, functions, parameters and file names | ESLint `unicorn/name-replacements` and `unicorn/filename-case` |
230
+ | Type names | ESLint `@typescript-eslint/naming-convention` |
231
+ | CSS variables and CSS Module classes | Stylelint |
232
+ | **Everything else** — folders, props, form fields, union values, database columns, routes, environment variables, test names | **Code review and AI agents.** The linter cannot read these, so every agent and reviewer checks them |
233
+
234
+ ESLint allows the [dictionary](#dictionary) it would otherwise flag (`docs`, `props`, `utils`), and exactly three third-party names as they are — `ref`, `params` and `searchParams`. It still flags any of our own names built from an third-party name, such as `inputRef`.
@@ -0,0 +1,139 @@
1
+ ---
2
+ sidebar_position: 1.5
3
+ sidebar_label: "Fixing Lint Errors"
4
+ ---
5
+
6
+ # Fixing Lint Errors
7
+
8
+ When `pnpm lint` reports an error, find the rule name at the end of the line in the tables below. Each row says what the error means in plain English and how to fix it.
9
+
10
+ ```text
11
+ src/userService.ts
12
+ 12:3 error Dependency cycle detected import-x/no-cycle
13
+ │ │ └── the rule name — look this up below
14
+ │ └── the message
15
+ └── line 12, column 3
16
+ ```
17
+
18
+ ## The golden rule
19
+
20
+ **Fix the code. Never switch the rule off to make the error go away.**
21
+
22
+ A lint error means the code breaks a standard. The fix is always to change the code. Do not add `eslint-disable` comments, do not delete rules from the config, and do not move files into `vendor/` to hide them.
23
+
24
+ There are exactly two rules that may be switched off for one line, and both need a comment saying why — see [the only allowed exceptions](#the-only-allowed-exceptions).
25
+
26
+ This applies to everyone, **including AI agents**. An agent's work is not finished while `pnpm lint` reports errors.
27
+
28
+ ---
29
+
30
+ ## Imports
31
+
32
+ | Rule | What you will see | What it means | How to fix it |
33
+ | -------------------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
34
+ | `import-x/no-cycle` | `Dependency cycle detected` | Two files import each other, directly or through other files. One will load before the other is ready | Move the part both files need into a **third file** that both import. If the cycle goes through an `index.ts`, import the file directly instead. See [Import safety](/Structure/import-organization#import-safety) |
35
+ | `import-x/no-unresolved` | `Unable to resolve path to module '…'` | The file being imported does not exist at that path | Check the spelling and the path. If the file was renamed or moved, update the import |
36
+ | `import-x/no-default-export` | `Prefer named exports` | The file uses `export default` | Change to a named export: `export const formatCurrency = …` |
37
+ | `@typescript-eslint/consistent-type-imports` | `All imports in the declaration are only used as types. Use import type` | A type is imported like a value | Change `import { UserType }` to `import type { UserType }` |
38
+
39
+ ## Order and variables
40
+
41
+ | Rule | What you will see | What it means | How to fix it |
42
+ | ----------------------------------- | ------------------------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
43
+ | `no-use-before-define` | `'formatReport' was used before it was defined` | Something is used above the line that creates it | Move the definition **above** the code that uses it |
44
+ | `no-restricted-syntax` | `Use const. If this value really must be reassigned…` | A variable is declared with `let` | Change `let` to `const`. If the value really must change, see [the allowed exceptions](#the-only-allowed-exceptions) |
45
+ | `no-var` | `Unexpected var, use let or const instead` | A variable is declared with `var` | Change `var` to `const` |
46
+ | `prefer-const` | `'total' is never reassigned. Use 'const' instead` | A `let` variable never changes | Change `let` to `const` |
47
+ | `no-magic-numbers` | `No magic number: 3` | A bare number is used in the logic | Give it a name: `const MAXIMUM_RETRY_ATTEMPTS = 3;` |
48
+ | `unicorn/name-replacements` | ``The variable `btn` should be named `button` `` | A name is shorthand | Rename it to the full English word |
49
+ | `unicorn/no-top-level-side-effects` | `Do not use top-level side effects in exported modules` | The file runs code as it loads | Put the code inside a function and export the function |
50
+
51
+ ## Functions
52
+
53
+ | Rule | What you will see | What it means | How to fix it |
54
+ | ----------------------- | ------------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------ |
55
+ | `func-style` | `Expected a function expression` | The `function` keyword was used | Rewrite as an arrow function: `const name = () => { … };` |
56
+ | `prefer-arrow-callback` | `Unexpected function expression` | A callback uses the `function` keyword | Rewrite the callback as an arrow function |
57
+ | `no-restricted-syntax` | `Use an arrow function` | `const name = function () {}` was used | Rewrite as `const name = () => {}` |
58
+ | `no-restricted-syntax` | `Use a single object parameter when a function needs more than one value` | A function has more than one parameter | Take one object instead: `({ name, emailAddress }: CreateUserProps) =>` |
59
+ | `no-restricted-syntax` | `Use functions, not classes` | A `class` was used | Rewrite it as functions |
60
+ | `max-depth` | `Blocks are nested too deeply (4). Maximum allowed is 3` | `if`s and loops are nested more than three deep | Return early for the error cases, or move the inner part into its own function |
61
+ | `no-nested-ternary` | `Do not nest ternary expressions` | A `? :` sits inside another `? :` | Use an `if`, or move it into its own function |
62
+
63
+ ## Files
64
+
65
+ | Rule | What you will see | What it means | How to fix it |
66
+ | ----------------------- | ------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------- |
67
+ | `max-lines` | `File has too many lines (312). Maximum allowed is 300` | The file is over 300 lines | Split it: move functions to `utils/`, sub-components to their own folders, types to `types.ts` |
68
+ | `unicorn/filename-case` | `Filename is not in camel case or pascal case` | The file name is in the wrong case | Rename it: camelCase for code files, PascalCase for component files |
69
+
70
+ ## Types
71
+
72
+ | Rule | What you will see | What it means | How to fix it |
73
+ | ----------------------------------------------- | ------------------------------------------------------------------ | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
74
+ | `@typescript-eslint/no-explicit-any` | `Unexpected any. Specify a different type` | `any` was used | Use the real type, or `unknown` and then check it |
75
+ | `@typescript-eslint/no-non-null-assertion` | `Forbidden non-null assertion` | `value!` was used | Check that the value exists first: `if (!value) { return; }` |
76
+ | `@typescript-eslint/consistent-type-assertions` | `Do not use any type assertions` | `value as SomeType` was used | Validate the value instead. If a cast is truly needed, see [the allowed exceptions](#the-only-allowed-exceptions) |
77
+ | `@typescript-eslint/naming-convention` | ``Interface name `User` must match the RegExp: /(Props\|Type)$/u`` | A type name does not end in `Props` or `Type` | Rename it: `UserType`, `ButtonProps` |
78
+
79
+ ## React
80
+
81
+ | Rule | What you will see | What it means | How to fix it |
82
+ | ------------------------------------- | ------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------ |
83
+ | `react/jsx-no-bind` | `JSX props should not use arrow functions` | A function is written inside the JSX, or passed without `useCallback` | Declare it above with `useCallback` and pass it by name |
84
+ | `react/no-multi-comp` | `Declare only one React component per file` | The file has more than one component | Move the second component to its own folder |
85
+ | `react/function-component-definition` | An error naming this rule | A component is written with the `function` keyword | Rewrite it as an arrow function. `pnpm lint:fix` does this automatically |
86
+
87
+ ## Comments
88
+
89
+ | Rule | What you will see | What it means | How to fix it |
90
+ | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------- |
91
+ | `@eslint-community/eslint-comments/require-description` | `Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary` | An `eslint-disable` comment has no reason | Add the reason after `--`. Better: remove the comment and fix the code |
92
+
93
+ ---
94
+
95
+ ## The only allowed exceptions
96
+
97
+ Two rules may be switched off for a single line. Both need the reason written after `--`, and ESLint rejects the comment without one.
98
+
99
+ ### A variable that must be reassigned
100
+
101
+ Always use `const`. When a value genuinely has to change — a running total, a retry counter — use `let` and say why:
102
+
103
+ ```ts
104
+ // eslint-disable-next-line no-restricted-syntax -- the running total is built up across the loop
105
+ let runningTotal = 0;
106
+ ```
107
+
108
+ Before reaching for `let`, check whether `const` with `map`, `filter` or `reduce` does the job. It usually does.
109
+
110
+ ### A type cast that cannot be avoided
111
+
112
+ ```ts
113
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- the API returns untyped JSON; validated by parseUser below
114
+ const user = response.data as UserType;
115
+ ```
116
+
117
+ Nothing else is switched off. If another rule seems impossible to satisfy, the code needs restructuring — ask before disabling it.
118
+
119
+ ---
120
+
121
+ ## Errors that stop ESLint running
122
+
123
+ | What you will see | What it means | How to fix it |
124
+ | ------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------- |
125
+ | `typescript-eslint does not support TS 7.0` | The linter cannot run against TypeScript 7 yet | See the [TypeScript 7 note](/Standards/eslint#installation) on the ESLint page |
126
+ | `contextOrFilename.getFilename is not a function` | The React plugin cannot detect the React version | Set `settings.react.version` to the project's React version instead of `"detect"` |
127
+ | `Cannot find module '…'` | A lint package is not installed | Run the install commands on the [ESLint page](/Standards/eslint#installation) |
128
+
129
+ ---
130
+
131
+ ## How errors are caught
132
+
133
+ Lint runs in three places, so a broken standard is caught before it reaches `main`:
134
+
135
+ | Where | When | What happens on an error |
136
+ | ---------------------------------- | ------------------------- | ------------------------------------------------------------------------ |
137
+ | **AI agents** | Before finishing any task | The agent fixes the error. Its work is not done until `pnpm lint` passes |
138
+ | **Git hook** (`.husky/pre-commit`) | When a person commits | The commit is refused until the errors are fixed |
139
+ | **CI** | On every pull request | The pull request cannot be merged |
@@ -0,0 +1,97 @@
1
+ ---
2
+ sidebar_position: 2
3
+ sidebar_label: "Prettier"
4
+ ---
5
+
6
+ # Prettier Configuration
7
+
8
+ A single shared Prettier config keeps formatting consistent and eliminates "style" discussion in code review.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pnpm add -D prettier prettier-plugin-tailwindcss
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ Create `prettier.config.js` in your project root:
19
+
20
+ ```js title="prettier.config.js"
21
+ /** @type {import("prettier").Config & import("prettier-plugin-tailwindcss").PluginOptions} */
22
+ const config = {
23
+ printWidth: 100,
24
+ tabWidth: 2,
25
+ useTabs: false,
26
+ singleQuote: false,
27
+ trailingComma: "all",
28
+ bracketSpacing: true,
29
+ bracketSameLine: false,
30
+ arrowParens: "always",
31
+ semi: true,
32
+ endOfLine: "lf",
33
+ plugins: ["prettier-plugin-tailwindcss"],
34
+ tailwindStylesheet: "./app/globals.css",
35
+ };
36
+
37
+ export default config;
38
+ ```
39
+
40
+ Add scripts to `package.json`:
41
+
42
+ ```json
43
+ {
44
+ "scripts": {
45
+ "format": "prettier --write .",
46
+ "format:check": "prettier --check ."
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Tailwind class sorting
52
+
53
+ The config includes [`prettier-plugin-tailwindcss`](https://github.com/tailwindlabs/prettier-plugin-tailwindcss), the official Tailwind plugin. It sorts the classes in every `className` into one standard order when the file is formatted, so the same classes are always written the same way:
54
+
55
+ ```tsx
56
+ // Before formatting
57
+ <button className="text-white px-8 hover:bg-brand-primary-hover rounded-md bg-brand-primary py-4 flex">
58
+
59
+ // After formatting
60
+ <button className="flex rounded-md bg-brand-primary px-8 py-4 text-white hover:bg-brand-primary-hover">
61
+ ```
62
+
63
+ - **It is part of the standard**, not a project extra. Every project that uses Tailwind has it.
64
+ - **`tailwindStylesheet` points at the project's global stylesheet**, so the plugin knows the project's own colours. Change the path if `globals.css` lives somewhere else.
65
+ - **A project with no Tailwind** (a plain Node.js service) removes the `plugins` and `tailwindStylesheet` lines.
66
+
67
+ ## Settings reference
68
+
69
+ | Option | Value | Rationale |
70
+ | --- | --- | --- |
71
+ | `printWidth` | `100` | Wider than 80 but avoids the illegibility of unconstrained lines |
72
+ | `tabWidth` | `2` | Standard for JS/TS; matches `.editorconfig` |
73
+ | `useTabs` | `false` | Spaces are consistent across all editors |
74
+ | `singleQuote` | `false` | Double quotes are standard in JSX and HTML; one style for all |
75
+ | `trailingComma` | `"all"` | Cleaner diffs when adding items to the end of a list |
76
+ | `bracketSpacing` | `true` | `{ foo }` is more readable than `{foo}` |
77
+ | `bracketSameLine` | `false` | Closing `>` on its own line for JSX |
78
+ | `arrowParens` | `"always"` | `(x) => x` is consistent whether 0, 1, or many params |
79
+ | `semi` | `true` | Explicit semicolons avoid ASI footguns |
80
+ | `endOfLine` | `"lf"` | Unix line endings everywhere; matches `.editorconfig` |
81
+
82
+ ## Editor integration
83
+
84
+ ### VS Code
85
+
86
+ Install the [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extension, then add to your workspace settings:
87
+
88
+ ```json
89
+ {
90
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
91
+ "editor.formatOnSave": true
92
+ }
93
+ ```
94
+
95
+ ### JetBrains IDEs
96
+
97
+ Go to **Settings → Languages & Frameworks → JavaScript → Prettier** and enable "Run on save".