less 3.10.0-beta.2 → 3.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/bin/lessc +6652 -5505
- package/dist/less.cjs.js +6593 -5448
- package/dist/less.js +10 -6
- package/dist/less.min.js +2 -2
- package/dist/less.min.js.map +1 -1
- package/lib/less/constants.js +13 -0
- package/lib/less/contexts.js +164 -0
- package/lib/less/data/colors.js +150 -0
- package/lib/less/data/index.js +4 -0
- package/lib/less/data/unit-conversions.js +21 -0
- package/lib/less/default-options.js +68 -0
- package/lib/less/environment/abstract-file-manager.js +127 -0
- package/lib/less/environment/abstract-plugin-loader.js +187 -0
- package/lib/less/environment/environment-api.js +25 -0
- package/lib/less/environment/environment.js +59 -0
- package/lib/less/environment/file-manager-api.js +103 -0
- package/lib/less/functions/boolean.js +13 -0
- package/lib/less/functions/color-blending.js +84 -0
- package/lib/less/functions/color.js +417 -0
- package/lib/less/functions/data-uri.js +74 -0
- package/lib/less/functions/default.js +25 -0
- package/lib/less/functions/function-caller.js +49 -0
- package/lib/less/functions/function-registry.js +35 -0
- package/lib/less/functions/index.js +33 -0
- package/lib/less/functions/list.js +143 -0
- package/lib/less/functions/math-helper.js +15 -0
- package/lib/less/functions/math.js +28 -0
- package/lib/less/functions/number.js +89 -0
- package/lib/less/functions/string.js +36 -0
- package/lib/less/functions/svg.js +87 -0
- package/lib/less/functions/types.js +70 -0
- package/lib/less/import-manager.js +169 -0
- package/lib/less/index.js +92 -0
- package/lib/less/less-error.js +140 -0
- package/lib/less/logger.js +34 -0
- package/lib/less/parse-tree.js +66 -0
- package/lib/less/parse.js +89 -0
- package/lib/less/parser/chunker.js +122 -0
- package/lib/less/parser/parser-input.js +390 -0
- package/lib/less/parser/parser.js +2418 -0
- package/lib/less/plugin-manager.js +168 -0
- package/lib/less/render.js +42 -0
- package/lib/less/source-map-builder.js +77 -0
- package/lib/less/source-map-output.js +149 -0
- package/lib/less/transform-tree.js +96 -0
- package/lib/less/tree/anonymous.js +37 -0
- package/lib/less/tree/assignment.js +33 -0
- package/lib/less/tree/atrule.js +165 -0
- package/lib/less/tree/attribute.js +34 -0
- package/lib/less/tree/call.js +105 -0
- package/lib/less/tree/color.js +246 -0
- package/lib/less/tree/combinator.js +29 -0
- package/lib/less/tree/comment.js +29 -0
- package/lib/less/tree/condition.js +43 -0
- package/lib/less/tree/debug-info.js +34 -0
- package/lib/less/tree/declaration.js +115 -0
- package/lib/less/tree/detached-ruleset.js +30 -0
- package/lib/less/tree/dimension.js +179 -0
- package/lib/less/tree/element.js +73 -0
- package/lib/less/tree/expression.js +74 -0
- package/lib/less/tree/extend.js +66 -0
- package/lib/less/tree/import.js +184 -0
- package/lib/less/tree/index.js +54 -0
- package/lib/less/tree/javascript.js +33 -0
- package/lib/less/tree/js-eval-node.js +58 -0
- package/lib/less/tree/keyword.js +21 -0
- package/lib/less/tree/media.js +154 -0
- package/lib/less/tree/mixin-call.js +215 -0
- package/lib/less/tree/mixin-definition.js +229 -0
- package/lib/less/tree/namespace-value.js +87 -0
- package/lib/less/tree/negative.js +26 -0
- package/lib/less/tree/node.js +178 -0
- package/lib/less/tree/operation.js +62 -0
- package/lib/less/tree/paren.js +22 -0
- package/lib/less/tree/property.js +77 -0
- package/lib/less/tree/quoted.js +70 -0
- package/lib/less/tree/ruleset.js +867 -0
- package/lib/less/tree/selector.js +146 -0
- package/lib/less/tree/unicode-descriptor.js +13 -0
- package/lib/less/tree/unit.js +141 -0
- package/lib/less/tree/url.js +65 -0
- package/lib/less/tree/value.js +44 -0
- package/lib/less/tree/variable-call.js +46 -0
- package/lib/less/tree/variable.js +67 -0
- package/lib/less/utils.js +122 -0
- package/lib/less/visitors/extend-visitor.js +505 -0
- package/lib/less/visitors/import-sequencer.js +58 -0
- package/lib/less/visitors/import-visitor.js +189 -0
- package/lib/less/visitors/index.js +15 -0
- package/lib/less/visitors/join-selector-visitor.js +57 -0
- package/lib/less/visitors/set-tree-visibility-visitor.js +45 -0
- package/lib/less/visitors/to-css-visitor.js +363 -0
- package/lib/less/visitors/visitor.js +163 -0
- package/lib/less-browser/add-default-options.js +49 -0
- package/lib/less-browser/bootstrap.js +69 -0
- package/lib/less-browser/browser.js +65 -0
- package/lib/less-browser/cache.js +43 -0
- package/lib/less-browser/error-reporting.js +170 -0
- package/lib/less-browser/file-manager.js +113 -0
- package/lib/less-browser/image-size.js +28 -0
- package/lib/less-browser/index.js +285 -0
- package/lib/less-browser/log-listener.js +42 -0
- package/lib/less-browser/plugin-loader.js +26 -0
- package/lib/less-browser/utils.js +24 -0
- package/lib/less-node/environment.js +16 -0
- package/lib/less-node/file-manager.js +177 -0
- package/lib/less-node/fs.js +10 -0
- package/lib/less-node/image-size.js +58 -0
- package/lib/less-node/index.js +27 -0
- package/lib/less-node/lessc-helper.js +89 -0
- package/lib/less-node/plugin-loader.js +53 -0
- package/lib/less-node/url-file-manager.js +49 -0
- package/lib/lessc.js +557 -0
- package/lib/source-map/source-map-0.1.31.js +1933 -0
- package/lib/source-map/source-map-footer.js +4 -0
- package/lib/source-map/source-map-header.js +3 -0
- package/package.json +1 -1
- package/test/.DS_Store +0 -0
- package/test/browser/less.min.js +11 -0
- package/test/browser/less.min.js.map +1 -0
- package/test/css/css-escapes.css +1 -0
- package/test/less/css-escapes.less +3 -1
- package/.git/index +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
import Media from './media';
|
|
3
|
+
import URL from './url';
|
|
4
|
+
import Quoted from './quoted';
|
|
5
|
+
import Ruleset from './ruleset';
|
|
6
|
+
import Anonymous from './anonymous';
|
|
7
|
+
import * as utils from '../utils';
|
|
8
|
+
import LessError from '../less-error';
|
|
9
|
+
|
|
10
|
+
//
|
|
11
|
+
// CSS @import node
|
|
12
|
+
//
|
|
13
|
+
// The general strategy here is that we don't want to wait
|
|
14
|
+
// for the parsing to be completed, before we start importing
|
|
15
|
+
// the file. That's because in the context of a browser,
|
|
16
|
+
// most of the time will be spent waiting for the server to respond.
|
|
17
|
+
//
|
|
18
|
+
// On creation, we push the import path to our import queue, though
|
|
19
|
+
// `import,push`, we also pass it a callback, which it'll call once
|
|
20
|
+
// the file has been fetched, and parsed.
|
|
21
|
+
//
|
|
22
|
+
class Import extends Node {
|
|
23
|
+
constructor(path, features, options, index, currentFileInfo, visibilityInfo) {
|
|
24
|
+
super();
|
|
25
|
+
|
|
26
|
+
this.options = options;
|
|
27
|
+
this._index = index;
|
|
28
|
+
this._fileInfo = currentFileInfo;
|
|
29
|
+
this.path = path;
|
|
30
|
+
this.features = features;
|
|
31
|
+
this.allowRoot = true;
|
|
32
|
+
|
|
33
|
+
if (this.options.less !== undefined || this.options.inline) {
|
|
34
|
+
this.css = !this.options.less || this.options.inline;
|
|
35
|
+
} else {
|
|
36
|
+
const pathValue = this.getPath();
|
|
37
|
+
if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) {
|
|
38
|
+
this.css = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
this.copyVisibilityInfo(visibilityInfo);
|
|
42
|
+
this.setParent(this.features, this);
|
|
43
|
+
this.setParent(this.path, this);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
accept(visitor) {
|
|
47
|
+
if (this.features) {
|
|
48
|
+
this.features = visitor.visit(this.features);
|
|
49
|
+
}
|
|
50
|
+
this.path = visitor.visit(this.path);
|
|
51
|
+
if (!this.options.isPlugin && !this.options.inline && this.root) {
|
|
52
|
+
this.root = visitor.visit(this.root);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
genCSS(context, output) {
|
|
57
|
+
if (this.css && this.path._fileInfo.reference === undefined) {
|
|
58
|
+
output.add('@import ', this._fileInfo, this._index);
|
|
59
|
+
this.path.genCSS(context, output);
|
|
60
|
+
if (this.features) {
|
|
61
|
+
output.add(' ');
|
|
62
|
+
this.features.genCSS(context, output);
|
|
63
|
+
}
|
|
64
|
+
output.add(';');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getPath() {
|
|
69
|
+
return (this.path instanceof URL) ?
|
|
70
|
+
this.path.value.value : this.path.value;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
isVariableImport() {
|
|
74
|
+
let path = this.path;
|
|
75
|
+
if (path instanceof URL) {
|
|
76
|
+
path = path.value;
|
|
77
|
+
}
|
|
78
|
+
if (path instanceof Quoted) {
|
|
79
|
+
return path.containsVariables();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
evalForImport(context) {
|
|
86
|
+
let path = this.path;
|
|
87
|
+
|
|
88
|
+
if (path instanceof URL) {
|
|
89
|
+
path = path.value;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
evalPath(context) {
|
|
96
|
+
const path = this.path.eval(context);
|
|
97
|
+
const fileInfo = this._fileInfo;
|
|
98
|
+
|
|
99
|
+
if (!(path instanceof URL)) {
|
|
100
|
+
// Add the rootpath if the URL requires a rewrite
|
|
101
|
+
const pathValue = path.value;
|
|
102
|
+
if (fileInfo &&
|
|
103
|
+
pathValue &&
|
|
104
|
+
context.pathRequiresRewrite(pathValue)) {
|
|
105
|
+
path.value = context.rewritePath(pathValue, fileInfo.rootpath);
|
|
106
|
+
} else {
|
|
107
|
+
path.value = context.normalizePath(path.value);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return path;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
eval(context) {
|
|
115
|
+
const result = this.doEval(context);
|
|
116
|
+
if (this.options.reference || this.blocksVisibility()) {
|
|
117
|
+
if (result.length || result.length === 0) {
|
|
118
|
+
result.forEach(node => {
|
|
119
|
+
node.addVisibilityBlock();
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
result.addVisibilityBlock();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
doEval(context) {
|
|
130
|
+
let ruleset;
|
|
131
|
+
let registry;
|
|
132
|
+
const features = this.features && this.features.eval(context);
|
|
133
|
+
|
|
134
|
+
if (this.options.isPlugin) {
|
|
135
|
+
if (this.root && this.root.eval) {
|
|
136
|
+
try {
|
|
137
|
+
this.root.eval(context);
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
e.message = 'Plugin error during evaluation';
|
|
141
|
+
throw new LessError(e, this.root.imports, this.root.filename);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
registry = context.frames[0] && context.frames[0].functionRegistry;
|
|
145
|
+
if ( registry && this.root && this.root.functions ) {
|
|
146
|
+
registry.addMultiple( this.root.functions );
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (this.skip) {
|
|
153
|
+
if (typeof this.skip === 'function') {
|
|
154
|
+
this.skip = this.skip();
|
|
155
|
+
}
|
|
156
|
+
if (this.skip) {
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (this.options.inline) {
|
|
161
|
+
const contents = new Anonymous(this.root, 0,
|
|
162
|
+
{
|
|
163
|
+
filename: this.importedFilename,
|
|
164
|
+
reference: this.path._fileInfo && this.path._fileInfo.reference
|
|
165
|
+
}, true, true);
|
|
166
|
+
|
|
167
|
+
return this.features ? new Media([contents], this.features.value) : [contents];
|
|
168
|
+
} else if (this.css) {
|
|
169
|
+
const newImport = new Import(this.evalPath(context), features, this.options, this._index);
|
|
170
|
+
if (!newImport.css && this.error) {
|
|
171
|
+
throw this.error;
|
|
172
|
+
}
|
|
173
|
+
return newImport;
|
|
174
|
+
} else {
|
|
175
|
+
ruleset = new Ruleset(null, utils.copyArray(this.root.rules));
|
|
176
|
+
ruleset.evalImports(context);
|
|
177
|
+
|
|
178
|
+
return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
Import.prototype.type = 'Import';
|
|
184
|
+
export default Import;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const tree = Object.create(null);
|
|
2
|
+
|
|
3
|
+
import Node from './node';
|
|
4
|
+
import Color from './color';
|
|
5
|
+
import AtRule from './atrule';
|
|
6
|
+
import DetachedRuleset from './detached-ruleset';
|
|
7
|
+
import Operation from './operation';
|
|
8
|
+
import Dimension from './dimension';
|
|
9
|
+
import Unit from './unit';
|
|
10
|
+
import Keyword from './keyword';
|
|
11
|
+
import Variable from './variable';
|
|
12
|
+
import Property from './property';
|
|
13
|
+
import Ruleset from './ruleset';
|
|
14
|
+
import Element from './element';
|
|
15
|
+
import Attribute from './attribute';
|
|
16
|
+
import Combinator from './combinator';
|
|
17
|
+
import Selector from './selector';
|
|
18
|
+
import Quoted from './quoted';
|
|
19
|
+
import Expression from './expression';
|
|
20
|
+
import Declaration from './declaration';
|
|
21
|
+
import Call from './call';
|
|
22
|
+
import URL from './url';
|
|
23
|
+
import Import from './import';
|
|
24
|
+
import Comment from './comment';
|
|
25
|
+
import Anonymous from './anonymous';
|
|
26
|
+
import Value from './value';
|
|
27
|
+
import JavaScript from './javascript';
|
|
28
|
+
import Assignment from './assignment';
|
|
29
|
+
import Condition from './condition';
|
|
30
|
+
import Paren from './paren';
|
|
31
|
+
import Media from './media';
|
|
32
|
+
import UnicodeDescriptor from './unicode-descriptor';
|
|
33
|
+
import Negative from './negative';
|
|
34
|
+
import Extend from './extend';
|
|
35
|
+
import VariableCall from './variable-call';
|
|
36
|
+
import NamespaceValue from './namespace-value';
|
|
37
|
+
|
|
38
|
+
// mixins
|
|
39
|
+
import MixinCall from './mixin-call';
|
|
40
|
+
import MixinDefinition from './mixin-definition';
|
|
41
|
+
|
|
42
|
+
export default {
|
|
43
|
+
Node, Color, AtRule, DetachedRuleset, Operation,
|
|
44
|
+
Dimension, Unit, Keyword, Variable, Property,
|
|
45
|
+
Ruleset, Element, Attribute, Combinator, Selector,
|
|
46
|
+
Quoted, Expression, Declaration, Call, URL, Import,
|
|
47
|
+
Comment, Anonymous, Value, JavaScript, Assignment,
|
|
48
|
+
Condition, Paren, Media, UnicodeDescriptor, Negative,
|
|
49
|
+
Extend, VariableCall, NamespaceValue,
|
|
50
|
+
mixin: {
|
|
51
|
+
Call: MixinCall,
|
|
52
|
+
Definition: MixinDefinition
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import JsEvalNode from './js-eval-node';
|
|
2
|
+
import Dimension from './dimension';
|
|
3
|
+
import Quoted from './quoted';
|
|
4
|
+
import Anonymous from './anonymous';
|
|
5
|
+
|
|
6
|
+
class JavaScript extends JsEvalNode {
|
|
7
|
+
constructor(string, escaped, index, currentFileInfo) {
|
|
8
|
+
super();
|
|
9
|
+
|
|
10
|
+
this.escaped = escaped;
|
|
11
|
+
this.expression = string;
|
|
12
|
+
this._index = index;
|
|
13
|
+
this._fileInfo = currentFileInfo;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
eval(context) {
|
|
17
|
+
const result = this.evaluateJavaScript(this.expression, context);
|
|
18
|
+
const type = typeof result;
|
|
19
|
+
|
|
20
|
+
if (type === 'number' && !isNaN(result)) {
|
|
21
|
+
return new Dimension(result);
|
|
22
|
+
} else if (type === 'string') {
|
|
23
|
+
return new Quoted(`"${result}"`, result, this.escaped, this._index);
|
|
24
|
+
} else if (Array.isArray(result)) {
|
|
25
|
+
return new Anonymous(result.join(', '));
|
|
26
|
+
} else {
|
|
27
|
+
return new Anonymous(result);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
JavaScript.prototype.type = 'JavaScript';
|
|
33
|
+
export default JavaScript;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
import Variable from './variable';
|
|
3
|
+
|
|
4
|
+
class JsEvalNode extends Node {
|
|
5
|
+
evaluateJavaScript(expression, context) {
|
|
6
|
+
let result;
|
|
7
|
+
const that = this;
|
|
8
|
+
const evalContext = {};
|
|
9
|
+
|
|
10
|
+
if (!context.javascriptEnabled) {
|
|
11
|
+
throw { message: 'Inline JavaScript is not enabled. Is it set in your options?',
|
|
12
|
+
filename: this.fileInfo().filename,
|
|
13
|
+
index: this.getIndex() };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
expression = expression.replace(/@\{([\w-]+)\}/g, (_, name) => that.jsify(new Variable(`@${name}`, that.getIndex(), that.fileInfo()).eval(context)));
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
expression = new Function(`return (${expression})`);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
throw { message: `JavaScript evaluation error: ${e.message} from \`${expression}\`` ,
|
|
22
|
+
filename: this.fileInfo().filename,
|
|
23
|
+
index: this.getIndex() };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const variables = context.frames[0].variables();
|
|
27
|
+
for (const k in variables) {
|
|
28
|
+
if (variables.hasOwnProperty(k)) {
|
|
29
|
+
/* jshint loopfunc:true */
|
|
30
|
+
evalContext[k.slice(1)] = {
|
|
31
|
+
value: variables[k].value,
|
|
32
|
+
toJS: function () {
|
|
33
|
+
return this.value.eval(context).toCSS();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
result = expression.call(evalContext);
|
|
41
|
+
} catch (e) {
|
|
42
|
+
throw { message: `JavaScript evaluation error: '${e.name}: ${e.message.replace(/["]/g, '\'')}'` ,
|
|
43
|
+
filename: this.fileInfo().filename,
|
|
44
|
+
index: this.getIndex() };
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
jsify(obj) {
|
|
50
|
+
if (Array.isArray(obj.value) && (obj.value.length > 1)) {
|
|
51
|
+
return `[${obj.value.map(v => v.toCSS()).join(', ')}]`;
|
|
52
|
+
} else {
|
|
53
|
+
return obj.toCSS();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default JsEvalNode;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
|
|
3
|
+
class Keyword extends Node {
|
|
4
|
+
constructor(value) {
|
|
5
|
+
super();
|
|
6
|
+
|
|
7
|
+
this.value = value;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
genCSS(context, output) {
|
|
11
|
+
if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; }
|
|
12
|
+
output.add(this.value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
Keyword.prototype.type = 'Keyword';
|
|
17
|
+
|
|
18
|
+
Keyword.True = new Keyword('true');
|
|
19
|
+
Keyword.False = new Keyword('false');
|
|
20
|
+
|
|
21
|
+
export default Keyword;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import Ruleset from './ruleset';
|
|
2
|
+
import Value from './value';
|
|
3
|
+
import Selector from './selector';
|
|
4
|
+
import Anonymous from './anonymous';
|
|
5
|
+
import Expression from './expression';
|
|
6
|
+
import AtRule from './atrule';
|
|
7
|
+
import * as utils from '../utils';
|
|
8
|
+
|
|
9
|
+
class Media extends AtRule {
|
|
10
|
+
constructor(value, features, index, currentFileInfo, visibilityInfo) {
|
|
11
|
+
super();
|
|
12
|
+
|
|
13
|
+
this._index = index;
|
|
14
|
+
this._fileInfo = currentFileInfo;
|
|
15
|
+
|
|
16
|
+
const selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors();
|
|
17
|
+
|
|
18
|
+
this.features = new Value(features);
|
|
19
|
+
this.rules = [new Ruleset(selectors, value)];
|
|
20
|
+
this.rules[0].allowImports = true;
|
|
21
|
+
this.copyVisibilityInfo(visibilityInfo);
|
|
22
|
+
this.allowRoot = true;
|
|
23
|
+
this.setParent(selectors, this);
|
|
24
|
+
this.setParent(this.features, this);
|
|
25
|
+
this.setParent(this.rules, this);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
isRulesetLike() {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
accept(visitor) {
|
|
33
|
+
if (this.features) {
|
|
34
|
+
this.features = visitor.visit(this.features);
|
|
35
|
+
}
|
|
36
|
+
if (this.rules) {
|
|
37
|
+
this.rules = visitor.visitArray(this.rules);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
genCSS(context, output) {
|
|
42
|
+
output.add('@media ', this._fileInfo, this._index);
|
|
43
|
+
this.features.genCSS(context, output);
|
|
44
|
+
this.outputRuleset(context, output, this.rules);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
eval(context) {
|
|
48
|
+
if (!context.mediaBlocks) {
|
|
49
|
+
context.mediaBlocks = [];
|
|
50
|
+
context.mediaPath = [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo());
|
|
54
|
+
if (this.debugInfo) {
|
|
55
|
+
this.rules[0].debugInfo = this.debugInfo;
|
|
56
|
+
media.debugInfo = this.debugInfo;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
media.features = this.features.eval(context);
|
|
60
|
+
|
|
61
|
+
context.mediaPath.push(media);
|
|
62
|
+
context.mediaBlocks.push(media);
|
|
63
|
+
|
|
64
|
+
this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit();
|
|
65
|
+
context.frames.unshift(this.rules[0]);
|
|
66
|
+
media.rules = [this.rules[0].eval(context)];
|
|
67
|
+
context.frames.shift();
|
|
68
|
+
|
|
69
|
+
context.mediaPath.pop();
|
|
70
|
+
|
|
71
|
+
return context.mediaPath.length === 0 ? media.evalTop(context) :
|
|
72
|
+
media.evalNested(context);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
evalTop(context) {
|
|
76
|
+
let result = this;
|
|
77
|
+
|
|
78
|
+
// Render all dependent Media blocks.
|
|
79
|
+
if (context.mediaBlocks.length > 1) {
|
|
80
|
+
const selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors();
|
|
81
|
+
result = new Ruleset(selectors, context.mediaBlocks);
|
|
82
|
+
result.multiMedia = true;
|
|
83
|
+
result.copyVisibilityInfo(this.visibilityInfo());
|
|
84
|
+
this.setParent(result, this);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
delete context.mediaBlocks;
|
|
88
|
+
delete context.mediaPath;
|
|
89
|
+
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
evalNested(context) {
|
|
94
|
+
let i;
|
|
95
|
+
let value;
|
|
96
|
+
const path = context.mediaPath.concat([this]);
|
|
97
|
+
|
|
98
|
+
// Extract the media-query conditions separated with `,` (OR).
|
|
99
|
+
for (i = 0; i < path.length; i++) {
|
|
100
|
+
value = path[i].features instanceof Value ?
|
|
101
|
+
path[i].features.value : path[i].features;
|
|
102
|
+
path[i] = Array.isArray(value) ? value : [value];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Trace all permutations to generate the resulting media-query.
|
|
106
|
+
//
|
|
107
|
+
// (a, b and c) with nested (d, e) ->
|
|
108
|
+
// a and d
|
|
109
|
+
// a and e
|
|
110
|
+
// b and c and d
|
|
111
|
+
// b and c and e
|
|
112
|
+
this.features = new Value(this.permute(path).map(path => {
|
|
113
|
+
path = path.map(fragment => fragment.toCSS ? fragment : new Anonymous(fragment));
|
|
114
|
+
|
|
115
|
+
for (i = path.length - 1; i > 0; i--) {
|
|
116
|
+
path.splice(i, 0, new Anonymous('and'));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return new Expression(path);
|
|
120
|
+
}));
|
|
121
|
+
this.setParent(this.features, this);
|
|
122
|
+
|
|
123
|
+
// Fake a tree-node that doesn't output anything.
|
|
124
|
+
return new Ruleset([], []);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
permute(arr) {
|
|
128
|
+
if (arr.length === 0) {
|
|
129
|
+
return [];
|
|
130
|
+
} else if (arr.length === 1) {
|
|
131
|
+
return arr[0];
|
|
132
|
+
} else {
|
|
133
|
+
const result = [];
|
|
134
|
+
const rest = this.permute(arr.slice(1));
|
|
135
|
+
for (let i = 0; i < rest.length; i++) {
|
|
136
|
+
for (let j = 0; j < arr[0].length; j++) {
|
|
137
|
+
result.push([arr[0][j]].concat(rest[i]));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
bubbleSelectors(selectors) {
|
|
145
|
+
if (!selectors) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.rules = [new Ruleset(utils.copyArray(selectors), [this.rules[0]])];
|
|
149
|
+
this.setParent(this.rules, this);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Media.prototype.type = 'Media';
|
|
154
|
+
export default Media;
|