Skip to content

update deps & migrate to oxlint/oxfmt#805

Merged
tannerlinsley merged 6 commits intoTanStack:mainfrom
LadyBluenotes:updates
Apr 1, 2026
Merged

update deps & migrate to oxlint/oxfmt#805
tannerlinsley merged 6 commits intoTanStack:mainfrom
LadyBluenotes:updates

Conversation

@LadyBluenotes
Copy link
Copy Markdown
Member

@LadyBluenotes LadyBluenotes commented Apr 1, 2026

Summary by CodeRabbit

  • Chores

    • Switched to new formatting and linting tools; updated dev tooling and dependencies; removed old formatter/linter configs.
    • Cleaned up build/config formatting and TypeScript/Vite path resolution.
  • Refactor

    • Removed the Feed page/route.
    • Standardized GitHub icon across the UI and added a shared icon export.
    • Improved keyboard/focus and button interactions in builder/explorer panels.
    • Exported width-toggle context for cross-module usage; minor accessibility and markup tweaks.

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 1, 2026

Deploy Preview for tanstack ready!

Name Link
🔨 Latest commit 056ffab
🔍 Latest deploy log https://app.netlify.com/projects/tanstack/deploys/69cd6d4b9a34030008da4434
😎 Deploy Preview https://deploy-preview-805--tanstack.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 47 (🔴 down 3 from production)
Accessibility: 90 (no change from production)
Best Practices: 75 (🔴 down 8 from production)
SEO: 97 (no change from production)
PWA: 70 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c85837b0-63da-4e15-943f-de15e253252d

📥 Commits

Reviewing files that changed from the base of the PR and between 8a61970 and 056ffab.

📒 Files selected for processing (3)
  • content-collections.ts
  • src/builder/api/remote.ts
  • src/ui/Icons.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/ui/Icons.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/builder/api/remote.ts
  • content-collections.ts

📝 Walkthrough

Walkthrough

Replaces ESLint/Prettier with Oxlint/Oxfmt, upgrades TypeScript and many dependencies, removes the /feed route and its UI, adds a local GitHub icon and reuses it, switches Vite path resolution to an explicit alias, and applies multiple component, util, and config tweaks across the codebase.

Changes

Cohort / File(s) Summary
Linting & Formatting
​.oxfmtrc.json, ​.oxlintrc.json, eslint.config.mjs
Added Oxfmt/Oxlint configs and removed the exported eslint.config.mjs contents; lint/format rules, plugins, and ignore patterns moved to new Ox configs.
Package & Scripts
package.json, scripts/test-npm-cache.ts
Bumped package manager and many deps, replaced eslint/prettier with oxlint/oxfmt in scripts, adjusted devDependencies, and changed one import path in scripts/test-npm-cache.ts.
Routing removal
src/routes/feed.tsx, src/routeTree.gen.ts
Deleted the /feed route file and removed its generated route registration and related type entries from the route tree.
Icon library & usage
src/ui/Icons.tsx, src/ui/index.ts, src/components/.../ExampleDeployDialog.tsx, src/components/.../builder/ConfigPanel.tsx, src/components/.../builder/DeployDialog.tsx
Added exported GitHub SVG component and re-export; replaced prior Github (lucide) usages with new GitHub across multiple components.
Context exposure & consumption
src/components/DocsLayout.tsx, src/components/Doc.tsx
Exported WidthToggleContext; Doc now consumes it via React.useContext(...) with optional chaining instead of prior try/catch approach.
Builder UI & Explorer refactor
src/components/builder/ExplorerPanel.tsx, src/components/builder/ConfigPanel.tsx, src/components/builder/DeployDialog.tsx
Refactored added-lines calc to declarative reduce, introduced featureName, replaced clickable container with accessible nested <button>s, and updated GitHub icon imports/usages.
Small component signature changes
src/components/AILibraryHero.tsx, src/components/UserFeedbackSection.tsx
Replaced unused destructured props with named _props parameter in a few components.
Tabs / children prop handling
src/components/markdown/MarkdownTabsHandler.tsx, src/components/markdown/PackageManagerTabs.tsx
Pass children as nested children to lazy FileTabs/Tabs and add a targeted lint suppression for children prop usage.
Minor component fixes
src/components/StackBlitzEmbed.tsx, src/components/TrustedByMarquee.tsx, src/routes/partners.tsx
Set iframe title earlier with inline lint disable, corrected marquee selector escaping, and simplified a pluralization expression.
Utilities & server tweaks
src/utils/cache.server.ts, src/utils/documents.server.ts, src/builder/api/remote.ts, scripts/mcp-eval/run-eval.ts, src/components/builder/webcontainer/useWebContainerStore.ts
Switched lru-cache import to named LRUCache and added @ts-expect-error for global cache init, adjusted Markdown image regex, replaced object type annotation with post-construction as cast, removed unused getDoc helper, and added eslint-disable comments for control-character regexes.
Config & build changes
tsconfig.json, vite.config.ts, netlify.toml, content-collections.ts, .prettierrc, .prettierignore
Removed baseUrl from tsconfig, replaced vite-tsconfig-paths with explicit ~ alias, reformatted Netlify TOML, converted posts schema to direct z.object(...) and z.iso.date(), and removed Prettier config/ignore files in favor of oxfmt configs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibbled at configs through the night,

