var Node = require("./node"), Media = require("./media"), URL = require("./url"), Quoted = require("./quoted"), Ruleset = require("./ruleset"), Anonymous = require("./anonymous"); // // CSS @import node // // The general strategy here is that we don't want to wait // for the parsing to be completed, before we start importing // the file. That's because in the context of a browser, // most of the time will be spent waiting for the server to respond. // // On creation, we push the import path to our import queue, though // `import,push`, we also pass it a callback, which it'll call once // the file has been fetched, and parsed. // var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) { this.options = options; this.index = index; this.path = path; this.features = features; this.currentFileInfo = currentFileInfo; if (this.options.less !== undefined || this.options.inline) { this.css = !this.options.less || this.options.inline; } else { var pathValue = this.getPath(); if (pathValue && /[#\.\&\?\/]css([\?;].*)?$/.test(pathValue)) { this.css = true; } } this.copyVisibilityInfo(visibilityInfo); }; // // The actual import node doesn't return anything, when converted to CSS. // The reason is that it's used at the evaluation stage, so that the rules // it imports can be treated like any other rules. // // In `eval`, we make sure all Import nodes get evaluated, recursively, so // we end up with a flat structure, which can easily be imported in the parent // ruleset. // Import.prototype = new Node(); Import.prototype.type = "Import"; Import.prototype.accept = function (visitor) { if (this.features) { this.features = visitor.visit(this.features); } this.path = visitor.visit(this.path); if (!this.options.plugin && !this.options.inline && this.root) { this.root = visitor.visit(this.root); } }; Import.prototype.genCSS = function (context, output) { if (this.css && this.path.currentFileInfo.reference === undefined) { output.add("@import ", this.currentFileInfo, this.index); this.path.genCSS(context, output); if (this.features) { output.add(" "); this.features.genCSS(context, output); } output.add(';'); } }; Import.prototype.getPath = function () { return (this.path instanceof URL) ? this.path.value.value : this.path.value; }; Import.prototype.isVariableImport = function () { var path = this.path; if (path instanceof URL) { path = path.value; } if (path instanceof Quoted) { return path.containsVariables(); } return true; }; Import.prototype.evalForImport = function (context) { var path = this.path; if (path instanceof URL) { path = path.value; } return new Import(path.eval(context), this.features, this.options, this.index, this.currentFileInfo, this.visibilityInfo()); }; Import.prototype.evalPath = function (context) { var path = this.path.eval(context); var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath; if (!(path instanceof URL)) { if (rootpath) { var pathValue = path.value; // Add the base path if the import is relative if (pathValue && context.isPathRelative(pathValue)) { path.value = rootpath + pathValue; } } path.value = context.normalizePath(path.value); } return path; }; Import.prototype.eval = function (context) { var result = this.doEval(context); if (this.options.reference || this.blocksVisibility()) { if (result.length || result.length === 0) { result.forEach(function (node) { node.addVisibilityBlock(); } ); } else { result.addVisibilityBlock(); } } return result; }; Import.prototype.doEval = function (context) { var ruleset, registry, features = this.features && this.features.eval(context); if (this.options.plugin) { registry = context.frames[0] && context.frames[0].functionRegistry; if ( registry && this.root && this.root.functions ) { registry.addMultiple( this.root.functions ); } return []; } if (this.skip) { if (typeof this.skip === "function") { this.skip = this.skip(); } if (this.skip) { return []; } } if (this.options.inline) { var contents = new Anonymous(this.root, 0, { filename: this.importedFilename, reference: this.path.currentFileInfo && this.path.currentFileInfo.reference }, true, true); return this.features ? new Media([contents], this.features.value) : [contents]; } else if (this.css) { var newImport = new Import(this.evalPath(context), features, this.options, this.index); if (!newImport.css && this.error) { throw this.error; } return newImport; } else { ruleset = new Ruleset(null, this.root.rules.slice(0)); ruleset.evalImports(context); return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules; } }; module.exports = Import;