Skip to content

fix(lint): noMisleadingReturnType false positive on union with exhausted boolean#10115

Merged
dyc3 merged 7 commits into
biomejs:mainfrom
minseong0324:fix/no-misleading-return-type-boolean-union
Apr 29, 2026
Merged

fix(lint): noMisleadingReturnType false positive on union with exhausted boolean#10115
dyc3 merged 7 commits into
biomejs:mainfrom
minseong0324:fix/no-misleading-return-type-boolean-union

Conversation

@minseong0324
Copy link
Copy Markdown
Contributor

@minseong0324 minseong0324 commented Apr 26, 2026

I used Claude Code to assist with this implementation.

Summary

Addresses items from #9810: noMisleadingReturnType no longer reports a false positive when a union return type's boolean variant is covered by both true and false returns.

The canonicalization happens in TypeData::union_of (true | false → boolean).
useExhaustiveSwitchCases now flags missing true/false cases on boolean discriminants, including when boolean is a union variant.

Test Plan

Snapshot tests.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 26, 2026

🦋 Changeset detected

Latest commit: b0f1701

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added A-Linter Area: linter L-JavaScript Language: JavaScript and super languages labels Apr 26, 2026
@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch from d5f2062 to d83b461 Compare April 26, 2026 03:33
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 26, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 196 skipped benchmarks1


Comparing minseong0324:fix/no-misleading-return-type-boolean-union (88059a0) with main (46a77d0)

Open in CodSpeed

Footnotes

  1. 196 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch from d83b461 to 6a96f2e Compare April 26, 2026 05:24
@github-actions github-actions Bot added the A-Type-Inference Area: type inference label Apr 26, 2026
@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch 7 times, most recently from c5bd9f4 to 5c601d6 Compare April 26, 2026 15:41
@github-actions github-actions Bot added the A-Project Area: project label Apr 26, 2026
@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch 7 times, most recently from baff7f5 to fe7d926 Compare April 26, 2026 22:19
@minseong0324 minseong0324 marked this pull request as ready for review April 27, 2026 00:25
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR adds boolean union canonicalisation across the type system and introduces a predefined boolean type ID (GLOBAL_BOOLEAN_ID). Union construction now collapses true | false into boolean and removes redundant boolean literal variants when boolean is present. The no_misleading_return_type lint relies on that normalisation and drops a dedicated early-exit check. The use_exhaustive_switch_cases lint records missing boolean coverage as explicit MissingCase::BooleanLiteral(true|false) and updates diagnostics and unsafe auto-fixes to emit case true/case false. Tests and Changesets were updated accordingly.

Possibly related PRs

  • #9999: Modifies the same no_misleading_return_type lint and its union-handling/is_wider_than logic.
  • #10006: Also changes no_misleading_return_type source, adjusting literal-widening checks overlapping union normalisation work.
  • #9873: Extends no_misleading_return_type and its type handling surface (methods/getters), touching the same lint implementation.

Suggested reviewers

  • dyc3
  • ematipico
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: addressing a false positive in noMisleadingReturnType when a boolean union is fully satisfied by true and false returns.
Description check ✅ Passed The description clearly relates to the changeset, explaining the false positive fix and referencing the related issue, though it could be slightly more detailed about scope.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
.changeset/calm-rivers-flow.md (1)

5-5: Reference the tracked issue in the bug-fix line.

