Conversation
…_matchConditionalBlockOrArray to accept undefined - Annotate conditionalChanges as ConditionalSettingEntry[] instead of relying on any - Replace 'domain' in rule check with rule.domain !== undefined for proper narrowing - Make _matchConditionalBlockOrArray explicitly accept undefined (no-condition = always match) - Preserves existing runtime behavior while eliminating the any cast Co-authored-by: Jonathan Kingston <jonathanKingston@users.noreply.github.com>
- Add ElementHidingRuleWithSelector type alias for rules with .selector - Add hasSelector type guard to narrow ElementHidingRule to rules with selector - Use type predicate filter for overrideRules to properly narrow to ElementHidingRuleHide - Type injectStyleTag param as ElementHidingRuleWithSelector[] removing casts for .selector access - Type extractTimeoutRules arrays explicitly so injectStyleTag receives correct types - Use hasSelector guard in hideAdNodes and override comparison instead of inline casts - Replace ConditionalSettingEntry item.rules cast with typed intermediate variable Co-authored-by: Jonathan Kingston <jonathanKingston@users.noreply.github.com>
|
Cursor Agent can help with this pull request. Just |
[Beta] Generated file diffTime updated: Mon, 09 Mar 2026 22:43:39 GMT Android
File has changed Apple
File has changed Chrome-mv3File has changed FirefoxFile has changed IntegrationFile has changed WindowsFile has changed |
|
This PR requires a manual review and approval from a member of one of the following teams:
|
…andle undefined at call site Move the undefined-condition guard into matchConditionalFeatureSetting's filter callback instead of widening _matchConditionalBlockOrArray's parameter type. This keeps the internal method's contract strict and avoids codifying the 'no condition = always match' behavior as part of a shared API surface. Co-authored-by: Jonathan Kingston <jonathanKingston@users.noreply.github.com>
Build Branch
Static preview entry points
QR codes (mobile preview)
Integration commandsnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", branch: "pr-releases/jkt/auto/type-casting-improvements-3f3a")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/jkt/auto/type-casting-improvements-3f3a
git -C submodules/content-scope-scripts checkout origin/pr-releases/jkt/auto/type-casting-improvements-3f3aPin to exact commitnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", revision: "1875896e64a5d1865412f329b4673ff05c740a87")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/jkt/auto/type-casting-improvements-3f3a
git -C submodules/content-scope-scripts checkout 1875896e64a5d1865412f329b4673ff05c740a87 |
The variable-level @type annotation on domainEntries was still a cast. Replace with Array.isArray guard on item.rules before the narrowing cast to ElementHidingRule[]. The cast at the Record<string, unknown> boundary is unavoidable, but is now guarded by a runtime check. Co-authored-by: Jonathan Kingston <jonathanKingston@users.noreply.github.com>
Dismissing stale approval — new commits pushed, awaiting Cursor re-review.
Dismissing stale approval — new commits pushed, awaiting Cursor re-review.
Dismissing stale approval — new commits pushed, awaiting Cursor re-review.
There was a problem hiding this comment.
Web Compatibility Assessment
-
injected/src/config-feature.js
Range:L139-L143
Severity:warning
The newif (condition === undefined) return truepath changes runtime semantics for malformed conditional entries from "non-match/error" to "apply everywhere". InConfigFeature, this affects all features usingmatchConditionalFeatureSetting(), so an accidentally incomplete config entry indomains/conditionalChangescan now broaden scope globally and create cross-site breakage instead of failing closed. -
injected/src/features/element-hiding.js
Range:L399-L400
Severity:info
Array.isArray(item.rules)is a good compatibility guard: it prevents non-array config payloads from flowing into selector processing and avoids downstreamquerySelectorAll/rule-shape failures.
Security Assessment
injected/src/features/element-hiding.js
Range:L74-L80
Severity:warning
hasSelector()uses'selector' in rule, which walks the prototype chain. In a hostile page,Object.prototype.selectorpollution can make non-selector rules pass the guard and route inherited values/accessors into selector handling. Prefer an own-property check (hasOwnProperty.call(rule, 'selector')) using captured globals to avoid prototype-chain influence.
Risk Level
Medium Risk — mostly type-hardening, but one behavior change in core config matching (ConfigFeature) can alter rule application scope across many features if config entries are incomplete.
Recommendations
- Tighten
matchConditionalFeatureSetting()fail-closed behavior for malformed entries: treat missing bothconditionanddomainas non-match (or gate "always match" to an explicitly supported key/path). - Harden selector type guard to own-property checks with captured globals (
hasOwnProperty.call(...)) rather than'in'. - Add regression tests in config-feature unit tests for entries missing both
conditionanddomain, and in element-hiding tests for prototype-polluted objects to ensure guard behavior is stable.


Asana Task/Github Issue: N/A
Description
This PR improves type safety by eliminating unnecessary
anycasts and introducing better type narrowing inconfig-feature.jsandelement-hiding.js.Specifically:
config-feature.js: Removed ananycast inmatchConditionalFeatureSetting's filter callback, which led to fixing two type gaps:rule.domaincould beundefined(now explicitly checked).conditioncould beundefinedwhen passed to_matchConditionalBlockOrArray(parameter type widened to handle "no condition = always matches" semantic).element-hiding.js: IntroducedElementHidingRuleWithSelectortype and ahasSelectortype guard to remove 6 inline casts related to.selectoraccess ininjectStyleTag,hideAdNodes, andoverrideRules.These are type-only changes that preserve existing runtime behavior.
Testing Steps
npx tsc --noEmitnpm run tsc-strict-corenpm run lint-fixnpm run test-unit(all 104 specs pass)npx playwright test --grep "Element Hiding" --reporter list(integration test passes)npm run test-unit -- config-feature(93 specs pass)Checklist
Please tick all that apply:
Note
Low Risk
Primarily type-narrowing/refactor changes with minimal logic adjustment; the main behavioral impact is that config entries with no
condition/domainnow explicitly match all pages.Overview
Improves type safety in conditional config and element-hiding rule handling by removing
anycasts and introducing explicit type narrowing.ConfigFeature.matchConditionalFeatureSettingnow explicitly handles missingcondition/domain(treating no condition as an unconditional match) instead of relying on property-in checks.ElementHidingintroduces ahasSelectortype guard andElementHidingRuleWithSelectorto only read.selectorwhere valid, hardening style-tag injection and override filtering against rules likedisable-defaultand non-arraydomains[].rules.Written by Cursor Bugbot for commit 92ae0df. This will update automatically on new commits. Configure here.