-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy patheslint.config.mjs
More file actions
76 lines (73 loc) · 3.58 KB
/
Copy patheslint.config.mjs
File metadata and controls
76 lines (73 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import nextCoreWebVitals from "eslint-config-next/core-web-vitals"
import nextTypeScript from "eslint-config-next/typescript"
import eslintConfigPrettier from "eslint-config-prettier"
// Native flat config from eslint-config-next (Next 16). Replaces the previous
// FlatCompat wrapper, which crashed under ESLint 9 (`Converting circular
// structure to JSON ... property 'react' closes the circle`) — the eslintrc
// validator can't serialize eslint-plugin-react's self-referential config.
/**
* Files allowed to create `Student` rows directly. Each entry is a deliberate
* exception, not an oversight. Exported so the vitest backstop in
* `src/tests/school-dashboard/listings/student-intake-invariant.test.ts` shares
* exactly one list with the lint rule and the two cannot drift apart.
*/
export const STUDENT_CREATE_ALLOWLIST = [
// THE core itself: the one place a Student row is supposed to be born.
"src/lib/student-provisioning.ts",
// Demo/tenant seeds mint their own shadow Applications inline (calling the
// full 12-step core ~1000x would slow every deploy's prebuild).
"prisma/seeds/**",
// Replays an existing snapshot whose rows already carry Applications --
// routing it through the core would double-provision.
"src/lib/backup-service.ts",
// Ops/migration scripts operate on already-provisioned rows.
"scripts/**",
"src/tests/**",
// createDraftStudent: a wizard draft is deliberately Application-less until
// completeStudentWizard runs provisionStudent. Drafts carry a non-null
// `wizardStep`, which is what exempts them from the invariant.
"src/components/school-dashboard/listings/students/wizard/actions.ts",
// TODO(intake-unification): unauthenticated self-registration flows. Gated
// for auth, but their AdmissionChannel is still undecided, so they remain
// outside the pipeline for now. Remove these two entries once they route
// through provisionStudent.
"src/components/internal-onboarding/actions.ts",
"src/components/onboarding/newcomers/actions.ts",
]
const eslintConfig = [
...nextCoreWebVitals,
...nextTypeScript,
{
rules: {
"@typescript-eslint/no-explicit-any": "error",
// Every student must be born from an Application, tagged with the
// AdmissionChannel it came through -- see content/docs-en/admission.mdx
// ("Student intake -- four channels, one pipeline"). That invariant is
// only maintained by `provisionStudent`, which mints (or reuses) the
// Application and links it. Downstream code already relies on it:
// `deriveIsSelfOnboarded` in listings/students/actions.ts reads
// `student.application.channel`, and reads `undefined` for any student
// created behind the core's back.
//
// Matches `<anything>.student.create/upsert/createMany(...)`, so it
// catches `db.`, `tx.` and `prisma.` receivers alike.
"no-restricted-syntax": [
"error",
{
selector:
"CallExpression[callee.object.property.name='student'][callee.property.name=/^(create|upsert|createMany)$/]",
message:
"Do not create Student rows directly -- call provisionStudent() from @/lib/student-provisioning so the student gets an Application, a student code, a login and fee assignments. If this is a genuine exception (seed, ops script, snapshot replay), add the file to the allowlist in eslint.config.mjs and say why.",
},
],
},
},
{
files: STUDENT_CREATE_ALLOWLIST,
rules: {
"no-restricted-syntax": "off",
},
},
eslintConfigPrettier, // Must be last to disable conflicting rules
]
export default eslintConfig