Skip to content

feat: version aware minimum version badge - #2327

Open
OrbisK wants to merge 26 commits into
nuxt:mainfrom
OrbisK:feat/version-aware-min-badge
Open

feat: version aware minimum version badge#2327
OrbisK wants to merge 26 commits into
nuxt:mainfrom
OrbisK:feat/version-aware-min-badge

Conversation

@OrbisK

@OrbisK OrbisK commented Jul 19, 2026

Copy link
Copy Markdown
Member

🔗 Linked issue

Followup on #2203

📚 Description

This PR aims to only show the minimalVersion Badge, if it matches the current major (of higher - but this should be unlikely), so it reduces noise on e.g. v4 docs by not displaying any v3 related badges that are already included/not relevant.

Possible Followups:

  • I aim to replace all :bage[vX.Y] in the documentation to use :versionBadge to achive the same effect.
  • Show version badge in sidebar if major + minor matches
image

Ibochkarev and others added 11 commits March 11, 2026 22:48
- Add minimalVersion to docs collection schemas (docsv3, docsv4, docsv5)
- Render version badge in docs page header when frontmatter has minimalVersion
- Badge shows vX.Y (e.g. v3.12), info color, with aria-label for a11y

Complements nuxt/nuxt#34485: API docs set minimalVersion in frontmatter;
this repo displays the badge so global inline badges are not needed.
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
Co-authored-by: Robin <robin.kehl@singular-it.de>
Co-authored-by: Robin <robin.kehl@singular-it.de>
Co-authored-by: Robin <robin.kehl@singular-it.de>
Co-authored-by: Robin <robin.kehl@singular-it.de>
Co-authored-by: Robin <robin.kehl@singular-it.de>
@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

@OrbisK is attempting to deploy a commit to the Nuxt Team on Vercel.

A member of the Team first needs to authorize it.

@OrbisK OrbisK changed the title Feat/version aware min badge feat: version aware minimu version badge Jul 19, 2026
@OrbisK OrbisK changed the title feat: version aware minimu version badge feat: version aware minimum version badge Jul 19, 2026
OrbisK and others added 4 commits July 19, 2026 18:19
Removes the z.preprocess wrapper around minimalVersion in the docsv3/
docsv4/docsv5 collection schemas in favor of a plain z.string().optional().
Trimming is now done consistently in the docs page template instead.

This is a defensive simplification; it does not touch the underlying
cause of the Vercel preview build failure (SQLITE_UNKNOWN: table
_content_docsv3 has 13 columns but 14 values were supplied), which
looks like a stale/pre-existing _content_docsv3 table on the preview's
content database predating this schema change. Nuxt Content only ever
emits CREATE TABLE IF NOT EXISTS (never ALTER TABLE), so an existing
table with the old 13-column shape won't pick up the new column
automatically; a redeploy without build cache is likely needed to
fully resolve the build failure.
OrbisK added 3 commits July 28, 2026 12:01
Keeps the VersionBadge component (tolerance-aware) over the inline UBadge
from the PR, and takes the PR's simplified `minimalVersion: z.string()`
content schema. Also brings in upstream main, which the PR head had merged.
@OrbisK
OrbisK marked this pull request as ready for review July 28, 2026 10:32
@OrbisK
OrbisK requested a review from atinux as a code owner July 28, 2026 10:32
@OrbisK

OrbisK commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

@HugoRCD I think its ready for review.

I have extracted a composable that performs all the tolerance logic.

Versions in the sidebar are only displayed if the minor version is within the last two minor versions, so as to reduce the noise.

We can adjust this value here:

https://github.com/OrbisK/nuxt.com/blob/00f1737092c771cb01623c563a182a6fb06a9863/app/pages/docs/%5B...slug%5D.vue#L35

Other badges (from the documentation tables and headlines) are displayed if they match the current major version.

Higher versions are always displayed, just in case we merge some v4 documents into v3 documents.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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

Walkthrough

