less 4.8.1 → 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 (129) hide show
  1. package/README.md +19 -5
  2. package/bin/lessc +190 -630
  3. package/dist/less-node.cjs +398 -14282
  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 +33 -40
  13. package/dist/less.cjs +0 -14929
  14. package/dist/less.js +0 -14929
  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 -36
  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/parser-input.js +0 -400
  52. package/lib/less/parser/parser.js +0 -2894
  53. package/lib/less/plugin-manager.js +0 -168
  54. package/lib/less/render.js +0 -41
  55. package/lib/less/source-map-builder.js +0 -82
  56. package/lib/less/source-map-output.js +0 -151
  57. package/lib/less/transform-tree.js +0 -102
  58. package/lib/less/tree/anonymous.js +0 -57
  59. package/lib/less/tree/assignment.js +0 -48
  60. package/lib/less/tree/atrule-syntax.js +0 -8
  61. package/lib/less/tree/atrule.js +0 -340
  62. package/lib/less/tree/attribute.js +0 -63
  63. package/lib/less/tree/call.js +0 -132
  64. package/lib/less/tree/color.js +0 -285
  65. package/lib/less/tree/combinator.js +0 -38
  66. package/lib/less/tree/comment.js +0 -48
  67. package/lib/less/tree/condition.js +0 -65
  68. package/lib/less/tree/container.js +0 -104
  69. package/lib/less/tree/debug-info.js +0 -80
  70. package/lib/less/tree/declaration.js +0 -139
  71. package/lib/less/tree/detached-ruleset.js +0 -45
  72. package/lib/less/tree/dimension.js +0 -215
  73. package/lib/less/tree/element.js +0 -93
  74. package/lib/less/tree/expression.js +0 -100
  75. package/lib/less/tree/extend.js +0 -88
  76. package/lib/less/tree/import.js +0 -299
  77. package/lib/less/tree/index.js +0 -56
  78. package/lib/less/tree/javascript.js +0 -45
  79. package/lib/less/tree/js-eval-node.js +0 -74
  80. package/lib/less/tree/keyword.js +0 -28
  81. package/lib/less/tree/media.js +0 -90
  82. package/lib/less/tree/merge-rules.js +0 -47
  83. package/lib/less/tree/mixin-call.js +0 -283
  84. package/lib/less/tree/mixin-definition.js +0 -319
  85. package/lib/less/tree/namespace-value.js +0 -95
  86. package/lib/less/tree/negative.js +0 -37
  87. package/lib/less/tree/nested-at-rule.js +0 -198
  88. package/lib/less/tree/node.js +0 -310
  89. package/lib/less/tree/operation.js +0 -81
  90. package/lib/less/tree/paren.js +0 -41
  91. package/lib/less/tree/property.js +0 -96
  92. package/lib/less/tree/query-in-parens.js +0 -64
  93. package/lib/less/tree/quoted.js +0 -114
  94. package/lib/less/tree/ruleset.js +0 -1066
  95. package/lib/less/tree/selector.js +0 -201
  96. package/lib/less/tree/unicode-descriptor.js +0 -14
  97. package/lib/less/tree/unit.js +0 -170
  98. package/lib/less/tree/url.js +0 -83
  99. package/lib/less/tree/value.js +0 -60
  100. package/lib/less/tree/variable-call.js +0 -60
  101. package/lib/less/tree/variable.js +0 -85
  102. package/lib/less/utils.js +0 -126
  103. package/lib/less/visitors/extend-visitor.js +0 -505
  104. package/lib/less/visitors/import-sequencer.js +0 -56
  105. package/lib/less/visitors/import-visitor.js +0 -203
  106. package/lib/less/visitors/index.js +0 -15
  107. package/lib/less/visitors/join-selector-visitor.js +0 -65
  108. package/lib/less/visitors/set-tree-visibility-visitor.js +0 -57
  109. package/lib/less/visitors/to-css-visitor.js +0 -332
  110. package/lib/less/visitors/visitor.js +0 -165
  111. package/lib/less-browser/add-default-options.js +0 -53
  112. package/lib/less-browser/bootstrap.js +0 -67
  113. package/lib/less-browser/browser.js +0 -65
  114. package/lib/less-browser/cache.js +0 -43
  115. package/lib/less-browser/error-reporting.js +0 -170
  116. package/lib/less-browser/file-manager.js +0 -112
  117. package/lib/less-browser/image-size.js +0 -28
  118. package/lib/less-browser/index.js +0 -284
  119. package/lib/less-browser/log-listener.js +0 -42
  120. package/lib/less-browser/plugin-loader.js +0 -24
  121. package/lib/less-browser/utils.js +0 -30
  122. package/lib/less-node/environment.js +0 -43
  123. package/lib/less-node/file-manager.js +0 -156
  124. package/lib/less-node/fs.js +0 -14
  125. package/lib/less-node/image-size.js +0 -78
  126. package/lib/less-node/index.js +0 -31
  127. package/lib/less-node/lessc-helper.js +0 -95
  128. package/lib/less-node/plugin-loader.js +0 -62
  129. 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;