Scaffold Project Generation Tool

repository·main·Indexed 41 days ago

https://github.com/hay-kot/scaffold

A Go-based project generation tool that uses Go templates to bootstrap new projects or inject boilerplate code into existing ones. It supports Git-based and local file system templates, multi-location generation via a `.scaffolds` directory, and interactive UX with conditional prompting. Key features include project initialization, template linting, metadata inspection, and the ability to inject snippets into existing files.

Tokens
28.6K
Snippets
126
Records
169
Agent score
52%

What's inside Scaffold

  1. Overview of Scaffold features

    main

    Scaffold is a project template scaffolding tool designed to generate boilerplate code efficiently. Key capabilities include:

    • Feature Flag Support: Use feature flags to guard large sections of templates, enabling easy feature toggling.
    • Interactive Forms: Powerful, grouped, and conditional inputs powered by Charm.sh for user prompts.
    • In-Project Scaffolding: Run scaffolds within an existing project to create new files or inject code into existing files.
    • Template Testing: Built-in utilities to test scaffolds and ensure template reliability.
  2. What is Scaffold?

    main

    Scaffold is a project generation tool written in Go that uses the Go template engine to generate projects from templates. It supports both local file system templates and Git-based templates (public or private).

    Unlike traditional scaffolding tools, Scaffold supports two distinct modes of operation:

    1. Whole Project Scaffolding: Generating a complete new project from a template (e.g., bootstrapping a new microservice).
    2. Template Scaffolds: Defining reusable scaffolds within a .scaffolds directory of an existing project. These can generate files in multiple locations or inject code snippets into existing files, making them ideal for generating boilerplate like components, Ansible roles, or API stubs.
  3. Overview of Scaffold project generation

    main

    Scaffold is a project generation tool written in Go, similar to cookiecutter, that uses the Go template engine to generate projects from templates. It supports both Git-based and local file system templates.

    A key differentiator is its ability to define template scaffolds within a .scaffolds directory of an existing project. These allow you to bootstrap code changes or boilerplate across multiple locations in a project simultaneously (e.g., generating React components, Ansible roles, or CRUD API stubs).

  4. Core features of Scaffold

    main

    Scaffold provides the following capabilities:

    • Project Generation: Generate entire projects from a template.
    • Scaffold Management: Update scaffolds with scaffold update and list available scaffolds with scaffold list.
    • Multi-location Generation: Generate files in multiple locations within an existing project using the .scaffolds directory.
    • Interactive UX: Supports conditional prompting based on user input and pre/post messages (supporting Markdown).
    • Advanced Templating:
      • Inject snippets into existing files using Scaffold Templates.
      • Feature flag support to block or enable the rendering of entire directories or specific glob matches.
    • CLI Ergonomics: Supports command aliases and shortcuts for common prefixes (e.g., gh: for github.com).
  5. Use feature flags to conditionally render files

    main

    The features field allows you to conditionally render entire directories or files based on a boolean value. This is ideal for optional components like databases or CI pipelines.

    Each feature entry contains:

    • value: A Go template expression that evaluates to a boolean.
    • globs: A list of glob patterns that will be rendered if value is true.
    features:
      - value: "{{ .Scaffold.database }}"
        globs:
          - "**/core/database/**/*"
  6. Expand multiple files using `each`

    main

    The each field enables multi-file output by expanding path segments containing [varname]. This allows you to generate a unique file or directory for every item in a list provided by a looped question.

    How to use each

    1. Define a question with loop: true (e.g., name: "services").
    2. Add that variable name to the each list.
    3. Use [services] in your template file or directory names.

    Context inside templates

    When expanding paths, you can access the current item and its index within the template using:

    • {{ .Each.Item }}: The current string value.
    • {{ .Each.Index }}: The zero-based index.

    Path Transformation with as

    By default, the item value is used directly. To transform the path (e.g., to PascalCase), use the object form with the as key.

    Supported Formats

    You can mix the string shorthand and the object form in the each array.

    # 1. Define the looped question
    questions:
      - name: "services"
        prompt:
          message: "Service names"
          loop: true
    
    # 2. Register the variable for expansion
    each:
      - services
      - var: models
        as: "{{ .Each.Item | toPascalCase }}"
    
    # 3. Use [services] or [models] in your file structure:
    # templates/[services]/handler.go
    # templates/[models].txt
  7. Template rendering and file inclusion rules

    main

    The Scaffold template engine follows specific rules regarding which files and directories are included in the final generated project based on their content after rendering:

    1. Empty source files: Files that are empty in the template source are skipped.
    2. Empty rendered files: If a template file results in an empty file after all variables and functions are processed, it is not included in the generated project.
    3. Empty directories: Any directories that do not contain any files (after the rules above are applied) are not included in the generated project.
  8. Understand scaffold default paths and cache behavior

    main

    Scaffold uses XDG base directory specifications for its default paths, but will fall back to legacy paths if they exist on disk.

    PurposeXDG PathLegacy Path
    ScaffoldRC$XDG_CONFIG_HOME/scaffold/scaffoldrc.yml~/.scaffold/scaffoldrc.yml
    Cache$XDG_DATA_HOME/scaffold/templates~/.scaffold/cache

    Note: XDG defaults typically resolve to ~/.config/ for configuration and ~/.local/share/ for data.

    Cache Management: Remote scaffolds (accessed via URLs or shorts) are cloned into the cache directory. You can override this location using the --cache flag or the SCAFFOLD_CACHE environment variable. To pull the latest updates for all scaffolds currently stored in your cache, use the scaffold update command.

  9. How scaffold argument resolution works

    main

    When generating a project, the scaffold argument you provide is resolved to a specific directory using a hierarchical lookup system. The resolution follows these rules:

    1. Remote Repositories: If the argument is a URL (e.g., https://github.com/org/repo), Scaffold clones the repository. If a subdirectory is specified using the # fragment (e.g., https://github.com/org/repo#subdirectory), it uses that specific subdirectory within the cloned repo.
    2. Absolute Paths: If the argument is a local absolute path, Scaffold uses it directly.
    3. Relative Paths: If the argument contains a / but is not an absolute path or a URL, it is treated as a local relative path (e.g., ./my-scaffold or ../shared-scaffolds/my-scaffold).
    4. Scaffold Names (Aliases): If the argument contains no slashes (e.g., my-scaffold), Scaffold searches for a match within the local ./.scaffold/ directory.

    Requirement: Regardless of how the path is resolved, the resulting directory must contain a scaffold.yaml or scaffold.yml configuration file.

  10. How Template Partials work

    main

    Template partials are reusable components stored in a partials/ directory at the root of your scaffold project. The scaffold engine automatically detects this directory and registers every file within it as a named partial. This allows you to reduce duplication across multiple template files.

    Project structure example:

    my-scaffold/
    ├── scaffold.yml
    ├── partials/
    │   ├── header.txt
    │   ├── footer.txt
    │   └── common/
    │       └── sidebar.txt
    ├── {{ .Project }}/
    │   └── index.html
    my-scaffold/
    ├── scaffold.yml
    ├── partials/
    │   ├── header.txt
    │   ├── footer.txt
    │   └── common/
    │       └── sidebar.txt
    ├── {{ .Project }}/
    │   └── index.html