Adds version keyword formatting, release and nightly paths, semver tolerance checks, latest-version resolution with cancellable requests, and release article lookup. Navigation data now includes minimum-version metadata. Documentation pages recursively apply version badges to navigation items and render linked VersionBadge components in page titles.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: version-aware minimum version badges.
Description check ✅ Passed The description matches the badge-visibility and sidebar version-badge changes in the diff.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@content.config.ts`:
- Around line 220-239: Update the shared collection schema used by docsv3,
docsv4, and docsv5 so minimalVersion accepts both YAML strings and numbers,
trims the normalized string value, and remains optional. Reuse this schema
across all three minimalVersion fields instead of keeping z.string().optional()
separately.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 92c220a9-f9ec-4ba8-8289-b8f2db63574d

📥 Commits

Reviewing files that changed from the base of the PR and between aa12207 and 00f1737.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • app/components/content/VersionBadge.vue
  • app/composables/useDocsVersion.ts
  • app/composables/useVersionBadge.ts
  • app/pages/docs/[...slug].vue
  • app/utils/version.ts
  • content.config.ts
  • package.json
  • server/api/navigation.json.get.ts

Comment thread content.config.ts
Comment on lines +220 to +239
links: z.array(Button),
minimalVersion: z.string().optional()
})
}),
docsv4: defineCollection({
type: 'page',
source: [docsV4Source, examplesV4Source],
schema: z.object({
titleTemplate: z.string().optional(),
links: z.array(Button)
links: z.array(Button),
minimalVersion: z.string().optional()
})
}),
docsv3: defineCollection({
type: 'page',
source: [docsV3Source, examplesV3Source],
schema: z.object({
titleTemplate: z.string().optional(),
links: z.array(Button)
links: z.array(Button),
minimalVersion: z.string().optional()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate content.config.ts =="
fd -a 'content\.config\.ts$' . || true

echo "== relevant lines =="
if [ -f content.config.ts ]; then
  nl -ba content.config.ts | sed -n '1,280p'
fi

echo "== search minimalVersion usages =="
rg -n "minimalVersion|TitleTemplate|minimal|version" -S --glob '!node_modules' --glob '!dist' --glob '!build' . | head -200

Repository: nuxt/nuxt.com

Length of output: 280


🌐 Web query:

Zod 4 z.string input values number string accepts number transforms number to string optional

💡 Result:

In Zod, standard string schemas (defined via z.string) are strict and do not accept numbers as valid input; they expect input of type string [1][2][3]. If you pass a number to z.string, Zod will throw a validation error [3][4]. To handle cases where you need to accept numbers and convert them into strings, or to make the input optional, you should use the following patterns: Accepting numbers and converting them to strings If you want to accept a number (or other input) and coerce it into a string during parsing, use z.coerce.string [5][6]: const schema = z.coerce.string; schema.parse(123); // "123" schema.parse("hello"); // "hello" Unlike.transform, which runs after validation, z.coerce.string runs before validation and uses the JavaScript String constructor to convert the input [5][6]. Making the string optional To make any schema optional (including coerced ones), chain the.optional method [3][4]. This allows the value to be undefined: const schema = z.coerce.string.optional; schema.parse(undefined); // undefined schema.parse(123); // "123" Summary of approaches - For strict string validation: Use z.string [1][2]. - For flexible input (accepting numbers and converting to strings): Use z.coerce.string [5][6]. - For optional fields: Append.optional to your schema [3][4]. - For custom transformation logic: If coercion via String is insufficient, you can use.transform to convert data after initial validation, or.preprocess to handle inputs before validation [7][4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant content.config.ts lines =="
sed -n '1,280p' content.config.ts | awk '{printf "%6d  %s\n", NR, $0}'

echo "== search minimalVersion usages =="
rg -n "minimalVersion|minimalVersion:" -S . || true

echo "== package zod versions =="
if [ -f package.json ]; then jq '.dependencies , .devDependencies // {}' package.json | sed -n '1,160p'; fi

Repository: nuxt/nuxt.com

Length of output: 13647


🌐 Web query:

Zod 4 z.coerce.string z.string number whitespace trim transforms trim documentation

💡 Result:

In Zod 4, coercion and string transformations function as follows based on the official documentation [1][2]. Zod Coercion The z.coerce namespace is used to automatically convert input data to a specified type before validation [3][4]. For strings, z.coerce.string applies the JavaScript String constructor to the input [1][4]. const schema = z.coerce.string; schema.parse(42); // "42" schema.parse(true); // "true" String Trimming and Transforms Zod provides a built-in.trim method for ZodString schemas, which removes whitespace from both ends of the input string [5][6]. This method returns a new ZodString instance, allowing for further chaining of string-specific validation methods (such as.min,.max,.email, etc.) [7]. Important Considerations: 1. Chaining: Methods like.trim return a ZodString instance, preserving compatibility with other string validations [7]. Conversely, using.transform creates a ZodEffects wrapper, which may obscure string-specific methods unless you use.pipe to restore the schema type [7]. 2. Validation vs. Transformation: Some specific validators (e.g., z.url, z.email) do not automatically trim whitespace, even if the underlying native constructor (like URL) might do so internally [8]. If you require a trimmed input to be validated by such helpers, it is recommended to explicitly use.trim followed by.pipe [8]: z.string.trim.pipe(z.url); 3. Zod 4 Availability: Zod 4 is the current stable major version [2][9]. It introduces significant performance improvements and fixes various long-standing design limitations found in previous versions [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== inspect docs where minimalVersion frontmatter is currently used =="
rg -n "minimalVersion|minimal-version|minimalVersion:" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || true

echo "== inspect consumer code =="
sed -n '1,320p' app/pages/docs/[...slug].vue | awk '{printf "%6d  %s\n", NR, $0}'

Repository: nuxt/nuxt.com

Length of output: 13958


Accept numeric minimalVersion and normalize it in the collection schema.

docsv3/4/5 schemas use z.string().optional(), so YAML values like minimalVersion: 3.12 validate as numbers and are rejected before badges can normalize them. Use a shared optional string coerced/transformed from both string and number input and trim it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content.config.ts` around lines 220 - 239, Update the shared collection
schema used by docsv3, docsv4, and docsv5 so minimalVersion accepts both YAML
strings and numbers, trims the normalized string value, and remains optional.
Reuse this schema across all three minimalVersion fields instead of keeping
z.string().optional() separately.