Oxfmt trimmed edges, Oxlint set things right,
TypeScript hopped up, icons found a new home,
The feed skippity-bye — we pranced, we roam,
Small tweaks, tidy hops — into the code we comb.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: updating dependencies and migrating from ESLint/Prettier to Oxlint/Oxfmt tooling.

✏️ 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

@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.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
content-collections.ts (1)

8-14: ⚠️ Potential issue | 🟡 Minor

Use z.iso.date() instead of z.string().date() for Zod v4 consistency.

In Zod v4, z.iso.date() is the recommended primary method for ISO date string validation. While z.string().date() remains functional, the official Zod v4 documentation emphasizes z.iso.date() as the standard approach. Update line 10 to use z.iso.date() for consistency with Zod v4 conventions.

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

In `@content-collections.ts` around lines 8 - 14, Update the Zod schema for the
"published" field to use the Zod v4 ISO date validator: replace the current
z.string().date() usage inside the schema object (the published property) with
z.iso.date() so the schema variable's published field validates ISO date strings
using the recommended Zod v4 API.
src/builder/api/remote.ts (1)

57-63: ⚠️ Potential issue | 🟡 Minor

Remove unsafe double cast or explicitly provide required framework and typescript fields.

The StarterCompiled interface requires framework: string and typescript: boolean as non-optional fields (lines 52 and 54 of src/builder/api/compile.ts). In the current implementation at lines 57-63, these fields are neither explicitly set nor guaranteed to exist in the spread starter object from the external loadStarter function. The as unknown as StarterCompiled cast bypasses type checking and masks this issue. Either explicitly provide these fields when constructing the template object, or ensure the external Starter type is properly validated to contain them.

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

In `@src/builder/api/remote.ts` around lines 57 - 63, The template object is being
unsafely double-cast to StarterCompiled while missing required non-optional
fields `framework` and `typescript`; update the construction in the code that
builds `template` (the `template` constant created from `starter` returned by
`loadStarter`) to explicitly provide `framework` (string) and `typescript`
(boolean) or validate and assign them from `starter` before casting (e.g.,
derive/validate `starter.framework` and `starter.typescript` and set defaults or
throw), ensuring the resulting object truly satisfies the `StarterCompiled`
shape rather than relying on `as unknown as StarterCompiled`.
src/components/builder/ExplorerPanel.tsx (1)

674-705: ⚠️ Potential issue | 🟡 Minor

The split-button row now has non-clickable dead space.

The wrapper still provides the full-row hover/selected styling, but only the inner button is actionable. That leaves padding around the label area that looks clickable and no longer selects the addon. Please move the padding/hit area onto the button, or make the selection button fill the non-remove area, so the visual affordance matches the pointer target.

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

