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.
Files changed (131) hide show
  1. package/README.md +19 -5
  2. package/bin/lessc +190 -630
  3. package/dist/less-node.cjs +399 -14570
  4. package/index.cjs +5 -2
  5. package/lib/index.js +164 -0
  6. package/lib/lessc-helper.js +52 -0
  7. package/lib/logger.js +76 -0
  8. package/lib/options.d.ts +46 -0
  9. package/lib/options.js +145 -0
  10. package/lib/types.js +20 -0
  11. package/lib/version.js +19 -0
  12. package/package.json +34 -40
  13. package/dist/less.cjs +0 -15215
  14. package/dist/less.js +0 -15215
  15. package/dist/less.min.js +0 -11
  16. package/dist/less.min.js.map +0 -1
  17. package/lib/less/constants.js +0 -13
  18. package/lib/less/contexts.js +0 -165
  19. package/lib/less/data/colors.js +0 -150
  20. package/lib/less/data/index.js +0 -4
  21. package/lib/less/data/unit-conversions.js +0 -21
  22. package/lib/less/default-options.js +0 -89
  23. package/lib/less/deprecation.js +0 -82
  24. package/lib/less/environment/abstract-file-manager.js +0 -140
  25. package/lib/less/environment/abstract-plugin-loader.js +0 -185
  26. package/lib/less/environment/environment-api.ts +0 -21
  27. package/lib/less/environment/environment.js +0 -59
  28. package/lib/less/environment/file-manager-api.ts +0 -77
  29. package/lib/less/functions/boolean.js +0 -29
  30. package/lib/less/functions/color-blending.js +0 -85
  31. package/lib/less/functions/color.js +0 -452
  32. package/lib/less/functions/data-uri.js +0 -74
  33. package/lib/less/functions/default.js +0 -26
  34. package/lib/less/functions/function-caller.js +0 -55
  35. package/lib/less/functions/function-registry.js +0 -36
  36. package/lib/less/functions/index.js +0 -35
  37. package/lib/less/functions/list.js +0 -158
  38. package/lib/less/functions/math-helper.js +0 -22
  39. package/lib/less/functions/math.js +0 -30
  40. package/lib/less/functions/number.js +0 -95
  41. package/lib/less/functions/string.js +0 -39
  42. package/lib/less/functions/style.js +0 -29
  43. package/lib/less/functions/svg.js +0 -87
  44. package/lib/less/functions/types.js +0 -70
  45. package/lib/less/import-manager.js +0 -183
  46. package/lib/less/index.js +0 -95
  47. package/lib/less/less-error.js +0 -166
  48. package/lib/less/logger.js +0 -34
  49. package/lib/less/parse-tree.js +0 -124
  50. package/lib/less/parse.js +0 -87
  51. package/lib/less/parser/lookup-pattern.js +0 -26
  52. package/lib/less/parser/parser-input.js +0 -400
  53. package/lib/less/parser/parser.js +0 -2998
  54. package/lib/less/plugin-manager.js +0 -168
  55. package/lib/less/render.js +0 -41
  56. package/lib/less/source-map-builder.js +0 -82
  57. package/lib/less/source-map-output.js +0 -151
  58. package/lib/less/transform-tree.js +0 -102
  59. package/lib/less/tree/anonymous.js +0 -61
  60. package/lib/less/tree/assignment.js +0 -48
  61. package/lib/less/tree/atrule-syntax.js +0 -8
  62. package/lib/less/tree/atrule.js +0 -340
  63. package/lib/less/tree/attribute.js +0 -63
  64. package/lib/less/tree/call.js +0 -132
  65. package/lib/less/tree/color.js +0 -285
  66. package/lib/less/tree/combinator.js +0 -38
  67. package/lib/less/tree/comment.js +0 -48
  68. package/lib/less/tree/condition.js +0 -65
  69. package/lib/less/tree/container.js +0 -104
  70. package/lib/less/tree/debug-info.js +0 -80
  71. package/lib/less/tree/declaration.js +0 -139
  72. package/lib/less/tree/detached-ruleset.js +0 -45
  73. package/lib/less/tree/dimension.js +0 -215
  74. package/lib/less/tree/element.js +0 -93
  75. package/lib/less/tree/expression.js +0 -100
  76. package/lib/less/tree/extend.js +0 -88
  77. package/lib/less/tree/import.js +0 -299
  78. package/lib/less/tree/index.js +0 -56
  79. package/lib/less/tree/interpolated-variable.js +0 -106
  80. package/lib/less/tree/javascript.js +0 -45
  81. package/lib/less/tree/js-eval-node.js +0 -80
  82. package/lib/less/tree/keyword.js +0 -28
  83. package/lib/less/tree/media.js +0 -90
  84. package/lib/less/tree/merge-rules.js +0 -47
  85. package/lib/less/tree/mixin-call.js +0 -283
  86. package/lib/less/tree/mixin-definition.js +0 -319
  87. package/lib/less/tree/namespace-value.js +0 -95
  88. package/lib/less/tree/negative.js +0 -37
  89. package/lib/less/tree/nested-at-rule.js +0 -239
  90. package/lib/less/tree/node.js +0 -310
  91. package/lib/less/tree/operation.js +0 -81
  92. package/lib/less/tree/paren.js +0 -41
  93. package/lib/less/tree/property.js +0 -96
  94. package/lib/less/tree/query-in-parens.js +0 -64
  95. package/lib/less/tree/quoted.js +0 -131
  96. package/lib/less/tree/ruleset.js +0 -1068
  97. package/lib/less/tree/selector.js +0 -201
  98. package/lib/less/tree/unicode-descriptor.js +0 -14
  99. package/lib/less/tree/unit.js +0 -170
  100. package/lib/less/tree/url.js +0 -83
  101. package/lib/less/tree/value.js +0 -60
  102. package/lib/less/tree/variable-call.js +0 -60
  103. package/lib/less/tree/variable.js +0 -85
  104. package/lib/less/utils.js +0 -126
  105. package/lib/less/visitors/extend-visitor.js +0 -505
  106. package/lib/less/visitors/import-sequencer.js +0 -56
  107. package/lib/less/visitors/import-visitor.js +0 -203
  108. package/lib/less/visitors/index.js +0 -15
  109. package/lib/less/visitors/join-selector-visitor.js +0 -65
  110. package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
  111. package/lib/less/visitors/to-css-visitor.js +0 -332
  112. package/lib/less/visitors/visitor.js +0 -165
  113. package/lib/less-browser/add-default-options.js +0 -53
  114. package/lib/less-browser/bootstrap.js +0 -67
  115. package/lib/less-browser/browser.js +0 -65
  116. package/lib/less-browser/cache.js +0 -43
  117. package/lib/less-browser/error-reporting.js +0 -170
  118. package/lib/less-browser/file-manager.js +0 -112
  119. package/lib/less-browser/image-size.js +0 -28
  120. package/lib/less-browser/index.js +0 -284
  121. package/lib/less-browser/log-listener.js +0 -42
  122. package/lib/less-browser/plugin-loader.js +0 -24
  123. package/lib/less-browser/utils.js +0 -30
  124. package/lib/less-node/environment.js +0 -43
  125. package/lib/less-node/file-manager.js +0 -156
  126. package/lib/less-node/fs.js +0 -14
  127. package/lib/less-node/image-size.js +0 -78
  128. package/lib/less-node/index.js +0 -31
  129. package/lib/less-node/lessc-helper.js +0 -95
  130. package/lib/less-node/plugin-loader.js +0 -62
  131. 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;