@shrkcrft/presets 0.1.0-alpha.7 → 0.1.0-alpha.9
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 +1 -1
- package/dist/builtin/builtin-presets.d.ts.map +1 -1
- package/dist/builtin/builtin-presets.js +9 -30
- package/dist/builtin/r26-presets.d.ts.map +1 -1
- package/dist/builtin/r26-presets.js +3 -3
- package/dist/builtin/r45-presets.d.ts.map +1 -1
- package/dist/builtin/r45-presets.js +3 -3
- package/dist/builtin/r47-presets.d.ts.map +1 -1
- package/dist/builtin/r47-presets.js +3 -3
- package/dist/builtin/shared-snippets.d.ts +3 -25
- package/dist/builtin/shared-snippets.d.ts.map +1 -1
- package/dist/builtin/shared-snippets.js +0 -265
- package/dist/emit/synthesize-files.d.ts.map +1 -1
- package/dist/emit/synthesize-files.js +17 -76
- package/package.json +8 -9
- package/dist/builtin/angular21-presets.d.ts +0 -9
- package/dist/builtin/angular21-presets.d.ts.map +0 -1
- package/dist/builtin/angular21-presets.js +0 -218
- package/dist/builtin/angular21-snippets.d.ts +0 -28
- package/dist/builtin/angular21-snippets.d.ts.map +0 -1
- package/dist/builtin/angular21-snippets.js +0 -243
- package/dist/builtin/nest11-presets.d.ts +0 -11
- package/dist/builtin/nest11-presets.d.ts.map +0 -1
- package/dist/builtin/nest11-presets.js +0 -257
- package/dist/builtin/nest11-snippets.d.ts +0 -32
- package/dist/builtin/nest11-snippets.d.ts.map +0 -1
- package/dist/builtin/nest11-snippets.js +0 -270
- package/dist/builtin/react19-presets.d.ts +0 -12
- package/dist/builtin/react19-presets.d.ts.map +0 -1
- package/dist/builtin/react19-presets.js +0 -299
- package/dist/builtin/react19-snippets.d.ts +0 -43
- package/dist/builtin/react19-snippets.d.ts.map +0 -1
- package/dist/builtin/react19-snippets.js +0 -363
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
// NestJS 11+ rule snippets.
|
|
2
|
-
//
|
|
3
|
-
// Covers the modern Nest service surface: module structure, thin
|
|
4
|
-
// controllers, DTOs with class-validator, the global ValidationPipe with
|
|
5
|
-
// strict options, async providers + lifecycle hooks, graceful shutdown,
|
|
6
|
-
// the Fastify adapter, caching, throttling, helmet, explicit CORS, JWT
|
|
7
|
-
// auth, structured logging via the Nest Logger, @nestjs/terminus health
|
|
8
|
-
// checks, and the TestingModule patterns for unit + supertest e2e.
|
|
9
|
-
//
|
|
10
|
-
// Each snippet is a string injected verbatim into a generated
|
|
11
|
-
// `sharkcraft/*.ts` file; `defineKnowledgeEntry`, `KnowledgeType`, and
|
|
12
|
-
// `KnowledgePriority` are provided by the local-mirror preamble the
|
|
13
|
-
// synthesizer prepends to the file.
|
|
14
|
-
import { ruleSnippet } from "./r26-snippets.js";
|
|
15
|
-
// ─── Architecture: modules, controllers, services, repos ──────────────────
|
|
16
|
-
export const NEST11_THIN_CONTROLLERS = ruleSnippet({
|
|
17
|
-
id: 'nest11.thin-controllers',
|
|
18
|
-
title: 'Controllers are thin — no business logic',
|
|
19
|
-
priority: 'critical',
|
|
20
|
-
tags: ['nestjs', 'nest-11', 'architecture'],
|
|
21
|
-
appliesWhen: ['generate-controller', 'review'],
|
|
22
|
-
content: 'Controllers parse the request (params/query/body via DTOs), call ONE service method, and return the result. No conditionals over domain rules, no inline database access, no orchestration of multiple services. If a controller method body is more than a handful of lines or branches on domain state, the logic belongs in a service.',
|
|
23
|
-
});
|
|
24
|
-
export const NEST11_SERVICE_OWNS_DOMAIN = ruleSnippet({
|
|
25
|
-
id: 'nest11.service-owns-domain',
|
|
26
|
-
title: 'Services own domain logic; repositories own data access',
|
|
27
|
-
priority: 'high',
|
|
28
|
-
tags: ['nestjs', 'nest-11', 'architecture'],
|
|
29
|
-
appliesWhen: ['generate-service', 'review'],
|
|
30
|
-
content: 'Services express domain rules and orchestrate work. Data access lives behind a repository (TypeORM Repository, Prisma client, or a hand-rolled interface). Services depend on repository interfaces, not on the ORM directly — that boundary is what makes unit tests cheap.',
|
|
31
|
-
});
|
|
32
|
-
export const NEST11_MODULE_PER_FEATURE = ruleSnippet({
|
|
33
|
-
id: 'nest11.module-per-feature',
|
|
34
|
-
title: 'Module per feature, not per layer',
|
|
35
|
-
priority: 'high',
|
|
36
|
-
tags: ['nestjs', 'nest-11', 'architecture'],
|
|
37
|
-
appliesWhen: ['create-feature'],
|
|
38
|
-
content: 'Each feature gets its own module under src/<feature>/ owning controller(s), service(s), DTOs, and (optionally) entities. Top-level grab-bags like ControllersModule / ServicesModule are an anti-pattern — they couple every feature to every other.',
|
|
39
|
-
});
|
|
40
|
-
export const NEST11_MODULE_PUBLIC_API = ruleSnippet({
|
|
41
|
-
id: 'nest11.module-public-api',
|
|
42
|
-
title: 'Each module exports its public API only',
|
|
43
|
-
priority: 'high',
|
|
44
|
-
tags: ['nestjs', 'nest-11', 'architecture', 'boundaries'],
|
|
45
|
-
appliesWhen: ['generate-code', 'review'],
|
|
46
|
-
content: 'A module\'s `exports: [...]` lists exactly the providers other modules may inject. Internal services stay unexported. Avoid `exports: [SomeModule]` re-exports unless you intentionally want the entire surface to be transitive.',
|
|
47
|
-
});
|
|
48
|
-
export const NEST11_NO_CIRCULAR_MODULES = ruleSnippet({
|
|
49
|
-
id: 'nest11.no-circular-modules',
|
|
50
|
-
title: 'Avoid circular module dependencies',
|
|
51
|
-
priority: 'critical',
|
|
52
|
-
tags: ['nestjs', 'nest-11', 'architecture'],
|
|
53
|
-
appliesWhen: ['generate-code', 'review'],
|
|
54
|
-
content: 'If module A imports module B and B imports A, extract the shared piece into a third module that both depend on. `forwardRef()` exists to escape genuine cycles in the dependency graph, not to paper over a missing abstraction.',
|
|
55
|
-
});
|
|
56
|
-
export const NEST11_DTO_AT_BOUNDARY = ruleSnippet({
|
|
57
|
-
id: 'nest11.dto-at-boundary',
|
|
58
|
-
title: 'DTOs at the HTTP boundary; never expose entities',
|
|
59
|
-
priority: 'critical',
|
|
60
|
-
tags: ['nestjs', 'nest-11', 'dto', 'security'],
|
|
61
|
-
appliesWhen: ['generate-controller', 'generate-dto'],
|
|
62
|
-
content: 'Request shapes live in `<feature>.dto.ts`; response shapes either in a dedicated response DTO or as a serialized projection. Never return an ORM entity directly — that leaks internal columns (audit fields, soft-delete flags, foreign keys) and couples your HTTP contract to your schema.',
|
|
63
|
-
});
|
|
64
|
-
// ─── Validation: ValidationPipe + class-validator ─────────────────────────
|
|
65
|
-
export const NEST11_GLOBAL_VALIDATION_PIPE = ruleSnippet({
|
|
66
|
-
id: 'nest11.global-validation-pipe',
|
|
67
|
-
title: 'Global ValidationPipe with whitelist + forbidNonWhitelisted + transform',
|
|
68
|
-
priority: 'critical',
|
|
69
|
-
tags: ['nestjs', 'nest-11', 'validation', 'security'],
|
|
70
|
-
appliesWhen: ['bootstrap'],
|
|
71
|
-
content: 'main.ts registers a global ValidationPipe: `app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, transformOptions: { enableImplicitConversion: true } }))`. whitelist strips unknown properties, forbidNonWhitelisted rejects them, transform turns plain objects into the DTO class so class-validator + class-transformer decorators fire.',
|
|
72
|
-
});
|
|
73
|
-
export const NEST11_CLASS_VALIDATOR_DTO = ruleSnippet({
|
|
74
|
-
id: 'nest11.class-validator-dto',
|
|
75
|
-
title: 'DTOs are classes with class-validator decorators',
|
|
76
|
-
priority: 'critical',
|
|
77
|
-
tags: ['nestjs', 'nest-11', 'validation', 'dto'],
|
|
78
|
-
appliesWhen: ['generate-dto'],
|
|
79
|
-
content: 'Define DTOs as classes (not interfaces) so class-validator can attach metadata. Use @IsString, @IsInt, @IsEmail, @IsUUID, @Length, @Min, @Max, @IsOptional, @IsEnum, @IsArray + @ValidateNested + @Type(() => Inner). Mark optional fields with @IsOptional() + a `?` on the property; the ValidationPipe will skip them when absent.',
|
|
80
|
-
});
|
|
81
|
-
export const NEST11_REQUEST_RESPONSE_DTOS = ruleSnippet({
|
|
82
|
-
id: 'nest11.request-response-dtos',
|
|
83
|
-
title: 'Separate request DTOs from response DTOs',
|
|
84
|
-
priority: 'high',
|
|
85
|
-
tags: ['nestjs', 'nest-11', 'dto'],
|
|
86
|
-
appliesWhen: ['generate-dto', 'generate-controller'],
|
|
87
|
-
content: 'CreateXDto, UpdateXDto, and XResponseDto are distinct classes — even when fields overlap. PartialType(CreateXDto) and PickType / OmitType from @nestjs/mapped-types compose them without duplication. This keeps the input surface (validated) and output surface (serialized) under independent control.',
|
|
88
|
-
});
|
|
89
|
-
export const NEST11_SWAGGER_DECORATORS = ruleSnippet({
|
|
90
|
-
id: 'nest11.swagger-decorators',
|
|
91
|
-
title: 'Annotate DTOs with @ApiProperty for OpenAPI',
|
|
92
|
-
priority: 'medium',
|
|
93
|
-
tags: ['nestjs', 'nest-11', 'openapi', 'swagger'],
|
|
94
|
-
appliesWhen: ['generate-dto'],
|
|
95
|
-
content: 'Pair each class-validator decorator with @ApiProperty / @ApiPropertyOptional from @nestjs/swagger. Set example, description, enum, and type explicitly — Swagger UI is the canonical contract reference for clients.',
|
|
96
|
-
});
|
|
97
|
-
// ─── Async lifecycle + graceful shutdown ──────────────────────────────────
|
|
98
|
-
export const NEST11_LIFECYCLE_HOOKS = ruleSnippet({
|
|
99
|
-
id: 'nest11.lifecycle-hooks',
|
|
100
|
-
title: 'Use Nest lifecycle hooks, not raw process events',
|
|
101
|
-
priority: 'high',
|
|
102
|
-
tags: ['nestjs', 'nest-11', 'lifecycle'],
|
|
103
|
-
appliesWhen: ['generate-service'],
|
|
104
|
-
content: 'Implement OnModuleInit / OnApplicationBootstrap for warm-up, OnModuleDestroy / OnApplicationShutdown for teardown. They run in DI-resolution order, so dependencies of a provider are still live during its destroy hook. Don\'t hook process.on(\'SIGTERM\') directly — Nest already wires it via enableShutdownHooks().',
|
|
105
|
-
});
|
|
106
|
-
export const NEST11_ENABLE_SHUTDOWN_HOOKS = ruleSnippet({
|
|
107
|
-
id: 'nest11.enable-shutdown-hooks',
|
|
108
|
-
title: 'Call app.enableShutdownHooks() in main.ts',
|
|
109
|
-
priority: 'high',
|
|
110
|
-
tags: ['nestjs', 'nest-11', 'lifecycle'],
|
|
111
|
-
appliesWhen: ['bootstrap'],
|
|
112
|
-
content: 'Without enableShutdownHooks() the OnModuleDestroy / OnApplicationShutdown hooks never fire on SIGTERM, leaving connections (DB pools, Kafka clients, etc.) dangling. Call it before app.listen().',
|
|
113
|
-
});
|
|
114
|
-
export const NEST11_ASYNC_PROVIDERS = ruleSnippet({
|
|
115
|
-
id: 'nest11.async-providers',
|
|
116
|
-
title: 'Use useFactory for async configuration providers',
|
|
117
|
-
priority: 'medium',
|
|
118
|
-
tags: ['nestjs', 'nest-11', 'di'],
|
|
119
|
-
appliesWhen: ['generate-module'],
|
|
120
|
-
content: 'Configuration that must be resolved at boot (env, secrets vault, schema generation) goes through `{ provide: TOKEN, useFactory: async (cfg) => …, inject: [ConfigService] }`. Don\'t lazy-load it inside a service\'s onModuleInit — that delays the readiness signal.',
|
|
121
|
-
});
|
|
122
|
-
// ─── Performance: Fastify, cache, throttler, pagination ──────────────────
|
|
123
|
-
export const NEST11_FASTIFY_ADAPTER = ruleSnippet({
|
|
124
|
-
id: 'nest11.fastify-adapter',
|
|
125
|
-
title: 'Use the Fastify adapter for high-throughput services',
|
|
126
|
-
priority: 'high',
|
|
127
|
-
tags: ['nestjs', 'nest-11', 'performance'],
|
|
128
|
-
appliesWhen: ['bootstrap'],
|
|
129
|
-
content: 'NestFactory.create<NestFastifyApplication>(AppModule, new FastifyAdapter()) gives ~2× the RPS of the default Express adapter and matches Nest\'s typed-decorator surface. Only stay on Express if you need a middleware that isn\'t available for Fastify (rare).',
|
|
130
|
-
});
|
|
131
|
-
export const NEST11_CACHE_MANAGER = ruleSnippet({
|
|
132
|
-
id: 'nest11.cache-manager',
|
|
133
|
-
title: 'Cache idempotent GETs via @nestjs/cache-manager',
|
|
134
|
-
priority: 'medium',
|
|
135
|
-
tags: ['nestjs', 'nest-11', 'performance'],
|
|
136
|
-
appliesWhen: ['generate-controller', 'optimize'],
|
|
137
|
-
content: 'Register CacheModule with a TTL appropriate to the data (seconds for hot reads, minutes for slowly-changing references). Decorate idempotent GET endpoints with @UseInterceptors(CacheInterceptor) or inject CACHE_MANAGER for explicit key-based caches. Never cache user-private responses without a per-user key.',
|
|
138
|
-
});
|
|
139
|
-
export const NEST11_THROTTLER = ruleSnippet({
|
|
140
|
-
id: 'nest11.throttler',
|
|
141
|
-
title: 'Rate-limit with @nestjs/throttler',
|
|
142
|
-
priority: 'high',
|
|
143
|
-
tags: ['nestjs', 'nest-11', 'performance', 'security'],
|
|
144
|
-
appliesWhen: ['bootstrap', 'generate-controller'],
|
|
145
|
-
content: 'Register ThrottlerModule globally with sane defaults (e.g. 60 requests / minute / IP), then loosen or tighten per route via @Throttle({ default: { limit, ttl } }) or @SkipThrottle() for internal endpoints. Without throttler a single client can DOS your service trivially.',
|
|
146
|
-
});
|
|
147
|
-
export const NEST11_PAGINATION_BY_DEFAULT = ruleSnippet({
|
|
148
|
-
id: 'nest11.pagination-by-default',
|
|
149
|
-
title: 'List endpoints paginate by default',
|
|
150
|
-
priority: 'high',
|
|
151
|
-
tags: ['nestjs', 'nest-11', 'performance'],
|
|
152
|
-
appliesWhen: ['generate-controller'],
|
|
153
|
-
content: 'Every list endpoint accepts `?page=1&pageSize=20` (or cursor-based) and caps pageSize server-side (e.g. max 100). Returning an unbounded array works on day 1 and dies in week 3 — paginate from the start so the contract never has to break.',
|
|
154
|
-
});
|
|
155
|
-
// ─── Security: helmet, CORS, auth, secrets ────────────────────────────────
|
|
156
|
-
export const NEST11_HELMET = ruleSnippet({
|
|
157
|
-
id: 'nest11.helmet',
|
|
158
|
-
title: 'Register helmet for HTTP security headers',
|
|
159
|
-
priority: 'critical',
|
|
160
|
-
tags: ['nestjs', 'nest-11', 'security'],
|
|
161
|
-
appliesWhen: ['bootstrap'],
|
|
162
|
-
content: 'Add `app.register(helmet)` (Fastify) or `app.use(helmet())` (Express) before any route is mounted. helmet sets X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security, and CSP defaults. Skipping it leaves you on every "missing security header" audit.',
|
|
163
|
-
});
|
|
164
|
-
export const NEST11_EXPLICIT_CORS = ruleSnippet({
|
|
165
|
-
id: 'nest11.explicit-cors',
|
|
166
|
-
title: 'CORS allowlist — never `origin: true` in production',
|
|
167
|
-
priority: 'critical',
|
|
168
|
-
tags: ['nestjs', 'nest-11', 'security'],
|
|
169
|
-
appliesWhen: ['bootstrap'],
|
|
170
|
-
content: 'Configure CORS with an explicit `origin: ["https://app.example.com"]` array (or a function that validates against an allowlist). `origin: true` reflects whatever the request sent — fine for local dev, catastrophic in prod for any cookie-/credential-bearing endpoint.',
|
|
171
|
-
});
|
|
172
|
-
export const NEST11_JWT_GUARDS = ruleSnippet({
|
|
173
|
-
id: 'nest11.jwt-guards',
|
|
174
|
-
title: 'Authentication via Guards, not middleware',
|
|
175
|
-
priority: 'high',
|
|
176
|
-
tags: ['nestjs', 'nest-11', 'security', 'auth'],
|
|
177
|
-
appliesWhen: ['generate-controller'],
|
|
178
|
-
content: 'Auth runs through @nestjs/passport + a JwtAuthGuard (or custom AuthGuard) applied via @UseGuards() at controller or method level. Guards see the full execution context (request, handler metadata) and integrate with @SetMetadata for role-based / permission-based checks. Middleware can\'t do that.',
|
|
179
|
-
});
|
|
180
|
-
export const NEST11_NO_SECRETS_IN_CODE = ruleSnippet({
|
|
181
|
-
id: 'nest11.no-secrets-in-code',
|
|
182
|
-
title: 'Secrets come from the env, never from source',
|
|
183
|
-
priority: 'critical',
|
|
184
|
-
tags: ['nestjs', 'nest-11', 'security'],
|
|
185
|
-
appliesWhen: ['generate-code', 'review'],
|
|
186
|
-
content: 'JWT signing keys, DB passwords, third-party API keys, encryption secrets — all loaded through @nestjs/config (ConfigService.get) from environment variables, .env (local only, in .gitignore), or a vault. A literal secret in a `.ts` file is a CVE waiting for a commit.',
|
|
187
|
-
});
|
|
188
|
-
export const NEST11_TRUST_PROXY_AWARE = ruleSnippet({
|
|
189
|
-
id: 'nest11.trust-proxy-aware',
|
|
190
|
-
title: 'Configure trust-proxy when behind a load balancer',
|
|
191
|
-
priority: 'medium',
|
|
192
|
-
tags: ['nestjs', 'nest-11', 'security'],
|
|
193
|
-
appliesWhen: ['bootstrap'],
|
|
194
|
-
content: 'When the service runs behind an ALB / Cloudflare / nginx, set the trust-proxy option on the adapter so req.ip + X-Forwarded-For resolve correctly. Otherwise throttler keys, audit logs, and rate-limiting all degenerate to the proxy\'s IP.',
|
|
195
|
-
});
|
|
196
|
-
// ─── Observability: Logger, structured logs, terminus ────────────────────
|
|
197
|
-
export const NEST11_LOGGER_WITH_CONTEXT = ruleSnippet({
|
|
198
|
-
id: 'nest11.logger-with-context',
|
|
199
|
-
title: 'Logger instances carry a context name',
|
|
200
|
-
priority: 'high',
|
|
201
|
-
tags: ['nestjs', 'nest-11', 'observability'],
|
|
202
|
-
appliesWhen: ['generate-service'],
|
|
203
|
-
content: 'In each provider, do `private readonly logger = new Logger(MyService.name)`. The context name appears in every log line so filtering by component is trivial. Don\'t share a single Logger instance across the app — you lose the grouping.',
|
|
204
|
-
});
|
|
205
|
-
export const NEST11_STRUCTURED_LOGS = ruleSnippet({
|
|
206
|
-
id: 'nest11.structured-logs',
|
|
207
|
-
title: 'JSON-structured logs in production (pino or nest-winston)',
|
|
208
|
-
priority: 'high',
|
|
209
|
-
tags: ['nestjs', 'nest-11', 'observability'],
|
|
210
|
-
appliesWhen: ['bootstrap', 'configure'],
|
|
211
|
-
content: 'Plug a structured logger (nestjs-pino or nest-winston) and route the Nest Logger through it. Production logs are JSON one-line records that ship cleanly into Loki / CloudWatch / Datadog. The default ConsoleLogger is fine for dev only.',
|
|
212
|
-
});
|
|
213
|
-
export const NEST11_NO_LOG_SECRETS = ruleSnippet({
|
|
214
|
-
id: 'nest11.no-log-secrets',
|
|
215
|
-
title: 'Never log secrets, tokens, PII, or full request bodies',
|
|
216
|
-
priority: 'critical',
|
|
217
|
-
tags: ['nestjs', 'nest-11', 'observability', 'security'],
|
|
218
|
-
appliesWhen: ['generate-code', 'review'],
|
|
219
|
-
content: 'Redact Authorization headers, JWTs, passwords, credit-card numbers, government IDs, and full request/response bodies that may contain user data. Configure the logger redact paths once (pino: redact: [\'req.headers.authorization\', \'body.password\']) so the discipline survives drive-by edits.',
|
|
220
|
-
});
|
|
221
|
-
export const NEST11_TERMINUS_HEALTH = ruleSnippet({
|
|
222
|
-
id: 'nest11.terminus-health',
|
|
223
|
-
title: 'Expose /health via @nestjs/terminus with liveness + readiness',
|
|
224
|
-
priority: 'high',
|
|
225
|
-
tags: ['nestjs', 'nest-11', 'observability'],
|
|
226
|
-
appliesWhen: ['generate-controller'],
|
|
227
|
-
content: 'Use @nestjs/terminus HealthCheckService to compose indicators (db.pingCheck, http.pingCheck, memory.heapCheck). Expose /health/liveness (process is up) AND /health/readiness (deps are reachable) separately — Kubernetes treats them differently. Don\'t return 200 from readiness when the DB is down.',
|
|
228
|
-
});
|
|
229
|
-
// ─── Testing: TestingModule + e2e ────────────────────────────────────────
|
|
230
|
-
export const NEST11_TESTING_MODULE = ruleSnippet({
|
|
231
|
-
id: 'nest11.testing-module',
|
|
232
|
-
title: 'Unit tests use Test.createTestingModule + overrideProvider',
|
|
233
|
-
priority: 'high',
|
|
234
|
-
tags: ['nestjs', 'nest-11', 'testing'],
|
|
235
|
-
appliesWhen: ['generate-test'],
|
|
236
|
-
content: 'Build a TestingModule that imports the module under test, then `overrideProvider(SlowDep).useValue(mock)` for whatever you want to fake. Resolve the unit under test with `module.get(MyService)`. Avoid `new MyService(...)` outside of testing the constructor itself — DI is part of the contract.',
|
|
237
|
-
});
|
|
238
|
-
export const NEST11_E2E_SUPERTEST = ruleSnippet({
|
|
239
|
-
id: 'nest11.e2e-supertest',
|
|
240
|
-
title: 'E2E with supertest against the real AppModule',
|
|
241
|
-
priority: 'high',
|
|
242
|
-
tags: ['nestjs', 'nest-11', 'testing'],
|
|
243
|
-
appliesWhen: ['generate-test'],
|
|
244
|
-
content: 'E2E tests bootstrap a TestingModule from AppModule, build a Nest application, and drive it with supertest (`request(app.getHttpServer()).get(...)`). Override only the truly slow/expensive deps (external HTTP, message brokers); keep the validation pipeline, guards, and interceptors live — that\'s the contract being tested.',
|
|
245
|
-
});
|
|
246
|
-
export const NEST11_TEST_FILE_LAYOUT = ruleSnippet({
|
|
247
|
-
id: 'nest11.test-file-layout',
|
|
248
|
-
title: 'Unit specs co-located; e2e under test/',
|
|
249
|
-
priority: 'medium',
|
|
250
|
-
tags: ['nestjs', 'nest-11', 'testing'],
|
|
251
|
-
appliesWhen: ['generate-test'],
|
|
252
|
-
content: 'Unit specs live next to the unit (`users.service.spec.ts` beside `users.service.ts`). E2E specs live under `test/*.e2e-spec.ts` — Nest\'s default jest-e2e.json glob matches that pattern. Don\'t mix the two; they have different setup costs and different debugging stories.',
|
|
253
|
-
});
|
|
254
|
-
// ─── API design ──────────────────────────────────────────────────────────
|
|
255
|
-
export const NEST11_API_VERSIONING = ruleSnippet({
|
|
256
|
-
id: 'nest11.api-versioning',
|
|
257
|
-
title: 'Enable versioning when the contract is consumed externally',
|
|
258
|
-
priority: 'medium',
|
|
259
|
-
tags: ['nestjs', 'nest-11', 'api'],
|
|
260
|
-
appliesWhen: ['bootstrap', 'generate-controller'],
|
|
261
|
-
content: 'For any service whose API has external consumers, call `app.enableVersioning({ type: VersioningType.URI, defaultVersion: \'1\' })` at bootstrap. Annotate controllers with @Controller({ path: \'users\', version: \'1\' }). Breaking changes ship as v2 alongside v1 — never as a silent overwrite.',
|
|
262
|
-
});
|
|
263
|
-
export const NEST11_NO_QUERY_IN_CONTROLLER = ruleSnippet({
|
|
264
|
-
id: 'nest11.no-query-in-controller',
|
|
265
|
-
title: 'Never query the database from a controller',
|
|
266
|
-
priority: 'high',
|
|
267
|
-
tags: ['nestjs', 'nest-11', 'architecture'],
|
|
268
|
-
appliesWhen: ['generate-controller', 'review'],
|
|
269
|
-
content: 'Repositories are injected into services, not controllers. A controller that imports `Repository<User>` or `prisma.user` directly is on the path to a 600-line "controller that does everything" — back it out into a service.',
|
|
270
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { IPreset } from '../model/preset.js';
|
|
2
|
-
export declare const REACT_19_MODERN_COMPONENTS: IPreset;
|
|
3
|
-
export declare const REACT_19_HOOKS_DISCIPLINE: IPreset;
|
|
4
|
-
export declare const REACT_19_ACTIONS_FORMS: IPreset;
|
|
5
|
-
export declare const REACT_19_STATE: IPreset;
|
|
6
|
-
export declare const REACT_19_PERFORMANCE: IPreset;
|
|
7
|
-
export declare const REACT_19_CONCURRENT: IPreset;
|
|
8
|
-
export declare const REACT_19_TESTING: IPreset;
|
|
9
|
-
export declare const REACT_19_RSC: IPreset;
|
|
10
|
-
export declare const REACT_19_MODERN: IPreset;
|
|
11
|
-
export declare const REACT_19_PRESETS: readonly IPreset[];
|
|
12
|
-
//# sourceMappingURL=react19-presets.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"react19-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/react19-presets.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAmElD,eAAO,MAAM,0BAA0B,EAAE,OAgCvC,CAAC;AAIH,eAAO,MAAM,yBAAyB,EAAE,OA+BtC,CAAC;AAIH,eAAO,MAAM,sBAAsB,EAAE,OA8BnC,CAAC;AAIH,eAAO,MAAM,cAAc,EAAE,OA6B3B,CAAC;AAIH,eAAO,MAAM,oBAAoB,EAAE,OA6BjC,CAAC;AAIH,eAAO,MAAM,mBAAmB,EAAE,OA6BhC,CAAC;AAIH,eAAO,MAAM,gBAAgB,EAAE,OA4B7B,CAAC;AAIH,eAAO,MAAM,YAAY,EAAE,OA6BzB,CAAC;AAIH,eAAO,MAAM,eAAe,EAAE,OA8C5B,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,SAAS,OAAO,EAU7C,CAAC"}
|
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
// React 19+ preset family.
|
|
2
|
-
//
|
|
3
|
-
// Eight presets — seven focused on a single slice of the modernisation
|
|
4
|
-
// surface, one comprehensive `react-19-modern` that composes the rest.
|
|
5
|
-
// Targets HasReact workspaces with weight 11-12 so the recommender
|
|
6
|
-
// prefers these when the workspace is React-based. The existing legacy
|
|
7
|
-
// `frontend-app` (weight 6) stays for projects pinned to it.
|
|
8
|
-
//
|
|
9
|
-
// Each preset's `paths` references the canonical React SPA structure
|
|
10
|
-
// (src/components, src/hooks, src/pages, src/lib) — the init paths
|
|
11
|
-
// advisory annotator flags any of these that don't exist in the live
|
|
12
|
-
// workspace, so RSC-framework users (Next.js app router under app/) see
|
|
13
|
-
// the mismatch immediately.
|
|
14
|
-
import { WorkspaceProfile } from '@shrkcrft/workspace';
|
|
15
|
-
import { definePreset } from "../define/define-preset.js";
|
|
16
|
-
import { COMMON_AGENT_BRIEFING, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_SAFETY_RULE, OVERVIEW_DOC, REACT_PATH_COMPONENTS, REACT_PATH_HOOKS, REACT_PATH_LIB, REACT_PATH_PAGES, } from "./shared-snippets.js";
|
|
17
|
-
import { REACT19_ASYNC_TRANSITIONS, REACT19_AVOID_PROP_DRILLING, REACT19_CLIENT_STATE_PROPORTIONAL, REACT19_COMPILER_AUTO_MEMO, REACT19_CONTEXT_AS_PROVIDER, REACT19_CUSTOM_HOOK_NAMING, REACT19_DOCUMENT_METADATA, REACT19_EFFECT_CLEANUP, REACT19_FORMS_LIBRARY, REACT19_FORM_ACTIONS, REACT19_FUNCTION_COMPONENTS, REACT19_IMAGE_OPTIMIZATION, REACT19_KEYS_FOR_RESET, REACT19_LAZY_SUSPENSE, REACT19_MSW, REACT19_NO_DERIVED_STATE_IN_EFFECT, REACT19_NO_FETCH_IN_EFFECT, REACT19_NO_REACT_FC, REACT19_PROPS_INTERFACE, REACT19_REF_AS_PROP, REACT19_RULES_OF_HOOKS, REACT19_SELF_CLOSING, REACT19_SERVER_ACTIONS, REACT19_SERVER_COMPONENTS_DEFAULT, REACT19_SERVER_STATE_LIBRARY, REACT19_STABLE_KEYS, REACT19_STREAMING_SSR, REACT19_STRICT_MODE, REACT19_STYLESHEETS_IN_TREE, REACT19_SUSPENSE_BOUNDARIES, REACT19_TEST_BEHAVIOR_NOT_IMPL, REACT19_TESTING_LIBRARY, REACT19_USE_ACTION_STATE, REACT19_USE_CLIENT_BOUNDARY, REACT19_USE_DEFERRED_VALUE, REACT19_USE_EFFECT_FOR_EXTERNAL_SYNC, REACT19_USE_FORM_STATUS, REACT19_USE_HOOK, REACT19_USE_OPTIMISTIC, REACT19_USE_TRANSITION, REACT19_VIRTUALIZE_LISTS, REACT19_VITEST, } from "./react19-snippets.js";
|
|
18
|
-
const REACT19_TAGS = ['react', 'react-19', 'frontend'];
|
|
19
|
-
const REACT19_NEXT_COMMANDS = [
|
|
20
|
-
'shrk doctor',
|
|
21
|
-
'shrk task "<task>"',
|
|
22
|
-
'shrk ci scaffold github-actions --quickstart',
|
|
23
|
-
];
|
|
24
|
-
// ─── 1) Modern component shape ────────────────────────────────────────────
|
|
25
|
-
export const REACT_19_MODERN_COMPONENTS = definePreset({
|
|
26
|
-
id: 'react-19-modern-components',
|
|
27
|
-
title: 'React 19 — modern component shape',
|
|
28
|
-
description: 'Function components only (no class components, no React.FC), props declared as interfaces, ref accepted as a regular prop (no forwardRef in the common case), <Context> rendered as the provider directly, document metadata in the component tree, scoped stylesheets via <link precedence>.',
|
|
29
|
-
tags: [...REACT19_TAGS, 'components'],
|
|
30
|
-
appliesTo: [WorkspaceProfile.HasReact, WorkspaceProfile.IsFrontend],
|
|
31
|
-
weight: 11,
|
|
32
|
-
includes: {
|
|
33
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
34
|
-
rules: [
|
|
35
|
-
COMMON_SAFETY_RULE,
|
|
36
|
-
REACT19_FUNCTION_COMPONENTS,
|
|
37
|
-
REACT19_NO_REACT_FC,
|
|
38
|
-
REACT19_PROPS_INTERFACE,
|
|
39
|
-
REACT19_REF_AS_PROP,
|
|
40
|
-
REACT19_CONTEXT_AS_PROVIDER,
|
|
41
|
-
REACT19_DOCUMENT_METADATA,
|
|
42
|
-
REACT19_STYLESHEETS_IN_TREE,
|
|
43
|
-
REACT19_SELF_CLOSING,
|
|
44
|
-
],
|
|
45
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_HOOKS, REACT_PATH_LIB],
|
|
46
|
-
templates: [],
|
|
47
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
48
|
-
docs: {
|
|
49
|
-
'overview.md': OVERVIEW_DOC('React 19 modern components', 'Function components only. No React.FC, no class components for new code. Props live in interfaces. Refs are regular props. <MyContext value={x}>{children}</MyContext> — no .Provider. Document metadata (<title>, <meta>) renders inside the tree; React hoists it.'),
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
53
|
-
});
|
|
54
|
-
// ─── 2) Hooks discipline ──────────────────────────────────────────────────
|
|
55
|
-
export const REACT_19_HOOKS_DISCIPLINE = definePreset({
|
|
56
|
-
id: 'react-19-hooks-discipline',
|
|
57
|
-
title: 'React 19 — hooks discipline',
|
|
58
|
-
description: 'Rules of hooks enforced via eslint-plugin-react-hooks (errors, not warnings). useEffect is for external-system sync only — derived state is computed during render, event responses live in handlers, fetches live in a server-state library, state resets are keyed. Custom hooks start with `use` and clean up their subscriptions.',
|
|
59
|
-
tags: [...REACT19_TAGS, 'hooks'],
|
|
60
|
-
appliesTo: [WorkspaceProfile.HasReact],
|
|
61
|
-
weight: 11,
|
|
62
|
-
includes: {
|
|
63
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
64
|
-
rules: [
|
|
65
|
-
COMMON_SAFETY_RULE,
|
|
66
|
-
REACT19_RULES_OF_HOOKS,
|
|
67
|
-
REACT19_USE_EFFECT_FOR_EXTERNAL_SYNC,
|
|
68
|
-
REACT19_NO_DERIVED_STATE_IN_EFFECT,
|
|
69
|
-
REACT19_NO_FETCH_IN_EFFECT,
|
|
70
|
-
REACT19_CUSTOM_HOOK_NAMING,
|
|
71
|
-
REACT19_EFFECT_CLEANUP,
|
|
72
|
-
REACT19_KEYS_FOR_RESET,
|
|
73
|
-
],
|
|
74
|
-
paths: [REACT_PATH_HOOKS, REACT_PATH_COMPONENTS],
|
|
75
|
-
templates: [],
|
|
76
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
77
|
-
docs: {
|
|
78
|
-
'overview.md': OVERVIEW_DOC('React 19 hooks discipline', 'Hooks at the top, never conditional. useEffect ONLY for syncing with external systems. Derived values are computed in render. Fetches go through TanStack Query / SWR / RTK Query. State resets use a `key` prop on the consumer, not a useEffect.'),
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
82
|
-
});
|
|
83
|
-
// ─── 3) Actions + forms (React 19) ────────────────────────────────────────
|
|
84
|
-
export const REACT_19_ACTIONS_FORMS = definePreset({
|
|
85
|
-
id: 'react-19-actions-forms',
|
|
86
|
-
title: 'React 19 — Actions, async transitions, optimistic UI',
|
|
87
|
-
description: 'The React 19 Actions surface: <form action> for submission, useActionState for result + pending + error in one hook, useFormStatus for child-level pending UI, useOptimistic for instant feedback on mutations, use() for promises and contexts in conditionals, async functions passed to startTransition / useTransition.',
|
|
88
|
-
tags: [...REACT19_TAGS, 'actions', 'forms'],
|
|
89
|
-
appliesTo: [WorkspaceProfile.HasReact, WorkspaceProfile.IsFrontend],
|
|
90
|
-
weight: 11,
|
|
91
|
-
includes: {
|
|
92
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
93
|
-
rules: [
|
|
94
|
-
COMMON_SAFETY_RULE,
|
|
95
|
-
REACT19_FORM_ACTIONS,
|
|
96
|
-
REACT19_USE_ACTION_STATE,
|
|
97
|
-
REACT19_USE_FORM_STATUS,
|
|
98
|
-
REACT19_USE_OPTIMISTIC,
|
|
99
|
-
REACT19_USE_HOOK,
|
|
100
|
-
REACT19_ASYNC_TRANSITIONS,
|
|
101
|
-
],
|
|
102
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_HOOKS],
|
|
103
|
-
templates: [],
|
|
104
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
105
|
-
docs: {
|
|
106
|
-
'overview.md': OVERVIEW_DOC('React 19 Actions', '<form action={async (fd) => ...}> for submission. useActionState owns pending + result. useFormStatus inside form children for spinners. useOptimistic for instant UI on writes. use(promise) inside Suspense. startTransition accepts async functions.'),
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
110
|
-
});
|
|
111
|
-
// ─── 4) State management — server, client, forms ─────────────────────────
|
|
112
|
-
export const REACT_19_STATE = definePreset({
|
|
113
|
-
id: 'react-19-state',
|
|
114
|
-
title: 'React 19 — state management (server, client, forms)',
|
|
115
|
-
description: 'Server state in TanStack Query / SWR / RTK Query (never useState). Client state in the right shape for its scope: local useState, lifted state for siblings, Context for low-frequency cross-tree, a real store (Zustand / Jotai / RTK) for high-frequency cross-tree. Forms past trivial use React Hook Form + Zod.',
|
|
116
|
-
tags: [...REACT19_TAGS, 'state'],
|
|
117
|
-
appliesTo: [WorkspaceProfile.HasReact],
|
|
118
|
-
weight: 11,
|
|
119
|
-
includes: {
|
|
120
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
121
|
-
rules: [
|
|
122
|
-
COMMON_SAFETY_RULE,
|
|
123
|
-
REACT19_SERVER_STATE_LIBRARY,
|
|
124
|
-
REACT19_CLIENT_STATE_PROPORTIONAL,
|
|
125
|
-
REACT19_FORMS_LIBRARY,
|
|
126
|
-
REACT19_AVOID_PROP_DRILLING,
|
|
127
|
-
REACT19_KEYS_FOR_RESET,
|
|
128
|
-
],
|
|
129
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_HOOKS, REACT_PATH_LIB],
|
|
130
|
-
templates: [],
|
|
131
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
132
|
-
docs: {
|
|
133
|
-
'overview.md': OVERVIEW_DOC('React 19 state', 'Server state belongs in a query library — TanStack Query is the default. Client state is sized to its scope: local / lifted / Context (low-frequency only) / store (high-frequency). Non-trivial forms use React Hook Form + Zod. Long prop-drilling chains are a refactor signal.'),
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
137
|
-
});
|
|
138
|
-
// ─── 5) Performance — Compiler, lazy, virtualization, images ─────────────
|
|
139
|
-
export const REACT_19_PERFORMANCE = definePreset({
|
|
140
|
-
id: 'react-19-performance',
|
|
141
|
-
title: 'React 19 — performance baseline',
|
|
142
|
-
description: 'React Compiler for automatic memoization (drops most hand-rolled useMemo / useCallback). Route-level code-splitting via React.lazy + Suspense. Virtualization past ~100 visible rows. Stable list keys (never the array index). Image dimensions explicit; lazy by default.',
|
|
143
|
-
tags: [...REACT19_TAGS, 'performance'],
|
|
144
|
-
appliesTo: [WorkspaceProfile.HasReact],
|
|
145
|
-
weight: 11,
|
|
146
|
-
includes: {
|
|
147
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
148
|
-
rules: [
|
|
149
|
-
COMMON_SAFETY_RULE,
|
|
150
|
-
REACT19_COMPILER_AUTO_MEMO,
|
|
151
|
-
REACT19_LAZY_SUSPENSE,
|
|
152
|
-
REACT19_VIRTUALIZE_LISTS,
|
|
153
|
-
REACT19_STABLE_KEYS,
|
|
154
|
-
REACT19_IMAGE_OPTIMIZATION,
|
|
155
|
-
],
|
|
156
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_PAGES],
|
|
157
|
-
templates: [],
|
|
158
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
159
|
-
docs: {
|
|
160
|
-
'overview.md': OVERVIEW_DOC('React 19 performance', 'Turn on the React Compiler (babel-plugin-react-compiler) and stop hand-rolling memo unless the profiler says otherwise. Route boundaries lazy-load. Long lists virtualize. List keys are stable ids, never the array index. Images carry explicit width/height + loading="lazy".'),
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
164
|
-
});
|
|
165
|
-
// ─── 6) Concurrent rendering ──────────────────────────────────────────────
|
|
166
|
-
export const REACT_19_CONCURRENT = definePreset({
|
|
167
|
-
id: 'react-19-concurrent',
|
|
168
|
-
title: 'React 19 — concurrent rendering',
|
|
169
|
-
description: 'useTransition / startTransition to keep input responsive under slow updates, useDeferredValue (with React 19\'s initialValue) for lagged derived renders, deliberate Suspense-boundary placement for streaming reveal, StrictMode in dev to surface concurrency bugs early.',
|
|
170
|
-
tags: [...REACT19_TAGS, 'concurrent'],
|
|
171
|
-
appliesTo: [WorkspaceProfile.HasReact],
|
|
172
|
-
weight: 11,
|
|
173
|
-
includes: {
|
|
174
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
175
|
-
rules: [
|
|
176
|
-
COMMON_SAFETY_RULE,
|
|
177
|
-
REACT19_USE_TRANSITION,
|
|
178
|
-
REACT19_USE_DEFERRED_VALUE,
|
|
179
|
-
REACT19_SUSPENSE_BOUNDARIES,
|
|
180
|
-
REACT19_STRICT_MODE,
|
|
181
|
-
REACT19_ASYNC_TRANSITIONS,
|
|
182
|
-
],
|
|
183
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_PAGES],
|
|
184
|
-
templates: [],
|
|
185
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
186
|
-
docs: {
|
|
187
|
-
'overview.md': OVERVIEW_DOC('React 19 concurrent rendering', 'Slow updates go through startTransition. Derived expensive views use useDeferredValue. Suspense boundaries are placed where a UI region should reveal together. StrictMode catches missing cleanups and impure renders in dev. React 19: startTransition accepts async functions.'),
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
191
|
-
});
|
|
192
|
-
// ─── 7) Testing ──────────────────────────────────────────────────────────
|
|
193
|
-
export const REACT_19_TESTING = definePreset({
|
|
194
|
-
id: 'react-19-testing',
|
|
195
|
-
title: 'React 19 — Vitest + Testing Library + userEvent + MSW',
|
|
196
|
-
description: 'Vitest for Vite-based apps, @testing-library/react for rendering + querying, userEvent.setup() for interactions (not fireEvent), MSW for network mocking, behavior-not-implementation as the testing posture.',
|
|
197
|
-
tags: [...REACT19_TAGS, 'testing'],
|
|
198
|
-
appliesTo: [WorkspaceProfile.HasReact],
|
|
199
|
-
weight: 11,
|
|
200
|
-
includes: {
|
|
201
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
202
|
-
rules: [
|
|
203
|
-
COMMON_SAFETY_RULE,
|
|
204
|
-
REACT19_VITEST,
|
|
205
|
-
REACT19_TESTING_LIBRARY,
|
|
206
|
-
REACT19_TEST_BEHAVIOR_NOT_IMPL,
|
|
207
|
-
REACT19_MSW,
|
|
208
|
-
],
|
|
209
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_HOOKS],
|
|
210
|
-
templates: [],
|
|
211
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_UNIT_TEST],
|
|
212
|
-
docs: {
|
|
213
|
-
'overview.md': OVERVIEW_DOC('React 19 testing', 'Vitest runs the suite. @testing-library/react queries by role/label/text. userEvent.setup() drives the keyboard + pointer. MSW intercepts fetch at the network. Asserts target what the user sees — not internal hooks or state.'),
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
217
|
-
});
|
|
218
|
-
// ─── 8) React Server Components (RSC frameworks) ─────────────────────────
|
|
219
|
-
export const REACT_19_RSC = definePreset({
|
|
220
|
-
id: 'react-19-rsc',
|
|
221
|
-
title: 'React 19 — Server Components + Server Actions',
|
|
222
|
-
description: 'For framework-driven fullstack apps (Next.js app router, Remix, Waku): components are Server Components by default; "use client" is pushed to leaf components that actually need interactivity; Server Actions replace manual API routes for mutations; SSR streams through Suspense boundaries.',
|
|
223
|
-
tags: [...REACT19_TAGS, 'rsc', 'ssr'],
|
|
224
|
-
appliesTo: [WorkspaceProfile.HasReact, WorkspaceProfile.IsFrontend],
|
|
225
|
-
weight: 11,
|
|
226
|
-
includes: {
|
|
227
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
228
|
-
rules: [
|
|
229
|
-
COMMON_SAFETY_RULE,
|
|
230
|
-
REACT19_SERVER_COMPONENTS_DEFAULT,
|
|
231
|
-
REACT19_USE_CLIENT_BOUNDARY,
|
|
232
|
-
REACT19_SERVER_ACTIONS,
|
|
233
|
-
REACT19_STREAMING_SSR,
|
|
234
|
-
REACT19_SUSPENSE_BOUNDARIES,
|
|
235
|
-
],
|
|
236
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_PAGES, REACT_PATH_LIB],
|
|
237
|
-
templates: [],
|
|
238
|
-
pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
|
|
239
|
-
docs: {
|
|
240
|
-
'overview.md': OVERVIEW_DOC('React 19 Server Components', 'Server-first by default in RSC frameworks. "use client" lives at the smallest interactive leaf, not the page root. Mutations go through Server Actions ("use server" functions) instead of manual API routes. SSR streams: shell ships first, slow data fills via Suspense.'),
|
|
241
|
-
},
|
|
242
|
-
},
|
|
243
|
-
recommendedNextCommands: REACT19_NEXT_COMMANDS,
|
|
244
|
-
});
|
|
245
|
-
// ─── 9) The whole stack — composes 1-7 ──────────────────────────────────
|
|
246
|
-
export const REACT_19_MODERN = definePreset({
|
|
247
|
-
id: 'react-19-modern',
|
|
248
|
-
title: 'React 19 — modern stack (components + hooks + actions + state + perf + concurrent + testing)',
|
|
249
|
-
description: 'The canonical preset for a new React 19+ app. Composes seven focused presets — components, hooks discipline, Actions, state, performance, concurrent, testing — and leaves RSC opt-in via the separate react-19-rsc preset (only relevant for framework apps).',
|
|
250
|
-
tags: [...REACT19_TAGS, 'comprehensive'],
|
|
251
|
-
appliesTo: [WorkspaceProfile.HasReact, WorkspaceProfile.IsFrontend],
|
|
252
|
-
weight: 12,
|
|
253
|
-
composes: [
|
|
254
|
-
'react-19-modern-components',
|
|
255
|
-
'react-19-hooks-discipline',
|
|
256
|
-
'react-19-actions-forms',
|
|
257
|
-
'react-19-state',
|
|
258
|
-
'react-19-performance',
|
|
259
|
-
'react-19-concurrent',
|
|
260
|
-
'react-19-testing',
|
|
261
|
-
],
|
|
262
|
-
includes: {
|
|
263
|
-
knowledge: [COMMON_AGENT_BRIEFING],
|
|
264
|
-
rules: [
|
|
265
|
-
COMMON_SAFETY_RULE,
|
|
266
|
-
// StrictMode and stable keys are baseline enough to repeat here.
|
|
267
|
-
REACT19_STRICT_MODE,
|
|
268
|
-
REACT19_STABLE_KEYS,
|
|
269
|
-
],
|
|
270
|
-
paths: [REACT_PATH_COMPONENTS, REACT_PATH_HOOKS, REACT_PATH_PAGES, REACT_PATH_LIB],
|
|
271
|
-
templates: [],
|
|
272
|
-
pipelines: [
|
|
273
|
-
COMMON_PIPELINE_CONTEXT_ONLY,
|
|
274
|
-
COMMON_PIPELINE_FEATURE_DEV,
|
|
275
|
-
COMMON_PIPELINE_UNIT_TEST,
|
|
276
|
-
],
|
|
277
|
-
docs: {
|
|
278
|
-
'overview.md': OVERVIEW_DOC('React 19 modern stack', 'Function components, no React.FC, ref-as-prop. Hooks at the top, useEffect only for external sync. <form action> + useActionState + useOptimistic for forms. TanStack Query for server state; the right shape for client state. React Compiler does memo for you. Lazy + Suspense for code-split. useTransition / useDeferredValue under load. Vitest + Testing Library + userEvent + MSW. Add react-19-rsc if the project is on a Server Components framework.'),
|
|
279
|
-
},
|
|
280
|
-
},
|
|
281
|
-
recommendedNextCommands: [
|
|
282
|
-
'shrk doctor',
|
|
283
|
-
'shrk surface list',
|
|
284
|
-
'shrk task "<task>"',
|
|
285
|
-
'shrk presets get react-19-rsc # add this preset if using Next.js / Remix / Waku',
|
|
286
|
-
],
|
|
287
|
-
surfaceProfile: 'small-app',
|
|
288
|
-
});
|
|
289
|
-
export const REACT_19_PRESETS = Object.freeze([
|
|
290
|
-
REACT_19_MODERN_COMPONENTS,
|
|
291
|
-
REACT_19_HOOKS_DISCIPLINE,
|
|
292
|
-
REACT_19_ACTIONS_FORMS,
|
|
293
|
-
REACT_19_STATE,
|
|
294
|
-
REACT_19_PERFORMANCE,
|
|
295
|
-
REACT_19_CONCURRENT,
|
|
296
|
-
REACT_19_TESTING,
|
|
297
|
-
REACT_19_RSC,
|
|
298
|
-
REACT_19_MODERN,
|
|
299
|
-
]);
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export declare const REACT19_FUNCTION_COMPONENTS: string;
|
|
2
|
-
export declare const REACT19_NO_REACT_FC: string;
|
|
3
|
-
export declare const REACT19_PROPS_INTERFACE: string;
|
|
4
|
-
export declare const REACT19_REF_AS_PROP: string;
|
|
5
|
-
export declare const REACT19_CONTEXT_AS_PROVIDER: string;
|
|
6
|
-
export declare const REACT19_DOCUMENT_METADATA: string;
|
|
7
|
-
export declare const REACT19_STYLESHEETS_IN_TREE: string;
|
|
8
|
-
export declare const REACT19_SELF_CLOSING: string;
|
|
9
|
-
export declare const REACT19_RULES_OF_HOOKS: string;
|
|
10
|
-
export declare const REACT19_USE_EFFECT_FOR_EXTERNAL_SYNC: string;
|
|
11
|
-
export declare const REACT19_NO_DERIVED_STATE_IN_EFFECT: string;
|
|
12
|
-
export declare const REACT19_NO_FETCH_IN_EFFECT: string;
|
|
13
|
-
export declare const REACT19_CUSTOM_HOOK_NAMING: string;
|
|
14
|
-
export declare const REACT19_EFFECT_CLEANUP: string;
|
|
15
|
-
export declare const REACT19_FORM_ACTIONS: string;
|
|
16
|
-
export declare const REACT19_USE_ACTION_STATE: string;
|
|
17
|
-
export declare const REACT19_USE_FORM_STATUS: string;
|
|
18
|
-
export declare const REACT19_USE_OPTIMISTIC: string;
|
|
19
|
-
export declare const REACT19_USE_HOOK: string;
|
|
20
|
-
export declare const REACT19_ASYNC_TRANSITIONS: string;
|
|
21
|
-
export declare const REACT19_SERVER_STATE_LIBRARY: string;
|
|
22
|
-
export declare const REACT19_CLIENT_STATE_PROPORTIONAL: string;
|
|
23
|
-
export declare const REACT19_FORMS_LIBRARY: string;
|
|
24
|
-
export declare const REACT19_AVOID_PROP_DRILLING: string;
|
|
25
|
-
export declare const REACT19_KEYS_FOR_RESET: string;
|
|
26
|
-
export declare const REACT19_COMPILER_AUTO_MEMO: string;
|
|
27
|
-
export declare const REACT19_LAZY_SUSPENSE: string;
|
|
28
|
-
export declare const REACT19_VIRTUALIZE_LISTS: string;
|
|
29
|
-
export declare const REACT19_STABLE_KEYS: string;
|
|
30
|
-
export declare const REACT19_IMAGE_OPTIMIZATION: string;
|
|
31
|
-
export declare const REACT19_USE_TRANSITION: string;
|
|
32
|
-
export declare const REACT19_USE_DEFERRED_VALUE: string;
|
|
33
|
-
export declare const REACT19_SUSPENSE_BOUNDARIES: string;
|
|
34
|
-
export declare const REACT19_STRICT_MODE: string;
|
|
35
|
-
export declare const REACT19_VITEST: string;
|
|
36
|
-
export declare const REACT19_TESTING_LIBRARY: string;
|
|
37
|
-
export declare const REACT19_TEST_BEHAVIOR_NOT_IMPL: string;
|
|
38
|
-
export declare const REACT19_MSW: string;
|
|
39
|
-
export declare const REACT19_SERVER_COMPONENTS_DEFAULT: string;
|
|
40
|
-
export declare const REACT19_USE_CLIENT_BOUNDARY: string;
|
|
41
|
-
export declare const REACT19_SERVER_ACTIONS: string;
|
|
42
|
-
export declare const REACT19_STREAMING_SSR: string;
|
|
43
|
-
//# sourceMappingURL=react19-snippets.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"react19-snippets.d.ts","sourceRoot":"","sources":["../../src/builtin/react19-snippets.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,2BAA2B,QAQtC,CAAC;AAEH,eAAO,MAAM,mBAAmB,QAQ9B,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAQlC,CAAC;AAEH,eAAO,MAAM,mBAAmB,QAQ9B,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAQtC,CAAC;AAEH,eAAO,MAAM,yBAAyB,QAQpC,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAQtC,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAQ/B,CAAC;AAIH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,oCAAoC,QAQ/C,CAAC;AAEH,eAAO,MAAM,kCAAkC,QAQ7C,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAIH,eAAO,MAAM,oBAAoB,QAQ/B,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAQnC,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAQlC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,gBAAgB,QAQ3B,CAAC;AAEH,eAAO,MAAM,yBAAyB,QAQpC,CAAC;AAIH,eAAO,MAAM,4BAA4B,QAQvC,CAAC;AAEH,eAAO,MAAM,iCAAiC,QAQ5C,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAQhC,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAQtC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAIH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAQhC,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAQnC,CAAC;AAEH,eAAO,MAAM,mBAAmB,QAQ9B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAIH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAQtC,CAAC;AAEH,eAAO,MAAM,mBAAmB,QAQ9B,CAAC;AAIH,eAAO,MAAM,cAAc,QAQzB,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAQlC,CAAC;AAEH,eAAO,MAAM,8BAA8B,QAQzC,CAAC;AAEH,eAAO,MAAM,WAAW,QAQtB,CAAC;AAIH,eAAO,MAAM,iCAAiC,QAQ5C,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAQtC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAQhC,CAAC"}
|