less 4.9.0 → 5.0.0-alpha.1
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/README.md +19 -5
- package/bin/lessc +190 -630
- package/dist/less-node.cjs +399 -14570
- package/index.cjs +5 -2
- package/lib/index.js +164 -0
- package/lib/lessc-helper.js +52 -0
- package/lib/logger.js +76 -0
- package/lib/options.d.ts +46 -0
- package/lib/options.js +145 -0
- package/lib/types.js +20 -0
- package/lib/version.js +19 -0
- package/package.json +34 -40
- package/dist/less.cjs +0 -15215
- package/dist/less.js +0 -15215
- package/dist/less.min.js +0 -11
- package/dist/less.min.js.map +0 -1
- package/lib/less/constants.js +0 -13
- package/lib/less/contexts.js +0 -165
- package/lib/less/data/colors.js +0 -150
- package/lib/less/data/index.js +0 -4
- package/lib/less/data/unit-conversions.js +0 -21
- package/lib/less/default-options.js +0 -89
- package/lib/less/deprecation.js +0 -82
- package/lib/less/environment/abstract-file-manager.js +0 -140
- package/lib/less/environment/abstract-plugin-loader.js +0 -185
- package/lib/less/environment/environment-api.ts +0 -21
- package/lib/less/environment/environment.js +0 -59
- package/lib/less/environment/file-manager-api.ts +0 -77
- package/lib/less/functions/boolean.js +0 -29
- package/lib/less/functions/color-blending.js +0 -85
- package/lib/less/functions/color.js +0 -452
- package/lib/less/functions/data-uri.js +0 -74
- package/lib/less/functions/default.js +0 -26
- package/lib/less/functions/function-caller.js +0 -55
- package/lib/less/functions/function-registry.js +0 -36
- package/lib/less/functions/index.js +0 -35
- package/lib/less/functions/list.js +0 -158
- package/lib/less/functions/math-helper.js +0 -22
- package/lib/less/functions/math.js +0 -30
- package/lib/less/functions/number.js +0 -95
- package/lib/less/functions/string.js +0 -39
- package/lib/less/functions/style.js +0 -29
- package/lib/less/functions/svg.js +0 -87
- package/lib/less/functions/types.js +0 -70
- package/lib/less/import-manager.js +0 -183
- package/lib/less/index.js +0 -95
- package/lib/less/less-error.js +0 -166
- package/lib/less/logger.js +0 -34
- package/lib/less/parse-tree.js +0 -124
- package/lib/less/parse.js +0 -87
- package/lib/less/parser/lookup-pattern.js +0 -26
- package/lib/less/parser/parser-input.js +0 -400
- package/lib/less/parser/parser.js +0 -2998
- package/lib/less/plugin-manager.js +0 -168
- package/lib/less/render.js +0 -41
- package/lib/less/source-map-builder.js +0 -82
- package/lib/less/source-map-output.js +0 -151
- package/lib/less/transform-tree.js +0 -102
- package/lib/less/tree/anonymous.js +0 -61
- package/lib/less/tree/assignment.js +0 -48
- package/lib/less/tree/atrule-syntax.js +0 -8
- package/lib/less/tree/atrule.js +0 -340
- package/lib/less/tree/attribute.js +0 -63
- package/lib/less/tree/call.js +0 -132
- package/lib/less/tree/color.js +0 -285
- package/lib/less/tree/combinator.js +0 -38
- package/lib/less/tree/comment.js +0 -48
- package/lib/less/tree/condition.js +0 -65
- package/lib/less/tree/container.js +0 -104
- package/lib/less/tree/debug-info.js +0 -80
- package/lib/less/tree/declaration.js +0 -139
- package/lib/less/tree/detached-ruleset.js +0 -45
- package/lib/less/tree/dimension.js +0 -215
- package/lib/less/tree/element.js +0 -93
- package/lib/less/tree/expression.js +0 -100
- package/lib/less/tree/extend.js +0 -88
- package/lib/less/tree/import.js +0 -299
- package/lib/less/tree/index.js +0 -56
- package/lib/less/tree/interpolated-variable.js +0 -106
- package/lib/less/tree/javascript.js +0 -45
- package/lib/less/tree/js-eval-node.js +0 -80
- package/lib/less/tree/keyword.js +0 -28
- package/lib/less/tree/media.js +0 -90
- package/lib/less/tree/merge-rules.js +0 -47
- package/lib/less/tree/mixin-call.js +0 -283
- package/lib/less/tree/mixin-definition.js +0 -319
- package/lib/less/tree/namespace-value.js +0 -95
- package/lib/less/tree/negative.js +0 -37
- package/lib/less/tree/nested-at-rule.js +0 -239
- package/lib/less/tree/node.js +0 -310
- package/lib/less/tree/operation.js +0 -81
- package/lib/less/tree/paren.js +0 -41
- package/lib/less/tree/property.js +0 -96
- package/lib/less/tree/query-in-parens.js +0 -64
- package/lib/less/tree/quoted.js +0 -131
- package/lib/less/tree/ruleset.js +0 -1068
- package/lib/less/tree/selector.js +0 -201
- package/lib/less/tree/unicode-descriptor.js +0 -14
- package/lib/less/tree/unit.js +0 -170
- package/lib/less/tree/url.js +0 -83
- package/lib/less/tree/value.js +0 -60
- package/lib/less/tree/variable-call.js +0 -60
- package/lib/less/tree/variable.js +0 -85
- package/lib/less/utils.js +0 -126
- package/lib/less/visitors/extend-visitor.js +0 -505
- package/lib/less/visitors/import-sequencer.js +0 -56
- package/lib/less/visitors/import-visitor.js +0 -203
- package/lib/less/visitors/index.js +0 -15
- package/lib/less/visitors/join-selector-visitor.js +0 -65
- package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
- package/lib/less/visitors/to-css-visitor.js +0 -332
- package/lib/less/visitors/visitor.js +0 -165
- package/lib/less-browser/add-default-options.js +0 -53
- package/lib/less-browser/bootstrap.js +0 -67
- package/lib/less-browser/browser.js +0 -65
- package/lib/less-browser/cache.js +0 -43
- package/lib/less-browser/error-reporting.js +0 -170
- package/lib/less-browser/file-manager.js +0 -112
- package/lib/less-browser/image-size.js +0 -28
- package/lib/less-browser/index.js +0 -284
- package/lib/less-browser/log-listener.js +0 -42
- package/lib/less-browser/plugin-loader.js +0 -24
- package/lib/less-browser/utils.js +0 -30
- package/lib/less-node/environment.js +0 -43
- package/lib/less-node/file-manager.js +0 -156
- package/lib/less-node/fs.js +0 -14
- package/lib/less-node/image-size.js +0 -78
- package/lib/less-node/index.js +0 -31
- package/lib/less-node/lessc-helper.js +0 -95
- package/lib/less-node/plugin-loader.js +0 -62
- package/lib/less-node/url-file-manager.js +0 -60
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-unused-vars */
|
|
2
|
-
/**
|
|
3
|
-
* @todo - Remove unused when JSDoc types are added for visitor methods
|
|
4
|
-
*/
|
|
5
|
-
import contexts from '../contexts.js';
|
|
6
|
-
import Visitor from './visitor.js';
|
|
7
|
-
import ImportSequencer from './import-sequencer.js';
|
|
8
|
-
import * as utils from '../utils.js';
|
|
9
|
-
|
|
10
|
-
const ImportVisitor = function(importer, finish) {
|
|
11
|
-
|
|
12
|
-
this._visitor = new Visitor(this);
|
|
13
|
-
this._importer = importer;
|
|
14
|
-
this._finish = finish;
|
|
15
|
-
this.context = new contexts.Eval();
|
|
16
|
-
this.importCount = 0;
|
|
17
|
-
this.onceFileDetectionMap = {};
|
|
18
|
-
this.recursionDetector = {};
|
|
19
|
-
this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this));
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
ImportVisitor.prototype = {
|
|
23
|
-
isReplacing: false,
|
|
24
|
-
run: function (root) {
|
|
25
|
-
try {
|
|
26
|
-
// process the contents
|
|
27
|
-
this._visitor.visit(root);
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
this.error = e;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
this.isFinished = true;
|
|
34
|
-
this._sequencer.tryRun();
|
|
35
|
-
},
|
|
36
|
-
_onSequencerEmpty: function() {
|
|
37
|
-
if (!this.isFinished) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
this._finish(this.error);
|
|
41
|
-
},
|
|
42
|
-
visitImport: function (importNode, visitArgs) {
|
|
43
|
-
const inlineCSS = importNode.options.inline;
|
|
44
|
-
|
|
45
|
-
if (!importNode.css || inlineCSS) {
|
|
46
|
-
|
|
47
|
-
const context = new contexts.Eval(this.context, utils.copyArray(this.context.frames));
|
|
48
|
-
const importParent = context.frames[0];
|
|
49
|
-
|
|
50
|
-
this.importCount++;
|
|
51
|
-
if (importNode.isVariableImport()) {
|
|
52
|
-
this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent));
|
|
53
|
-
} else {
|
|
54
|
-
this.processImportNode(importNode, context, importParent);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
visitArgs.visitDeeper = false;
|
|
58
|
-
},
|
|
59
|
-
processImportNode: function(importNode, context, importParent) {
|
|
60
|
-
let evaldImportNode;
|
|
61
|
-
const inlineCSS = importNode.options.inline;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
evaldImportNode = importNode.evalForImport(context);
|
|
65
|
-
} catch (e) {
|
|
66
|
-
if (!e.filename) { e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename; }
|
|
67
|
-
// attempt to eval properly and treat as css
|
|
68
|
-
importNode.css = true;
|
|
69
|
-
// if that fails, this error will be thrown
|
|
70
|
-
importNode.error = e;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
|
|
74
|
-
|
|
75
|
-
if (evaldImportNode.options.multiple) {
|
|
76
|
-
context.importMultiple = true;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// try appending if we haven't determined if it is css or not
|
|
80
|
-
const tryAppendLessExtension = evaldImportNode.css === undefined;
|
|
81
|
-
|
|
82
|
-
for (let i = 0; i < importParent.rules.length; i++) {
|
|
83
|
-
if (importParent.rules[i] === importNode) {
|
|
84
|
-
importParent.rules[i] = evaldImportNode;
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const onImported = this.onImported.bind(this, evaldImportNode, context), sequencedOnImported = this._sequencer.addImport(onImported);
|
|
90
|
-
|
|
91
|
-
this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(),
|
|
92
|
-
evaldImportNode.options, sequencedOnImported);
|
|
93
|
-
} else {
|
|
94
|
-
this.importCount--;
|
|
95
|
-
if (this.isFinished) {
|
|
96
|
-
this._sequencer.tryRun();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {
|
|
101
|
-
if (e) {
|
|
102
|
-
if (!e.filename) {
|
|
103
|
-
e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename;
|
|
104
|
-
}
|
|
105
|
-
this.error = e;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const importVisitor = this,
|
|
109
|
-
inlineCSS = importNode.options.inline,
|
|
110
|
-
isPlugin = importNode.options.isPlugin,
|
|
111
|
-
isOptional = importNode.options.optional,
|
|
112
|
-
duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;
|
|
113
|
-
|
|
114
|
-
if (!context.importMultiple) {
|
|
115
|
-
if (duplicateImport) {
|
|
116
|
-
importNode.skip = true;
|
|
117
|
-
} else {
|
|
118
|
-
importNode.skip = function() {
|
|
119
|
-
if (fullPath in importVisitor.onceFileDetectionMap) {
|
|
120
|
-
return true;
|
|
121
|
-
}
|
|
122
|
-
importVisitor.onceFileDetectionMap[fullPath] = true;
|
|
123
|
-
return false;
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (!fullPath && isOptional) {
|
|
129
|
-
importNode.skip = true;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (root) {
|
|
133
|
-
importNode.root = root;
|
|
134
|
-
importNode.importedFilename = fullPath;
|
|
135
|
-
|
|
136
|
-
if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) {
|
|
137
|
-
importVisitor.recursionDetector[fullPath] = true;
|
|
138
|
-
|
|
139
|
-
const oldContext = this.context;
|
|
140
|
-
this.context = context;
|
|
141
|
-
try {
|
|
142
|
-
this._visitor.visit(root);
|
|
143
|
-
} catch (e) {
|
|
144
|
-
this.error = e;
|
|
145
|
-
}
|
|
146
|
-
this.context = oldContext;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
importVisitor.importCount--;
|
|
151
|
-
|
|
152
|
-
if (importVisitor.isFinished) {
|
|
153
|
-
importVisitor._sequencer.tryRun();
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
visitDeclaration: function (declNode, visitArgs) {
|
|
157
|
-
if (declNode.value.type === 'DetachedRuleset') {
|
|
158
|
-
this.context.frames.unshift(declNode);
|
|
159
|
-
} else {
|
|
160
|
-
visitArgs.visitDeeper = false;
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
visitDeclarationOut: function(declNode) {
|
|
164
|
-
if (declNode.value.type === 'DetachedRuleset') {
|
|
165
|
-
this.context.frames.shift();
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
visitAtRule: function (atRuleNode, visitArgs) {
|
|
169
|
-
if (atRuleNode.value) {
|
|
170
|
-
this.context.frames.unshift(atRuleNode);
|
|
171
|
-
} else if (atRuleNode.declarations && atRuleNode.declarations.length) {
|
|
172
|
-
if (atRuleNode.isRooted) {
|
|
173
|
-
this.context.frames.unshift(atRuleNode);
|
|
174
|
-
} else {
|
|
175
|
-
this.context.frames.unshift(atRuleNode.declarations[0]);
|
|
176
|
-
}
|
|
177
|
-
} else if (atRuleNode.rules && atRuleNode.rules.length) {
|
|
178
|
-
this.context.frames.unshift(atRuleNode);
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
visitAtRuleOut: function (atRuleNode) {
|
|
182
|
-
this.context.frames.shift();
|
|
183
|
-
},
|
|
184
|
-
visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
|
|
185
|
-
this.context.frames.unshift(mixinDefinitionNode);
|
|
186
|
-
},
|
|
187
|
-
visitMixinDefinitionOut: function (mixinDefinitionNode) {
|
|
188
|
-
this.context.frames.shift();
|
|
189
|
-
},
|
|
190
|
-
visitRuleset: function (rulesetNode, visitArgs) {
|
|
191
|
-
this.context.frames.unshift(rulesetNode);
|
|
192
|
-
},
|
|
193
|
-
visitRulesetOut: function (rulesetNode) {
|
|
194
|
-
this.context.frames.shift();
|
|
195
|
-
},
|
|
196
|
-
visitMedia: function (mediaNode, visitArgs) {
|
|
197
|
-
this.context.frames.unshift(mediaNode.rules[0]);
|
|
198
|
-
},
|
|
199
|
-
visitMediaOut: function (mediaNode) {
|
|
200
|
-
this.context.frames.shift();
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
export default ImportVisitor;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import Visitor from './visitor.js';
|
|
2
|
-
import ImportVisitor from './import-visitor.js';
|
|
3
|
-
import MarkVisibleSelectorsVisitor from './set-tree-visibility-visitor.js';
|
|
4
|
-
import ExtendVisitor from './extend-visitor.js';
|
|
5
|
-
import JoinSelectorVisitor from './join-selector-visitor.js';
|
|
6
|
-
import ToCSSVisitor from './to-css-visitor.js';
|
|
7
|
-
|
|
8
|
-
export default {
|
|
9
|
-
Visitor,
|
|
10
|
-
ImportVisitor,
|
|
11
|
-
MarkVisibleSelectorsVisitor,
|
|
12
|
-
ExtendVisitor,
|
|
13
|
-
JoinSelectorVisitor,
|
|
14
|
-
ToCSSVisitor
|
|
15
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-unused-vars */
|
|
2
|
-
/**
|
|
3
|
-
* @todo - Remove unused when JSDoc types are added for visitor methods
|
|
4
|
-
*/
|
|
5
|
-
import Visitor from './visitor.js';
|
|
6
|
-
|
|
7
|
-
class JoinSelectorVisitor {
|
|
8
|
-
constructor() {
|
|
9
|
-
this.contexts = [[]];
|
|
10
|
-
this._visitor = new Visitor(this);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
run(root) {
|
|
14
|
-
return this._visitor.visit(root);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
visitDeclaration(declNode, visitArgs) {
|
|
18
|
-
visitArgs.visitDeeper = false;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
visitMixinDefinition(mixinDefinitionNode, visitArgs) {
|
|
22
|
-
visitArgs.visitDeeper = false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
visitRuleset(rulesetNode, visitArgs) {
|
|
26
|
-
const context = this.contexts[this.contexts.length - 1];
|
|
27
|
-
const paths = [];
|
|
28
|
-
let selectors;
|
|
29
|
-
|
|
30
|
-
this.contexts.push(paths);
|
|
31
|
-
|
|
32
|
-
if (!rulesetNode.root) {
|
|
33
|
-
selectors = rulesetNode.selectors;
|
|
34
|
-
if (selectors) {
|
|
35
|
-
selectors = selectors.filter(function(selector) { return selector.getIsOutput(); });
|
|
36
|
-
rulesetNode.selectors = selectors.length ? selectors : (selectors = null);
|
|
37
|
-
if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); }
|
|
38
|
-
}
|
|
39
|
-
if (!selectors) { rulesetNode.rules = null; }
|
|
40
|
-
rulesetNode.paths = paths;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
visitRulesetOut(rulesetNode) {
|
|
45
|
-
this.contexts.length = this.contexts.length - 1;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
visitMedia(mediaNode, visitArgs) {
|
|
49
|
-
const context = this.contexts[this.contexts.length - 1];
|
|
50
|
-
mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
visitAtRule(atRuleNode, visitArgs) {
|
|
54
|
-
const context = this.contexts[this.contexts.length - 1];
|
|
55
|
-
|
|
56
|
-
if (atRuleNode.declarations && atRuleNode.declarations.length) {
|
|
57
|
-
atRuleNode.declarations[0].root = (context.length === 0 || context[0].multiMedia);
|
|
58
|
-
}
|
|
59
|
-
else if (atRuleNode.rules && atRuleNode.rules.length) {
|
|
60
|
-
atRuleNode.rules[0].root = (atRuleNode.isRooted || context.length === 0 || null);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export default JoinSelectorVisitor;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import Node from '../tree/node.js';
|
|
2
|
-
|
|
3
|
-
class SetTreeVisibilityVisitor {
|
|
4
|
-
/** @param {boolean} visible */
|
|
5
|
-
constructor(visible) {
|
|
6
|
-
this.visible = visible;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/** @param {Node} root */
|
|
10
|
-
run(root) {
|
|
11
|
-
this.visit(root);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @param {Node[]} nodes
|
|
16
|
-
* @returns {Node[]}
|
|
17
|
-
*/
|
|
18
|
-
visitArray(nodes) {
|
|
19
|
-
if (!nodes) {
|
|
20
|
-
return nodes;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const cnt = nodes.length;
|
|
24
|
-
let i;
|
|
25
|
-
for (i = 0; i < cnt; i++) {
|
|
26
|
-
this.visit(nodes[i]);
|
|
27
|
-
}
|
|
28
|
-
return nodes;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @param {*} node
|
|
33
|
-
* @returns {*}
|
|
34
|
-
*/
|
|
35
|
-
visit(node) {
|
|
36
|
-
if (!node) {
|
|
37
|
-
return node;
|
|
38
|
-
}
|
|
39
|
-
if (node.constructor === Array) {
|
|
40
|
-
return this.visitArray(node);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (!node.blocksVisibility || node.blocksVisibility()) {
|
|
44
|
-
return node;
|
|
45
|
-
}
|
|
46
|
-
if (this.visible) {
|
|
47
|
-
node.ensureVisibility();
|
|
48
|
-
} else {
|
|
49
|
-
node.ensureInvisibility();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
node.accept(this);
|
|
53
|
-
return node;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export default SetTreeVisibilityVisitor;
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-unused-vars */
|
|
2
|
-
/**
|
|
3
|
-
* @todo - Remove unused when JSDoc types are added for visitor methods
|
|
4
|
-
*/
|
|
5
|
-
import tree from '../tree/index.js';
|
|
6
|
-
import Visitor from './visitor.js';
|
|
7
|
-
import mergeRules from '../tree/merge-rules.js';
|
|
8
|
-
|
|
9
|
-
class CSSVisitorUtils {
|
|
10
|
-
constructor(context) {
|
|
11
|
-
this._visitor = new Visitor(this);
|
|
12
|
-
this._context = context;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
containsSilentNonBlockedChild(bodyRules) {
|
|
16
|
-
let rule;
|
|
17
|
-
if (!bodyRules) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
for (let r = 0; r < bodyRules.length; r++) {
|
|
21
|
-
rule = bodyRules[r];
|
|
22
|
-
if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {
|
|
23
|
-
// the atrule contains something that was referenced (likely by extend)
|
|
24
|
-
// therefore it needs to be shown in output too
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
keepOnlyVisibleChilds(owner) {
|
|
32
|
-
if (owner && owner.rules) {
|
|
33
|
-
owner.rules = owner.rules.filter(thing => thing.isVisible());
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
isEmpty(owner) {
|
|
38
|
-
return (owner && owner.rules)
|
|
39
|
-
? (owner.rules.length === 0) : true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
hasVisibleSelector(rulesetNode) {
|
|
43
|
-
return (rulesetNode && rulesetNode.paths)
|
|
44
|
-
? (rulesetNode.paths.length > 0) : false;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
resolveVisibility(node) {
|
|
48
|
-
if (!node.blocksVisibility()) {
|
|
49
|
-
if (this.isEmpty(node)) {
|
|
50
|
-
return ;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return node;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const compiledRulesBody = node.rules[0];
|
|
57
|
-
this.keepOnlyVisibleChilds(compiledRulesBody);
|
|
58
|
-
|
|
59
|
-
if (this.isEmpty(compiledRulesBody)) {
|
|
60
|
-
return ;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
node.ensureVisibility();
|
|
64
|
-
node.removeVisibilityBlock();
|
|
65
|
-
|
|
66
|
-
return node;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
isVisibleRuleset(rulesetNode) {
|
|
70
|
-
if (rulesetNode.firstRoot) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (this.isEmpty(rulesetNode)) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const ToCSSVisitor = function(context) {
|
|
87
|
-
this._visitor = new Visitor(this);
|
|
88
|
-
this._context = context;
|
|
89
|
-
this.utils = new CSSVisitorUtils(context);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
ToCSSVisitor.prototype = {
|
|
93
|
-
isReplacing: true,
|
|
94
|
-
run: function (root) {
|
|
95
|
-
return this._visitor.visit(root);
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
visitDeclaration: function (declNode, visitArgs) {
|
|
99
|
-
if (declNode.blocksVisibility() || declNode.variable) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
return declNode;
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
visitMixinDefinition: function (mixinNode, visitArgs) {
|
|
106
|
-
// mixin definitions do not get eval'd - this means they keep state
|
|
107
|
-
// so we have to clear that state here so it isn't used if toCSS is called twice
|
|
108
|
-
mixinNode.frames = [];
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
visitExtend: function (extendNode, visitArgs) {
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
visitComment: function (commentNode, visitArgs) {
|
|
115
|
-
if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
return commentNode;
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
visitMedia: function(mediaNode, visitArgs) {
|
|
122
|
-
const originalRules = mediaNode.rules[0].rules;
|
|
123
|
-
mediaNode.accept(this._visitor);
|
|
124
|
-
visitArgs.visitDeeper = false;
|
|
125
|
-
|
|
126
|
-
return this.utils.resolveVisibility(mediaNode, originalRules);
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
visitImport: function (importNode, visitArgs) {
|
|
130
|
-
if (importNode.blocksVisibility()) {
|
|
131
|
-
return ;
|
|
132
|
-
}
|
|
133
|
-
return importNode;
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
visitAtRule: function(atRuleNode, visitArgs) {
|
|
137
|
-
if (atRuleNode.rules && atRuleNode.rules.length) {
|
|
138
|
-
return this.visitAtRuleWithBody(atRuleNode, visitArgs);
|
|
139
|
-
} else {
|
|
140
|
-
return this.visitAtRuleWithoutBody(atRuleNode, visitArgs);
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
visitAnonymous: function(anonymousNode, visitArgs) {
|
|
145
|
-
if (!anonymousNode.blocksVisibility()) {
|
|
146
|
-
anonymousNode.accept(this._visitor);
|
|
147
|
-
return anonymousNode;
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
visitAtRuleWithBody: function(atRuleNode, visitArgs) {
|
|
152
|
-
// if there is only one nested ruleset and that one has no path, then it is
|
|
153
|
-
// just fake ruleset
|
|
154
|
-
function hasFakeRuleset(atRuleNode) {
|
|
155
|
-
const bodyRules = atRuleNode.rules;
|
|
156
|
-
return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);
|
|
157
|
-
}
|
|
158
|
-
function getBodyRules(atRuleNode) {
|
|
159
|
-
const nodeRules = atRuleNode.rules;
|
|
160
|
-
if (hasFakeRuleset(atRuleNode)) {
|
|
161
|
-
return nodeRules[0].rules;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return nodeRules;
|
|
165
|
-
}
|
|
166
|
-
// it is still true that it is only one ruleset in array
|
|
167
|
-
// this is last such moment
|
|
168
|
-
// process childs
|
|
169
|
-
const originalRules = getBodyRules(atRuleNode);
|
|
170
|
-
atRuleNode.accept(this._visitor);
|
|
171
|
-
visitArgs.visitDeeper = false;
|
|
172
|
-
|
|
173
|
-
if (!this.utils.isEmpty(atRuleNode)) {
|
|
174
|
-
this._mergeRules(atRuleNode.rules[0].rules);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return this.utils.resolveVisibility(atRuleNode, originalRules);
|
|
178
|
-
},
|
|
179
|
-
|
|
180
|
-
visitAtRuleWithoutBody: function(atRuleNode, visitArgs) {
|
|
181
|
-
if (atRuleNode.blocksVisibility()) {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (atRuleNode.name === '@charset') {
|
|
186
|
-
// Only output the debug info together with subsequent @charset definitions
|
|
187
|
-
// a comment (or @media statement) before the actual @charset atrule would
|
|
188
|
-
// be considered illegal css as it has to be on the first line
|
|
189
|
-
if (this.charset) {
|
|
190
|
-
if (atRuleNode.debugInfo) {
|
|
191
|
-
const comment = new tree.Comment(`/* ${atRuleNode.toCSS(this._context).replace(/\n/g, '')} */\n`);
|
|
192
|
-
comment.debugInfo = atRuleNode.debugInfo;
|
|
193
|
-
return this._visitor.visit(comment);
|
|
194
|
-
}
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
this.charset = true;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return atRuleNode;
|
|
201
|
-
},
|
|
202
|
-
|
|
203
|
-
checkValidNodes: function(rules, isRoot) {
|
|
204
|
-
if (!rules) {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
for (let i = 0; i < rules.length; i++) {
|
|
209
|
-
const ruleNode = rules[i];
|
|
210
|
-
if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) {
|
|
211
|
-
throw { message: 'Properties must be inside selector blocks. They cannot be in the root',
|
|
212
|
-
index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
|
|
213
|
-
}
|
|
214
|
-
if (ruleNode instanceof tree.Call) {
|
|
215
|
-
throw { message: `Function '${ruleNode.name}' did not return a root node`,
|
|
216
|
-
index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
|
|
217
|
-
}
|
|
218
|
-
if (ruleNode.type && !ruleNode.allowRoot) {
|
|
219
|
-
throw { message: `${ruleNode.type} node returned by a function is not valid here`,
|
|
220
|
-
index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
|
|
225
|
-
visitRuleset: function (rulesetNode, visitArgs) {
|
|
226
|
-
// at this point rulesets are nested into each other
|
|
227
|
-
let rule;
|
|
228
|
-
|
|
229
|
-
const rulesets = [];
|
|
230
|
-
|
|
231
|
-
this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);
|
|
232
|
-
|
|
233
|
-
if (!rulesetNode.root) {
|
|
234
|
-
// remove invisible paths
|
|
235
|
-
this._compileRulesetPaths(rulesetNode);
|
|
236
|
-
|
|
237
|
-
// remove rulesets from this ruleset body and compile them separately
|
|
238
|
-
const nodeRules = rulesetNode.rules;
|
|
239
|
-
|
|
240
|
-
let nodeRuleCnt = nodeRules ? nodeRules.length : 0;
|
|
241
|
-
for (let i = 0; i < nodeRuleCnt; ) {
|
|
242
|
-
rule = nodeRules[i];
|
|
243
|
-
if (rule && rule.rules) {
|
|
244
|
-
// visit because we are moving them out from being a child
|
|
245
|
-
rulesets.push(this._visitor.visit(rule));
|
|
246
|
-
nodeRules.splice(i, 1);
|
|
247
|
-
nodeRuleCnt--;
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
i++;
|
|
251
|
-
}
|
|
252
|
-
// accept the visitor to remove rules and refactor itself
|
|
253
|
-
// then we can decide nogw whether we want it or not
|
|
254
|
-
// compile body
|
|
255
|
-
if (nodeRuleCnt > 0) {
|
|
256
|
-
rulesetNode.accept(this._visitor);
|
|
257
|
-
} else {
|
|
258
|
-
rulesetNode.rules = null;
|
|
259
|
-
}
|
|
260
|
-
visitArgs.visitDeeper = false;
|
|
261
|
-
} else { // if (! rulesetNode.root) {
|
|
262
|
-
rulesetNode.accept(this._visitor);
|
|
263
|
-
visitArgs.visitDeeper = false;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (rulesetNode.rules) {
|
|
267
|
-
this._mergeRules(rulesetNode.rules);
|
|
268
|
-
this._removeDuplicateRules(rulesetNode.rules);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// now decide whether we keep the ruleset
|
|
272
|
-
if (this.utils.isVisibleRuleset(rulesetNode)) {
|
|
273
|
-
rulesetNode.ensureVisibility();
|
|
274
|
-
rulesets.splice(0, 0, rulesetNode);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (rulesets.length === 1) {
|
|
278
|
-
return rulesets[0];
|
|
279
|
-
}
|
|
280
|
-
return rulesets;
|
|
281
|
-
},
|
|
282
|
-
|
|
283
|
-
_compileRulesetPaths: function(rulesetNode) {
|
|
284
|
-
if (rulesetNode.paths) {
|
|
285
|
-
rulesetNode.paths = rulesetNode.paths
|
|
286
|
-
.filter(p => {
|
|
287
|
-
let i;
|
|
288
|
-
if (p[0].elements[0].combinator.value === ' ') {
|
|
289
|
-
p[0].elements[0].combinator = new(tree.Combinator)('');
|
|
290
|
-
}
|
|
291
|
-
for (i = 0; i < p.length; i++) {
|
|
292
|
-
if (p[i].isVisible() && p[i].getIsOutput()) {
|
|
293
|
-
return true;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return false;
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
|
|
301
|
-
_removeDuplicateRules: function(rules) {
|
|
302
|
-
if (!rules) { return; }
|
|
303
|
-
|
|
304
|
-
// remove duplicates
|
|
305
|
-
const ruleCache = {};
|
|
306
|
-
|
|
307
|
-
for (let i = rules.length - 1; i >= 0 ; i--) {
|
|
308
|
-
let rule = rules[i];
|
|
309
|
-
if (rule instanceof tree.Declaration) {
|
|
310
|
-
if (!Object.prototype.hasOwnProperty.call(ruleCache, rule.name)) {
|
|
311
|
-
ruleCache[rule.name] = rule;
|
|
312
|
-
} else {
|
|
313
|
-
let ruleList = ruleCache[rule.name];
|
|
314
|
-
if (!Array.isArray(ruleList)) {
|
|
315
|
-
const prevRuleCSS = ruleList.toCSS(this._context);
|
|
316
|
-
ruleList = ruleCache[rule.name] = [prevRuleCSS];
|
|
317
|
-
}
|
|
318
|
-
const ruleCSS = rule.toCSS(this._context);
|
|
319
|
-
if (ruleList.indexOf(ruleCSS) !== -1) {
|
|
320
|
-
rules.splice(i, 1);
|
|
321
|
-
} else {
|
|
322
|
-
ruleList.push(ruleCSS);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
|
|
329
|
-
_mergeRules: mergeRules
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
export default ToCSSVisitor;
|