scaffold

package
v0.36.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const (
	VarTypeString  = tmplconfig.VarTypeString
	VarTypeBoolean = tmplconfig.VarTypeBoolean
	VarTypeNumber  = tmplconfig.VarTypeNumber
	VarTypeChoice  = tmplconfig.VarTypeChoice
)
View Source
const MaxConfigFileSize = 10 * 1024 * 1024

MaxConfigFileSize is the maximum allowed size for tag.template.json (10 MB).

Variables

View Source
var (
	// ErrPromptCancelled is returned when the user cancels an interactive prompt.
	ErrPromptCancelled = errors.New("prompt cancelled by user")

	// ErrRequiredVariableMissing is returned when a required variable has no value.
	ErrRequiredVariableMissing = errors.New("required variable missing")

	// ErrInvalidVariableType is returned when a variable value doesn't match its type.
	ErrInvalidVariableType = errors.New("invalid variable type")

	// ErrOutputExists is returned when the output directory already exists.
	ErrOutputExists = errors.New("output directory already exists")

	// ErrTemplateNotFound is returned when the template directory doesn't exist.
	ErrTemplateNotFound = errors.New("template directory not found")

	// ErrConfigNotFound is returned when tag.template.json is missing.
	ErrConfigNotFound = errors.New("tag.template.json not found")
)

Common errors for the scaffold package.

View Source
var ErrCircularDependency = errors.New("circular variable dependency")

ErrCircularDependency is returned when variable defaults form a circular dependency.

View Source
var IsCookiecutterTemplate = tmplconfig.IsCookiecutterTemplate

IsCookiecutterTemplate checks if a directory contains a Cookiecutter template. Returns the path to cookiecutter.json if found, and a boolean indicating detection.

View Source
var ParseTemplateConfig = tmplconfig.ParseTemplateConfig

ParseTemplateConfig parses a tag.template.json file from bytes.

Functions

func GenerateTagConfig

func GenerateTagConfig(outputDir string, opts TagConfigOptions) error

GenerateTagConfig generates a .tagconfig.json file in the output directory. The template section is always written with an explicit type discriminator.

func IsTTY

func IsTTY() bool

IsTTY checks if stdin is connected to a terminal.

func ResolveDerivedVars

func ResolveDerivedVars(engine template.TemplateRenderer, config *TemplateConfig, vars map[string]any) error

ResolveDerivedVars evaluates derived and evaluated-default variable expressions through the template engine.

Derived variables (minimal form, no explicit prompt) always resolve from their expression default. Evaluated-default variables (expanded form with explicit prompt) resolve only if their current value is still a raw template expression — meaning they were not collected via an interactive prompt, values file, or --meta flag (e.g. non-TTY mode or --no-input).

Variables are processed in dependency order (topological sort) so that expressions referencing other derived variables see already-resolved values.

Types

type CookiecutterDetectedError

type CookiecutterDetectedError struct {
	CookiecutterPath string
}

CookiecutterDetectedError represents a Cookiecutter template detection. It carries the path to the detected cookiecutter.json file.

func (*CookiecutterDetectedError) Error

func (e *CookiecutterDetectedError) Error() string

type DefaultOutputWriter

type DefaultOutputWriter struct {
	// contains filtered or unexported fields
}

DefaultOutputWriter implements OutputWriter.

func NewOutputWriter

func NewOutputWriter(engine template.TemplateRenderer, pathProcessor PathProcessor) *DefaultOutputWriter

NewOutputWriter creates a new output writer.

func (*DefaultOutputWriter) SetAllowRecursiveRender

func (w *DefaultOutputWriter) SetAllowRecursiveRender(allow bool)

SetAllowRecursiveRender controls whether user-provided variable values containing template syntax are rendered in file content. When false (default), template delimiters in non-derived variable values are escaped to prevent SSTI.

func (*DefaultOutputWriter) SetDerivedVarNames

func (w *DefaultOutputWriter) SetDerivedVarNames(names map[string]bool)

SetDerivedVarNames sets the derived variable names for SSTI protection. Derived variables are always rendered through the template engine.

func (*DefaultOutputWriter) SetDryRun

func (w *DefaultOutputWriter) SetDryRun(v bool)

SetDryRun enables dry-run mode, where file paths are logged instead of written.

func (*DefaultOutputWriter) SetRecorder

func (w *DefaultOutputWriter) SetRecorder(r *history.Recorder)

