这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 28, 2025

The Valibot plugin generates v.object({}) for additionalProperties with type definitions, causing silent data loss as Valibot strips unknown keys by default.

Changes

Modified packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts:

  • Condition now handles any additionalProperties with a schema, not just type: 'object'
  • Objects with only additionalPropertiesv.record(v.string(), <valueSchema>)
  • Objects with properties + additionalPropertiesv.objectWithRest(<properties>, <valueSchema>)

Added test coverage:

  • 15 tests covering string, number, boolean, and object additional property types
  • Tests validate both preservation and type checking of additional properties

Example

Before:

// OpenAPI: additionalProperties: { type: string }
export const vCreateChallengeBody = v.object({
    headers: v.optional(v.object({}))  // ❌ strips all keys
});

After:

// OpenAPI: additionalProperties: { type: string }
export const vCreateChallengeBody = v.object({
    headers: v.optional(v.record(v.string(), v.string()))
});

// OpenAPI: properties + additionalProperties
export const vSchema = v.objectWithRest({
    id: v.optional(v.string()),
    count: v.optional(v.pipe(v.number(), v.integer()))
}, v.number());

Breaking Change

Updates 9 snapshots. Free-form objects (additionalProperties: true or {}) now generate v.record(v.string(), v.unknown()) instead of v.object({}), aligning with OpenAPI semantics. Users relying on automatic key stripping will need to explicitly use additionalProperties: false.

Original prompt

This section details on the original issue you should resolve

<issue_title>Valibot plugin: additionalProperties with type converts to v.object({}) instead of v.record()</issue_title>
<issue_description>### Description

The Valibot plugin incorrectly handles additionalProperties when it contains a type definition. Instead of generating v.record(), it generates v.object({}), which causes silent data loss at runtime.
Valibot's v.object({}) removes unknown keys by default. This means all additional properties are stripped during validation without any error or warning.

Current Behavior

OpenAPI Spec:

CreateChallengeBody:
  type: object
  properties:
    headers:
      type: object
      additionalProperties:
        type: string

Generated Valibot Schema:

export const vCreateChallengeBody = v.object({
    headers: v.optional(v.object({}))
});

Runtime Result:

const input = {
  headers: {
    'Authorization': 'Bearer token',
    'Content-Type': 'application/json'
  }
};

const result = v.parse(vCreateChallengeBody, input);
console.log(result.headers); // {} ❌ All properties are lost!

Expected Behavior

Expected Valibot Schema:

export const vCreateChallengeBody = v.object({
    headers: v.optional(v.record(v.string(), v.string()))
});

Expected Runtime Result:

const result = v.parse(vCreateChallengeBody, input);
console.log(result.headers); 
// { 'Authorization': 'Bearer token', 'Content-Type': 'application/json' } ✅

Root Cause

The issue is in packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts at lines 75-78:

if (
  schema.additionalProperties &&
  schema.additionalProperties.type === 'object' &&  // ❌ Only handles 'object' type
  !Object.keys(properties).length
) {

This condition only converts to v.record() when:

  • additionalProperties.type === 'object'
  • No named properties exist

It fails to handle:

  • type: 'string', type: 'number', etc.
  • additionalProperties: true
  • additionalProperties: {}

Reproducible example or configuration

import { defineConfig } from '@hey-api/openapi-ts';

export default defineConfig({
  client: '@hey-api/client-fetch',
  input: 'openapi.yaml',
  output: 'src/client',
  plugins: [
    '@hey-api/typescript',
    {
      name: 'valibot',
    },
  ],
});
  1. Use the OpenAPI spec below
  2. Run npx @hey-api/openapi-ts
  3. Check the generated Valibot schema
  4. Try validating data with additional properties
  5. Observe data loss

OpenAPI specification (optional)

openapi: 3.0.0
info:
title: Minimal Example
version: 1.0.0
paths:
/test:
post:
operationId: CreateChallenge
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
headers:
type: object
additionalProperties:
type: string
responses:
'200':
description: Success

System information (optional)

  • @hey-api/openapi-ts version: 0.83.1
  • Node.js version: v20.x
  • OS: macOS
  • Valibot version: Latest</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@changeset-bot
Copy link

changeset-bot bot commented Oct 28, 2025

🦋 Changeset detected

Latest commit: da88dd9

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

This PR includes changesets to release 1 package
Name Type
@hey-api/openapi-ts 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

@vercel
Copy link

vercel bot commented Oct 28, 2025

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

Project Deployment Preview Comments Updated (UTC)
hey-api-docs Ready Ready Preview Comment Oct 28, 2025 9:49am

…h types

Fixed the Valibot plugin to correctly handle additionalProperties with type definitions. Now generates v.record() instead of v.object({}) to prevent silent data loss.

- Modified object.ts to check for any additionalProperties.type (not just 'object')
- Objects with only additionalProperties: generate v.record(v.string(), <valueSchema>)
- Objects with properties AND additionalProperties: generate v.objectWithRest({properties}, <valueSchema>)

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Updated test snapshots to reflect the corrected behavior for additionalProperties. The fix now properly generates:
- v.record() for objects with only additionalProperties
- v.objectWithRest() for objects with both properties and additionalProperties

This correctly handles free-form objects per OpenAPI spec defaults.

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Valibot plugin handling of additionalProperties type fix(valibot): generate v.record() for additionalProperties with typed schemas Oct 28, 2025
Copilot AI requested a review from mrlubos October 28, 2025 08:53
Copilot finished work on behalf of mrlubos October 28, 2025 08:53
@codecov
Copy link

codecov bot commented Oct 28, 2025

Codecov Report

❌ Patch coverage is 0% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 30.58%. Comparing base (a71d840) to head (da88dd9).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
.../openapi-ts/src/plugins/valibot/v1/toAst/object.ts 0.00% 25 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2870      +/-   ##
==========================================
- Coverage   30.59%   30.58%   -0.02%     
==========================================
  Files         488      488              
  Lines       39938    39953      +15     
  Branches     2442     2442              
==========================================
  Hits        12219    12219              
- Misses      27685    27700      +15     
  Partials       34       34              
Flag Coverage Δ
unittests 30.58% <0.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Oct 28, 2025
@mrlubos mrlubos marked this pull request as ready for review October 28, 2025 09:49
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Oct 28, 2025
@dosubot dosubot bot added the bug 🔥 Something isn't working label Oct 28, 2025
@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 28, 2025

Open in StackBlitz

npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/codegen-core@2870
npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/nuxt@2870
npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/openapi-ts@2870
npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/vite-plugin@2870

commit: da88dd9

@mrlubos mrlubos merged commit 0229551 into main Oct 28, 2025
15 of 17 checks passed
@mrlubos mrlubos deleted the copilot/fix-valibot-additional-properties branch October 28, 2025 10:01
@hey-api hey-api bot mentioned this pull request Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🔥 Something isn't working lgtm This PR has been approved by a maintainer size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Valibot plugin: additionalProperties with type converts to v.object({}) instead of v.record()

2 participants