nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: danielgtaylor/huma
Pull request #69 (2022-09-20 21:08:04)

feat: add deprecated flag to operations
This adds support for the [OpenAPI flag/marker deprecated](https://swagger.io/specification/#fixed-fields-8) for operations.


Patch:
diff --git a/operation.go b/operation.go
index fc5091f..0108a6f 100644
--- a/operation.go
+++ b/operation.go
@@ -56,6 +56,7 @@ type Operation struct {
 	responses          []Response
 	maxBodyBytes       int64
 	bodyReadTimeout    time.Duration
+	deprecated         bool
 }
 
 func newOperation(resource *Resource, method, id, docs string, responses []Response) *Operation {
@@ -72,6 +73,7 @@ func newOperation(resource *Resource, method, id, docs string, responses []Respo
 		maxBodyBytes: 1024 * 1024,
 		// 15 second timeout by default
 		bodyReadTimeout: resource.router.defaultBodyReadTimeout,
+		deprecated:      false,
 	}
 }
 
@@ -85,6 +87,9 @@ func (o *Operation) toOpenAPI(components *oaComponents) *gabs.Container {
 	if o.description != "" {
 		doc.Set(o.description, "description")
 	}
+	if o.deprecated {
+		doc.Set(o.deprecated, "deprecated")
+	}
 
 	// Request params
 	for _, param := range o.params {
@@ -188,6 +193,12 @@ func (o *Operation) RequestSchema(s *schema.Schema) {
 	o.RequestSchemaForContentType("application/json", s)
 }
 
+// Deprecated marks the operation is deprecated, warning consumers should
+// refrain from using this.
+func (o *Operation) Deprecated() {
+	o.deprecated = true
+}
+
 func (o *Operation) RequestSchemaForContentType(ct string, s *schema.Schema) {
 	if o.requests[ct] == nil {
 		o.requests[ct] = &request{}


Test patch:
diff --git a/operation_test.go b/operation_test.go
new file mode 100644
index 0000000..1cffa54
--- /dev/null
+++ b/operation_test.go
@@ -0,0 +1,22 @@
+package huma
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestOperation(t *testing.T) {
+	op := Operation{}
+
+	assert.Equal(t, op.toOpenAPI(&oaComponents{}).Data(), map[string]interface{}{
+		"operationId": "",
+	})
+}
+
+func TestDeprecatedOperation(t *testing.T) {
+	op := Operation{}
+	op.Deprecated()
+
+	assert.Contains(t, op.toOpenAPI(&oaComponents{}).Data(), "deprecated")
+}
Repository: danielgtaylor/huma
Pull request #70 (2022-09-21 21:46:37)

fix: auto-mark patch deprecated
This will mark auto-generated `PATCH` operations to also be flagged as `deprecated` if the corresponding `PUT` operation is flagged as so. 


Patch:
diff --git a/patch.go b/patch.go
index e8c88be..35b4140 100644
--- a/patch.go
+++ b/patch.go
@@ -168,7 +168,8 @@ func generatePatch(resource *Resource, get *Operation, put *Operation) {
 				model:    jsonPatchType,
 			},
 		},
-		responses: responses,
+		responses:  responses,
+		deprecated: put.deprecated,
 	})
 
 	// Manually register the handler with the router. This bypasses the normal


Test patch:
diff --git a/patch_test.go b/patch_test.go
index c7c3edc..73ff60e 100644
--- a/patch_test.go
+++ b/patch_test.go
@@ -200,3 +200,30 @@ func TestPatchPutNoBody(t *testing.T) {
 	app.ServeHTTP(w, req)
 	assert.Equal(t, http.StatusMethodNotAllowed, w.Code, w.Body.String())
 }
+
+func TestDeprecatedPatch(t *testing.T) {
+	app := newTestRouter()
+	things := app.Resource("/things/{thing-id}")
+
+	things.Get("get-thing", "docs",
+		NewResponse(http.StatusOK, "OK").Model(&ThingModel{}),
+	).Run(func(ctx Context, input struct {
+		ThingIDParam
+	}) {
+		ctx.WriteModel(http.StatusOK, &ThingModel{})
+	})
+
+	put := things.Put("put-thing", "docs",
+		NewResponse(http.StatusOK, "OK").Model(&ThingModel{}),
+	)
+	put.Deprecated()
+	put.Run(func(ctx Context, input struct {
+		ThingIDParam
+		Body ThingModel
+	}) {
+		ctx.WriteModel(http.StatusOK, &ThingModel{})
+	})
+
+	app.setupDocs()
+	assert.Contains(t, app.OpenAPI().Search("paths", "/things/{thing-id}", "patch").String(), "deprecated")
+}
Repository: danielgtaylor/huma
Pull request #95 (2023-03-13 19:50:48)

Add stoplight elements docs handler option


Patch:
diff --git a/docs.go b/docs.go
index 3605423..9ab01cf 100644
--- a/docs.go
+++ b/docs.go
@@ -127,3 +127,31 @@ func SwaggerUIHandler(router *Router) http.Handler {
 </html>`, router.GetTitle(), router.OpenAPIPath())))
 	})
 }
+
+// StoplightElementsHandler renders documentation using Stoplight Elements.
+func StoplightElementsHandler(router *Router) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "text/html")
+		w.Write([]byte(fmt.Sprintf(`<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <title>%s</title>
+    <!-- Embed elements Elements via Web Component -->
+    <script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
+    <link rel="stylesheet" href="https://unpkg.com/@stoplight/elements/styles.min.css">
+  </head>
+  <body>
+
+    <elements-api
+      apiDescriptionUrl="%s"
+      router="hash"
+      layout="sidebar"
+      style="display:flex;flex-direction:column;height:100vh;"
+    />
+
+  </body>
+</html>`, router.GetTitle(), router.OpenAPIPath())))
+	})
+}


Test patch:
diff --git a/docs_test.go b/docs_test.go
index fdc5a5b..5c4f0fd 100644
--- a/docs_test.go
+++ b/docs_test.go
@@ -15,6 +15,7 @@ var handlers = []struct {
 	{"RapiDoc", RapiDocHandler(New("Test API", "1.0.0"))},
 	{"ReDoc", ReDocHandler(New("Test API", "1.0.0"))},
 	{"SwaggerUI", SwaggerUIHandler(New("Test API", "1.0.0"))},
+	{"StoplightElements", StoplightElementsHandler(New("Test API", "1.0.0"))},
 }
 
 func TestDocHandlers(outer *testing.T) {
Repository: danielgtaylor/huma
Pull request #115 (2023-08-31 04:24:41)

fix: better support of generic named types
Simpler refs & links when using named types with generics since `[` and `]` don't work well.


Patch:
diff --git a/registry.go b/registry.go
index 8b6356c..9773be9 100644
--- a/registry.go
+++ b/registry.go
@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"reflect"
+	"strings"
 )
 
 // Registry creates and stores schemas and their references, and supports
@@ -16,18 +17,22 @@ type Registry interface {
 	SchemaFromRef(ref string) *Schema
 	TypeFromRef(ref string) reflect.Type
 	Map() map[string]*Schema
-	MarshalJSON() ([]byte, error)
-	MarshalYAML() (interface{}, error)
 }
 
 // DefaultSchemaNamer provides schema names for types. It uses the type name
-// when possible, ignoring the package name. If the type is unnamed, then
-// the name hint is used.
+// when possible, ignoring the package name. If the type is generic, e.g.
+// `MyType[SubType]`, then the brackets are removed like `MyTypeSubType`.
+// If the type is unnamed, then the name hint is used.
 // Note: if you plan to use types with the same name from different packages,
 // you should implement your own namer function to prevent issues. Nested
 // anonymous types can also present naming issues.
 func DefaultSchemaNamer(t reflect.Type, hint string) string {
 	name := deref(t).Name()
+
+	// Fix up generics, if used, for nicer refs & URLs.
+	name = strings.ReplaceAll(name, "[", "")
+	name = strings.ReplaceAll(name, "]", "")
+
 	if name == "" {
 		name = hint
 	}


Test patch:
diff --git a/schema_test.go b/schema_test.go
index f6649dc..c04968b 100644
--- a/schema_test.go
+++ b/schema_test.go
@@ -425,6 +425,20 @@ func TestSchemaOld(t *testing.T) {
 	// fmt.Println(string(b))
 }
 
+func TestSchemaGenericNaming(t *testing.T) {
+	type SchemaGeneric[T any] struct {
+		Value T `json:"value"`
+	}
+
+	r := NewMapRegistry("#/components/schemas/", DefaultSchemaNamer)
+	s := r.Schema(reflect.TypeOf(SchemaGeneric[int]{}), true, "")
+
+	b, _ := json.Marshal(s)
+	assert.JSONEq(t, `{
+		"$ref": "#/components/schemas/SchemaGenericint"
+	}`, string(b))
+}
+
 type BenchSub struct {
 	Visible bool      `json:"visible" default:"true"`
 	Metrics []float64 `json:"metrics" maxItems:"31"`
Repository: danielgtaylor/huma
Pull request #177 (2023-11-22 18:15:58)

fix: use 415 status for bad input content type
Return a 415 when the body unmarshaling fails due to the client-reported content type.


Patch:
diff --git a/api.go b/api.go
index 5b3d9e4..30ecc9c 100644
--- a/api.go
+++ b/api.go
@@ -3,6 +3,7 @@ package huma
 import (
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io"
 	"mime/multipart"
@@ -19,6 +20,8 @@ import (
 
 var rxSchema = regexp.MustCompile(`#/components/schemas/([^"]+)`)
 
+var ErrUnknownContentType = errors.New("unknown content type")
+
 // Resolver runs a `Resolve` function after a request has been parsed, enabling
 // you to run custom validation or other code that can modify the request and /
 // or return errors.
@@ -229,7 +232,7 @@ func (a *api) Unmarshal(contentType string, data []byte, v any) error {
 	}
 	f, ok := a.formats[ct]
 	if !ok {
-		return fmt.Errorf("unknown content type: %s", contentType)
+		return fmt.Errorf("%w: %s", ErrUnknownContentType, contentType)
 	}
 	return f.Unmarshal(data, v)
 }
diff --git a/huma.go b/huma.go
index 547f654..4f89e42 100644
--- a/huma.go
+++ b/huma.go
@@ -10,6 +10,7 @@ package huma
 import (
 	"bytes"
 	"context"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -824,8 +825,10 @@ func Register[I, O any](api API, op Operation, handler func(context.Context, *I)
 					// expected struct type to call the handler.
 					var parsed any
 					if err := api.Unmarshal(ctx.Header("Content-Type"), body, &parsed); err != nil {
-						// TODO: handle not acceptable
 						errStatus = http.StatusBadRequest
+						if errors.Is(err, ErrUnknownContentType) {
+							errStatus = http.StatusUnsupportedMediaType
+						}
 						res.Errors = append(res.Errors, &ErrorDetail{
 							Location: "body",
 							Message:  err.Error(),


Test patch:
diff --git a/huma_test.go b/huma_test.go
index 7b02df5..21af041 100644
--- a/huma_test.go
+++ b/huma_test.go
@@ -292,6 +292,31 @@ func TestFeatures(t *testing.T) {
 				assert.Equal(t, http.StatusBadRequest, resp.Code)
 			},
 		},
+		{
+			Name: "request-body-unsupported-media-type",
+			Register: func(t *testing.T, api huma.API) {
+				huma.Register(api, huma.Operation{
+					Method: http.MethodPut,
+					Path:   "/body",
+				}, func(ctx context.Context, input *struct {
+					RawBody []byte
+					Body    struct {
+						Name string `json:"name"`
+					}
+				}) (*struct{}, error) {
+					assert.Equal(t, `{"name":"foo"}`, string(input.RawBody))
+					assert.Equal(t, "foo", input.Body.Name)
+					return nil, nil
+				})
+			},
+			Method:  http.MethodPut,
+			URL:     "/body",
+			Headers: map[string]string{"Content-Type": "application/foo"},
+			Body:    `abcd`,
+			Assert: func(t *testing.T, resp *httptest.ResponseRecorder) {
+				assert.Equal(t, http.StatusUnsupportedMediaType, resp.Code)
+			},
+		},
 		{
 			Name: "request-body-file-upload",
 			Register: func(t *testing.T, api huma.API) {
Repository: danielgtaylor/huma
Pull request #196 (2024-01-03 05:55:54)

fix: better validation of manual schemas
Manually created schemas were not having `propertyNames` and `requiredMap` set up, which meant that validation of the inputs for those manual schemas was incomplete. This fixes it by backfilling any pre-computed data during the `PrecomputeMessages()` call, ensuring the validation works as expected.

This is related to some more complex scenarios described in #185 where schemas can't be generated from structs.


Patch:
diff --git a/schema.go b/schema.go
index e981975..06c7fd3 100644
--- a/schema.go
+++ b/schema.go
@@ -168,6 +168,28 @@ func (s *Schema) PrecomputeMessages() {
 		}
 	}
 
+	if s.propertyNames == nil {
+		s.propertyNames = make([]string, 0, len(s.Properties))
+		for name := range s.Properties {
+			s.propertyNames = append(s.propertyNames, name)
+		}
+	}
+
+	if s.requiredMap == nil {
+		s.requiredMap = map[string]bool{}
+		for _, name := range s.Required {
+			s.requiredMap[name] = true
+		}
+	}
+
+	if s.Items != nil {
+		s.Items.PrecomputeMessages()
+	}
+
+	for _, prop := range s.Properties {
+		prop.PrecomputeMessages()
+	}
+
 	for _, sub := range s.OneOf {
 		sub.PrecomputeMessages()
 	}


Test patch:
diff --git a/validate_test.go b/validate_test.go
index 517fc9d..b685f79 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -893,6 +893,18 @@ var validateTests = []struct {
 		input: map[any]any{"items": []any{map[any]any{}}},
 		errs:  []string{"expected required property value to be present"},
 	},
+	{
+		name: "manual object property required",
+		s: &huma.Schema{
+			Type:     huma.TypeObject,
+			Required: []string{"value"},
+			Properties: map[string]*huma.Schema{
+				"value": {Type: huma.TypeString},
+			},
+		},
+		input: map[string]any{},
+		errs:  []string{"expected required property value to be present"},
+	},
 	{
 		name: "enum success",
 		typ: reflect.TypeOf(struct {
Repository: danielgtaylor/huma
Pull request #199 (2024-01-04 16:12:19)

fix ref name contains recursive brackets '[]'
PR #195 fixed ISSUE #189. But regex matched a shorter string when a generic parameter is an slice( that means there's embedded brackets). 

And the expression is more complex when the generic parameter is another generic type. 

Propose to use a full path name as  the name is used as an ID and reference in the yaml. Readability is trivial. 


Patch:
diff --git a/.gitignore b/.gitignore
index e8cd0ba..a879595 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ mem.out
 docs/site
 docs/__pycache__
 docs/.cache
+.idea/
diff --git a/registry.go b/registry.go
index 813a3de..06011f8 100644
--- a/registry.go
+++ b/registry.go
@@ -4,14 +4,9 @@ import (
 	"encoding/json"
 	"fmt"
 	"reflect"
-	"regexp"
 	"strings"
 )
 
-// reGenericName helps to convert `MyType[path/to.SubType]` to `MyTypeSubType`
-// when using the default schema namer.
-var reGenericName = regexp.MustCompile(`\[[^\]]+\]`)
-
 // Registry creates and stores schemas and their references, and supports
 // marshalling to JSON/YAML for use as an OpenAPI #/components/schemas object.
 // Behavior is implementation-dependent, but the design allows for recursive
@@ -35,14 +30,14 @@ func DefaultSchemaNamer(t reflect.Type, hint string) string {
 	name := deref(t).Name()
 
 	// Fix up generics, if used, for nicer refs & URLs.
-	name = reGenericName.ReplaceAllStringFunc(name, func(s string) string {
-		// Convert `MyType[path/to.SubType]` to `MyType[SubType]`.
-		parts := strings.Split(s, ".")
-		return parts[len(parts)-1]
-	})
-	// Remove square brackets.
-	name = strings.ReplaceAll(name, "[", "")
-	name = strings.ReplaceAll(name, "]", "")
+	// Convert `MyType[path/to.SubType]` to `MyTypepathtoSubType`.
+	replaced := strings.Builder{}
+	for _, c := range name {
+		if !strings.ContainsRune("[*/.]", c) {
+			replaced.WriteRune(c)
+		}
+	}
+	name = replaced.String()
 
 	if name == "" {
 		name = hint


Test patch:
diff --git a/registry_test.go b/registry_test.go
new file mode 100644
index 0000000..b188e56
--- /dev/null
+++ b/registry_test.go
@@ -0,0 +1,27 @@
+package huma
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/danielgtaylor/huma/v2/examples/protodemo/protodemo"
+	"github.com/stretchr/testify/assert"
+)
+
+type Output[T any] struct {
+	data T
+}
+
+type Embedded[P any] struct {
+	data P
+}
+
+func TestDefaultSchemaNamer(t *testing.T) {
+	testUser := Output[*[]Embedded[protodemo.User]]{}
+
+	name := DefaultSchemaNamer(reflect.TypeOf(testUser), "hint")
+	fmt.Println(reflect.TypeOf(testUser))
+	fmt.Println(name)
+	assert.True(t, name == "Outputgithubcomdanielgtaylorhumav2Embeddedgithubcomdanielgtaylorhumav2examplesprotodemoprotodemoUser")
+}
Repository: danielgtaylor/huma
Pull request #298 (2024-03-12 13:13:49)

fix: length validation for utf8 strings
Hi! Current string length validation made with go's standard `len` function works incorrectly with non ascii characters. So if there any non-english symbols `"maxLength"` validator will fail when it shouldn't.

In this PR I'v replaced `len` with `utf8.RuneCountInString`. Instead of number of bytes it will calculate number of runes. 

It will resolve most issues. But it don't take into account [unicode text segmentation](https://unicode.org/reports/tr29/). So if there will be symbols such as emojis, that consists of more than one unicode character it still will calculate length incorrectly. More info could be found [here](https://stackoverflow.com/a/12668840). 

So may be the next step is to add usage of https://github.com/rivo/uniseg. But considering it is a big change and new dependancy may be it is not worth it.


Patch:
diff --git a/validate.go b/validate.go
index b7f2293..2e9f3cc 100644
--- a/validate.go
+++ b/validate.go
@@ -12,6 +12,7 @@ import (
 	"strconv"
 	"strings"
 	"time"
+	"unicode/utf8"
 	"unsafe"
 )
 
@@ -412,12 +413,12 @@ func Validate(r Registry, s *Schema, path *PathBuffer, mode ValidateMode, v any,
 		}
 
 		if s.MinLength != nil {
-			if len(str) < *s.MinLength {
+			if utf8.RuneCountInString(str) < *s.MinLength {
 				res.Addf(path, str, s.msgMinLength)
 			}
 		}
 		if s.MaxLength != nil {
-			if len(str) > *s.MaxLength {
+			if utf8.RuneCountInString(str) > *s.MaxLength {
 				res.Add(path, str, s.msgMaxLength)
 			}
 		}


Test patch:
diff --git a/validate_test.go b/validate_test.go
index caa1aaf..44be70e 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -234,6 +234,13 @@ var validateTests = []struct {
 		}{}),
 		input: map[string]any{"value": "a"},
 	},
+	{
+		name: "non ascii max length success",
+		typ: reflect.TypeOf(struct {
+			Value string `json:"value" maxLength:"2"`
+		}{}),
+		input: map[string]any{"value": "аб"},
+	},
 	{
 		name: "max length fail",
 		typ: reflect.TypeOf(struct {
Repository: danielgtaylor/huma
Pull request #304 (2024-03-12 22:24:11)

fix: issue 299
This pull request fixes issue #299 by checking if a field was already processed by its original name and not by the name given through a tag.


Patch:
diff --git a/schema.go b/schema.go
index c6131ad..a4ea351 100644
--- a/schema.go
+++ b/schema.go
@@ -501,10 +501,10 @@ type fieldInfo struct {
 
 // getFields performs a breadth-first search for all fields including embedded
 // ones. It may return multiple fields with the same name, the first of which
-// represents the outer-most declaration.
+// represents the outermost declaration.
 func getFields(typ reflect.Type) []fieldInfo {
 	fields := make([]fieldInfo, 0, typ.NumField())
-	embedded := []reflect.StructField{}
+	var embedded []reflect.StructField
 
 	for i := 0; i < typ.NumField(); i++ {
 		f := typ.Field(i)
@@ -632,11 +632,20 @@ func SchemaFromType(r Registry, t reflect.Type) *Schema {
 	case reflect.Struct:
 		required := []string{}
 		requiredMap := map[string]bool{}
+		fieldSet := map[string]struct{}{}
 		propNames := []string{}
 		props := map[string]*Schema{}
 		for _, info := range getFields(t) {
 			f := info.Field
 
+			if _, ok := fieldSet[f.Name]; ok {
+				// This field was overridden by an ancestor type, so we
+				// should ignore it.
+				continue
+			}
+
+			fieldSet[f.Name] = struct{}{}
+
 			name := f.Name
 			omit := false
 			if j := f.Tag.Get("json"); j != "" {
@@ -649,11 +658,6 @@ func SchemaFromType(r Registry, t reflect.Type) *Schema {
 				// This field is deliberately ignored.
 				continue
 			}
-			if props[name] != nil {
-				// This field was overridden by an ancestor type, so we
-				// should ignore it.
-				continue
-			}
 
 			fs := SchemaFromField(r, f, t.Name()+f.Name+"Struct")
 			if fs != nil {


Test patch:
diff --git a/schema_test.go b/schema_test.go
index 82a9076..8d12303 100644
--- a/schema_test.go
+++ b/schema_test.go
@@ -501,6 +501,24 @@ func TestSchema(t *testing.T) {
 				}
 			}`,
 		},
+		{
+			name: "field-embed-override",
+			input: struct {
+				Embedded
+				Value string `json:"override" doc:"override"`
+			}{},
+			expected: `{
+				"type": "object",
+				"additionalProperties": false,
+				"required": ["override"],
+				"properties": {
+					"override": {
+						"type": "string",
+						"description": "override"
+					}
+				}
+			}`,
+		},
 		{
 			name: "field-pointer-example",
 			input: struct {
Repository: danielgtaylor/huma
Pull request #312 (2024-03-14 15:53:28)

feat: support dep required for map[any]any
This was missed in #303, needed to potentially support other formats like CBOR/msgpack/YAML/etc that may create maps where keys may not all be strings. The one caveat is the checked dependent key type will always be a string, but I think that's acceptable for now.


Patch:
diff --git a/validate.go b/validate.go
index 8d6a3f2..6addce4 100644
--- a/validate.go
+++ b/validate.go
@@ -646,6 +646,16 @@ func handleMapAny(r Registry, s *Schema, path *PathBuffer, mode ValidateMode, m
 			continue
 		}
 
+		if m[k] != nil && s.DependentRequired[k] != nil {
+			for _, dependent := range s.DependentRequired[k] {
+				if m[dependent] != nil {
+					continue
+				}
+
+				res.Add(path, m, s.msgDependentRequired[k][dependent])
+			}
+		}
+
 		path.Push(k)
 		Validate(r, v, path, mode, m[k], res)
 		path.Pop()


Test patch:
diff --git a/validate_test.go b/validate_test.go
index a10eec0..20201cc 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -1062,6 +1062,50 @@ var validateTests = []struct {
 			"expected property dependent3 to be present when value2 is present",
 		},
 	},
+	{
+		name: "dependentRequired empty success any",
+		typ: reflect.TypeOf(struct {
+			Value     string `json:"value,omitempty" dependentRequired:"dependent"`
+			Dependent string `json:"dependent,omitempty"`
+		}{}),
+		input: map[any]any{},
+		errs:  nil,
+	},
+	{
+		name: "dependentRequired filled success any",
+		typ: reflect.TypeOf(struct {
+			Value     string `json:"value,omitempty" dependentRequired:"dependent"`
+			Dependent string `json:"dependent,omitempty"`
+		}{}),
+		input: map[any]any{"value": "abc", "dependent": "123"},
+		errs:  nil,
+	},
+	{
+		name: "dependentRequired ignored success any",
+		typ: reflect.TypeOf(struct {
+			Value     string `json:"value,omitempty" dependentRequired:""`
+			Dependent string `json:"dependent,omitempty"`
+		}{}),
+		input: map[any]any{},
+		errs:  nil,
+	},
+	{
+		name: "dependentRequired failure any",
+		typ: reflect.TypeOf(struct {
+			Value1     string `json:"value1,omitempty" dependentRequired:"dependent1,dependent3"`
+			Dependent1 string `json:"dependent1,omitempty"`
+			Value2     string `json:"value2,omitempty" dependentRequired:"dependent2,dependent3"`
+			Dependent2 string `json:"dependent2,omitempty"`
+			Dependent3 string `json:"dependent3,omitempty"`
+		}{}),
+		input: map[any]any{"value1": "abc", "value2": "123"},
+		errs: []string{
+			"expected property dependent1 to be present when value1 is present",
+			"expected property dependent3 to be present when value1 is present",
+			"expected property dependent2 to be present when value2 is present",
+			"expected property dependent3 to be present when value2 is present",
+		},
+	},
 	{
 		name: "oneOf success bool",
 		s: &huma.Schema{