Skip to main content

Keeping the Template Valid for Your IDE

Your IDE reads a template before CodeBaker does, so it sees the tags too. In a PHP, Java or TypeScript file a {% if %} in the middle of a class is a syntax error, and the template stops being a file you can work in. This lesson shows how to keep the conditions and loops and still have a valid file: put each tag in a comment.

There are two tools, and you use them together:

  • Values are written as a declared placeholder such as ___name___, which is a valid identifier in most languages (Values and Variables).
  • Logic (conditions and loops) goes in a comment that starts with CodeBaker:, which the IDE sees as an ordinary comment.

A tag in a comment​

Write the tag after CodeBaker: in a comment. CodeBaker removes the comment, and what follows CodeBaker: takes its place:

//CodeBaker: {% if hasTimestamps %} → {% if hasTimestamps %}

Here is a PHP model that uses a placeholder for its class name, a loop for its properties and a condition for one more. Every tag is in a comment, and the template is valid PHP:

A PHP model class
Template.CodeBaker/product-model/
Download the template (.zip)https://codebaker.dev/examples/product-model.zip
Install in IntelliJ IDEA

Needs the CodeBaker plugin and an open project. Another IDE, or the button does nothing? Copy the link, then in the IDE right-click any folder → New → Generate from Template → Install Template from URL… and paste it. You always get a confirmation dialog before anything is installed.

___modelName___.php
<?php

class ___modelName___
{
//CodeBaker: {% for field in fields %}
public ___field_dot_type___ $___field_dot_name___;
//CodeBaker: {% endfor %}
//CodeBaker: {% if withTimestamps %}

public DateTimeImmutable $createdAt;
//CodeBaker: {% endif %}
}
codebaker.config.json5
{
// The folder name when the template is installed under .CodeBaker/
id: "product-model",

name: "PHP Model",

// The placeholder style used in the template files: ___modelName___, ___field_dot_name___ ...
placeholders: ["___VAR___"],

// Each variable becomes a text field in the dialog, with this as its default value.
vars: {
modelName: "Product",
withTimestamps: "true",
},

// Lists go in the json area of the dialog. Each top-level key is a variable too.
json: {
fields: [
{ name: "title", type: "string" },
{ name: "price", type: "float" },
],
},

// Opened in the editor after generation (the path is relative to the folder you generated into).
open: ["___modelName___.php"],
}
Typed in the dialogstep 1, Custom Properties
modelName
Product
withTimestamps
true
JSON
{
"fields": [
{
"name": "title",
"type": "string"
},
{
"name": "price",
"type": "float"
}
]
}
Generated resultwhat lands in your project
Product.php
<?php

class Product
{
public string $title;
public float $price;

public DateTimeImmutable $createdAt;
}

Look at the result: the lines that held only a directive left no empty line, the loop wrote one property per item, and the file name ___modelName___.php became Product.php.

The rules​

  • Comment styles: //, /* */, #, -- and <!-- -->. A closing */ or --> is optional and is removed too.

    PrefixLanguages
    //PHP, Java, Kotlin, JavaScript, TypeScript, Go, SCSS, LESS
    /* ... */CSS and C-style block comments: write /* CodeBaker: ... */
    #Python, Ruby, shell, YAML
    --SQL, Lua
    <!-- ... -->HTML, XML, Markdown

    // is not a comment in plain CSS or in a <style> block, so write /* CodeBaker: ... */ there.

  • The directive is the last thing on its line. It runs to the end of the line, so anything after it belongs to it.

  • Only CodeBaker: makes a directive. The word and the colon are both required, and the word is case-sensitive. // CodeBaker is a tool, // see CodeBaker: docs and // codebaker: x are ordinary comments.

  • The tag line leaves no empty line. A line that holds only tags joins the next line, which keeps its own indentation.

  • Indentation of the comment is not kept. Text that replaces a full-line comment starts at the beginning of the line. After code on the same line, the text is appended to that code: echo 1; //CodeBaker: {% if x %} becomes echo 1; {% if x %}.

  • Your IDE shows which comments are directives. The CodeBaker plugin colors the CodeBaker: that starts one (teal on a light theme, cyan on a dark one), and does not color a comment that only mentions CodeBaker.

A few words after CodeBaker: are commands, not text, and nothing is written for them:

  • replace, regex, off, on and reset define replacement rules: Replacing Real Values.
  • separator becomes a comma between the items of a loop: Generating JSON.
  • {% slot name %}, {% endslot %}, {% fragment id %} and {% endfragment %} mark a place for the insert type, bare or in a comment. They are copied into the generated file exactly as written: Advanced Templates.

The same name twice​

Because the IDE reads both branches of a condition, it sees the second declaration as a duplicate:

class User extends Model
{
//CodeBaker: {% if hasTimestamps %}
public $timestamps = true;
//CodeBaker: {% else %}
public $timestamps = false;
//CodeBaker: {% endif %}
}
  • Duplicate property declaration: $timestamps

The generated file has only one of them, so the error exists only in the template. To silence it, add a placeholder that exists only to make the name unique, a throwaway suffix. It disappears when the file is generated:

class Config
{
//CodeBaker: {% if cacheDriver == 'redis' %}
protected $driver = 'redis';
//CodeBaker: {% elseif cacheDriver == 'file' %}
protected $driver___alt1___ = 'file';
//CodeBaker: {% else %}
protected $driver___alt2___ = 'array';
//CodeBaker: {% endif %}
}

With cacheDriver = file, the output is protected $driver = 'file';.

How it works. ___alt1___ is converted to {{ alt1 }} before Pebble runs (the template declares the ___VAR___ style). Pebble keeps only the branch whose condition holds. alt1 is not defined, and Pebble prints an undefined variable as an empty string, so the suffix vanishes.

Rules for a suffix

  • It must not be a real variable. $name___modelName___ becomes $nameUser if modelName is defined, in vars, in the dialog or as a loop variable. Names such as alt1, alt2, disabled and sync are safe.
  • It must not be a Pebble keyword or literal. ___true___ prints true and ___false___ prints false. ___and___, ___or___, ___not___ and ___is___ fail with a Pebble parse error.
  • The IDE sees two different names, so rename and find usages do not connect them. If only a method body differs, put the condition inside the body and skip the suffix.

The same idea resolves a duplicate key in a .json5 template: see Generating JSON.


What the IDE cannot know​

  • A loop variable such as item or field in a //CodeBaker: {% for %} loop is unknown to the IDE, so it may be reported as undefined in the template.
  • A value in a position that accepts no identifier, such as a CSS value, still needs another tool: Replacing Real Values.

These affect only the template: the generated code contains none of the directive comments. Known Limitations lists every case with what to do.


Next​