API reference
Global settings and blueprintor.config.js share one format.
interface BlueprintorConfig { blueprints: Blueprint[];}Blueprint
Section titled âBlueprintâinterface Blueprint { title: string; variables?: Variable[]; snippets?: Record<string, string | string[]>; structure: Structure;}| Field | Type | Default | Description |
|---|---|---|---|
title |
string |
required | Name in the blueprint list. Also the key used to merge global and local blueprints. Blueprints without a title are ignored. |
variables |
Variable[] |
none | Values to ask for before creating anything. |
snippets |
Record<string, string | string[]> |
none | Named texts that files can reference with snippet. |
structure |
Structure |
required | What to create inside the target folder. |
Variables
Section titled âVariablesâinterface Variable { key: string; prompt?: string;}| Field | Type | Default | Description |
|---|---|---|---|
key |
string |
required | Name used in placeholders. Letters, digits and underscores, not starting with a digit. Must be unique within the blueprint. |
prompt |
string |
Enter value for [key] |
Question shown in the input box. |
Variables are asked in the order they are listed. The relative path of the target folder is appended to every question.
- An empty value is not accepted: the input box shows âA value is requiredâ.
- Esc cancels the whole run, nothing is created.
- Without
variablesnothing is asked and the blueprint runs immediately.
The values are used through placeholders. A variable that is never used in a name or text is still asked, but has no effect.
Blueprint without variables
Section titled âBlueprint without variablesâA static blueprint needs no questions. Names and texts are used exactly as written:
{ title: "Project basics", structure: { files: [ { name: ".gitignore", content: ["node_modules", "dist"] }, { name: "README.md", content: "# Project" }, ], },}Snippets
Section titled âSnippetsâA map from a snippet name to its text. The text is either a string or an array of strings (joined with a line break). Files reference a snippet with snippet, so one text can be reused by several files.
Files and folders
Section titled âFiles and foldersâinterface Structure { files?: FileItem[]; folders?: FolderItem[];}
interface FolderItem extends Structure { name: string;}
interface FileItem { name: string; snippet?: string; content?: string | string[];}| Field | Description |
|---|---|
name |
File or folder name. Placeholders are allowed. |
snippet |
Name of an entry in the blueprintâs snippets. |
content |
Inline text of the file: a string or an array of lines. |
Folders can be nested to any depth and are created if they donât exist. A name must not contain a path (src/a.ts): describe nesting with folders.
How file content is chosen
Section titled âHow file content is chosenâ- If
snippetis set, the file gets the text of that snippet. - Otherwise, if
contentis set, the file gets its owncontent. - Otherwise, the file is created empty.
Use either snippet or content in one file, not both. A snippet that is defined as an empty string is valid and produces an empty file.
Placeholders are substituted in the text, then leading and trailing whitespace is trimmed. The file does not end with a line break.
Placeholders
Section titled âPlaceholdersâFor every variable there are five forms:
| Placeholder | my idea |
user_profile |
|---|---|---|
{key.raw} |
my idea |
user_profile |
{key.pascal} |
MyIdea |
UserProfile |
{key.camel} |
myIdea |
userProfile |
{key.kebab} |
my-idea |
user-profile |
{key.snake} |
my_idea |
user_profile |
Placeholders work in file names, folder names and texts. A form is always required: {key} on its own is not a placeholder, so code such as {name} in your templates is never touched by accident.
- Words are split on spaces, hyphens, underscores and lower-to-upper transitions (
UserProfilegivesuser-profile). pascal,camel,kebabandsnakekeep only Latin letters, digits, spaces,-and_. Everything else (including Cyrillic) is removed, which can leave an empty result.rawinserts the value exactly as typed.- Unknown placeholders and other braces, such as
{children}, are left in the text as they are.
Priority and merging
Section titled âPriority and mergingâBlueprints come from two places:
| Source | Marker in the list |
|---|---|
Local blueprintor.config.js |
đŚ |
Global blueprintor.defaultConfig |
đ |
If both define a blueprint with the same title (compared exactly, case-sensitive), the local one wins and the global one is hidden. Blueprints with different titles are all shown. Blueprints are not merged field by field: the local one replaces the global one entirely.
Next to each title the list shows the keys of the variables that will be asked.
Existing files
Section titled âExisting filesâBefore writing, the extension checks which files already exist (folders are not checked). If there are any, a modal dialog offers:
- Overwrite: replace them;
- Skip existing: create only the missing files;
- cancel: do nothing.
The whole blueprint is checked before anything is written. If a check fails, you see âGeneration failedâ with the reason, and nothing is created.
| Problem | Message |
|---|---|
Invalid or duplicate variable key |
Use letters, digits and underscores; keys must be unique. |
snippet that is not defined in snippets |
The snippet name is reported. |
snippet and content in the same file |
Use only one of them. |
| Text that is not a string or an array of strings | The snippet or file is reported. |
| Empty name after substitution | Usually a value without Latin letters or digits. |
| Name with a slash | Use folders for nesting. |
| A file where a folder is needed, or the other way round | The path is reported. |
No files or folders in structure |
The blueprint is reported. |
Full example
Section titled âFull exampleâTwo variables, a folder named after the first one:
module.exports = { blueprints: [ { title: "Service", variables: [ { key: "domain", prompt: "Domain (e.g. billing)" }, { key: "name", prompt: "Service name" }, ], snippets: { service: `// Domain: {domain.kebab}export class {name.pascal}Service {}`, }, structure: { folders: [ { name: "{domain.kebab}", files: [{ name: "{name.kebab}.service.ts", snippet: "service" }], }, ], }, }, ],};Run it on src/services, enter User Billing and invoice:
Directorysrc
Directoryservices
Directoryuser-billing
- invoice.service.ts
// Domain: user-billingexport class InvoiceService {}