Files
less.js/lib/less/tree/import.js
meri ead3e29f7b Fixing import by reference
- refactored how import reference works
- refactored to-css-visitor (this is side product, it was getting
  complicated)
- fixes issues #1851, #1896, #1878, #2716, #1968, #2162 (same as #1896)
2015-11-20 15:10:53 +01:00

166 lines
5.3 KiB
JavaScript

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;