In `@src/components/builder/ExplorerPanel.tsx` around lines 674 - 705, The row
wrapper currently holds the padding/hover/selected styling while only the inner
button (onClick={() => setSelectedAddon(featureId)}) is actionable, creating
dead space; move the layout/padding/rounded/conditional twMerge classes and the
conditional style from the outer div onto the button (so the button becomes the
full-row hit area) or alternatively make the button span the full non-remove
area by giving it className="flex flex-1 min-w-0 items-center gap-2 text-left
px-3 py-2 rounded-lg transition-colors" and applying the same isSelected
conditional classes and style ({ backgroundColor: `${featureColor}20` }) to the
button; keep the outer div as a simple key wrapper without hover/selection
styles and preserve addedLines rendering and aria-pressed on the button.
🧹 Nitpick comments (1)
.oxlintrc.json (1)

135-142: Permissive no-unused-vars ignore patterns.

The patterns ^e$ and ^error$ allow any variable named e or error to be unused without warning. This is quite broad and may mask legitimate unused variable issues beyond catch blocks.

Consider narrowing to only catch error parameters by using caughtErrorsIgnorePattern alone, or documenting why these patterns are needed.

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

In @.oxlintrc.json around lines 135 - 142, The current "no-unused-vars" rule is
too permissive because argsIgnorePattern and varsIgnorePattern include (^e$) and
(^error$), allowing any variables named e or error to be unused; remove (^e$)
and (^error$) from argsIgnorePattern and varsIgnorePattern and leave only the
underscore patterns there, then move the e/error patterns exclusively into
caughtErrorsIgnorePattern (or document why broader ignores are required) so that
only catch-block error parameters are exempt while other unused e/error
variables still trigger warnings; update the rule keys "no-unused-vars",
"argsIgnorePattern", "varsIgnorePattern", and "caughtErrorsIgnorePattern"
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@content-collections.ts`:
- Line 10: The schema field named "published" currently uses the deprecated Zod
pattern z.string().date(); update it to use z.iso.date() so it validates ISO
YYYY-MM-DD strings under Zod v4 compatibility—locate the "published" field in
the content collection schema (the property named published) and replace
z.string().date() with z.iso.date(), keeping the rest of the schema intact.

In `@package.json`:
- Around line 78-79: The package.json currently lists the linting packages
"oxlint" and "oxlint-tsgolint" under dependencies; move both entries into the
devDependencies object (preserve their versions "^1.58.0" and "^0.19.0") and
remove them from dependencies, then update the lockfile by running the package
manager install (npm install or yarn) so the lockfile reflects the change;
confirm no runtime code imports these packages so moving them doesn't break
production builds.

In `@src/builder/api/remote.ts`:
- Around line 29-34: The returned object `integration` is being force-cast to
`StarterCompiled` but `RemoteIntegrationResponse.integration` is actually typed
as `AddOnCompiled`; fix this by either (A) keeping the add-on shape: change
`RemoteIntegrationResponse.integration` to `AddOnCompiled` and remove the `as
unknown as StarterCompiled` cast so `integration` is returned with its natural
type, or (B) if `StarterCompiled` is intended, construct `integration` with the
required `framework`, `mode`, and `typescript` fields and remove the
double-cast, updating the response type to `StarterCompiled`; locate the
`integration` construction in `src/builder/api/remote.ts` and update the
type/fields accordingly (referencing `RemoteIntegrationResponse`,
`AddOnCompiled`, `StarterCompiled`, and the `integration` variable).

In `@src/components/Doc.tsx`:
- Around line 125-133: The anchor builds a markdown link using the optional
variable pagePath (the template `${pagePath}.md` and the link text), which
yields "undefined.md" when pagePath is not provided; fix by guarding this anchor
in the Doc component so it only renders when pagePath is a non-empty string (or
compute a safePath = pagePath ?? '' and check safePath.length > 0 before
rendering), and update the href/text generation to use that safe value (replace
usages of `${pagePath}.md` and the inline {pagePath}.md text with the
guarded/safe value or omit the anchor entirely when missing).

In `@src/components/TrustedByMarquee.tsx`:
- Line 75: The CSS rule uses an unescaped selector so it won't match the
Tailwind arbitrary class animate-[marquee_linear_infinite]; update the selector
to the escaped form (escape the square brackets and any special chars) so
.animate-\[marquee_linear_infinite\] targets elements with
class="animate-[marquee_linear_infinite]"; locate the rule near TrustedByMarquee
(the .animate-[marquee_linear_infinite] declaration) and replace the selector
with the escaped version while keeping the animation properties unchanged.

In `@src/ui/Icons.tsx`:
- Line 12: The SVG group element in Icons.tsx uses the non-React prop name
clip-path (seen as <g clip-path="url(`#clip0_730_27136`)">) which breaks TSX
typing and attribute rendering; change the prop to the React/JSX camelCase name
clipPath on that <g> element (and any other SVG elements using dash-cased props)
so TypeScript and React will handle the attribute correctly while preserving the
same value ("url(`#clip0_730_27136`)").

