{"id":25853123,"url":"https://github.com/aliev/baker","last_synced_at":"2025-10-10T21:44:58.264Z","repository":{"id":272058002,"uuid":"892460035","full_name":"aliev/baker","owner":"aliev","description":"Baker is a command-line tool that helps you quickly scaffold new projects. It supports language-independent hooks for automating routine tasks. Baker is written in Rust and distributed as a standalone binary.","archived":false,"fork":false,"pushed_at":"2025-10-06T17:36:15.000Z","size":720,"stargazers_count":32,"open_issues_count":2,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-10-06T19:32:45.863Z","etag":null,"topics":["cli","cross-platform","project-template","rust","scaffolding","terminal"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aliev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-11-22T06:40:08.000Z","updated_at":"2025-10-06T17:36:13.000Z","dependencies_parsed_at":"2025-03-28T20:27:02.993Z","dependency_job_id":"1db28c1b-dde6-4eca-8cfc-8db87cbae811","html_url":"https://github.com/aliev/baker","commit_stats":null,"previous_names":["aliev/baker"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/aliev/baker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliev%2Fbaker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliev%2Fbaker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliev%2Fbaker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliev%2Fbaker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aliev","download_url":"https://codeload.github.com/aliev/baker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliev%2Fbaker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279005428,"owners_count":26083883,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cross-platform","project-template","rust","scaffolding","terminal"],"created_at":"2025-03-01T14:33:23.758Z","updated_at":"2025-10-10T21:44:58.257Z","avatar_url":"https://github.com/aliev.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# What is Baker?\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.ai.png\" alt=\"\" width=100\u003e\n  \u003cp\u003e\u003cstrong\u003eBaker\u003c/strong\u003e is a command-line tool that helps you quickly \u003ca href=\"https://en.wikipedia.org/wiki/Scaffold_(programming)\"\u003escaffold\u003c/a\u003e new projects. It supports language-independent \u003ca href=\"#using-hooks\"\u003ehooks\u003c/a\u003e for automating routine tasks. Baker is written in Rust and distributed as a standalone binary. Precompiled binaries are available for popular platforms on the \u003ca href=\"https://github.com/aliev/baker/releases\"\u003ereleases page\u003c/a\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\n## Table of Contents\n\n- [Architecture Overview](#architecture-overview)\n- [Installation](#installation)\n- [Project template example](#project-template-example)\n  - [baker.yaml File](#bakeryaml-file)\n  - [Files with .baker.j2 extension](#files-with-bakerj2-extension)\n  - [Templated File Names](#templated-file-names)\n  - [.bakerignore File](#bakerignore-file)\n  - [Importing Jinja templates and macros](#importing-jinja-templates-and-macros)\n  - [Loop Templates and Delimiters](#loop-templates-and-delimiters)\n- [Recipes](#recipes)\n  - [Passing Default Answers](#passing-default-answers)\n  - [Non-Interactive Mode](#non-interactive-mode)\n  - [Conditional Questions](#conditional-questions)\n  - [Debugging Templates](#debugging-templates)\n- [Hooks](#hooks)\n  - [Customizing Hook Filenames](#customizing-hook-filenames)\n  - [Customizing Hook Runners](#customizing-hook-runners)\n  - [Available Platform Variables](#available-platform-variables)\n- [Questions](#questions)\n  - [Single-Input](#single-input)\n  - [Yes / No](#yes--no)\n  - [Single Choice](#single-choice)\n  - [Multiple Choice](#multiple-choice)\n  - [JSON Complex Type](#json-complex-type)\n  - [YAML Complex Type](#yaml-complex-type)\n  - [Validation](#validation)\n    - [Required Field Validation](#required-field-validation)\n    - [Numeric Value Validation](#numeric-value-validation)\n    - [Pattern Matching with Regular Expressions](#pattern-matching-with-regular-expressions)\n  - [Conditional questions](#conditional-questions)\n- [Built-in Filters](#built-in-filters)\n- [Comparing Baker to other project generators](#comparing-baker-to-other-project-generators)\n- [Community Templates](#community-templates)\n\n## Architecture Overview\n\nLooking for an end-to-end view of the codebase? See [`docs/architecture.md`](docs/architecture.md) for a tour of the CLI runner, configuration loader, prompt layer, template processor, and supporting modules.\n\n## Installation\n\nYou can install Baker using one of the following methods:\n\n### Install via Homebrew (macOS)\n\n```bash\nbrew install aliev/tap/baker\n```\n\n### Install prebuilt binaries via shell script (Linux/macOS)\n\n```bash\ncurl --proto '=https' --tlsv1.2 -LsSf https://github.com/aliev/baker/releases/latest/download/baker-installer.sh | sh\n```\n\n### Install prebuilt binaries via PowerShell script (Windows)\n\n```powershell\npowershell -ExecutionPolicy Bypass -c \"irm https://github.com/aliev/baker/releases/latest/download/baker-installer.ps1 | iex\"\n```\n\nPrebuilt binaries for all supported platforms are available on the [releases page](https://github.com/aliev/baker/releases).\n\n## Project template example\n\nTo get started, you can use the [examples/demo](examples/demo) template, which demonstrates the core features of Baker:\n\n```\n│   Template configuration.\n├── baker.yaml\n│\n│   The content of files with the `.baker.j2` extension will be processed by the templating engine\n├── CONTRIBUTING.md.baker.j2\n│\n│   any other files will be copied as is,\n├── README.md\n│\n│   unless they are listed in .bakerignore.\n├── .bakerignore\n│\n│   File names can be templated\n├── {{project_slug}}\n│   └── __init__.py\n│\n│   any template features can be used, such as conditions:\n└── {% if use_tests %}tests{% endif %}\n    └── __init__.py\n```\n\nAs a quick start, you can run the following command to generate a project:\n\n```\nbaker examples/demo my-project\n```\n\nEach component of this template is described in detail below.\n\n### `baker.yaml` File\n\nThe `baker.yaml` file defines the directory as a template. It contains template settings and [questions](#question) to be prompted to the user:\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  project_name:\n    type: str\n    help: Please enter the name of your project\n\n  project_author:\n    type: str\n    help: \"Please enter the author's name for {{project_name}}\"\n\n  project_slug:\n    type: str\n    help: Please enter the project slug (or press Enter to use the default)\n    default: \"{{ project_name|lower|replace(' ', '_') }}\"\n\n  use_tests:\n    type: bool\n    help: Will your project include tests?\n    default: true\n```\n\nThe values of the `help` and `default` keys can include templates for value substitution. Each subsequent question has access to the answers of the previous ones as demonstrated in `project_author` and `project_slug`.\n\nIn addition to YAML, Baker also supports JSON due to its backward compatibility with JSON. If multiple configuration files exist in the template directory, Baker will load them in the following order of priority: `baker.json`, `baker.yaml`, and `baker.yml`.\n\n### Files with `.baker.j2` extension\n\nThe content of files with the `.baker.j2` extension will be processed by the templating engine and written to the target directory. The resulting files in the target directory will not include the `.baker.j2` extension in their names.\n\nThe content of such files can include the `questions` keys, which will be replaced by the corresponding user-provided answers during processing. Baker uses the MiniJinja this purpose. For more details on the syntax and capabilities of the templating engine, please refer to the [MiniJinja](https://docs.rs/minijinja/latest/minijinja/) documentation.\n\n**Example:**\n\n**Content of CONTRIBUTING.md.baker.j2**\n\n```\n  # {{project_name}}\n  Author: {{project_author}}\n```\n\n**Processed file in target directory: CONTRIBUTING.md**\n\n```\nContent of CONTRIBUTING.md:\n  # MyAwesomeProject\n  Author: John Doe\n```\n\nNote:\nThe template suffix (default: .baker.j2) is fully configurable in your baker.yaml file using the template_suffix option. You can set it to any value, as long as it starts with a . and has at least one character after the dot (e.g., .tpl, .jinja, .tmpl). This allows you to use custom extensions for your template files.\n\nExample:\n\n```\nschemaVersion: v1\ntemplate_suffix: \".tpl\"\n```\n\nWith this configuration, files ending with .tpl will be processed as templates instead of .baker.j2.\n\n### Templated File Names\n\nFile and directory names can be templated to dynamically adjust based on user input.\n\n**Example:**\n\n```yaml\nproject_name:\n  type: str\n  help: Please enter the name of your project\n\nproject_slug:\n  type: str\n  help: Please enter the project slug (or press Enter to use the default)\n  default: \"{{ project_name|lower|replace(' ', '_') }}\"\n```\n\n```\n├── {{project_slug}}\n│ └── __init__.py\n```\n\nThis will create a directory named according to the value of the `project_slug` provided by the user.\n\n---\n\nFile and directory names can include conditions that control their creation. If a condition evaluates to `false`, the corresponding file or directory will not be created. This feature is especially useful with [Yes / No](#yes--no) type questions, allowing you to dynamically include or exclude specific files and directories based on user responses.\n\n**Example:**\n\n```yaml\nuse_tests:\n  type: bool\n  help: Will your project include tests?\n  default: true\n```\n\n```\n└── {% if use_tests %}tests{% endif %}\n    └── __init__.py\n```\n\nIn this example, if the user answers \"no\" the `tests` directory will not be created.\n\n### `.bakerignore` File\n\nThe `.bakerignore` file in the template root is used to exclude files and directories from being copied from the template. Bakerignore uses [Globset syntax](https://docs.rs/globset/latest/globset/#syntax).\n\nBy default, Baker ignores the following files and patterns:\n\n```rust\nconst DEFAULT_IGNORE_PATTERNS: \u0026[\u0026str] = \u0026[\n    \".git/**\",\n    \".git\",\n    \".hg/**\",\n    \".hg\",\n    \".svn/**\",\n    \".svn\",\n    \"**/.DS_Store\",\n    \".bakerignore\",\n    \"hooks\",\n    \"hooks/**\",\n    \"baker.yaml\",\n    \"baker.yml\",\n    \"baker.json\",\n];\n```\n\n## Importing Jinja templates and macros\n\nYou can specify multiple patterns for files to be included in the template engine. Then you can [include templates](https://docs.rs/minijinja/latest/minijinja/syntax/index.html#-include-) or [import macros](https://docs.rs/minijinja/latest/minijinja/syntax/index.html#-import-) in your templates.\n\n#### Example:\n\n```yaml\nschemaVersion: v1\ntemplate_globs:\n  - \"*.tpl\"\n  - \"*.jinja\"\nquestions:\n  project_name:\n    type: str\n    help: Please enter the name of your project\n```\n\nThis will include all files ending with .tpl and .jinja in the template engine, allowing you to use them in your templates.\n\n\n## Loop Templates and Delimiters\n\nBaker supports loop templates using MiniJinja for-loop blocks in template filenames. This allows you to generate multiple files based on a list of items in your answers.\n\nFor example, a template file named:\n\n```\n{% for item in items %}{{ item.name }}.md.baker.j2{% endfor %}\n```\nwill generate a file for each item in the `items` array, with the filename rendered from `item.name`.\n\n### loop_separator and loop_content_separator\n\nWhen rendering loop templates, Baker uses two configuration options to split and organize the generated content:\n\n- `loop_separator`: A string used to separate each file's content in the rendered output. This allows Baker to distinguish between multiple files generated from a single loop template. Default value is `\u003c--SPLIT--\u003e`.\n- `loop_content_separator`: A string used to separate the filename from the file content within each split section. This enables Baker to extract the correct filename and its corresponding content. Default value is `\u003c\u003cCONTENT\u003e\u003e`.\n\n**Example Usage:**\n\nSuppose your template renders the following output:\n\n```\nfilename1.md\u003c\u003cCONTENT\u003e\u003eContent for file 1\u003c--SPLIT--\u003e\nfilename2.md\u003c\u003cCONTENT\u003e\u003eContent for file 2\u003c--SPLIT--\u003e\n```\n\nHere, `\u003c\u003cCONTENT\u003e\u003e` is the `loop_content_separator` and `\u003c--SPLIT--\u003e` is the `loop_separator`. Baker will split the output on `\u003c--SPLIT--\u003e`, then split each part on `\u003c\u003cCONTENT\u003e\u003e` to get the filename and content for each file.\n\nYou can configure these separators in your Baker settings or pass them to the processor:\n\n```yaml\nschemaVersion: v1\ntemplate_suffix: \".baker.j2\",\nloop_separator: \"\u003c--SPLIT--\u003e\",\nloop_content_separator: \"\u003c\u003cCONTENT\u003e\u003e\",\n```\n\nThis mechanism allows flexible generation of multiple files from a single template, especially useful for code generation, documentation, or any batch file creation scenario.\n\n## Recipes\n\n### Passing Default Answers\n\nPassing default answers can be useful when the answers are already known, such as in a CI/CD pipeline.\n\nDefault answers can be provided using the `--answers` option.\n\n**Example**\n\n```bash\n# Alternatively, use --answers='{\"name\": \"John\"}'\necho '{\"name\": \"John\"}' | baker template my-project --answers=-\n```\n\n```yaml\nschemaVersion: v1\nquestions:\n  name:\n    type: str\n    help: What is your name?\n```\n\nThe provided answer will be used as the default in the user prompt:\n\n```\nWhat is your name? [John]:\n```\n\n#### Non-Interactive Mode\n\nFor fully automated workflows like CI/CD pipelines, you can combine `--answers` with the `--non-interactive` flag to completely skip all prompts:\n\n```bash\nbaker template my-project --answers='{\"project_name\": \"Example Project\"}' --non-interactive\n```\n\nIn `--non-interactive` mode, Baker determines whether to skip user prompts based on two factors:\n\n1. The `--non-interactive` flag itself\n2. The template's `ask_if` conditions (if defined)\n\nWhen a prompt is skipped, Baker uses the following strategy to determine the answer:\n\n1. If an answer was already provided via the `--answers` parameter, use that value\n2. If a default value (`default`) exists in the template configuration, use that\n3. If neither exists, Baker will still prompt the user interactively for that question\n\nFor example, if your template contains:\n\n```yaml\nschemaVersion: v1\nquestions:\n  project_name:\n    type: str\n    help: Please enter the name of your project\n  project_author:\n    type: str\n    help: Please enter the author's name\n    default: Anonymous\n  use_tests:\n    type: bool\n    help: Will your project include tests?\n    default: true\n```\n\nAnd you run:\n\n```bash\nbaker template my-project --answers='{\"project_name\": \"Example\"}' --non-interactive\n```\n\nBaker will automatically use \"Example\" for `project_name`, \"Anonymous\" for `project_author` (from the default value), and `true` for `use_tests` (from the default value).\n\nThis is especially useful for CI/CD environments where interactive input isn't possible.\n\n#### Conditional Questions\n\nTo skip the prompt entirely, you can use the `ask_if` attribute:\n\n```yaml\nschemaVersion: v1\nquestions:\n  name:\n    type: str\n    help: What is your name?\n    # Skips the prompt if \"name\" was provided in answers\n    ask_if: name is not defined or name == ''\n```\n\nA detailed description of the `ask_if` key can be found in the [Conditional Questions](#conditional-questions) section.\n\n### Debugging Templates\n\nSince Baker uses MiniJinja, it benefits from all MiniJinja features, including debugging. You can use the `debug()` function to inspect the current context.\n\n**Example**\n\n```yaml\nschemaVersion: v1\nquestions:\n  first_name:\n    type: str\n    help: What is your name?\n  last_name:\n    type: str\n    help: \"Hello, {{first_name}}. What is your last name?\"\n  debug:\n    type: str\n    help: \"{{debug()}}\"\n```\n\nWhen you run the template, the `debug()` function will output the current context:\n\n```\nbaker example out\nWhat is your name?: aaa\nHello, aaa. What is your last name?: bbb\nState {\n    name: \"temp\",\n    current_block: None,\n    auto_escape: None,\n    ctx: {\n        \"first_name\": \"aaa\",\n        \"last_name\": \"bbb\",\n    },\n    env: Environment {\n        globals: {\n            \"debug\": minijinja::functions::builtins::debug,\n            \"dict\": minijinja::functions::builtins::dict,\n            \"namespace\": minijinja::functions::builtins::namespace,\n            \"range\": minijinja::functions::builtins::range,\n        },\n        tests: [\n            \"!=\",\n            \"\u003c\",\n            \"\u003c=\",\n            \"==\",\n            \"\u003e\",\n            \"\u003e=\",\n            \"boolean\",\n            \"defined\",\n            \"divisibleby\",\n...\n```\n\nThis output provides a detailed view of the current context, including defined variables, their values, and available functions, helping you troubleshoot and debug your templates effectively.\n\n## Hooks\n\nHooks are useful for performing routine tasks before (pre-hook) or after (post-hook) project generation.\n\nBaker executes hooks as separate processes, which makes them language-independent.\n\nFor a hook to be executed, it must meet two requirements:\n\n1. It must be located in the template directory `template_root/hooks/` and named according to the `pre_hook_filename` or `post_hook_filename` specified in the configuration.\n2. It must be an executable file (`chmod +x template_root/hooks/\u003chook_filename\u003e`).\n\nWhen generating a project containing a hook, Baker will issue a warning:\n\n```\nbaker examples/hooks out\nWARNING: This template contains the following hooks that will execute commands on your system:\nexamples/hooks/hooks/post\nDo you want to run these hooks? [y/N]\n```\n\nThis warning can be omitted by using the `--skip-confirms=hooks` parameter.\n\nThe `pre` hook can generate answers and pass them to `baker` through `stdout`:\n\n```python\n#!/usr/bin/env python\nimport json\n\nif __name__ == \"__main__\":\n    # Passing the default answers to baker\n    json.dump({\"name\": \"John\"}, sys.stdout)\n```\n\nThe `post` hook can consume the answers, which will be passed by `baker` to the `stdin` of the `post` hook. The answers can be parsed as follows:\n\n```python\n#!/usr/bin/env python\nimport json\nimport pathlib\nfrom typing import Any, TypedDict\n\npath = pathlib.Path()\n\nclass Input(TypedDict):\n    answers: dict[str, Any]\n    template_dir: str\n    output_dir: str\n\nif __name__ == \"__main__\":\n    context: Input = json.load(sys.stdin)\n    output_dir_path = path / context[\"output_dir\"]\n    template_dir_path = path / context[\"template_dir\"]\n```\n\nThe diagram below illustrates this process in more detail\n\n```mermaid\ngraph LR\n    %% Data streams\n    Pre[hooks/pre] --\u003e stdout1[stdout]\n    stdout1 --\u003e |JSON answers| Baker[baker]\n    any_cmd --\u003e |JSON answers| stdin2[stdin] --\u003e Baker\n    Baker --\u003e |JSON output| stdin3[stdin]\n    stdin3 --\u003e Post[hooks/post]\n    Post --\u003e stdout3[stdout]\n\n    %% Add descriptions\n    subgraph Pre-processing\n        Pre\n    end\n\n    subgraph Main Process\n        Baker\n    end\n\n    subgraph Post-processing\n        Post\n    end\n\n    %% Style\n    classDef process fill:#2d3436,stroke:#fff,stroke-width:2px,color:#fff\n    classDef stream fill:#3498db,stroke:#fff,stroke-width:2px,color:#fff\n\n    class Pre,Post,Baker process\n    class stdin2,stdin3,stdout1,stdout3 stream\n```\n\n### Customizing Hook Filenames\n\nBy default, Baker looks for hook scripts named `pre` and `post` in the `hooks` directory of your template. You can customize these filenames using the `pre_hook_filename` and `post_hook_filename` configuration options in your `baker.yaml` file:\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  # Your regular questions here...\n\n# Custom hook filenames\npre_hook_filename: \"setup-environment\"\npost_hook_filename: \"finalize-project\"\n```\n\nWith this configuration, Baker will:\n\n1. Look for a pre-hook script at `template_root/hooks/setup-environment`\n2. Look for a post-hook script at `template_root/hooks/finalize-project`\n\nHook filenames also support template strings, which can be used to create platform-specific hooks:\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  license:\n    type: str\n    help: \"Please select a licence for {{platform.os}}\"\n    default: MIT\n    choices:\n      - MIT\n      - BSD\n      - GPLv3\n      - Apache Software License 2.0\n      - Not open source\n\npre_hook_filename: \"{{platform.family}}/pre\"\npost_hook_filename: \"{{platform.family}}/post\"\n```\n\nThis configuration allows you to organize hooks by platform. For example:\n\n```\nhooks/\n├── unix/\n│   ├── pre\n│   └── post\n└── windows/\n    ├── pre\n    └── post\n```\n\nBaker will automatically select the appropriate hook based on the current platform.\n\n### Customizing Hook Runners\n\nYou can declare how Baker should execute hook scripts by specifying a runner for\neach hook. Runners are defined as arrays of strings (similar to Docker's\n`ENTRYPOINT` syntax), allowing you to include the command and its arguments.\n\n```yaml\npre_hook_filename: pre.ps1\npre_hook_runner:\n  - powershell\n  - -NoLogo\n  - -File\n\npost_hook_filename: post.py\npost_hook_runner:\n  - python3\n  - -u\n```\n\n- If a runner is provided, Baker runs the hook using the supplied command and\n  passes the rendered hook path as the final argument.\n- If omitted (default), Baker executes the hook path directly, matching the\n  existing behaviour on Unix systems with executable scripts.\n- Runner tokens are rendered through the template engine, so you can use\n  variables from `baker.yaml` if needed.\n\nThis feature is especially helpful on Windows where scripts such as `.ps1`\ncannot be launched directly, and on Unix when you want to force a specific\ninterpreter (e.g., Python, Node.js, Bash).\n\n### Available Platform Variables\n\nBaker provides these platform variables that can be used in templates and hook filenames:\n\n- `platform.os` - Operating system name (e.g., \"linux\", \"macos\", \"windows\")\n- `platform.family` - OS family (e.g., \"unix\", \"windows\")\n- `platform.arch` - CPU architecture (e.g., \"x86_64\", \"aarch64\")\n\nYou can use these variables in any template, including hook filenames, questions, help text, defaults, etc.\n\n## Questions\n\nBaker supports various question components, which are described below.\n\n### Single-Input\n\nSingle Input prompts the user to enter a text value.\n\n#### Example\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  readme_content:\n    type: str\n    help: Please enter the content for CONTRIBUTING.md\n    default: My super duper project\n```\n\n- **`type`**: Must be `str`.\n- **`help`**: Should be a string, optionally containing a `minijinja` template.\n- **`default`**: Should be a string, optionally containing a `minijinja` template.\n\n#### Result\n\n```\nPlease enter the content for CONTRIBUTING.md []:\n```\n\n### Yes / No\n\n#### Example\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  include_tests:\n    type: bool\n    help: Do you want to include tests in the generated project?\n    default: true\n```\n\n- **`type`**: Must be `bool`.\n- **`help`**: Should be a string, optionally containing a `minijinja` template.\n- **`default`**: Should be a boolean value, defaulting to `false`.\n\n#### Result\n\n```\nDo you want to include tests in the generated project? [Y/n]\n```\n\n### Single Choice\n\n#### Example\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  favourite_language:\n    type: str\n    help: What is your favorite programming language?\n    default: Rust\n    choices:\n      - Python\n      - Rust\n      - Go\n      - TypeScript\n```\n\n- **`type`**: Must be `str`.\n- **`help`**: Should be a string, optionally containing a `minijinja` template.\n- **`choices`**: Should be a list of strings.\n- **`default`**: Should be a string, optionally containing a `minijinja` template.\n\n#### Result\n\n```\nWhat is your favorite programming language?:\n  Python\n\u003e Rust\n  Go\n  TypeScript\n```\n\n### Multiple Choice\n\n#### Example\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  favourite_language:\n    type: str\n    help: What are your favorite programming languages?\n    multiselect: true\n    default:\n      - Python\n      - Rust\n    choices:\n      - Python\n      - Rust\n      - Go\n      - TypeScript\n```\n\n- **`type`**: Must be `str`.\n- **`help`**: Should be a string, optionally containing a `minijinja` template.\n- **`multiselect`**: Must be `true` to enable multiple choice.\n- **`default`**: Should be a list of strings.\n- **`choices`**: Should be a list of strings.\n\n#### Result\n\n```\nWhat are your favorite programming languages?:\n  [x] Python\n\u003e [x] Rust\n  [ ] Go\n  [ ] TypeScript\n```\n\n### JSON Complex Type\n\nThe JSON type allows you to collect structured data from the user in JSON format. This is useful for configuration files, environment settings, and other structured data.\n\n#### Example\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  database_config:\n    type: json\n    help: Configure your database settings\n    schema: |\n      {\n        \"type\": \"object\",\n        \"required\": [\"engine\", \"host\", \"port\"],\n        \"properties\": {\n          \"engine\": {\n            \"type\": \"string\",\n            \"enum\": [\"postgresql\", \"mysql\", \"sqlite\", \"mongodb\"]\n          },\n          \"host\": {\n            \"type\": \"string\"\n          },\n          \"port\": {\n            \"type\": \"integer\",\n            \"minimum\": 1,\n            \"maximum\": 65535\n          }\n        }\n      }\n    default: |\n      {\n        \"engine\": \"postgresql\",\n        \"host\": \"localhost\",\n        \"port\": 5432\n      }\n```\n\n- **`type`**: Must be `json`.\n- **`help`**: Should be a string, optionally containing a `minijinja` template.\n- **`schema`**: Optional JSON Schema for validation. Follows the [JSON Schema standard](https://json-schema.org/).\n- **`default`**: JSON object, can be provided as a string or native YAML object.\n\n#### Result\n\nWhen prompted for JSON input, the user is given multiple options:\n\n1. Open in external text editor\n2. Enter multi-line input in console\n\n```\nConfigure your database settings - Choose input method:\n\u003e Use text editor\n  Enter inline\n```\n\nJSON data can be accessed in templates like any other nested structure:\n\n```\nConnection string: {{ database_config.engine }}://{{ database_config.host }}:{{ database_config.port }}\n```\n\n### YAML Complex Type\n\nThe YAML type works similarly to the JSON type but uses YAML syntax, which is more readable and less verbose.\n\n#### Example\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  environments:\n    type: yaml\n    help: Configure your deployment environments\n    default:\n      development:\n        url: http://localhost:8000\n        debug: true\n      staging:\n        url: https://staging.example.com\n        debug: true\n      production:\n        url: https://example.com\n        debug: false\n```\n\n- **`type`**: Must be `yaml`.\n- **`help`**: Should be a string, optionally containing a `minijinja` template.\n- **`schema`**: Optional JSON Schema for validation (same format as for JSON type).\n- **`default`**: YAML data, can be provided as a string or native YAML object.\n\n#### Result\n\nSimilar to JSON input, the user is prompted to choose an input method. YAML is particularly useful for configuration data due to its readability:\n\n```\nDefine your environments:\n\ndevelopment:\n  url: http://localhost:8000\n  debug: true\nstaging:\n  url: https://staging.example.com\n  debug: true\nproduction:\n  url: https://example.com\n  debug: false\n```\n\nTemplate usage:\n\n```\n{% for env_name, env_config in environments|items %}\n[{{ env_name }}]\nURL={{ env_config.url }}\nDEBUG={{ env_config.debug }}\n\n{% endfor %}\n```\n\n### Validation\n\nBaker supports answer validation using the `validation` attribute. The `condition` attribute uses MiniJinja's expression language to validate user input, while `error_message` provides feedback when validation fails.\n\n#### Required Field Validation\n\nEnsure a field is not empty:\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  age:\n    type: str\n    help: \"Enter your age\"\n    validation:\n      condition: \"age\"\n      error_message: \"Value cannot be empty\"\n```\n\n#### Numeric Value Validation\n\nCheck if a numeric value meets certain criteria:\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  age:\n    type: str\n    help: \"Enter your age\"\n    validation:\n      condition: \"age|int \u003e= 18\"\n      error_message: \"You must be at least 18 years old. You entered {{age}}.\"\n```\n\nThe error message can include template variables to provide context about the invalid input.\n\n#### Pattern Matching with Regular Expressions\n\nComplex validation combining regex pattern matching with numeric validation and detailed error messages:\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  age:\n    type: str\n    help: Enter your age\n    validation:\n      condition: \"age and (age|regex('[0-9]')) and (age|int \u003e= 18)\"\n      error_message: \u003e\n        {% if not age %}Age is required field\n        {% elif not age|regex('[0-9]') %}Age must be numeric\n        {% elif not age|int \u003e= 18 %}You must be at least 18 years old. You entered {{age}}\n        {% else %}Invalid input\n        {% endif %}\n```\n\nThis example demonstrates:\n\n1. Required field validation using `age`\n2. Pattern matching using `regex('[0-9]')` to ensure numeric input\n3. Numeric value validation ensuring age is at least 18\n4. Conditional error messages that provide specific feedback based on the validation failure\n\nIf validation fails, Baker will:\n\n1. Display the appropriate error message\n2. Clear the invalid answer\n3. Prompt the user to try again\n\n### Conditional questions\n\nThe `ask_if` attribute is used to control the display of a question, using [expression language](https://docs.rs/minijinja/latest/minijinja/#expression-usage) from MiniJinja. It enables conditional logic to determine whether a question should be prompted based on user input or other contextual factors. In the following example, the `py_framework` question is only prompted if the user selects `Python` as the programming language in the `language` question:\n\n```yaml\nschemaVersion: v1\n\nquestions:\n  language:\n    type: str\n    help: What is your programming language?\n    default: Rust\n    choices:\n      - Python\n      - Rust\n      - Go\n      - TypeScript\n  py_framework:\n    type: str\n    help: What is your Python framework?\n    choices:\n      - Django\n      - FastAPI\n      - Pyramid\n      - Tornado\n    ask_if: \"language == 'Python'\"\n```\n\n## Built-in Filters\n\nBaker provides a set of built-in filters and functions to enhance the flexibility of your templates. These are powered by the MiniJinja templating engine and additional custom filters.\n\n### Available Filters\n\n| **Filter Name**        | **Description**                                               |\n| ---------------------- | ------------------------------------------------------------- |\n| `camel_case`           | Converts a string to camelCase.                               |\n| `kebab_case`           | Converts a string to kebab-case.                              |\n| `pascal_case`          | Converts a string to PascalCase.                              |\n| `screaming_snake_case` | Converts a string to SCREAMING_SNAKE_CASE.                    |\n| `snake_case`           | Converts a string to snake_case.                              |\n| `table_case`           | Converts a string to table_case (lowercase with underscores). |\n| `train_case`           | Converts a string to Train-Case.                              |\n| `plural`               | Converts a word to its plural form.                           |\n| `singular`             | Converts a word to its singular form.                         |\n| `foreign_key`          | Converts a string to a foreign key format (e.g., `user_id`).  |\n| `regex`                | Applies a regular expression to transform a string.           |\n\n### Usage Examples\n\n#### 1. Camel Case Filter\n\n```yaml\n{{ \"hello world\" | camel_case }}\n// Output: \"helloWorld\"\n```\n\n#### 2. Kebab Case Filter\n\n```yaml\n{{ \"hello world\" | kebab_case }}\n// Output: \"hello-world\"\n```\n\n#### 3. Pascal Case Filter\n\n```yaml\n{{ \"hello world\" | pascal_case }}\n// Output: \"HelloWorld\"\n```\n\n#### 4. Screaming Snake Case Filter\n\n```yaml\n{{ \"hello world\" | screaming_snake_case }}\n// Output: \"HELLO_WORLD\"\n```\n\n#### 5. Snake Case Filter\n\n```yaml\n{{ \"hello world\" | snake_case }}\n// Output: \"hello_world\"\n```\n\n#### 6. Table Case Filter\n\n```yaml\n{{ \"Hello World\" | table_case }}\n// Output: \"hello_world\"\n```\n\n#### 7. Train Case Filter\n\n```yaml\n{{ \"hello world\" | train_case }}\n// Output: \"Hello-World\"\n```\n\n#### 8. Plural Filter\n\n```yaml\n{{ \"car\" | plural }}\n// Output: \"cars\"\n```\n\n#### 9. Singular Filter\n\n```yaml\n{{ \"cars\" | singular }}\n// Output: \"car\"\n```\n\n#### 10. Foreign Key Filter\n\n```yaml\n{{ \"User\" | foreign_key }}\n// Output: \"user_id\"\n```\n\n#### 11. Regex Filter\n\n```yaml\n{{ \"hello world\" | regex: \"world\", \"Rust\" }}\n// Output: \"hello Rust\"\n```\n\n## Comparing Baker to other project generators\n\n| Feature                                           | Baker                                                                                | Kickstart     | cargo-generate         | Copier                                    | Cookiecutter              | Yeoman                       |\n|---------------------------------------------------|--------------------------------------------------------------------------------------|---------------|------------------------|-------------------------------------------|---------------------------|------------------------------|\n| 🟢 **Structured JSON/YAML input**                 | ✅ Native support with validation and schema                                          | ❌             | ❌                      | ⚠️ Limited                                | ❌                         | ⚠️ Custom logic required     |\n| 🟢 **JSON Schema validation**                     | ✅ Enforce data validity with standard JSON Schema                                    | ❌             | ❌                      | ❌                                         | ❌                         | ⚠️ Custom logic required     |\n| 🟢 **Complex data editing modes**                 | ✅ Editor/Console/File input for structured data                                      | ❌             | ❌                      | ❌                                         | ❌                         | ❌                            |\n| 🟢 **In-template debug() support**                | ✅ Use `{{ debug() }}` to inspect context                                             | ❌             | ❌                      | ❌                                         | ❌                         | ⚠️ Only via console.log      |\n| 🟢 **Structured hook communication**              | ✅ pre/post hooks exchange structured JSON via stdin/stdout                           | ❌             | ❌                      | ❌                                         | ❌                         | ❌                            |\n| 🟢 **Safe hook execution**                        | ✅ Warns before executing hooks                                                       | ❌             | ❌                      | ❌                                         | ❌                         | ⚠️ Depends on generator      |\n| 🟢 **Schema versioning for config**               | ✅ Schema version ensures backward compatibility across Baker versions                | ✅             | ❌                      | ❌                                         | ❌                         | ❌                            |\n| 🟢 **YAML \u0026 JSON config support**                 | ✅ Supports `yaml` **and** `json` configurations                                      | ❌ Only TOML   | ❌ Only TOML            | ❌ Only YAML                               | ❌ Only JSON               | ❌ In JS code                 |\n| 🟢 **Platform-specific hooks**                    | ✅ Use `{{platform.family}}/pre` etc. for OS-aware logic                              | ❌             | ⚠️ Limited via Rhai    | ❌                                         | ❌                         | ⚠️ Custom logic required     |\n| 🟢 **CI/CD-friendly answers piping**              | ✅ `--answers=-` or echo JSON into CLI                                                | ❌             | ⚠️ Partial             | ✅ Via pre-filled YAML                     | ⚠️ `--no-input` only      | ❌ Manual scripting           |\n| 🟢 **Lightweight \u0026 Fast**                         | ✅ Rust binary, no runtime dependencies                                               | ✅ Rust binary | ✅ Rust binary          | ❌ Requires Python                         | ❌ Requires Python         | ❌ Requires Node.js           |\n| 🟢 **Simple CLI Interface**                       | ✅ `baker \u003ctemplate\u003e \u003coutput\u003e` + `--answers`, `--skip-confirms`                       | ✅ Simple      | ❌ Requires Cargo usage | ❌ More verbose                            | ✅ Simple                  | ❌ Requires generator install |\n| 🟢 **Language-agnostic hooks**                    | ✅ Hooks can be in _any_ language (Bash, Python, etc.)                                | ✅ Yes         | ⚠️ Only Rhai scripting | ✅ Yes                                     | ✅ Yes                     | ❌ Only JS                    |\n| 🟢 **Templated file/dir names**                   | ✅ Full MiniJinja templating in names \u0026 conditions                                    | ✅ Yes         | ✅ Yes                  | ✅ Yes                                     | ✅ Yes                     | ✅ Via JS logic               |\n| 🟢 **Templated prompts \u0026 defaults**               | ✅ Dynamic defaults using MiniJinja, conditional via `ask_if`                         | ✅ Yes         | ⚠️ Limited             | ✅ Full Jinja                              | ❌ Static only             | ✅ Full control in JS         |\n| 🟢 **Glob-based ignore file**                     | ✅ `.bakerignore` with advanced Globset syntax                                        | ✅ Yes         | ✅ Yes                  | ✅ `_exclude`                              | ⚠️ `_copy_without_render` | ❌ Manual filter in code      |\n| 🟢 **Cross-platform binaries**                    | ✅ Precompiled for Linux, macOS, Windows                                              | ✅ Yes         | ✅ Yes                  | ✅ Yes                                     | ✅ Yes                     | ✅ Yes                        |\n| 🟢 **Language-agnostic scaffolding**              | ✅ Works with any language / stack                                                    | ✅ Yes         | ❌ Rust-focused         | ✅ Yes                                     | ✅ Yes                     | ⚠️ JS-centric                |\n| 🟢 **Answers accessible in later questions**      | ✅ All previous answers available via MiniJinja in `default`, `help`, `ask_if`        | ⚠️ Limited    | ⚠️ Partial (via Rhai)  | ✅ Yes (Jinja context)                     | ❌                         | ✅ Full control in JS         |\n| 🟢 **Templated engine**                           | ✅ Fast, safe, embedded Jinja2-like templating in Rust                                | Tera          | Liquid                 | Jinja2                                    | Jinja2                    | EJS                          |\n| 🟢 **Looping of files (template filename loops)** | ✅ Generate multiple files from a single template using Jinja2 for-loops in filenames | ❌             | ❌                      | ⚠️ Limited (Jinja2 loops in content only) | ❌                         | ⚠️ Custom logic required     |\n\n### ℹ️ Disclaimer\n\nThis comparison was made based on available documentation. If you notice any **inaccuracies or outdated information**, please [create an issue](https://github.com/aliev/baker/issues) — I'll be happy to update the table accordingly.\n\n## Community Templates\n\nSee [here](https://github.com/topics/baker-template) for a list of community maintained templates built with baker.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faliev%2Fbaker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faliev%2Fbaker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faliev%2Fbaker/lists"}