Giter VIP home page Giter VIP logo

template-file's Introduction

template-file

🔀 Replace {{ variables }} in all your files

Use variables to replace template strings in any type of file. This is both a runnable command-line application and JavaScript/TypeScript module.

✨ Some helpful features:

  • If you use a JavaScript file as the dataFile argument, whatever object the JS exports is used for replacement.
  • If the value of one of the keys is a function, the result of that function is used for replacement.
  • Deeply-nested keys can be used for replacements.

Usage

template-file <dataFile> <sourceGlob> <destination>

Arguments

  • data - Data file in JSON; used to replace variables in source files
  • sourceGlob - Files to process; see glob for syntax
  • destination - Destination directory where processed files go

ℹ️ TIP: Remember to place quotes around your arguments (if they contain asterisks, question marks, etc.) to keep your shell from expanding globs before template-file gets to consume them.

Examples

Just handle one file:

template-file data.json template.txt build/

Compile all .abc files in src/ to build/:

template-file stuff.json 'src/**/*.abc' build/

Compile all HTML files in src/ to dist/ using the exported result of a JavaScript module:

template-file retrieveData.js 'src/**/*.html' './dist'

Templates

This uses templates similar to mustache templates, but there are some differences.

Anything between {{ and }} can be replaced with a value. Spacing doesn't matter.

const template = '{{ location.name }} is {{adjective}}.';
const data = {
  location: { name: 'Nashville' },
  adjective: 'cool'
};

render(template, data); //» 'Nashville is cool.'

To render a list of items, you can use {{#example}} and {{/example}}. Empty lists and falsy values aren't rendered:

const template = `
  <h3>Friend List:</h3>
  <ul>
    {{#friends}}
    <li>{{name}}</li>
    {{/friends}}
  </ul>
`;

const data = {
  friends: [{ name: 'Amanda' }, { name: 'Bryson' }, { name: 'Josh' }]
};

render(template, data);
// <h3>Friend List:</h3>
// <ul>
//   <li>Amanda</li>
//   <li>Bryson</li>
//   <li>Josh</li>
// </ul>

If you have an array of primitive values instead of objects, you can use {{ this }} to refer to the current value:

const template = `
### Foods I Like

{{#foods}}
  - {{ this }}
{{/foods}}
`;

const data = {
  foods: ['steak', 'eggs', 'avocado']
};

render(template, data);
// ### Foods I Like
//
// - steak
// - eggs
// - avocado

If a replacement is a function, it is called with no arguments:

const template = `Hello, {{name}}`;

const data = {
  name: () => 'Charles'
};

render(template, data); //» Hello, Charles

API

In addition to the CLI, this module exports several helpers to programmatically render templates.

Example:

import { render, renderFile } from 'template-file';

const data = {
  location: { name: 'Nashville' },
  adjective: 'cool'
};

// Replace variables in string
render('{{ location.name }} is {{ adjective }}.', data); //» 'Nashville is cool.'

// Replace variables in a file (same as above, but from a file)
const string = await renderFile('/path/to/file', data);
console.log(renderedString);

render

Type:

function render(template: string, data: Data): string;

Replaces values from data and returns the rendered string.

import { render } from 'template-file';

const data = {
  location: { name: 'Nashville' },
  adjective: 'cool'
};

render('{{ location.name }} is {{ adjective }}.', data); //» 'Nashville is cool.'

renderFile

Type:

function renderFile(filepath: string, data: Data): Promise<string>;

Reads a file replaces values from data, and returns the rendered string.

import { renderFile } from 'template-file';

// example.html:
// <h1>Welcome back, {{ sites.github.username }}!</h1>

const data = {
  name: 'Blake',
  sites: {
    github: {
      username: 'blakek'
    }
  }
};

renderFile('./example.html', data); //» '<h1>Welcome back, blakek!</h1>'

renderGlob

Type: (note, this may change in a future major version release)

function renderGlob(
  sourceGlob: string,
  data: Data,
  onFileCallback: (filename: string, contents: string) => void
): Promise<void>;

Finds files matching a glob pattern, reads those files, replaces values from data, and calls a function for each file. Note, no string is returned from the function; values are handled through callbacks for each file.

import { renderGlob } from 'template-file';

// ./templates/profile.html:
// <h1>Welcome back, {{ name }}!</h1>

// ./templates/sign-in.html:
// <p>Currently signed in as <em>{{ sites.github.username }}<em>.</p>

const data = {
  name: 'Blake',
  sites: {
    github: {
      username: 'blakek'
    }
  }
};

const files = [];

renderGlob('./templates/*.html', data, (filename, contents) => {
  files.push({ filename, contents });
});

console.log(files);
// [
//   {
//     contents: '<h1>Welcome back, Blake!</h1>',
//     filename: './templates/profile.html'
//   },
//   {
//     contents: '<p>Currently signed in as <em>blakek<em>.</p>',
//     filename: './templates/sign-in.html'
//   }
// ]

renderToFolder

Type:

function renderToFolder(
  sourceGlob: string,
  destination: string,
  data: Data
): Promise<void>;
import { renderToFolder } from 'template-file';

const data = {
  name: 'Blake',
  sites: {
    github: {
      username: 'blakek'
    }
  }
};

renderToFolder('./templates/*.html', './dist/', data);

Finds files matching a glob pattern, reads those files, replaces values from data, and writes a file with the same name to destination.

Upgrading from older versions:

Version 5 renamed some functions to be simpler:

  • renderString was renamed render
  • renderTemplateFile was renamed renderFile
  • renderGlob and renderToFolder were in v4 but were undocumented. The API for renderGlob may change in the future, depending on usage.

Versions < 4 could not lookup properties with a dot in the name. This should be possible since version 4. For example, this was not possible before v4.0.0:

import { render } from 'template-file';

const data = { 'with.dot': 'yep' };

render('Does this work? {{with.dot}}', data);

Install

With either Yarn or npm installed, run one of the following:

Task with Yarn with npm
Add this to a project yarn add template-file npm install --save template-file
Install this as a development dependency yarn add --dev template-file npm install --save-dev template-file
Install this globally yarn global add template-file npm install --global template-file

License

MIT

template-file's People

Contributors

bingtimren avatar blakek avatar dependabot[bot] avatar greenkeeper[bot] avatar idmadj avatar justynhunter avatar meyer-mcmains avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

template-file's Issues

[Bug] Empty arrays are still rendered

The documentation says, "Empty lists and falsy values aren't rendered". This doesn't appear to be true.

If I pass in any of the following arrays: [], [undefined], [null], the contents within the array template string are still rendered.

[align=center]{{#emptyArray}}[img]{{ this }}[/img]{{/emptyArray}}[/align]

returns

[align=center][img][/img][/align]

I would expect based on that "aren't rendered" statement for the output to be:

[align=center][/align]

As you can see by my examples, I'm using bbcode. In bbcode, an empty image element ([img][/img]) throws an error. Furthermore, this means you can't use this syntax as a makeshift if-statement by wrapping an item in an array and relying on it to not render contents if the array is empty.

assert util fs path issue with Angular 14

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "assert": require.resolve("assert/") }'
- install 'assert'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "assert": false }

if/else tags?

First of all, thank you for this amazing library!!!

I've tried playing with the mustache if/else rendering tags {#items[0].content}something here{/items[0].content} but I keep getting this error:

(node:35373) UnhandledPromiseRejectionWarning: TypeError: replacements.map is not a function
at /Users/nicolaeolariu/work/github/tribute-video-creator/ffmpeg-node/node_modules/template-file/src/index.ts:60:12
at String.replace (<anonymous>)

File template used: -> an .ass subtitle file

    [Script Info]
    PlayResX: {{videoWidth}}
    PlayResY: {{videoHeight}}
    WrapStyle: 1
    
    [V4+ Styles]
    Format: Name, Alignment, MarginL, MarginR
    Style: center_align, 5, {{marginLeft}}, {{marginRight}}
    
    [Events]
    Format: Start, End, Style, Text
    Dialogue: {{videoStart}}, {{videoEnd}}, center_align, {\fad({{fadeIn}},{{fadeOut}})}{{#texts[0].content}}{\fn{{texts[0].fontName}}}{\fs46}{\c&{{texts[0].bgrColor}}&}{{texts[0].content}}{\fn}\N{{/texts[0].content}}{{#texts[1].content}}{\fn{{texts[1].fontName}}}{\fs40}{\c&{{texts[1].bgrColor}}&}{{texts[1].content}}{\fn}\N{{/texts[1].content}}{{#texts[2].content}}{\fn{{texts[2].fontName}}}{\fs30}{\c&H{{texts[2].bgrColor}}&}{{texts[2].content}}{\fn}{{/texts[2].content}}

Model used for binding:

    {
    videoWidth: 878,
    videoHeight: 494,
    videoStart: "",
    videoEnd: "",
    marginLeft: 350,
    marginRight: 50,
    fadeIn: 1000,
    fadeOut: 0,
    texts: [ [Object], [Object], [Object] ] // each object contain properties: fontName, content, bgrColor
  }

Any ideas of what am I doing wrong? Everything works great until I'm adding the if/else tags.

Thank you in advance!

Only shallow/first-level of JSON values can be used

Current behavior:

In data.json:

{
  "adjective": "cool",
  "person": {
    "name": "Blake"
  }
}

In file:

{{ person.name }} is {{ adjective }}.

Renders:
is cool.

Expected behavior:

This should render:
Blake is cool.

Getting: "Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined ...." error

This might be a problem with my setup, however, i keep getting the below error:

internal/process/esm_loader.js:74
internalBinding('errors').triggerUncaughtException(

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in /Users/john.doe/Documents/Projects/cli/node_modules/template-file/package.json imported from /Users/john.doe/Documents/Projects/cli/lib/config-generator.js

Please could you help point me in the right direction on resolving this?

`renderString` should insert resolved promise values

Right now, we allow inserting data returned from a function.

Current behavior:

const getUserDetails = () => ({ name: 'John Doe' })

renderString('{{ name }} is cool.', getUserDetails)

However, it'd be nice if this allowed promises to be specified. This would allow async tasks to be run instead of requiring it all be done in advance.

Proposed behavior:

const getUserDetails = async () => {
  const user = await getUserFromDatabase()
  return { name: user.name }
}

await renderString('{{ name }} is cool.', getUserDetails)

This would be a major-version API change because renderString will return a promise instead of a string.

Dependency meow security vulnerability

There is a vulnerability in the trim-newlines library used.
template-file>meow 8.0.0 >trim-newlines 3.0.0

GHSA-7p7h-4mm5-852v

Is there a change to update meow to v10.0.1 or a later one, so that it ends up using trim-newlines v4.0.1 which is the patched version?

Feature: renderFolder

Hey, I'd like to move the recursive rendering to the index.js file, in that way a renderFolder or renderGlob could be used to replace them recursively

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.