@sarj/eslint-plugin 19.16.0 → 19.18.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 +290 -4
- package/dist/{chunk-F6SYEJAW.js → chunk-E2O4LN7G.js} +759 -282
- package/dist/index.js +1 -1
- package/dist/stylelint.js +96 -0
- package/package.json +11 -1
package/dist/catalog.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
publicDocumentation,
|
|
3
3
|
ruleSpec,
|
|
4
4
|
src_default
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-E2O4LN7G.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.",
|
|
@@ -4888,11 +5118,13 @@ var PREFER_DISCRIMINATED_UNION_DOCUMENTATION = {
|
|
|
4888
5118
|
summary: "Preserve producer-proven tag/payload and Boolean state relationships in return types.",
|
|
4889
5119
|
defaultLevel: "warning",
|
|
4890
5120
|
rationale: "A flat object with optional branch data loses the relationship between a tag and its payload. Callers cannot narrow to the required fields, and the type permits incomplete or contradictory combinations.",
|
|
4891
|
-
remediation: "If the variants are mutually exclusive, represent each with a literal tag and its required payload.
|
|
5121
|
+
remediation: "If the variants are mutually exclusive, represent each with a literal tag and its required payload. For predicates over one current state, consider returning that authoritative state instead of storing multiple derived flags. Preserve every valid state, independent dimension, shared field, payload value type and nullability. For a producer returning a subset of a broader wire contract, give the producer a precise domain return type after validation.",
|
|
4892
5122
|
category: "correctness",
|
|
4893
5123
|
autofix: "safe",
|
|
4894
5124
|
limitations: [
|
|
4895
|
-
"Names, Boolean counts and optional-field counts never establish a finding. A producer's literal writes establish either tag-specific payload presence or a pair of required Boolean fields with two or three distinct combinations, with both fields varying. Boolean members may use boolean, true | false or one unmerged nongeneric local alias of either. All four combinations, constant dimensions
|
|
5125
|
+
"Names, Boolean counts and optional-field counts never establish a finding. A producer's literal writes establish either tag-specific payload presence or a pair of required Boolean fields with two or three distinct combinations, with both fields varying. Boolean members may use boolean, true | false or one unmerged nongeneric local alias of either. All four combinations, constant dimensions and optional/unknown dimensions are excluded. Expression-valued flags require the separate typed evidence described below. At most eight Boolean fields are compared. Only one relationship is reported per contract; existing literal/payload evidence takes precedence. Independently nullable payloads do not erase Boolean evidence.",
|
|
5126
|
+
"With type services enabled, a synchronous nongeneric producer with exactly one own return, a final direct object return and a supported flat local contract also exposes strict equality predicates over the same earlier local const binding. Native types at both reads must be finite domains of at most sixteen string/number literals containing both distinct singleton comparison values. Literal constants and direct named-import/local enum members are supported; enum declarations and members are resolved by symbol identity and raw runtime literal values, including renamed imports and reexports. At most 128 candidate pairs per file are analyzed; exceeding the bound abstains from all typed findings in that file. No automatic fix is offered for these projections.",
|
|
5127
|
+
"The const snapshot may be destructured or copied from another primitive binding, passed to callbacks, or read by closures without losing its value. Mutable bindings, parameters and module captures, property reads/getters, open/nullable/object/symbol domains, async producers, multiple own returns, generic/inherited/imported contracts and dynamic eval abstain. Nested callback returns do not belong to the producer. Enum namespace writes, aliases, escapes, computed accesses, calls and merged declarations in the analyzed file abstain. Cross-file enum declarations can supply type/constant identity; external mutation, dishonest declarations/assertions and runtime monkeypatching are not modeled. The analysis proves a relationship under those type and mutation assumptions, not domain intent or a whole-program ownership guarantee.",
|
|
4896
5128
|
"Producer analysis requires a finite literal tag, every declared tag syntactically witnessed, exhaustive simple return paths without literal constant conditions, plain object returns, and consistent optional-field presence for each tag. It resolves only unmerged local aliases/interfaces without inheritance or generics, one local alias of a literal tag domain, and the built-in Promise around async returns. Callable or opaque own then properties abstain for async producers because Promise assimilation can replace the fulfilled value. Inherited then methods and external prototype mutation are not modeled. This is syntax-only evidence of field presence; explicit undefined, void and null payloads do not establish payload requirements, while expression value types are not inferred. Type-only assertion/satisfies/non-null wrappers, literal computed string keys and a sole-use const immediately before its return are recognized. Const alias chains, observation, mutation and dynamic eval abstain. Dynamic returns, spreads, dynamic computed keys, accessors, loops and try statements are deliberately skipped.",
|
|
4897
5129
|
"A switch producer is supported only for a non-overloaded function declaration when its sole body statement switches on an unchanged direct string or number parameter, has unique same-kind literal labels and a default, and every nonempty case body is a sole object return or throw, optionally inside sole blocks. Empty labels may share the next terminating body; nested conditions, conditional returns, statement prefixes, breaks, other fallthrough, captured/closed inputs, dynamic eval and switches under preceding control flow abstain. Broad parameter domains establish input witnesses for each label and the default; this does not infer branch-specific runtime effects or expression value types. Path visits, depth and returned objects are bounded conservatively.",
|
|
4898
5130
|
"These are refactoring advisories, not proven defects or proof that other writers cannot produce more states. Historical observations, partial results, unknown states and independently completing operations may need the broader contract. Review all readers and writers before migrating a shared contract; preserve every valid combination. A union of existing literal flag pairs is the smallest type-only replacement; a named disposition is a reviewed domain migration.",
|
|
@@ -4908,6 +5140,8 @@ var PREFER_DISCRIMINATED_UNION_DOCUMENTATION = {
|
|
|
4908
5140
|
{ id: "explicit-produced-variants", scenarioId: "produced-variants", title: "Give each produced variant its payload", outcome: "no-match", files: [{ path: "src/job.ts", source: 'function job(done: boolean): { phase: "queued"; ticket: string } | { phase: "complete" } { return done ? { phase: "complete" } : { phase: "queued", ticket: "t" }; }' }], focusPath: "src/job.ts", expectedCount: 0, public: true },
|
|
4909
5141
|
{ id: "flat-switch-producer", scenarioId: "switch-producer", title: "A complete dispatcher preserves each returned variant", outcome: "match", files: [{ path: "src/job.ts", source: 'function job(command: string): { phase: "queued" | "complete"; ticket?: string } { switch (command) { case "start": return { phase: "queued", ticket: "t" }; default: return { phase: "complete" }; } }' }], focusPath: "src/job.ts", expectedCount: 1, public: true },
|
|
4910
5142
|
{ id: "explicit-switch-variants", scenarioId: "switch-producer", title: "An explicit dispatcher result supports payload narrowing", outcome: "no-match", files: [{ path: "src/job.ts", source: 'function job(command: string): { phase: "queued"; ticket: string } | { phase: "complete" } { switch (command) { case "start": return { phase: "queued", ticket: "t" }; default: return { phase: "complete" }; } }' }], focusPath: "src/job.ts", expectedCount: 0, public: true },
|
|
5143
|
+
{ id: "immutable-state-projections", scenarioId: "state-projection", title: "Two predicates over one immutable phase cannot both be true", outcome: "match", files: [{ path: "src/projection.ts", source: 'type Phase = "ready" | "waiting" | "unknown"; declare function snapshot(): Phase; function state(): { ready: boolean; waiting: boolean } { const phase = snapshot(); return { ready: phase === "ready", waiting: phase === "waiting" }; }' }], focusPath: "src/projection.ts", expectedCount: 1, public: true },
|
|
5144
|
+
{ id: "authoritative-state", scenarioId: "state-projection", title: "Return the phase while preserving the independent timeout dimension", outcome: "no-match", files: [{ path: "src/projection.ts", source: 'type Phase = "ready" | "waiting" | "reconnecting" | "unknown"; declare function snapshot(): Phase; function state(timeout: boolean): { phase: Phase; timeout: boolean } { const phase = snapshot(); return { phase, timeout }; }' }], focusPath: "src/projection.ts", expectedCount: 0, public: true },
|
|
4911
5145
|
{
|
|
4912
5146
|
id: "safe-autofix",
|
|
4913
5147
|
title: "Preserve an unused private producer's exact existing variants",
|
|
@@ -6565,6 +6799,53 @@ var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
|
|
|
6565
6799
|
]
|
|
6566
6800
|
};
|
|
6567
6801
|
|
|
6802
|
+
// src/docs/require-ime-safe-enter-handler.ts
|
|
6803
|
+
var REQUIRE_IME_SAFE_ENTER_HANDLER_DOCUMENTATION = {
|
|
6804
|
+
defaultLevel: "warning",
|
|
6805
|
+
summary: "Preserve IME composition before Enter submits or blurs a native text control.",
|
|
6806
|
+
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.",
|
|
6807
|
+
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.",
|
|
6808
|
+
category: "correctness",
|
|
6809
|
+
requiresTypeInformation: false,
|
|
6810
|
+
limitations: [
|
|
6811
|
+
"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.",
|
|
6812
|
+
"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."
|
|
6813
|
+
],
|
|
6814
|
+
references: [
|
|
6815
|
+
"https://github.com/GoogleChrome/modern-web-guidance/blob/4dd968349e54ca45a05dd5c818fb035c9054b022/skills/modern-web-guidance/guides/forms/ime-safe-enter-submit.md"
|
|
6816
|
+
],
|
|
6817
|
+
examples: [
|
|
6818
|
+
{
|
|
6819
|
+
id: "guarded-composition",
|
|
6820
|
+
title: "guarded composition",
|
|
6821
|
+
outcome: "no-match",
|
|
6822
|
+
files: [
|
|
6823
|
+
{
|
|
6824
|
+
path: "src/input.tsx",
|
|
6825
|
+
source: '<textarea onKeyDown={e => { if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return; if (e.key === "Enter") { e.preventDefault(); e.currentTarget.form?.requestSubmit(); } }} />'
|
|
6826
|
+
}
|
|
6827
|
+
],
|
|
6828
|
+
focusPath: "src/input.tsx",
|
|
6829
|
+
expectedCount: 0,
|
|
6830
|
+
public: true
|
|
6831
|
+
},
|
|
6832
|
+
{
|
|
6833
|
+
id: "interrupted-composition",
|
|
6834
|
+
title: "interrupted composition",
|
|
6835
|
+
outcome: "match",
|
|
6836
|
+
files: [
|
|
6837
|
+
{
|
|
6838
|
+
path: "src/input.tsx",
|
|
6839
|
+
source: '<textarea onKeyDown={e => { if (e.key === "Enter") e.currentTarget.form?.requestSubmit(); }} />'
|
|
6840
|
+
}
|
|
6841
|
+
],
|
|
6842
|
+
focusPath: "src/input.tsx",
|
|
6843
|
+
expectedCount: 1,
|
|
6844
|
+
public: true
|
|
6845
|
+
}
|
|
6846
|
+
]
|
|
6847
|
+
};
|
|
6848
|
+
|
|
6568
6849
|
// src/docs/require-interface-for-exported-class.ts
|
|
6569
6850
|
var REQUIRE_INTERFACE_FOR_EXPORTED_CLASS_DOCUMENTATION = {
|
|
6570
6851
|
defaultLevel: "error",
|
|
@@ -7167,6 +7448,7 @@ var RULE_DOCUMENTATION = {
|
|
|
7167
7448
|
"named-child-schema-type": NAMED_CHILD_SCHEMA_TYPE_DOCUMENTATION,
|
|
7168
7449
|
"no-bare-return-from-test-catch": NO_BARE_RETURN_FROM_TEST_CATCH_DOCUMENTATION,
|
|
7169
7450
|
"no-bespoke-api-case-conversion": NO_BESPOKE_API_CASE_CONVERSION_DOCUMENTATION,
|
|
7451
|
+
"no-blocked-input-paste": NO_BLOCKED_INPUT_PASTE_DOCUMENTATION,
|
|
7170
7452
|
"no-boolean-selector-parameter": NO_BOOLEAN_SELECTOR_PARAMETER_DOCUMENTATION,
|
|
7171
7453
|
"no-broad-return-type": NO_BROAD_RETURN_TYPE_DOCUMENTATION,
|
|
7172
7454
|
"no-client-side-data-fetching": NO_CLIENT_SIDE_DATA_FETCHING_DOCUMENTATION,
|
|
@@ -7200,6 +7482,7 @@ var RULE_DOCUMENTATION = {
|
|
|
7200
7482
|
"no-in-operator-on-built-in-collections": NO_IN_OPERATOR_ON_BUILT_IN_COLLECTIONS_DOCUMENTATION,
|
|
7201
7483
|
"no-insecure-random-id": NO_INSECURE_RANDOM_ID_DOCUMENTATION,
|
|
7202
7484
|
"no-invalid-typed-mutation": NO_INVALID_TYPED_MUTATION_DOCUMENTATION,
|
|
7485
|
+
"no-invalid-web-resource-hints": NO_INVALID_WEB_RESOURCE_HINTS_DOCUMENTATION,
|
|
7203
7486
|
"no-invalid-zod-custom-parse": NO_INVALID_ZOD_CUSTOM_PARSE_DOCUMENTATION,
|
|
7204
7487
|
"no-json-stringify-error": NO_JSON_STRINGIFY_ERROR_DOCUMENTATION,
|
|
7205
7488
|
"no-json-stringify-object-equality": NO_JSON_STRINGIFY_OBJECT_EQUALITY_DOCUMENTATION,
|
|
@@ -7207,6 +7490,7 @@ var RULE_DOCUMENTATION = {
|
|
|
7207
7490
|
"no-log-only-catch": NO_LOG_ONLY_CATCH_DOCUMENTATION,
|
|
7208
7491
|
"no-logical-or-fallback": NO_LOGICAL_OR_FALLBACK_DOCUMENTATION,
|
|
7209
7492
|
"no-long-comment": NO_LONG_COMMENT_DOCUMENTATION,
|
|
7493
|
+
"no-message-origin-string-matching": NO_MESSAGE_ORIGIN_STRING_MATCHING_DOCUMENTATION,
|
|
7210
7494
|
"no-mutating-container-transform": NO_MUTATING_CONTAINER_TRANSFORM_DOCUMENTATION,
|
|
7211
7495
|
"no-mutating-input-with-result": NO_MUTATING_INPUT_WITH_RESULT_DOCUMENTATION,
|
|
7212
7496
|
"no-negative-only-http-status-assertion": NO_NEGATIVE_ONLY_HTTP_STATUS_ASSERTION_DOCUMENTATION,
|
|
@@ -7214,6 +7498,7 @@ var RULE_DOCUMENTATION = {
|
|
|
7214
7498
|
"no-offset-pagination": NO_OFFSET_PAGINATION_DOCUMENTATION,
|
|
7215
7499
|
"no-oxlint-directive": NO_OXLINT_DIRECTIVE_DOCUMENTATION,
|
|
7216
7500
|
"no-partial-type-predicate": NO_PARTIAL_TYPE_PREDICATE_DOCUMENTATION,
|
|
7501
|
+
"no-password-get-form": NO_PASSWORD_GET_FORM_DOCUMENTATION,
|
|
7217
7502
|
"no-positional-tuple-return": NO_POSITIONAL_TUPLE_RETURN_DOCUMENTATION,
|
|
7218
7503
|
"no-production-browser-source-maps": NO_PRODUCTION_BROWSER_SOURCE_MAPS_DOCUMENTATION,
|
|
7219
7504
|
"no-raw-env": NO_RAW_ENV_DOCUMENTATION,
|
|
@@ -7301,6 +7586,7 @@ var RULE_DOCUMENTATION = {
|
|
|
7301
7586
|
"require-explicit-contract-implementation": REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION,
|
|
7302
7587
|
"require-explicit-service-contract": REQUIRE_EXPLICIT_SERVICE_CONTRACT_DOCUMENTATION,
|
|
7303
7588
|
"require-fetch-timeout": REQUIRE_FETCH_TIMEOUT_DOCUMENTATION,
|
|
7589
|
+
"require-ime-safe-enter-handler": REQUIRE_IME_SAFE_ENTER_HANDLER_DOCUMENTATION,
|
|
7304
7590
|
"require-interface-for-exported-class": REQUIRE_INTERFACE_FOR_EXPORTED_CLASS_DOCUMENTATION,
|
|
7305
7591
|
"require-jwt-lifetime": REQUIRE_JWT_LIFETIME_DOCUMENTATION,
|
|
7306
7592
|
"require-pascal-case-zod-schema-name": REQUIRE_PASCAL_CASE_ZOD_SCHEMA_NAME_DOCUMENTATION,
|
|
@@ -7313,7 +7599,7 @@ var RULE_DOCUMENTATION = {
|
|
|
7313
7599
|
"require-zod-form-validation": REQUIRE_ZOD_FORM_VALIDATION_DOCUMENTATION,
|
|
7314
7600
|
"sole-export-matches-filename": SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION,
|
|
7315
7601
|
"source-coupled-test": SOURCE_COUPLED_TEST_DOCUMENTATION,
|
|
7316
|
-
|
|
7602
|
+
stepdown: STEPDOWN_DOCUMENTATION,
|
|
7317
7603
|
"store-insert-requires-on-conflict": STORE_INSERT_REQUIRES_ON_CONFLICT_DOCUMENTATION,
|
|
7318
7604
|
"test-loops-over-literal-cases": TEST_LOOPS_OVER_LITERAL_CASES_DOCUMENTATION,
|
|
7319
7605
|
"test-phase-label-comment": TEST_PHASE_LABEL_COMMENT_DOCUMENTATION
|