template.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /**
  2. * Wrapper for underscore's template utility to allow loading templates from files.
  3. * @module jsdoc/template
  4. */
  5. const _ = require('underscore');
  6. const fs = require('jsdoc/fs');
  7. const path = require('path');
  8. /**
  9. * Underscore template helper.
  10. */
  11. class Template {
  12. /**
  13. * @param {string} filepath - Templates directory.
  14. */
  15. constructor(filepath) {
  16. this.path = filepath;
  17. this.layout = null;
  18. this.cache = {};
  19. // override default template tag settings
  20. this.settings = {
  21. evaluate: /<\?js([\s\S]+?)\?>/g,
  22. interpolate: /<\?js=([\s\S]+?)\?>/g,
  23. escape: /<\?js~([\s\S]+?)\?>/g
  24. };
  25. }
  26. /**
  27. * Loads template from given file.
  28. * @param {string} file - Template filename.
  29. * @return {function} Returns template closure.
  30. */
  31. load(file) {
  32. return _.template(fs.readFileSync(file, 'utf8'), null, this.settings);
  33. }
  34. /**
  35. * Renders template using given data.
  36. *
  37. * This is low-level function, for rendering full templates use {@link Template.render()}.
  38. *
  39. * @param {string} file - Template filename.
  40. * @param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use).
  41. * @return {string} Rendered template.
  42. */
  43. partial(file, data) {
  44. file = path.resolve(this.path, file);
  45. // load template into cache
  46. if (!(file in this.cache)) {
  47. this.cache[file] = this.load(file);
  48. }
  49. // keep template helper context
  50. return this.cache[file].call(this, data);
  51. }
  52. /**
  53. * Renders template with given data.
  54. *
  55. * This method automaticaly applies layout if set.
  56. *
  57. * @param {string} file - Template filename.
  58. * @param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use).
  59. * @return {string} Rendered template.
  60. */
  61. render(file, data) {
  62. // main content
  63. let content = this.partial(file, data);
  64. // apply layout
  65. if (this.layout) {
  66. data.content = content;
  67. content = this.partial(this.layout, data);
  68. }
  69. return content;
  70. }
  71. }
  72. exports.Template = Template;