Comment thread content.config.ts
titleTemplate: z.string().optional(),
links: z.array(Button)
links: z.array(Button),
minimalVersion: z.string().optional()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@HugoRCD I think we need the process you removed to ensure that it doesnt fail on numbers 🤔

@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nuxt Ready Ready Preview, Comment Jul 29, 2026 2:27pm

Request Review

@OrbisK

OrbisK commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

I have added a nightly shortcut to also display pending/unrealeased changes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
test/nuxt/index.spec.ts (1)

204-213: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover threshold boundaries and all tolerance granularities.

versionThreshold drives badge visibility, but the suite only exercises one minor-tolerance path indirectly. Add direct assertions for major, minor-boundary, patch, invalid-latest, and newer-major behavior.

Suggested coverage
+  describe('versionThreshold', () => {
+    it('computes each tolerance granularity', () => {
+      expect(versionThreshold('4.5.2', { major: 0 })).toBe('4.0.0')
+      expect(versionThreshold('4.5.2', { minor: 2 })).toBe('4.3.0')
+      expect(versionThreshold('4.5.2', { patch: 2 })).toBe('4.5.0')
+      expect(versionThreshold('nope')).toBeUndefined()
+    })
+  })
+
       expect(satisfiesVersionTolerance('4.4.0', '4.5.2', { minor: 2 })).toBe(true)
+      expect(satisfiesVersionTolerance('4.3.0', '4.5.2', { minor: 2 })).toBe(true)
       expect(satisfiesVersionTolerance('4.2.0', '4.5.2', { minor: 2 })).toBe(false)
