@critiq/rules 0.0.1 → 0.1.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/LICENSE +201 -0
- package/README.md +256 -140
- package/catalog.yaml +985 -19
- package/package.json +7 -1
- package/rules/go/go.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/go/go.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/go/go.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/go/go.security.echo-sensitive-binding-without-validation.rule.yaml +46 -0
- package/rules/go/go.security.echo-unsafe-multipart-upload.rule.yaml +45 -0
- package/rules/go/go.security.fiber-sensitive-binding-without-validation.rule.yaml +45 -0
- package/rules/go/go.security.fiber-unsafe-multipart-upload.rule.yaml +45 -0
- package/rules/go/go.security.gin-sensitive-binding-without-validation.rule.yaml +45 -0
- package/rules/go/go.security.gin-trust-all-proxies.rule.yaml +45 -0
- package/rules/go/go.security.gin-wildcard-cors-with-credentials.rule.yaml +47 -0
- package/rules/go/go.security.net-http-missing-timeouts.rule.yaml +45 -0
- package/rules/go/go.security.sensitive-data-egress.rule.yaml +46 -0
- package/rules/go/go.security.tar-path-traversal.rule.yaml +45 -0
- package/rules/go/go.security.template-unescaped-request-value.rule.yaml +45 -0
- package/rules/go/go.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/go/go.testing.t-skip-without-ticket-reference.rule.yaml +33 -0
- package/rules/go/go.testing.time-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/java/java.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/java/java.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/java/java.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/java/java.security.android-screenshot-exposure.rule.yaml +35 -0
- package/rules/java/java.security.android-world-readable-mode.rule.yaml +35 -0
- package/rules/java/java.security.jpa-concatenated-query.rule.yaml +47 -0
- package/rules/java/java.security.reflected-output-from-request.rule.yaml +35 -0
- package/rules/java/java.security.servlet-insecure-cookie.rule.yaml +35 -0
- package/rules/java/java.security.spring-actuator-health-details-always.rule.yaml +40 -0
- package/rules/java/java.security.spring-actuator-sensitive-exposure.rule.yaml +40 -0
- package/rules/java/java.security.spring-csrf-globally-disabled.rule.yaml +49 -0
- package/rules/java/java.security.spring-debug-exposure.rule.yaml +35 -0
- package/rules/java/java.security.spring-permit-all-default.rule.yaml +47 -0
- package/rules/java/java.security.spring-webmvc-unrestricted-data-binding.rule.yaml +47 -0
- package/rules/java/java.security.template-unescaped-user-output.rule.yaml +49 -0
- package/rules/java/java.testing.disabled-without-ticket-reference.rule.yaml +33 -0
- package/rules/java/java.testing.http-client-in-unit-test.rule.yaml +33 -0
- package/rules/java/java.testing.thread-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/php/php.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/php/php.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/php/php.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/php/php.security.insecure-cors-wildcard-with-credentials.rule.yaml +41 -0
- package/rules/php/php.security.insecure-mail-or-file-transport.rule.yaml +41 -0
- package/rules/php/php.security.insecure-session-or-cookie-config.rule.yaml +42 -0
- package/rules/php/php.security.laravel-sensitive-csrf-exclusion.rule.yaml +42 -0
- package/rules/php/php.security.laravel-unsafe-blade-output.rule.yaml +42 -0
- package/rules/php/php.security.laravel-unsafe-mass-assignment.rule.yaml +45 -0
- package/rules/php/php.security.sensitive-data-egress.rule.yaml +42 -0
- package/rules/php/php.security.symfony-csrf-disabled.rule.yaml +42 -0
- package/rules/php/php.security.symfony-debug-exposure.rule.yaml +44 -0
- package/rules/php/php.security.unsafe-file-upload-handling.rule.yaml +41 -0
- package/rules/php/php.security.wordpress-missing-nonce-or-capability.rule.yaml +42 -0
- package/rules/php/php.security.wordpress-unprepared-sql.rule.yaml +42 -0
- package/rules/php/php.testing.curl-in-unit-test.rule.yaml +33 -0
- package/rules/php/php.testing.mark-test-skipped-without-ticket-reference.rule.yaml +33 -0
- package/rules/php/php.testing.sleep-in-unit-test.rule.yaml +33 -0
- package/rules/python/py.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/python/py.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/python/py.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/python/py.security.django-csrf-exempt-state-changing.rule.yaml +46 -0
- package/rules/python/py.security.django-missing-csrf-middleware.rule.yaml +47 -0
- package/rules/python/py.security.django-unsafe-production-settings.rule.yaml +47 -0
- package/rules/python/py.security.drf-allow-any-default.rule.yaml +46 -0
- package/rules/python/py.security.drf-allow-any-unsafe-method.rule.yaml +46 -0
- package/rules/python/py.security.fastapi-insecure-cors.rule.yaml +43 -0
- package/rules/python/py.security.flask-missing-upload-body-limit.rule.yaml +44 -0
- package/rules/python/py.security.flask-unsafe-html-output.rule.yaml +44 -0
- package/rules/python/py.security.flask-unsafe-upload-filename.rule.yaml +44 -0
- package/rules/python/py.testing.pytest-skip-without-ticket-reference.rule.yaml +33 -0
- package/rules/python/py.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/python/py.testing.time-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/ruby/ruby.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/ruby/ruby.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/ruby/ruby.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/ruby/ruby.security.rails-csrf-disabled.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-detailed-exceptions-enabled.rule.yaml +44 -0
- package/rules/ruby/ruby.security.rails-open-redirect.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-unsafe-html-output.rule.yaml +46 -0
- package/rules/ruby/ruby.security.rails-unsafe-render.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-unsafe-session-or-cookie-store.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-unsafe-strong-parameters.rule.yaml +46 -0
- package/rules/ruby/ruby.security.sensitive-data-egress.rule.yaml +45 -0
- package/rules/ruby/ruby.security.sidekiq-web-unauthenticated-mount.rule.yaml +45 -0
- package/rules/ruby/ruby.testing.focused-example.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.pending-without-ticket-reference.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.skip-without-ticket-reference.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.sleep-in-unit-test.rule.yaml +33 -0
- package/rules/rust/rust.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/rust/rust.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/rust/rust.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/rust/rust.security.actix-wildcard-cors-with-credentials.rule.yaml +47 -0
- package/rules/rust/rust.security.axum-body-limit-disabled.rule.yaml +45 -0
- package/rules/rust/rust.security.axum-insecure-cors-with-credentials.rule.yaml +47 -0
- package/rules/rust/rust.security.rocket-panic-prone-request-handler.rule.yaml +45 -0
- package/rules/rust/rust.security.rocket-unsafe-template-output.rule.yaml +47 -0
- package/rules/rust/rust.security.sqlx-diesel-raw-interpolated-query.rule.yaml +47 -0
- package/rules/rust/rust.security.template-unescaped-request-value.rule.yaml +47 -0
- package/rules/rust/rust.security.warp-blocking-or-panic-in-async-handler.rule.yaml +45 -0
- package/rules/rust/rust.testing.ignore-without-ticket-reference.rule.yaml +33 -0
- package/rules/rust/rust.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/rust/rust.testing.thread-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/shared/security.archive-path-traversal.rule.yaml +41 -0
- package/rules/shared/security.external-file-upload.rule.yaml +40 -0
- package/rules/shared/security.permissive-file-permissions.rule.yaml +40 -0
- package/rules/shared/security.sensitive-data-egress.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.assignment-in-condition.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.assignment-to-import-binding.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.async-promise-executor.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-function-parameter.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-import-source.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-object-key.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-switch-case.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.empty-block-statement.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.identical-comparison-operands.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.reassign-catch-binding.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.regexp-pattern-unusual-control-character.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.self-assignment.rule.yaml +36 -0
- package/rules/typescript/ts.next.server-action-missing-local-auth.rule.yaml +35 -0
- package/rules/typescript/ts.performance.no-array-spread-in-hot-loop.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-cache-miss-from-unstable-key.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-expensive-sort-in-render-path.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-json-parse-stringify-clone.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-large-object-spread-in-loop.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-n-plus-one-await-in-map.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-redundant-network-fetch.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-regex-construction-in-loop.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-sync-fs-in-request-path.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-unbounded-concurrency.rule.yaml +32 -0
- package/rules/typescript/ts.quality.no-ambiguous-abbreviations.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-barrel-file-cycle.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-boolean-parameter-trap.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-dead-export.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-hidden-side-effect-import.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-inconsistent-error-shape.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-mixed-abstraction-level.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-primitive-obsession-in-domain-model.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-temporal-coupling.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-wide-public-surface.rule.yaml +27 -0
- package/rules/typescript/ts.react.no-accessibility-label-missing.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-activedescendant-on-non-focusable-host.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-click-without-keyboard-handler.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-deprecated-create-factory.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-deprecated-react-dom-root-api.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-derived-state-from-props.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-effect-fetch-without-cancellation.rule.yaml +35 -0
- package/rules/typescript/ts.react.no-find-dom-node.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-img-missing-alt-text.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-index-as-key-in-dynamic-list.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-interactive-role-on-static-semantics.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-invalid-anchor-href.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-keyboard-interaction-without-widget-role.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-legacy-lifecycle.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-missing-error-boundary.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-positive-tabindex.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-static-element-with-synthetic-handlers.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-string-ref.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-uncontrolled-to-controlled-input.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-widget-role-without-tabindex.rule.yaml +36 -0
- package/rules/typescript/ts.security.ajv-insecure-configuration.rule.yaml +34 -0
- package/rules/typescript/ts.security.angular-dom-sanitizer-bypass-untrusted-input.rule.yaml +35 -0
- package/rules/typescript/ts.security.apollo-server-csrf-disabled.rule.yaml +36 -0
- package/rules/typescript/ts.security.apollo-server-graphql-dev-tooling-exposure.rule.yaml +36 -0
- package/rules/typescript/ts.security.apollo-server-introspection-exposure.rule.yaml +35 -0
- package/rules/typescript/ts.security.apollo-server-missing-query-limits.rule.yaml +35 -0
- package/rules/typescript/ts.security.astro-vite-public-secret-define.rule.yaml +39 -0
- package/rules/typescript/ts.security.debug-statement-in-source.rule.yaml +36 -0
- package/rules/typescript/ts.security.electron-dangerous-webpreferences.rule.yaml +35 -0
- package/rules/typescript/ts.security.electron-insecure-local-state.rule.yaml +35 -0
- package/rules/typescript/ts.security.electron-missing-ipc-origin-check.rule.yaml +35 -0
- package/rules/typescript/ts.security.electron-shell-open-external-unvalidated.rule.yaml +35 -0
- package/rules/typescript/ts.security.express-error-handler-information-disclosure.rule.yaml +35 -0
- package/rules/typescript/ts.security.express-static-dotfiles-allow.rule.yaml +35 -0
- package/rules/typescript/ts.security.express-unbounded-body-parser.rule.yaml +34 -0
- package/rules/typescript/ts.security.express-user-controlled-static-mount.rule.yaml +35 -0
- package/rules/typescript/ts.security.fastify-excessive-body-limit.rule.yaml +34 -0
- package/rules/typescript/ts.security.fastify-public-bind-without-trust-proxy.rule.yaml +38 -0
- package/rules/typescript/ts.security.graphql-upload-without-csrf-guard.rule.yaml +36 -0
- package/rules/typescript/ts.security.iframe-missing-sandbox-attribute.rule.yaml +35 -0
- package/rules/typescript/ts.security.insecure-content-security-policy-literal.rule.yaml +35 -0
- package/rules/typescript/ts.security.insecure-helmet-hardening-options.rule.yaml +36 -0
- package/rules/typescript/ts.security.jwt-insecure-signing-algorithm.rule.yaml +35 -0
- package/rules/typescript/ts.security.legacy-buffer-constructor.rule.yaml +35 -0
- package/rules/typescript/ts.security.log-injection.rule.yaml +36 -0
- package/rules/typescript/ts.security.nestjs-helmet-after-route-mount.rule.yaml +34 -0
- package/rules/typescript/ts.security.nestjs-missing-global-validation-pipe.rule.yaml +35 -0
- package/rules/typescript/ts.security.nestjs-skip-throttle-sensitive-route.rule.yaml +35 -0
- package/rules/typescript/ts.security.nestjs-validation-pipe-without-whitelist.rule.yaml +36 -0
- package/rules/typescript/ts.security.nuxt-public-runtime-secret.rule.yaml +38 -0
- package/rules/typescript/ts.security.open-redirect.rule.yaml +2 -0
- package/rules/typescript/ts.security.request-driven-array-index-access.rule.yaml +33 -0
- package/rules/typescript/ts.security.sensitive-data-egress.rule.yaml +1 -0
- package/rules/typescript/ts.security.ssrf.rule.yaml +1 -0
- package/rules/typescript/ts.security.unsafe-dompurify-version.rule.yaml +36 -0
- package/rules/typescript/ts.security.unsafe-marked-version.rule.yaml +36 -0
- package/rules/typescript/ts.security.xml-parse-string-with-untrusted-input.rule.yaml +35 -0
- package/rules/typescript/ts.testing.no-flaky-timer-test.rule.yaml +38 -0
- package/rules/typescript/ts.testing.no-focused-test.rule.yaml +34 -0
- package/rules/typescript/ts.testing.no-missing-edge-case-tests.rule.yaml +35 -0
- package/rules/typescript/ts.testing.no-network-call-in-unit-test.rule.yaml +38 -0
- package/rules/typescript/ts.testing.no-skipped-test-without-ticket.rule.yaml +34 -0
- package/rules/typescript/ts.testing.no-snapshot-without-intent.rule.yaml +34 -0
- package/rules/typescript/ts.testing.no-test-only-code-in-production.rule.yaml +38 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-expensive-sort-in-render-path
|
|
5
|
+
title: Avoid expensive sort or transforms in render path
|
|
6
|
+
summary: Sorting or heavy transforms in React render paths should be memoized or precomputed.
|
|
7
|
+
rationale: Sorting or heavy transforms in React render paths should be memoized or precomputed.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-expensive-sort-in-render-path
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.render
|
|
24
|
+
severity: medium
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid expensive sort or transforms in render path
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-expensive-sort-in-render-path."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-json-parse-stringify-clone
|
|
5
|
+
title: Avoid JSON parse/stringify deep-clone
|
|
6
|
+
summary: JSON stringify/parse cloning is expensive and loses type fidelity for rich objects.
|
|
7
|
+
rationale: JSON stringify/parse cloning is expensive and loses type fidelity for rich objects.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-json-parse-stringify-clone
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.cpu
|
|
24
|
+
severity: medium
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid JSON parse/stringify deep-clone
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-json-parse-stringify-clone."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-large-object-spread-in-loop
|
|
5
|
+
title: Avoid large object spread inside loops
|
|
6
|
+
summary: Object spread inside loops creates repeated allocations and can degrade throughput.
|
|
7
|
+
rationale: Object spread inside loops creates repeated allocations and can degrade throughput.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-large-object-spread-in-loop
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.allocation
|
|
24
|
+
severity: medium
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid large object spread inside loops
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-large-object-spread-in-loop."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-n-plus-one-await-in-map
|
|
5
|
+
title: Avoid N+1 await patterns in map flows
|
|
6
|
+
summary: Per-item awaits inside map-like flows often create avoidable latency and fan-out bottlenecks.
|
|
7
|
+
rationale: Per-item awaits inside map-like flows often create avoidable latency and fan-out bottlenecks.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-n-plus-one-await-in-map
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.async
|
|
24
|
+
severity: high
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid N+1 await patterns in map flows
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-n-plus-one-await-in-map."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-redundant-network-fetch
|
|
5
|
+
title: Avoid redundant network fetches in one path
|
|
6
|
+
summary: Repeated fetches for the same stable request identity waste network and CPU budget.
|
|
7
|
+
rationale: Repeated fetches for the same stable request identity waste network and CPU budget.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-redundant-network-fetch
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.network
|
|
24
|
+
severity: medium
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid redundant network fetches in one path
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-redundant-network-fetch."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-regex-construction-in-loop
|
|
5
|
+
title: Avoid regex construction inside loops
|
|
6
|
+
summary: Constructing regular expressions inside loops repeatedly allocates and reparses patterns.
|
|
7
|
+
rationale: Constructing regular expressions inside loops repeatedly allocates and reparses patterns.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-regex-construction-in-loop
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.allocation
|
|
24
|
+
severity: medium
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid regex construction inside loops
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-regex-construction-in-loop."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-sync-fs-in-request-path
|
|
5
|
+
title: Avoid sync filesystem calls in request paths
|
|
6
|
+
summary: Synchronous filesystem calls on request paths block the event loop and degrade latency.
|
|
7
|
+
rationale: Synchronous filesystem calls on request paths block the event loop and degrade latency.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-sync-fs-in-request-path
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.io
|
|
24
|
+
severity: high
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid sync filesystem calls in request paths
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-sync-fs-in-request-path."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.performance.no-unbounded-concurrency
|
|
5
|
+
title: Avoid unbounded concurrency fan-out
|
|
6
|
+
summary: Unbounded Promise fan-out over unknown input can exhaust downstream capacity.
|
|
7
|
+
rationale: Unbounded Promise fan-out over unknown input can exhaust downstream capacity.
|
|
8
|
+
tags:
|
|
9
|
+
- performance
|
|
10
|
+
- rules-catalog
|
|
11
|
+
stability: stable
|
|
12
|
+
appliesTo: block
|
|
13
|
+
scope:
|
|
14
|
+
languages:
|
|
15
|
+
- typescript
|
|
16
|
+
- javascript
|
|
17
|
+
match:
|
|
18
|
+
fact:
|
|
19
|
+
kind: performance.no-unbounded-concurrency
|
|
20
|
+
bind: issue
|
|
21
|
+
emit:
|
|
22
|
+
finding:
|
|
23
|
+
category: performance.async
|
|
24
|
+
severity: high
|
|
25
|
+
confidence: 0.8
|
|
26
|
+
tags:
|
|
27
|
+
- performance
|
|
28
|
+
message:
|
|
29
|
+
title: Avoid unbounded concurrency fan-out
|
|
30
|
+
summary: "`${captures.issue.text}` matches ts.performance.no-unbounded-concurrency."
|
|
31
|
+
remediation:
|
|
32
|
+
summary: Refactor this path to avoid repeated work in hot execution paths.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-ambiguous-abbreviations
|
|
5
|
+
title: Avoid ambiguous abbreviations in public APIs
|
|
6
|
+
summary: Ambiguous abbreviated names in exported APIs reduce readability and onboarding speed.
|
|
7
|
+
rationale: Public API names are long-lived and should optimize for clarity over brevity.
|
|
8
|
+
tags: [quality, maintainability, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.ambiguous-abbreviation-public-api
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.maintainability
|
|
20
|
+
severity: low
|
|
21
|
+
confidence: 0.76
|
|
22
|
+
tags: [quality, naming]
|
|
23
|
+
message:
|
|
24
|
+
title: Use explicit naming for exported API symbols
|
|
25
|
+
summary: "`${captures.issue.text}` looks like an ambiguous abbreviation in a public API."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Rename exported symbols to descriptive terms that communicate domain intent.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-barrel-file-cycle
|
|
5
|
+
title: Avoid barrel file cycles
|
|
6
|
+
summary: Cycles involving barrel files obscure ownership and complicate module boundaries.
|
|
7
|
+
rationale: Re-export cycles make import behavior less predictable and harder to review.
|
|
8
|
+
tags: [quality, architecture, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.barrel-file-cycle
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.architecture
|
|
20
|
+
severity: medium
|
|
21
|
+
confidence: 0.83
|
|
22
|
+
tags: [quality, architecture]
|
|
23
|
+
message:
|
|
24
|
+
title: Break the barrel cycle between modules
|
|
25
|
+
summary: "`${captures.issue.text}` participates in a re-export cycle."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Remove cycle edges, move shared symbols to a third module, and keep barrel ownership explicit.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-boolean-parameter-trap
|
|
5
|
+
title: Avoid boolean parameter trap in public APIs
|
|
6
|
+
summary: Public APIs with multiple boolean flags reduce readability and increase change risk.
|
|
7
|
+
rationale: Boolean-heavy signatures hide intent and make call-sites brittle.
|
|
8
|
+
tags: [quality, maintainability, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.boolean-parameter-trap
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.maintainability
|
|
20
|
+
severity: medium
|
|
21
|
+
confidence: 0.86
|
|
22
|
+
tags: [quality, maintainability]
|
|
23
|
+
message:
|
|
24
|
+
title: Replace multiple boolean flags with an options object
|
|
25
|
+
summary: "`${captures.issue.text}` appears to accept multiple boolean flags."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Prefer explicit option objects or dedicated methods to encode behavior clearly.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-dead-export
|
|
5
|
+
title: Remove dead exports
|
|
6
|
+
summary: Exported symbols with no known consumers increase maintenance overhead.
|
|
7
|
+
rationale: Dead exports are accidental API surface that should be removed or documented.
|
|
8
|
+
tags: [quality, maintainability, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.dead-export
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.maintainability
|
|
20
|
+
severity: low
|
|
21
|
+
confidence: 0.78
|
|
22
|
+
tags: [quality, maintainability]
|
|
23
|
+
message:
|
|
24
|
+
title: Remove or justify unused exported symbol
|
|
25
|
+
summary: "`${captures.issue.text}` appears to be exported but unused by the project."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Remove dead exports, make them internal, or document supported public entrypoints.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-hidden-side-effect-import
|
|
5
|
+
title: Avoid hidden side-effect imports
|
|
6
|
+
summary: Bare side-effect imports outside setup files make module behavior implicit.
|
|
7
|
+
rationale: Hidden side effects are difficult to reason about and can create order-dependent bugs.
|
|
8
|
+
tags: [quality, maintainability, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.hidden-side-effect-import
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.maintainability
|
|
20
|
+
severity: medium
|
|
21
|
+
confidence: 0.85
|
|
22
|
+
tags: [quality, maintainability]
|
|
23
|
+
message:
|
|
24
|
+
title: Move side effects into explicit setup boundaries
|
|
25
|
+
summary: "`${captures.issue.text}` is a side-effect-only import outside allowlisted setup files."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Use explicit setup modules or import named symbols instead of hidden side effects.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-inconsistent-error-shape
|
|
5
|
+
title: Keep error payload shape consistent
|
|
6
|
+
summary: Inconsistent thrown or rejected error shapes make error handling brittle.
|
|
7
|
+
rationale: Standardized error construction simplifies observability, retries, and user-safe handling.
|
|
8
|
+
tags: [quality, error-handling, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: block
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.inconsistent-error-shape
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.error-handling
|
|
20
|
+
severity: medium
|
|
21
|
+
confidence: 0.82
|
|
22
|
+
tags: [quality, error-handling]
|
|
23
|
+
message:
|
|
24
|
+
title: Use a consistent error construction pattern
|
|
25
|
+
summary: "`${captures.issue.text}` indicates mixed error shapes in this module."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Standardize on one error type or envelope and normalize throw/reject paths.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-mixed-abstraction-level
|
|
5
|
+
title: Keep function abstraction levels consistent
|
|
6
|
+
summary: Functions that mix transport, persistence, validation, and domain logic are hard to change safely.
|
|
7
|
+
rationale: Mixed abstraction creates hidden coupling and complicates testing and review.
|
|
8
|
+
tags: [quality, architecture, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.mixed-abstraction-level
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.architecture
|
|
20
|
+
severity: medium
|
|
21
|
+
confidence: 0.8
|
|
22
|
+
tags: [quality, architecture]
|
|
23
|
+
message:
|
|
24
|
+
title: Split this flow into cohesive layers
|
|
25
|
+
summary: "`${captures.issue.text}` combines multiple abstraction levels in a single flow."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Separate transport, validation, persistence, and domain logic into dedicated functions or services.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-primitive-obsession-in-domain-model
|
|
5
|
+
title: Avoid primitive obsession in domain model APIs
|
|
6
|
+
summary: Domain-facing APIs with many primitive parameters should use richer value objects.
|
|
7
|
+
rationale: Grouping related primitives into value types improves readability and reduces argument-order bugs.
|
|
8
|
+
tags: [quality, maintainability, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.primitive-obsession-domain-model
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.design
|
|
20
|
+
severity: low
|
|
21
|
+
confidence: 0.8
|
|
22
|
+
tags: [quality, design]
|
|
23
|
+
message:
|
|
24
|
+
title: Replace primitive parameter groups with domain objects
|
|
25
|
+
summary: "`${captures.issue.text}` appears to rely on repeated primitive parameters."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Introduce a value object or typed input model for related arguments.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-temporal-coupling
|
|
5
|
+
title: Avoid APIs with hidden call-order requirements
|
|
6
|
+
summary: APIs that require callers to invoke methods in strict hidden order are fragile.
|
|
7
|
+
rationale: Temporal coupling is a common source of runtime bugs and unclear contracts.
|
|
8
|
+
tags: [quality, architecture, rules-catalog]
|
|
9
|
+
stability: experimental
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.temporal-coupling-api-order
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.architecture
|
|
20
|
+
severity: low
|
|
21
|
+
confidence: 0.65
|
|
22
|
+
tags: [quality, architecture]
|
|
23
|
+
message:
|
|
24
|
+
title: Encode call ordering in the API contract
|
|
25
|
+
summary: "`${captures.issue.text}` suggests implicit call ordering requirements."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Model lifecycle stages explicitly in types or stateful objects to prevent invalid sequences.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.quality.no-wide-public-surface
|
|
5
|
+
title: Keep module public surface narrow
|
|
6
|
+
summary: Modules exporting too many symbols become hard to evolve safely.
|
|
7
|
+
rationale: Broad module APIs increase accidental coupling and long-term maintenance cost.
|
|
8
|
+
tags: [quality, architecture, rules-catalog]
|
|
9
|
+
stability: stable
|
|
10
|
+
appliesTo: file
|
|
11
|
+
scope:
|
|
12
|
+
languages: [typescript, javascript]
|
|
13
|
+
match:
|
|
14
|
+
fact:
|
|
15
|
+
kind: quality.wide-public-surface
|
|
16
|
+
bind: issue
|
|
17
|
+
emit:
|
|
18
|
+
finding:
|
|
19
|
+
category: quality.architecture
|
|
20
|
+
severity: medium
|
|
21
|
+
confidence: 0.84
|
|
22
|
+
tags: [quality, architecture]
|
|
23
|
+
message:
|
|
24
|
+
title: Reduce public exports in this module
|
|
25
|
+
summary: "`${captures.issue.text}` exports more public symbols than the maintainability threshold."
|
|
26
|
+
remediation:
|
|
27
|
+
summary: Split APIs, hide internals, or create focused entrypoints with fewer exports.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.react.no-accessibility-label-missing
|
|
5
|
+
title: Give interactive elements an accessible name
|
|
6
|
+
summary: Buttons, links, and inputs need labels, aria attributes, or visible text so assistive technologies can describe them.
|
|
7
|
+
rationale: Unlabeled controls are ambiguous to keyboard and screen reader users and fail basic accessibility expectations.
|
|
8
|
+
tags:
|
|
9
|
+
- react
|
|
10
|
+
- accessibility
|
|
11
|
+
- ui
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: experimental
|
|
14
|
+
appliesTo: function
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: ui.react.missing-accessible-name
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.ui
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.74
|
|
28
|
+
tags:
|
|
29
|
+
- react
|
|
30
|
+
- accessibility
|
|
31
|
+
- ui
|
|
32
|
+
message:
|
|
33
|
+
title: Add an accessible name to interactive elements
|
|
34
|
+
summary: "`${captures.issue.text}` renders without aria labeling or visible text."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Add aria-label or aria-labelledby, associate a label element, or include descriptive visible content.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.react.no-activedescendant-on-non-focusable-host
|
|
5
|
+
title: Make aria-activedescendant hosts keyboard focusable
|
|
6
|
+
summary: "Elements that manage active descendants must participate in the tab order or be native controls that already receive focus."
|
|
7
|
+
rationale: Screen readers and keyboard users cannot follow listbox and combobox patterns when the controlling node never becomes focused.
|
|
8
|
+
tags:
|
|
9
|
+
- react
|
|
10
|
+
- accessibility
|
|
11
|
+
- ui
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: experimental
|
|
14
|
+
appliesTo: function
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: ui.react.activedescendant-host-not-focusable
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.ui
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.8
|
|
28
|
+
tags:
|
|
29
|
+
- react
|
|
30
|
+
- accessibility
|
|
31
|
+
- ui
|
|
32
|
+
message:
|
|
33
|
+
title: Add focusability to the active-descendant owner
|
|
34
|
+
summary: "`${captures.issue.text}` sets `aria-activedescendant` on a host that is not keyboard focusable."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Use a native input or button where possible, or add `tabIndex={0}` on the owning element while preserving roving tabindex semantics for options.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.react.no-click-without-keyboard-handler
|
|
5
|
+
title: Support keyboard interaction for click handlers
|
|
6
|
+
summary: "Non-interactive JSX elements that respond to clicks also need an equivalent keyboard path."
|
|
7
|
+
rationale: Mouse-only interaction blocks keyboard users and creates inaccessible custom controls that do not behave like native UI elements.
|
|
8
|
+
tags:
|
|
9
|
+
- react
|
|
10
|
+
- accessibility
|
|
11
|
+
- ui
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: experimental
|
|
14
|
+
appliesTo: function
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: ui.react.click-without-keyboard-handler
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.ui
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.84
|
|
28
|
+
tags:
|
|
29
|
+
- react
|
|
30
|
+
- accessibility
|
|
31
|
+
- ui
|
|
32
|
+
message:
|
|
33
|
+
title: Add keyboard support to click-driven UI
|
|
34
|
+
summary: "`${captures.issue.text}` handles clicks without an equivalent keyboard event."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Prefer native buttons or links, or add the necessary role, focus behavior, and keyboard handlers for the same action.
|