| |
| |
| |
| |
| |
| |
|
|
|
|
| 'use strict';
|
|
|
| |
| |
| |
|
|
|
|
| var debug = require('debug')('express:view');
|
| var path = require('node:path');
|
| var fs = require('node:fs');
|
|
|
| |
| |
| |
|
|
|
|
| var dirname = path.dirname;
|
| var basename = path.basename;
|
| var extname = path.extname;
|
| var join = path.join;
|
| var resolve = path.resolve;
|
|
|
| |
| |
| |
|
|
|
|
| module.exports = View;
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| function View(name, options) {
|
| var opts = options || {};
|
|
|
| this.defaultEngine = opts.defaultEngine;
|
| this.ext = extname(name);
|
| this.name = name;
|
| this.root = opts.root;
|
|
|
| if (!this.ext && !this.defaultEngine) {
|
| throw new Error('No default engine was specified and no extension was provided.');
|
| }
|
|
|
| var fileName = name;
|
|
|
| if (!this.ext) {
|
|
|
| this.ext = this.defaultEngine[0] !== '.'
|
| ? '.' + this.defaultEngine
|
| : this.defaultEngine;
|
|
|
| fileName += this.ext;
|
| }
|
|
|
| if (!opts.engines[this.ext]) {
|
|
|
| var mod = this.ext.slice(1)
|
| debug('require "%s"', mod)
|
|
|
|
|
| var fn = require(mod).__express
|
|
|
| if (typeof fn !== 'function') {
|
| throw new Error('Module "' + mod + '" does not provide a view engine.')
|
| }
|
|
|
| opts.engines[this.ext] = fn
|
| }
|
|
|
|
|
| this.engine = opts.engines[this.ext];
|
|
|
|
|
| this.path = this.lookup(fileName);
|
| }
|
|
|
| |
| |
| |
| |
| |
|
|
|
|
| View.prototype.lookup = function lookup(name) {
|
| var path;
|
| var roots = [].concat(this.root);
|
|
|
| debug('lookup "%s"', name);
|
|
|
| for (var i = 0; i < roots.length && !path; i++) {
|
| var root = roots[i];
|
|
|
|
|
| var loc = resolve(root, name);
|
| var dir = dirname(loc);
|
| var file = basename(loc);
|
|
|
|
|
| path = this.resolve(dir, file);
|
| }
|
|
|
| return path;
|
| };
|
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| View.prototype.render = function render(options, callback) {
|
| var sync = true;
|
|
|
| debug('render "%s"', this.path);
|
|
|
|
|
| this.engine(this.path, options, function onRender() {
|
| if (!sync) {
|
| return callback.apply(this, arguments);
|
| }
|
|
|
|
|
| var args = new Array(arguments.length);
|
| var cntx = this;
|
|
|
| for (var i = 0; i < arguments.length; i++) {
|
| args[i] = arguments[i];
|
| }
|
|
|
|
|
| return process.nextTick(function renderTick() {
|
| return callback.apply(cntx, args);
|
| });
|
| });
|
|
|
| sync = false;
|
| };
|
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| View.prototype.resolve = function resolve(dir, file) {
|
| var ext = this.ext;
|
|
|
|
|
| var path = join(dir, file);
|
| var stat = tryStat(path);
|
|
|
| if (stat && stat.isFile()) {
|
| return path;
|
| }
|
|
|
|
|
| path = join(dir, basename(file, ext), 'index' + ext);
|
| stat = tryStat(path);
|
|
|
| if (stat && stat.isFile()) {
|
| return path;
|
| }
|
| };
|
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| function tryStat(path) {
|
| debug('stat "%s"', path);
|
|
|
| try {
|
| return fs.statSync(path);
|
| } catch (e) {
|
| return undefined;
|
| }
|
| }
|
|
|