SetRecorder attaches a history recorder to this writer. When set, every file written during scaffold is recorded as a "create" entry.

func (*DefaultOutputWriter) Write

func (w *DefaultOutputWriter) Write(templateRoot, outputDir string, vars map[string]any) error

Write processes the template directory and writes to the output directory.

type DefaultPathProcessor

type DefaultPathProcessor struct {
	// contains filtered or unexported fields
}

DefaultPathProcessor implements PathProcessor using the Gonja template engine.

func NewPathProcessor

func NewPathProcessor(engine template.TemplateRenderer) *DefaultPathProcessor

NewPathProcessor creates a new path processor with the given template renderer.

func (*DefaultPathProcessor) ProcessPath

func (p *DefaultPathProcessor) ProcessPath(path string, vars map[string]any) (string, error)

ProcessPath replaces placeholders in a path with variable values. Supports any valid Jinja2 expression including method calls. Examples: {{ vars.name }}, {{ vars.name | snake }}, {{ vars.name.lower() }}

func (*DefaultPathProcessor) SetAllowRecursiveRender

func (p *DefaultPathProcessor) SetAllowRecursiveRender(allow bool)

SetAllowRecursiveRender controls whether user-provided variable values containing template syntax are rendered. When false (default), template delimiters in non-derived variable values are escaped to prevent SSTI attacks. Derived variables (whose defaults are template expressions) are always rendered regardless.

func (*DefaultPathProcessor) SetDerivedVarNames

func (p *DefaultPathProcessor) SetDerivedVarNames(names map[string]bool)

SetDerivedVarNames sets the list of derived variable names. These variables have template expressions as defaults and need recursive rendering to resolve.

type DefaultVariableCollector

type DefaultVariableCollector struct {
	// contains filtered or unexported fields
}

DefaultVariableCollector implements VariableCollector with the standard priority chain.

func NewVariableCollector

func NewVariableCollector(prompter Prompter, output io.Writer) *DefaultVariableCollector

NewVariableCollector creates a new variable collector with the given prompter.

func (*DefaultVariableCollector) Collect

func (c *DefaultVariableCollector) Collect(config *TemplateConfig, opts Options, isTTY bool) (map[string]any, error)

Collect gathers variables following the priority chain: defaults -> --replay -> --values file -> --meta flags -> prompts

Meta overrides are applied before prompts so that evaluated defaults (expressions like "{{ vars.project_name | kebab }}") see CLI-provided values instead of static defaults. Variables are prompted in dependency order (topological sort) so that evaluated defaults can reference previously-prompted values.

func (*DefaultVariableCollector) WithEngine

func (c *DefaultVariableCollector) WithEngine(engine template.TemplateRenderer)

WithEngine sets the template engine used to resolve expression defaults at prompt time for evaluated-default variables (expanded form with prompt + template-expression default).

type FileProcessingError

type FileProcessingError struct {
	File    string
	Message string
	Err     error
}

FileProcessingError represents an error during template processing.

func NewFileProcessingError

func NewFileProcessingError(file, message string, err error) *FileProcessingError

NewFileProcessingError creates a new template error.

func (*FileProcessingError) Error

func (e *FileProcessingError) Error() string

func (*FileProcessingError) Unwrap

func (e *FileProcessingError) Unwrap() error

type InteractivePrompter

type InteractivePrompter struct{}

InteractivePrompter implements Prompter using charmbracelet/huh.

func NewInteractivePrompter

func NewInteractivePrompter() *InteractivePrompter

NewInteractivePrompter creates a new interactive prompter.

func (*InteractivePrompter) Confirm

func (p *InteractivePrompter) Confirm(label string, defaultValue bool) (bool, error)

Confirm prompts for a yes/no confirmation.

func (*InteractivePrompter) Input

func (p *InteractivePrompter) Input(label, defaultValue string, secret bool) (string, error)

Input prompts for a string value.

func (*InteractivePrompter) Number

func (p *InteractivePrompter) Number(label string, defaultValue float64) (float64, error)

Number prompts for a numeric value.

func (*InteractivePrompter) Select

func (p *InteractivePrompter) Select(label string, options []string, defaultIndex int) (string, error)

Select prompts for a selection from a list of options.

type NoopPrompter

type NoopPrompter struct{}

NoopPrompter is a prompter that returns defaults without prompting. Used when --no-input is specified or stdin is not a TTY.

func NewNoopPrompter

func NewNoopPrompter() *NoopPrompter

