The Generator is the schema for generators.
As a generator author, this is the definition you will use
to define how an input is combined with templates
to produce the output files.
As a user, you will supply the input values
to a specific geneartor to create code.
Hof’s ad-hoc code gen also assembles a generator
from the arguments and flags you provide.
hof/schema/gen.#Generator
packagegenimport ("github.com/hofstadter-io/hof/schema""github.com/hofstadter-io/hof/schema/common""github.com/hofstadter-io/hof/schema/create")// Definition for a generatorGenerator: { schema.Hof #hof: gen: root: true// Base directory for the output Outdir: string|*"./"// Name of the generator, will default to kebab(label) where defined Name: common.NameLabel// Generator wide input value to templates.// Merged with any template or file level In values// File.In will extend or replace any top-level fields here In: {...}// Should In be added to the input of every output file? applyInToAllOut: bool|*true// doing this in the schema crushes CUE performance//if applyInToAllOut == true {// Out: [...{"In": In}]//}// TODO, Generator wide cue.Value for writing incomplete values Val: _// File globs to watch and trigger regen when changed WatchFull: [...string] // reloads & regens everything WatchFast: [...string] // skips CUE reload, regens everything// Enable Diff3 Diff3: bool|*true// Formatting Control Formatting: {// default for all files, unless overridden in a file Disabled: bool|*false// Should data files also be formatted?// (cue,yaml,json,toml,xml) FormatData: bool|*true// Map of names to formatter config values.// Supports multiple configurations for a formatter,// particularly useful for prettier.// Hof has defaults it will use if none are specified// map from file extensions to formatters Formatters: [Extension=string]: {// Name of the formatter, like 'prettier' or 'black' Formatter: string// formatter specific configuration Config: _ } } PreFlow?: _// run hof flow beforehand PostFlow?: _// run hof flow afterwards// The final list of 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: ["./statics/**/*"], TrimPrefix: "./statics/"}]// The following mirror their non-embedded versions// however they have the content as a string in CUE// For templates and partials, Name is the path to reference EmbeddedTemplates: [name=string]: Template EmbeddedPartials: [name=string]: Template// For statics, Name is the path to write the content EmbeddedStatics: [name=string]: string// For subgenerators so a generator can leverage and design for other hofmods Generators: [name=string]: Generator & {Name: name}// Embed the creator to get creator fields create.Creator// This should be set to default to the module name// (i.e. 'string | *"github.com/<org>/<repo>"')// Users should not have to set this.// // Used for indexing into the cue.mod/pkg directory...// until embed is supported, at which point this shouldn't be needed at all// only needed when you have example usage in the same module the generator is in// set to the empty string ("") as a generator writer who is making an example in the same module ModuleName: string PackageName: ModuleName ModuleName: PackageName// TODO, hof, can we introspect the generator / example packages and figure this out?// print debug info during load & gen Debug: bool|*false// TODO, consider adding 'Override*' for templates, partials, statics// Note, open so you can have any extra fields ...}// deprecated#Generator: Generator#HofGenerator: Generator
These are fields that a user of a generator will typically fill in.
The following fields are the default suggested user inputs
You can decided to ignore these fields and
make any set of exposed input fields for your generators.
Name
In
This is the primary input for users and will be used when rendering the templates.
(need to check if this is provided as a root context on repeated templates,
or if that is set by authors, or is it the default applied when no input is
set on a per template basis)
As a generator author, you will likely want to provide a schema and set In: #MySchema.
This will make it easier for users to know if they have correctly specified
the required input.
They are often put in a schemas directory in your generator module.
Outdir
This is the base dir where the generator output will be written.
Other
#Generator was left open so you can specify any other inputs for your users.
This can be useful when you want more contextual inputs presented to the user
or you want to transform the user input before passing into the template system.
Author Fields
Out
This is the primary field processed by hof.
Your generator should fill in this field based on the user input.
Each element will have both input and a template specified.
This is where the conditional logic for what to generate comes in.
More details can be found in the next section.
Templates, Partials, Statics
These are lists of templates, partials, and statics to load from disk,
relative to your generator module base directory.
Embedded{Templates,Partials,Statics}
These are inline or “in-cue” templates, partials, and static fils.
Generators
This is where you set sub-generators
that your generator builds on.
We have used this for
Using one generator in another, for example to provide a more advanced CLI for our REST server binary.
Building higher level generators, for example an APP which has Client, Server, and Database subgenerators with a single input.
ModuleName
This is the CUE module name of your generator.
It is used for indexing into the cue.mod folder
to find your templates and partials from disk.
(this will go away once CUE supports the @embed() for this purpose, and likely structural sharing will be needed as well)
File
File is the schema for a generated output file.
The generator Out field is a list of these
and what hof iterates over and processes.
hof/schema/gen.#File
packagegen// A file which should be generated by hofFile: {// The local input data, any struct// The Generator.In will be merged here// but will not replace any values set locally In?: {...} // for templates// input value for data files, always remains a CUE value Val?: _// for datafiles// The full path under the output location// empty implies don't generate, even though it may end up in the out list Filepath?: string//// One and only one of these next three may be set//// The template contents TemplateContent?: string// Path into the loaded templates TemplatePath?: string// Writes a datafile, bypassing template rendering// Supports infering DatafileFormat by matching extensions// You only have to set this when hof cannot infer from the file extension DatafileFormat?: "cue"|"json"|"yaml"|"xml"|"toml"// TODO, we would like to make the above a disjunction (multi-field)// but it results in a significant slowdown 50-100% for hof self-gen// Most likely need to wait for structural sharing to land in cue// CUE settings// for data files which need a package or namespace at the beginning Package: string|*"" Raw: bool|*false Final: bool|*false Concrete: bool|*true Definitions: bool|*true Optional: bool|*true Hidden: bool|*true Attributes: bool|*true Docs: bool|*true InlineImports: bool|*false ErrorsAsValues: bool|*false// Alternative Template Delimiters Delims: #TemplateDelims TemplateDelims?: Delims// Formatting Control Formatting?: { Disabled?: bool// Name of the formatter, like 'prettier' or 'black' Formatter: string// formatter specific configuration Config: _ }// note, how In gets combined may be opaque, and non-CUEish// we should think about applying it at the schema level// local override if the generator is set the opposite way applyGenInToOut: bool|*true// Note, intentionally closed to prevent user error when creating GenFiles}// deprecated#File: File#HofGeneratorFile: File
You must specify one or the other.
TemplateContent is the listeral content as a string
whereas TemplatePath references one of the predefined templates.
TemplateDelims
Only needed when you need alternative delimiters.
The default is {{ and }}.
Templates
The template config schemas are the parameters
for the different available rendering engines.
hof/schmea/gen.#Template
packagegen#EmptyTemplates: EmptyTemplatesEmptyTemplates: { Templates: [] Partials: [] Statics: [] ...}#SubdirTemplates: SubdirTemplatesSubdirTemplates: { #subdir: string|*"." Templates: [{ Globs: ["\(#subdir)/templates/**/*"] TrimPrefix: "\(#subdir)/templates/" }] Partials: [{ Globs: ["\(#subdir)/partials/**/*"] TrimPrefix: "\(#subdir)/partials/" }] Statics: [{ Globs: ["\(#subdir)/statics/**/*"] TrimPrefix: "\(#subdir)/statics/" }] ...}#TemplateSubdirs: TemplateSubdirsTemplateSubdirs: { #subdir: string|*"." Templates: [{ Globs: ["./templates/\(#subdir)/**/*"] TrimPrefix: "./templates/\(#subdir)/" }] Partials: [{ Globs: ["./partials/\(#subdir)/**/*"] TrimPrefix: "./partials/\(#subdir)/" }] Statics: [{ Globs: ["./statics/\(#subdir)/**/*"] TrimPrefix: "./statics/\(#subdir)/" }] ...}// #Statics is used for static files copied over, bypassing the template engine#Statics: StaticsStatics: { Globs: [...string] TrimPrefix?: string OutPrefix?: string}// #Template is used for embedded or named templates or partials#Template: TemplateTemplate: { Content: string Delims?: TemplateDelims}// #Templates is used for templates or partials loaded from a filesystem#Templates: TemplatesTemplates: { Globs: [...string] TrimPrefix?: string Delims?: TemplateDelims// apply delims to a subset of templates, by glob DelimGlobs: [glob=string]: TemplateDelims}#TemplateDelims: TemplateDelimsTemplateDelims: { LHS: string|*"" RHS: string|*""}
Represents a list of Globs to copy into the output, bypassing the template rendering engine.
You can specify TrimPrefix to remove leading directories and OutPrefix to write to subdirectories
relative to the output dir.
#Template
Represents an inline Template and content.
#Templates
Represents Globs to load into the template system. Used for both templates and partials.
Use TrimPrefix to remove leading directories and Delims to specify alternative
template delimiters for all Globs.
#Delims
The schema for template delimiters
when you need to override the defaults
({{ and }}).