@ngxtm/devkit 3.4.0 → 3.4.1
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/package.json +2 -1
- package/rules/README.md +141 -0
- package/rules/dart/best-practices/SKILL.md +23 -0
- package/rules/dart/language/SKILL.md +52 -0
- package/rules/dart/tooling/SKILL.md +43 -0
- package/rules/dotnet/aspnet-core/SKILL.md +92 -0
- package/rules/dotnet/aspnet-core/references/REFERENCE.md +335 -0
- package/rules/dotnet/best-practices/SKILL.md +101 -0
- package/rules/dotnet/best-practices/references/REFERENCE.md +256 -0
- package/rules/dotnet/blazor/SKILL.md +146 -0
- package/rules/dotnet/blazor/references/REFERENCE.md +392 -0
- package/rules/dotnet/language/SKILL.md +82 -0
- package/rules/dotnet/language/references/REFERENCE.md +222 -0
- package/rules/dotnet/patterns.rule.md +388 -0
- package/rules/dotnet/razor-pages/SKILL.md +124 -0
- package/rules/dotnet/razor-pages/references/REFERENCE.md +321 -0
- package/rules/dotnet/security/SKILL.md +89 -0
- package/rules/dotnet/security/references/REFERENCE.md +295 -0
- package/rules/dotnet/tooling/SKILL.md +92 -0
- package/rules/dotnet/tooling/references/REFERENCE.md +300 -0
- package/rules/flutter/auto-route-navigation/SKILL.md +43 -0
- package/rules/flutter/auto-route-navigation/references/REFERENCE.md +19 -0
- package/rules/flutter/auto-route-navigation/references/router-config.md +62 -0
- package/rules/flutter/bloc-state-management/SKILL.md +64 -0
- package/rules/flutter/bloc-state-management/references/REFERENCE.md +20 -0
- package/rules/flutter/bloc-state-management/references/auth-bloc-example.md +52 -0
- package/rules/flutter/bloc-state-management/references/equatable-usage.md +56 -0
- package/rules/flutter/bloc-state-management/references/property-based-state.md +68 -0
- package/rules/flutter/bloc.rule.md +76 -0
- package/rules/flutter/cicd/SKILL.md +48 -0
- package/rules/flutter/cicd/references/advanced-workflow.md +66 -0
- package/rules/flutter/cicd/references/fastlane.md +139 -0
- package/rules/flutter/cicd/references/github-actions.md +59 -0
- package/rules/flutter/dependency-injection/SKILL.md +42 -0
- package/rules/flutter/dependency-injection/references/REFERENCE.md +15 -0
- package/rules/flutter/dependency-injection/references/modules.md +37 -0
- package/rules/flutter/error-handling/SKILL.md +32 -0
- package/rules/flutter/error-handling/references/REFERENCE.md +19 -0
- package/rules/flutter/error-handling/references/error-mapping.md +31 -0
- package/rules/flutter/feature-based-clean-architecture/SKILL.md +46 -0
- package/rules/flutter/feature-based-clean-architecture/references/REFERENCE.md +14 -0
- package/rules/flutter/feature-based-clean-architecture/references/folder-structure.md +36 -0
- package/rules/flutter/getx-navigation/SKILL.md +70 -0
- package/rules/flutter/getx-navigation/references/app-pages.md +40 -0
- package/rules/flutter/getx-navigation/references/middleware-example.md +29 -0
- package/rules/flutter/getx-state-management/SKILL.md +76 -0
- package/rules/flutter/getx-state-management/references/binding-example.md +32 -0
- package/rules/flutter/getx-state-management/references/reactive-vs-simple.md +39 -0
- package/rules/flutter/go-router-navigation/SKILL.md +57 -0
- package/rules/flutter/idiomatic-flutter/SKILL.md +20 -0
- package/rules/flutter/layer-based-clean-architecture/SKILL.md +50 -0
- package/rules/flutter/layer-based-clean-architecture/references/REFERENCE.md +60 -0
- package/rules/flutter/layer-based-clean-architecture/references/repository-mapping.md +50 -0
- package/rules/flutter/localization/SKILL.md +50 -0
- package/rules/flutter/localization/references/REFERENCE.md +48 -0
- package/rules/flutter/localization/references/sheet-loader.md +33 -0
- package/rules/flutter/navigator-v1-navigation/SKILL.md +71 -0
- package/rules/flutter/navigator-v1-navigation/references/on-generate-route.md +48 -0
- package/rules/flutter/performance/SKILL.md +24 -0
- package/rules/flutter/retrofit-networking/SKILL.md +51 -0
- package/rules/flutter/retrofit-networking/references/REFERENCE.md +19 -0
- package/rules/flutter/retrofit-networking/references/token-refresh.md +40 -0
- package/rules/flutter/riverpod-state-management/SKILL.md +53 -0
- package/rules/flutter/riverpod-state-management/references/architecture.md +124 -0
- package/rules/flutter/riverpod-state-management/references/best-practices.md +89 -0
- package/rules/flutter/riverpod-state-management/references/testing.md +73 -0
- package/rules/flutter/riverpod.rule.md +78 -0
- package/rules/flutter/security/SKILL.md +33 -0
- package/rules/flutter/security/references/REFERENCE.md +15 -0
- package/rules/flutter/security/references/network-security.md +28 -0
- package/rules/flutter/testing/SKILL.md +44 -0
- package/rules/flutter/testing/references/REFERENCE.md +21 -0
- package/rules/flutter/testing/references/bloc-testing.md +38 -0
- package/rules/flutter/testing/references/integration-testing.md +128 -0
- package/rules/flutter/testing/references/robot-pattern.md +82 -0
- package/rules/flutter/testing/references/unit-testing.md +130 -0
- package/rules/flutter/testing/references/widget-testing.md +120 -0
- package/rules/flutter/widgets/SKILL.md +37 -0
- package/rules/golang/chi-router/SKILL.md +219 -0
- package/rules/golang/chi-router/references/REFERENCE.md +13 -0
- package/rules/golang/chi-router/references/routing-patterns.md +205 -0
- package/rules/golang/cobra-cli/SKILL.md +227 -0
- package/rules/golang/cobra-cli/references/REFERENCE.md +13 -0
- package/rules/golang/cobra-cli/references/command-patterns.md +224 -0
- package/rules/golang/core/SKILL.md +210 -0
- package/rules/golang/core/references/REFERENCE.md +14 -0
- package/rules/golang/core/references/concurrency-patterns.md +114 -0
- package/rules/golang/core/references/error-handling.md +87 -0
- package/rules/golang/echo-framework/SKILL.md +215 -0
- package/rules/golang/echo-framework/references/REFERENCE.md +14 -0
- package/rules/golang/echo-framework/references/middleware-patterns.md +141 -0
- package/rules/golang/echo-framework/references/routing-patterns.md +140 -0
- package/rules/golang/ent-orm/SKILL.md +239 -0
- package/rules/golang/ent-orm/references/REFERENCE.md +13 -0
- package/rules/golang/ent-orm/references/schema-patterns.md +255 -0
- package/rules/golang/fiber-framework/SKILL.md +196 -0
- package/rules/golang/fiber-framework/references/REFERENCE.md +13 -0
- package/rules/golang/fiber-framework/references/routing-patterns.md +191 -0
- package/rules/golang/gin-framework/SKILL.md +205 -0
- package/rules/golang/gin-framework/references/REFERENCE.md +14 -0
- package/rules/golang/gin-framework/references/middleware-patterns.md +119 -0
- package/rules/golang/gorm-orm/SKILL.md +196 -0
- package/rules/golang/gorm-orm/references/REFERENCE.md +14 -0
- package/rules/golang/gorm-orm/references/model-definitions.md +167 -0
- package/rules/golang/gorm-orm/references/query-patterns.md +161 -0
- package/rules/golang/grpc/SKILL.md +231 -0
- package/rules/golang/grpc/references/REFERENCE.md +13 -0
- package/rules/golang/grpc/references/service-patterns.md +276 -0
- package/rules/golang/testify/SKILL.md +239 -0
- package/rules/golang/testify/references/REFERENCE.md +13 -0
- package/rules/golang/testify/references/assert-patterns.md +170 -0
- package/rules/golang/validator/SKILL.md +234 -0
- package/rules/golang/validator/references/REFERENCE.md +13 -0
- package/rules/golang/validator/references/validation-tags.md +211 -0
- package/rules/golang/viper-config/SKILL.md +244 -0
- package/rules/golang/viper-config/references/REFERENCE.md +13 -0
- package/rules/golang/viper-config/references/config-loading.md +181 -0
- package/rules/golang/wire-di/SKILL.md +243 -0
- package/rules/golang/wire-di/references/REFERENCE.md +13 -0
- package/rules/golang/wire-di/references/provider-patterns.md +193 -0
- package/rules/golang/zap-logging/SKILL.md +203 -0
- package/rules/golang/zap-logging/references/REFERENCE.md +13 -0
- package/rules/golang/zap-logging/references/logger-config.md +165 -0
- package/rules/java/build-gradle/SKILL.md +92 -0
- package/rules/java/build-gradle/references/REFERENCE.md +14 -0
- package/rules/java/build-gradle/references/kotlin-dsl.md +118 -0
- package/rules/java/build-gradle/references/task-configuration.md +132 -0
- package/rules/java/build-maven/SKILL.md +86 -0
- package/rules/java/build-maven/references/REFERENCE.md +14 -0
- package/rules/java/build-maven/references/dependency-management.md +111 -0
- package/rules/java/build-maven/references/lifecycle-phases.md +114 -0
- package/rules/java/graalvm-native/SKILL.md +105 -0
- package/rules/java/graalvm-native/references/REFERENCE.md +12 -0
- package/rules/java/java-collections-streams/SKILL.md +148 -0
- package/rules/java/java-collections-streams/references/REFERENCE.md +15 -0
- package/rules/java/java-collections-streams/references/collectors-patterns.md +178 -0
- package/rules/java/java-collections-streams/references/stream-pipelines.md +165 -0
- package/rules/java/java-concurrency/SKILL.md +187 -0
- package/rules/java/java-concurrency/references/REFERENCE.md +17 -0
- package/rules/java/java-concurrency/references/completable-future.md +165 -0
- package/rules/java/java-concurrency/references/executor-patterns.md +176 -0
- package/rules/java/java-concurrency/references/virtual-threads.md +190 -0
- package/rules/java/java-core-language/SKILL.md +121 -0
- package/rules/java/java-core-language/references/REFERENCE.md +15 -0
- package/rules/java/java-core-language/references/jvm-memory-model.md +160 -0
- package/rules/java/java-core-language/references/modern-java-features.md +168 -0
- package/rules/java/java-project-structure/SKILL.md +195 -0
- package/rules/java/java-project-structure/references/REFERENCE.md +15 -0
- package/rules/java/java-project-structure/references/maven-project-layout.md +199 -0
- package/rules/java/java-project-structure/references/module-system.md +159 -0
- package/rules/java/micronaut-core/SKILL.md +99 -0
- package/rules/java/micronaut-core/references/REFERENCE.md +12 -0
- package/rules/java/micronaut-reactive/SKILL.md +68 -0
- package/rules/java/micronaut-reactive/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-core/SKILL.md +85 -0
- package/rules/java/quarkus-core/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-reactive/SKILL.md +67 -0
- package/rules/java/quarkus-reactive/references/REFERENCE.md +12 -0
- package/rules/java/spring-batch/SKILL.md +102 -0
- package/rules/java/spring-batch/references/REFERENCE.md +12 -0
- package/rules/java/spring-boot-architecture/SKILL.md +206 -0
- package/rules/java/spring-boot-architecture/references/REFERENCE.md +15 -0
- package/rules/java/spring-boot-architecture/references/auto-configuration.md +158 -0
- package/rules/java/spring-boot-architecture/references/configuration-properties.md +202 -0
- package/rules/java/spring-boot-web/SKILL.md +217 -0
- package/rules/java/spring-boot-web/references/REFERENCE.md +17 -0
- package/rules/java/spring-cloud/SKILL.md +109 -0
- package/rules/java/spring-cloud/references/REFERENCE.md +13 -0
- package/rules/java/spring-data-jpa/SKILL.md +241 -0
- package/rules/java/spring-data-jpa/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/SKILL.md +161 -0
- package/rules/java/spring-security/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/references/jwt-auth-flow.md +213 -0
- package/rules/java/testing-junit-mockito/SKILL.md +135 -0
- package/rules/java/testing-junit-mockito/references/REFERENCE.md +15 -0
- package/rules/java/testing-junit-mockito/references/junit5-patterns.md +159 -0
- package/rules/java/testing-junit-mockito/references/mockito-patterns.md +148 -0
- package/rules/java/testing-junit-mockito/references/spring-boot-testing.md +152 -0
- package/rules/javascript/best-practices/SKILL.md +64 -0
- package/rules/javascript/best-practices/references/REFERENCE.md +91 -0
- package/rules/javascript/language/SKILL.md +71 -0
- package/rules/javascript/language/references/REFERENCE.md +106 -0
- package/rules/javascript/tooling/SKILL.md +60 -0
- package/rules/javascript/tooling/references/REFERENCE.md +107 -0
- package/rules/metadata.json +54 -0
- package/rules/nestjs/api-standards/SKILL.md +47 -0
- package/rules/nestjs/api-standards/references/pagination-wrapper.md +87 -0
- package/rules/nestjs/architecture/SKILL.md +68 -0
- package/rules/nestjs/architecture/references/dynamic-module.md +53 -0
- package/rules/nestjs/caching/SKILL.md +51 -0
- package/rules/nestjs/caching/references/REFERENCE.md +13 -0
- package/rules/nestjs/caching/references/cache-patterns.md +183 -0
- package/rules/nestjs/configuration/SKILL.md +41 -0
- package/rules/nestjs/configuration/references/REFERENCE.md +13 -0
- package/rules/nestjs/configuration/references/config-patterns.md +184 -0
- package/rules/nestjs/controllers-services/SKILL.md +63 -0
- package/rules/nestjs/controllers-services/references/REFERENCE.md +14 -0
- package/rules/nestjs/controllers-services/references/controller-patterns.md +119 -0
- package/rules/nestjs/controllers-services/references/service-patterns.md +129 -0
- package/rules/nestjs/database/SKILL.md +102 -0
- package/rules/nestjs/database/references/REFERENCE.md +14 -0
- package/rules/nestjs/database/references/typeorm-patterns.md +156 -0
- package/rules/nestjs/deployment/SKILL.md +36 -0
- package/rules/nestjs/deployment/references/REFERENCE.md +13 -0
- package/rules/nestjs/deployment/references/deployment-patterns.md +140 -0
- package/rules/nestjs/documentation/SKILL.md +64 -0
- package/rules/nestjs/documentation/references/REFERENCE.md +13 -0
- package/rules/nestjs/documentation/references/swagger-patterns.md +139 -0
- package/rules/nestjs/error-handling/SKILL.md +55 -0
- package/rules/nestjs/error-handling/references/REFERENCE.md +13 -0
- package/rules/nestjs/error-handling/references/exception-filters.md +152 -0
- package/rules/nestjs/file-uploads/SKILL.md +35 -0
- package/rules/nestjs/file-uploads/references/REFERENCE.md +13 -0
- package/rules/nestjs/file-uploads/references/upload-patterns.md +125 -0
- package/rules/nestjs/observability/SKILL.md +39 -0
- package/rules/nestjs/observability/references/REFERENCE.md +13 -0
- package/rules/nestjs/observability/references/logging-metrics.md +175 -0
- package/rules/nestjs/performance/SKILL.md +60 -0
- package/rules/nestjs/performance/references/REFERENCE.md +13 -0
- package/rules/nestjs/performance/references/performance-patterns.md +107 -0
- package/rules/nestjs/real-time/SKILL.md +45 -0
- package/rules/nestjs/real-time/references/REFERENCE.md +13 -0
- package/rules/nestjs/real-time/references/websocket-patterns.md +121 -0
- package/rules/nestjs/scheduling/SKILL.md +39 -0
- package/rules/nestjs/scheduling/references/REFERENCE.md +13 -0
- package/rules/nestjs/scheduling/references/scheduling-patterns.md +137 -0
- package/rules/nestjs/search/SKILL.md +41 -0
- package/rules/nestjs/search/references/REFERENCE.md +13 -0
- package/rules/nestjs/search/references/search-patterns.md +137 -0
- package/rules/nestjs/security/SKILL.md +87 -0
- package/rules/nestjs/security/references/REFERENCE.md +14 -0
- package/rules/nestjs/security/references/authentication.md +151 -0
- package/rules/nestjs/testing/SKILL.md +40 -0
- package/rules/nestjs/testing/references/REFERENCE.md +14 -0
- package/rules/nestjs/testing/references/unit-testing.md +179 -0
- package/rules/nestjs/transport/SKILL.md +45 -0
- package/rules/nestjs/transport/references/REFERENCE.md +13 -0
- package/rules/nestjs/transport/references/microservices-patterns.md +170 -0
- package/rules/nextjs/app-router/SKILL.md +46 -0
- package/rules/nextjs/app-router/references/REFERENCE.md +14 -0
- package/rules/nextjs/app-router/references/routing-patterns.md +182 -0
- package/rules/nextjs/architecture/SKILL.md +44 -0
- package/rules/nextjs/architecture/references/fsd-structure.md +77 -0
- package/rules/nextjs/authentication/SKILL.md +29 -0
- package/rules/nextjs/authentication/references/auth-implementation.md +73 -0
- package/rules/nextjs/caching/SKILL.md +66 -0
- package/rules/nextjs/caching/references/REFERENCE.md +13 -0
- package/rules/nextjs/caching/references/cache-strategies.md +168 -0
- package/rules/nextjs/data-access-layer/SKILL.md +33 -0
- package/rules/nextjs/data-access-layer/references/patterns.md +66 -0
- package/rules/nextjs/data-fetching/SKILL.md +59 -0
- package/rules/nextjs/data-fetching/references/REFERENCE.md +13 -0
- package/rules/nextjs/data-fetching/references/fetch-patterns.md +160 -0
- package/rules/nextjs/internationalization/SKILL.md +105 -0
- package/rules/nextjs/internationalization/references/REFERENCE.md +13 -0
- package/rules/nextjs/internationalization/references/i18n-patterns.md +180 -0
- package/rules/nextjs/optimization/SKILL.md +64 -0
- package/rules/nextjs/optimization/references/REFERENCE.md +13 -0
- package/rules/nextjs/optimization/references/optimization-patterns.md +190 -0
- package/rules/nextjs/rendering/SKILL.md +91 -0
- package/rules/nextjs/rendering/references/REFERENCE.md +13 -0
- package/rules/nextjs/rendering/references/rendering-modes.md +163 -0
- package/rules/nextjs/server-actions/SKILL.md +46 -0
- package/rules/nextjs/server-actions/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-actions/references/action-patterns.md +188 -0
- package/rules/nextjs/server-components/SKILL.md +52 -0
- package/rules/nextjs/server-components/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-components/references/component-patterns.md +175 -0
- package/rules/nextjs/state-management/SKILL.md +73 -0
- package/rules/nextjs/state-management/references/REFERENCE.md +13 -0
- package/rules/nextjs/state-management/references/state-patterns.md +218 -0
- package/rules/nextjs/styling/SKILL.md +31 -0
- package/rules/nextjs/styling/references/implementation.md +56 -0
- package/rules/react/component-patterns/SKILL.md +66 -0
- package/rules/react/component-patterns/references/REFERENCE.md +126 -0
- package/rules/react/hooks/SKILL.md +60 -0
- package/rules/react/hooks/references/REFERENCE.md +132 -0
- package/rules/react/hooks.rule.md +79 -0
- package/rules/react/performance/SKILL.md +69 -0
- package/rules/react/performance/references/REFERENCE.md +143 -0
- package/rules/react/security/SKILL.md +46 -0
- package/rules/react/security/references/REFERENCE.md +170 -0
- package/rules/react/state-management/SKILL.md +56 -0
- package/rules/react/state-management/references/REFERENCE.md +137 -0
- package/rules/react/testing/SKILL.md +45 -0
- package/rules/react/testing/references/REFERENCE.md +149 -0
- package/rules/react/tooling/SKILL.md +39 -0
- package/rules/react/typescript/SKILL.md +53 -0
- package/rules/rust/actix-web/SKILL.md +160 -0
- package/rules/rust/actix-web/references/REFERENCE.md +13 -0
- package/rules/rust/actix-web/references/handler-patterns.md +198 -0
- package/rules/rust/async-graphql/SKILL.md +228 -0
- package/rules/rust/async-graphql/references/REFERENCE.md +13 -0
- package/rules/rust/async-graphql/references/schema-patterns.md +215 -0
- package/rules/rust/axum/SKILL.md +161 -0
- package/rules/rust/axum/references/REFERENCE.md +14 -0
- package/rules/rust/axum/references/handler-patterns.md +97 -0
- package/rules/rust/bevy/SKILL.md +206 -0
- package/rules/rust/bevy/references/REFERENCE.md +13 -0
- package/rules/rust/bevy/references/ecs-patterns.md +226 -0
- package/rules/rust/clap/SKILL.md +217 -0
- package/rules/rust/clap/references/REFERENCE.md +13 -0
- package/rules/rust/clap/references/derive-patterns.md +205 -0
- package/rules/rust/core/SKILL.md +154 -0
- package/rules/rust/core/references/REFERENCE.md +14 -0
- package/rules/rust/core/references/error-handling.md +92 -0
- package/rules/rust/diesel-orm/SKILL.md +176 -0
- package/rules/rust/diesel-orm/references/REFERENCE.md +13 -0
- package/rules/rust/diesel-orm/references/schema-patterns.md +206 -0
- package/rules/rust/rocket/SKILL.md +182 -0
- package/rules/rust/rocket/references/REFERENCE.md +13 -0
- package/rules/rust/rocket/references/handler-patterns.md +209 -0
- package/rules/rust/sea-orm/SKILL.md +230 -0
- package/rules/rust/sea-orm/references/REFERENCE.md +13 -0
- package/rules/rust/sea-orm/references/entity-patterns.md +221 -0
- package/rules/rust/serde-serialization/SKILL.md +150 -0
- package/rules/rust/serde-serialization/references/REFERENCE.md +13 -0
- package/rules/rust/serde-serialization/references/serialization-patterns.md +199 -0
- package/rules/rust/sqlx-database/SKILL.md +140 -0
- package/rules/rust/sqlx-database/references/REFERENCE.md +13 -0
- package/rules/rust/sqlx-database/references/query-patterns.md +210 -0
- package/rules/rust/tauri/SKILL.md +180 -0
- package/rules/rust/tauri/references/REFERENCE.md +13 -0
- package/rules/rust/tauri/references/command-patterns.md +209 -0
- package/rules/rust/tokio-runtime/SKILL.md +167 -0
- package/rules/rust/tokio-runtime/references/REFERENCE.md +14 -0
- package/rules/rust/tokio-runtime/references/async-patterns.md +137 -0
- package/rules/rust/tokio-runtime/references/synchronization.md +152 -0
- package/rules/rust/tonic/SKILL.md +231 -0
- package/rules/rust/tonic/references/REFERENCE.md +13 -0
- package/rules/rust/tonic/references/service-patterns.md +213 -0
- package/rules/rust/tracing/SKILL.md +214 -0
- package/rules/rust/tracing/references/REFERENCE.md +13 -0
- package/rules/rust/tracing/references/instrumentation.md +187 -0
- package/rules/typescript/best-practices/SKILL.md +108 -0
- package/rules/typescript/best-practices/references/REFERENCE.md +68 -0
- package/rules/typescript/language/SKILL.md +72 -0
- package/rules/typescript/language/references/REFERENCE.md +67 -0
- package/rules/typescript/patterns.rule.md +85 -0
- package/rules/typescript/security/SKILL.md +59 -0
- package/rules/typescript/security/references/REFERENCE.md +113 -0
- package/rules/typescript/tooling/SKILL.md +52 -0
- package/rules/typescript/tooling/references/REFERENCE.md +110 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# React Security Reference
|
|
2
|
+
|
|
3
|
+
CSP configuration and advanced security patterns.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Content Security Policy**](csp.md) - CSP headers configuration.
|
|
8
|
+
- [**Auth Patterns**](auth-patterns.md) - Secure authentication flows.
|
|
9
|
+
|
|
10
|
+
## Content Security Policy
|
|
11
|
+
|
|
12
|
+
```jsx
|
|
13
|
+
// Next.js middleware or server config
|
|
14
|
+
const cspHeader = `
|
|
15
|
+
default-src 'self';
|
|
16
|
+
script-src 'self' 'unsafe-inline' 'unsafe-eval';
|
|
17
|
+
style-src 'self' 'unsafe-inline';
|
|
18
|
+
img-src 'self' blob: data: https:;
|
|
19
|
+
font-src 'self';
|
|
20
|
+
object-src 'none';
|
|
21
|
+
base-uri 'self';
|
|
22
|
+
form-action 'self';
|
|
23
|
+
frame-ancestors 'none';
|
|
24
|
+
upgrade-insecure-requests;
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
// Vite plugin for CSP
|
|
28
|
+
import { defineConfig } from 'vite';
|
|
29
|
+
import htmlPlugin from 'vite-plugin-html';
|
|
30
|
+
|
|
31
|
+
export default defineConfig({
|
|
32
|
+
plugins: [
|
|
33
|
+
htmlPlugin({
|
|
34
|
+
inject: {
|
|
35
|
+
data: {
|
|
36
|
+
csp: cspHeader.replace(/\s+/g, ' ').trim(),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## OAuth2 / JWT Authentication Flow
|
|
45
|
+
|
|
46
|
+
```jsx
|
|
47
|
+
import { createContext, useContext, useState, useEffect } from 'react';
|
|
48
|
+
|
|
49
|
+
const AuthContext = createContext(null);
|
|
50
|
+
|
|
51
|
+
export function AuthProvider({ children }) {
|
|
52
|
+
const [user, setUser] = useState(null);
|
|
53
|
+
const [loading, setLoading] = useState(true);
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
// Check if user is already authenticated
|
|
57
|
+
checkAuth();
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
const checkAuth = async () => {
|
|
61
|
+
try {
|
|
62
|
+
// Token is in httpOnly cookie, automatically sent
|
|
63
|
+
const response = await fetch('/api/auth/me', {
|
|
64
|
+
credentials: 'include',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (response.ok) {
|
|
68
|
+
const userData = await response.json();
|
|
69
|
+
setUser(userData);
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Auth check failed:', error);
|
|
73
|
+
} finally {
|
|
74
|
+
setLoading(false);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const login = async (credentials) => {
|
|
79
|
+
const response = await fetch('/api/auth/login', {
|
|
80
|
+
method: 'POST',
|
|
81
|
+
headers: { 'Content-Type': 'application/json' },
|
|
82
|
+
credentials: 'include',
|
|
83
|
+
body: JSON.stringify(credentials),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
throw new Error('Login failed');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const userData = await response.json();
|
|
91
|
+
setUser(userData);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const logout = async () => {
|
|
95
|
+
await fetch('/api/auth/logout', {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
credentials: 'include',
|
|
98
|
+
});
|
|
99
|
+
setUser(null);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<AuthContext.Provider value={{ user, loading, login, logout }}>
|
|
104
|
+
{children}
|
|
105
|
+
</AuthContext.Provider>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function useAuth() {
|
|
110
|
+
const context = useContext(AuthContext);
|
|
111
|
+
if (!context) {
|
|
112
|
+
throw new Error('useAuth must be used within AuthProvider');
|
|
113
|
+
}
|
|
114
|
+
return context;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## CSRF Protection
|
|
119
|
+
|
|
120
|
+
```jsx
|
|
121
|
+
// Get CSRF token from cookie or meta tag
|
|
122
|
+
function getCsrfToken() {
|
|
123
|
+
return document.querySelector('meta[name="csrf-token"]')?.content;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Include in requests
|
|
127
|
+
async function securePost(url, data) {
|
|
128
|
+
const csrfToken = getCsrfToken();
|
|
129
|
+
|
|
130
|
+
const response = await fetch(url, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: {
|
|
133
|
+
'Content-Type': 'application/json',
|
|
134
|
+
'X-CSRF-Token': csrfToken,
|
|
135
|
+
},
|
|
136
|
+
credentials: 'include',
|
|
137
|
+
body: JSON.stringify(data),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return response;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Rate Limiting on Client
|
|
145
|
+
|
|
146
|
+
```jsx
|
|
147
|
+
// Simple rate limiter for API calls
|
|
148
|
+
function createRateLimiter(maxCalls, timeWindow) {
|
|
149
|
+
const calls = [];
|
|
150
|
+
|
|
151
|
+
return function rateLimitedFetch(url, options) {
|
|
152
|
+
const now = Date.now();
|
|
153
|
+
|
|
154
|
+
// Remove old calls outside time window
|
|
155
|
+
while (calls.length > 0 && calls[0] < now - timeWindow) {
|
|
156
|
+
calls.shift();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (calls.length >= maxCalls) {
|
|
160
|
+
throw new Error('Rate limit exceeded');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
calls.push(now);
|
|
164
|
+
return fetch(url, options);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Usage: max 10 calls per 60 seconds
|
|
169
|
+
const rateLimitedFetch = createRateLimiter(10, 60000);
|
|
170
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: React State Management
|
|
3
|
+
description: Standards for managing local, global, and server state.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [react, state, redux, zustand, context]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.tsx', '**/*.jsx']
|
|
8
|
+
keywords: [state, useReducer, context, store, props]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# React State Management
|
|
12
|
+
|
|
13
|
+
## **Priority: P0 (CRITICAL)**
|
|
14
|
+
|
|
15
|
+
Choosing the right tool for state scope.
|
|
16
|
+
|
|
17
|
+
## Implementation Guidelines
|
|
18
|
+
|
|
19
|
+
- **Local**: `useState`. `useReducer` if complex (state machine).
|
|
20
|
+
- **Derived**: `const fullName = first + last`. No state sync.
|
|
21
|
+
- **Context**: DI, Theming, Auth. Not for high-freq data.
|
|
22
|
+
- **Global**: Zustand/Redux for app-wide complex flow.
|
|
23
|
+
- **Server Cache**: Use `React.cache` (RSC) to dedupe requests per render.
|
|
24
|
+
- **Server State**: React Query / SWR / Apollo. Cache != UI State.
|
|
25
|
+
- **URL**: Store filter/sort params in URL (Source of Truth).
|
|
26
|
+
- **Immutability**: Never mutate. Use spread or Immer.
|
|
27
|
+
|
|
28
|
+
## Anti-Patterns
|
|
29
|
+
|
|
30
|
+
- **No Prop Drilling > 2**: Use Context/Composition.
|
|
31
|
+
- **No Mirroring Refs**: Don't copy props to state.
|
|
32
|
+
- **No Multi-Source**: Single Source of Truth.
|
|
33
|
+
- **No Context Abuse**: Context causes full-tree re-render.
|
|
34
|
+
|
|
35
|
+
## Code
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
// Derived State (Efficient)
|
|
39
|
+
function List({ items, filter }) {
|
|
40
|
+
// Correct: Calculated on fly
|
|
41
|
+
const visible = items.filter((i) => i.includes(filter));
|
|
42
|
+
return (
|
|
43
|
+
<ul>
|
|
44
|
+
{visible.map((i) => (
|
|
45
|
+
<li key={i}>{i}</li>
|
|
46
|
+
))}
|
|
47
|
+
</ul>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Zustand (Global)
|
|
52
|
+
const useStore = create((set) => ({
|
|
53
|
+
count: 0,
|
|
54
|
+
inc: () => set((s) => ({ count: s.count + 1 })),
|
|
55
|
+
}));
|
|
56
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# React State Management Reference
|
|
2
|
+
|
|
3
|
+
Advanced state management with Zustand, Redux Toolkit, and TanStack Query.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Zustand**](zustand.md) - Lightweight state management.
|
|
8
|
+
- [**Redux Toolkit**](redux-toolkit.md) - Redux best practices.
|
|
9
|
+
- [**TanStack Query**](tanstack-query.md) - Server state management.
|
|
10
|
+
|
|
11
|
+
## Zustand Store
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
import { create } from 'zustand';
|
|
15
|
+
|
|
16
|
+
// Simple store
|
|
17
|
+
export const useStore = create((set) => ({
|
|
18
|
+
count: 0,
|
|
19
|
+
increment: () => set((state) => ({ count: state.count + 1 })),
|
|
20
|
+
decrement: () => set((state) => ({ count: state.count - 1 })),
|
|
21
|
+
reset: () => set({ count: 0 }),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
// Advanced store with middleware
|
|
25
|
+
import { devtools, persist } from 'zustand/middleware';
|
|
26
|
+
|
|
27
|
+
export const useAuthStore = create(
|
|
28
|
+
devtools(
|
|
29
|
+
persist(
|
|
30
|
+
(set) => ({
|
|
31
|
+
user: null,
|
|
32
|
+
token: null,
|
|
33
|
+
login: (user, token) => set({ user, token }),
|
|
34
|
+
logout: () => set({ user: null, token: null }),
|
|
35
|
+
}),
|
|
36
|
+
{ name: 'auth-storage' }
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// Usage
|
|
42
|
+
function Component() {
|
|
43
|
+
const count = useStore((state) => state.count);
|
|
44
|
+
const increment = useStore((state) => state.increment);
|
|
45
|
+
|
|
46
|
+
return <button onClick={increment}>Count: {count}</button>;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Redux Toolkit
|
|
51
|
+
|
|
52
|
+
```jsx
|
|
53
|
+
import { createSlice, configureStore } from '@reduxjs/toolkit';
|
|
54
|
+
|
|
55
|
+
// Slice
|
|
56
|
+
const counterSlice = createSlice({
|
|
57
|
+
name: 'counter',
|
|
58
|
+
initialState: { value: 0 },
|
|
59
|
+
reducers: {
|
|
60
|
+
increment: (state) => {
|
|
61
|
+
state.value += 1; // Immer allows mutation
|
|
62
|
+
},
|
|
63
|
+
decrement: (state) => {
|
|
64
|
+
state.value -= 1;
|
|
65
|
+
},
|
|
66
|
+
incrementByAmount: (state, action) => {
|
|
67
|
+
state.value += action.payload;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
|
|
73
|
+
|
|
74
|
+
// Store
|
|
75
|
+
export const store = configureStore({
|
|
76
|
+
reducer: {
|
|
77
|
+
counter: counterSlice.reducer,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Usage with hooks
|
|
82
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
83
|
+
|
|
84
|
+
function Counter() {
|
|
85
|
+
const count = useSelector((state) => state.counter.value);
|
|
86
|
+
const dispatch = useDispatch();
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div>
|
|
90
|
+
<button onClick={() => dispatch(decrement())}>-</button>
|
|
91
|
+
<span>{count}</span>
|
|
92
|
+
<button onClick={() => dispatch(increment())}>+</button>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## TanStack Query (React Query)
|
|
99
|
+
|
|
100
|
+
```jsx
|
|
101
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
102
|
+
|
|
103
|
+
// Fetch data
|
|
104
|
+
function UserProfile({ userId }) {
|
|
105
|
+
const { data, isLoading, error } = useQuery({
|
|
106
|
+
queryKey: ['user', userId],
|
|
107
|
+
queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
|
|
108
|
+
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (isLoading) return <div>Loading...</div>;
|
|
112
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
113
|
+
|
|
114
|
+
return <div>{data.name}</div>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Mutations
|
|
118
|
+
function CreateUser() {
|
|
119
|
+
const queryClient = useQueryClient();
|
|
120
|
+
|
|
121
|
+
const mutation = useMutation({
|
|
122
|
+
mutationFn: (newUser) => fetch('/api/users', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
body: JSON.stringify(newUser),
|
|
125
|
+
}),
|
|
126
|
+
onSuccess: () => {
|
|
127
|
+
queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<button onClick={() => mutation.mutate({ name: 'John' })}>
|
|
133
|
+
Create User
|
|
134
|
+
</button>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: React Testing
|
|
3
|
+
description: Testing strategies with RTL and Jest/Vitest.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [react, testing, jest, vitest]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.test.tsx', '**/*.spec.tsx']
|
|
8
|
+
keywords: [render, screen, userEvent, expect]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# React Testing
|
|
12
|
+
|
|
13
|
+
## **Priority: P2 (MAINTENANCE)**
|
|
14
|
+
|
|
15
|
+
Reliable tests focusing on user behavior.
|
|
16
|
+
|
|
17
|
+
## Implementation Guidelines
|
|
18
|
+
|
|
19
|
+
- **Tooling**: React Testing Library + Vitest.
|
|
20
|
+
- **Philosophy**: Test behavior, not implementation (State/Internal vars).
|
|
21
|
+
- **Queries**: `getByRole` > `getByText` > `getByTestId`.
|
|
22
|
+
- **Events**: Use `userEvent` (async) over `fireEvent`.
|
|
23
|
+
- **Async**: `await screen.findBy*` for async updates.
|
|
24
|
+
- **Mocks**: MSW for network. Mock heavy 3rd-party libs.
|
|
25
|
+
- **Accessibility**: Testing Lib implicitly tests a11y roles.
|
|
26
|
+
|
|
27
|
+
## Anti-Patterns
|
|
28
|
+
|
|
29
|
+
- **No Shallow Rendering**: Render full tree.
|
|
30
|
+
- **No Testing Implementation Details**: Don't check `component.state`.
|
|
31
|
+
- **No Wait**: Use `findBy`, avoid `waitFor` if possible.
|
|
32
|
+
|
|
33
|
+
## Code
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
test('submits form', async () => {
|
|
37
|
+
const user = userEvent.setup();
|
|
38
|
+
render(<LoginForm />);
|
|
39
|
+
|
|
40
|
+
await user.type(screen.getByLabelText(/email/i), 'test@test.com');
|
|
41
|
+
await user.click(screen.getByRole('button', { name: /login/i }));
|
|
42
|
+
|
|
43
|
+
expect(await screen.findByText(/welcome/i)).toBeInTheDocument();
|
|
44
|
+
});
|
|
45
|
+
```
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# React Testing Reference
|
|
2
|
+
|
|
3
|
+
Advanced testing patterns and integration testing.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Mocking Patterns**](mocking.md) - API, module, and component mocking.
|
|
8
|
+
- [**Integration Tests**](integration-tests.md) - Testing component interactions.
|
|
9
|
+
|
|
10
|
+
## Mocking API Calls
|
|
11
|
+
|
|
12
|
+
```jsx
|
|
13
|
+
// Using MSW (Mock Service Worker)
|
|
14
|
+
import { rest } from 'msw';
|
|
15
|
+
import { setupServer } from 'msw/node';
|
|
16
|
+
|
|
17
|
+
const server = setupServer(
|
|
18
|
+
rest.get('/api/users/:id', (req, res, ctx) => {
|
|
19
|
+
const { id } = req.params;
|
|
20
|
+
return res(
|
|
21
|
+
ctx.json({ id, name: 'John Doe', email: 'john@example.com' })
|
|
22
|
+
);
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
beforeAll(() => server.listen());
|
|
27
|
+
afterEach(() => server.resetHandlers());
|
|
28
|
+
afterAll(() => server.close());
|
|
29
|
+
|
|
30
|
+
test('fetches and displays user', async () => {
|
|
31
|
+
render(<UserProfile userId="1" />);
|
|
32
|
+
|
|
33
|
+
expect(await screen.findByText('John Doe')).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Override handler for error case
|
|
37
|
+
test('handles fetch error', async () => {
|
|
38
|
+
server.use(
|
|
39
|
+
rest.get('/api/users/:id', (req, res, ctx) => {
|
|
40
|
+
return res(ctx.status(500));
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
render(<UserProfile userId="1" />);
|
|
45
|
+
|
|
46
|
+
expect(await screen.findByText(/error/i)).toBeInTheDocument();
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Testing Context
|
|
51
|
+
|
|
52
|
+
```jsx
|
|
53
|
+
import { render, screen } from '@testing-library/react';
|
|
54
|
+
import { AuthProvider, useAuth } from './AuthContext';
|
|
55
|
+
|
|
56
|
+
function TestComponent() {
|
|
57
|
+
const { user } = useAuth();
|
|
58
|
+
return <div>{user ? user.name : 'Not logged in'}</div>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
test('provides auth context', () => {
|
|
62
|
+
const mockUser = { id: '1', name: 'John' };
|
|
63
|
+
|
|
64
|
+
render(
|
|
65
|
+
<AuthProvider initialUser={mockUser}>
|
|
66
|
+
<TestComponent />
|
|
67
|
+
</AuthProvider>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
expect(screen.getByText('John')).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Testing Forms
|
|
75
|
+
|
|
76
|
+
```jsx
|
|
77
|
+
import { render, screen } from '@testing-library/react';
|
|
78
|
+
import userEvent from '@testing-library/user-event';
|
|
79
|
+
import { LoginForm } from './LoginForm';
|
|
80
|
+
|
|
81
|
+
test('submits form with credentials', async () => {
|
|
82
|
+
const onSubmit = jest.fn();
|
|
83
|
+
const user = userEvent.setup();
|
|
84
|
+
|
|
85
|
+
render(<LoginForm onSubmit={onSubmit} />);
|
|
86
|
+
|
|
87
|
+
await user.type(screen.getByLabelText(/email/i), 'john@example.com');
|
|
88
|
+
await user.type(screen.getByLabelText(/password/i), 'password123');
|
|
89
|
+
await user.click(screen.getByRole('button', { name: /login/i }));
|
|
90
|
+
|
|
91
|
+
expect(onSubmit).toHaveBeenCalledWith({
|
|
92
|
+
email: 'john@example.com',
|
|
93
|
+
password: 'password123',
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('shows validation errors', async () => {
|
|
98
|
+
const user = userEvent.setup();
|
|
99
|
+
|
|
100
|
+
render(<LoginForm />);
|
|
101
|
+
|
|
102
|
+
await user.click(screen.getByRole('button', { name: /login/i }));
|
|
103
|
+
|
|
104
|
+
expect(await screen.findByText(/email is required/i)).toBeInTheDocument();
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Testing with React Router
|
|
109
|
+
|
|
110
|
+
```jsx
|
|
111
|
+
import { render, screen } from '@testing-library/react';
|
|
112
|
+
import { MemoryRouter, Routes, Route } from 'react-router-dom';
|
|
113
|
+
import { Dashboard } from './Dashboard';
|
|
114
|
+
|
|
115
|
+
test('renders dashboard at /dashboard', () => {
|
|
116
|
+
render(
|
|
117
|
+
<MemoryRouter initialEntries={['/dashboard']}>
|
|
118
|
+
<Routes>
|
|
119
|
+
<Route path="/dashboard" element={<Dashboard />} />
|
|
120
|
+
</Routes>
|
|
121
|
+
</MemoryRouter>
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Component Integration Tests
|
|
129
|
+
|
|
130
|
+
```jsx
|
|
131
|
+
test('user can complete full workflow', async () => {
|
|
132
|
+
const user = userEvent.setup();
|
|
133
|
+
|
|
134
|
+
render(<App />);
|
|
135
|
+
|
|
136
|
+
// Navigate to form
|
|
137
|
+
await user.click(screen.getByRole('link', { name: /create user/i }));
|
|
138
|
+
|
|
139
|
+
// Fill form
|
|
140
|
+
await user.type(screen.getByLabelText(/name/i), 'Jane Doe');
|
|
141
|
+
await user.type(screen.getByLabelText(/email/i), 'jane@example.com');
|
|
142
|
+
|
|
143
|
+
// Submit
|
|
144
|
+
await user.click(screen.getByRole('button', { name: /submit/i }));
|
|
145
|
+
|
|
146
|
+
// Verify success
|
|
147
|
+
expect(await screen.findByText(/user created/i)).toBeInTheDocument();
|
|
148
|
+
});
|
|
149
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: React Tooling
|
|
3
|
+
description: Debugging, build analysis, and ecosystem tools.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [react, tooling, debug, performance]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['package.json']
|
|
8
|
+
keywords: [devtool, bundle, strict mode, profile]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# React Tooling
|
|
12
|
+
|
|
13
|
+
## **Priority: P2 (OPTIONAL)**
|
|
14
|
+
|
|
15
|
+
Tools for analysis and debugging.
|
|
16
|
+
|
|
17
|
+
## Implementation Guidelines
|
|
18
|
+
|
|
19
|
+
- **DevTools**: Use "Highlight Updates" to spot re-renders.
|
|
20
|
+
- **Debugger**: `useDebugValue` for custom hooks.
|
|
21
|
+
- **Performance**: `why-did-you-render` to catch wasted renders.
|
|
22
|
+
- **Bundle**: `source-map-explorer` or `bundle-visualizer`.
|
|
23
|
+
- **Linting**: `eslint-plugin-react-hooks` (Errors) + `react-refresh`.
|
|
24
|
+
- **Strict Mode**: Enable for double-invoke checks (effects/reducers).
|
|
25
|
+
|
|
26
|
+
## Code
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
// Debugging Hooks
|
|
30
|
+
useDebugValue(isOnline ? 'Online' : 'Offline');
|
|
31
|
+
|
|
32
|
+
// why-did-you-render
|
|
33
|
+
if (process.env.NODE_ENV === 'development') {
|
|
34
|
+
const whyDidYouRender = require('@welldone-software/why-did-you-render');
|
|
35
|
+
whyDidYouRender(React, {
|
|
36
|
+
trackAllPureComponents: true,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: React TypeScript
|
|
3
|
+
description: TypeScript patterns specific to React components and hooks.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [react, typescript, types]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.tsx']
|
|
8
|
+
keywords: [ReactNode, FC, PropsWithChildren, ComponentProps]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# React TypeScript
|
|
12
|
+
|
|
13
|
+
## **Priority: P1 (OPERATIONAL)**
|
|
14
|
+
|
|
15
|
+
Type-safe React patterns.
|
|
16
|
+
|
|
17
|
+
## Implementation Guidelines
|
|
18
|
+
|
|
19
|
+
- **Components**: Return `JSX.Element`. Props interface over `React.FC`.
|
|
20
|
+
- **Children**: Use `ReactNode` or `PropsWithChildren<T>`.
|
|
21
|
+
- **Events**: `React.ChangeEvent<HTMLInputElement>`.
|
|
22
|
+
- **Hooks**: `useRef<HTMLDivElement>(null)`. `useState<User | null>(null)`.
|
|
23
|
+
- **Props**: Use `ComponentProps<'button'>` to mirror native els.
|
|
24
|
+
- **Generics**: `<T,>(props: ListProps<T>)`.
|
|
25
|
+
- **Polymorphism**: `as` prop patterns.
|
|
26
|
+
|
|
27
|
+
## Anti-Patterns
|
|
28
|
+
|
|
29
|
+
- **No `any`**: Use `unknown`.
|
|
30
|
+
- **No `React.FC`**: Implicit children is deprecated/bad practice.
|
|
31
|
+
- **No `Function`**: Use `(args: T) => void`.
|
|
32
|
+
|
|
33
|
+
## Code
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
// Modern Props
|
|
37
|
+
type ButtonProps = ComponentProps<'button'> & {
|
|
38
|
+
variant?: 'primary' | 'secondary';
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Generic Component
|
|
42
|
+
type ListProps<T> = {
|
|
43
|
+
items: T[];
|
|
44
|
+
render: (item: T) => ReactNode;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function List<T>({ items, render }: ListProps<T>) {
|
|
48
|
+
return <ul>{items.map(render)}</ul>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Hook Ref
|
|
52
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
53
|
+
```
|