index.js 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. /*
  2. * Module dependencies
  3. */
  4. var balanced = require("balanced-match")
  5. /**
  6. * Expose `reduceFunctionCall`
  7. *
  8. * @type {Function}
  9. */
  10. module.exports = reduceFunctionCall
  11. /**
  12. * Walkthrough all expressions, evaluate them and insert them into the declaration
  13. *
  14. * @param {Array} expressions
  15. * @param {Object} declaration
  16. */
  17. function reduceFunctionCall(string, functionRE, callback) {
  18. var call = string
  19. return getFunctionCalls(string, functionRE).reduce(function(string, obj) {
  20. return string.replace(obj.functionIdentifier + "(" + obj.matches.body + ")", evalFunctionCall(obj.matches.body, obj.functionIdentifier, callback, call, functionRE))
  21. }, string)
  22. }
  23. /**
  24. * Parses expressions in a value
  25. *
  26. * @param {String} value
  27. * @returns {Array}
  28. * @api private
  29. */
  30. function getFunctionCalls(call, functionRE) {
  31. var expressions = []
  32. var fnRE = typeof functionRE === "string" ? new RegExp("\\b(" + functionRE + ")\\(") : functionRE
  33. do {
  34. var searchMatch = fnRE.exec(call)
  35. if (!searchMatch) {
  36. return expressions
  37. }
  38. if (searchMatch[1] === undefined) {
  39. throw new Error("Missing the first couple of parenthesis to get the function identifier in " + functionRE)
  40. }
  41. var fn = searchMatch[1]
  42. var startIndex = searchMatch.index
  43. var matches = balanced("(", ")", call.substring(startIndex))
  44. if (!matches || matches.start !== searchMatch[0].length - 1) {
  45. throw new SyntaxError(fn + "(): missing closing ')' in the value '" + call + "'")
  46. }
  47. expressions.push({matches: matches, functionIdentifier: fn})
  48. call = matches.post
  49. }
  50. while (fnRE.test(call))
  51. return expressions
  52. }
  53. /**
  54. * Evaluates an expression
  55. *
  56. * @param {String} expression
  57. * @returns {String}
  58. * @api private
  59. */
  60. function evalFunctionCall (string, functionIdentifier, callback, call, functionRE) {
  61. // allow recursivity
  62. return callback(reduceFunctionCall(string, functionRE, callback), functionIdentifier, call)
  63. }