Generators specify the mapping from inputs through templates to output files.
Using the schema and user input, you decide what files to generate,
what inputs to provide to templates, and can reshape or enrich the inputs.
Your generator file definds this process to
map the In field to the Out field for hof to process.
Generator Schema
HofGenerators and Files have their own schemas.
Only the core fields are shown here.
You can find the real schemas in the hof repository.
Generator Schemas
// Definition for a generatorGenerator: {// Base directory for the output Outdir: string|*"./"// "Global" input, merged with In per file before generating output In: {...} |*{...}// you may also supply additional user config// often you will construct "In" from// more meaningful fields presented to the user// The list fo files for hof to generate Out: [...File] |*[]// Template (top-level) TemplateConfig (globs+config) Templates: [...Templates] |*[Templates & {Globs: ["./templates/**/*"], TrimPrefix: "./templates/"}]// Partial (nested) TemplateConfig (globs+config) Partials: [...Templates] |*[Templates & {Globs: ["./partials/**/*"], TrimPrefix: "./partials/"}]// Statics are copied directly into the output, bypassing the rendering Statics: [...Statics] |*[Statics & {Globs: ["./static/**/*"], TrimPrefix: "./static/"}]// ... other fields for generator writers}// A file which should be generated by hofFile: {// The local input data, defaults to the generator In fields In: {...}// The full path under the output location// empty implies don't generate, even though it may endup in the list Filepath: string|*""// One of the following should be set// The template contents TemplateContent: string|*""// Path for the loaded templates TemplatePath: string|*""// ... advanced template configuration}
Mapping In to Out
Your goal as a generator writer is to fill in the Out field from the In field.
The In field will be passed through the templates and partials
if they are defined in the Out list.
In represents the data presented to the templates.
You can have your users set values in meaningful fields and collect them
You can add any other separate or calculated data
The top-level In is passed to all templates and can be extended with the per-template field
Out holds the files to be rendered by hof
Is a list of HofGeneratorFiles, where each…
Has a filepath for where it will be written under Outdir
Has an In value which will be unified with the top-level
There are typically two types of files (templates)
Files which are generated once per application. Think of a main.go or index.js. We often call these “once” files or templates.
Files which are generated for each sub-resource. These might be routes in a server or commands in a CLI. We often call these “repeated” files or templates.
You can use as many helper fields or calculations as you want
Calculate commonly used fields or values for In
Interpolate common base paths for filepaths
Create file lists for repeated templates.
Server Generator
The following is the generator for our simple REST server.
gen/server.cue
packagegenimport ("github.com/hofstadter-io/hof/schema/gen""hof.io/docs/example/schema")// Generator definitionGenerator: gen.Generator & {// User inputs to this generator// -----------------------------// The server design conforming to the server schema Server: schema.Server// Base output directory, defaults to current Outdir: string|*"./"// In & Out fields for hof// ------------------------// In is passed to every template as the root keys In: {// a convention for making root keys stand out visually SERVER: Server }// Actual files generated by hof, combined into a single list Out: [...gen.File] & _All// Everything below here is for convenience _All: [ for _, F in _OnceFiles {F}, for _, F in _RouteFiles {F}, ]// Note, we can omit Templates, Partials, and Statics// since the default values are sufficient for us// Internal fields for mapping Input to templates// ----------------------------------------------// Files that are generated once per server _OnceFiles: [...gen.File] & [ { TemplatePath: "go.mod" Filepath: "go.mod" }, { TemplatePath: "server.go" Filepath: "server.go" }, { TemplatePath: "router.go" Filepath: "router.go" }, { TemplatePath: "middleware.go" Filepath: "middleware.go" },// a conditional fileif Server.Auth !=_|_ { TemplatePath: "auth.go" Filepath: "auth.go" }, ]// Routes, we create a file per route in the Server _RouteFiles: [...gen.File] & [ for _, R in Server.Routes { In: { ROUTE: { R } } TemplatePath: "route.go" Filepath: "routes/\(In.ROUTE.Name).go" }, ]// We'll see how to handle nested routes and resources in upcoming sections}