| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // 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;
- }
|