Schema



Hof has a few schemas for you to use when creating an using generators.

You can find their source files on GitHub

Generator

The Generator is the schema for generators. As a creator, 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.


Source on GitHub

gen.#Generator

package gen

// Definition for a generator
#Generator: {
	// Base directory for the output
	Outdir: string | *"./"

	// Generater 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: {...}

	// 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 overriden 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: [Extenstion=string]: {
			// Name of the formatter, like 'prettier' or 'black'
			Formatter: string
			// formatter specific configuration
			Config: _
		}
	}

	// 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: ["./static/**/*"], TrimPrefix: "./static/"}]

	// TODO, CUE files

	// 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

	// TODO, consider adding 'Override*' for templates, partials, statics

	// For subgenerators so a generator can leverage and design for other hofmods
	Generators: [Name=string]: #Generator

	// 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
	PackageName: string | *""
	// TODO, hof, can we introspect the generator / example packages and figure this out?

	// Note, open so you can have any extra fields
	...
}

// deprecated
#HofGenerator: #Generator

Generator User Fields

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.

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 creators, or is it the default applied when no input is set on a per template basis)

As a creator, 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.

Outdir

This is the base dir where the generator output will be written.

Other

#HofGenerator 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.

Generator Creator 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.
PackageName

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 file. The generator Out field is a list of these and what hof iterates over and processes.


Source on GitHub

gen.#File

package gen

// A file which should be generated by hof
#File: {
	// The local input data, any struct
	// The Generator.In will be added here
	//   but will not replace any values set locally
	In?: {...} // for templates
	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

	// Only one of these three may be set
	// The template contents
	TemplateContent?: string
	// Path into the loaded templates
	TemplatePath?: string
	// Writes a datafile, bypassing template rendering
	DatafileFormat?: "cue" | "json" | "yaml" | "xml" | "toml"

	// TODO, we would like to make the above a disjunction
	// 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

	// Include Common attributes
	//  '.' will bre replaced by generator defaults
	TemplateDelims?: #TemplateDelims

	// Formatting Control
	Formatting?: {
		Disabled?: bool
		// Name of the formatter, like 'prettier' or 'black'
		Formatter: string
		// formatter specific configuration
		Config: _
	}

	// Note, intentionally closed to prevent user error when creating GenFiles
}

// deprecated
#HofGeneratorFile: #File

Creator Fields

#HofGeneratorFile is only for generator creators.

In

The input data used when rendering the template.

Filepath

The full filepath within the outdir to generate.

TemplateContent, TemplatePath

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 delimitors. The default is {{ and }}.

Templates

The template config schemas are the parameters for the different available rendering engines.


Source on GitHub

gen.#Template

package gen

// #Statics is used for static files copied over, bypassing the template engine
#Statics: {
	Globs: [...string]
	TrimPrefix?: string
	OutPrefix?:  string
}

// #Template is used for embedded or named templates or partials
#Template: {
	Content: string
	Delims?: #TemplateDelims
}

// #Templates is used for templates or partials loaded from a filesystem
#Templates: {
	Globs: [...string]
	TrimPrefix?: string
	Delims?:     #TemplateDelims
}

#TemplateDelims: {
	LHS: string
	RHS: string
}

#Statics

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 }}).

2022 Hofstadter, Inc