+      expect(satisfiesVersionTolerance('5.0.0', '4.5.2', { major: 0 })).toBe(true)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/nuxt/index.spec.ts` around lines 204 - 213, Expand the
satisfiesVersionTolerance test suite to directly cover every tolerance
granularity and threshold boundary: major tolerance, minor values at and beyond
the boundary, patch tolerance, invalid latest-version input, and versions from a
newer major release. Keep the existing keyword and minor-range assertions, and
assert the expected true/false outcomes for each boundary case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/nuxt/index.spec.ts`:
- Around line 204-213: Expand the satisfiesVersionTolerance test suite to
directly cover every tolerance granularity and threshold boundary: major
tolerance, minor values at and beyond the boundary, patch tolerance, invalid
latest-version input, and versions from a newer major release. Keep the existing
keyword and minor-range assertions, and assert the expected true/false outcomes
for each boundary case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 58fe2ffb-25b7-4697-b798-fc915735b2c5

📥 Commits

Reviewing files that changed from the base of the PR and between 397d073 and a3d2141.

📒 Files selected for processing (5)
  • app/components/content/VersionBadge.vue
  • app/composables/useVersionBadge.ts
  • app/pages/docs/[...slug].vue
  • app/utils/version.ts
  • test/nuxt/index.spec.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/composables/useVersionBadge.ts
  • app/pages/docs/[...slug].vue
  • app/components/content/VersionBadge.vue

@OrbisK
OrbisK marked this pull request as draft July 28, 2026 16:03
@OrbisK

OrbisK commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

converted to draft. I will slighly rework the nightly shortcut.

  1. the trigger keyword should be unreleased
  2. we may need a shorter label for navigation

@OrbisK

OrbisK commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

switching to :versionBadge should also solve the issue that versions are part of the heading, resulting in content nav pollution and noisy hash links:

image

@OrbisK

OrbisK commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

unreleased is displayed like this:

image

I have used "soon" for navigation as a shorter label

@OrbisK

OrbisK commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

Nightly version tags now link to https://nuxt.com/docs/4.x/guide/going-further/nightly-release-channel

Others to the minor blog post.

(excluding navigation tags)

@OrbisK
OrbisK marked this pull request as ready for review July 29, 2026 10:15
@HugoRCD

HugoRCD commented Jul 29, 2026

Copy link
Copy Markdown
Member

@OrbisK Am I crazy or is the "soon" not centered?
CleanShot 2026-07-29 at 14 05 58@2x

@OrbisK

OrbisK commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

@OrbisK Am I crazy or is the "soon" not centered? CleanShot 2026-07-29 at 14 05 58@2x

what about

image

🤔

@HugoRCD

HugoRCD commented Jul 29, 2026

Copy link
Copy Markdown
Member

@OrbisK Am I crazy or is the "soon" not centered? CleanShot 2026-07-29 at 14 05 58@2x

what about

image 🤔

Maybe a tiny bit too big, but I'm nitpicking

@OrbisK

OrbisK commented Jul 29, 2026

Copy link
Copy Markdown
Member Author
image

@HugoRCD

@HugoRCD

HugoRCD commented Jul 29, 2026

Copy link
Copy Markdown
Member

@OrbisK
i-love-it-chefs-kiss-gif-by-magic-the-gathering

Comment on lines +46 to +54
return {
// The sidebar has no room for `nightly v4`
'label': labels.shortLabel,
'size': 'sm' as const,
'color': 'info' as const,
'variant': 'subtle' as const,
'aria-label': labels.ariaLabel
}
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@HugoRCD if you want to add some classes to the navigation badge, you can do this here

Comment thread app/pages/docs/[...slug].vue Outdated
Comment thread app/utils/version.ts Outdated
Co-authored-by: Robin <robin.kehl@singular-it.de>
Comment thread test/nuxt/index.spec.ts Outdated
Co-authored-by: Robin <robin.kehl@singular-it.de>
@OrbisK

OrbisK commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

had to only uppercase Soon so that it would not affect vX.Y

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.

5 participants