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,165 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
import Selector from './selector';
|
|
3
|
+
import Ruleset from './ruleset';
|
|
4
|
+
import Anonymous from './anonymous';
|
|
5
|
+
|
|
6
|
+
class AtRule extends Node {
|
|
7
|
+
constructor(
|
|
8
|
+
name,
|
|
9
|
+
value,
|
|
10
|
+
rules,
|
|
11
|
+
index,
|
|
12
|
+
currentFileInfo,
|
|
13
|
+
debugInfo,
|
|
14
|
+
isRooted,
|
|
15
|
+
visibilityInfo
|
|
16
|
+
) {
|
|
17
|
+
super();
|
|
18
|
+
|
|
19
|
+
let i;
|
|
20
|
+
|
|
21
|
+
this.name = name;
|
|
22
|
+
this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value);
|
|
23
|
+
if (rules) {
|
|
24
|
+
if (Array.isArray(rules)) {
|
|
25
|
+
this.rules = rules;
|
|
26
|
+
} else {
|
|
27
|
+
this.rules = [rules];
|
|
28
|
+
this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors();
|
|
29
|
+
}
|
|
30
|
+
for (i = 0; i < this.rules.length; i++) {
|
|
31
|
+
this.rules[i].allowImports = true;
|
|
32
|
+
}
|
|
33
|
+
this.setParent(this.rules, this);
|
|
34
|
+
}
|
|
35
|
+
this._index = index;
|
|
36
|
+
this._fileInfo = currentFileInfo;
|
|
37
|
+
this.debugInfo = debugInfo;
|
|
38
|
+
this.isRooted = isRooted || false;
|
|
39
|
+
this.copyVisibilityInfo(visibilityInfo);
|
|
40
|
+
this.allowRoot = true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
accept(visitor) {
|
|
44
|
+
const value = this.value;
|
|
45
|
+
const rules = this.rules;
|
|
46
|
+
if (rules) {
|
|
47
|
+
this.rules = visitor.visitArray(rules);
|
|
48
|
+
}
|
|
49
|
+
if (value) {
|
|
50
|
+
this.value = visitor.visit(value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
isRulesetLike() {
|
|
55
|
+
return this.rules || !this.isCharset();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
isCharset() {
|
|
59
|
+
return '@charset' === this.name;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
genCSS(context, output) {
|
|
63
|
+
const value = this.value;
|
|
64
|
+
const rules = this.rules;
|
|
65
|
+
output.add(this.name, this.fileInfo(), this.getIndex());
|
|
66
|
+
if (value) {
|
|
67
|
+
output.add(' ');
|
|
68
|
+
value.genCSS(context, output);
|
|
69
|
+
}
|
|
70
|
+
if (rules) {
|
|
71
|
+
this.outputRuleset(context, output, rules);
|
|
72
|
+
} else {
|
|
73
|
+
output.add(';');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
eval(context) {
|
|
78
|
+
let mediaPathBackup;
|
|
79
|
+
let mediaBlocksBackup;
|
|
80
|
+
let value = this.value;
|
|
81
|
+
let rules = this.rules;
|
|
82
|
+
|
|
83
|
+
// media stored inside other atrule should not bubble over it
|
|
84
|
+
// backpup media bubbling information
|
|
85
|
+
mediaPathBackup = context.mediaPath;
|
|
86
|
+
mediaBlocksBackup = context.mediaBlocks;
|
|
87
|
+
// deleted media bubbling information
|
|
88
|
+
context.mediaPath = [];
|
|
89
|
+
context.mediaBlocks = [];
|
|
90
|
+
|
|
91
|
+
if (value) {
|
|
92
|
+
value = value.eval(context);
|
|
93
|
+
}
|
|
94
|
+
if (rules) {
|
|
95
|
+
// assuming that there is only one rule at this point - that is how parser constructs the rule
|
|
96
|
+
rules = [rules[0].eval(context)];
|
|
97
|
+
rules[0].root = true;
|
|
98
|
+
}
|
|
99
|
+
// restore media bubbling information
|
|
100
|
+
context.mediaPath = mediaPathBackup;
|
|
101
|
+
context.mediaBlocks = mediaBlocksBackup;
|
|
102
|
+
|
|
103
|
+
return new AtRule(this.name, value, rules,
|
|
104
|
+
this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
variable(name) {
|
|
108
|
+
if (this.rules) {
|
|
109
|
+
// assuming that there is only one rule at this point - that is how parser constructs the rule
|
|
110
|
+
return Ruleset.prototype.variable.call(this.rules[0], name);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
find(...args) {
|
|
115
|
+
if (this.rules) {
|
|
116
|
+
// assuming that there is only one rule at this point - that is how parser constructs the rule
|
|
117
|
+
return Ruleset.prototype.find.apply(this.rules[0], args);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
rulesets() {
|
|
122
|
+
if (this.rules) {
|
|
123
|
+
// assuming that there is only one rule at this point - that is how parser constructs the rule
|
|
124
|
+
return Ruleset.prototype.rulesets.apply(this.rules[0]);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
outputRuleset(context, output, rules) {
|
|
129
|
+
const ruleCnt = rules.length;
|
|
130
|
+
let i;
|
|
131
|
+
context.tabLevel = (context.tabLevel | 0) + 1;
|
|
132
|
+
|
|
133
|
+
// Compressed
|
|
134
|
+
if (context.compress) {
|
|
135
|
+
output.add('{');
|
|
136
|
+
for (i = 0; i < ruleCnt; i++) {
|
|
137
|
+
rules[i].genCSS(context, output);
|
|
138
|
+
}
|
|
139
|
+
output.add('}');
|
|
140
|
+
context.tabLevel--;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Non-compressed
|
|
145
|
+
const tabSetStr = `\n${Array(context.tabLevel).join(' ')}`;
|
|
146
|
+
|
|
147
|
+
const tabRuleStr = `${tabSetStr} `;
|
|
148
|
+
if (!ruleCnt) {
|
|
149
|
+
output.add(` {${tabSetStr}}`);
|
|
150
|
+
} else {
|
|
151
|
+
output.add(` {${tabRuleStr}`);
|
|
152
|
+
rules[0].genCSS(context, output);
|
|
153
|
+
for (i = 1; i < ruleCnt; i++) {
|
|
154
|
+
output.add(tabRuleStr);
|
|
155
|
+
rules[i].genCSS(context, output);
|
|
156
|
+
}
|
|
157
|
+
output.add(`${tabSetStr}}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
context.tabLevel--;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
AtRule.prototype.type = 'AtRule';
|
|
165
|
+
export default AtRule;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
|
|
3
|
+
class Attribute extends Node {
|
|
4
|
+
constructor(key, op, value) {
|
|
5
|
+
super();
|
|
6
|
+
|
|
7
|
+
this.key = key;
|
|
8
|
+
this.op = op;
|
|
9
|
+
this.value = value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
eval(context) {
|
|
13
|
+
return new Attribute(this.key.eval ? this.key.eval(context) : this.key,
|
|
14
|
+
this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
genCSS(context, output) {
|
|
18
|
+
output.add(this.toCSS(context));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
toCSS(context) {
|
|
22
|
+
let value = this.key.toCSS ? this.key.toCSS(context) : this.key;
|
|
23
|
+
|
|
24
|
+
if (this.op) {
|
|
25
|
+
value += this.op;
|
|
26
|
+
value += (this.value.toCSS ? this.value.toCSS(context) : this.value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return `[${value}]`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Attribute.prototype.type = 'Attribute';
|
|
34
|
+
export default Attribute;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
import Anonymous from './anonymous';
|
|
3
|
+
import FunctionCaller from '../functions/function-caller';
|
|
4
|
+
|
|
5
|
+
//
|
|
6
|
+
// A function call node.
|
|
7
|
+
//
|
|
8
|
+
class Call extends Node {
|
|
9
|
+
constructor(name, args, index, currentFileInfo) {
|
|
10
|
+
super();
|
|
11
|
+
|
|
12
|
+
this.name = name;
|
|
13
|
+
this.args = args;
|
|
14
|
+
this.calc = name === 'calc';
|
|
15
|
+
this._index = index;
|
|
16
|
+
this._fileInfo = currentFileInfo;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
accept(visitor) {
|
|
20
|
+
if (this.args) {
|
|
21
|
+
this.args = visitor.visitArray(this.args);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//
|
|
26
|
+
// When evaluating a function call,
|
|
27
|
+
// we either find the function in the functionRegistry,
|
|
28
|
+
// in which case we call it, passing the evaluated arguments,
|
|
29
|
+
// if this returns null or we cannot find the function, we
|
|
30
|
+
// simply print it out as it appeared originally [2].
|
|
31
|
+
//
|
|
32
|
+
// The reason why we evaluate the arguments, is in the case where
|
|
33
|
+
// we try to pass a variable to a function, like: `saturate(@color)`.
|
|
34
|
+
// The function should receive the value, not the variable.
|
|
35
|
+
//
|
|
36
|
+
eval(context) {
|
|
37
|
+
/**
|
|
38
|
+
* Turn off math for calc(), and switch back on for evaluating nested functions
|
|
39
|
+
*/
|
|
40
|
+
const currentMathContext = context.mathOn;
|
|
41
|
+
context.mathOn = !this.calc;
|
|
42
|
+
if (this.calc || context.inCalc) {
|
|
43
|
+
context.enterCalc();
|
|
44
|
+
}
|
|
45
|
+
const args = this.args.map(a => a.eval(context));
|
|
46
|
+
if (this.calc || context.inCalc) {
|
|
47
|
+
context.exitCalc();
|
|
48
|
+
}
|
|
49
|
+
context.mathOn = currentMathContext;
|
|
50
|
+
|
|
51
|
+
let result;
|
|
52
|
+
const funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
|
|
53
|
+
|
|
54
|
+
if (funcCaller.isValid()) {
|
|
55
|
+
try {
|
|
56
|
+
result = funcCaller.call(args);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
throw {
|
|
59
|
+
type: e.type || 'Runtime',
|
|
60
|
+
message: `error evaluating function \`${this.name}\`${e.message ? `: ${e.message}` : ''}`,
|
|
61
|
+
index: this.getIndex(),
|
|
62
|
+
filename: this.fileInfo().filename,
|
|
63
|
+
line: e.lineNumber,
|
|
64
|
+
column: e.columnNumber
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (result !== null && result !== undefined) {
|
|
69
|
+
// Results that that are not nodes are cast as Anonymous nodes
|
|
70
|
+
// Falsy values or booleans are returned as empty nodes
|
|
71
|
+
if (!(result instanceof Node)) {
|
|
72
|
+
if (!result || result === true) {
|
|
73
|
+
result = new Anonymous(null);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
result = new Anonymous(result.toString());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
result._index = this._index;
|
|
81
|
+
result._fileInfo = this._fileInfo;
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return new Call(this.name, args, this.getIndex(), this.fileInfo());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
genCSS(context, output) {
|
|
91
|
+
output.add(`${this.name}(`, this.fileInfo(), this.getIndex());
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < this.args.length; i++) {
|
|
94
|
+
this.args[i].genCSS(context, output);
|
|
95
|
+
if (i + 1 < this.args.length) {
|
|
96
|
+
output.add(', ');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
output.add(')');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
Call.prototype.type = 'Call';
|
|
105
|
+
export default Call;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
import colors from '../data/colors';
|
|
3
|
+
|
|
4
|
+
//
|
|
5
|
+
// RGB Colors - #ff0014, #eee
|
|
6
|
+
//
|
|
7
|
+
class Color extends Node {
|
|
8
|
+
constructor(rgb, a, originalForm) {
|
|
9
|
+
super();
|
|
10
|
+
|
|
11
|
+
const self = this;
|
|
12
|
+
//
|
|
13
|
+
// The end goal here, is to parse the arguments
|
|
14
|
+
// into an integer triplet, such as `128, 255, 0`
|
|
15
|
+
//
|
|
16
|
+
// This facilitates operations and conversions.
|
|
17
|
+
//
|
|
18
|
+
if (Array.isArray(rgb)) {
|
|
19
|
+
this.rgb = rgb;
|
|
20
|
+
} else if (rgb.length >= 6) {
|
|
21
|
+
this.rgb = [];
|
|
22
|
+
rgb.match(/.{2}/g).map((c, i) => {
|
|
23
|
+
if (i < 3) {
|
|
24
|
+
self.rgb.push(parseInt(c, 16));
|
|
25
|
+
} else {
|
|
26
|
+
self.alpha = (parseInt(c, 16)) / 255;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
this.rgb = [];
|
|
31
|
+
rgb.split('').map((c, i) => {
|
|
32
|
+
if (i < 3) {
|
|
33
|
+
self.rgb.push(parseInt(c + c, 16));
|
|
34
|
+
} else {
|
|
35
|
+
self.alpha = (parseInt(c + c, 16)) / 255;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
this.alpha = this.alpha || (typeof a === 'number' ? a : 1);
|
|
40
|
+
if (typeof originalForm !== 'undefined') {
|
|
41
|
+
this.value = originalForm;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
luma() {
|
|
46
|
+
let r = this.rgb[0] / 255;
|
|
47
|
+
let g = this.rgb[1] / 255;
|
|
48
|
+
let b = this.rgb[2] / 255;
|
|
49
|
+
|
|
50
|
+
r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
|
|
51
|
+
g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
|
|
52
|
+
b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
|
|
53
|
+
|
|
54
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
genCSS(context, output) {
|
|
58
|
+
output.add(this.toCSS(context));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
toCSS(context, doNotCompress) {
|
|
62
|
+
const compress = context && context.compress && !doNotCompress;
|
|
63
|
+
let color;
|
|
64
|
+
let alpha;
|
|
65
|
+
let colorFunction;
|
|
66
|
+
let args = [];
|
|
67
|
+
|
|
68
|
+
// `value` is set if this color was originally
|
|
69
|
+
// converted from a named color string so we need
|
|
70
|
+
// to respect this and try to output named color too.
|
|
71
|
+
alpha = this.fround(context, this.alpha);
|
|
72
|
+
|
|
73
|
+
if (this.value) {
|
|
74
|
+
if (this.value.indexOf('rgb') === 0) {
|
|
75
|
+
if (alpha < 1) {
|
|
76
|
+
colorFunction = 'rgba';
|
|
77
|
+
}
|
|
78
|
+
} else if (this.value.indexOf('hsl') === 0) {
|
|
79
|
+
if (alpha < 1) {
|
|
80
|
+
colorFunction = 'hsla';
|
|
81
|
+
} else {
|
|
82
|
+
colorFunction = 'hsl';
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
return this.value;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
if (alpha < 1) {
|
|
89
|
+
colorFunction = 'rgba';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
switch (colorFunction) {
|
|
94
|
+
case 'rgba':
|
|
95
|
+
args = this.rgb.map(c => clamp(Math.round(c), 255)).concat(clamp(alpha, 1));
|
|
96
|
+
break;
|
|
97
|
+
case 'hsla':
|
|
98
|
+
args.push(clamp(alpha, 1));
|
|
99
|
+
case 'hsl':
|
|
100
|
+
color = this.toHSL();
|
|
101
|
+
args = [
|
|
102
|
+
this.fround(context, color.h),
|
|
103
|
+
`${this.fround(context, color.s * 100)}%`,
|
|
104
|
+
`${this.fround(context, color.l * 100)}%`
|
|
105
|
+
].concat(args);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (colorFunction) {
|
|
109
|
+
// Values are capped between `0` and `255`, rounded and zero-padded.
|
|
110
|
+
return `${colorFunction}(${args.join(`,${compress ? '' : ' '}`)})`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
color = this.toRGB();
|
|
114
|
+
|
|
115
|
+
if (compress) {
|
|
116
|
+
const splitcolor = color.split('');
|
|
117
|
+
|
|
118
|
+
// Convert color to short format
|
|
119
|
+
if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {
|
|
120
|
+
color = `#${splitcolor[1]}${splitcolor[3]}${splitcolor[5]}`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return color;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
//
|
|
128
|
+
// Operations have to be done per-channel, if not,
|
|
129
|
+
// channels will spill onto each other. Once we have
|
|
130
|
+
// our result, in the form of an integer triplet,
|
|
131
|
+
// we create a new Color node to hold the result.
|
|
132
|
+
//
|
|
133
|
+
operate(context, op, other) {
|
|
134
|
+
const rgb = new Array(3);
|
|
135
|
+
const alpha = this.alpha * (1 - other.alpha) + other.alpha;
|
|
136
|
+
for (let c = 0; c < 3; c++) {
|
|
137
|
+
rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]);
|
|
138
|
+
}
|
|
139
|
+
return new Color(rgb, alpha);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
toRGB() {
|
|
143
|
+
return toHex(this.rgb);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
toHSL() {
|
|
147
|
+
const r = this.rgb[0] / 255;
|
|
148
|
+
const g = this.rgb[1] / 255;
|
|
149
|
+
const b = this.rgb[2] / 255;
|
|
150
|
+
const a = this.alpha;
|
|
151
|
+
const max = Math.max(r, g, b);
|
|
152
|
+
const min = Math.min(r, g, b);
|
|
153
|
+
let h;
|
|
154
|
+
let s;
|
|
155
|
+
const l = (max + min) / 2;
|
|
156
|
+
const d = max - min;
|
|
157
|
+
|
|
158
|
+
if (max === min) {
|
|
159
|
+
h = s = 0;
|
|
160
|
+
} else {
|
|
161
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
162
|
+
|
|
163
|
+
switch (max) {
|
|
164
|
+
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
|
165
|
+
case g: h = (b - r) / d + 2; break;
|
|
166
|
+
case b: h = (r - g) / d + 4; break;
|
|
167
|
+
}
|
|
168
|
+
h /= 6;
|
|
169
|
+
}
|
|
170
|
+
return { h: h * 360, s, l, a };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
|
|
174
|
+
toHSV() {
|
|
175
|
+
const r = this.rgb[0] / 255;
|
|
176
|
+
const g = this.rgb[1] / 255;
|
|
177
|
+
const b = this.rgb[2] / 255;
|
|
178
|
+
const a = this.alpha;
|
|
179
|
+
const max = Math.max(r, g, b);
|
|
180
|
+
const min = Math.min(r, g, b);
|
|
181
|
+
let h;
|
|
182
|
+
let s;
|
|
183
|
+
const v = max;
|
|
184
|
+
|
|
185
|
+
const d = max - min;
|
|
186
|
+
if (max === 0) {
|
|
187
|
+
s = 0;
|
|
188
|
+
} else {
|
|
189
|
+
s = d / max;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (max === min) {
|
|
193
|
+
h = 0;
|
|
194
|
+
} else {
|
|
195
|
+
switch (max) {
|
|
196
|
+
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
|
197
|
+
case g: h = (b - r) / d + 2; break;
|
|
198
|
+
case b: h = (r - g) / d + 4; break;
|
|
199
|
+
}
|
|
200
|
+
h /= 6;
|
|
201
|
+
}
|
|
202
|
+
return { h: h * 360, s, v, a };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
toARGB() {
|
|
206
|
+
return toHex([this.alpha * 255].concat(this.rgb));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
compare(x) {
|
|
210
|
+
return (x.rgb &&
|
|
211
|
+
x.rgb[0] === this.rgb[0] &&
|
|
212
|
+
x.rgb[1] === this.rgb[1] &&
|
|
213
|
+
x.rgb[2] === this.rgb[2] &&
|
|
214
|
+
x.alpha === this.alpha) ? 0 : undefined;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
Color.prototype.type = 'Color';
|
|
219
|
+
|
|
220
|
+
function clamp(v, max) {
|
|
221
|
+
return Math.min(Math.max(v, 0), max);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function toHex(v) {
|
|
225
|
+
return `#${v.map(c => {
|
|
226
|
+
c = clamp(Math.round(c), 255);
|
|
227
|
+
return (c < 16 ? '0' : '') + c.toString(16);
|
|
228
|
+
}).join('')}`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
Color.fromKeyword = keyword => {
|
|
232
|
+
let c;
|
|
233
|
+
const key = keyword.toLowerCase();
|
|
234
|
+
if (colors.hasOwnProperty(key)) {
|
|
235
|
+
c = new Color(colors[key].slice(1));
|
|
236
|
+
}
|
|
237
|
+
else if (key === 'transparent') {
|
|
238
|
+
c = new Color([0, 0, 0], 0);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (c) {
|
|
242
|
+
c.value = keyword;
|
|
243
|
+
return c;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
export default Color;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
const _noSpaceCombinators = {
|
|
3
|
+
'': true,
|
|
4
|
+
' ': true,
|
|
5
|
+
'|': true
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
class Combinator extends Node {
|
|
9
|
+
constructor(value) {
|
|
10
|
+
super();
|
|
11
|
+
|
|
12
|
+
if (value === ' ') {
|
|
13
|
+
this.value = ' ';
|
|
14
|
+
this.emptyOrWhitespace = true;
|
|
15
|
+
} else {
|
|
16
|
+
this.value = value ? value.trim() : '';
|
|
17
|
+
this.emptyOrWhitespace = this.value === '';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
genCSS(context, output) {
|
|
22
|
+
const spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' ';
|
|
23
|
+
output.add(spaceOrEmpty + this.value + spaceOrEmpty);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Combinator.prototype.type = 'Combinator';
|
|
28
|
+
|
|
29
|
+
export default Combinator;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
import getDebugInfo from './debug-info';
|
|
3
|
+
|
|
4
|
+
class Comment extends Node {
|
|
5
|
+
constructor(value, isLineComment, index, currentFileInfo) {
|
|
6
|
+
super();
|
|
7
|
+
|
|
8
|
+
this.value = value;
|
|
9
|
+
this.isLineComment = isLineComment;
|
|
10
|
+
this._index = index;
|
|
11
|
+
this._fileInfo = currentFileInfo;
|
|
12
|
+
this.allowRoot = true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
genCSS(context, output) {
|
|
16
|
+
if (this.debugInfo) {
|
|
17
|
+
output.add(getDebugInfo(context, this), this.fileInfo(), this.getIndex());
|
|
18
|
+
}
|
|
19
|
+
output.add(this.value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
isSilent(context) {
|
|
23
|
+
const isCompressed = context.compress && this.value[2] !== '!';
|
|
24
|
+
return this.isLineComment || isCompressed;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Comment.prototype.type = 'Comment';
|
|
29
|
+
export default Comment;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Node from './node';
|
|
2
|
+
|
|
3
|
+
class Condition extends Node {
|
|
4
|
+
constructor(op, l, r, i, negate) {
|
|
5
|
+
super();
|
|
6
|
+
|
|
7
|
+
this.op = op.trim();
|
|
8
|
+
this.lvalue = l;
|
|
9
|
+
this.rvalue = r;
|
|
10
|
+
this._index = i;
|
|
11
|
+
this.negate = negate;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
accept(visitor) {
|
|
15
|
+
this.lvalue = visitor.visit(this.lvalue);
|
|
16
|
+
this.rvalue = visitor.visit(this.rvalue);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
eval(context) {
|
|
20
|
+
const result = ((op, a, b) => {
|
|
21
|
+
switch (op) {
|
|
22
|
+
case 'and': return a && b;
|
|
23
|
+
case 'or': return a || b;
|
|
24
|
+
default:
|
|
25
|
+
switch (Node.compare(a, b)) {
|
|
26
|
+
case -1:
|
|
27
|
+
return op === '<' || op === '=<' || op === '<=';
|
|
28
|
+
case 0:
|
|
29
|
+
return op === '=' || op === '>=' || op === '=<' || op === '<=';
|
|
30
|
+
case 1:
|
|
31
|
+
return op === '>' || op === '>=';
|
|
32
|
+
default:
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
})(this.op, this.lvalue.eval(context), this.rvalue.eval(context));
|
|
37
|
+
|
|
38
|
+
return this.negate ? !result : result;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Condition.prototype.type = 'Condition';
|
|
43
|
+
export default Condition;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const debugInfo = (context, ctx, lineSeparator) => {
|
|
2
|
+
let result = '';
|
|
3
|
+
if (context.dumpLineNumbers && !context.compress) {
|
|
4
|
+
switch (context.dumpLineNumbers) {
|
|
5
|
+
case 'comments':
|
|
6
|
+
result = debugInfo.asComment(ctx);
|
|
7
|
+
break;
|
|
8
|
+
case 'mediaquery':
|
|
9
|
+
result = debugInfo.asMediaQuery(ctx);
|
|
10
|
+
break;
|
|
11
|
+
case 'all':
|
|
12
|
+
result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx);
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
debugInfo.asComment = ctx => `/* line ${ctx.debugInfo.lineNumber}, ${ctx.debugInfo.fileName} */\n`;
|
|
20
|
+
|
|
21
|
+
debugInfo.asMediaQuery = ctx => {
|
|
22
|
+
let filenameWithProtocol = ctx.debugInfo.fileName;
|
|
23
|
+
if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) {
|
|
24
|
+
filenameWithProtocol = `file://${filenameWithProtocol}`;
|
|
25
|
+
}
|
|
26
|
+
return `@media -sass-debug-info{filename{font-family:${filenameWithProtocol.replace(/([.:\/\\])/g, a => {
|
|
27
|
+
if (a == '\\') {
|
|
28
|
+
a = '\/';
|
|
29
|
+
}
|
|
30
|
+
return `\\${a}`;
|
|
31
|
+
})}}line{font-family:\\00003${ctx.debugInfo.lineNumber}}}\n`;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default debugInfo;
|