| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 | 'use strict';/*! * Pug * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca> * MIT Licensed *//** * Module dependencies. */var fs = require('fs');var path = require('path');var lex = require('pug-lexer');var stripComments = require('pug-strip-comments');var parse = require('pug-parser');var load = require('pug-load');var filters = require('pug-filters');var link = require('pug-linker');var generateCode = require('pug-code-gen');var runtime = require('pug-runtime');var runtimeWrap = require('pug-runtime/wrap');/** * Name for detection */exports.name = 'Pug';/** * Pug runtime helpers. */exports.runtime = runtime;/** * Template function cache. */exports.cache = {};function applyPlugins(value, options, plugins, name) {  return plugins.reduce(function (value, plugin) {    return (      plugin[name]      ? plugin[name](value, options)      : value    );  }, value);}function findReplacementFunc(plugins, name) {  var eligiblePlugins = plugins.filter(function (plugin) {    return plugin[name];  });  if (eligiblePlugins.length > 1) {    throw new Error('Two or more plugins all implement ' + name + ' method.');  } else if (eligiblePlugins.length) {    return eligiblePlugins[0][name].bind(eligiblePlugins[0]);  }  return null;}/** * Object for global custom filters.  Note that you can also just pass a `filters` * option to any other method. */exports.filters = {};/** * Compile the given `str` of pug and return a function body. * * @param {String} str * @param {Object} options * @return {Object} * @api private */function compileBody(str, options){  var debug_sources = {};  debug_sources[options.filename] = str;  var dependencies = [];  var plugins = options.plugins || [];  var ast = load.string(str, {    filename: options.filename,    basedir: options.basedir,    lex: function (str, options) {      var lexOptions = {};      Object.keys(options).forEach(function (key) {        lexOptions[key] = options[key];      });      lexOptions.plugins = plugins.filter(function (plugin) {        return !!plugin.lex;      }).map(function (plugin) {        return plugin.lex;      });      var contents = applyPlugins(str, {filename: options.filename}, plugins, 'preLex');      return applyPlugins(lex(contents, lexOptions), options, plugins, 'postLex');    },    parse: function (tokens, options) {      tokens = tokens.map(function (token) {        if (token.type === 'path' && path.extname(token.val) === '') {          return {            type: 'path',            loc: token.loc,            val: token.val + '.pug'          };        }        return token;      });      tokens = stripComments(tokens, options);      tokens = applyPlugins(tokens, options, plugins, 'preParse');      var parseOptions = {};      Object.keys(options).forEach(function (key) {        parseOptions[key] = options[key];      });      parseOptions.plugins = plugins.filter(function (plugin) {        return !!plugin.parse;      }).map(function (plugin) {        return plugin.parse;      });      return applyPlugins(        applyPlugins(parse(tokens, parseOptions), options, plugins, 'postParse'),        options, plugins, 'preLoad'      );    },    resolve: function (filename, source, loadOptions) {      var replacementFunc = findReplacementFunc(plugins, 'resolve');      if (replacementFunc) {        return replacementFunc(filename, source, options);      }      return load.resolve(filename, source, loadOptions);    },    read: function (filename, loadOptions) {      dependencies.push(filename);      var contents;      var replacementFunc = findReplacementFunc(plugins, 'read');      if (replacementFunc) {        contents = replacementFunc(filename, options);      } else {        contents = load.read(filename, loadOptions);      }      debug_sources[filename] = contents;      return contents;    }  });  ast = applyPlugins(ast, options, plugins, 'postLoad');  ast = applyPlugins(ast, options, plugins, 'preFilters');  var filtersSet = {};  Object.keys(exports.filters).forEach(function (key) {    filtersSet[key] = exports.filters[key];  });  if (options.filters) {    Object.keys(options.filters).forEach(function (key) {      filtersSet[key] = options.filters[key];    });  }  ast = filters.handleFilters(ast, filtersSet, options.filterOptions, options.filterAliases);  ast = applyPlugins(ast, options, plugins, 'postFilters');  ast = applyPlugins(ast, options, plugins, 'preLink');  ast = link(ast);  ast = applyPlugins(ast, options, plugins, 'postLink');  // Compile  ast = applyPlugins(ast, options, plugins, 'preCodeGen');  var js = generateCode(ast, {    pretty: options.pretty,    compileDebug: options.compileDebug,    doctype: options.doctype,    inlineRuntimeFunctions: options.inlineRuntimeFunctions,    globals: options.globals,    self: options.self,    includeSources: options.includeSources ? debug_sources : false,    templateName: options.templateName  });  js = applyPlugins(js, options, plugins, 'postCodeGen');  // Debug compiler  if (options.debug) {    console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, '  '));  }  return {body: js, dependencies: dependencies};}/** * Get the template from a string or a file, either compiled on-the-fly or * read from cache (if enabled), and cache the template if needed. * * If `str` is not set, the file specified in `options.filename` will be read. * * If `options.cache` is true, this function reads the file from * `options.filename` so it must be set prior to calling this function. * * @param {Object} options * @param {String=} str * @return {Function} * @api private */function handleTemplateCache (options, str) {  var key = options.filename;  if (options.cache && exports.cache[key]) {    return exports.cache[key];  } else {    if (str === undefined) str = fs.readFileSync(options.filename, 'utf8');    var templ = exports.compile(str, options);    if (options.cache) exports.cache[key] = templ;    return templ;  }}/** * Compile a `Function` representation of the given pug `str`. * * Options: * *   - `compileDebug` when `false` debugging code is stripped from the compiled       template, when it is explicitly `true`, the source code is included in       the compiled template for better accuracy. *   - `filename` used to improve errors when `compileDebug` is not `false` and to resolve imports/extends * * @param {String} str * @param {Options} options * @return {Function} * @api public */exports.compile = function(str, options){  var options = options || {}  str = String(str);  var parsed = compileBody(str, {    compileDebug: options.compileDebug !== false,    filename: options.filename,    basedir: options.basedir,    pretty: options.pretty,    doctype: options.doctype,    inlineRuntimeFunctions: options.inlineRuntimeFunctions,    globals: options.globals,    self: options.self,    includeSources: options.compileDebug === true,    debug: options.debug,    templateName: 'template',    filters: options.filters,    filterOptions: options.filterOptions,    filterAliases: options.filterAliases,    plugins: options.plugins,  });  var res = options.inlineRuntimeFunctions    ? new Function('', parsed.body + ';return template;')()    : runtimeWrap(parsed.body);  res.dependencies = parsed.dependencies;  return res;};/** * Compile a JavaScript source representation of the given pug `str`. * * Options: * *   - `compileDebug` When it is `true`, the source code is included in *     the compiled template for better error messages. *   - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends *   - `name` the name of the resulting function (defaults to "template") *   - `module` when it is explicitly `true`, the source code include export module syntax * * @param {String} str * @param {Options} options * @return {Object} * @api public */exports.compileClientWithDependenciesTracked = function(str, options){  var options = options || {};  str = String(str);  var parsed = compileBody(str, {    compileDebug: options.compileDebug,    filename: options.filename,    basedir: options.basedir,    pretty: options.pretty,    doctype: options.doctype,    inlineRuntimeFunctions: options.inlineRuntimeFunctions !== false,    globals: options.globals,    self: options.self,    includeSources: options.compileDebug,    debug: options.debug,    templateName: options.name || 'template',    filters: options.filters,    filterOptions: options.filterOptions,    filterAliases: options.filterAliases,    plugins: options.plugins  });  var body = parsed.body;  if(options.module) {    if(options.inlineRuntimeFunctions === false) {      body = 'var pug = require("pug-runtime");' + body;    }    body += ' module.exports = ' + (options.name || 'template') + ';';  }  return {body: body, dependencies: parsed.dependencies};};/** * Compile a JavaScript source representation of the given pug `str`. * * Options: * *   - `compileDebug` When it is `true`, the source code is included in *     the compiled template for better error messages. *   - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends *   - `name` the name of the resulting function (defaults to "template") * * @param {String} str * @param {Options} options * @return {String} * @api public */exports.compileClient = function (str, options) {  return exports.compileClientWithDependenciesTracked(str, options).body;};/** * Compile a `Function` representation of the given pug file. * * Options: * *   - `compileDebug` when `false` debugging code is stripped from the compiled       template, when it is explicitly `true`, the source code is included in       the compiled template for better accuracy. * * @param {String} path * @param {Options} options * @return {Function} * @api public */exports.compileFile = function (path, options) {  options = options || {};  options.filename = path;  return handleTemplateCache(options);};/** * Render the given `str` of pug. * * Options: * *   - `cache` enable template caching *   - `filename` filename required for `include` / `extends` and caching * * @param {String} str * @param {Object|Function} options or fn * @param {Function|undefined} fn * @returns {String} * @api public */exports.render = function(str, options, fn){  // support callback API  if ('function' == typeof options) {    fn = options, options = undefined;  }  if (typeof fn === 'function') {    var res;    try {      res = exports.render(str, options);    } catch (ex) {      return fn(ex);    }    return fn(null, res);  }  options = options || {};  // cache requires .filename  if (options.cache && !options.filename) {    throw new Error('the "filename" option is required for caching');  }  return handleTemplateCache(options, str)(options);};/** * Render a Pug file at the given `path`. * * @param {String} path * @param {Object|Function} options or callback * @param {Function|undefined} fn * @returns {String} * @api public */exports.renderFile = function(path, options, fn){  // support callback API  if ('function' == typeof options) {    fn = options, options = undefined;  }  if (typeof fn === 'function') {    var res;    try {      res = exports.renderFile(path, options);    } catch (ex) {      return fn(ex);    }    return fn(null, res);  }  options = options || {};  options.filename = path;  return handleTemplateCache(options)(options);};/** * Compile a Pug file at the given `path` for use on the client. * * @param {String} path * @param {Object} options * @returns {String} * @api public */exports.compileFileClient = function(path, options){  var key = path + ':client';  options = options || {};  options.filename = path;  if (options.cache && exports.cache[key]) {    return exports.cache[key];  }  var str = fs.readFileSync(options.filename, 'utf8');  var out = exports.compileClient(str, options);  if (options.cache) exports.cache[key] = out;  return out;};/** * Express support. */exports.__express = function(path, options, fn) {  if(options.compileDebug == undefined && process.env.NODE_ENV === 'production') {    options.compileDebug = false;  }  exports.renderFile(path, options, fn);}
 |