Skip to content

Custom helpers

Templates may import custom helpers, by specifying the helpers array in the frontmatter. The helpers array contains the relative paths to the helpers, and these paths are relative to the template.

Custom helper files are JavaScript files, often with the .helper.js extension. The contents of this file must be evaluated into a JavaScript function named helpers, that takes no arguments. The return value of this function may contain named helper functions. These helper functions will be registered into Handlebars (the templating engine used by ProJor) and will be available in the template.

This feature is not used very often, but it is available nevertheless. We can only show "synthetic" example of what a custom helper file must look like.

An example helper file looks like this:

javascript
(function helpers() {
    return {
        javaColumnType: function (typeName) {
            if (typeName === "ID") {
                return "Long";
            } else if (typeName === "STRING") {
                return "String";
            }
            return typeName;
        }
    }
})

If you have a template in .projor/template/my-template.ptemplate.mustache, and you place the helper at .projor/helpers/my-helper.helper.js, you should include the following in the template's frontmatter:

json
{
    "helpers": ["../helpers/my-helper.helper.js"]
}

Then you may use it in a template like this:

{
    "helpers": ["../helpers/my-helper.helper.js"],
}
---
public class {{pascalCase name}} {
    {{#each fields}}
    private {{javaColumnType fieldType.name}} {{camelCase name}};
    {{/each}}
}

Helper modules (CommonJS)

If your helper's file extension is .cjs, ProJor will treat it as a CommonJS helper module. Place your helper functions in the module.exports object, and each one will be available in the templates that reference this helper script.

When to use helper modules?

Suppose that you have a schema like this:

yaml
id: Trophy
name: Trophy
description: A single trophy asset
fields:
  - name: filename
    type: string
    description: The filename of the trophy image
  - name: title
    type: string
    description: The title of the trophy

In this concrete example we are generating cloud function source code, that embeds the trophy images inside the generated source code as Base64. To accomplish this, we can write the following helper (in game.helpers.cjs):

js
const fs = require("fs");
const path = require("path");

function imageBase64(filename) {
    let filePath = path.join(__dirname, "..", "..", "assets", filename);
    if (!fs.existsSync(filePath)) {
        filePath = path.join(__dirname, "..", "..", "design", filename);
    }
    const image = fs.readFileSync(filePath);
    return image.toString("base64");
}

module.exports = {
    imageBase64,
};

Our trophies.pdata.yaml file would then contain this:

yaml
id: trophies
name: Trophies
schema: Trophy
objects:
  - name: lost_game_cartridge
    filename: "trophy/lost_game_cartridge.jpg"
    title: "Lost Game Cartridge"

And finally, in our cloud function template we can write:

go
{
    "map": {
        "trophies": "online-trophies"
    },
    "filename": "online/go-cloud-function-trophies/function.go",
    "helpers": [
        "game.helpers.cjs"
    ]
  }
---
package rewards

// Imports, etc.

var allTrophies = map[string]OnlineTrophy{  
    {{#each trophies}}
    "{{name}}": {
        Id: "{{name}}",
        Title: "{{{title}}}",
        ImageDataBase64: "{{{imageBase64 filename}}}",
    },
    {{/each}}
}

// ... other code ...

The imageBase64 helper defined in game.helpers.cjs is thus able to use the fs and path Node.JS modules to accomplish the in-source embedding we wanted.