Socket
Socket
Sign inDemoInstall

@acrontum/fst

Package Overview
Dependencies
1
Maintainers
7
Versions
2
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @acrontum/fst

Filesystem templating engine and project scaffolding tool


Version published
Weekly downloads
2
Maintainers
7
Install size
184 kB
Created
Weekly downloads
 

Readme

Source

filesystem-template

NOTE fst is in early beta, docs are subject to change and may not be accurate.


Usage

Quickstart:
npm install --save-dev @acrontum/fst

Basic usage:
npx fst [options] <path_to_recipe_file>

See npx fst --help for more options, or see API.


Recipe file

Schema
interface RecipeSchema {
  /**
   * unique name of the recipe (for use with depends and passing data between files)
   */
  name?: string;
  /**
   * file, recipe, path to file(s), url, or repository to fetch templates from
   */
  from?: string;
  /**
   * output folder
   */
  to?: string;
  /**
   * arbitrary data store
   */
  data?: any;
  /**
   * array of names of other recipes which must be built first
   */
  depends?: string[];
  /**
   * lifecycle cli / shell commands
   */
  scripts?: { before?: string; after?: string };
  /**
   * path to render handler js file or handler function
   */
  fileHandler?: string | RenderFunction;
  /**
   * dependent / sub recipes
   */
  recipes?: RecipeSchema[];
  /**
   * list of folders to skip when copying or generating
   */
  excludeDirs?: string[];
  /**
   * when cloning, only clone certain folders
   */
  includeDirs?: string[];
}
Example
{
  "recipes": [
    {
      "name": "openapi-spec",
      "to": "spec",
      "scripts": {
        "after": "npm run build"
      }
    },
    {
      "name": "server",
      "from": "https://mytemplates.test/server-template",
      "to": "backend",
      "fileHandler": "server-builder.js",
      "recipes": [
        {
          "name": "client",
          "from": "./client",
          "to": "./client",
          "scripts": {
            "after": "node link-client.js"
          }
        }
      ]
    },
    {
      "name": "docker-compose",
      "from": "https://fstr-std.com/compose",
      "to": "docker",
      "depends": ["openapi-spec", "server", "client"],
      "excludeDirs": ["volumes"]
    }
  ]
}
Understanding relative paths

All recipe block paths are relative to the parent recipe's "to" section (defaulting to './' when not present. In the case of the root, it's relative to where the recipe was called from (cwd).
Eg:

For this file setup:

.
├── demo.fstr.json
├── scripts
│   ├── child-script.js
│   └── parent-script.js
└── sub-template
    └── readme.txt

With demo.fstr.json:

{
  "name": "demo",
  "to": "./demo-output",
  "fileHandler": "scripts/parent-script.js",
  "recipes": [
    {
      "name": "demo-sub-recipe",
      "from": "../sub-template",
      "to": "sub-folder",
      "fileHandler": "scripts/child-script.js",
      "scripts": {
        "before": "touch readme.txt"
      }
    }
  ]
}

Note that for demo-sub-recipe, both "from" and "scripts" are relative to the parent "to", wheras the top-level script path ('scripts/parent-script.js') is relative to the recipe file (in this case, './').

For the sub-recipe, since both "from" and "scripts" read from folders in the root, their paths are parsed as ./demo-output/../sub-template and ./demo-output/../scripts/child-script.js (respectively).

Running the recipe file would then generate this folder structure:

.
├── demo.fstr.json
├── demo-output          <-- generated
│   └── sub-folder
│       └── readme.txt
├── scripts
│   ├── child-script.js
│   └── parent-script.js
└── sub-template
    └── readme.txt

Lifecycle scripts

Import and run scripts at different points in the runtime.

scripts.before:

Runs after source material exists on disk (after pulling from remote, or on finding local path), but before the render.

{
  // ...
  "scripts": {
    "before": "rm -rf old-files"
  }
}
scripts.after:

Runs after render and all files copied. Useful for cleanup or logging.

{
  // ...
  "scripts": {
    "after": "./build.sh && cp output ../release"
  }
}

fileHandler (rendering callback):

Used when registering callbacks for during render.

fileHandler?: (recipe: Recipe, renderer: Renderer) => void | Promise<void>;

FST will search in the current directory of the recipe for the file handler script and, if that does not exist, in the temp template source folder.

import * as nunjucks from 'nunjucks';
import { promises } from 'fs';
import { RenderFunction, Recipe, Renderer, VirtualFile } from '@acrontum/filesystem-template';

const render: RenderFunction = (recipe: Recipe, renderer: Renderer) => {
  // recipe contains a name-indexed map of other recipes that have run
  const parentRecipeData = recipe.map['parent-name'].data;

  renderer.onFile(async (node: VirtualFile) => {
    if (node.name === 'ignore-me.txt') {
      node.skip = true; // skip generating this file

      return;
    }

    if (!node.name.endsWith('.njk')) {
      // if node is not skipped, and has no outputs, the default rendering will be to copy the file or folder
      return;
    }

    const njkTemplate = await promises.readFile(node.fullSourcePath, 'utf8');

    // the parent node may be a folder which generated in multiple places, meaning the source file will have multple outputs
    for (const output of node.getGenerationTargets()) {
      const content = await nunjunks.renderFile(njkTemplate, { ...parentRecipeData, ...recipe.data });
      await promises.writeFile(output, content);
      node.outputs.push(output);
    }
  });
};

API

fst <options | RECIPE>

options:
  -c, --cache             Do not delete fetched files between runs
  -o, --output PATH       Folder to output files
  -p, --parallel COUNT    Max number of concurrent recipe parsing (default 10)
  -r, --recipe RECIPE     Add recipe to builder (file or URL)
  -s, --silent            Log less verbosely
  -v, --verbose           Log more verbosely
  -e, --exclude PATHS     Skip PATHS in template generation (default node_modules,.git)
  -b, --no-buffer         Disable log buffering (default true unless not tty, CI=true, or TERM=dumb)

Try:
npx fst --help

Roadmap

  • write more tests
  • update docs
  • re-implement cli params (include / exclude files, cache, parallel, etc)
  • re-implement recipe params (include / exclude files, cache, parallel, etc)

FAQs

Last updated on 08 Apr 2023

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc