@@ -57,12 +57,10 @@ type applyFirstMarker interface {
5757 ApplyFirst ()
5858}
5959
60- // schemaFetcher is a function that fetches a schema for a given type.
61- type schemaFetcher func (TypeIdent ) * apiext.JSONSchemaProps
62-
6360// schemaRequester knows how to marker that another schema (e.g. via an external reference) is necessary.
6461type schemaRequester interface {
6562 NeedSchemaFor (typ TypeIdent )
63+ LookupType (pkg * loader.Package , name string ) * markers.TypeInfo
6664}
6765
6866// schemaContext stores and provides information across a hierarchy of schema generation.
@@ -71,7 +69,6 @@ type schemaContext struct {
7169 info * markers.TypeInfo
7270
7371 schemaRequester schemaRequester
74- schemaFetcher schemaFetcher
7572 PackageMarkers markers.MarkerValues
7673
7774 allowDangerousTypes bool
@@ -80,12 +77,11 @@ type schemaContext struct {
8077
8178// newSchemaContext constructs a new schemaContext for the given package and schema requester.
8279// It must have type info added before use via ForInfo.
83- func newSchemaContext (pkg * loader.Package , req schemaRequester , fetcher schemaFetcher , allowDangerousTypes , ignoreUnexportedFields bool ) * schemaContext {
80+ func newSchemaContext (pkg * loader.Package , req schemaRequester , allowDangerousTypes , ignoreUnexportedFields bool ) * schemaContext {
8481 pkg .NeedTypesInfo ()
8582 return & schemaContext {
8683 pkg : pkg ,
8784 schemaRequester : req ,
88- schemaFetcher : fetcher ,
8985 allowDangerousTypes : allowDangerousTypes ,
9086 ignoreUnexportedFields : ignoreUnexportedFields ,
9187 }
@@ -98,7 +94,6 @@ func (c *schemaContext) ForInfo(info *markers.TypeInfo) *schemaContext {
9894 pkg : c .pkg ,
9995 info : info ,
10096 schemaRequester : c .schemaRequester ,
101- schemaFetcher : c .schemaFetcher ,
10297 allowDangerousTypes : c .allowDangerousTypes ,
10398 ignoreUnexportedFields : c .ignoreUnexportedFields ,
10499 }
@@ -240,9 +235,7 @@ func typeToSchema(ctx *schemaContext, rawType ast.Expr) *apiext.JSONSchemaProps
240235 return & apiext.JSONSchemaProps {}
241236 }
242237
243- if ctx .info .Doc != "" {
244- props .Description = ctx .info .Doc
245- }
238+ props .Description = ctx .info .Doc
246239
247240 applyMarkers (ctx , ctx .info .Markers , props , rawType )
248241
@@ -278,7 +271,6 @@ func localNamedToSchema(ctx *schemaContext, ident *ast.Ident) *apiext.JSONSchema
278271 if aliasInfo , isAlias := typeInfo .(* types.Alias ); isAlias {
279272 typeInfo = aliasInfo .Rhs ()
280273 }
281-
282274 if basicInfo , isBasic := typeInfo .(* types.Basic ); isBasic {
283275 typ , fmt , err := builtinToType (basicInfo , ctx .allowDangerousTypes )
284276 if err != nil {
@@ -290,21 +282,50 @@ func localNamedToSchema(ctx *schemaContext, ident *ast.Ident) *apiext.JSONSchema
290282 // > Otherwise, the alias information is only in the type name, which
291283 // > points directly to the actual (aliased) type.
292284 if basicInfo .Name () != ident .Name {
293- return ctx .schemaFetcher (TypeIdent {
294- Package : ctx .pkg ,
295- Name : ident .Name ,
296- })
285+ ctx .requestSchema ("" , ident .Name )
286+ link := TypeRefLink ("" , ident .Name )
287+ return & apiext.JSONSchemaProps {
288+ Type : typ ,
289+ Format : fmt ,
290+ Ref : & link ,
291+ }
297292 }
298293 return & apiext.JSONSchemaProps {
299294 Type : typ ,
300295 Format : fmt ,
301296 }
302297 }
298+ // NB(directxman12): if there are dot imports, this might be an external reference,
299+ // so use typechecking info to get the actual object
300+ typeNameInfo := typeInfo .(interface { Obj () * types.TypeName }).Obj ()
301+ pkg := typeNameInfo .Pkg ()
302+ pkgPath := loader .NonVendorPath (pkg .Path ())
303+ if pkg == ctx .pkg .Types {
304+ pkgPath = ""
305+ }
306+ ctx .requestSchema (pkgPath , typeNameInfo .Name ())
307+ link := TypeRefLink (pkgPath , typeNameInfo .Name ())
308+
309+ // In cases where we have a named type, apply the type and format from the named schema
310+ // to allow markers that need this information to apply correctly.
311+ var typ , fmt string
312+ if namedInfo , isNamed := typeInfo .(* types.Named ); isNamed {
313+ // We don't want/need to do this for structs, maps, or arrays.
314+ // These are already handled in infoToSchema if they have custom marshalling.
315+ if _ , isBasic := namedInfo .Underlying ().(* types.Basic ); isBasic {
316+ namedTypeInfo := ctx .schemaRequester .LookupType (ctx .pkg , namedInfo .Obj ().Name ())
317+
318+ namedSchema := infoToSchema (ctx .ForInfo (namedTypeInfo ))
319+ typ = namedSchema .Type
320+ fmt = namedSchema .Format
321+ }
322+ }
303323
304- return ctx .schemaFetcher (TypeIdent {
305- Package : ctx .pkg ,
306- Name : ident .Name ,
307- })
324+ return & apiext.JSONSchemaProps {
325+ Type : typ ,
326+ Format : fmt ,
327+ Ref : & link ,
328+ }
308329}
309330
310331// namedSchema creates a schema (ref) for an explicitly external type reference.
@@ -504,9 +525,7 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON
504525 } else {
505526 propSchema = typeToSchema (ctx .ForInfo (& markers.TypeInfo {}), field .RawField .Type )
506527 }
507- if field .Doc != "" {
508- propSchema .Description = field .Doc
509- }
528+ propSchema .Description = field .Doc
510529
511530 applyMarkers (ctx , field .Markers , propSchema , field .RawField )
512531
0 commit comments