From 38e836527032ca01e61e188d61d020cbcb3b1043 Mon Sep 17 00:00:00 2001 From: Harminder virk Date: Mon, 13 Apr 2020 21:49:55 +0530 Subject: [PATCH] feat: add mustache templates support --- package-lock.json | 5 +++++ package.json | 1 + src/Contracts/index.ts | 5 +++++ src/Generator/File.ts | 13 ++++++++++-- src/utils/template.ts | 13 ++++++++---- test/fixtures/template1.mustache | 1 + test/template.spec.ts | 35 ++++++++++++++++++-------------- 7 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 test/fixtures/template1.mustache diff --git a/package-lock.json b/package-lock.json index 506f2cf..fa75934 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5149,6 +5149,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "mustache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.0.1.tgz", + "integrity": "sha512-yL5VE97+OXn4+Er3THSmTdCFCtx5hHWzrolvH+JObZnUYwuaG7XV+Ch4fR2cIrcYI0tFHxS7iyFYl14bW8y2sA==" + }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", diff --git a/package.json b/package.json index 79cb39b..e6291f6 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "fast-levenshtein": "^2.0.6", "fs-extra": "^9.0.0", "getopts": "^2.2.4", + "mustache": "^4.0.1", "pluralize": "^8.0.0", "slash": "^3.0.0" }, diff --git a/src/Contracts/index.ts b/src/Contracts/index.ts index 210a528..4c73016 100644 --- a/src/Contracts/index.ts +++ b/src/Contracts/index.ts @@ -208,6 +208,11 @@ export interface GeneratorFileContract { */ stub (fileOrContents: string, options?: { raw: boolean }): this + /** + * Instruct to use mustache templating syntax, instead of template literals + */ + useMustache (): this + /** * The relative path to the destination directory. */ diff --git a/src/Generator/File.ts b/src/Generator/File.ts index 2097cd0..e9feae5 100644 --- a/src/Generator/File.ts +++ b/src/Generator/File.ts @@ -23,6 +23,7 @@ export class GeneratorFile implements GeneratorFileContract { private templateData: any = {} private customDestinationPath?: string private customAppRoot?: string + private mustache: boolean = false constructor ( private name: string, @@ -69,6 +70,14 @@ export class GeneratorFile implements GeneratorFileContract { return this } + /** + * Instruct to use mustache + */ + public useMustache () { + this.mustache = true + return this + } + /** * Variables for stub subsitution */ @@ -127,8 +136,8 @@ export class GeneratorFile implements GeneratorFileContract { const contents = this.stubContents ? ( this.isStubRaw - ? template(this.stubContents, templateContents) - : templateFromFile(this.stubContents, templateContents) + ? template(this.stubContents, templateContents, this.mustache) + : templateFromFile(this.stubContents, templateContents, this.mustache) ) : '' diff --git a/src/utils/template.ts b/src/utils/template.ts index d8d3303..32465bd 100644 --- a/src/utils/template.ts +++ b/src/utils/template.ts @@ -7,16 +7,21 @@ * file that was distributed with this source code. */ +import Mustache from 'mustache' import { readFileSync } from 'fs' /** * Process string as a template literal string and processes * data */ -export function template (tpl: string, data: Object) { +export function template (tpl: string, data: Object, isMustache: boolean) { + if (isMustache) { + return Mustache.render(tpl, data) + } + return tpl.replace(/\$\{([a-zA-Z0-9_-]*)}/g, (_, p1: string) => { if (!(p1 in data)) { - throw new Error(`Missing value for "${p1}"`) + return '' } return String(data[p1]) }) @@ -26,7 +31,7 @@ export function template (tpl: string, data: Object) { * Loads template file from the disk and process it contents * using the [[template]] method */ -export function templateFromFile (file: string, data: object): string { +export function templateFromFile (file: string, data: object, isMustache: boolean): string { const contents = readFileSync(file, 'utf8') - return template(contents, data) + return template(contents, data, isMustache) } diff --git a/test/fixtures/template1.mustache b/test/fixtures/template1.mustache new file mode 100644 index 0000000..58a5d94 --- /dev/null +++ b/test/fixtures/template1.mustache @@ -0,0 +1 @@ +Hello {{value1}}, {{value2}} diff --git a/test/template.spec.ts b/test/template.spec.ts index 77bcb81..51e3beb 100644 --- a/test/template.spec.ts +++ b/test/template.spec.ts @@ -12,37 +12,42 @@ import { join } from 'path' import { template, templateFromFile } from '../src/utils/template' test.group('template', () => { - test('template: interpolate valid template', (assert) => { + test('interpolate valid template', (assert) => { const result = template('${test} ${other}', { test: 123, other: 'hello', - }) + }, false) assert.strictEqual(result, '123 hello') }) - test('template: error if a value is missing', (assert) => { - assert.throws( - () => template('${param}', {}), - 'Missing value for "param"' - ) + test('interpolate template using mustache', (assert) => { + const result = template('{{test}} {{other}}', { + test: 123, + other: 'hello', + }, true) + assert.strictEqual(result, '123 hello') }) +}) - test('templateFromFile: interpolate valid template', (assert) => { +test.group('Template From File', () => { + test('interpolate valid template', (assert) => { const result = templateFromFile(join(__dirname, 'fixtures/template1.txt'), { value1: 'World', value2: 42, - }) + }, false) assert.strictEqual(result, 'Hello World, 42') }) - test('templateFromFile: error if a value is missing', (assert) => { - assert.throws(() => templateFromFile(join(__dirname, 'fixtures/template1.txt'), { - value1: 'World', - }), 'Missing value for "value2"') + test('error if file is missing', (assert) => { + assert.throws(() => templateFromFile(join(__dirname, 'fixtures/i-do-not-exist'), {}, false)) }) - test('templateFromFile: error if file is missing', (assert) => { - assert.throws(() => templateFromFile(join(__dirname, 'fixtures/i-do-not-exist'), {})) + test('interpolate mustache from template file', (assert) => { + const result = templateFromFile(join(__dirname, 'fixtures/template1.mustache'), { + value1: 'World', + value2: 42, + }, true) + assert.strictEqual(result.trim(), 'Hello World, 42') }) })