// Except for a block in #visitImport, everything here is an exact copy of the // source in stylus this currently depends on. If stylus is updated, update // this appropriately. var Evaluator = require('stylus/lib/visitor/evaluator') , nodes = require('stylus/lib/nodes') , Stack = require('stylus/lib/stack') , Frame = require('stylus/lib/stack/frame') , Scope = require('stylus/lib/stack/scope') , utils = require('stylus/lib/utils') , bifs = require('stylus/lib/functions') , basename = require('path').basename , dirname = require('path').dirname , relative = require('path').relative , join = require('path').join , colors = require('stylus/lib/colors') // , debug = require('debug')('stylus:evaluator') , fs = require('fs'); module.exports = CachedPathEvaluator; /** * Import `file` and return Block node. * * @api private */ function importFile(node, file, literal, index) { var importStack = this.importStack , Parser = require('stylus/lib/parser') , stat; // Handling the `require` if (node.once) { if (this.requireHistory[file]) return nodes.null; this.requireHistory[file] = true; if (literal && !this.includeCSS) { return node; } } // Expose imports node.path = file; node.dirname = dirname(file); // Store the modified time stat = fs.statSync(file); node.mtime = stat.mtime; this.paths.push(node.dirname); // Avoid overflows from importing the same file over again if (file === importStack[importStack.length - 1]) return nodes.null; if (this.options._imports) this.options._imports.push(node.clone()); // Parse the file importStack.push(file); nodes.filename = file; var str; if (this.cache.sources && this.cache.sources[file]) { str = this.cache.sources[file]; } else { str = fs.readFileSync(file, 'utf8'); } if (literal && !this.resolveURL) return new nodes.Literal(str.replace(/\r\n?/g, '\n')); // parse var block = new nodes.Block , parser = new Parser(str, utils.merge({ root: block }, this.options)); try { block = parser.parse(); } catch (err) { err.filename = file; err.lineno = parser.lexer.lineno; err.input = str; throw err; } // Evaluate imported "root" block.parent = this.root; block.scope = false; var ret = this.visit(block); importStack.pop(); if (importStack.length || index) this.paths.pop(); return ret; } function CachedPathEvaluator(root, options) { Evaluator.apply(this, arguments); this.cache = options.cache; } CachedPathEvaluator.prototype = Object.create(Evaluator.prototype); CachedPathEvaluator.prototype.constructor = CachedPathEvaluator; CachedPathEvaluator.prototype.visitImport = function(imported) { this.return++; var path = this.visit(imported.path).first , nodeName = imported.once ? 'require' : 'import' , found , literal , index; this.return--; // debug('import %s', path); // url() passed if ('url' == path.name) { if (imported.once) throw new Error('You cannot @require a url'); return imported; } // Ensure string if (!path.string) throw new Error('@' + nodeName + ' string expected'); var name = path = path.string; // Absolute URL if (/url\s*\(\s*['"]?(?:https?:)?\/\//i.test(path)) { if (imported.once) throw new Error('You cannot @require a url'); return imported; } // Literal if (/\.css(?:"|$)/.test(path)) { literal = true; if (!imported.once && !this.includeCSS) { return imported; } } // support optional .styl if (!literal && !/\.styl$/i.test(path)) path += '.styl'; /***************************************************************************** * THIS IS THE ONLY BLOCK THAT DIFFERS FROM THE ACTUAL STYLUS IMPLEMENTATION. * *****************************************************************************/ // Lookup var dirname = this.paths[this.paths.length - 1]; found = this.cache.find(path, dirname); index = this.cache.isIndex(path, dirname); if (!found) { found = utils.find(path, this.paths, this.filename); if (!found) { found = utils.lookupIndex(name, this.paths, this.filename); index = true; } } // Throw if import failed if (!found) throw new Error('failed to locate @' + nodeName + ' file ' + path); var block = new nodes.Block; for (var i = 0, len = found.length; i < len; ++i) { block.push(importFile.call(this, imported, found[i], literal, index)); } return block; }