mirror of
https://github.com/less/less.js.git
synced 2026-02-08 22:15:04 -05:00
The genCss method of ruleset.js splits child nodes into two groups: * rules, * rulesets. Rules are always printed first and have special handling for last rule. Rulesets are always printed second. Wrong ordering was caused by the condition that determined what is rule and what is ruleset. Issue #2013: The condition made no difference between @charset and @page, because both are compiled into tree.Directive nodes. I added isRulesetLike method to the tree.Directive to differentiate between them. Issue #1954: The condition treated all tree.Anonymous types as rules and caused them to float up. That is incorrect, because `@import (inline)` is compiled into tree.Anonymous too, but should be treated as ruleset and stay where it is.
125 lines
4.2 KiB
JavaScript
125 lines
4.2 KiB
JavaScript
(function (tree) {
|
|
//
|
|
// 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.
|
|
//
|
|
tree.Import = function (path, features, options, index, currentFileInfo) {
|
|
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;
|
|
}
|
|
}
|
|
};
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
tree.Import.prototype = {
|
|
type: "Import",
|
|
accept: function (visitor) {
|
|
if (this.features) {
|
|
this.features = visitor.visit(this.features);
|
|
}
|
|
this.path = visitor.visit(this.path);
|
|
if (!this.options.inline && this.root) {
|
|
this.root = visitor.visit(this.root);
|
|
}
|
|
},
|
|
genCSS: function (env, output) {
|
|
if (this.css) {
|
|
output.add("@import ", this.currentFileInfo, this.index);
|
|
this.path.genCSS(env, output);
|
|
if (this.features) {
|
|
output.add(" ");
|
|
this.features.genCSS(env, output);
|
|
}
|
|
output.add(';');
|
|
}
|
|
},
|
|
toCSS: tree.toCSS,
|
|
getPath: function () {
|
|
if (this.path instanceof tree.Quoted) {
|
|
var path = this.path.value;
|
|
return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less';
|
|
} else if (this.path instanceof tree.URL) {
|
|
return this.path.value.value;
|
|
}
|
|
return null;
|
|
},
|
|
evalForImport: function (env) {
|
|
return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo);
|
|
},
|
|
evalPath: function (env) {
|
|
var path = this.path.eval(env);
|
|
var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
|
|
|
|
if (!(path instanceof tree.URL)) {
|
|
if (rootpath) {
|
|
var pathValue = path.value;
|
|
// Add the base path if the import is relative
|
|
if (pathValue && env.isPathRelative(pathValue)) {
|
|
path.value = rootpath +pathValue;
|
|
}
|
|
}
|
|
path.value = env.normalizePath(path.value);
|
|
}
|
|
|
|
return path;
|
|
},
|
|
eval: function (env) {
|
|
var ruleset, features = this.features && this.features.eval(env);
|
|
|
|
if (this.skip) {
|
|
if (typeof this.skip === "function") {
|
|
this.skip = this.skip();
|
|
}
|
|
if (this.skip) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
if (this.options.inline) {
|
|
//todo needs to reference css file not import
|
|
var contents = new(tree.Anonymous)(this.root, 0, {filename: this.importedFilename}, true, true);
|
|
return this.features ? new(tree.Media)([contents], this.features.value) : [contents];
|
|
} else if (this.css) {
|
|
var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index);
|
|
if (!newImport.css && this.error) {
|
|
throw this.error;
|
|
}
|
|
return newImport;
|
|
} else {
|
|
ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
|
|
|
|
ruleset.evalImports(env);
|
|
|
|
return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
|
|
}
|
|
}
|
|
};
|
|
|
|
})(require('../tree'));
|