In `@src/utils/cache.server.ts`:
- Around line 3-11: Remove the unnecessary "@ts-expect-error" inside the declare
global block for the docCache global declaration: update the global augmentation
so it simply declares var docCache: LRUCache<string, unknown> (no suppression),
while keeping the existing "@ts-expect-error" on the assignment expression that
sets globalThis.docCache = new LRUCache(...) in the docCache initialization
(retain that suppression if it prevents a real type error); this touches the
declare global block and the docCache initialization/assignment symbols.

In `@vite.config.ts`:
- Around line 14-18: The Vite alias configuration is missing the
content-collections mapping which causes imports in src/utils/blog.ts and
src/routes/blog.$.tsx to fail; update the resolve.alias block in vite.config.ts
(where '~' is configured) to add a 'content-collections' alias pointing to the
generated folder (./.content-collections/generated) so that imports using the
content-collections alias resolve correctly (ensure the alias pattern matches
how it's imported, e.g., 'content-collections' or 'content-collections/*'
mapping to path.resolve(__dirname, './.content-collections/generated')).

---

Outside diff comments:
In `@content-collections.ts`:
- Around line 8-14: Update the Zod schema for the "published" field to use the
Zod v4 ISO date validator: replace the current z.string().date() usage inside
the schema object (the published property) with z.iso.date() so the schema
variable's published field validates ISO date strings using the recommended Zod
v4 API.

In `@src/builder/api/remote.ts`:
- Around line 57-63: The template object is being unsafely double-cast to
StarterCompiled while missing required non-optional fields `framework` and
`typescript`; update the construction in the code that builds `template` (the
`template` constant created from `starter` returned by `loadStarter`) to
explicitly provide `framework` (string) and `typescript` (boolean) or validate
and assign them from `starter` before casting (e.g., derive/validate
`starter.framework` and `starter.typescript` and set defaults or throw),
ensuring the resulting object truly satisfies the `StarterCompiled` shape rather
than relying on `as unknown as StarterCompiled`.

In `@src/components/builder/ExplorerPanel.tsx`:
- Around line 674-705: The row wrapper currently holds the
padding/hover/selected styling while only the inner button (onClick={() =>
setSelectedAddon(featureId)}) is actionable, creating dead space; move the
layout/padding/rounded/conditional twMerge classes and the conditional style
from the outer div onto the button (so the button becomes the full-row hit area)
or alternatively make the button span the full non-remove area by giving it
className="flex flex-1 min-w-0 items-center gap-2 text-left px-3 py-2 rounded-lg
transition-colors" and applying the same isSelected conditional classes and
style ({ backgroundColor: `${featureColor}20` }) to the button; keep the outer
div as a simple key wrapper without hover/selection styles and preserve
addedLines rendering and aria-pressed on the button.

---

Nitpick comments:
In @.oxlintrc.json:
- Around line 135-142: The current "no-unused-vars" rule is too permissive
because argsIgnorePattern and varsIgnorePattern include (^e$) and (^error$),
allowing any variables named e or error to be unused; remove (^e$) and (^error$)
from argsIgnorePattern and varsIgnorePattern and leave only the underscore
patterns there, then move the e/error patterns exclusively into
caughtErrorsIgnorePattern (or document why broader ignores are required) so that
only catch-block error parameters are exempt while other unused e/error
variables still trigger warnings; update the rule keys "no-unused-vars",
"argsIgnorePattern", "varsIgnorePattern", and "caughtErrorsIgnorePattern"
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5ca9c4fc-67f3-43dc-8c79-aca18d869e79

📥 Commits

Reviewing files that changed from the base of the PR and between d46c374 and 0ec9f55.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (31)
  • .oxfmtrc.json
  • .oxlintrc.json
  • content-collections.ts
  • eslint.config.mjs
  • netlify.toml
  • package.json
  • scripts/mcp-eval/run-eval.ts
  • scripts/test-npm-cache.ts
  • src/builder/api/remote.ts
  • src/components/AILibraryHero.tsx
  • src/components/Doc.tsx
  • src/components/DocsLayout.tsx
  • src/components/ExampleDeployDialog.tsx
  • src/components/StackBlitzEmbed.tsx
  • src/components/TrustedByMarquee.tsx
  • src/components/UserFeedbackSection.tsx
  • src/components/builder/ConfigPanel.tsx
  • src/components/builder/DeployDialog.tsx
  • src/components/builder/ExplorerPanel.tsx
  • src/components/builder/webcontainer/useWebContainerStore.ts
  • src/components/markdown/MarkdownTabsHandler.tsx
  • src/components/markdown/PackageManagerTabs.tsx
  • src/routeTree.gen.ts
  • src/routes/feed.tsx
  • src/routes/partners.tsx
  • src/ui/Icons.tsx
  • src/ui/index.ts
  • src/utils/cache.server.ts
  • src/utils/documents.server.ts
  • tsconfig.json
  • vite.config.ts
💤 Files with no reviewable changes (5)
  • tsconfig.json
  • eslint.config.mjs
  • src/routes/feed.tsx
  • src/routeTree.gen.ts
  • scripts/mcp-eval/run-eval.ts

Comment on lines +125 to 133
<a
href={`${pagePath}.md`}
className="sr-only"
tabIndex={-1}
aria-hidden="true"
>
AI/LLM: This documentation page is available in plain markdown format at
{pagePath}.md
</a>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard optional pagePath before building markdown link.

pagePath is optional, but Line 126 always interpolates it. When absent, this renders undefined.md in both href and text.

💡 Suggested fix
-      <a
-        href={`${pagePath}.md`}
-        className="sr-only"
-        tabIndex={-1}
-        aria-hidden="true"
-      >
-        AI/LLM: This documentation page is available in plain markdown format at
-        {pagePath}.md
-      </a>
+      {pagePath ? (
+        <a
+          href={`${pagePath}.md`}
+          className="sr-only"
+          tabIndex={-1}
+          aria-hidden="true"
+        >
+          AI/LLM: This documentation page is available in plain markdown format at
+          {pagePath}.md
+        </a>
+      ) : null}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a
href={`${pagePath}.md`}
className="sr-only"
tabIndex={-1}
aria-hidden="true"
>
AI/LLM: This documentation page is available in plain markdown format at
{pagePath}.md
</a>
{pagePath ? (
<a
href={`${pagePath}.md`}
className="sr-only"
tabIndex={-1}
aria-hidden="true"
>
AI/LLM: This documentation page is available in plain markdown format at
{pagePath}.md
</a>
) : null}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Doc.tsx` around lines 125 - 133, The anchor builds a markdown
link using the optional variable pagePath (the template `${pagePath}.md` and the
link text), which yields "undefined.md" when pagePath is not provided; fix by
guarding this anchor in the Doc component so it only renders when pagePath is a
non-empty string (or compute a safePath = pagePath ?? '' and check
safePath.length > 0 before rendering), and update the href/text generation to
use that safe value (replace usages of `${pagePath}.md` and the inline
{pagePath}.md text with the guarded/safe value or omit the anchor entirely when
missing).

__html: `
@keyframes marquee { 0% { transform: translateX(0); } 100% { transform: translateX(-33.333%); } }
.animate-\[marquee_linear_infinite\] { animation-name: marquee; animation-timing-function: linear; animation-iteration-count: infinite; }
.animate-[marquee_linear_infinite] { animation-name: marquee; animation-timing-function: linear; animation-iteration-count: infinite; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore escaped class selector for the Tailwind arbitrary animation class.

Line 75 currently uses an unescaped selector, so this rule won’t match class="animate-[marquee_linear_infinite]" and the marquee animation can silently stop applying.

Proposed fix
-          .animate-[marquee_linear_infinite] { animation-name: marquee; animation-timing-function: linear; animation-iteration-count: infinite; }
+          .animate-\[marquee_linear_infinite\] { animation-name: marquee; animation-timing-function: linear; animation-iteration-count: infinite; }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.animate-[marquee_linear_infinite] { animation-name: marquee; animation-timing-function: linear; animation-iteration-count: infinite; }
.animate-\[marquee_linear_infinite\] { animation-name: marquee; animation-timing-function: linear; animation-iteration-count: infinite; }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/TrustedByMarquee.tsx` at line 75, The CSS rule uses an
unescaped selector so it won't match the Tailwind arbitrary class
animate-[marquee_linear_infinite]; update the selector to the escaped form
(escape the square brackets and any special chars) so
.animate-\[marquee_linear_infinite\] targets elements with
class="animate-[marquee_linear_infinite]"; locate the rule near TrustedByMarquee
(the .animate-[marquee_linear_infinite] declaration) and replace the selector
with the escaped version while keeping the animation properties unchanged.

Comment on lines 3 to 11
declare global {
// @ts-expect-error - globalThis.docCache is set in the server entrypoint
var docCache: LRUCache<string, unknown>
}

const docCache =
globalThis.docCache ||
// @ts-expect-error - globalThis.docCache is set in the server entrypoint
(globalThis.docCache = new LRUCache<string, unknown>({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if TypeScript reports unused `@ts-expect-error` directives

# Find tsconfig and run type check to see if there are unused directive warnings
fd -t f 'tsconfig.*\.json$' --max-depth 2 | head -1 | xargs -I{} echo "Found tsconfig: {}"

# Search for how this file is being type-checked
rg -l "cache\.server" --type ts -g '!node_modules'

Repository: TanStack/tanstack.com

Length of output: 177


🏁 Script executed:

cat -n src/utils/cache.server.ts | head -20

Repository: TanStack/tanstack.com

Length of output: 749


🏁 Script executed:

# Run TypeScript type checking to see if there are unused `@ts-expect-error` warnings
npm list typescript 2>/dev/null | head -5

Repository: TanStack/tanstack.com

Length of output: 110


🏁 Script executed:

# Check if TypeScript can find any actual errors without the `@ts-expect-error` directives
# by looking at the tsconfig and trying to understand strict settings
cat tsconfig.json | jq -r '.compilerOptions | {strict, noImplicitAny, declaration}'

Repository: TanStack/tanstack.com

Length of output: 133


🏁 Script executed:

# Run TypeScript compiler to check for errors and unused `@ts-expect-error` directives
npx tsc --noEmit 2>&1 | grep -A 3 "cache.server\|TS2578\|Unused" | head -20

Repository: TanStack/tanstack.com

Length of output: 47


🏁 Script executed:

# Check the actual TypeScript version and strict settings more thoroughly
cat tsconfig.json | head -40

Repository: TanStack/tanstack.com

Length of output: 834


🏁 Script executed:

# Create a temporary test version without `@ts-expect-error` on line 4
cat > /tmp/cache_test.ts << 'EOF'
import { LRUCache } from 'lru-cache'

declare global {
  var docCache: LRUCache<string, unknown>
}

const docCache =
  globalThis.docCache ||
  (globalThis.docCache = new LRUCache<string, unknown>({
    max: 300,
    ttl: 1000,
  }))
EOF

# Try to type-check this version
cd /home/jailuser/git && npx tsc --noEmit --lib DOM,DOM.Iterable,ES2022 --strict --esModuleInterop --module ESNext --moduleResolution Bundler /tmp/cache_test.ts 2>&1

Repository: TanStack/tanstack.com

Length of output: 206


🏁 Script executed:

# Also check if globalThis is properly augmented in the current setup
# by looking at TypeScript's understanding of globalThis.docCache
rg -A 5 "declare global" src/utils/cache.server.ts

Repository: TanStack/tanstack.com

Length of output: 219


🏁 Script executed:

# Backup the original file
cp src/utils/cache.server.ts src/utils/cache.server.ts.bak

# Create a version without the `@ts-expect-error` on line 4 (inside declare global)
cat > src/utils/cache.server.ts << 'EOF'
import { LRUCache } from 'lru-cache'

declare global {
  var docCache: LRUCache<string, unknown>
}

const docCache =
  globalThis.docCache ||
  // `@ts-expect-error` - globalThis.docCache is set in the server entrypoint
  (globalThis.docCache = new LRUCache<string, unknown>({
    max: 300,
    // ttl: 1,
    ttl: process.env.NODE_ENV === 'production' ? 1 : 1000000,
  }))

export async function fetchCached<T>(opts: {
  fn: () => Promise<T>
  key: string
  ttl: number
}) {
  return {}
}
EOF

# Run TypeScript type check
npx tsc --noEmit 2>&1 | grep -E "cache\.server|error TS"

# Restore original
mv src/utils/cache.server.ts.bak src/utils/cache.server.ts

Repository: TanStack/tanstack.com

Length of output: 130


🏁 Script executed:

# Now test removing line 10's suppression while keeping line 4's
cp src/utils/cache.server.ts src/utils/cache.server.ts.bak

cat > src/utils/cache.server.ts << 'EOF'
import { LRUCache } from 'lru-cache'

declare global {
  // `@ts-expect-error` - globalThis.docCache is set in the server entrypoint
  var docCache: LRUCache<string, unknown>
}

const docCache =
  globalThis.docCache ||
  (globalThis.docCache = new LRUCache<string, unknown>({
    max: 300,
    // ttl: 1,
    ttl: process.env.NODE_ENV === 'production' ? 1 : 1000000,
  }))

export async function fetchCached<T>(opts: {
  fn: () => Promise<T>
  key: string
  ttl: number
}) {
  return {}
}
EOF

# Run TypeScript type check
npx tsc --noEmit 2>&1 | grep -E "cache\.server|error TS"

# Restore original
mv src/utils/cache.server.ts.bak src/utils/cache.server.ts

Repository: TanStack/tanstack.com

Length of output: 222


🏁 Script executed:

# Test removing BOTH suppressions
cp src/utils/cache.server.ts src/utils/cache.server.ts.bak

cat > src/utils/cache.server.ts << 'EOF'
import { LRUCache } from 'lru-cache'

declare global {
  var docCache: LRUCache<string, unknown>
}

const docCache =
  globalThis.docCache ||
  (globalThis.docCache = new LRUCache<string, unknown>({
    max: 300,
    // ttl: 1,
    ttl: process.env.NODE_ENV === 'production' ? 1 : 1000000,
  }))

export async function fetchCached<T>(opts: {
  fn: () => Promise<T>
  key: string
  ttl: number
}) {
  return {}
}
EOF

# Run TypeScript type check
npx tsc --noEmit 2>&1 | grep -E "cache\.server|error TS"

# Restore original
mv src/utils/cache.server.ts.bak src/utils/cache.server.ts

Repository: TanStack/tanstack.com

Length of output: 222


🏁 Script executed:

# Check for ESLint configuration that might validate `@ts-expect-error`
fd -t f '.eslintrc*' -o 'eslint.config.*'

Repository: TanStack/tanstack.com

Length of output: 214


🏁 Script executed:

# Look for other `@ts-expect-error` usages to understand the pattern
rg "@ts-expect-error" --type ts --max-count 20

Repository: TanStack/tanstack.com

Length of output: 747


🏁 Script executed:

# Search for other globalThis declarations to understand the pattern
rg "declare global" --type ts -A 3

Repository: TanStack/tanstack.com

Length of output: 780


🏁 Script executed:

# Verify the context of why line 4 might need suppression by checking TypeScript docs
# Look for how globalThis is augmented and if there's any actual error case
rg -B 2 -A 5 "globalThis\." src/utils/cache.server.ts

Repository: TanStack/tanstack.com

Length of output: 400


🏁 Script executed:

# Check if ESLint or other tooling catches unused `@ts-expect-error`
fd -name '.eslintrc*' -o -name 'eslint.config.*' 2>/dev/null

Repository: TanStack/tanstack.com

Length of output: 47


Remove the unnecessary @ts-expect-error on line 4.

The suppression inside the declare global block is non-standard. Other global declarations in the codebase (src/types/css-anchor-positioning.d.ts, src/routes/__root.tsx) do not use @ts-expect-error inside declare global blocks—this is standard TypeScript syntax that does not produce errors. In strict mode, unused @ts-expect-error directives trigger TS2578 errors.

The suppression on line 10 (the assignment) may be necessary and should be retained pending confirmation that it suppresses an actual type error.

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

In `@src/utils/cache.server.ts` around lines 3 - 11, Remove the unnecessary
"@ts-expect-error" inside the declare global block for the docCache global
declaration: update the global augmentation so it simply declares var docCache:
LRUCache<string, unknown> (no suppression), while keeping the existing
"@ts-expect-error" on the assignment expression that sets globalThis.docCache =
new LRUCache(...) in the docCache initialization (retain that suppression if it
prevents a real type error); this touches the declare global block and the
docCache initialization/assignment symbols.

Comment on lines +14 to +18
resolve: {
alias: {
'~': path.resolve(__dirname, './src'),
},
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if 'content-collections' alias is used in imports
rg -n "from ['\"]content-collections['\"]" --type=ts --type=tsx
rg -n "import.*content-collections" --type=ts --type=tsx
# Also check for any direct imports
ast-grep --pattern 'import $_ from "content-collections"'

Repository: TanStack/tanstack.com

Length of output: 120


🏁 Script executed:

# Fix the search - rg doesn't support tsx file type, use ts or search all files
rg "content-collections" --type ts -n
rg "content-collections" -n

Repository: TanStack/tanstack.com

Length of output: 2283


🏁 Script executed:

# Also verify the tsconfig.json definition mentioned in the review
find . -name "tsconfig.json" -type f | head -5

Repository: TanStack/tanstack.com

Length of output: 80


🏁 Script executed:

# Check if there's a .content-collections directory
find . -name "*content-collections*" -type d

Repository: TanStack/tanstack.com

Length of output: 47


Missing content-collections path alias will cause resolution failures.

The tsconfig.json defines two path aliases: ~/*./src/* and content-collections./.content-collections/generated. Only the ~ alias is configured in vite.config.ts. Since vite-tsconfig-paths was removed, imports using the content-collections alias in src/utils/blog.ts and src/routes/blog.$.tsx will fail to resolve at build time.

Proposed fix
   resolve: {
     alias: {
       '~': path.resolve(__dirname, './src'),
+      'content-collections': path.resolve(__dirname, './.content-collections/generated'),
     },
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
resolve: {
alias: {
'~': path.resolve(__dirname, './src'),
},
},
resolve: {
alias: {
'~': path.resolve(__dirname, './src'),
'content-collections': path.resolve(__dirname, './.content-collections/generated'),
},
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vite.config.ts` around lines 14 - 18, The Vite alias configuration is missing
the content-collections mapping which causes imports in src/utils/blog.ts and
src/routes/blog.$.tsx to fail; update the resolve.alias block in vite.config.ts
(where '~' is configured) to add a 'content-collections' alias pointing to the
generated folder (./.content-collections/generated) so that imports using the
content-collections alias resolve correctly (ensure the alias pattern matches
how it's imported, e.g., 'content-collections' or 'content-collections/*'
mapping to path.resolve(__dirname, './.content-collections/generated')).

@tannerlinsley tannerlinsley merged commit e7ac541 into TanStack:main Apr 1, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants