@sarj/eslint-plugin 19.16.0 → 19.17.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/dist/catalog.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  publicDocumentation,
3
3
  ruleSpec,
4
4
  src_default
5
- } from "./chunk-F6SYEJAW.js";
5
+ } from "./chunk-4USNCXB3.js";
6
6
 
7
7
  // src/docs/directive-disable-enable-pair.ts
8
8
  var DIRECTIVE_DISABLE_ENABLE_PAIR_DOCUMENTATION = {
@@ -636,6 +636,56 @@ var NO_BESPOKE_API_CASE_CONVERSION_DOCUMENTATION = {
636
636
  ]
637
637
  };
638
638
 
639
+ // src/docs/no-blocked-input-paste.ts
640
+ var NO_BLOCKED_INPUT_PASTE_DOCUMENTATION = {
641
+ defaultLevel: "warning",
642
+ summary: "Allow clipboard input when a text control has no replacement paste handling.",
643
+ rationale: "An editable text control that only cancels paste prevents users from entering generated passwords, authentication codes and copied data. This creates avoidable accessibility and password-manager barriers.",
644
+ remediation: "Allow native paste. If the product must normalize clipboard content, provide explicit replacement processing and preserve keyboard and password-manager access; review the behavior instead of applying an automatic edit.",
645
+ category: "correctness",
646
+ requiresTypeInformation: false,
647
+ limitations: [
648
+ "An unresolved alternate paste phase or spread may supply replacement handling and suppresses the warning.",
649
+ "Only intrinsic editable input and textarea handlers whose complete inline body is a direct preventDefault() call are reported.",
650
+ "Clipboard processing, conditional cancellation, referenced handlers, rich editors, non-text inputs, custom components, optional calls and uncertain effective props remain outside the detector."
651
+ ],
652
+ references: [
653
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/forms/forms.md",
654
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/forms/autofill-sign-in-form.md",
655
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/forms/sms-otp-form.md"
656
+ ],
657
+ examples: [
658
+ {
659
+ id: "native-paste",
660
+ title: "Allow native clipboard input",
661
+ outcome: "no-match",
662
+ files: [
663
+ {
664
+ path: "src/view.tsx",
665
+ source: '<input type="password" />'
666
+ }
667
+ ],
668
+ focusPath: "src/view.tsx",
669
+ expectedCount: 0,
670
+ public: true
671
+ },
672
+ {
673
+ id: "pure-paste-blocker",
674
+ title: "Review unconditional paste cancellation",
675
+ outcome: "match",
676
+ files: [
677
+ {
678
+ path: "src/view.tsx",
679
+ source: '<input type="password" onPaste={event => event.preventDefault()} />'
680
+ }
681
+ ],
682
+ focusPath: "src/view.tsx",
683
+ expectedCount: 1,
684
+ public: true
685
+ }
686
+ ]
687
+ };
688
+
639
689
  // src/docs/no-boolean-selector-parameter.ts
640
690
  var NO_BOOLEAN_SELECTOR_PARAMETER_DOCUMENTATION = {
641
691
  summary: "Prefer intention-revealing operations over a boolean parameter selecting between actions.",
@@ -1918,6 +1968,88 @@ var NO_INVALID_TYPED_MUTATION_DOCUMENTATION = {
1918
1968
  ]
1919
1969
  };
1920
1970
 
1971
+ // src/docs/no-invalid-web-resource-hints.ts
1972
+ var NO_INVALID_WEB_RESOURCE_HINTS_DOCUMENTATION = {
1973
+ defaultLevel: "warning",
1974
+ summary: "Keep native resource hints consistent with browser loading and preload request modes.",
1975
+ rationale: "Lazy loading delays even explicitly high-priority images until layout. Font preloads with incompatible credentials modes cannot satisfy the subsequent font request. The unsupported loading=auto value and obsolete importance attribute do not express supported native loading behavior. Oxlint 1.91 still accepts importance, so this advisory fills that verified upstream gap.",
1976
+ remediation: "Review whether the image is critical or offscreen, use the matching loading policy, specify the preload destination, and use anonymous CORS for font preloads. Do not change request behavior automatically.",
1977
+ category: "performance",
1978
+ requiresTypeInformation: false,
1979
+ limitations: [
1980
+ "Only intrinsic JSX img, iframe, video, audio, script and link attributes are inspected. Custom framework media components, HTML strings and DOM mutations are outside this rule.",
1981
+ "Stable local string bindings are resolved. Later unknown spreads and dynamic values remain unproven; explicit attributes after spreads can establish a finding.",
1982
+ "The rule does not infer which element is LCP, count page-wide priority hints, require image dimensions that may come from CSS, or require sizes when 100vw may be correct."
1983
+ ],
1984
+ references: [
1985
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/performance/optimize-image-priority.md",
1986
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/performance/optimize-preload-priority.md",
1987
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/performance/optimize-script-priority.md"
1988
+ ],
1989
+ examples: [
1990
+ {
1991
+ id: "eager-critical-image",
1992
+ scenarioId: "image-loading",
1993
+ title: "Load a declared critical image eagerly",
1994
+ outcome: "no-match",
1995
+ files: [
1996
+ {
1997
+ path: "src/view.tsx",
1998
+ source: '<img loading="eager" fetchPriority="high" />'
1999
+ }
2000
+ ],
2001
+ focusPath: "src/view.tsx",
2002
+ expectedCount: 0,
2003
+ public: true
2004
+ },
2005
+ {
2006
+ id: "lazy-critical-image",
2007
+ scenarioId: "image-loading",
2008
+ title: "Review conflicting image hints",
2009
+ outcome: "match",
2010
+ files: [
2011
+ {
2012
+ path: "src/view.tsx",
2013
+ source: '<img loading="lazy" fetchPriority="high" />'
2014
+ }
2015
+ ],
2016
+ focusPath: "src/view.tsx",
2017
+ expectedCount: 1,
2018
+ public: true
2019
+ },
2020
+ {
2021
+ id: "anonymous-font-preload",
2022
+ scenarioId: "font-preload",
2023
+ title: "Match the font request mode",
2024
+ outcome: "no-match",
2025
+ files: [
2026
+ {
2027
+ path: "src/view.tsx",
2028
+ source: '<link rel="preload" as="font" href="/font.woff2" crossOrigin="anonymous" />'
2029
+ }
2030
+ ],
2031
+ focusPath: "src/view.tsx",
2032
+ expectedCount: 0,
2033
+ public: true
2034
+ },
2035
+ {
2036
+ id: "font-preload-without-cors",
2037
+ scenarioId: "font-preload",
2038
+ title: "Review a non-reusable font preload",
2039
+ outcome: "match",
2040
+ files: [
2041
+ {
2042
+ path: "src/view.tsx",
2043
+ source: '<link rel="preload" as="font" href="/font.woff2" />'
2044
+ }
2045
+ ],
2046
+ focusPath: "src/view.tsx",
2047
+ expectedCount: 1,
2048
+ public: true
2049
+ }
2050
+ ]
2051
+ };
2052
+
1921
2053
  // src/docs/no-invalid-zod-custom-parse.ts
1922
2054
  var NO_INVALID_ZOD_CUSTOM_PARSE_DOCUMENTATION = {
1923
2055
  summary: "Do not parse an incompatible primitive literal through an unvalidated Zod custom schema.",
@@ -2179,6 +2311,55 @@ export function PortBars() { return null; }`
2179
2311
  ]
2180
2312
  };
2181
2313
 
2314
+ // src/docs/no-message-origin-string-matching.ts
2315
+ var NO_MESSAGE_ORIGIN_STRING_MATCHING_DOCUMENTATION = {
2316
+ defaultLevel: "warning",
2317
+ summary: "Compare incoming browser message origins against exact trusted origins.",
2318
+ rationale: "Prefix, suffix and substring checks do not establish an origin trust boundary. For example, https://trusted.example.attacker.invalid passes a prefix check against https://trusted.example.",
2319
+ remediation: "Compare exact allowlisted origins or parse the origin and validate the intended scheme, host and port. Reject opaque null origins unless a separately verified source/capability contract establishes trust; do not require an experimental Origin API.",
2320
+ category: "security",
2321
+ requiresTypeInformation: false,
2322
+ limitations: [
2323
+ "Only inline callbacks registered for message on ambient addEventListener, window, self or globalThis are tracked by variable identity.",
2324
+ "Named listeners, event aliases, transformed origin strings, regular expressions and cross-file authorization helpers are not followed. Ordinary object.origin strings and shadowed globals are preserved.",
2325
+ "This detects imprecise incoming origin matching, not all missing authorization checks. Outgoing target origins remain owned by Unicorn's require-post-message-target-origin rule."
2326
+ ],
2327
+ references: [
2328
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/security/validate-origins.md",
2329
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/security/security.md"
2330
+ ],
2331
+ examples: [
2332
+ {
2333
+ id: "exact-origin",
2334
+ title: "Compare an explicit trusted origin",
2335
+ outcome: "no-match",
2336
+ files: [
2337
+ {
2338
+ path: "src/listener.ts",
2339
+ source: 'window.addEventListener("message", event => { if (event.origin === "https://trusted.example") accept(event.data); });'
2340
+ }
2341
+ ],
2342
+ focusPath: "src/listener.ts",
2343
+ expectedCount: 0,
2344
+ public: true
2345
+ },
2346
+ {
2347
+ id: "prefix-origin",
2348
+ title: "Review a spoofable origin prefix",
2349
+ outcome: "match",
2350
+ files: [
2351
+ {
2352
+ path: "src/listener.ts",
2353
+ source: 'window.addEventListener("message", event => { if (event.origin.startsWith("https://trusted.example")) accept(event.data); });'
2354
+ }
2355
+ ],
2356
+ focusPath: "src/listener.ts",
2357
+ expectedCount: 1,
2358
+ public: true
2359
+ }
2360
+ ]
2361
+ };
2362
+
2182
2363
  // src/docs/no-mutating-container-transform.ts
2183
2364
  var NO_MUTATING_CONTAINER_TRANSFORM_DOCUMENTATION = {
2184
2365
  defaultLevel: "warning",
@@ -2382,6 +2563,55 @@ var NO_PARTIAL_TYPE_PREDICATE_DOCUMENTATION = {
2382
2563
  ]
2383
2564
  };
2384
2565
 
2566
+ // src/docs/no-password-get-form.ts
2567
+ var NO_PASSWORD_GET_FORM_DOCUMENTATION = {
2568
+ defaultLevel: "warning",
2569
+ summary: "Keep named password controls out of native GET form submissions.",
2570
+ rationale: "Native GET submission serializes enabled, named password controls into the URL, exposing credentials through browser history and request logs. GET is also the default for missing or invalid method attributes.",
2571
+ remediation: "Review the destination endpoint and submit credentials with POST. Keep server-side validation, HTTPS and the appropriate anti-CSRF protections; this rule only checks the native form serialization boundary.",
2572
+ category: "security",
2573
+ requiresTypeInformation: false,
2574
+ limitations: [
2575
+ "Only native form elements and direct intrinsic/fragment descendants are proved. Custom components, expressions, external form ownership, disabled fieldsets and unknown spreads are preserved.",
2576
+ "Forms with custom submission handlers, function or dynamic actions, or dynamic methods are left to review. React function actions submit using POST even when the method is omitted.",
2577
+ "Unnamed, empty-name and disabled password controls are not successful controls. The detector reports once per offending form and does not infer sensitive data from field names."
2578
+ ],
2579
+ references: [
2580
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/forms/forms.md",
2581
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/forms/autofill-sign-in-form.md"
2582
+ ],
2583
+ examples: [
2584
+ {
2585
+ id: "post-password",
2586
+ title: "Submit the password with POST",
2587
+ outcome: "no-match",
2588
+ files: [
2589
+ {
2590
+ path: "src/view.tsx",
2591
+ source: '<form method="post"><input type="password" name="password" /></form>'
2592
+ }
2593
+ ],
2594
+ focusPath: "src/view.tsx",
2595
+ expectedCount: 0,
2596
+ public: true
2597
+ },
2598
+ {
2599
+ id: "default-get-password",
2600
+ title: "Review password serialization into the URL",
2601
+ outcome: "match",
2602
+ files: [
2603
+ {
2604
+ path: "src/view.tsx",
2605
+ source: '<form><input type="password" name="password" /></form>'
2606
+ }
2607
+ ],
2608
+ focusPath: "src/view.tsx",
2609
+ expectedCount: 1,
2610
+ public: true
2611
+ }
2612
+ ]
2613
+ };
2614
+
2385
2615
  // src/docs/no-positional-tuple-return.ts
2386
2616
  var NO_POSITIONAL_TUPLE_RETURN_DOCUMENTATION = {
2387
2617
  summary: "Disallow returning a multi-field tuple from a named function; return a named object so call sites cannot mismatch slots.",
@@ -6565,6 +6795,53 @@ var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
6565
6795
  ]
6566
6796
  };
6567
6797
 
6798
+ // src/docs/require-ime-safe-enter-handler.ts
6799
+ var REQUIRE_IME_SAFE_ENTER_HANDLER_DOCUMENTATION = {
6800
+ defaultLevel: "warning",
6801
+ summary: "Preserve IME composition before Enter submits or blurs a native text control.",
6802
+ rationale: "The Enter key confirms Japanese, Chinese and Korean composition as well as triggering custom actions. An unguarded native form submission or blur interrupts composing text.",
6803
+ remediation: "Check the native keyboard event composition state before the action. Retain the Safari keyCode 229 or composition-timestamp fallback required by the browser policy; offer a native submit button.",
6804
+ category: "correctness",
6805
+ requiresTypeInformation: false,
6806
+ limitations: [
6807
+ "Only inline editable input/textarea keydown handlers with direct Enter equality (optionally combined with !shiftKey) and currentTarget.blur() or currentTarget.form.requestSubmit() are checked. Unknown guards and rebound event parameters remain unproven. Referenced handlers, custom components, arbitrary submission helpers, logical/conditional branches and DOM listeners need review.",
6808
+ "The presence of a composition/keyCode/modifier check or composition listener suppresses the warning conservatively; this does not prove the guard dominates the action or implements the correct Safari fallback."
6809
+ ],
6810
+ references: [
6811
+ "https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/forms/ime-safe-enter-submit.md"
6812
+ ],
6813
+ examples: [
6814
+ {
6815
+ id: "guarded-composition",
6816
+ title: "guarded composition",
6817
+ outcome: "no-match",
6818
+ files: [
6819
+ {
6820
+ path: "src/input.tsx",
6821
+ source: '<textarea onKeyDown={e => { if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return; if (e.key === "Enter") { e.preventDefault(); e.currentTarget.form?.requestSubmit(); } }} />'
6822
+ }
6823
+ ],
6824
+ focusPath: "src/input.tsx",
6825
+ expectedCount: 0,
6826
+ public: true
6827
+ },
6828
+ {
6829
+ id: "interrupted-composition",
6830
+ title: "interrupted composition",
6831
+ outcome: "match",
6832
+ files: [
6833
+ {
6834
+ path: "src/input.tsx",
6835
+ source: '<textarea onKeyDown={e => { if (e.key === "Enter") e.currentTarget.form?.requestSubmit(); }} />'
6836
+ }
6837
+ ],
6838
+ focusPath: "src/input.tsx",
6839
+ expectedCount: 1,
6840
+ public: true
6841
+ }
6842
+ ]
6843
+ };
6844
+
6568
6845
  // src/docs/require-interface-for-exported-class.ts
6569
6846
  var REQUIRE_INTERFACE_FOR_EXPORTED_CLASS_DOCUMENTATION = {
6570
6847
  defaultLevel: "error",
@@ -7167,6 +7444,7 @@ var RULE_DOCUMENTATION = {
7167
7444
  "named-child-schema-type": NAMED_CHILD_SCHEMA_TYPE_DOCUMENTATION,
7168
7445
  "no-bare-return-from-test-catch": NO_BARE_RETURN_FROM_TEST_CATCH_DOCUMENTATION,
7169
7446
  "no-bespoke-api-case-conversion": NO_BESPOKE_API_CASE_CONVERSION_DOCUMENTATION,
7447
+ "no-blocked-input-paste": NO_BLOCKED_INPUT_PASTE_DOCUMENTATION,
7170
7448
  "no-boolean-selector-parameter": NO_BOOLEAN_SELECTOR_PARAMETER_DOCUMENTATION,
7171
7449
  "no-broad-return-type": NO_BROAD_RETURN_TYPE_DOCUMENTATION,
7172
7450
  "no-client-side-data-fetching": NO_CLIENT_SIDE_DATA_FETCHING_DOCUMENTATION,
@@ -7200,6 +7478,7 @@ var RULE_DOCUMENTATION = {
7200
7478
  "no-in-operator-on-built-in-collections": NO_IN_OPERATOR_ON_BUILT_IN_COLLECTIONS_DOCUMENTATION,
7201
7479
  "no-insecure-random-id": NO_INSECURE_RANDOM_ID_DOCUMENTATION,
7202
7480
  "no-invalid-typed-mutation": NO_INVALID_TYPED_MUTATION_DOCUMENTATION,
7481
+ "no-invalid-web-resource-hints": NO_INVALID_WEB_RESOURCE_HINTS_DOCUMENTATION,
7203
7482
  "no-invalid-zod-custom-parse": NO_INVALID_ZOD_CUSTOM_PARSE_DOCUMENTATION,
7204
7483
  "no-json-stringify-error": NO_JSON_STRINGIFY_ERROR_DOCUMENTATION,
7205
7484
  "no-json-stringify-object-equality": NO_JSON_STRINGIFY_OBJECT_EQUALITY_DOCUMENTATION,
@@ -7207,6 +7486,7 @@ var RULE_DOCUMENTATION = {
7207
7486
  "no-log-only-catch": NO_LOG_ONLY_CATCH_DOCUMENTATION,
7208
7487
  "no-logical-or-fallback": NO_LOGICAL_OR_FALLBACK_DOCUMENTATION,
7209
7488
  "no-long-comment": NO_LONG_COMMENT_DOCUMENTATION,
7489
+ "no-message-origin-string-matching": NO_MESSAGE_ORIGIN_STRING_MATCHING_DOCUMENTATION,
7210
7490
  "no-mutating-container-transform": NO_MUTATING_CONTAINER_TRANSFORM_DOCUMENTATION,
7211
7491
  "no-mutating-input-with-result": NO_MUTATING_INPUT_WITH_RESULT_DOCUMENTATION,
7212
7492
  "no-negative-only-http-status-assertion": NO_NEGATIVE_ONLY_HTTP_STATUS_ASSERTION_DOCUMENTATION,
@@ -7214,6 +7494,7 @@ var RULE_DOCUMENTATION = {
7214
7494
  "no-offset-pagination": NO_OFFSET_PAGINATION_DOCUMENTATION,
7215
7495
  "no-oxlint-directive": NO_OXLINT_DIRECTIVE_DOCUMENTATION,
7216
7496
  "no-partial-type-predicate": NO_PARTIAL_TYPE_PREDICATE_DOCUMENTATION,
7497
+ "no-password-get-form": NO_PASSWORD_GET_FORM_DOCUMENTATION,
7217
7498
  "no-positional-tuple-return": NO_POSITIONAL_TUPLE_RETURN_DOCUMENTATION,
7218
7499
  "no-production-browser-source-maps": NO_PRODUCTION_BROWSER_SOURCE_MAPS_DOCUMENTATION,
7219
7500
  "no-raw-env": NO_RAW_ENV_DOCUMENTATION,
@@ -7301,6 +7582,7 @@ var RULE_DOCUMENTATION = {
7301
7582
  "require-explicit-contract-implementation": REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION,
7302
7583
  "require-explicit-service-contract": REQUIRE_EXPLICIT_SERVICE_CONTRACT_DOCUMENTATION,
7303
7584
  "require-fetch-timeout": REQUIRE_FETCH_TIMEOUT_DOCUMENTATION,
7585
+ "require-ime-safe-enter-handler": REQUIRE_IME_SAFE_ENTER_HANDLER_DOCUMENTATION,
7304
7586
  "require-interface-for-exported-class": REQUIRE_INTERFACE_FOR_EXPORTED_CLASS_DOCUMENTATION,
7305
7587
  "require-jwt-lifetime": REQUIRE_JWT_LIFETIME_DOCUMENTATION,
7306
7588
  "require-pascal-case-zod-schema-name": REQUIRE_PASCAL_CASE_ZOD_SCHEMA_NAME_DOCUMENTATION,
@@ -7313,7 +7595,7 @@ var RULE_DOCUMENTATION = {
7313
7595
  "require-zod-form-validation": REQUIRE_ZOD_FORM_VALIDATION_DOCUMENTATION,
7314
7596
  "sole-export-matches-filename": SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION,
7315
7597
  "source-coupled-test": SOURCE_COUPLED_TEST_DOCUMENTATION,
7316
- "stepdown": STEPDOWN_DOCUMENTATION,
7598
+ stepdown: STEPDOWN_DOCUMENTATION,
7317
7599
  "store-insert-requires-on-conflict": STORE_INSERT_REQUIRES_ON_CONFLICT_DOCUMENTATION,
7318
7600
  "test-loops-over-literal-cases": TEST_LOOPS_OVER_LITERAL_CASES_DOCUMENTATION,
7319
7601
  "test-phase-label-comment": TEST_PHASE_LABEL_COMMENT_DOCUMENTATION