99 "github.com/pb33f/libopenapi"
1010 "github.com/pb33f/libopenapi/datamodel/high/base"
1111
12- "github.com/oapi-codegen/oapi-codegen-exp/experimental/internal/ codegen/templates"
12+ "github.com/oapi-codegen/oapi-codegen-exp/experimental/codegen/internal /templates"
1313)
1414
1515// Generate produces Go code from the parsed OpenAPI document.
@@ -20,6 +20,17 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
2020 // Create a single CodegenContext that all generators share.
2121 ctx := NewCodegenContext ()
2222
23+ // Configure runtime package prefixes if an external runtime is specified.
24+ var runtimePrefixes RuntimePrefixes
25+ if cfg .Generation .RuntimePackage != nil {
26+ runtimePrefixes = RuntimePrefixes {
27+ Params : "params." ,
28+ Types : "types." ,
29+ Helpers : "helpers." ,
30+ }
31+ ctx .SetRuntimePrefixes (runtimePrefixes .Params , runtimePrefixes .Types , runtimePrefixes .Helpers )
32+ }
33+
2334 // Create content type matcher for filtering request/response bodies
2435 contentTypeMatcher := NewContentTypeMatcher (cfg .ContentTypes )
2536
@@ -102,7 +113,7 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
102113
103114 ops = FilterOperations (ops , cfg .OutputOptions )
104115
105- clientGen , err := NewClientGenerator (schemaIndex , cfg .Generation .SimpleClient , cfg .Generation .ModelsPackage )
116+ clientGen , err := NewClientGenerator (schemaIndex , cfg .Generation .SimpleClient , cfg .Generation .ModelsPackage , runtimePrefixes )
106117 if err != nil {
107118 return "" , fmt .Errorf ("creating client generator: %w" , err )
108119 }
@@ -140,7 +151,7 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
140151 ops = FilterOperations (ops , cfg .OutputOptions )
141152
142153 if len (ops ) > 0 {
143- serverGen , err := NewServerGenerator (cfg .Generation .Server )
154+ serverGen , err := NewServerGenerator (cfg .Generation .Server , runtimePrefixes )
144155 if err != nil {
145156 return "" , fmt .Errorf ("creating server generator: %w" , err )
146157 }
@@ -171,7 +182,7 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
171182 }
172183
173184 if len (webhookOps ) > 0 {
174- initiatorGen , err := NewInitiatorGenerator ("Webhook" , schemaIndex , true , cfg .Generation .ModelsPackage )
185+ initiatorGen , err := NewInitiatorGenerator ("Webhook" , schemaIndex , true , cfg .Generation .ModelsPackage , runtimePrefixes )
175186 if err != nil {
176187 return "" , fmt .Errorf ("creating webhook initiator generator: %w" , err )
177188 }
@@ -202,7 +213,7 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
202213 }
203214
204215 if len (callbackOps ) > 0 {
205- initiatorGen , err := NewInitiatorGenerator ("Callback" , schemaIndex , true , cfg .Generation .ModelsPackage )
216+ initiatorGen , err := NewInitiatorGenerator ("Callback" , schemaIndex , true , cfg .Generation .ModelsPackage , runtimePrefixes )
206217 if err != nil {
207218 return "" , fmt .Errorf ("creating callback initiator generator: %w" , err )
208219 }
@@ -237,7 +248,7 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
237248 }
238249
239250 if len (webhookOps ) > 0 {
240- receiverGen , err := NewReceiverGenerator ("Webhook" , cfg .Generation .Server )
251+ receiverGen , err := NewReceiverGenerator ("Webhook" , cfg .Generation .Server , runtimePrefixes )
241252 if err != nil {
242253 return "" , fmt .Errorf ("creating webhook receiver generator: %w" , err )
243254 }
@@ -288,7 +299,7 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
288299 }
289300
290301 if len (callbackOps ) > 0 {
291- receiverGen , err := NewReceiverGenerator ("Callback" , cfg .Generation .Server )
302+ receiverGen , err := NewReceiverGenerator ("Callback" , cfg .Generation .Server , runtimePrefixes )
292303 if err != nil {
293304 return "" , fmt .Errorf ("creating callback receiver generator: %w" , err )
294305 }
@@ -329,31 +340,47 @@ func Generate(doc libopenapi.Document, specData []byte, cfg Configuration) (stri
329340
330341 // ── Phase 2: Render helpers ──
331342
332- // Emit custom type templates (Date, Email, UUID, File, Nullable, etc.)
333- for _ , templateName := range ctx .RequiredCustomTypes () {
334- typeCode := ctx .loadAndRegisterCustomType (templateName )
335- if typeCode != "" {
336- output .AddType (typeCode )
343+ if cfg .Generation .RuntimePackage != nil {
344+ // Runtime package is configured — don't embed helpers, import them.
345+ // Add imports for whichever sub-packages are actually needed.
346+ ctx .AddImport (cfg .Generation .RuntimePackage .TypesImport ())
347+ if ctx .HasAnyParams () {
348+ ctx .AddImport (cfg .Generation .RuntimePackage .ParamsImport ())
349+ }
350+ if len (ctx .RequiredHelpers ()) > 0 {
351+ ctx .AddImport (cfg .Generation .RuntimePackage .HelpersImport ())
352+ }
353+ } else {
354+ // Resolve param template dependencies first — this may register
355+ // additional custom types (e.g., Date) that need to be emitted.
356+ ctx .GetRequiredParamTemplates ()
357+
358+ // Emit custom type templates (Date, Email, UUID, File, Nullable, etc.)
359+ for _ , templateName := range ctx .RequiredCustomTypes () {
360+ typeCode := ctx .loadAndRegisterCustomType (templateName )
361+ if typeCode != "" {
362+ output .AddType (typeCode )
363+ }
337364 }
338- }
339-
340- // Emit param functions
341- paramFuncs , err := generateParamFunctionsFromContext (ctx )
342- if err != nil {
343- return "" , fmt .Errorf ("generating param functions: %w" , err )
344- }
345- if paramFuncs != "" {
346- output .AddType (paramFuncs )
347- }
348365
349- // Emit helper templates (e.g., marshal_form)
350- for _ , helperName := range ctx .RequiredHelpers () {
351- helperCode , err := generateHelper (helperName , ctx )
366+ // Emit param functions (typesPrefix is empty when embedded — Date is in same package)
367+ paramFuncs , err := generateParamFunctionsFromContext (ctx , "" )
352368 if err != nil {
353- return "" , fmt .Errorf ("generating helper %s: %w" , helperName , err )
369+ return "" , fmt .Errorf ("generating param functions: %w" , err )
370+ }
371+ if paramFuncs != "" {
372+ output .AddType (paramFuncs )
354373 }
355- if helperCode != "" {
356- output .AddType (helperCode )
374+
375+ // Emit helper templates (e.g., marshal_form)
376+ for _ , helperName := range ctx .RequiredHelpers () {
377+ helperCode , err := generateHelper (helperName , ctx )
378+ if err != nil {
379+ return "" , fmt .Errorf ("generating helper %s: %w" , helperName , err )
380+ }
381+ if helperCode != "" {
382+ output .AddType (helperCode )
383+ }
357384 }
358385 }
359386
@@ -397,7 +424,8 @@ func generateMarshalFormHelper() (string, error) {
397424}
398425
399426// generateParamFunctionsFromContext generates the parameter styling/binding functions based on CodegenContext usage.
400- func generateParamFunctionsFromContext (ctx * CodegenContext ) (string , error ) {
427+ // typesPrefix is prepended to Date/DateFormat references in param templates; empty when embedded.
428+ func generateParamFunctionsFromContext (ctx * CodegenContext , typesPrefix string ) (string , error ) {
401429 if ! ctx .HasAnyParams () {
402430 return "" , nil
403431 }
@@ -412,7 +440,9 @@ func generateParamFunctionsFromContext(ctx *CodegenContext) (string, error) {
412440 return "" , fmt .Errorf ("reading param template %s: %w" , tmplInfo .Template , err )
413441 }
414442
415- tmpl , err := template .New (tmplInfo .Name ).Parse (string (content ))
443+ tmpl , err := template .New (tmplInfo .Name ).Funcs (template.FuncMap {
444+ "typesPrefix" : func () string { return typesPrefix },
445+ }).Parse (string (content ))
416446 if err != nil {
417447 return "" , fmt .Errorf ("parsing param template %s: %w" , tmplInfo .Template , err )
418448 }
0 commit comments