NewNoopPrompter creates a new noop prompter.

func (*NoopPrompter) Confirm

func (p *NoopPrompter) Confirm(label string, defaultValue bool) (bool, error)

Confirm returns the default value without prompting.

func (*NoopPrompter) Input

func (p *NoopPrompter) Input(label, defaultValue string, secret bool) (string, error)

Input returns the default value without prompting.

func (*NoopPrompter) Number

func (p *NoopPrompter) Number(label string, defaultValue float64) (float64, error)

Number returns the default value without prompting.

func (*NoopPrompter) Select

func (p *NoopPrompter) Select(label string, options []string, defaultIndex int) (string, error)

Select returns the first option (or default) without prompting.

type Options

type Options struct {
	TemplateDir          string            // Path to template directory
	OutputDir            string            // Output directory (-o flag)
	ProjectName          string            // Project name argument
	ValuesFile           string            // Path to values JSON file (--values flag)
	Meta                 map[string]string // Individual variable overrides (-m/--meta flags)
	NoInput              bool              // Skip interactive prompts (--no-input flag)
	Force                bool              // Overwrite existing output (--force flag)
	Replay               bool              // Use saved replay values (--replay flag)
	NoSave               bool              // Don't save inputs for replay (--no-save flag)
	TemplateRef          string            // Original template reference (for replay ID generation)
	AcceptHooks          bool              // Accept hooks without prompting (--accept-hooks flag)
	IsRemote             bool              // Whether the template source is remote
	AllowRecursiveRender bool              // Allow recursive template rendering in variable values (--allow-recursive-render flag)
	TemplateName         string            // Library name (set by tag scaffold)
	TemplateVersion      string            // From tag.template.json (set after config load)
	UpdateLock           bool              // Refresh lockfile entry for this template (--update-lock flag)
	IgnoreLock           bool              // Skip lockfile verification (--ignore-lock flag)
	DryRun               bool              // Preview changes without writing files (--dry-run flag)
	SkipGeneratorCopy    bool              // Skip copying generators/bundles to output .tag/ directory
}

Options represents scaffold command options.

type OutputWriter

type OutputWriter interface {
	// Write processes a template directory and writes output.
	Write(templateRoot, outputDir string, vars map[string]any) error
}

OutputWriter handles file generation and copying during scaffolding.

type PathError

type PathError struct {
	Path    string
	Message string
	Err     error
}

PathError represents an error related to path processing.

func NewPathError

func NewPathError(path, message string, err error) *PathError

NewPathError creates a new path error.

func (*PathError) Error

func (e *PathError) Error() string

func (*PathError) Unwrap

func (e *PathError) Unwrap() error

type PathProcessor

type PathProcessor interface {
	// ProcessPath processes a path, replacing Jinja2 expressions like {{ vars.name }}.
	ProcessPath(path string, vars map[string]any) (string, error)
}

PathProcessor handles path placeholder substitution.

type Prompter

type Prompter interface {
	// Input prompts for a string value with an optional default.
	Input(label, defaultValue string, secret bool) (string, error)
	// Select prompts for a selection from a list of options.
	Select(label string, options []string, defaultIndex int) (string, error)
	// Confirm prompts for a yes/no confirmation.
	Confirm(label string, defaultValue bool) (bool, error)
	// Number prompts for a numeric value.
	Number(label string, defaultValue float64) (float64, error)
}

Prompter defines the interface for interactive prompts.

func GetPrompter

func GetPrompter(noInput bool) Prompter

GetPrompter returns an appropriate prompter based on TTY status and noInput flag.

type SSTIConfigurable

type SSTIConfigurable interface {
	SetDerivedVarNames(names map[string]bool)
}

SSTIConfigurable is implemented by path processors that support derived-variable tracking for SSTI protection.

type Scaffold

type Scaffold struct {
	// contains filtered or unexported fields
}

Scaffold orchestrates the scaffolding process.

func NewScaffold

func NewScaffold(opts Options, fopts ...ScaffoldOption) (*Scaffold, error)

func (*Scaffold) Run

func (s *Scaffold) Run(opts Options) (ScaffoldResult, error)

Run executes the scaffolding process.

func (*Scaffold) SetRecorder

func (s *Scaffold) SetRecorder(r *history.Recorder)

SetRecorder attaches a history recorder. When set, file operations during scaffolding are recorded and a manifest entry is written on success.

type ScaffoldOption

