diff --git a/internal/helpers/schema_date.go b/internal/helpers/schema_date.go new file mode 100644 index 0000000..4c28aad --- /dev/null +++ b/internal/helpers/schema_date.go @@ -0,0 +1,37 @@ +package helpers + +import ( + "reflect" + + "github.com/google/jsonschema-go/jsonschema" + twapi "github.com/teamwork/twapi-go-sdk" +) + +// WithDateTypeSchema registers a JSON-schema override for the twapi.Date type +// on the given generation options. twapi.Date is defined as `type Date +// time.Time`, so the reflection-based generator would otherwise emit a useless +// object schema for time.Time's unexported fields. This override forces it to a +// nullable, date-only string. +// +// Use it whenever generating an output schema from a response type that carries +// (or sideloads) twapi.Date fields: +// +// schema, err = jsonschema.For[Response](helpers.WithDateTypeSchema(&jsonschema.ForOptions{})) +// +// Any other options already set on opts (including pre-existing TypeSchemas +// entries) are preserved. The options value is modified in place and also +// returned for convenient chaining. +func WithDateTypeSchema(opts *jsonschema.ForOptions) *jsonschema.ForOptions { + if opts == nil { + opts = &jsonschema.ForOptions{} + } + if opts.TypeSchemas == nil { + opts.TypeSchemas = make(map[reflect.Type]*jsonschema.Schema) + } + opts.TypeSchemas[reflect.TypeFor[twapi.Date]()] = &jsonschema.Schema{ + Types: []string{"null", "string"}, + Format: "date", + Description: "Null or date-only date string", + } + return opts +} diff --git a/internal/twprojects/calendar_events.go b/internal/twprojects/calendar_events.go index cdce2a8..ee6119d 100644 --- a/internal/twprojects/calendar_events.go +++ b/internal/twprojects/calendar_events.go @@ -29,7 +29,9 @@ func init() { var err error // generate the output schema only once - calendarEventListOutputSchema, err = jsonschema.For[projects.CalendarEventListResponse](&jsonschema.ForOptions{}) + calendarEventListOutputSchema, err = jsonschema.For[projects.CalendarEventListResponse]( + helpers.WithDateTypeSchema(&jsonschema.ForOptions{}), + ) if err != nil { panic(fmt.Sprintf("failed to generate JSON schema for CalendarEventListResponse: %v", err)) } diff --git a/internal/twprojects/search.go b/internal/twprojects/search.go index 968a05a..f90c14a 100644 --- a/internal/twprojects/search.go +++ b/internal/twprojects/search.go @@ -28,7 +28,7 @@ var ( func init() { var err error - searchOutputSchema, err = jsonschema.For[projects.SearchResponse](&jsonschema.ForOptions{}) + searchOutputSchema, err = jsonschema.For[projects.SearchResponse](helpers.WithDateTypeSchema(&jsonschema.ForOptions{})) if err != nil { panic(fmt.Sprintf("failed to generate JSON schema for SearchResponse: %v", err)) } diff --git a/internal/twprojects/tasks.go b/internal/twprojects/tasks.go index b13830a..db357da 100644 --- a/internal/twprojects/tasks.go +++ b/internal/twprojects/tasks.go @@ -37,12 +37,12 @@ func init() { var err error // generate the output schemas only once - taskGetOutputSchema, err = jsonschema.For[projects.TaskGetResponse](&jsonschema.ForOptions{}) + taskGetOutputSchema, err = jsonschema.For[projects.TaskGetResponse](helpers.WithDateTypeSchema(&jsonschema.ForOptions{})) if err != nil { panic(fmt.Sprintf("failed to generate JSON schema for TaskGetResponse: %v", err)) } helpers.WithMetaWebLinkSchema(taskGetOutputSchema) - taskListOutputSchema, err = jsonschema.For[projects.TaskListResponse](&jsonschema.ForOptions{}) + taskListOutputSchema, err = jsonschema.For[projects.TaskListResponse](helpers.WithDateTypeSchema(&jsonschema.ForOptions{})) if err != nil { panic(fmt.Sprintf("failed to generate JSON schema for TaskListResponse: %v", err)) }