Advanced Templates
By default CodeBaker copies every file of your template into the folder you generated from, keeping the template's folder structure, and applies your variables to file names and file contents.
Advanced templates go beyond that. A template can:
- put a file somewhere else, or under a different name
- name or place a file depending on your variables and generate a file only when a condition holds (Loops and Conditions)
- generate one source file or a whole folder several times (a loop, same page)
- write a file only once and never overwrite your later edits (
seed), update one block inside an existing file (insert) or swap the whole content of a block (replace) (Seed, Insert and Replace) - add or update an entry in a JSON list (
json-upsert, JSON Upsert) - read data from another file, another part of the document or a web address (Data Sources)
- leave a template file out of the output
Where it is set up
All of this is described in one optional file, codebaker.advanced.json5, in the template folder. A template without it simply copies its files.
.CodeBaker/
└── MyTemplate/
├── codebaker.config.json5 ← variables, name, version
├── codebaker.advanced.json5 ← file placement and generation rules (optional)
└── ...your template files
The file has two sections:
{
// Runs first, in the order written. Use it to prepare shared files other files depend on.
init: { /* ... */ },
// Everything else.
mapping: { /* ... */ },
}
Before it is read, codebaker.advanced.json5 is run through the template engine with all your variables. So
{{ name }} works anywhere in it (in a target, an id, a data value), and so does a style you declare under placeholders, such as ___name___. A for loop can
create items (see Loops and Conditions in the Mapping File). The examples on this page use ___name___-style placeholders, so their templates declare placeholders: ["___VAR___"] in the config.
Mapping entries
Each entry is "path of a file or folder inside the template": <value>.
- The key is the source path inside the template folder, written with forward slashes (
js/entities.js). - A key that matches nothing in the template is silently ignored. (A missing source under
initlogs a warning in the generation log instead.)
The value is one of:
| Value | Meaning |
|---|---|
"path/name.ext" | Generate it once, at that path. Shorthand for a list with a single string. |
[ "path/name.ext", ... ] | Generate it once per string, at that path. |
{ target: "...", ... } | Generate it once, with its own target, data and type. Shorthand for a list with a single item. |
[ { target: "...", ... }, ... ] | Generate it once per item, each with its own target, data and type. |
false or [] | Do not generate this file or folder at all. |
mapping: {
// Put a file somewhere else (one target, written as a plain string)
"Model.php": "app/Models/___modelName___.php",
// Do not copy this file
"notes.md": false,
// One source, two outputs, each with its own data
"card.html": [
{ target: "cards/a.html", data: { title: "Alpha" } },
{ target: "cards/b.html", data: { title: "Beta" } },
],
}
Files you do not list are copied as they are. A file that is claimed in init is left out of this ordinary
copy automatically: you do not need a second false entry for it.
What an item can contain
| Key | Meaning |
|---|---|
target | Where to write it (required). See below. |
data | An object of extra variables for this output. Its keys override variables of the same name from codebaker.config.json5. |
type | seed, insert, replace or json-upsert. No type means an ordinary file. |
format | What the text of the file is turned into. "json" writes it as plain JSON; false or "json5" writes it as it is. Not set: a .json5 source with a .json target is converted to JSON, everything else is written as it is. See Choosing the format. |
insert, replace and json-upsert items take a few more keys, described on their own pages.
Where does target point?
- A plain path is relative to where the source file's own folder is generated.
- A leading
/makes it relative to the root of the generated output (the folder you generated into). ..goes one folder up (it never goes above the output root).- Declared placeholders (such as
___name___) and{{ name }}in atargetare replaced like everywhere else.
Folders
An entry can name a folder. A target on a folder renames its output location, and everything inside
follows. A list with several items clones the whole folder, each clone with its own data. data on a folder
is inherited by every file inside it (a file's own data with the same key replaces the folder's value for that
key, as a whole: nested objects are not merged).
seed on a folder applies to every file insidetype: "seed" on a folder item makes every file inside it, at any depth, a seed: written once and kept
on the next generations. A file that has a mapping entry of its own uses that entry instead, so you can exclude one file
(false) or write it as an ordinary file. The other types (insert, replace, json-upsert) change one file, so on a
folder they stop the generation with a message that says to set them on the file. So does format.
The init phase
init is the first section of the mapping file. Its entries are written before everything else, in the order you wrote them, and they are meant for a file that other entries read.
{
init: {
// 1. First: add this run's entry to the registry file
"entity-record.json5": [{ target: "entities.json5", type: "json-upsert" }],
},
mapping: {
// 2. Later: a file that reads the registry, with everything this run has already put in it
"js/entities.js": [
{ target: "entities.js", data: { entities: { "$file": "target://entities.json5" } } },
],
},
}
- It runs on every generation, not only the first. The name says it runs first, not once.
- It names files. An
initentry is a source file of the template, written with the same keys as amappingentry (target,type,data, ...). A source named ininitis not copied again by the ordinary pass, so you do not need a secondfalseentry for it. A source that does not exist logs a warning in the step 2 log instead of stopping the generation. - The order is the order you wrote. The ordinary files, the
seedfiles and thejson-upsertentries that are not ininithave no defined order among themselves. That is the reason to put anything another file reads intoinit. - When a later file reads it, use
$filewithtarget://, which sees what this very run has already produced even before it is written to disk.
Entry types and run order
No type means an ordinary file: it is written on every generation, and the diff preview is your safety net.
Generation runs in three passes, one after another:
initentries, in the order you wrote them.- All ordinary files,
seedfiles andjson-upsertentries (the order inside this pass is not defined). insertandreplaceentries, last.
Anything that other files read, for example a json-upsert data file, belongs in init. Anything an insert
writes into is produced earlier, in pass 1 or 2.
Which one do I use?
| I want to... | Use |
|---|---|
| write a file again on every generation | an ordinary entry: no type |
| write a file once and never touch it again | type: "seed" |
| add or update one block inside a file that exists | type: "insert" with a slot |
| swap the whole content of a slot | type: "replace" |
| add or update an entry of a JSON list | type: "json-upsert" |
| write the same file several times | a list of items |
| leave a file out | false |
| prepare a file that other entries read | an entry in init |
The types in detail:
seed,insertandreplace: Seed, Insert and Replace.json-upsert: JSON Upsert.
Things to watch out for
- The mapping file is processed as a template. Do not write a literal
{{,{%or aCodeBaker:comment as example text in a comment. It is read as real syntax. Describe it in words instead. - A
.json5source written as.jsonis converted to plain JSON (comments, trailing commas and the other JSON5 forms are removed). Setformat: falseon the entry to write the text as it is. See Choosing the format. - Preview first. Step 3 of the wizard, Code Preview, shows every file before anything is written, and you can edit the text there.
See also
- How It Works - the whole process on one diagram
- Under the Hood - what happens in each step, and how to choose a
type - Data Sources -
$file,$refand$api - Configuration Reference
- Template Basics