lib/view.js JAVASCRIPT 206 lines View on github.com → Search inside
1/*!2 * express3 * Copyright(c) 2009-2013 TJ Holowaychuk4 * Copyright(c) 2013 Roman Shtylman5 * Copyright(c) 2014-2015 Douglas Christopher Wilson6 * MIT Licensed7 */89'use strict';1011/**12 * Module dependencies.13 * @private14 */1516var debug = require('debug')('express:view');17var path = require('node:path');18var fs = require('node:fs');1920/**21 * Module variables.22 * @private23 */2425var dirname = path.dirname;26var basename = path.basename;27var extname = path.extname;28var join = path.join;29var resolve = path.resolve;3031/**32 * Module exports.33 * @public34 */3536module.exports = View;3738/**39 * Initialize a new `View` with the given `name`.40 *41 * Options:42 *43 *   - `defaultEngine` the default template engine name44 *   - `engines` template engine require() cache45 *   - `root` root path for view lookup46 *47 * @param {string} name48 * @param {object} options49 * @public50 */5152function View(name, options) {53  var opts = options || {};5455  this.defaultEngine = opts.defaultEngine;56  this.ext = extname(name);57  this.name = name;58  this.root = opts.root;5960  if (!this.ext && !this.defaultEngine) {61    throw new Error('No default engine was specified and no extension was provided.');62  }6364  var fileName = name;6566  if (!this.ext) {67    // get extension from default engine name68    this.ext = this.defaultEngine[0] !== '.'69      ? '.' + this.defaultEngine70      : this.defaultEngine;7172    fileName += this.ext;73  }7475  if (!opts.engines[this.ext]) {76    // load engine77    var mod = this.ext.slice(1)78    debug('require "%s"', mod)7980    // default engine export81    var fn = require(mod).__express8283    if (typeof fn !== 'function') {84      throw new Error('Module "' + mod + '" does not provide a view engine.')85    }8687    opts.engines[this.ext] = fn88  }8990  // store loaded engine91  this.engine = opts.engines[this.ext];9293  // lookup path94  this.path = this.lookup(fileName);95}9697/**98 * Lookup view by the given `name`99 *100 * @param {string} name101 * @private102 */103104View.prototype.lookup = function lookup(name) {105  var path;106  var roots = [].concat(this.root);107108  debug('lookup "%s"', name);109110  for (var i = 0; i < roots.length && !path; i++) {111    var root = roots[i];112113    // resolve the path114    var loc = resolve(root, name);115    var dir = dirname(loc);116    var file = basename(loc);117118    // resolve the file119    path = this.resolve(dir, file);120  }121122  return path;123};124125/**126 * Render with the given options.127 *128 * @param {object} options129 * @param {function} callback130 * @private131 */132133View.prototype.render = function render(options, callback) {134  var sync = true;135136  debug('render "%s"', this.path);137138  // render, normalizing sync callbacks139  this.engine(this.path, options, function onRender() {140    if (!sync) {141      return callback.apply(this, arguments);142    }143144    // copy arguments145    var args = new Array(arguments.length);146    var cntx = this;147148    for (var i = 0; i < arguments.length; i++) {149      args[i] = arguments[i];150    }151152    // force callback to be async153    return process.nextTick(function renderTick() {154      return callback.apply(cntx, args);155    });156  });157158  sync = false;159};160161/**162 * Resolve the file within the given directory.163 *164 * @param {string} dir165 * @param {string} file166 * @private167 */168169View.prototype.resolve = function resolve(dir, file) {170  var ext = this.ext;171172  // <path>.<ext>173  var path = join(dir, file);174  var stat = tryStat(path);175176  if (stat && stat.isFile()) {177    return path;178  }179180  // <path>/index.<ext>181  path = join(dir, basename(file, ext), 'index' + ext);182  stat = tryStat(path);183184  if (stat && stat.isFile()) {185    return path;186  }187};188189/**190 * Return a stat, maybe.191 *192 * @param {string} path193 * @return {fs.Stats}194 * @private195 */196197function tryStat(path) {198  debug('stat "%s"', path);199200  try {201    return fs.statSync(path);202  } catch (e) {203    return undefined;204  }205}

Code quality findings 31

Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var debug = require('debug')('express:view');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var path = require('node:path');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var fs = require('node:fs');
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var dirname = path.dirname;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var basename = path.basename;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var extname = path.extname;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var join = path.join;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var resolve = path.resolve;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var opts = options || {};
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var fileName = name;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
this.ext = this.defaultEngine[0] !== '.'
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var mod = this.ext.slice(1)
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var fn = require(mod).__express
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (typeof fn !== 'function') {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
if (typeof fn !== 'function') {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var path;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var roots = [].concat(this.root);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var i = 0; i < roots.length && !path; i++) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var i = 0; i < roots.length && !path; i++) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var root = roots[i];
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var loc = resolve(root, name);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var dir = dirname(loc);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var file = basename(loc);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var sync = true;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var args = new Array(arguments.length);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var cntx = this;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
for (var i = 0; i < arguments.length; i++) {
Use let instead of var in loops to avoid scope issues
info correctness var-in-loop
for (var i = 0; i < arguments.length; i++) {
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var ext = this.ext;
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var path = join(dir, file);
Use let or const to avoid scope issues and hoisting
info correctness var-declaration
var stat = tryStat(path);

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.