Per the changeset guideline, bug-fix entries should start with Fixed [#NUMBER](issue link): ... when a GitHub issue exists. Issue #9810 is referenced by this PR, so let's link it.

📝 Suggested wording
-[`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) no longer reports false positives when a union return type's `boolean` variant is covered by both `true` and `false` returns.
+Fixed [`#9810`](https://github.com/biomejs/biome/issues/9810): [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) no longer reports false positives when a union return type's `boolean` variant is covered by both `true` and `false` returns.

As per coding guidelines: "For changeset descriptions of bug fixes, reference the issue with a link (e.g., 'Fixed #4444')".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/calm-rivers-flow.md at line 5, Update the changeset entry for the
bug fix so the description starts with the required "Fixed
[`#9810`](https://github.com/your-repo/issues/9810):" prefix; specifically edit
the .changeset/calm-rivers-flow.md line that mentions the noMisleadingReturnType
rule and replace the current sentence with one beginning "Fixed
[`#9810`](https://github.com/your-repo/issues/9810): noMisleadingReturnType no
longer reports false positives when a union return type's `boolean` variant is
covered by both `true` and `false` returns." Ensure the issue number and URL are
correct and keep the rest of the text unchanged.
crates/biome_js_analyze/src/lint/nursery/no_misleading_return_type.rs (1)

602-602: Tiny doc nit. The comment links [TypeData::union_of] — double-check the intra-doc link resolves (i.e. union_of is pub on TypeData), otherwise cargo doc will warn.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/no_misleading_return_type.rs` at
line 602, The doc comment references TypeData::union_of but may produce a broken
intra-doc link; verify that the method/associated function union_of on TypeData
is exported (pub) and that the path matches the actual symbol name, and if it is
not public either make union_of pub or update the comment to point to the
correct public item (or use plain text) so the intra-doc link resolves without
cargo doc warnings; check the TypeData type and the union_of item name to ensure
the link syntax [`TypeData::union_of`] is correct.
crates/biome_js_type_info/src/type.rs (1)

92-116: Same algorithm, second copy.

This mirrors normalize_boolean_union_variants in crates/biome_js_type_info/src/helpers.rs, just at the Type level instead of TypeReference. Functionally fine, but keeping the two implementations in lock-step is on us forever — worth a follow-up to extract the shared classification (has_boolean / has_true / has_false → action) so a future tweak only has to land in one place.

Also: the template dance is only needed to inherit a resolver for with_id. If you exposed something like Type::from_id(self.resolver.clone(), GLOBAL_BOOLEAN_ID) at this call site, you could skip the find(...).cloned() step entirely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/type.rs` around lines 92 - 116, Extract the
duplicated boolean-union classification logic (has_boolean / has_true /
has_false → action) from normalized_boolean_union_variants in Type (and the
existing normalize_boolean_union_variants in helpers.rs) into a shared helper
function used by both Type and TypeReference so future changes land in one
place; additionally add a constructor/associated fn on Type (e.g. Type::from_id
taking a resolver and GLOBAL_BOOLEAN_ID) so normalized_boolean_union_variants
can construct the boolean Type directly instead of doing the current template
find().cloned() + with_id dance, then update normalized_boolean_union_variants
to call the shared classifier and use Type::from_id(GLOBAL_BOOLEAN_ID) (or
equivalent) when injecting the boolean variant.
crates/biome_js_type_info/src/helpers.rs (1)

327-353: Logic is correct, a couple of small polish opportunities.

  • !(has_boolean || has_true && has_false) parses as !(has_boolean || (has_true && has_false)) thanks to && binding tighter than ||. Adding parens would save the next reader a trip to the precedence table.
  • Each any(...) re-calls resolver.resolve_and_get(ty) — a single pass classifying every variant once would do the same job with one resolution per entry.
  • This is conceptually the same algorithm as Type::normalized_boolean_union_variants in type.rs. Worth a TODO to share a single source of truth eventually.
♻️ Suggested clarity tweak
-    if !(has_boolean || has_true && has_false) {
+    if !(has_boolean || (has_true && has_false)) {
         return;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/helpers.rs` around lines 327 - 353, In
normalize_boolean_union_variants: add parentheses around the conditional check
to make the intent explicit (e.g. !(has_boolean || (has_true && has_false)));
then refactor the logic to do a single pass over variants calling
resolver.resolve_and_get once per entry to classify each variant into boolean
keyword / true literal / false literal (use is_boolean_keyword_reference and
is_boolean_literal_reference semantics) while building a new retained list
without boolean literals; after the pass, set has_boolean/has_true/has_false
from those flags, replace variants with the retained list, and if !has_boolean
but has_true && has_false push TypeReference::Resolved(GLOBAL_BOOLEAN_ID); add a
TODO note referencing Type::normalized_boolean_union_variants in type.rs for
future sharing of logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.changeset/calm-rivers-flow.md:
- Line 5: Update the changeset entry for the bug fix so the description starts
with the required "Fixed [`#9810`](https://github.com/your-repo/issues/9810):"
prefix; specifically edit the .changeset/calm-rivers-flow.md line that mentions
the noMisleadingReturnType rule and replace the current sentence with one
beginning "Fixed [`#9810`](https://github.com/your-repo/issues/9810):
noMisleadingReturnType no longer reports false positives when a union return
type's `boolean` variant is covered by both `true` and `false` returns." Ensure
the issue number and URL are correct and keep the rest of the text unchanged.

In `@crates/biome_js_analyze/src/lint/nursery/no_misleading_return_type.rs`:
- Line 602: The doc comment references TypeData::union_of but may produce a
broken intra-doc link; verify that the method/associated function union_of on
TypeData is exported (pub) and that the path matches the actual symbol name, and
if it is not public either make union_of pub or update the comment to point to
the correct public item (or use plain text) so the intra-doc link resolves
without cargo doc warnings; check the TypeData type and the union_of item name
to ensure the link syntax [`TypeData::union_of`] is correct.

In `@crates/biome_js_type_info/src/helpers.rs`:
- Around line 327-353: In normalize_boolean_union_variants: add parentheses
around the conditional check to make the intent explicit (e.g. !(has_boolean ||
(has_true && has_false))); then refactor the logic to do a single pass over
variants calling resolver.resolve_and_get once per entry to classify each
variant into boolean keyword / true literal / false literal (use
is_boolean_keyword_reference and is_boolean_literal_reference semantics) while
building a new retained list without boolean literals; after the pass, set
has_boolean/has_true/has_false from those flags, replace variants with the
retained list, and if !has_boolean but has_true && has_false push
TypeReference::Resolved(GLOBAL_BOOLEAN_ID); add a TODO note referencing
Type::normalized_boolean_union_variants in type.rs for future sharing of logic.

In `@crates/biome_js_type_info/src/type.rs`:
- Around line 92-116: Extract the duplicated boolean-union classification logic
(has_boolean / has_true / has_false → action) from
normalized_boolean_union_variants in Type (and the existing
normalize_boolean_union_variants in helpers.rs) into a shared helper function
used by both Type and TypeReference so future changes land in one place;
additionally add a constructor/associated fn on Type (e.g. Type::from_id taking
a resolver and GLOBAL_BOOLEAN_ID) so normalized_boolean_union_variants can
construct the boolean Type directly instead of doing the current template
find().cloned() + with_id dance, then update normalized_boolean_union_variants
to call the shared classifier and use Type::from_id(GLOBAL_BOOLEAN_ID) (or
equivalent) when injecting the boolean variant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 080d561a-1fce-416d-a908-1897f4519c08

📥 Commits

Reviewing files that changed from the base of the PR and between f3e76ab and fe7d926.

⛔ Files ignored due to path filters (9)
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_type_info/tests/snapshots/infer_type_of_function_with_destructured_arguments.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_export_type_referencing_imported_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_exports.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_imported_promise_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_reexported_promise_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_type_of_property_with_getter.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (12)
  • .changeset/calm-rivers-flow.md
  • crates/biome_js_analyze/src/lint/nursery/no_misleading_return_type.rs
  • crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/invalid.ts
  • crates/biome_js_type_info/src/globals.rs
  • crates/biome_js_type_info/src/globals_ids.rs
  • crates/biome_js_type_info/src/helpers.rs
  • crates/biome_js_type_info/src/lib.rs
  • crates/biome_js_type_info/src/type.rs
  • crates/biome_js_type_info/tests/flattening.rs

@minseong0324 minseong0324 marked this pull request as draft April 27, 2026 00:32
@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch 3 times, most recently from 04a3452 to 36da022 Compare April 27, 2026 01:17
@minseong0324 minseong0324 marked this pull request as ready for review April 27, 2026 01:41
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
crates/biome_js_type_info/src/helpers.rs (2)

327-378: Note the parallel implementation in type.rs.

Type::normalized_boolean_union_variants (in crates/biome_js_type_info/src/type.rs) implements the exact same canonicalisation rule on a Vec<Type> instead of Vec<TypeReference>. Two sources of truth for the same invariant is a minor maintenance hazard — if one is later tweaked (e.g. to also collapse boolean | true | false differently), the other will silently drift. Worth a short doc comment cross-referencing them so future maintainers know to keep them in sync, or extracting the shared "(has_boolean, has_true, has_false) → action" decision into a tiny helper. Not a blocker.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/helpers.rs` around lines 327 - 378, The
boolean-union canonicalization in normalize_boolean_union_variants duplicates
the logic in Type::normalized_boolean_union_variants; either add a short doc
comment on normalize_boolean_union_variants that cross-references
Type::normalized_boolean_union_variants (and vice‑versa) so maintainers know
they must stay in sync, or refactor the shared decision logic (the
has_boolean/has_true/has_false detection and resulting action) into a tiny
shared helper used by both normalize_boolean_union_variants and
Type::normalized_boolean_union_variants to avoid two sources of truth.

330-356: Optional: collapse the three scans into one.

has_boolean, has_true, and has_false each iterate variants and resolve every reference independently — three resolver lookups per element before we even get to retain. A single pass would be cheaper and arguably clearer. Logic-wise the current code is correct (operator precedence in the early-return condition is fine).

♻️ Suggested single-pass variant
-    let has_boolean = variants
-        .iter()
-        .any(|ty| is_boolean_keyword_reference(resolver, ty));
-    let has_true = variants
-        .iter()
-        .any(|ty| is_boolean_literal_reference(resolver, ty, true));
-    let has_false = variants
-        .iter()
-        .any(|ty| is_boolean_literal_reference(resolver, ty, false));
+    let (mut has_boolean, mut has_true, mut has_false) = (false, false, false);
+    for ty in variants.iter() {
+        match resolver.resolve_and_get(ty).as_ref().map(|r| r.as_raw_data()) {
+            Some(TypeData::Boolean) => has_boolean = true,
+            Some(TypeData::Literal(lit)) => match lit.as_ref() {
+                Literal::Boolean(b) if b.as_bool() => has_true = true,
+                Literal::Boolean(_) => has_false = true,
+                _ => {}
+            },
+            _ => {}
+        }
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/helpers.rs` around lines 330 - 356, The three
separate scans in normalize_boolean_union_variants are inefficient; replace them
with a single pass over variants that checks each TypeReference once using
is_boolean_keyword_reference and is_boolean_literal_reference to set
has_boolean, has_true, and has_false flags (and optionally mark which indexes
are literal true/false). After the single pass, use the same early-return logic
(if !(has_boolean || (has_true && has_false)) return), then remove boolean
literal references (e.g., via variants.retain or by constructing a filtered Vec)
and, if has_boolean is false, push TypeReference::Resolved(GLOBAL_BOOLEAN_ID);
keep the function name and calls to is_boolean_keyword_reference,
is_boolean_literal_reference, and GLOBAL_BOOLEAN_ID unchanged.
crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts (1)

161-174: Solid valid-case set; one nit on placement.

The five new cases — including duplicateBooleanReturns to verify dedup before canonicalisation — give good coverage. Minor nit: they're inserted between storeObj (line 159) and StaticStore (line 175), which splits the "getter + setter" cluster. Consider moving the boolean-union block to the end of the file (after StaticStore) so related groups stay contiguous. Non-blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts`
around lines 161 - 174, The added boolean-union test cases (useCloudLogin,
booleanOrUndefined, booleanOrLiteral, nullOrBoolean, duplicateBooleanReturns)
are placed between the related "getter + setter" cluster (storeObj and
StaticStore); move this entire block of five functions so it appears after the
StaticStore block (i.e., append the boolean-union block to the end of the file
after the StaticStore declaration) to keep related test groups contiguous.
crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs (1)

254-275: Tiny nit: rename the loop binding.

for ty in &state.missing_cases reads a bit oddly now that the element type is MissingCase, not Type. Renaming to case (matching the helper parameter names below) keeps things consistent.

♻️ Suggested rename
-        for ty in &state.missing_cases {
+        for case in &state.missing_cases {
@@
-                missing_case_to_expression(ty)?,
+                missing_case_to_expression(case)?,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 254 - 275, Rename the loop binding `ty` in the `for ty in
&state.missing_cases` loop to `case` (or `missing_case`) to reflect the element
type `MissingCase` and match the helper names like `missing_case_to_expression`;
update the loop header and all uses of `ty` inside the loop (where you call
`missing_case_to_expression(ty)?`, build the `case_token`, construct the
`AnyJsSwitchClause::JsCaseClause` via `make::js_case_clause`, and when pushing
to `clauses`) so names are consistent and clearer.
crates/biome_js_type_info/src/type.rs (1)

87-116: Mirrors helpers.rs::normalize_boolean_union_variants — cross-link them.

This Type-level helper duplicates the canonicalisation already performed inside TypeData::union_of (via helpers.rs::normalize_boolean_union_variants). The two will run on different inputs (already-resolved Type values vs raw TypeReferences during union construction), so consolidating fully is awkward, but at minimum a doc-comment cross-reference would help future maintainers keep the rules in sync.

Also: the template dance is fine, but since you've established that has_true && has_false holds in the !has_boolean branch, the find is guaranteed to return Some. A tiny readability win is to express that without the Option<Option<_>> flatten:

♻️ Slightly tidier template extraction
-        let template = (!has_boolean)
-            .then(|| {
-                types
-                    .iter()
-                    .find(|ty| ty.is_boolean_literal(true) || ty.is_boolean_literal(false))
-                    .cloned()
-            })
-            .flatten();
+        let template = (!has_boolean).then(|| {
+            types
+                .iter()
+                .find(|ty| ty.is_boolean_literal(true) || ty.is_boolean_literal(false))
+                .cloned()
+                .expect("has_true && has_false implies a literal variant exists")
+        });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/type.rs` around lines 87 - 116, Add a
doc-comment cross-reference in Type::normalized_boolean_union_variants pointing
to helpers.rs::normalize_boolean_union_variants so maintainers know these two
routines implement the same canonicalization rules, and simplify the template
extraction: replace the current Option<Option> flatten pattern by directly
finding and cloning the boolean literal (use find(...).cloned().expect(...) or
equivalent) inside the (!has_boolean) branch because has_true && has_false
guarantees a match; keep the subsequent retain(...) and
push(template.with_id(...)) behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`:
- Around line 254-275: Rename the loop binding `ty` in the `for ty in
&state.missing_cases` loop to `case` (or `missing_case`) to reflect the element
type `MissingCase` and match the helper names like `missing_case_to_expression`;
update the loop header and all uses of `ty` inside the loop (where you call
`missing_case_to_expression(ty)?`, build the `case_token`, construct the
`AnyJsSwitchClause::JsCaseClause` via `make::js_case_clause`, and when pushing
to `clauses`) so names are consistent and clearer.

In `@crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts`:
- Around line 161-174: The added boolean-union test cases (useCloudLogin,
booleanOrUndefined, booleanOrLiteral, nullOrBoolean, duplicateBooleanReturns)
are placed between the related "getter + setter" cluster (storeObj and
StaticStore); move this entire block of five functions so it appears after the
StaticStore block (i.e., append the boolean-union block to the end of the file
after the StaticStore declaration) to keep related test groups contiguous.

In `@crates/biome_js_type_info/src/helpers.rs`:
- Around line 327-378: The boolean-union canonicalization in
normalize_boolean_union_variants duplicates the logic in
Type::normalized_boolean_union_variants; either add a short doc comment on
normalize_boolean_union_variants that cross-references
Type::normalized_boolean_union_variants (and vice‑versa) so maintainers know
they must stay in sync, or refactor the shared decision logic (the
has_boolean/has_true/has_false detection and resulting action) into a tiny
shared helper used by both normalize_boolean_union_variants and
Type::normalized_boolean_union_variants to avoid two sources of truth.
- Around line 330-356: The three separate scans in
normalize_boolean_union_variants are inefficient; replace them with a single
pass over variants that checks each TypeReference once using
is_boolean_keyword_reference and is_boolean_literal_reference to set
has_boolean, has_true, and has_false flags (and optionally mark which indexes
are literal true/false). After the single pass, use the same early-return logic
(if !(has_boolean || (has_true && has_false)) return), then remove boolean
literal references (e.g., via variants.retain or by constructing a filtered Vec)
and, if has_boolean is false, push TypeReference::Resolved(GLOBAL_BOOLEAN_ID);
keep the function name and calls to is_boolean_keyword_reference,
is_boolean_literal_reference, and GLOBAL_BOOLEAN_ID unchanged.

In `@crates/biome_js_type_info/src/type.rs`:
- Around line 87-116: Add a doc-comment cross-reference in
Type::normalized_boolean_union_variants pointing to
helpers.rs::normalize_boolean_union_variants so maintainers know these two
routines implement the same canonicalization rules, and simplify the template
extraction: replace the current Option<Option> flatten pattern by directly
finding and cloning the boolean literal (use find(...).cloned().expect(...) or
equivalent) inside the (!has_boolean) branch because has_true && has_false
guarantees a match; keep the subsequent retain(...) and
push(template.with_id(...)) behavior intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fd14ef3d-01db-4bfa-a3f6-3c282cd6f91a

📥 Commits

Reviewing files that changed from the base of the PR and between fe7d926 and 36da022.

⛔ Files ignored due to path filters (9)
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_type_info/tests/snapshots/infer_type_of_function_with_destructured_arguments.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_export_type_referencing_imported_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_exports.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_imported_promise_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_reexported_promise_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_type_of_property_with_getter.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (12)
  • .changeset/calm-rivers-flow.md
  • crates/biome_js_analyze/src/lint/nursery/no_misleading_return_type.rs
  • crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/invalid.ts
  • crates/biome_js_type_info/src/globals.rs
  • crates/biome_js_type_info/src/globals_ids.rs
  • crates/biome_js_type_info/src/helpers.rs
  • crates/biome_js_type_info/src/lib.rs
  • crates/biome_js_type_info/src/type.rs
  • crates/biome_js_type_info/tests/flattening.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/biome_js_type_info/src/lib.rs
  • .changeset/calm-rivers-flow.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/biome_js_type_info/src/globals.rs
  • crates/biome_js_type_info/src/globals_ids.rs
  • crates/biome_js_analyze/src/lint/nursery/no_misleading_return_type.rs
  • crates/biome_js_type_info/tests/flattening.rs

@minseong0324 minseong0324 marked this pull request as draft April 27, 2026 01:56
@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch from 36da022 to 8b3b56d Compare April 27, 2026 03:46
@minseong0324 minseong0324 marked this pull request as ready for review April 27, 2026 03:49
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
crates/biome_js_type_info/src/type.rs (2)

73-85: with_id: nice helper, soft contract worth flagging.

The debug_assert! is great for tests but in release builds an unknown id silently degrades to UNKNOWN_DATA via Deref. Today the only caller passes GLOBAL_BOOLEAN_ID, which any sane resolver in this codebase resolves, so this is fine. If with_id ever becomes public-facing for arbitrary ids, consider returning Option<Self> instead.

Also, the doc comment mentions only "predefined global ID" — works for now, but future callers may want a clearer rule.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/type.rs` around lines 73 - 85, The current
Type::with_id uses a debug_assert! to check resolver can resolve the provided
ResolvedTypeId, which is silent in release builds and can lead to UNKNOWN_DATA;
change the API to return Option<Self> (or Result<Self, ...>) instead of Self so
callers must handle unknown ids—update the function signature of with_id to
return Option<Type>, perform a runtime check using
self.resolver.get_by_resolved_id(id).is_some() and return Some(Self { resolver:
self.resolver.clone(), id }) or None; update callers (e.g., where
GLOBAL_BOOLEAN_ID is used) to unwrap or handle the Option and amend the doc
comment to state the contract clearly (that callers must supply a resolver-known
ResolvedTypeId or handle None).

94-129: Logic checks out across the four interesting shapes.

Walked through true|false, boolean|true, boolean|true|false, and boolean alone — all collapse correctly, and the seen_boolean retain dedupes aliased Boolean references to one. 👍

Minor:

  • Same readability tweak as helpers.rs: !(has_boolean || (has_true && has_false)) parses faster.
  • crate::globals_ids::GLOBAL_BOOLEAN_ID could just be added to the existing use crate::globals::{ ... } block (it's re-exported there) to avoid the inline path:
 use crate::globals::{
-    GLOBAL_ARRAY_ID, GLOBAL_ASYNC_DISPOSABLE_ID, GLOBAL_DISPOSABLE_ID, GLOBAL_NUMBER_ID,
+    GLOBAL_ARRAY_ID, GLOBAL_ASYNC_DISPOSABLE_ID, GLOBAL_BOOLEAN_ID, GLOBAL_DISPOSABLE_ID, GLOBAL_NUMBER_ID,
     GLOBAL_PROMISE_ID, GLOBAL_STRING_ID, GLOBAL_SYMBOL_ASYNC_DISPOSE_ID,
     GLOBAL_SYMBOL_DISPOSE_ID, GLOBAL_UNKNOWN_ID,
 },
-            types.push(template.with_id(crate::globals_ids::GLOBAL_BOOLEAN_ID));
+            types.push(template.with_id(GLOBAL_BOOLEAN_ID));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/type.rs` around lines 94 - 129, The function
normalized_boolean_union_variants is fine but please apply two small readability
tweaks: (1) change the conditional !(has_boolean || has_true && has_false) to
the clearer form !(has_boolean || (has_true && has_false)) around the
early-return so the precedence is explicit, and (2) replace the inline path
crate::globals_ids::GLOBAL_BOOLEAN_ID by importing GLOBAL_BOOLEAN_ID from the
crate::globals re-export (add GLOBAL_BOOLEAN_ID to the existing use
crate::globals::{ ... } block) and then use GLOBAL_BOOLEAN_ID in the types.push
call.
crates/biome_js_type_info/src/helpers.rs (2)

327-378: Heads-up: this duplicates Type::normalized_boolean_union_variants in type.rs.

Same algorithm, different value type (TypeReference vs Type). Not a blocker — they operate at different layers — but if it ever drifts, the lints will silently diverge from union_of. Worth a small shared primitive (e.g. a generic helper taking is_boolean/is_literal/make_boolean closures) at some point.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/helpers.rs` around lines 327 - 378, The logic
in normalize_boolean_union_variants (helpers.rs) duplicates
Type::normalized_boolean_union_variants (type.rs); extract the shared algorithm
into a single generic helper that both layers call by parameterizing the
type-specific checks/constructors via closures (e.g., take is_boolean_predicate,
is_literal_predicate, and make_boolean_constructor closures) and then replace
normalize_boolean_union_variants and Type::normalized_boolean_union_variants to
invoke that helper; reference the existing helpers is_boolean_literal_reference
and is_boolean_keyword_reference as the predicates to wire into the new generic
function so both implementations reuse the same canonicalization logic.

327-378: Logic is correct; readability nit on the early-return condition.

The four-case truth table checks out (boolean alone, true|false, boolean|true, neither). Two small suggestions:

  1. !(has_boolean || has_true && has_false) relies on && binding tighter than ||. It's correct but a quick parenthesis makes it scan instantly:
-    if !(has_boolean || has_true && has_false) {
+    if !(has_boolean || (has_true && has_false)) {
         return;
     }
  1. Three full passes of iter().any(...) over variants before the retain could fold into one loop. Not a hot path today, so feel free to defer.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_type_info/src/helpers.rs` around lines 327 - 378, In
normalize_boolean_union_variants the early-return condition is correct but
ambiguous; change the if condition to use explicit parentheses (e.g., if
!(has_boolean || (has_true && has_false)) ) for clarity. Optionally, to avoid
three separate iter().any passes, replace the three .any calls with a single
loop over variants that sets has_boolean, has_true and has_false flags (still
using is_boolean_keyword_reference and is_boolean_literal_reference) before the
early return and retain logic.
crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs (1)

158-163: Nit: match on a bool reads a bit awkwardly.

A plain if/else is more idiomatic here (and Clippy tends to grumble about match true => … false => …). Same applies to lines 330–333 and the inner pattern at 343–346, if you want to harmonise them.

♻️ Suggested tweak
-        let variants = match discriminant_ty.is_union() {
-            true => Type::normalized_boolean_union_variants(
-                discriminant_ty.flattened_union_variants().collect(),
-            ),
-            false => vec![discriminant_ty],
-        };
+        let variants = if discriminant_ty.is_union() {
+            Type::normalized_boolean_union_variants(
+                discriminant_ty.flattened_union_variants().collect(),
+            )
+        } else {
+            vec![discriminant_ty]
+        };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 158 - 163, The current code uses match on a boolean to set variants
(matching discriminant_ty.is_union()), which is awkward; replace the match
expression that assigns variants with an idiomatic if/else using
discriminant_ty.is_union() to choose between
Type::normalized_boolean_union_variants(...) and vec![discriminant_ty]; apply
the same refactor to the other occurrences mentioned (the block using
discriminant_ty.is_union() at the locations corresponding to lines ~330–333 and
the inner pattern around ~343–346) so all boolean matches become simple if/else
branches referencing the same expressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`:
- Around line 158-163: The current code uses match on a boolean to set variants
(matching discriminant_ty.is_union()), which is awkward; replace the match
expression that assigns variants with an idiomatic if/else using
discriminant_ty.is_union() to choose between
Type::normalized_boolean_union_variants(...) and vec![discriminant_ty]; apply
the same refactor to the other occurrences mentioned (the block using
discriminant_ty.is_union() at the locations corresponding to lines ~330–333 and
the inner pattern around ~343–346) so all boolean matches become simple if/else
branches referencing the same expressions.

In `@crates/biome_js_type_info/src/helpers.rs`:
- Around line 327-378: The logic in normalize_boolean_union_variants
(helpers.rs) duplicates Type::normalized_boolean_union_variants (type.rs);
extract the shared algorithm into a single generic helper that both layers call
by parameterizing the type-specific checks/constructors via closures (e.g., take
is_boolean_predicate, is_literal_predicate, and make_boolean_constructor
closures) and then replace normalize_boolean_union_variants and
Type::normalized_boolean_union_variants to invoke that helper; reference the
existing helpers is_boolean_literal_reference and is_boolean_keyword_reference
as the predicates to wire into the new generic function so both implementations
reuse the same canonicalization logic.
- Around line 327-378: In normalize_boolean_union_variants the early-return
condition is correct but ambiguous; change the if condition to use explicit
parentheses (e.g., if !(has_boolean || (has_true && has_false)) ) for clarity.
Optionally, to avoid three separate iter().any passes, replace the three .any
calls with a single loop over variants that sets has_boolean, has_true and
has_false flags (still using is_boolean_keyword_reference and
is_boolean_literal_reference) before the early return and retain logic.

In `@crates/biome_js_type_info/src/type.rs`:
- Around line 73-85: The current Type::with_id uses a debug_assert! to check
resolver can resolve the provided ResolvedTypeId, which is silent in release
builds and can lead to UNKNOWN_DATA; change the API to return Option<Self> (or
Result<Self, ...>) instead of Self so callers must handle unknown ids—update the
function signature of with_id to return Option<Type>, perform a runtime check
using self.resolver.get_by_resolved_id(id).is_some() and return Some(Self {
resolver: self.resolver.clone(), id }) or None; update callers (e.g., where
GLOBAL_BOOLEAN_ID is used) to unwrap or handle the Option and amend the doc
comment to state the contract clearly (that callers must supply a resolver-known
ResolvedTypeId or handle None).
- Around line 94-129: The function normalized_boolean_union_variants is fine but
please apply two small readability tweaks: (1) change the conditional
!(has_boolean || has_true && has_false) to the clearer form !(has_boolean ||
(has_true && has_false)) around the early-return so the precedence is explicit,
and (2) replace the inline path crate::globals_ids::GLOBAL_BOOLEAN_ID by
importing GLOBAL_BOOLEAN_ID from the crate::globals re-export (add
GLOBAL_BOOLEAN_ID to the existing use crate::globals::{ ... } block) and then
use GLOBAL_BOOLEAN_ID in the types.push call.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f50c83b5-0fac-468f-a0ba-dc439e8283ea

📥 Commits

Reviewing files that changed from the base of the PR and between 36da022 and 8b3b56d.

⛔ Files ignored due to path filters (9)
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/invalid.ts.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_type_info/tests/snapshots/infer_type_of_function_with_destructured_arguments.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_export_type_referencing_imported_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_exports.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_imported_promise_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_reexported_promise_type.snap is excluded by !**/*.snap and included by **
  • crates/biome_module_graph/tests/snapshots/test_resolve_type_of_property_with_getter.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (12)
  • .changeset/calm-rivers-flow.md
  • crates/biome_js_analyze/src/lint/nursery/no_misleading_return_type.rs
  • crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/valid.ts
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/invalid.ts
  • crates/biome_js_type_info/src/globals.rs
  • crates/biome_js_type_info/src/globals_ids.rs
  • crates/biome_js_type_info/src/helpers.rs
  • crates/biome_js_type_info/src/lib.rs
  • crates/biome_js_type_info/src/type.rs
  • crates/biome_js_type_info/tests/flattening.rs
✅ Files skipped from review due to trivial changes (1)
  • .changeset/calm-rivers-flow.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_js_type_info/src/lib.rs
  • crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts

Comment thread .changeset/calm-rivers-flow.md Outdated
Comment thread crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs Outdated
Comment thread crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs (3)

160-165: Tiny nit: match on a bool reads as if/else.

match discriminant_ty.is_union() { true => ..., false => ... } is the pattern clippy::match_bool lints against. An if/else is a touch friendlier here, but feel free to ignore.

♻️ Optional cleanup
-        let variants = match discriminant_ty.is_union() {
-            true => Type::normalized_boolean_union_variants(
-                discriminant_ty.flattened_union_variants().collect(),
-            ),
-            false => vec![discriminant_ty],
-        };
+        let variants = if discriminant_ty.is_union() {
+            Type::normalized_boolean_union_variants(
+                discriminant_ty.flattened_union_variants().collect(),
+            )
+        } else {
+            vec![discriminant_ty]
+        };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 160 - 165, The match on a boolean here is clearer as an if/else:
replace the match on discriminant_ty.is_union() that sets variants with an if
discriminant_ty.is_union() { /* call Type::normalized_boolean_union_variants
with discriminant_ty.flattened_union_variants().collect() */ } else {
vec![discriminant_ty] }; keep the same calls to
Type::normalized_boolean_union_variants and
discriminant_ty.flattened_union_variants() so only the control structure for
computing variants (the variable named variants) is changed from match to an
if/else.

260-281: Variable name nit: ty no longer holds a Type.

Now that state: &Vec<MissingCase>, calling the loop variable ty is a small leftover from the old shape. Renaming to case (or missing) matches the new type and the surrounding missing_case_to_expression call.

-        for ty in state {
+        for case in state {
             ...
-                missing_case_to_expression(ty)?,
+                missing_case_to_expression(case)?,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 260 - 281, Loop variable `ty` no longer represents a Type; rename
it to something like `case` or `missing` in the for loop that iterates over
`state: &Vec<MissingCase>` and update all usages inside that loop (including the
call to `missing_case_to_expression(ty)?` and any references when building
`case_token` and `clause`) to the new name so the identifier matches the
`MissingCase` semantics.

307-312: Simplify using is_some_and.

The .and_then(|literal| Some(literal.value_token().ok()?.kind() == T![true])) is harder to read than necessary — you're opening a Some(...) just to use ? inside it. Since the project targets Rust 1.94.1, is_some_and (stable since 1.70.0) makes this much cleaner:

♻️ Suggested refactor
 fn is_true_literal_expression(expr: &AnyJsExpression) -> bool {
     expr.as_any_js_literal_expression()
         .and_then(|literal| literal.as_js_boolean_literal_expression())
-        .and_then(|literal| Some(literal.value_token().ok()?.kind() == T![true]))
-        .unwrap_or_default()
+        .and_then(|literal| literal.value_token().ok())
+        .is_some_and(|token| token.kind() == T![true])
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 307 - 312, The helper is_true_literal_expression has an unnecessary
and_then wrapping a Some(...) to use `?`; replace the third combinator with
`is_some_and` to directly test the boolean literal token kind. Specifically, in
is_true_literal_expression change the chain that calls
as_js_boolean_literal_expression() and then the and_then(|literal|
Some(literal.value_token().ok()?.kind() == T![true])) to use
is_some_and(|literal| literal.value_token().ok().map(|t| t.kind() ==
T![true]).unwrap_or(false)) or preferably is_some_and(|literal|
literal.value_token().ok().map(|t| t.kind() == T![true]).unwrap_or_default()) so
the result is a simple boolean without creating an inner Some.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`:
- Around line 160-165: The match on a boolean here is clearer as an if/else:
replace the match on discriminant_ty.is_union() that sets variants with an if
discriminant_ty.is_union() { /* call Type::normalized_boolean_union_variants
with discriminant_ty.flattened_union_variants().collect() */ } else {
vec![discriminant_ty] }; keep the same calls to
Type::normalized_boolean_union_variants and
discriminant_ty.flattened_union_variants() so only the control structure for
computing variants (the variable named variants) is changed from match to an
if/else.
- Around line 260-281: Loop variable `ty` no longer represents a Type; rename it
to something like `case` or `missing` in the for loop that iterates over `state:
&Vec<MissingCase>` and update all usages inside that loop (including the call to
`missing_case_to_expression(ty)?` and any references when building `case_token`
and `clause`) to the new name so the identifier matches the `MissingCase`
semantics.
- Around line 307-312: The helper is_true_literal_expression has an unnecessary
and_then wrapping a Some(...) to use `?`; replace the third combinator with
`is_some_and` to directly test the boolean literal token kind. Specifically, in
is_true_literal_expression change the chain that calls
as_js_boolean_literal_expression() and then the and_then(|literal|
Some(literal.value_token().ok()?.kind() == T![true])) to use
is_some_and(|literal| literal.value_token().ok().map(|t| t.kind() ==
T![true]).unwrap_or(false)) or preferably is_some_and(|literal|
literal.value_token().ok().map(|t| t.kind() == T![true]).unwrap_or_default()) so
the result is a simple boolean without creating an inner Some.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 16d6f501-fd1c-441d-a10f-c8c1f193917e

📥 Commits

Reviewing files that changed from the base of the PR and between 8b3b56d and 34ea360.

⛔ Files ignored due to path filters (1)
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/valid.ts.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (4)
  • .changeset/eleven-impalas-smell.md
  • .changeset/light-wasps-jog.md
  • crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/valid.ts
✅ Files skipped from review due to trivial changes (2)
  • .changeset/eleven-impalas-smell.md
  • .changeset/light-wasps-jog.md

@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch from 34ea360 to 08bdb2c Compare April 27, 2026 16:12
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs (4)

107-110: Consider moving MissingCase below the impl Rule block.

Per project convention, helper structs/enums belong below the rule's impl block. The documented exception is for node unions used in the rule's Query type, but MissingCase is the State type, so it doesn't qualify.

Based on learnings from PR 8960: "all helper functions, structs, and enums must be placed below the impl Rule block. The only exception is when declaring a node union to use in the rule's Query type".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 107 - 110, The enum MissingCase (used as the rule's State) should
be moved below the impl Rule block to follow project convention for helper
types; locate the MissingCase declaration and cut/paste it so it appears after
the impl Rule { ... } implementation (not before), ensuring any references to
MissingCase in the rule's State/Query remain unchanged and compile.

159-164: Prefer if/else over match on a bool.

Slightly more idiomatic and saves a level of indentation:

♻️ Suggested tweak
-        let variants = match discriminant_ty.is_union() {
-            true => Type::normalized_boolean_union_variants(
-                discriminant_ty.flattened_union_variants().collect(),
-            ),
-            false => vec![discriminant_ty],
-        };
+        let variants = if discriminant_ty.is_union() {
+            Type::normalized_boolean_union_variants(
+                discriminant_ty.flattened_union_variants().collect(),
+            )
+        } else {
+            vec![discriminant_ty]
+        };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 159 - 164, Replace the match on the boolean returned by
discriminant_ty.is_union() with an if/else for clarity and to remove an
unnecessary match; specifically, in the block that defines variants (currently
using match discriminant_ty.is_union()), use if discriminant_ty.is_union() {
Type::normalized_boolean_union_variants(discriminant_ty.flattened_union_variants().collect())
} else { vec![discriminant_ty] } so the logic around discriminant_ty,
normalized_boolean_union_variants, and flattened_union_variants remains the same
but uses an idiomatic if/else.

259-280: Rename loop binding tycase (or missing).

state is now Vec<MissingCase>, so ty is a touch misleading at the action site. Cosmetic only.

♻️ Suggested tweak
-        for ty in state {
+        for case in state {
@@
-                missing_case_to_expression(ty)?,
+                missing_case_to_expression(case)?,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 259 - 280, The loop variable name `ty` is misleading because
`state` is a Vec<MissingCase>; rename the binding to `case` (or `missing`) in
the for loop and update all uses inside the block — e.g., change `for ty in
state {` to `for case in state {` and replace `missing_case_to_expression(ty)?`
with `missing_case_to_expression(case)?` (also update any other occurrences of
`ty` inside this block such as in the `clause` construction that references
`throw_stmt`/`clauses`), keeping the same logic and types.

166-188: Stale variable name: intersection_part is now a union variant.

Since the loop iterates over union variants (post normalized_boolean_union_variants), variant would read more truthfully than intersection_part. Purely cosmetic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`
around lines 166 - 188, The loop variable name intersection_part is misleading
now that it iterates union variants; rename the loop variable to variant and
update all uses accordingly (e.g., change for intersection_part in variants to
for variant in variants, then call flatten_type(&variant) and update subsequent
checks and contains calls to use the new name or a clearly named flattened
variable such as flat_variant), ensuring references to has_boolean_case,
missing_cases.push(MissingCase::BooleanLiteral(...)), found_cases.contains(...),
and missing_cases.push(MissingCase::Type(...)) use the updated identifier names
so the code remains correct and readable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs`:
- Around line 107-110: The enum MissingCase (used as the rule's State) should be
moved below the impl Rule block to follow project convention for helper types;
locate the MissingCase declaration and cut/paste it so it appears after the impl
Rule { ... } implementation (not before), ensuring any references to MissingCase
in the rule's State/Query remain unchanged and compile.
- Around line 159-164: Replace the match on the boolean returned by
discriminant_ty.is_union() with an if/else for clarity and to remove an
unnecessary match; specifically, in the block that defines variants (currently
using match discriminant_ty.is_union()), use if discriminant_ty.is_union() {
Type::normalized_boolean_union_variants(discriminant_ty.flattened_union_variants().collect())
} else { vec![discriminant_ty] } so the logic around discriminant_ty,
normalized_boolean_union_variants, and flattened_union_variants remains the same
but uses an idiomatic if/else.
- Around line 259-280: The loop variable name `ty` is misleading because `state`
is a Vec<MissingCase>; rename the binding to `case` (or `missing`) in the for
loop and update all uses inside the block — e.g., change `for ty in state {` to
`for case in state {` and replace `missing_case_to_expression(ty)?` with
`missing_case_to_expression(case)?` (also update any other occurrences of `ty`
inside this block such as in the `clause` construction that references
`throw_stmt`/`clauses`), keeping the same logic and types.
- Around line 166-188: The loop variable name intersection_part is misleading
now that it iterates union variants; rename the loop variable to variant and
update all uses accordingly (e.g., change for intersection_part in variants to
for variant in variants, then call flatten_type(&variant) and update subsequent
checks and contains calls to use the new name or a clearly named flattened
variable such as flat_variant), ensuring references to has_boolean_case,
missing_cases.push(MissingCase::BooleanLiteral(...)), found_cases.contains(...),
and missing_cases.push(MissingCase::Type(...)) use the updated identifier names
so the code remains correct and readable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 27481a2e-92b3-4206-9361-79dcca8edce8

📥 Commits

Reviewing files that changed from the base of the PR and between 34ea360 and 08bdb2c.

⛔ Files ignored due to path filters (1)
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/valid.ts.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (2)
  • crates/biome_js_analyze/src/lint/nursery/use_exhaustive_switch_cases.rs
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/valid.ts
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_js_analyze/tests/specs/nursery/useExhaustiveSwitchCases/valid.ts

@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch 2 times, most recently from cf2b724 to 17878b6 Compare April 27, 2026 17:04
@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch from 17878b6 to c37bd08 Compare April 27, 2026 17:07
@minseong0324 minseong0324 force-pushed the fix/no-misleading-return-type-boolean-union branch from c37bd08 to b0f1701 Compare April 27, 2026 17:13
@minseong0324 minseong0324 requested a review from dyc3 April 27, 2026 17:17
…eturn-type-boolean-union

# Conflicts:
#	crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts
#	crates/biome_js_analyze/tests/specs/nursery/noMisleadingReturnType/invalid.ts.snap
#	crates/biome_js_type_info/src/globals.rs
#	crates/biome_js_type_info/src/globals_ids.rs
@dyc3 dyc3 merged commit d428d76 into biomejs:main Apr 29, 2026
30 checks passed
@github-actions github-actions Bot mentioned this pull request Apr 28, 2026
minseong0324 added a commit to minseong0324/biome that referenced this pull request Apr 29, 2026
Resolved conflicts in noMisleadingReturnType/invalid.ts and its snapshot.
Kept this branch's union-bailout test cases and added upstream's
partialBooleanUnion/ternaryBoolean cases from biomejs#10115. Snapshot regenerated
via INSTA_UPDATE=always; all flagged cases preserved.
OIRNOIR pushed a commit to OIRNOIR/YouTube-Helper-Client that referenced this pull request May 4, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [@biomejs/biome](https://biomejs.dev) ([source](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome)) | imports | patch | [`2.4.13` -> `2.4.14`](https://renovatebot.com/diffs/npm/@biomejs%2fbiome/2.4.13/2.4.14) |

---

### Release Notes

<details>
<summary>biomejs/biome (@&#8203;biomejs/biome)</summary>

### [`v2.4.14`](https://github.com/biomejs/biome/blob/HEAD/packages/@&#8203;biomejs/biome/CHANGELOG.md#2414)

[Compare Source](https://github.com/biomejs/biome/compare/@biomejs/biome@2.4.13...@biomejs/biome@2.4.14)

##### Patch Changes

- [#&#8203;9393](biomejs/biome#9393) [`491b171`](biomejs/biome@491b171) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the nursery rule [`useTestHooksOnTop`](https://biomejs.dev/linter/rules/use-test-hooks-on-top) in the `test` domain. The rule flags lifecycle hooks (`beforeEach`, `beforeAll`, `afterEach`, `afterAll`) that appear after test cases in the same block, enforcing that hooks are defined before any test case.

- [#&#8203;10157](biomejs/biome#10157) [`eefc5ab`](biomejs/biome@eefc5ab) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;7882](biomejs/biome#7882): The HTML parser will now emit better diagnostics when it encounters a void element with a closing tag, such as `<br></br>`. Previously, the parser would emit multiple diagnostics with conflicting advice. Now it emits a single diagnostic that clearly states that void elements should not have closing tags.

- [#&#8203;10054](biomejs/biome#10054) [`0e9f569`](biomejs/biome@0e9f569) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) no longer misses widening from concrete object types, class instances, object literals, tuples, functions, and regular expressions to `: object`.

  A function annotated `: object` returning an object literal:

  ```ts
  function f(): object {
    return { retry: true };
  }
  ```

- [#&#8203;10116](biomejs/biome#10116) [`53269eb`](biomejs/biome@53269eb) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;6201](biomejs/biome#6201): [`noUselessEscapeInRegex`](https://biomejs.dev/linter/rules/no-useless-escape-in-regex/) no longer flags an escaped backslash followed by `-` as a useless escape. Patterns like `/[\\-]/` are now considered valid because the second `\` is the escaped backslash, not an unnecessary escape of the trailing dash.

- [#&#8203;10092](biomejs/biome#10092) [`33d8543`](biomejs/biome@33d8543) Thanks [@&#8203;Conaclos](https://github.com/Conaclos)! - Fixed [#&#8203;9097](biomejs/biome#9097): [`organizeImports`](https://biomejs.dev/assist/actions/organize-imports/) no longer adds a blank line between a never-matched group and a matched group.

  Given the following `organizeImports` options:

  ```json
  {
    "groups": [":NODE:", ":BLANK_LINE:", ":PACKAGE:", ":BLANK_LINE:", ":PATH:"]
  }
  ```

  The following code...

  ```js
  // Comment
  import "package";
  import "./file.js";
  ```

  ...was organized as:

  ```diff
  +
    // Comment
    import "package";
  +
    import "./file.js";
  ```

  A blank line was added even though the group ':NODE:' doesn't match any imports here.
  `:BLANK_LINE:` between never-matched groups and matched groups are now ignored.
  The code is now organized as:

  ```diff
    // Comment
    import "package";
  +
    import "./file.js";
  ```

- [#&#8203;10138](biomejs/biome#10138) [`a10b6c1`](biomejs/biome@a10b6c1) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed Vue `v-for` handling for [`noUndeclaredVariables`](https://biomejs.dev/linter/rules/no-undeclared-variables/) and [`noUnusedVariables`](https://biomejs.dev/linter/rules/no-unused-variables/). Biome now recognizes variables declared by `v-for` directives and references to iterated values in Vue templates.

- [#&#8203;10115](biomejs/biome#10115) [`d428d76`](biomejs/biome@d428d76) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) no longer reports false positives when a union return type's `boolean` variant is covered by both `true` and `false` returns.

- [#&#8203;9922](biomejs/biome#9922) [`7acf1e0`](biomejs/biome@7acf1e0) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the new nursery rule [`noReactStringRefs`](https://biomejs.dev/linter/rules/no-react-string-refs/), which disallows legacy React string refs such as `ref="hello"` and `this.refs.hello`.

  Biome also reports template-literal refs such as ``ref={`hello`}``, so React code can consistently migrate to callback refs, `createRef()`, or `useRef()`.

- [#&#8203;10010](biomejs/biome#10010) [`f3e76ab`](biomejs/biome@f3e76ab) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed a bug in the LSP file watcher registration so Biome now watches `.biome.json` and `.biome.jsonc` configuration files and reloads workspace settings when they change.

- [#&#8203;10176](biomejs/biome#10176) [`8a40ef8`](biomejs/biome@8a40ef8) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;10011](biomejs/biome#10011): The [`noThisInStatic`](https://biomejs.dev/linter/rules/no-this-in-static/) rule no longer reports `this` when it is used as the constructor target in `new this(...)`, which is required for inherited static factory methods.

- [#&#8203;10163](biomejs/biome#10163) [`6867e96`](biomejs/biome@6867e96) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;9884](biomejs/biome#9884): The [`useSortedAttributes`](https://biomejs.dev/assist/actions/use-sorted-attributes/) auto-fix no longer corrupts source code when both an outer JSX element and a nested JSX-valued attribute have unsorted attributes in the same pass. Multiple unsorted groups separated by spread or shorthand attributes within the same JSX element are now reported as a single diagnostic.

- [#&#8203;10079](biomejs/biome#10079) [`d29dd19`](biomejs/biome@d29dd19) Thanks [@&#8203;Damix48](https://github.com/Damix48)! - Fixed false positive in `noAssignInExpressions` for Svelte `{@&#8203;const}` blocks. Assignments in `{@&#8203;const name = value}` are now correctly recognized as declarations rather than accidental assignments in expressions.

- [#&#8203;10080](biomejs/biome#10080) [`5d8fdac`](biomejs/biome@5d8fdac) Thanks [@&#8203;Damix48](https://github.com/Damix48)! - Fixed parsing of closing parentheses in Svelte `{#each}` block key expressions. Biome now correctly parses method calls and other parenthesised expressions used as keys.

  For example, the following snippets are now parsed correctly:

  ```svelte
  {#each numbers as number, index (number.toString())}
    <p>{number}</p>
  {/each}

  {#each numbers as number (key(number))}
    <p>{number}</p>
  {/each}
  ```

- [#&#8203;10140](biomejs/biome#10140) [`e7024b9`](biomejs/biome@e7024b9) Thanks [@&#8203;solithcy](https://github.com/solithcy)! - Fixed [#&#8203;10135](biomejs/biome#10135): Biome no longer crashes on missing Svelte template expressions.

  The following code snippet longer panics:

  ```svelte
  {#if }
   <p>^ this would previously crash</p>
  {/if}
  {@&#8203;const }
  <p>    ^ this would also crash</p>
  ```

- [#&#8203;10111](biomejs/biome#10111) [`7818009`](biomejs/biome@7818009) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;9997](biomejs/biome#9997): [`noDuplicateSelectors`](https://biomejs.dev/linter/rules/no-duplicate-selectors/) no longer reports false positives for selectors inside `@scope` queries. Biome now treats `@scope` as a separate at-rule context, like `@media`, `@supports`, `@container`, and `@starting-style`.

  The following snippet is no longer flagged as a duplicate:

  ```css
  .Example {
    padding: 0;
  }

  @&#8203;scope (.theme-dark) {
    .Example {
      color: white;
    }
  }
  ```

- [#&#8203;9926](biomejs/biome#9926) [`d62b331`](biomejs/biome@d62b331) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the nursery lint rule [`useMathMinMax`](https://biomejs.dev/linter/rules/use-math-min-max/), which prefers `Math.min()` and `Math.max()` over equivalent ternary comparisons.

  For example, this code:

  ```js
  const min = a < b ? a : b;
  ```

  is much more readable when rewritten as:

  ```js
  const min = Math.min(a, b);
  ```

- [#&#8203;10115](biomejs/biome#10115) [`d428d76`](biomejs/biome@d428d76) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - [`useExhaustiveSwitchCases`](https://biomejs.dev/linter/rules/use-exhaustive-switch-cases/) now flags missing `true`/`false` cases for `boolean` discriminants, including when `boolean` is a union variant.

- [#&#8203;10125](biomejs/biome#10125) [`a55a0b6`](biomejs/biome@a55a0b6) Thanks [@&#8203;bmish](https://github.com/bmish)! - Fixed a resolver bug where packages that define a typed entry point through `package.json`'s `main` field but omit `types` were ignored during type-aware resolution. Type-aware rules such as [`noFloatingPromises`](https://biomejs.dev/linter/rules/no-floating-promises/) can now inspect imports from those packages.

- [#&#8203;10117](biomejs/biome#10117) [`895e809`](biomejs/biome@895e809) Thanks [@&#8203;denizdogan](https://github.com/denizdogan)! - Added support for the `corner-shape` family of CSS properties and the `superellipse()`/`squircle()` value functions, so [`noUnknownProperty`](https://biomejs.dev/linter/rules/no-unknown-property/) and [`noUnknownFunction`](https://biomejs.dev/linter/rules/no-unknown-function/) no longer flag them as unknown.

  New known properties: `corner-shape`, `corner-block-end-shape`, `corner-block-start-shape`, `corner-bottom-left-shape`, `corner-bottom-right-shape`, `corner-bottom-shape`, `corner-end-end-shape`, `corner-end-start-shape`, `corner-inline-end-shape`, `corner-inline-start-shape`, `corner-left-shape`, `corner-right-shape`, `corner-start-end-shape`, `corner-start-start-shape`, `corner-top-left-shape`, `corner-top-right-shape`, `corner-top-shape`.

  New known value functions: `superellipse()`, `squircle()`.

- [#&#8203;8620](biomejs/biome#8620) [`8df8f73`](biomejs/biome@8df8f73) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;8062](biomejs/biome#8062): Added support for parsing Vue `v-for` directives more accurately.

- [#&#8203;10191](biomejs/biome#10191) [`aa055cd`](biomejs/biome@aa055cd) Thanks [@&#8203;guney](https://github.com/guney)! - Now the rule [`noStaticElementInteractions`](https://biomejs.dev/linter/rules/no-static-element-interactions/) doesn't trigger custom elements.

- [#&#8203;9757](biomejs/biome#9757) [`2c62594`](biomejs/biome@2c62594) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;9099](biomejs/biome#9099): the HTML formatter collapsing non-text children (inline elements, Svelte expressions, comments) onto a single line when the source had them on separate lines. Biome now preserves the user's intended line breaks for exclusively non-text children.

  For example, the following Svelte snippet is now preserved instead of being collapsed to `<div>{name}<!-- comment --></div>`:

  ```svelte
  <div>
    {name}<!-- comment -->
  </div>
  ```

  Similarly, HTML elements like `<span>` inside a `<div>` are now preserved when written on their own line:

  ```html
  <div>
    <span>text</span>
  </div>
  ```

- [#&#8203;10105](biomejs/biome#10105) [`e7c1a6d`](biomejs/biome@e7c1a6d) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;10039](biomejs/biome#10039): [`useReadonlyClassProperties`](https://biomejs.dev/linter/rules/use-readonly-class-properties/) now detects unreassigned private members in class expressions and export default classes, not only in class declarations.

  The following patterns are now correctly flagged:

  ```ts
  const AnonClass = class {
    #prop = 123;
    constructor() {
      console.log(this.#prop);
    }
  };

  export default class {
    #prop = 123;
    constructor() {
      console.log(this.#prop);
    }
  }
  ```

- [#&#8203;10141](biomejs/biome#10141) [`46a77d0`](biomejs/biome@46a77d0) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Improved [`noUnnecessaryConditions`](https://biomejs.dev/linter/rules/no-unnecessary-conditions/) to detect conditions that are always truthy because they check built-in global class instances such as `Date`, `Map`, `Set`, `WeakMap`, and `Error`.

- [#&#8203;10178](biomejs/biome#10178) [`7b05a89`](biomejs/biome@7b05a89) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;10177](biomejs/biome#10177): The HTML parser no longer reports lowercase `html` or `doctype` text as invalid after void elements such as `<br>`.

- [#&#8203;10155](biomejs/biome#10155) [`0d4595d`](biomejs/biome@0d4595d) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;10045](biomejs/biome#10045): the CSS formatter no longer compounds indentation inside nested functional pseudo-classes such as `:not(:where(...))`, `:is(:where(...))`, and similar combinations. The same fix also removes one level of unnecessary indentation that was added inside any pseudo-class function whose argument list wrapped onto multiple lines, including `:nth-child(... of ...)`, `::part(...)`, and `:active-view-transition-type(...)`.
  The following snippet is now correctly formatted, matching Prettier.

  ```css
  input:not(
    :where(
      [type="submit"],
      [type="checkbox"],
      [type="radio"],
      [type="button"],
      [type="reset"]
    )
  ) {
    inline-size: 100%;
  }
  ```

- [#&#8203;10112](biomejs/biome#10112) [`6f0251e`](biomejs/biome@6f0251e) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;10110](biomejs/biome#10110): Biome's parser now accepts surrogate code points in JavaScript string `\u{...}` escapes.

- [#&#8203;10141](biomejs/biome#10141) [`46a77d0`](biomejs/biome@46a77d0) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Improved [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) to detect `object` return annotations that hide built-in global class instances such as `Date`, `Map`, `Set`, `WeakMap`, and `Error`.

- [#&#8203;10083](biomejs/biome#10083) [`4a664c1`](biomejs/biome@4a664c1) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Added two new options to [`noShadow`](https://biomejs.dev/linter/rules/no-shadow/), both defaulting to `true` to match typescript-eslint's behavior.

  Fixed [#&#8203;9482](biomejs/biome#9482): Added `ignoreFunctionTypeParameterNameValueShadow` option. When enabled, parameter names inside function type annotations (e.g. `(options: unknown) => void`) are not flagged as shadowing outer variables.

  Fixed [#&#8203;7812](biomejs/biome#7812): Added `ignoreTypeValueShadow` option. When enabled, a value binding that shares its name with a type-only declaration (type alias or interface) is not flagged, since types and values occupy separate namespaces in TypeScript.

- [#&#8203;9286](biomejs/biome#9286) [`52695cf`](biomejs/biome@52695cf) Thanks [@&#8203;Hugo-Polloli](https://github.com/Hugo-Polloli)! - Fixed [#&#8203;6316](biomejs/biome#6316): Biome now resolves Svelte `$store` references to the underlying `store` binding in semantic analysis, preventing false `noUndeclaredVariables` diagnostics when the store is declared.

- [#&#8203;10188](biomejs/biome#10188) [`ae659dd`](biomejs/biome@ae659dd) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added a new nursery rule [`noExcessiveNestedCallbacks`](https://biomejs.dev/linter/rules/no-excessive-nested-callbacks/), which disallows callbacks nested deeper than the configured maximum.

- [#&#8203;9757](biomejs/biome#9757) [`2c62594`](biomejs/biome@2c62594) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;9450](biomejs/biome#9450): the HTML formatter now correctly preserves multiline formatting for nested `<template>` elements (e.g. `<template #body>`) when the source has children on separate lines. Previously, the children were collapsed onto a single line.

  ```diff
   <template>
     <UModal>
  -    <template #body> <p>content</p> </template>
  +    <template #body>
  +      <p>content</p>
  +    </template>
     </UModal>
   </template>
  ```

- [#&#8203;10118](biomejs/biome#10118) [`c6edcb4`](biomejs/biome@c6edcb4) Thanks [@&#8203;Netail](https://github.com/Netail)! - Fixed [#&#8203;10024](biomejs/biome#10024): `biome migrate eslint` correctly migrates `eslint` rules that belong to multiple Biome rules.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNjAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE2MC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.oirnoir.dev/OIRNOIR/YouTube-Helper-Client/pulls/2
OIRNOIR pushed a commit to OIRNOIR/YouTube-Helper-Server that referenced this pull request May 5, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [@biomejs/biome](https://biomejs.dev) ([source](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome)) | imports | patch | [`2.4.13` -> `2.4.14`](https://renovatebot.com/diffs/npm/@biomejs%2fbiome/2.4.13/2.4.14) |

---

### Release Notes

<details>
<summary>biomejs/biome (@&#8203;biomejs/biome)</summary>

### [`v2.4.14`](https://github.com/biomejs/biome/blob/HEAD/packages/@&#8203;biomejs/biome/CHANGELOG.md#2414)

[Compare Source](https://github.com/biomejs/biome/compare/@biomejs/biome@2.4.13...@biomejs/biome@2.4.14)

##### Patch Changes

- [#&#8203;9393](biomejs/biome#9393) [`491b171`](biomejs/biome@491b171) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the nursery rule [`useTestHooksOnTop`](https://biomejs.dev/linter/rules/use-test-hooks-on-top) in the `test` domain. The rule flags lifecycle hooks (`beforeEach`, `beforeAll`, `afterEach`, `afterAll`) that appear after test cases in the same block, enforcing that hooks are defined before any test case.

- [#&#8203;10157](biomejs/biome#10157) [`eefc5ab`](biomejs/biome@eefc5ab) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;7882](biomejs/biome#7882): The HTML parser will now emit better diagnostics when it encounters a void element with a closing tag, such as `<br></br>`. Previously, the parser would emit multiple diagnostics with conflicting advice. Now it emits a single diagnostic that clearly states that void elements should not have closing tags.

- [#&#8203;10054](biomejs/biome#10054) [`0e9f569`](biomejs/biome@0e9f569) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) no longer misses widening from concrete object types, class instances, object literals, tuples, functions, and regular expressions to `: object`.

  A function annotated `: object` returning an object literal:

  ```ts
  function f(): object {
    return { retry: true };
  }
  ```

- [#&#8203;10116](biomejs/biome#10116) [`53269eb`](biomejs/biome@53269eb) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;6201](biomejs/biome#6201): [`noUselessEscapeInRegex`](https://biomejs.dev/linter/rules/no-useless-escape-in-regex/) no longer flags an escaped backslash followed by `-` as a useless escape. Patterns like `/[\\-]/` are now considered valid because the second `\` is the escaped backslash, not an unnecessary escape of the trailing dash.

- [#&#8203;10092](biomejs/biome#10092) [`33d8543`](biomejs/biome@33d8543) Thanks [@&#8203;Conaclos](https://github.com/Conaclos)! - Fixed [#&#8203;9097](biomejs/biome#9097): [`organizeImports`](https://biomejs.dev/assist/actions/organize-imports/) no longer adds a blank line between a never-matched group and a matched group.

  Given the following `organizeImports` options:

  ```json
  {
    "groups": [":NODE:", ":BLANK_LINE:", ":PACKAGE:", ":BLANK_LINE:", ":PATH:"]
  }
  ```

  The following code...

  ```js
  // Comment
  import "package";
  import "./file.js";
  ```

  ...was organized as:

  ```diff
  +
    // Comment
    import "package";
  +
    import "./file.js";
  ```

  A blank line was added even though the group ':NODE:' doesn't match any imports here.
  `:BLANK_LINE:` between never-matched groups and matched groups are now ignored.
  The code is now organized as:

  ```diff
    // Comment
    import "package";
  +
    import "./file.js";
  ```

- [#&#8203;10138](biomejs/biome#10138) [`a10b6c1`](biomejs/biome@a10b6c1) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed Vue `v-for` handling for [`noUndeclaredVariables`](https://biomejs.dev/linter/rules/no-undeclared-variables/) and [`noUnusedVariables`](https://biomejs.dev/linter/rules/no-unused-variables/). Biome now recognizes variables declared by `v-for` directives and references to iterated values in Vue templates.

- [#&#8203;10115](biomejs/biome#10115) [`d428d76`](biomejs/biome@d428d76) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) no longer reports false positives when a union return type's `boolean` variant is covered by both `true` and `false` returns.

- [#&#8203;9922](biomejs/biome#9922) [`7acf1e0`](biomejs/biome@7acf1e0) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the new nursery rule [`noReactStringRefs`](https://biomejs.dev/linter/rules/no-react-string-refs/), which disallows legacy React string refs such as `ref="hello"` and `this.refs.hello`.

  Biome also reports template-literal refs such as ``ref={`hello`}``, so React code can consistently migrate to callback refs, `createRef()`, or `useRef()`.

- [#&#8203;10010](biomejs/biome#10010) [`f3e76ab`](biomejs/biome@f3e76ab) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed a bug in the LSP file watcher registration so Biome now watches `.biome.json` and `.biome.jsonc` configuration files and reloads workspace settings when they change.

- [#&#8203;10176](biomejs/biome#10176) [`8a40ef8`](biomejs/biome@8a40ef8) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;10011](biomejs/biome#10011): The [`noThisInStatic`](https://biomejs.dev/linter/rules/no-this-in-static/) rule no longer reports `this` when it is used as the constructor target in `new this(...)`, which is required for inherited static factory methods.

- [#&#8203;10163](biomejs/biome#10163) [`6867e96`](biomejs/biome@6867e96) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;9884](biomejs/biome#9884): The [`useSortedAttributes`](https://biomejs.dev/assist/actions/use-sorted-attributes/) auto-fix no longer corrupts source code when both an outer JSX element and a nested JSX-valued attribute have unsorted attributes in the same pass. Multiple unsorted groups separated by spread or shorthand attributes within the same JSX element are now reported as a single diagnostic.

- [#&#8203;10079](biomejs/biome#10079) [`d29dd19`](biomejs/biome@d29dd19) Thanks [@&#8203;Damix48](https://github.com/Damix48)! - Fixed false positive in `noAssignInExpressions` for Svelte `{@&#8203;const}` blocks. Assignments in `{@&#8203;const name = value}` are now correctly recognized as declarations rather than accidental assignments in expressions.

- [#&#8203;10080](biomejs/biome#10080) [`5d8fdac`](biomejs/biome@5d8fdac) Thanks [@&#8203;Damix48](https://github.com/Damix48)! - Fixed parsing of closing parentheses in Svelte `{#each}` block key expressions. Biome now correctly parses method calls and other parenthesised expressions used as keys.

  For example, the following snippets are now parsed correctly:

  ```svelte
  {#each numbers as number, index (number.toString())}
    <p>{number}</p>
  {/each}

  {#each numbers as number (key(number))}
    <p>{number}</p>
  {/each}
  ```

- [#&#8203;10140](biomejs/biome#10140) [`e7024b9`](biomejs/biome@e7024b9) Thanks [@&#8203;solithcy](https://github.com/solithcy)! - Fixed [#&#8203;10135](biomejs/biome#10135): Biome no longer crashes on missing Svelte template expressions.

  The following code snippet longer panics:

  ```svelte
  {#if }
   <p>^ this would previously crash</p>
  {/if}
  {@&#8203;const }
  <p>    ^ this would also crash</p>
  ```

- [#&#8203;10111](biomejs/biome#10111) [`7818009`](biomejs/biome@7818009) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;9997](biomejs/biome#9997): [`noDuplicateSelectors`](https://biomejs.dev/linter/rules/no-duplicate-selectors/) no longer reports false positives for selectors inside `@scope` queries. Biome now treats `@scope` as a separate at-rule context, like `@media`, `@supports`, `@container`, and `@starting-style`.

  The following snippet is no longer flagged as a duplicate:

  ```css
  .Example {
    padding: 0;
  }

  @&#8203;scope (.theme-dark) {
    .Example {
      color: white;
    }
  }
  ```

- [#&#8203;9926](biomejs/biome#9926) [`d62b331`](biomejs/biome@d62b331) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the nursery lint rule [`useMathMinMax`](https://biomejs.dev/linter/rules/use-math-min-max/), which prefers `Math.min()` and `Math.max()` over equivalent ternary comparisons.

  For example, this code:

  ```js
  const min = a < b ? a : b;
  ```

  is much more readable when rewritten as:

  ```js
  const min = Math.min(a, b);
  ```

- [#&#8203;10115](biomejs/biome#10115) [`d428d76`](biomejs/biome@d428d76) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - [`useExhaustiveSwitchCases`](https://biomejs.dev/linter/rules/use-exhaustive-switch-cases/) now flags missing `true`/`false` cases for `boolean` discriminants, including when `boolean` is a union variant.

- [#&#8203;10125](biomejs/biome#10125) [`a55a0b6`](biomejs/biome@a55a0b6) Thanks [@&#8203;bmish](https://github.com/bmish)! - Fixed a resolver bug where packages that define a typed entry point through `package.json`'s `main` field but omit `types` were ignored during type-aware resolution. Type-aware rules such as [`noFloatingPromises`](https://biomejs.dev/linter/rules/no-floating-promises/) can now inspect imports from those packages.

- [#&#8203;10117](biomejs/biome#10117) [`895e809`](biomejs/biome@895e809) Thanks [@&#8203;denizdogan](https://github.com/denizdogan)! - Added support for the `corner-shape` family of CSS properties and the `superellipse()`/`squircle()` value functions, so [`noUnknownProperty`](https://biomejs.dev/linter/rules/no-unknown-property/) and [`noUnknownFunction`](https://biomejs.dev/linter/rules/no-unknown-function/) no longer flag them as unknown.

  New known properties: `corner-shape`, `corner-block-end-shape`, `corner-block-start-shape`, `corner-bottom-left-shape`, `corner-bottom-right-shape`, `corner-bottom-shape`, `corner-end-end-shape`, `corner-end-start-shape`, `corner-inline-end-shape`, `corner-inline-start-shape`, `corner-left-shape`, `corner-right-shape`, `corner-start-end-shape`, `corner-start-start-shape`, `corner-top-left-shape`, `corner-top-right-shape`, `corner-top-shape`.

  New known value functions: `superellipse()`, `squircle()`.

- [#&#8203;8620](biomejs/biome#8620) [`8df8f73`](biomejs/biome@8df8f73) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;8062](biomejs/biome#8062): Added support for parsing Vue `v-for` directives more accurately.

- [#&#8203;10191](biomejs/biome#10191) [`aa055cd`](biomejs/biome@aa055cd) Thanks [@&#8203;guney](https://github.com/guney)! - Now the rule [`noStaticElementInteractions`](https://biomejs.dev/linter/rules/no-static-element-interactions/) doesn't trigger custom elements.

- [#&#8203;9757](biomejs/biome#9757) [`2c62594`](biomejs/biome@2c62594) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;9099](biomejs/biome#9099): the HTML formatter collapsing non-text children (inline elements, Svelte expressions, comments) onto a single line when the source had them on separate lines. Biome now preserves the user's intended line breaks for exclusively non-text children.

  For example, the following Svelte snippet is now preserved instead of being collapsed to `<div>{name}<!-- comment --></div>`:

  ```svelte
  <div>
    {name}<!-- comment -->
  </div>
  ```

  Similarly, HTML elements like `<span>` inside a `<div>` are now preserved when written on their own line:

  ```html
  <div>
    <span>text</span>
  </div>
  ```

- [#&#8203;10105](biomejs/biome#10105) [`e7c1a6d`](biomejs/biome@e7c1a6d) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;10039](biomejs/biome#10039): [`useReadonlyClassProperties`](https://biomejs.dev/linter/rules/use-readonly-class-properties/) now detects unreassigned private members in class expressions and export default classes, not only in class declarations.

  The following patterns are now correctly flagged:

  ```ts
  const AnonClass = class {
    #prop = 123;
    constructor() {
      console.log(this.#prop);
    }
  };

  export default class {
    #prop = 123;
    constructor() {
      console.log(this.#prop);
    }
  }
  ```

- [#&#8203;10141](biomejs/biome#10141) [`46a77d0`](biomejs/biome@46a77d0) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Improved [`noUnnecessaryConditions`](https://biomejs.dev/linter/rules/no-unnecessary-conditions/) to detect conditions that are always truthy because they check built-in global class instances such as `Date`, `Map`, `Set`, `WeakMap`, and `Error`.

- [#&#8203;10178](biomejs/biome#10178) [`7b05a89`](biomejs/biome@7b05a89) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;10177](biomejs/biome#10177): The HTML parser no longer reports lowercase `html` or `doctype` text as invalid after void elements such as `<br>`.

- [#&#8203;10155](biomejs/biome#10155) [`0d4595d`](biomejs/biome@0d4595d) Thanks [@&#8203;jiwon79](https://github.com/jiwon79)! - Fixed [#&#8203;10045](biomejs/biome#10045): the CSS formatter no longer compounds indentation inside nested functional pseudo-classes such as `:not(:where(...))`, `:is(:where(...))`, and similar combinations. The same fix also removes one level of unnecessary indentation that was added inside any pseudo-class function whose argument list wrapped onto multiple lines, including `:nth-child(... of ...)`, `::part(...)`, and `:active-view-transition-type(...)`.
  The following snippet is now correctly formatted, matching Prettier.

  ```css
  input:not(
    :where(
      [type="submit"],
      [type="checkbox"],
      [type="radio"],
      [type="button"],
      [type="reset"]
    )
  ) {
    inline-size: 100%;
  }
  ```

- [#&#8203;10112](biomejs/biome#10112) [`6f0251e`](biomejs/biome@6f0251e) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;10110](biomejs/biome#10110): Biome's parser now accepts surrogate code points in JavaScript string `\u{...}` escapes.

- [#&#8203;10141](biomejs/biome#10141) [`46a77d0`](biomejs/biome@46a77d0) Thanks [@&#8203;minseong0324](https://github.com/minseong0324)! - Improved [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) to detect `object` return annotations that hide built-in global class instances such as `Date`, `Map`, `Set`, `WeakMap`, and `Error`.

- [#&#8203;10083](biomejs/biome#10083) [`4a664c1`](biomejs/biome@4a664c1) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Added two new options to [`noShadow`](https://biomejs.dev/linter/rules/no-shadow/), both defaulting to `true` to match typescript-eslint's behavior.

  Fixed [#&#8203;9482](biomejs/biome#9482): Added `ignoreFunctionTypeParameterNameValueShadow` option. When enabled, parameter names inside function type annotations (e.g. `(options: unknown) => void`) are not flagged as shadowing outer variables.

  Fixed [#&#8203;7812](biomejs/biome#7812): Added `ignoreTypeValueShadow` option. When enabled, a value binding that shares its name with a type-only declaration (type alias or interface) is not flagged, since types and values occupy separate namespaces in TypeScript.

- [#&#8203;9286](biomejs/biome#9286) [`52695cf`](biomejs/biome@52695cf) Thanks [@&#8203;Hugo-Polloli](https://github.com/Hugo-Polloli)! - Fixed [#&#8203;6316](biomejs/biome#6316): Biome now resolves Svelte `$store` references to the underlying `store` binding in semantic analysis, preventing false `noUndeclaredVariables` diagnostics when the store is declared.

- [#&#8203;10188](biomejs/biome#10188) [`ae659dd`](biomejs/biome@ae659dd) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added a new nursery rule [`noExcessiveNestedCallbacks`](https://biomejs.dev/linter/rules/no-excessive-nested-callbacks/), which disallows callbacks nested deeper than the configured maximum.

- [#&#8203;9757](biomejs/biome#9757) [`2c62594`](biomejs/biome@2c62594) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed [#&#8203;9450](biomejs/biome#9450): the HTML formatter now correctly preserves multiline formatting for nested `<template>` elements (e.g. `<template #body>`) when the source has children on separate lines. Previously, the children were collapsed onto a single line.

  ```diff
   <template>
     <UModal>
  -    <template #body> <p>content</p> </template>
  +    <template #body>
  +      <p>content</p>
  +    </template>
     </UModal>
   </template>
  ```

- [#&#8203;10118](biomejs/biome#10118) [`c6edcb4`](biomejs/biome@c6edcb4) Thanks [@&#8203;Netail](https://github.com/Netail)! - Fixed [#&#8203;10024](biomejs/biome#10024): `biome migrate eslint` correctly migrates `eslint` rules that belong to multiple Biome rules.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNjAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE2MC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.oirnoir.dev/OIRNOIR/YouTube-Helper-Server/pulls/10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Linter Area: linter A-Project Area: project A-Type-Inference Area: type inference L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants