@gspothq/cli 0.1.1 → 0.2.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.
- package/README.md +58 -11
- package/configurations/database/postgres/manifest.toml +51 -57
- package/configurations/database/postgres/rules/POSTGRES.md +14 -13
- package/configurations/framework/astro/manifest.toml +33 -35
- package/configurations/framework/astro/rules/ASTRO.md +2 -2
- package/configurations/framework/expo/manifest.toml +19 -19
- package/configurations/framework/express/manifest.toml +10 -4
- package/configurations/framework/express/rules/EXPRESS.md +9 -7
- package/configurations/framework/fastapi/manifest.toml +9 -3
- package/configurations/framework/fastapi/rules/FASTAPI.md +19 -18
- package/configurations/framework/nestjs/manifest.toml +12 -12
- package/configurations/framework/nestjs/rules/NESTJS.md +9 -9
- package/configurations/framework/nextjs/manifest.toml +39 -79
- package/configurations/framework/nextjs/rules/NEXTJS.md +9 -7
- package/configurations/framework/nextjs/tool-files/semgrep/nextjs.yml +35 -0
- package/configurations/framework/react/manifest.toml +33 -43
- package/configurations/framework/react/rules/REACT.md +14 -20
- package/configurations/framework/react-dom/manifest.toml +6 -6
- package/configurations/framework/react-native/manifest.toml +11 -11
- package/configurations/framework/react-native/rules/REACT-NATIVE.md +3 -5
- package/configurations/framework/site/manifest.toml +57 -110
- package/configurations/framework/site/rules/SITE.md +1 -1
- package/configurations/framework/svelte/manifest.toml +29 -31
- package/configurations/framework/svelte/rules/SVELTE.md +6 -6
- package/configurations/framework/vue/manifest.toml +37 -37
- package/configurations/framework/vue/rules/VUE.md +6 -6
- package/configurations/general/commits/manifest.toml +20 -84
- package/configurations/general/commits/rules/GIT.md +24 -13
- package/configurations/general/coverage/manifest.toml +1 -1
- package/configurations/general/dependencies/manifest.toml +47 -107
- package/configurations/general/dependencies/rules/DEPENDENCIES.md +13 -7
- package/configurations/general/docs/manifest.toml +28 -43
- package/configurations/general/docs/rules/DOCS.md +16 -9
- package/configurations/general/duplication/manifest.toml +12 -14
- package/configurations/general/engineering/manifest.toml +6 -2
- package/configurations/general/engineering/rules/agent/PLANNING.md +9 -6
- package/configurations/general/engineering/rules/agent/SUPPRESSIONS.md +20 -11
- package/configurations/general/engineering/rules/agent/TASKS.md +6 -2
- package/configurations/general/engineering/rules/agent/WORKING.md +34 -29
- package/configurations/general/engineering/rules/code/ACCESSIBILITY.md +9 -7
- package/configurations/general/engineering/rules/code/CLI.md +12 -9
- package/configurations/general/engineering/rules/code/COMMENTS.md +11 -1
- package/configurations/general/engineering/rules/code/CONFIGURATION.md +2 -0
- package/configurations/general/engineering/rules/code/ERRORS.md +5 -3
- package/configurations/general/engineering/rules/code/HTTP.md +9 -10
- package/configurations/general/engineering/rules/code/LOGGING.md +10 -9
- package/configurations/general/engineering/rules/code/TESTING.md +18 -11
- package/configurations/general/files/manifest.toml +45 -73
- package/configurations/general/files/rules/YAML.md +20 -10
- package/configurations/general/format/manifest.toml +53 -106
- package/configurations/general/gspot/manifest.toml +19 -39
- package/configurations/general/gspot/rules/GENERATED.md +14 -4
- package/configurations/general/licenses/manifest.toml +12 -14
- package/configurations/general/naming/defaults.json +14 -13
- package/configurations/general/naming/manifest.toml +17 -17
- package/configurations/general/naming/rules/NAMING.md +87 -67
- package/configurations/general/prose/manifest.toml +166 -25
- package/configurations/general/prose/rules/WRITING.md +6 -2
- package/configurations/general/repository/manifest.toml +12 -12
- package/configurations/general/secrets/manifest.toml +52 -73
- package/configurations/general/secrets/rules/SECRETS.md +3 -1
- package/configurations/general/security/manifest.toml +29 -52
- package/configurations/general/security/rules/SECURITY.md +8 -6
- package/configurations/general/spelling/manifest.toml +15 -25
- package/configurations/general/structure/manifest.toml +31 -31
- package/configurations/infrastructure/ansible/manifest.toml +15 -15
- package/configurations/infrastructure/docker/manifest.toml +55 -67
- package/configurations/infrastructure/docker/rules/DOCKER.md +15 -13
- package/configurations/infrastructure/github-actions/manifest.toml +21 -41
- package/configurations/infrastructure/github-actions/rules/GITHUB-ACTIONS.md +16 -12
- package/configurations/infrastructure/github-actions/tool-files/zizmor.yml +5 -0
- package/configurations/infrastructure/nginx/manifest.toml +20 -20
- package/configurations/infrastructure/nginx/rules/NGINX.md +5 -4
- package/configurations/infrastructure/openapi/manifest.toml +20 -20
- package/configurations/infrastructure/openapi/rules/OPENAPI.md +3 -1
- package/configurations/infrastructure/xcode/manifest.toml +55 -75
- package/configurations/infrastructure/xcode/rules/XCODE.md +5 -3
- package/configurations/language/bash/manifest.toml +89 -170
- package/configurations/language/bash/rules/BASH.md +79 -17
- package/configurations/language/bash/rules/LANGUAGE.md +30 -26
- package/configurations/language/bash/rules/OPERATIONS.md +10 -8
- package/configurations/language/bash/rules/SAFETY.md +39 -35
- package/configurations/language/css/manifest.toml +22 -61
- package/configurations/language/css/rules/CSS.md +21 -2
- package/configurations/language/css/rules/TAILWIND.md +7 -5
- package/configurations/language/html/manifest.toml +16 -35
- package/configurations/language/html/rules/HTML.md +23 -5
- package/configurations/language/javascript/eslint-runtime-names.json +66 -61
- package/configurations/language/javascript/eslint-runtime.mjs +118 -0
- package/configurations/language/javascript/manifest.toml +135 -207
- package/configurations/language/javascript/rules/BUN.md +2 -2
- package/configurations/language/javascript/rules/COMPONENTS.md +4 -4
- package/configurations/language/javascript/rules/DENO.md +1 -1
- package/configurations/language/javascript/rules/JAVASCRIPT.md +30 -17
- package/configurations/language/javascript/rules/NODE.md +2 -2
- package/configurations/language/javascript/rules/PLAYWRIGHT.md +10 -9
- package/configurations/language/markdown/manifest.toml +20 -51
- package/configurations/language/python/manifest.toml +231 -342
- package/configurations/language/python/rules/DESIGN.md +40 -33
- package/configurations/language/python/rules/FLOW.md +8 -6
- package/configurations/language/python/rules/PACKAGING.md +14 -7
- package/configurations/language/python/rules/PYTHON.md +83 -33
- package/configurations/language/python/rules/TYPING.md +25 -23
- package/configurations/language/sql/manifest.toml +19 -37
- package/configurations/language/sql/rules/SQL.md +90 -2
- package/configurations/language/swift/manifest.toml +67 -78
- package/configurations/language/swift/rules/SWIFT.md +138 -40
- package/configurations/language/swift/rules/SWIFTUI.md +11 -9
- package/configurations/language/swift/rules/UIKIT.md +21 -19
- package/configurations/language/typescript/manifest.toml +34 -34
- package/configurations/language/typescript/rules/TYPESCRIPT.md +62 -10
- package/configurations/library/drizzle/manifest.toml +25 -38
- package/configurations/library/drizzle/rules/DRIZZLE.md +4 -2
- package/configurations/library/react-hook-form/manifest.toml +4 -4
- package/configurations/library/react-hook-form/rules/REACT-HOOK-FORM.md +15 -13
- package/configurations/library/tanstack-query/manifest.toml +6 -6
- package/configurations/library/tanstack-query/rules/TANSTACK-QUERY.md +5 -3
- package/configurations/library/testing-library/manifest.toml +6 -6
- package/configurations/library/translations/manifest.toml +22 -22
- package/configurations/library/translations/rules/NEXT-INTL.md +6 -8
- package/configurations/library/translations/rules/TRANSLATIONS.md +22 -23
- package/configurations/library/trpc/manifest.toml +3 -3
- package/configurations/library/trpc/rules/TRPC.md +8 -6
- package/configurations/library/zod/manifest.toml +6 -6
- package/configurations/library/zod/rules/ZOD.md +4 -2
- package/configurations/library/zustand/manifest.toml +4 -4
- package/configurations/library/zustand/rules/ZUSTAND.md +16 -14
- package/configurations/platform/cloudflare/manifest.toml +28 -47
- package/configurations/platform/cloudflare/rules/CLOUDFLARE.md +11 -6
- package/configurations/platform/supabase/manifest.toml +48 -61
- package/configurations/platform/supabase/rules/SUPABASE.md +27 -28
- package/configurations/testing/jest/manifest.toml +21 -22
- package/configurations/testing/pytest/manifest.toml +28 -28
- package/configurations/testing/swift-tests/manifest.toml +18 -29
- package/configurations/testing/swift-tests/rules/SWIFT-TESTS.md +7 -5
- package/configurations/testing/vitest/manifest.toml +32 -32
- package/configurations/testing/vitest/rules/VITEST.md +3 -1
- package/dist/gspot.js +22297 -24707
- package/dist/{linkinator-program.js → linkinator-process.js} +5 -7
- package/dist/{purgecss-program.js → purgecss-process.js} +12 -12
- package/package.json +7 -9
- package/configurations/infrastructure/github-actions/zizmor.yml +0 -3
- package/configurations/language/bash/rules/NAMING.md +0 -62
- package/configurations/language/css/rules/NAMING.md +0 -17
- package/configurations/language/html/rules/NAMING.md +0 -16
- package/configurations/language/javascript/rules/NAMING.md +0 -31
- package/configurations/language/markdown/markdownlint-cli2.mjs +0 -19
- package/configurations/language/python/rules/NAMING.md +0 -53
- package/configurations/language/sql/rules/NAMING.md +0 -90
- package/configurations/language/swift/rules/NAMING.md +0 -88
- package/configurations/language/typescript/rules/NAMING.md +0 -73
- package/configurations/library/swift-snapshot-testing/manifest.toml +0 -32
- package/dist/THIRD-PARTY-NOTICES.md +0 -25
- package/dist/eslint-rule-levels.json +0 -10
- package/dist/tool-versions.json +0 -3
- package/gspot.schema.json +0 -45991
- /package/{dist/LICENSE.md → LICENSE.md} +0 -0
- /package/configurations/framework/express/{semgrep → tool-files/semgrep}/express.yml +0 -0
- /package/configurations/framework/fastapi/{semgrep → tool-files/semgrep}/fastapi.yml +0 -0
- /package/configurations/general/dependencies/{syncpack.json → tool-files/syncpack.json} +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/LICENSES.md +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/ampm.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/conscious-language.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/contractions.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/currency.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/dashes.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/date-ordinals.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/dates.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/file-paths.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/future.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/hedging.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/history.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/idioms.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/interface-verbs.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/jargon.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/leading-conjunctions.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/link-text.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/locations.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/marketing.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/merge-conflict-markers.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/militaristic-language.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/modals.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/numbered-units.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/obvious-fields.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/ordinal-adverbs.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/percentage-numbers.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/placeholders.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/product-centric-writing.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/punctuated-headings.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/self-reference.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/session-identifiers.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/since.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/straight-quotes.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/suspended-hyphens.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/symbols.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/time-ranges.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/url-prepositions.yml +0 -0
- /package/configurations/general/prose/{vale → tool-files/vale}/styles/gspot/version-range.yml +0 -0
- /package/configurations/general/secrets/{gitleaks.toml → tool-files/gitleaks.toml} +0 -0
- /package/configurations/infrastructure/docker/{trivyignore → tool-files/trivyignore} +0 -0
- /package/configurations/language/bash/{semgrep → tool-files/semgrep}/bash.yml +0 -0
- /package/configurations/language/javascript/{semgrep → tool-files/semgrep}/javascript.yml +0 -0
- /package/configurations/language/swift/{semgrep → tool-files/semgrep}/swift.yml +0 -0
- /package/configurations/platform/cloudflare/{semgrep → tool-files/semgrep}/cloudflare.yml +0 -0
- /package/configurations/platform/supabase/{semgrep → tool-files/semgrep}/supabase.yml +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# FastAPI
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Read this rule when you change a FastAPI application.
|
|
4
|
+
|
|
5
|
+
These rules target FastAPI with Pydantic v2.
|
|
5
6
|
|
|
6
7
|
## Structure
|
|
7
8
|
|
|
8
9
|
<!-- level: all -->
|
|
9
10
|
|
|
10
|
-
Path operations
|
|
11
|
+
Path operations turn HTTP input into application calls and results into responses. Business logic
|
|
11
12
|
lives outside them. One main module creates the `FastAPI` object and wires routers, global
|
|
12
13
|
dependencies, middleware, exception handlers, and startup. Routers group related operations under
|
|
13
14
|
a prefix that does not end in `/`, and imports use their domain, `items.router` and `users.router`.
|
|
@@ -46,16 +47,16 @@ app.include_router(router)
|
|
|
46
47
|
|
|
47
48
|
## Parameters
|
|
48
49
|
|
|
49
|
-
`Annotated[..., Query(...)]`, `Path`, `Body`, `Header`, `Cookie`, `Form`, `File`, or
|
|
50
|
-
|
|
50
|
+
Declare each parameter with `Annotated[..., Query(...)]`, `Path`, `Body`, `Header`, `Cookie`, `Form`, `File`, or
|
|
51
|
+
`Depends`. A plain scalar supplies a query parameter. A parameter without a default requires a value, even when it
|
|
51
52
|
accepts `None`. Constraints such as `max_length` or `ge` belong at the boundary when the public interface requires them. Use a dependency for a check that needs a database or authorization state, not
|
|
52
53
|
a validator. Declare fixed routes such as `/users/me` before `/users/{user_id}`, and group
|
|
53
54
|
pagination or filter parameters into a query model with `extra="forbid"`.
|
|
54
55
|
|
|
55
|
-
Forms need `python-multipart`, and one operation never mixes JSON body fields with form
|
|
56
|
+
Forms need `python-multipart`, and one operation never mixes JSON body fields with form data
|
|
56
57
|
or files. Uploads arrive as `UploadFile`, bounded in count and size; `bytes` holds only small
|
|
57
|
-
values. Never use a filename as a filesystem path
|
|
58
|
-
|
|
58
|
+
values. Never use a filename as a filesystem path or log uploaded contents. A content type proves nothing
|
|
59
|
+
about safety.
|
|
59
60
|
|
|
60
61
|
## Schemas and responses
|
|
61
62
|
|
|
@@ -63,32 +64,32 @@ Pydantic models define the schemas where data enters or leaves. Use separate cla
|
|
|
63
64
|
their fields differ. Never return an input with passwords or tokens as the response. Known JSON
|
|
64
65
|
shapes use nested models with typed containers. Use `UUID` for identifiers, timezone-aware instants across a
|
|
65
66
|
boundary, and `Decimal` for money. A partial update reads
|
|
66
|
-
`model_dump(exclude_unset=True)`, merges with the stored value, and validates the
|
|
67
|
-
|
|
67
|
+
`model_dump(exclude_unset=True)`, merges with the stored value, and validates the whole model;
|
|
68
|
+
`model_copy(update=...)` skips validation.
|
|
68
69
|
|
|
69
70
|
The return type defines the public schema; `response_model` serves a returned object of another
|
|
70
71
|
shape. A dedicated output model filters fields, never `response_model_exclude`, which still
|
|
71
|
-
documents the
|
|
72
|
+
documents the whole schema. A response validation failure shows a server bug. Fix the data or
|
|
72
73
|
the schema.
|
|
73
74
|
|
|
74
75
|
## Status codes and errors
|
|
75
76
|
|
|
76
77
|
Non-default success codes go in the decorator with `fastapi.status` constants: 201 for creation,
|
|
77
78
|
202 for accepted work, and 204 for a deliberate empty body. Raise `HTTPException` rather than returning it. Its `detail` supplies a public error message. Existence and
|
|
78
|
-
authorization checks
|
|
79
|
-
handlers return the standard error shape and never echo a validation
|
|
79
|
+
authorization checks fail the same way, so responses do not reveal a private resource. Global exception
|
|
80
|
+
handlers return the standard error shape and never echo the request body from a validation failure.
|
|
80
81
|
|
|
81
82
|
## Runtime
|
|
82
83
|
|
|
83
|
-
- Declare a path operation or dependency `async def` when it awaits async libraries and `def` when it
|
|
84
|
-
calls blocking code
|
|
84
|
+
- Declare a path operation or dependency `async def` when it awaits async libraries, and `def` when it
|
|
85
|
+
calls blocking code. A blocking call inside `async def` stalls the event loop. Run CPU-heavy work in a worker process, not in `async def`.
|
|
85
86
|
- Dependencies carry request-scoped concerns: authentication, sessions, pagination, and
|
|
86
87
|
reusable validation. A `yield` dependency owns one resource, cleans up in `finally`, and
|
|
87
88
|
re-raises what it catches.
|
|
88
89
|
- Authentication that appears in OpenAPI uses the security utilities. A JSON Web Token (JWT) verifier allows an
|
|
89
90
|
explicit algorithm list and requires `exp` and `sub`.
|
|
90
|
-
- `BackgroundTasks` runs small follow-up
|
|
91
|
-
a queue. Middleware holds cross-cutting HTTP behavior only, and the
|
|
91
|
+
- `BackgroundTasks` runs small follow-up jobs after the response; durable or heavy work goes to
|
|
92
|
+
a queue. Middleware holds cross-cutting HTTP behavior only, and the one added last runs
|
|
92
93
|
outermost.
|
|
93
94
|
- Turn OpenAPI and the interactive docs off unless a typed setting turns them on, and the schema
|
|
94
95
|
exposes no internal or admin routes.
|
|
@@ -97,4 +98,4 @@ handlers return the standard error shape and never echo a validation error's bod
|
|
|
97
98
|
|
|
98
99
|
Tests cover the HTTP contract through the test client: status codes, bodies, headers, and
|
|
99
100
|
authentication. Replace external systems with dependency overrides at the application
|
|
100
|
-
boundary. Tests cover the application
|
|
101
|
+
boundary. Tests cover the application, not the routing implementation of FastAPI.
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
[prefix_collisions]
|
|
2
|
-
kinds = ["controller", "service", "module", "guard", "pipe", "filter", "interceptor", "middleware", "decorator", "gateway", "resolver", "repository", "entity", "dto", "strategy", "provider"]
|
|
3
|
-
|
|
4
1
|
[configuration]
|
|
5
|
-
|
|
2
|
+
description = "A NestJS service: the compiler options that decorators need, plugin rules for providers, routes, and DTOs, and no circular modules."
|
|
6
3
|
requires = ["typescript"]
|
|
7
4
|
suggests = []
|
|
8
|
-
|
|
5
|
+
title = "NestJS"
|
|
9
6
|
|
|
10
7
|
[detect]
|
|
11
8
|
dependencies = ["@nestjs/core"]
|
|
@@ -14,12 +11,15 @@ filenames = ["nest-cli.json"]
|
|
|
14
11
|
[files]
|
|
15
12
|
filenames = ["nest-cli.json"]
|
|
16
13
|
|
|
14
|
+
[shared_prefixes]
|
|
15
|
+
kinds = ["controller", "service", "module", "guard", "pipe", "filter", "interceptor", "middleware", "decorator", "gateway", "resolver", "repository", "entity", "dto", "strategy", "provider"]
|
|
16
|
+
|
|
17
17
|
[[tool]]
|
|
18
|
+
kind = "library"
|
|
18
19
|
name = "@darraghor/eslint-plugin-nestjs-typed"
|
|
20
|
+
npm = "@darraghor/eslint-plugin-nestjs-typed"
|
|
19
21
|
rule_prefix = "@darraghor/nestjs-typed"
|
|
20
|
-
kind = "library"
|
|
21
22
|
version = "7.5.5"
|
|
22
|
-
npm = "@darraghor/eslint-plugin-nestjs-typed"
|
|
23
23
|
|
|
24
24
|
[eslint]
|
|
25
25
|
all_level_rules = ["@darraghor/nestjs-typed/api-operation-summary-description-capitalized"]
|
|
@@ -33,20 +33,20 @@ package = "@darraghor/eslint-plugin-nestjs-typed"
|
|
|
33
33
|
source = "configs.flatNoSwagger"
|
|
34
34
|
|
|
35
35
|
[[eslint.rules_off]]
|
|
36
|
-
rules = ["gspot/no-trivial-files", "gspot/no-trivial-functions"]
|
|
37
36
|
files = ["**/*.module.ts"]
|
|
38
37
|
reason = "A Nest module is an empty decorated class that registers providers and controllers, which is the shape Nest asks for."
|
|
38
|
+
rules = ["gspot/no-trivial-files", "gspot/no-trivial-functions"]
|
|
39
39
|
|
|
40
40
|
[[eslint.selectors]]
|
|
41
|
-
selector = "CallExpression[callee.name='forwardRef']"
|
|
42
41
|
message = "forwardRef papers over two modules that import each other. Move what both need into a third module."
|
|
42
|
+
selector = "CallExpression[callee.name='forwardRef']"
|
|
43
43
|
|
|
44
44
|
[[eslint.selectors]]
|
|
45
|
-
selector = "Decorator[expression.callee.name=/^(Res|Response)$/]:not(:has(Property[key.name='passthrough'][value.value=true]))"
|
|
46
45
|
message = "Taking the response object turns off interceptors and the return value. Return the value, or pass { passthrough: true }."
|
|
46
|
+
selector = "Decorator[expression.callee.name=/^(Res|Response)$/]:not(:has(Property[key.name='passthrough'][value.value=true]))"
|
|
47
47
|
|
|
48
48
|
[[tool_file]]
|
|
49
|
-
target = ".gspot/config/eslint.config.mjs"
|
|
50
|
-
tool = "eslint"
|
|
51
49
|
fragment = true
|
|
52
50
|
required_tools = ["@darraghor/eslint-plugin-nestjs-typed"]
|
|
51
|
+
target = ".gspot/config/eslint.config.mjs"
|
|
52
|
+
tool = "eslint"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# NestJS
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read this rule when you change NestJS modules, controllers, providers, or their tests.
|
|
4
4
|
|
|
5
5
|
## Request handling
|
|
6
6
|
|
|
@@ -11,25 +11,25 @@ These rules cover NestJS modules, controllers, providers, validation, configurat
|
|
|
11
11
|
|
|
12
12
|
## Providers and lifecycle
|
|
13
13
|
|
|
14
|
-
- Register each provider
|
|
14
|
+
- Register each provider in the module that owns it. Repeated registration can create distinct instances.
|
|
15
15
|
- Request-scoped dependencies propagate request scope to their consumers. Check lifetime and
|
|
16
|
-
resource costs before
|
|
16
|
+
resource costs before choosing that scope.
|
|
17
17
|
- Close connections and timers through the application lifecycle, such as `OnModuleDestroy`.
|
|
18
18
|
|
|
19
19
|
## Configuration and security
|
|
20
20
|
|
|
21
21
|
- Fail startup when required configuration has missing or malformed values.
|
|
22
|
-
- Use guards for route authorization. Enforce
|
|
23
|
-
when one request
|
|
24
|
-
- Guards run before pipes. Do not assume guard inputs have passed DTO transformation or validation.
|
|
22
|
+
- Use guards for route authorization. Enforce extra permissions inside each protected operation
|
|
23
|
+
when one request runs several, or the service has non-HTTP callers.
|
|
24
|
+
- Guards run before pipes. Do not assume guard inputs have passed data transfer object (DTO) transformation or validation.
|
|
25
25
|
- Set request-size limits, security headers, and rate limits for the exposed application.
|
|
26
26
|
|
|
27
27
|
## Feature organization
|
|
28
28
|
|
|
29
29
|
<!-- level: all -->
|
|
30
30
|
|
|
31
|
-
- Give each feature one module and export only providers
|
|
32
|
-
- Inject dependencies through constructors instead of
|
|
31
|
+
- Give each feature one module, and export only the providers that other modules consume.
|
|
32
|
+
- Inject dependencies through constructors instead of creating them inside consumers.
|
|
33
33
|
- Define the versioning contract before publishing a public API.
|
|
34
34
|
- Keep request DTOs distinct from persistence entities and map between them explicitly.
|
|
35
35
|
|
|
@@ -40,5 +40,5 @@ These rules cover NestJS modules, controllers, providers, validation, configurat
|
|
|
40
40
|
- Do not mock the class under test or assert on private methods.
|
|
41
41
|
- Close test applications in teardown.
|
|
42
42
|
|
|
43
|
-
See
|
|
43
|
+
See the NestJS [response handling](https://docs.nestjs.com/controllers) and
|
|
44
44
|
[authorization guidance](https://docs.nestjs.com/security/authorization).
|
|
@@ -1,25 +1,11 @@
|
|
|
1
|
-
route_files = ["page", "layout", "template", "default", "loading", "error", "not-found", "global-error", "route", "middleware", "proxy"]
|
|
2
1
|
allowed_words = ["Next.js"]
|
|
3
2
|
generated = ["next-env.d.ts"]
|
|
4
3
|
|
|
5
|
-
[[naming.override]]
|
|
6
|
-
paths = ["**/app/**", "**/pages/**"]
|
|
7
|
-
categories = ["files"]
|
|
8
|
-
allowed_names = ["instrumentation", "sitemap", "robots", "manifest", "opengraph-image", "icon", "apple-icon", "_app", "_document", "_error", "404", "500"]
|
|
9
|
-
reason = "Next.js names these files."
|
|
10
|
-
|
|
11
|
-
[[naming.override]]
|
|
12
|
-
paths = ["**"]
|
|
13
|
-
languages = ["typescript", "javascript"]
|
|
14
|
-
categories = ["functions", "methods", "variables"]
|
|
15
|
-
allowed_names = ["getStaticProps", "getServerSideProps", "generateMetadata", "generateStaticParams", "generateViewport"]
|
|
16
|
-
reason = "Next.js discovers these data and metadata exports by name."
|
|
17
|
-
|
|
18
4
|
[configuration]
|
|
19
|
-
|
|
5
|
+
description = "A Next.js app: ESLint rules for the framework and hooks, and server code marked server-only. The configuration leaves every build check on."
|
|
20
6
|
requires = ["typescript", "react", "react-dom"]
|
|
21
7
|
suggests = ["css"]
|
|
22
|
-
|
|
8
|
+
title = "Next.js"
|
|
23
9
|
|
|
24
10
|
[detect]
|
|
25
11
|
dependencies = ["next"]
|
|
@@ -27,75 +13,31 @@ dependencies = ["next"]
|
|
|
27
13
|
[files]
|
|
28
14
|
paths = ["**/next.config.js", "**/next.config.mjs", "**/next.config.ts"]
|
|
29
15
|
|
|
16
|
+
[[naming.override]]
|
|
17
|
+
allowed_names = ["page", "layout", "template", "default", "loading", "error", "not-found", "global-error", "route", "middleware", "proxy", "instrumentation", "sitemap", "robots", "manifest", "opengraph-image", "icon", "apple-icon", "_app", "_document", "_error", "404", "500"]
|
|
18
|
+
categories = ["files"]
|
|
19
|
+
paths = ["**/app/**", "**/pages/**"]
|
|
20
|
+
reason = "Next.js names these files."
|
|
21
|
+
|
|
22
|
+
[[naming.override]]
|
|
23
|
+
allowed_names = ["getStaticProps", "getServerSideProps", "generateMetadata", "generateStaticParams", "generateViewport"]
|
|
24
|
+
categories = ["functions", "methods", "variables"]
|
|
25
|
+
languages = ["typescript", "javascript"]
|
|
26
|
+
paths = ["**"]
|
|
27
|
+
reason = "Next.js discovers these data and metadata exports by name."
|
|
28
|
+
|
|
30
29
|
[[tool]]
|
|
30
|
+
min_version = "15.5.0"
|
|
31
31
|
name = "next"
|
|
32
32
|
system = true
|
|
33
|
-
min_version = "15.5.0"
|
|
34
33
|
version_command = ["--version"]
|
|
35
34
|
|
|
36
35
|
[[tool]]
|
|
36
|
+
kind = "library"
|
|
37
37
|
name = "@next/eslint-plugin-next"
|
|
38
|
+
npm = "@next/eslint-plugin-next"
|
|
38
39
|
rule_prefix = "@next/next"
|
|
39
|
-
kind = "library"
|
|
40
40
|
version = "16.3.8"
|
|
41
|
-
npm = "@next/eslint-plugin-next"
|
|
42
|
-
|
|
43
|
-
[[check]]
|
|
44
|
-
name = "tsc"
|
|
45
|
-
tool = "next"
|
|
46
|
-
example = "The TypeScript declaration `const count: number = \"one\";` reports an incompatible assignment. Correct it to `const count: number = 1;` when the contract requires a number."
|
|
47
|
-
level = "recommended"
|
|
48
|
-
stage = "push"
|
|
49
|
-
runs = "scope"
|
|
50
|
-
instead_of = "typescript/tsc"
|
|
51
|
-
summary = "Has Next.js write its types, then type-checks the app with the strict compiler options."
|
|
52
|
-
why = "A fresh clone holds no next-env.d.ts and no route types, so a plain tsc run fails on imports the framework resolves."
|
|
53
|
-
help = "Read the first error tsc prints and fix that file; later errors are often the same mistake."
|
|
54
|
-
|
|
55
|
-
[[check]]
|
|
56
|
-
name = "build"
|
|
57
|
-
tool = "next"
|
|
58
|
-
example = "A Next.js page importing a nonexistent component fails the project build. Restore the component or correct the import path and rerun the configured build."
|
|
59
|
-
level = "all"
|
|
60
|
-
stage = "push"
|
|
61
|
-
runs = "scope"
|
|
62
|
-
needs = ["build"]
|
|
63
|
-
summary = "Builds the app with next build at all when its scope contains an app or pages tree."
|
|
64
|
-
why = "Some mistakes show only at build time: a server import in a client file, or a page that cannot be prerendered."
|
|
65
|
-
help = "Run next build and read the first error it prints."
|
|
66
|
-
|
|
67
|
-
[check.files]
|
|
68
|
-
paths = ["**/app/**", "**/pages/**"]
|
|
69
|
-
|
|
70
|
-
[[check]]
|
|
71
|
-
name = "route-segments"
|
|
72
|
-
example = "A Next.js segment containing both `page.tsx` and `route.ts` reports conflicting route ownership. Move the route handler into a separate segment, such as `api`, and update its callers."
|
|
73
|
-
level = "recommended"
|
|
74
|
-
stage = "commit"
|
|
75
|
-
runs = "once"
|
|
76
|
-
summary = "Checks that no route segment holds both a page and a route handler."
|
|
77
|
-
why = "This commit check finds route conflicts before next build and also runs at recommended, where the build check does not."
|
|
78
|
-
help = "Move the route handler into a segment of its own, such as an api folder."
|
|
79
|
-
|
|
80
|
-
[[check]]
|
|
81
|
-
name = "next-config"
|
|
82
|
-
example = "Setting `typescript.ignoreBuildErrors` to `true` in Next.js configuration reports a disabled type gate. Remove the switch and correct the type errors before building."
|
|
83
|
-
level = "recommended"
|
|
84
|
-
stage = "commit"
|
|
85
|
-
runs = "once"
|
|
86
|
-
summary = "Checks that the framework configuration turns no build check off and puts no secret into the client environment."
|
|
87
|
-
why = "A build that ignores lint and type errors ships them, and a key under env is readable by every visitor."
|
|
88
|
-
help = "Remove the switch, and read the secret on the server."
|
|
89
|
-
|
|
90
|
-
[[check]]
|
|
91
|
-
name = "version-pairs"
|
|
92
|
-
example = "Different installed versions of `next` and its lint package report an alignment finding. Install the same version of both and update the lockfile with the package manager."
|
|
93
|
-
level = "recommended"
|
|
94
|
-
stage = "commit"
|
|
95
|
-
runs = "once"
|
|
96
|
-
summary = "Checks that Next.js and its lint packages use the same installed version."
|
|
97
|
-
why = "A lint package a version behind flags what the framework allows and allows what it removed."
|
|
98
|
-
help = "Move both packages to the same version."
|
|
99
41
|
|
|
100
42
|
[eslint]
|
|
101
43
|
all_level_rules = ["@next/next/next-script-for-ga", "@next/next/no-html-link-for-pages", "@next/next/no-img-element", "@next/next/no-page-custom-font"]
|
|
@@ -109,11 +51,29 @@ package = "eslint-plugin-react-refresh"
|
|
|
109
51
|
source = "configs.next"
|
|
110
52
|
|
|
111
53
|
[[eslint.rules_off]]
|
|
112
|
-
|
|
54
|
+
files = ["**/{page,layout,template,default,loading,error,not-found,global-error,route,middleware,proxy}.{js,jsx,ts,tsx}"]
|
|
113
55
|
reason = "Next.js discovers route files by name, so each file can hold one export in its own folder."
|
|
56
|
+
rules = ["gspot/no-trivial-files"]
|
|
114
57
|
|
|
115
58
|
[[tool_file]]
|
|
116
|
-
target = ".gspot/config/eslint.config.mjs"
|
|
117
|
-
tool = "eslint"
|
|
118
59
|
fragment = true
|
|
119
60
|
required_tools = ["@next/eslint-plugin-next"]
|
|
61
|
+
target = ".gspot/config/eslint.config.mjs"
|
|
62
|
+
tool = "eslint"
|
|
63
|
+
|
|
64
|
+
[[tool_file]]
|
|
65
|
+
per_scope = true
|
|
66
|
+
target = ".gspot/config/semgrep/nextjs.yml"
|
|
67
|
+
tool = "semgrep"
|
|
68
|
+
|
|
69
|
+
[[check]]
|
|
70
|
+
example = "`const count: number = \"one\";` reports an incompatible assignment. Assign a number, such as `const count: number = 1;`."
|
|
71
|
+
help = "Fix the first error tsc prints; later errors often come from the same mistake."
|
|
72
|
+
instead_of = "typescript/tsc"
|
|
73
|
+
level = "recommended"
|
|
74
|
+
name = "tsc"
|
|
75
|
+
runs = "scope"
|
|
76
|
+
stage = "push"
|
|
77
|
+
summary = "Has Next.js write its types, then type-checks the app with the strict compiler options."
|
|
78
|
+
tool = "next"
|
|
79
|
+
why = "A fresh clone holds no next-env.d.ts and no route types, so a plain tsc run fails on imports the framework resolves."
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# Next.js
|
|
2
2
|
|
|
3
|
+
Read this rule when you change a Next.js application.
|
|
4
|
+
|
|
3
5
|
Preserve the project's router, installed Next.js and React versions, runtime, and deployment
|
|
4
6
|
adapter. App Router guidance applies only to App Router routes.
|
|
5
7
|
|
|
6
8
|
## Server and client ownership
|
|
7
9
|
|
|
8
10
|
Keep privileged operations and credentials on the server. Send only authorized fields to the
|
|
9
|
-
browser
|
|
10
|
-
does not
|
|
11
|
+
browser; that covers query hydration and Server Component props too. A hidden control, type, or filename
|
|
12
|
+
does not restrict access. A client boundary pulls its imports into the browser bundle; keep it small
|
|
11
13
|
and compose server-rendered children into it.
|
|
12
14
|
|
|
13
|
-
Validate and authorize every mutation at its server entry. Routes, actions, and RPC procedures
|
|
14
|
-
share
|
|
15
|
+
Validate and authorize every mutation at its server entry point. Routes, actions, and RPC procedures
|
|
16
|
+
share one domain operation. Initial server reads do not HTTP-fetch the application's own
|
|
15
17
|
Route Handler. Rendering, `GET` requests, and prefetching perform no writes.
|
|
16
18
|
|
|
17
19
|
See [Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components).
|
|
@@ -19,12 +21,12 @@ See [Server and Client Components](https://nextjs.org/docs/app/getting-started/s
|
|
|
19
21
|
## Loading and failures
|
|
20
22
|
|
|
21
23
|
Put a loading boundary around the section that waits. Keep useful content mounted during refresh,
|
|
22
|
-
and reset pending state when the
|
|
24
|
+
and reset pending state when the user switches resources. Start independent work early without
|
|
23
25
|
moving protected reads before authorization.
|
|
24
26
|
|
|
25
27
|
Decide status, headers, cookies, redirects, and not-found behavior before streaming commits the
|
|
26
28
|
response. Preserve framework control-flow exceptions. Check direct load, client navigation,
|
|
27
|
-
refresh, Back, and failed prefetch; those paths
|
|
29
|
+
refresh, Back, and failed prefetch; those paths may differ in state.
|
|
28
30
|
|
|
29
31
|
See [streaming](https://nextjs.org/docs/app/guides/streaming).
|
|
30
32
|
|
|
@@ -36,7 +38,7 @@ filters, and permissions where they affect results; session tokens stay out of k
|
|
|
36
38
|
|
|
37
39
|
Default private data to uncached until an isolation design exists. Never let a cached decision
|
|
38
40
|
retain revoked access. Clear private browser caches on logout. Invalidate after the write commits
|
|
39
|
-
and before a terminating redirect; a failed refresh must not retry
|
|
41
|
+
and before a terminating redirect; a failed refresh must not retry it.
|
|
40
42
|
Next.js and a client query cache need separate reconciliation.
|
|
41
43
|
|
|
42
44
|
See [caching](https://nextjs.org/docs/app/getting-started/caching)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
rules:
|
|
2
|
+
- id: nextjs.checks-off
|
|
3
|
+
languages: [typescript, javascript]
|
|
4
|
+
severity: ERROR
|
|
5
|
+
message: $KEY true lets next build pass with errors. Remove it.
|
|
6
|
+
paths:
|
|
7
|
+
include: ['**/next.config.*']
|
|
8
|
+
patterns:
|
|
9
|
+
- pattern-either:
|
|
10
|
+
- pattern: |
|
|
11
|
+
{..., $KEY: true, ...}
|
|
12
|
+
- pattern: |
|
|
13
|
+
{..., $KEY: (true as $T), ...}
|
|
14
|
+
- pattern: |
|
|
15
|
+
{..., $KEY: true satisfies $T, ...}
|
|
16
|
+
- metavariable-regex:
|
|
17
|
+
metavariable: $KEY
|
|
18
|
+
regex: ^["']?(ignoreBuildErrors|ignoreDuringBuilds)["']?$
|
|
19
|
+
- focus-metavariable: $KEY
|
|
20
|
+
- id: nextjs.env-secret
|
|
21
|
+
languages: [typescript, javascript]
|
|
22
|
+
severity: ERROR
|
|
23
|
+
message: $KEY under env is written into the client bundle. Read it on the server.
|
|
24
|
+
paths:
|
|
25
|
+
include: ['**/next.config.*']
|
|
26
|
+
patterns:
|
|
27
|
+
- pattern-either:
|
|
28
|
+
- pattern: |
|
|
29
|
+
{..., env: {..., $KEY: $V, ...}, ...}
|
|
30
|
+
- pattern: |
|
|
31
|
+
{..., env: {..., $KEY, ...}, ...}
|
|
32
|
+
- metavariable-regex:
|
|
33
|
+
metavariable: $KEY
|
|
34
|
+
regex: ^["']?(?=[A-Z\d_]*(?:SECRET|TOKEN|PASSWORD|PRIVATE_KEY|API_KEY))[A-Z][A-Z\d_]*["']?$
|
|
35
|
+
- focus-metavariable: $KEY
|
|
@@ -1,63 +1,56 @@
|
|
|
1
1
|
allowed_words = ["React"]
|
|
2
2
|
|
|
3
3
|
[configuration]
|
|
4
|
-
|
|
4
|
+
description = "React components: the recommended React and hooks rules as errors, and component files that keep their state on a reload."
|
|
5
5
|
requires = ["javascript"]
|
|
6
6
|
suggests = ["typescript", "css", "react-dom"]
|
|
7
|
-
|
|
7
|
+
title = "React"
|
|
8
8
|
|
|
9
9
|
[detect]
|
|
10
10
|
dependencies = ["react"]
|
|
11
11
|
|
|
12
|
+
[defaults]
|
|
13
|
+
"tools.eslint.import_extension" = "extensionless"
|
|
14
|
+
|
|
15
|
+
[[naming.override]]
|
|
16
|
+
cases = ["pascal", "kebab"]
|
|
17
|
+
categories = ["files"]
|
|
18
|
+
paths = ["**/*.tsx", "**/*.jsx"]
|
|
19
|
+
reason = "A component file takes the component's name."
|
|
20
|
+
|
|
21
|
+
[[naming.override]]
|
|
22
|
+
cases = ["pascal", "camel"]
|
|
23
|
+
categories = ["functions"]
|
|
24
|
+
paths = ["**/*.tsx", "**/*.jsx"]
|
|
25
|
+
reason = "A function that returns JSX is a component and takes a capital."
|
|
26
|
+
|
|
27
|
+
[[naming.override]]
|
|
28
|
+
allowed_names = ["useSyncExternalStore", "getSnapshot", "getServerSnapshot"]
|
|
29
|
+
categories = ["functions", "methods", "variables"]
|
|
30
|
+
languages = ["typescript", "javascript"]
|
|
31
|
+
paths = ["**"]
|
|
32
|
+
reason = "React defines these subscription and snapshot callback names."
|
|
33
|
+
|
|
12
34
|
[[tool]]
|
|
35
|
+
kind = "library"
|
|
13
36
|
name = "eslint-plugin-react-hooks"
|
|
37
|
+
npm = "eslint-plugin-react-hooks"
|
|
14
38
|
rule_prefix = "react-hooks"
|
|
15
|
-
kind = "library"
|
|
16
39
|
version = "7.1.1"
|
|
17
|
-
npm = "eslint-plugin-react-hooks"
|
|
18
40
|
|
|
19
41
|
[[tool]]
|
|
42
|
+
kind = "library"
|
|
20
43
|
name = "eslint-plugin-react"
|
|
44
|
+
npm = "eslint-plugin-react"
|
|
21
45
|
rule_prefix = "react"
|
|
22
|
-
kind = "library"
|
|
23
46
|
version = "7.37.5"
|
|
24
|
-
npm = "eslint-plugin-react"
|
|
25
47
|
|
|
26
48
|
[[tool]]
|
|
49
|
+
kind = "library"
|
|
27
50
|
name = "eslint-plugin-react-refresh"
|
|
51
|
+
npm = "eslint-plugin-react-refresh"
|
|
28
52
|
rule_prefix = "react-refresh"
|
|
29
|
-
kind = "library"
|
|
30
53
|
version = "0.5.7"
|
|
31
|
-
npm = "eslint-plugin-react-refresh"
|
|
32
|
-
|
|
33
|
-
[[check]]
|
|
34
|
-
name = "version-pairs"
|
|
35
|
-
example = "Different installed versions of react and react-dom report an alignment finding. Install the same version of both and update the lockfile with the package manager."
|
|
36
|
-
level = "recommended"
|
|
37
|
-
stage = "commit"
|
|
38
|
-
runs = "once"
|
|
39
|
-
summary = "Checks that react and react-dom use the same installed version."
|
|
40
|
-
why = "React and its DOM renderer ship together and expect matching versions."
|
|
41
|
-
help = "Install the same version of react and react-dom."
|
|
42
|
-
|
|
43
|
-
[[naming.override]]
|
|
44
|
-
paths = ["**/*.tsx", "**/*.jsx"]
|
|
45
|
-
categories = ["files"]
|
|
46
|
-
cases = ["pascal", "kebab"]
|
|
47
|
-
reason = "A component file takes the component's name."
|
|
48
|
-
|
|
49
|
-
[[naming.override]]
|
|
50
|
-
paths = ["**/*.tsx", "**/*.jsx"]
|
|
51
|
-
categories = ["functions"]
|
|
52
|
-
cases = ["pascal", "camel"]
|
|
53
|
-
reason = "A function that returns JSX is a component and takes a capital."
|
|
54
|
-
|
|
55
|
-
[[naming.override]]
|
|
56
|
-
paths = ["**"]
|
|
57
|
-
languages = ["typescript", "javascript"]
|
|
58
|
-
categories = ["functions", "methods", "variables"]
|
|
59
|
-
allowed_names = ["useSyncExternalStore", "getSnapshot", "getServerSnapshot"]
|
|
60
|
-
reason = "React defines these subscription and snapshot callback names."
|
|
61
54
|
|
|
62
55
|
[eslint]
|
|
63
56
|
all_level_rules = ["react/self-closing-comp", "react/display-name", "react/no-array-index-key", "react/prop-types"]
|
|
@@ -79,15 +72,12 @@ package = "eslint-plugin-react-refresh"
|
|
|
79
72
|
source = "configs.recommended"
|
|
80
73
|
|
|
81
74
|
[[eslint.rules_off]]
|
|
82
|
-
rules = ["gspot/no-trivial-files", "gspot/no-trivial-functions"]
|
|
83
75
|
files = ["**/*.tsx", "**/*.jsx"]
|
|
84
76
|
reason = "React renders a component by its name, so a component of one statement, alone in its file, is the shape React asks for."
|
|
85
|
-
|
|
86
|
-
[defaults]
|
|
87
|
-
"tools.eslint.import_extension" = "extensionless"
|
|
77
|
+
rules = ["gspot/no-trivial-files", "gspot/no-trivial-functions"]
|
|
88
78
|
|
|
89
79
|
[[tool_file]]
|
|
90
|
-
target = ".gspot/config/eslint.config.mjs"
|
|
91
|
-
tool = "eslint"
|
|
92
80
|
fragment = true
|
|
93
81
|
required_tools = ["eslint-plugin-react-hooks", "eslint-plugin-react", "eslint-plugin-react-refresh"]
|
|
82
|
+
target = ".gspot/config/eslint.config.mjs"
|
|
83
|
+
tool = "eslint"
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# React
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
adds routing, server components, and caching on top of these.
|
|
3
|
+
Read this rule when you change React components, hooks, or state.
|
|
5
4
|
|
|
6
5
|
## Components
|
|
7
6
|
|
|
@@ -15,7 +14,7 @@ adds routing, server components, and caching on top of these.
|
|
|
15
14
|
|
|
16
15
|
- Compose downward: a component imports children and shared primitives, never its parent, its
|
|
17
16
|
section, or its route.
|
|
18
|
-
- Domain-neutral primitives such as button, input, dialog, popover, and tooltip live in the shared UI
|
|
17
|
+
- Domain-neutral primitives such as button, input, dialog, popover, and tooltip live in the shared UI folder
|
|
19
18
|
and take values and callbacks. They never fetch or import a feature.
|
|
20
19
|
- Keep a component small enough that its JSX reads as one screen region. Extract by visual
|
|
21
20
|
responsibility, not by line count.
|
|
@@ -26,18 +25,18 @@ adds routing, server components, and caching on top of these.
|
|
|
26
25
|
## Hooks
|
|
27
26
|
|
|
28
27
|
- Every custom hook starts with `use` and owns one concern.
|
|
29
|
-
- Memoize
|
|
30
|
-
|
|
28
|
+
- Memoize with `useMemo`, `useCallback`, or `memo` only when a measurement shows expensive work or a consumer
|
|
29
|
+
needs a stable reference.
|
|
31
30
|
|
|
32
31
|
## Effects and state
|
|
33
32
|
|
|
34
33
|
- Keep renders pure. Effects synchronize external systems; handlers own user-triggered work. Derive
|
|
35
34
|
ordinary values during render rather than synchronizing duplicate state with effects. Clean up
|
|
36
35
|
timers, observers, subscriptions, animation frames, and requests.
|
|
37
|
-
- Use refs for mutable controller values and state for
|
|
36
|
+
- Use refs for mutable controller values and state for what the UI displays.
|
|
38
37
|
|
|
39
|
-
- Give each state value one
|
|
40
|
-
|
|
38
|
+
- Give each state value one place. Navigation goes in the URL, server snapshots in the query cache, edits in
|
|
39
|
+
form or local state, and shared data in a client store.
|
|
41
40
|
|
|
42
41
|
- Reset private state across identity and tenant changes; give each request its own server stores.
|
|
43
42
|
|
|
@@ -47,23 +46,23 @@ adds routing, server components, and caching on top of these.
|
|
|
47
46
|
|
|
48
47
|
## Read states and writes
|
|
49
48
|
|
|
50
|
-
- Keep the first pending
|
|
49
|
+
- Keep the first pending load, an empty result, and a failed request distinct. Show a stable
|
|
51
50
|
fallback, an explanation of the empty result, or safe error and retry UI for the matching state.
|
|
52
51
|
- Keep existing content during a background refresh or a pending next page. A failed refresh does
|
|
53
52
|
not erase a successful result. Revoked access removes stale private content.
|
|
54
53
|
- Capture the resource identity when work starts. A superseded request must not overwrite the
|
|
55
|
-
|
|
54
|
+
resource now in view.
|
|
56
55
|
- An optimistic update defines how to confirm or undo the operation.
|
|
57
|
-
-
|
|
56
|
+
- Show the result of a save apart from that of a refresh.
|
|
58
57
|
|
|
59
58
|
## URL state
|
|
60
59
|
|
|
61
|
-
- The URL owns filters, sorting, and other shareable navigation values. It carries a
|
|
60
|
+
- The URL owns filters, sorting, and other shareable navigation values. It carries a minimal,
|
|
62
61
|
versioned representation, never credentials, private drafts, or the whole store.
|
|
63
62
|
- Validate parsed values, and handle missing or malformed input without assertions or an unchecked
|
|
64
63
|
`JSON.parse`.
|
|
65
64
|
- Define the precedence among URL values, stored preferences, and defaults. When the URL owns a
|
|
66
|
-
value, back and forward navigation reach the
|
|
65
|
+
value, back and forward navigation reach the code that holds it.
|
|
67
66
|
- One synchronization path compares values before writing, so store-to-URL and URL-to-store updates
|
|
68
67
|
never loop.
|
|
69
68
|
- Keep unrelated query parameters and fragments. Use the installed router or the History API to replace history for transient edits and to push an entry when back navigation restores the previous state.
|
|
@@ -83,7 +82,7 @@ UI updates after hydration. Fix the mismatch instead of hiding warnings globally
|
|
|
83
82
|
- Give date/time formatting the same initial locale, time zone, and reference time where relative output otherwise differs.
|
|
84
83
|
- Do not branch rendered markup on `typeof window` as a routine hydration fix. Server and first
|
|
85
84
|
browser output agree on the visible tree.
|
|
86
|
-
- Theme initialization may need the
|
|
85
|
+
- Theme initialization may need the documented early script of its library and a narrow hydration
|
|
87
86
|
exception. Keep that exception local to the affected node.
|
|
88
87
|
- Do not mutate React-owned DOM to coordinate application state. Controlled state, refs, and
|
|
89
88
|
third-party imperative APIs have explicit ownership boundaries.
|
|
@@ -98,11 +97,6 @@ UI updates after hydration. Fix the mismatch instead of hiding warnings globally
|
|
|
98
97
|
## Forms and inputs
|
|
99
98
|
|
|
100
99
|
- Keep each input controlled or uncontrolled, never both. Choose per form and keep it.
|
|
101
|
-
- Validate input against the declared contract and expose its errors to the user. When the application
|
|
100
|
+
- Validate input against the declared contract and expose its errors to the user. When the application has a form
|
|
102
101
|
library, use its supported validation and state APIs.
|
|
103
102
|
- A form awaits the save and reports its result.
|
|
104
|
-
|
|
105
|
-
## Accessibility
|
|
106
|
-
|
|
107
|
-
- Use native interactive elements such as `button`, `a`, and `input`, or give each element the matching role,
|
|
108
|
-
keyboard handling, and focus management.
|