type ScaffoldOption func(*Scaffold)

ScaffoldOption is a functional option for NewScaffold.

func WithEngine

func WithEngine(e *template.Engine) ScaffoldOption

WithEngine injects a pre-configured template engine. This allows callers to create an engine with specific options (e.g., dialect registry) before scaffold construction. If not provided, a default engine is created.

func WithIsTTY

func WithIsTTY(v bool) ScaffoldOption

WithIsTTY overrides the TTY detection for testing. In production, IsTTY() is called automatically by NewScaffold.

func WithOutput

func WithOutput(w io.Writer) ScaffoldOption

WithOutput sets the writer for user-facing messages.

type ScaffoldResult

type ScaffoldResult struct {
	OutputDir   string         // Absolute path to the top-level output directory
	ProjectRoot string         // Absolute path to the project root (may differ from OutputDir with wrapper dirs)
	TemplateDir string         // Absolute path to the template directory (for README)
	Vars        map[string]any // Resolved template variables
	Opts        Options        // Options used for this scaffold run
}

ScaffoldResult contains the output of a successful scaffold run. It carries the information needed by the commands layer to render a post-scaffold summary (output location, resolved variables, etc.).

type TagConfig

type TagConfig struct {
	SchemaVersion int                 `json:"schema_version,omitempty"`
	Template      *TagTemplate        `json:"template,omitempty"`
	Variables     map[string]any      `json:"variables,omitempty"`
	SkipPatterns  []string            `json:"skip_patterns,omitempty"`
	Env           map[string]string   `json:"env,omitempty"`
	Hooks         map[string][]string `json:"hooks,omitempty"`
}

TagConfig represents a parsed .tagconfig.json file. Used by the update system to read existing project configurations.

func LoadTagConfig

func LoadTagConfig(projectDir string) (*TagConfig, error)

LoadTagConfig reads and parses a .tagconfig.json from the given project directory.

func ParseTagConfigJSON

func ParseTagConfigJSON(data []byte) (*TagConfig, error)

ParseTagConfigJSON parses raw JSON bytes into a TagConfig.

func (*TagConfig) HasTemplateOrigin

func (c *TagConfig) HasTemplateOrigin() bool

HasTemplateOrigin reports whether the config has enough template metadata for the update system to resolve the original template.

type TagConfigOptions

type TagConfigOptions struct {
	TemplateType    types.TemplateType // "local" or "remote"
	TemplateSource  string             // Original ref (e.g., "gh:user/repo" or local path)
	TemplateName    string             // Library name (if any)
	TemplateVersion string             // From tag.template.json
	TemplateRef     string             // Branch/tag used (e.g., "main", "v1.2.0")
	CommitSHA       string             // Resolved git commit SHA (empty for local/zip)
	SkipPatterns    []string           // User-configurable update exclusions
	Variables       map[string]any     // Scaffold-time variable values
}

TagConfigOptions provides template metadata for enriched .tagconfig.json generation.

type TagTemplate

type TagTemplate struct {
	Type      types.TemplateType `json:"type,omitempty"`
	Source    string             `json:"source,omitempty"`
	Name      string             `json:"name,omitempty"`
	Version   string             `json:"version,omitempty"`
	Ref       string             `json:"ref,omitempty"`
	CommitSHA string             `json:"commit,omitempty"`
}

TagTemplate describes the template origin recorded in .tagconfig.json.

type TemplateConfig

type TemplateConfig = tmplconfig.TemplateConfig

Type aliases for backward compatibility within the scaffold package. External packages should import tmplconfig directly.

type VariableCollector

type VariableCollector interface {
	Collect(config *TemplateConfig, opts Options, isTTY bool) (map[string]any, error)
}

VariableCollector gathers variable values from all sources.

type VariableDef

type VariableDef = tmplconfig.VariableDef

Type aliases for backward compatibility within the scaffold package. External packages should import tmplconfig directly.

type VariableError

type VariableError struct {
	Name    string
	Message string
	Err     error
}

VariableError represents an error related to a specific variable.

func NewVariableError

func NewVariableError(name, message string, err error) *VariableError

NewVariableError creates a new variable error.

func (*VariableError) Error

func (e *VariableError) Error() string

func (*VariableError) Unwrap

func (e *VariableError) Unwrap() error

type VariableType

type VariableType = tmplconfig.VariableType

Type aliases for backward compatibility within the scaffold package. External packages should import tmplconfig directly.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL