From 0b2dbd0a4bacf787c701a2238fbf73de0d8d7457 Mon Sep 17 00:00:00 2001 From: Mejia1994 Date: Sat, 9 Jul 2022 10:58:38 -0600 Subject: [PATCH] feat: allow to register global "functions" to be accessed from mustache global instance. --- mustache.js | 33 ++++++++++++++++++++++++++++++++- test/render-test.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/mustache.js b/mustache.js index ed0cd6d..85112b3 100644 --- a/mustache.js +++ b/mustache.js @@ -12,6 +12,16 @@ function isFunction (object) { return typeof object === 'function'; } +function putFunctionsIntoView (view, functions) { + for (var fn in functions){ + if (!view.hasOwnProperty(fn)){ + view[fn] = functions[fn]; + } + } + + return view; +} + /** * More correct typeof string handling array * which normally returns typeof 'object' @@ -703,6 +713,7 @@ var mustache = { Scanner: undefined, Context: undefined, Writer: undefined, + globalFunctions: {}, /** * Allows a user to override the default caching strategy, by providing an * object with set, get and clear methods. This can also be used to disable @@ -749,7 +760,27 @@ mustache.render = function render (template, view, partials, config) { 'argument for mustache#render(template, view, partials)'); } - return defaultWriter.render(template, view, partials, config); + return defaultWriter.render(template, putFunctionsIntoView(view, mustache.globalFunctions), partials, config); +}; + +mustache.registerFunction = function registerFunction (name, fn) { + if (typeStr(name) !== 'string') { + throw new TypeError('String expected on first argument to mustache.registerFunction'); + } + + if (!isFunction(fn)){ + throw new TypeError('Function expected on second argument to mustache.registerFunction'); + } + + if (hasProperty(mustache.globalFunctions, name)){ + console.warn('Function "' + name + '" is already registered, it will be overridden'); + } + + mustache.globalFunctions[name] = function globalFunction () { + return function run (text, render) { + return fn.call(null, render(text)); + }; + }; }; // Export the escaping function so that the user may override it. diff --git a/test/render-test.js b/test/render-test.js index d055523..3711a22 100644 --- a/test/render-test.js +++ b/test/render-test.js @@ -227,6 +227,35 @@ describe('Mustache.render', function () { }); }); + describe('globals functions', function () { + it('the name of the function must be a string', function () { + assert.throws(function () { + Mustache.registerFunction(['wrong name'], function () {}); + }, TypeError, 'String expected on first argument to mustache.registerFunction'); + }); + + it('the function parameter must be a Function', function () { + assert.throws(function () { + Mustache.registerFunction('wrong name', ['wrong function']); + }, TypeError, 'Function expected on second argument to mustache.registerFunction'); + }); + + it('should register a function', function () { + Mustache.registerFunction('upperCase', function (str) { + return str.charAt(0).toUpperCase() + str.slice(1); + }); + + assert.ok(Mustache.globalFunctions.hasOwnProperty('upperCase')); + }); + + it('should render a template with a registered function', function () { + + var template = 'Hello from {{#upperCase}}{{country}}{{/upperCase}}'; + + assert.equal(Mustache.render(template, {country: 'nicaragua'}), 'Hello from Nicaragua'); + }); + }); + tests.forEach(function (test) { var view = eval(test.view);