less 4.1.2 → 4.2.0

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 (150) hide show
  1. package/.eslintrc.js +63 -0
  2. package/Gruntfile.js +2 -1
  3. package/LICENSE +177 -0
  4. package/bin/lessc +19 -1
  5. package/dist/less.js +7129 -6951
  6. package/dist/less.min.js +3 -3
  7. package/dist/less.min.js.map +1 -1
  8. package/lib/less/contexts.js +1 -1
  9. package/lib/less/contexts.js.map +1 -1
  10. package/lib/less/default-options.js +0 -1
  11. package/lib/less/default-options.js.map +1 -1
  12. package/lib/less/environment/abstract-file-manager.js +9 -3
  13. package/lib/less/environment/abstract-file-manager.js.map +1 -1
  14. package/lib/less/environment/environment-api.js +0 -25
  15. package/lib/less/environment/environment-api.js.map +1 -1
  16. package/lib/less/environment/environment.js +1 -1
  17. package/lib/less/environment/environment.js.map +1 -1
  18. package/lib/less/environment/file-manager-api.js +0 -103
  19. package/lib/less/environment/file-manager-api.js.map +1 -1
  20. package/lib/less/functions/color-blending.js +1 -0
  21. package/lib/less/functions/color-blending.js.map +1 -1
  22. package/lib/less/functions/color.js +19 -19
  23. package/lib/less/functions/color.js.map +1 -1
  24. package/lib/less/functions/default.js +2 -1
  25. package/lib/less/functions/default.js.map +1 -1
  26. package/lib/less/functions/function-registry.js +1 -0
  27. package/lib/less/functions/function-registry.js.map +1 -1
  28. package/lib/less/functions/list.js +2 -2
  29. package/lib/less/functions/list.js.map +1 -1
  30. package/lib/less/functions/math-helper.js +1 -1
  31. package/lib/less/functions/math-helper.js.map +1 -1
  32. package/lib/less/functions/math.js +1 -0
  33. package/lib/less/functions/math.js.map +1 -1
  34. package/lib/less/functions/number.js +4 -3
  35. package/lib/less/functions/number.js.map +1 -1
  36. package/lib/less/functions/svg.js +1 -1
  37. package/lib/less/functions/svg.js.map +1 -1
  38. package/lib/less/import-manager.js +0 -1
  39. package/lib/less/import-manager.js.map +1 -1
  40. package/lib/less/index.js +0 -1
  41. package/lib/less/index.js.map +1 -1
  42. package/lib/less/less-error.js +1 -2
  43. package/lib/less/less-error.js.map +1 -1
  44. package/lib/less/parse-tree.js +1 -2
  45. package/lib/less/parse-tree.js.map +1 -1
  46. package/lib/less/parse.js +1 -2
  47. package/lib/less/parse.js.map +1 -1
  48. package/lib/less/parser/chunker.js +0 -1
  49. package/lib/less/parser/chunker.js.map +1 -1
  50. package/lib/less/parser/parser-input.js +10 -4
  51. package/lib/less/parser/parser-input.js.map +1 -1
  52. package/lib/less/parser/parser.js +128 -94
  53. package/lib/less/parser/parser.js.map +1 -1
  54. package/lib/less/render.js +1 -2
  55. package/lib/less/render.js.map +1 -1
  56. package/lib/less/source-map-builder.js +0 -1
  57. package/lib/less/source-map-builder.js.map +1 -1
  58. package/lib/less/source-map-output.js +1 -1
  59. package/lib/less/source-map-output.js.map +1 -1
  60. package/lib/less/transform-tree.js +0 -1
  61. package/lib/less/transform-tree.js.map +1 -1
  62. package/lib/less/tree/atrule-syntax.js +10 -0
  63. package/lib/less/tree/atrule-syntax.js.map +1 -0
  64. package/lib/less/tree/attribute.js +6 -2
  65. package/lib/less/tree/attribute.js.map +1 -1
  66. package/lib/less/tree/call.js +1 -0
  67. package/lib/less/tree/call.js.map +1 -1
  68. package/lib/less/tree/color.js +2 -0
  69. package/lib/less/tree/color.js.map +1 -1
  70. package/lib/less/tree/container.js +48 -0
  71. package/lib/less/tree/container.js.map +1 -0
  72. package/lib/less/tree/debug-info.js +30 -33
  73. package/lib/less/tree/debug-info.js.map +1 -1
  74. package/lib/less/tree/dimension.js +4 -2
  75. package/lib/less/tree/dimension.js.map +1 -1
  76. package/lib/less/tree/expression.js +0 -2
  77. package/lib/less/tree/expression.js.map +1 -1
  78. package/lib/less/tree/extend.js +2 -0
  79. package/lib/less/tree/extend.js.map +1 -1
  80. package/lib/less/tree/import.js +1 -1
  81. package/lib/less/tree/import.js.map +1 -1
  82. package/lib/less/tree/index.js +4 -0
  83. package/lib/less/tree/index.js.map +1 -1
  84. package/lib/less/tree/js-eval-node.js +1 -1
  85. package/lib/less/tree/js-eval-node.js.map +1 -1
  86. package/lib/less/tree/media.js +4 -88
  87. package/lib/less/tree/media.js.map +1 -1
  88. package/lib/less/tree/namespace-value.js +1 -1
  89. package/lib/less/tree/namespace-value.js.map +1 -1
  90. package/lib/less/tree/nested-at-rule.js +91 -0
  91. package/lib/less/tree/nested-at-rule.js.map +1 -0
  92. package/lib/less/tree/node.js +6 -4
  93. package/lib/less/tree/node.js.map +1 -1
  94. package/lib/less/tree/query-in-parens.js +41 -0
  95. package/lib/less/tree/query-in-parens.js.map +1 -0
  96. package/lib/less/tree/quoted.js +1 -1
  97. package/lib/less/tree/quoted.js.map +1 -1
  98. package/lib/less/tree/ruleset.js +7 -4
  99. package/lib/less/tree/ruleset.js.map +1 -1
  100. package/lib/less/tree/selector.js +5 -3
  101. package/lib/less/tree/selector.js.map +1 -1
  102. package/lib/less/tree/unit.js +3 -1
  103. package/lib/less/tree/unit.js.map +1 -1
  104. package/lib/less/tree/url.js +1 -1
  105. package/lib/less/tree/url.js.map +1 -1
  106. package/lib/less/utils.js +7 -3
  107. package/lib/less/utils.js.map +1 -1
  108. package/lib/less/visitors/extend-visitor.js +4 -0
  109. package/lib/less/visitors/extend-visitor.js.map +1 -1
  110. package/lib/less/visitors/import-visitor.js +4 -0
  111. package/lib/less/visitors/import-visitor.js.map +1 -1
  112. package/lib/less/visitors/join-selector-visitor.js +4 -0
  113. package/lib/less/visitors/join-selector-visitor.js.map +1 -1
  114. package/lib/less/visitors/to-css-visitor.js +6 -2
  115. package/lib/less/visitors/to-css-visitor.js.map +1 -1
  116. package/lib/less-browser/bootstrap.js +3 -4
  117. package/lib/less-browser/bootstrap.js.map +1 -1
  118. package/lib/less-browser/cache.js +1 -1
  119. package/lib/less-browser/cache.js.map +1 -1
  120. package/lib/less-browser/error-reporting.js +2 -2
  121. package/lib/less-browser/error-reporting.js.map +1 -1
  122. package/lib/less-browser/file-manager.js +1 -2
  123. package/lib/less-browser/file-manager.js.map +1 -1
  124. package/lib/less-browser/index.js +6 -2
  125. package/lib/less-browser/index.js.map +1 -1
  126. package/lib/less-browser/plugin-loader.js +3 -2
  127. package/lib/less-browser/plugin-loader.js.map +1 -1
  128. package/lib/less-browser/utils.js +7 -4
  129. package/lib/less-browser/utils.js.map +1 -1
  130. package/lib/less-node/file-manager.js +16 -16
  131. package/lib/less-node/file-manager.js.map +1 -1
  132. package/lib/less-node/image-size.js +0 -2
  133. package/lib/less-node/image-size.js.map +1 -1
  134. package/lib/less-node/index.js.map +1 -1
  135. package/lib/less-node/lessc-helper.js +2 -0
  136. package/lib/less-node/lessc-helper.js.map +1 -1
  137. package/lib/less-node/url-file-manager.js +5 -0
  138. package/lib/less-node/url-file-manager.js.map +1 -1
  139. package/package.json +10 -7
  140. package/test/browser/generator/benchmark.config.js +19 -19
  141. package/test/browser/generator/runner.config.js +69 -69
  142. package/test/browser/runner-rewrite-urls-spec.js +1 -1
  143. package/test/index.js +5 -1
  144. package/test/less-test.js +76 -8
  145. package/test/plugins/filemanager/index.js +1 -1
  146. package/test/sourcemaps-variable-selector/basic.json +1 -0
  147. package/test/test-es6.ts +5 -5
  148. package/tsconfig.build.json +7 -0
  149. package/tsconfig.json +4 -3
  150. package/.eslintrc.json +0 -71
@@ -7,6 +7,7 @@ var visitors_1 = tslib_1.__importDefault(require("../visitors"));
7
7
  var parser_input_1 = tslib_1.__importDefault(require("./parser-input"));
8
8
  var utils = tslib_1.__importStar(require("../utils"));
9
9
  var function_registry_1 = tslib_1.__importDefault(require("../functions/function-registry"));
10
+ var atrule_syntax_1 = require("../tree/atrule-syntax");
10
11
  //
11
12
  // less.js - parser
12
13
  //
@@ -39,7 +40,8 @@ var function_registry_1 = tslib_1.__importDefault(require("../functions/function
39
40
  // a terminal string or regexp, or a non-terminal function to call.
40
41
  // It also takes care of moving all the indices forwards.
41
42
  //
42
- var Parser = function Parser(context, imports, fileInfo) {
43
+ var Parser = function Parser(context, imports, fileInfo, currentIndex) {
44
+ currentIndex = currentIndex || 0;
43
45
  var parsers;
44
46
  var parserInput = parser_input_1.default();
45
47
  function error(msg, type) {
@@ -82,7 +84,7 @@ var Parser = function Parser(context, imports, fileInfo) {
82
84
  * @param {Number} currentIndex - start number to begin indexing
83
85
  * @param {Object} fileInfo - fileInfo to attach to created nodes
84
86
  */
85
- function parseNode(str, parseList, currentIndex, fileInfo, callback) {
87
+ function parseNode(str, parseList, callback) {
86
88
  var result;
87
89
  var returnNodes = [];
88
90
  var parser = parserInput;
@@ -93,20 +95,9 @@ var Parser = function Parser(context, imports, fileInfo) {
93
95
  index: index + currentIndex
94
96
  });
95
97
  });
96
- for (var x = 0, p = void 0, i = void 0; (p = parseList[x]); x++) {
97
- i = parser.i;
98
+ for (var x = 0, p = void 0; (p = parseList[x]); x++) {
98
99
  result = parsers[p]();
99
- if (result) {
100
- try {
101
- result._index = i + currentIndex;
102
- result._fileInfo = fileInfo;
103
- }
104
- catch (e) { }
105
- returnNodes.push(result);
106
- }
107
- else {
108
- returnNodes.push(null);
109
- }
100
+ returnNodes.push(result || null);
110
101
  }
111
102
  var endInfo = parser.end();
112
103
  if (endInfo.isFinished) {
@@ -139,11 +130,20 @@ var Parser = function Parser(context, imports, fileInfo) {
139
130
  //
140
131
  parse: function (str, callback, additionalData) {
141
132
  var root;
142
- var error = null;
133
+ var err = null;
143
134
  var globalVars;
144
135
  var modifyVars;
145
136
  var ignored;
146
137
  var preText = '';
138
+ // Optionally disable @plugin parsing
139
+ if (additionalData && additionalData.disablePluginRule) {
140
+ parsers.plugin = function () {
141
+ var dir = parserInput.$re(/^@plugin?\s+/);
142
+ if (dir) {
143
+ error('@plugin statements are not allowed when disablePluginRule is set to true');
144
+ }
145
+ };
146
+ }
147
147
  globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + "\n" : '';
148
148
  modifyVars = (additionalData && additionalData.modifyVars) ? "\n" + Parser.serializeVars(additionalData.modifyVars) : '';
149
149
  if (context.pluginManager) {
@@ -208,7 +208,7 @@ var Parser = function Parser(context, imports, fileInfo) {
208
208
  message += '. Possibly missing something';
209
209
  }
210
210
  }
211
- error = new less_error_1.default({
211
+ err = new less_error_1.default({
212
212
  type: 'Parse',
213
213
  message: message,
214
214
  index: endInfo.furthest,
@@ -216,7 +216,7 @@ var Parser = function Parser(context, imports, fileInfo) {
216
216
  }, imports);
217
217
  }
218
218
  var finish = function (e) {
219
- e = error || e || imports.error;
219
+ e = err || e || imports.error;
220
220
  if (e) {
221
221
  if (!(e instanceof less_error_1.default)) {
222
222
  e = new less_error_1.default(e, imports, fileInfo.filename);
@@ -326,7 +326,7 @@ var Parser = function Parser(context, imports, fileInfo) {
326
326
  comment: function () {
327
327
  if (parserInput.commentStore.length) {
328
328
  var comment = parserInput.commentStore.shift();
329
- return new (tree_1.default.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo);
329
+ return new (tree_1.default.Comment)(comment.text, comment.isLineComment, comment.index + currentIndex, fileInfo);
330
330
  }
331
331
  },
332
332
  //
@@ -359,7 +359,7 @@ var Parser = function Parser(context, imports, fileInfo) {
359
359
  return;
360
360
  }
361
361
  parserInput.forget();
362
- return new (tree_1.default.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo);
362
+ return new (tree_1.default.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index + currentIndex, fileInfo);
363
363
  },
364
364
  //
365
365
  // A catch-all word, such as:
@@ -389,7 +389,7 @@ var Parser = function Parser(context, imports, fileInfo) {
389
389
  return;
390
390
  }
391
391
  parserInput.save();
392
- name = parserInput.$re(/^([\w-]+|%|~|progid:[\w\.]+)\(/);
392
+ name = parserInput.$re(/^([\w-]+|%|~|progid:[\w.]+)\(/);
393
393
  if (!name) {
394
394
  parserInput.forget();
395
395
  return;
@@ -409,7 +409,7 @@ var Parser = function Parser(context, imports, fileInfo) {
409
409
  return;
410
410
  }
411
411
  parserInput.forget();
412
- return new (tree_1.default.Call)(name, args, index, fileInfo);
412
+ return new (tree_1.default.Call)(name, args, index + currentIndex, fileInfo);
413
413
  },
414
414
  //
415
415
  // Parsing rules for functions with non-standard args, e.g.:
@@ -431,7 +431,7 @@ var Parser = function Parser(context, imports, fileInfo) {
431
431
  function f(parse, stop) {
432
432
  return {
433
433
  parse: parse,
434
- stop: stop // when true - stop after parse() and return its result,
434
+ stop: stop // when true - stop after parse() and return its result,
435
435
  // otherwise continue for plain args
436
436
  };
437
437
  }
@@ -522,13 +522,13 @@ var Parser = function Parser(context, imports, fileInfo) {
522
522
  return;
523
523
  }
524
524
  value = this.quoted() || this.variable() || this.property() ||
525
- parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || '';
525
+ parserInput.$re(/^(?:(?:\\[()'"])|[^()'"])+/) || '';
526
526
  parserInput.autoCommentAbsorb = true;
527
527
  expectChar(')');
528
- return new (tree_1.default.URL)((value.value != null ||
528
+ return new (tree_1.default.URL)((value.value !== undefined ||
529
529
  value instanceof tree_1.default.Variable ||
530
530
  value instanceof tree_1.default.Property) ?
531
- value : new (tree_1.default.Anonymous)(value, index), index, fileInfo);
531
+ value : new (tree_1.default.Anonymous)(value, index), index + currentIndex, fileInfo);
532
532
  },
533
533
  //
534
534
  // A Variable entity, such as `@fink`, in
@@ -554,7 +554,7 @@ var Parser = function Parser(context, imports, fileInfo) {
554
554
  }
555
555
  }
556
556
  parserInput.forget();
557
- return new (tree_1.default.Variable)(name, index, fileInfo);
557
+ return new (tree_1.default.Variable)(name, index + currentIndex, fileInfo);
558
558
  }
559
559
  parserInput.restore();
560
560
  },
@@ -563,7 +563,7 @@ var Parser = function Parser(context, imports, fileInfo) {
563
563
  var curly;
564
564
  var index = parserInput.i;
565
565
  if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) {
566
- return new (tree_1.default.Variable)("@" + curly[1], index, fileInfo);
566
+ return new (tree_1.default.Variable)("@" + curly[1], index + currentIndex, fileInfo);
567
567
  }
568
568
  },
569
569
  //
@@ -575,7 +575,7 @@ var Parser = function Parser(context, imports, fileInfo) {
575
575
  var name;
576
576
  var index = parserInput.i;
577
577
  if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) {
578
- return new (tree_1.default.Property)(name, index, fileInfo);
578
+ return new (tree_1.default.Property)(name, index + currentIndex, fileInfo);
579
579
  }
580
580
  },
581
581
  // A property entity useing the protective {} e.g. ${prop}
@@ -583,7 +583,7 @@ var Parser = function Parser(context, imports, fileInfo) {
583
583
  var curly;
584
584
  var index = parserInput.i;
585
585
  if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) {
586
- return new (tree_1.default.Property)("$" + curly[1], index, fileInfo);
586
+ return new (tree_1.default.Property)("$" + curly[1], index + currentIndex, fileInfo);
587
587
  }
588
588
  },
589
589
  //
@@ -596,7 +596,7 @@ var Parser = function Parser(context, imports, fileInfo) {
596
596
  color: function () {
597
597
  var rgb;
598
598
  parserInput.save();
599
- if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#\[])?/))) {
599
+ if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3,4})([\w.#[])?/))) {
600
600
  if (!rgb[2]) {
601
601
  parserInput.forget();
602
602
  return new (tree_1.default.Color)(rgb[1], undefined, rgb[0]);
@@ -642,7 +642,7 @@ var Parser = function Parser(context, imports, fileInfo) {
642
642
  //
643
643
  unicodeDescriptor: function () {
644
644
  var ud;
645
- ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/);
645
+ ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(-[0-9a-fA-F?]+)?/);
646
646
  if (ud) {
647
647
  return new (tree_1.default.UnicodeDescriptor)(ud[0]);
648
648
  }
@@ -665,7 +665,7 @@ var Parser = function Parser(context, imports, fileInfo) {
665
665
  js = parserInput.$re(/^[^`]*`/);
666
666
  if (js) {
667
667
  parserInput.forget();
668
- return new (tree_1.default.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo);
668
+ return new (tree_1.default.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index + currentIndex, fileInfo);
669
669
  }
670
670
  parserInput.restore('invalid javascript definition');
671
671
  }
@@ -749,7 +749,7 @@ var Parser = function Parser(context, imports, fileInfo) {
749
749
  if (!elements) {
750
750
  error('Missing target selector for :extend().');
751
751
  }
752
- extend = new (tree_1.default.Extend)(new (tree_1.default.Selector)(elements), option, index, fileInfo);
752
+ extend = new (tree_1.default.Extend)(new (tree_1.default.Selector)(elements), option, index + currentIndex, fileInfo);
753
753
  if (extendList) {
754
754
  extendList.push(extend);
755
755
  }
@@ -825,7 +825,7 @@ var Parser = function Parser(context, imports, fileInfo) {
825
825
  }
826
826
  if (inValue || parsers.end()) {
827
827
  parserInput.forget();
828
- var mixin = new (tree_1.default.mixin.Call)(elements, args, index, fileInfo, !lookups && important);
828
+ var mixin = new (tree_1.default.mixin.Call)(elements, args, index + currentIndex, fileInfo, !lookups && important);
829
829
  if (lookups) {
830
830
  return new tree_1.default.NamespaceValue(mixin, lookups);
831
831
  }
@@ -853,7 +853,7 @@ var Parser = function Parser(context, imports, fileInfo) {
853
853
  if (!e) {
854
854
  break;
855
855
  }
856
- elem = new (tree_1.default.Element)(c, e, false, elemIndex, fileInfo);
856
+ elem = new (tree_1.default.Element)(c, e, false, elemIndex + currentIndex, fileInfo);
857
857
  if (elements) {
858
858
  elements.push(elem);
859
859
  }
@@ -1046,14 +1046,12 @@ var Parser = function Parser(context, imports, fileInfo) {
1046
1046
  },
1047
1047
  ruleLookups: function () {
1048
1048
  var rule;
1049
- var args;
1050
1049
  var lookups = [];
1051
1050
  if (parserInput.currentChar() !== '[') {
1052
1051
  return;
1053
1052
  }
1054
1053
  while (true) {
1055
1054
  parserInput.save();
1056
- args = null;
1057
1055
  rule = this.lookupValue();
1058
1056
  if (!rule && rule !== '') {
1059
1057
  parserInput.restore();
@@ -1140,9 +1138,10 @@ var Parser = function Parser(context, imports, fileInfo) {
1140
1138
  var index = parserInput.i;
1141
1139
  c = this.combinator();
1142
1140
  e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) ||
1141
+ // eslint-disable-next-line no-control-regex
1143
1142
  parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
1144
1143
  parserInput.$char('*') || parserInput.$char('&') || this.attribute() ||
1145
- parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[\.#:](?=@)/) ||
1144
+ parserInput.$re(/^\([^&()@]+\)/) || parserInput.$re(/^[.#:](?=@)/) ||
1146
1145
  this.entities.variableCurly();
1147
1146
  if (!e) {
1148
1147
  parserInput.save();
@@ -1160,7 +1159,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1160
1159
  }
1161
1160
  }
1162
1161
  if (e) {
1163
- return new (tree_1.default.Element)(c, e, e instanceof tree_1.default.Variable, index, fileInfo);
1162
+ return new (tree_1.default.Element)(c, e, e instanceof tree_1.default.Variable, index + currentIndex, fileInfo);
1164
1163
  }
1165
1164
  },
1166
1165
  //
@@ -1253,7 +1252,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1253
1252
  }
1254
1253
  }
1255
1254
  if (elements) {
1256
- return new (tree_1.default.Selector)(elements, allExtends, condition, index, fileInfo);
1255
+ return new (tree_1.default.Selector)(elements, allExtends, condition, index + currentIndex, fileInfo);
1257
1256
  }
1258
1257
  if (allExtends) {
1259
1258
  error('Extend must be used to extend a selector, it cannot be used on its own');
@@ -1275,13 +1274,13 @@ var Parser = function Parser(context, imports, fileInfo) {
1275
1274
  }
1276
1275
  parserInput.commentStore.length = 0;
1277
1276
  if (s.condition && selectors.length > 1) {
1278
- error("Guards are only currently allowed on a single selector.");
1277
+ error('Guards are only currently allowed on a single selector.');
1279
1278
  }
1280
1279
  if (!parserInput.$char(',')) {
1281
1280
  break;
1282
1281
  }
1283
1282
  if (s.condition) {
1284
- error("Guards are only currently allowed on a single selector.");
1283
+ error('Guards are only currently allowed on a single selector.');
1285
1284
  }
1286
1285
  parserInput.commentStore.length = 0;
1287
1286
  }
@@ -1295,15 +1294,23 @@ var Parser = function Parser(context, imports, fileInfo) {
1295
1294
  var key;
1296
1295
  var val;
1297
1296
  var op;
1297
+ //
1298
+ // case-insensitive flag
1299
+ // e.g. [attr operator value i]
1300
+ //
1301
+ var cif;
1298
1302
  if (!(key = entities.variableCurly())) {
1299
- key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
1303
+ key = expect(/^(?:[_A-Za-z0-9-*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
1300
1304
  }
1301
1305
  op = parserInput.$re(/^[|~*$^]?=/);
1302
1306
  if (op) {
1303
1307
  val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly();
1308
+ if (val) {
1309
+ cif = parserInput.$re(/^[iIsS]/);
1310
+ }
1304
1311
  }
1305
1312
  expectChar(']');
1306
- return new (tree_1.default.Attribute)(key, op, val);
1313
+ return new (tree_1.default.Attribute)(key, op, val, cif);
1307
1314
  },
1308
1315
  //
1309
1316
  // The `block` rule is used by `ruleset` and `mixin.definition`.
@@ -1406,7 +1413,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1406
1413
  merge = !isVariable && name.length > 1 && name.pop().value;
1407
1414
  // Custom property values get permissive parsing
1408
1415
  if (name[0].value && name[0].value.slice(0, 2) === '--') {
1409
- value = this.permissiveValue();
1416
+ value = this.permissiveValue(/[;}]/);
1410
1417
  }
1411
1418
  // Try to store values as anonymous
1412
1419
  // If we need the value later we'll re-parse it in ruleset.parseValue
@@ -1416,7 +1423,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1416
1423
  if (value) {
1417
1424
  parserInput.forget();
1418
1425
  // anonymous values absorb the end ';' which is required for them to work
1419
- return new (tree_1.default.Declaration)(name, value, false, merge, index, fileInfo);
1426
+ return new (tree_1.default.Declaration)(name, value, false, merge, index + currentIndex, fileInfo);
1420
1427
  }
1421
1428
  if (!value) {
1422
1429
  value = this.value();
@@ -1431,7 +1438,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1431
1438
  }
1432
1439
  if (value && (this.end() || hasDR)) {
1433
1440
  parserInput.forget();
1434
- return new (tree_1.default.Declaration)(name, value, important, merge, index, fileInfo);
1441
+ return new (tree_1.default.Declaration)(name, value, important, merge, index + currentIndex, fileInfo);
1435
1442
  }
1436
1443
  else {
1437
1444
  parserInput.restore();
@@ -1443,9 +1450,9 @@ var Parser = function Parser(context, imports, fileInfo) {
1443
1450
  },
1444
1451
  anonymousValue: function () {
1445
1452
  var index = parserInput.i;
1446
- var match = parserInput.$re(/^([^.#@\$+\/'"*`(;{}-]*);/);
1453
+ var match = parserInput.$re(/^([^.#@$+/'"*`(;{}-]*);/);
1447
1454
  if (match) {
1448
- return new (tree_1.default.Anonymous)(match[1], index);
1455
+ return new (tree_1.default.Anonymous)(match[1], index + currentIndex);
1449
1456
  }
1450
1457
  },
1451
1458
  /**
@@ -1550,17 +1557,17 @@ var Parser = function Parser(context, imports, fileInfo) {
1550
1557
  var path;
1551
1558
  var features;
1552
1559
  var index = parserInput.i;
1553
- var dir = parserInput.$re(/^@import?\s+/);
1560
+ var dir = parserInput.$re(/^@import\s+/);
1554
1561
  if (dir) {
1555
1562
  var options = (dir ? this.importOptions() : null) || {};
1556
1563
  if ((path = this.entities.quoted() || this.entities.url())) {
1557
- features = this.mediaFeatures();
1564
+ features = this.mediaFeatures({});
1558
1565
  if (!parserInput.$char(';')) {
1559
1566
  parserInput.i = index;
1560
1567
  error('missing semi-colon or unrecognised media features on import');
1561
1568
  }
1562
1569
  features = features && new (tree_1.default.Value)(features);
1563
- return new (tree_1.default.Import)(path, features, options, index, fileInfo);
1570
+ return new (tree_1.default.Import)(path, features, options, index + currentIndex, fileInfo);
1564
1571
  }
1565
1572
  else {
1566
1573
  parserInput.i = index;
@@ -1607,11 +1614,12 @@ var Parser = function Parser(context, imports, fileInfo) {
1607
1614
  return opt[1];
1608
1615
  }
1609
1616
  },
1610
- mediaFeature: function () {
1617
+ mediaFeature: function (syntaxOptions) {
1611
1618
  var entities = this.entities;
1612
1619
  var nodes = [];
1613
1620
  var e;
1614
1621
  var p;
1622
+ var rangeP;
1615
1623
  parserInput.save();
1616
1624
  do {
1617
1625
  e = entities.keyword() || entities.variable() || entities.mixinLookup();
@@ -1620,10 +1628,27 @@ var Parser = function Parser(context, imports, fileInfo) {
1620
1628
  }
1621
1629
  else if (parserInput.$char('(')) {
1622
1630
  p = this.property();
1623
- e = this.value();
1631
+ parserInput.save();
1632
+ if (!p && syntaxOptions.queryInParens && parserInput.$re(/^[0-9a-z-]*\s*([<>]=|<=|>=|[<>]|=)/)) {
1633
+ parserInput.restore();
1634
+ p = this.condition();
1635
+ parserInput.save();
1636
+ rangeP = this.atomicCondition(null, p.rvalue);
1637
+ if (!rangeP) {
1638
+ parserInput.restore();
1639
+ }
1640
+ }
1641
+ else {
1642
+ parserInput.restore();
1643
+ e = this.value();
1644
+ }
1624
1645
  if (parserInput.$char(')')) {
1625
- if (p && e) {
1626
- nodes.push(new (tree_1.default.Paren)(new (tree_1.default.Declaration)(p, e, null, null, parserInput.i, fileInfo, true)));
1646
+ if (p && !e) {
1647
+ nodes.push(new (tree_1.default.Paren)(new (tree_1.default.QueryInParens)(p.op, p.lvalue, p.rvalue, rangeP ? rangeP.op : null, rangeP ? rangeP.rvalue : null, p._index)));
1648
+ e = p;
1649
+ }
1650
+ else if (p && e) {
1651
+ nodes.push(new (tree_1.default.Paren)(new (tree_1.default.Declaration)(p, e, null, null, parserInput.i + currentIndex, fileInfo, true)));
1627
1652
  }
1628
1653
  else if (e) {
1629
1654
  nodes.push(new (tree_1.default.Paren)(e));
@@ -1642,12 +1667,12 @@ var Parser = function Parser(context, imports, fileInfo) {
1642
1667
  return new (tree_1.default.Expression)(nodes);
1643
1668
  }
1644
1669
  },
1645
- mediaFeatures: function () {
1670
+ mediaFeatures: function (syntaxOptions) {
1646
1671
  var entities = this.entities;
1647
1672
  var features = [];
1648
1673
  var e;
1649
1674
  do {
1650
- e = this.mediaFeature();
1675
+ e = this.mediaFeature(syntaxOptions);
1651
1676
  if (e) {
1652
1677
  features.push(e);
1653
1678
  if (!parserInput.$char(',')) {
@@ -1666,28 +1691,33 @@ var Parser = function Parser(context, imports, fileInfo) {
1666
1691
  } while (e);
1667
1692
  return features.length > 0 ? features : null;
1668
1693
  },
1669
- media: function () {
1670
- var features;
1671
- var rules;
1672
- var media;
1694
+ prepareAndGetNestableAtRule: function (treeType, index, debugInfo, syntaxOptions) {
1695
+ var features = this.mediaFeatures(syntaxOptions);
1696
+ var rules = this.block();
1697
+ if (!rules) {
1698
+ error('media definitions require block statements after any features');
1699
+ }
1700
+ parserInput.forget();
1701
+ var atRule = new (treeType)(rules, features, index + currentIndex, fileInfo);
1702
+ if (context.dumpLineNumbers) {
1703
+ atRule.debugInfo = debugInfo;
1704
+ }
1705
+ return atRule;
1706
+ },
1707
+ nestableAtRule: function () {
1673
1708
  var debugInfo;
1674
1709
  var index = parserInput.i;
1675
1710
  if (context.dumpLineNumbers) {
1676
1711
  debugInfo = getDebugInfo(index);
1677
1712
  }
1678
1713
  parserInput.save();
1679
- if (parserInput.$str('@media')) {
1680
- features = this.mediaFeatures();
1681
- rules = this.block();
1682
- if (!rules) {
1683
- error('media definitions require block statements after any features');
1714
+ if (parserInput.$peekChar('@')) {
1715
+ if (parserInput.$str('@media')) {
1716
+ return this.prepareAndGetNestableAtRule(tree_1.default.Media, index, debugInfo, atrule_syntax_1.MediaSyntaxOptions);
1684
1717
  }
1685
- parserInput.forget();
1686
- media = new (tree_1.default.Media)(rules, features, index, fileInfo);
1687
- if (context.dumpLineNumbers) {
1688
- media.debugInfo = debugInfo;
1718
+ if (parserInput.$str('@container')) {
1719
+ return this.prepareAndGetNestableAtRule(tree_1.default.Container, index, debugInfo, atrule_syntax_1.ContainerSyntaxOptions);
1689
1720
  }
1690
- return media;
1691
1721
  }
1692
1722
  parserInput.restore();
1693
1723
  },
@@ -1701,7 +1731,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1701
1731
  var args;
1702
1732
  var options;
1703
1733
  var index = parserInput.i;
1704
- var dir = parserInput.$re(/^@plugin?\s+/);
1734
+ var dir = parserInput.$re(/^@plugin\s+/);
1705
1735
  if (dir) {
1706
1736
  args = this.pluginArgs();
1707
1737
  if (args) {
@@ -1718,7 +1748,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1718
1748
  parserInput.i = index;
1719
1749
  error('missing semi-colon on @plugin');
1720
1750
  }
1721
- return new (tree_1.default.Import)(path, null, options, index, fileInfo);
1751
+ return new (tree_1.default.Import)(path, null, options, index + currentIndex, fileInfo);
1722
1752
  }
1723
1753
  else {
1724
1754
  parserInput.i = index;
@@ -1733,7 +1763,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1733
1763
  parserInput.restore();
1734
1764
  return null;
1735
1765
  }
1736
- var args = parserInput.$re(/^\s*([^\);]+)\)\s*/);
1766
+ var args = parserInput.$re(/^\s*([^);]+)\)\s*/);
1737
1767
  if (args[1]) {
1738
1768
  parserInput.forget();
1739
1769
  return args[1].trim();
@@ -1762,7 +1792,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1762
1792
  if (parserInput.currentChar() !== '@') {
1763
1793
  return;
1764
1794
  }
1765
- value = this['import']() || this.plugin() || this.media();
1795
+ value = this['import']() || this.plugin() || this.nestableAtRule();
1766
1796
  if (value) {
1767
1797
  return value;
1768
1798
  }
@@ -1827,7 +1857,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1827
1857
  }
1828
1858
  if (rules || (!hasBlock && value && parserInput.$char(';'))) {
1829
1859
  parserInput.forget();
1830
- return new (tree_1.default.AtRule)(name, value, rules, index, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted);
1860
+ return new (tree_1.default.AtRule)(name, value, rules, index + currentIndex, fileInfo, context.dumpLineNumbers ? getDebugInfo(index) : null, isRooted);
1831
1861
  }
1832
1862
  parserInput.restore('at-rule options not recognised');
1833
1863
  },
@@ -1853,7 +1883,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1853
1883
  }
1854
1884
  } while (e);
1855
1885
  if (expressions.length > 0) {
1856
- return new (tree_1.default.Value)(expressions, index);
1886
+ return new (tree_1.default.Value)(expressions, index + currentIndex);
1857
1887
  }
1858
1888
  },
1859
1889
  important: function () {
@@ -1888,7 +1918,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1888
1918
  if (m) {
1889
1919
  isSpaced = parserInput.isWhitespace(-1);
1890
1920
  while (true) {
1891
- if (parserInput.peek(/^\/[*\/]/)) {
1921
+ if (parserInput.peek(/^\/[*/]/)) {
1892
1922
  break;
1893
1923
  }
1894
1924
  parserInput.save();
@@ -1952,7 +1982,7 @@ var Parser = function Parser(context, imports, fileInfo) {
1952
1982
  if (!b) {
1953
1983
  break;
1954
1984
  }
1955
- condition = new (tree_1.default.Condition)('or', condition || a, b, index);
1985
+ condition = new (tree_1.default.Condition)('or', condition || a, b, index + currentIndex);
1956
1986
  }
1957
1987
  return condition || a;
1958
1988
  }
@@ -2059,18 +2089,22 @@ var Parser = function Parser(context, imports, fileInfo) {
2059
2089
  parserInput.forget();
2060
2090
  return body;
2061
2091
  },
2062
- atomicCondition: function (needsParens) {
2092
+ atomicCondition: function (needsParens, preparsedCond) {
2063
2093
  var entities = this.entities;
2064
2094
  var index = parserInput.i;
2065
2095
  var a;
2066
2096
  var b;
2067
2097
  var c;
2068
2098
  var op;
2069
- function cond() {
2099
+ var cond = (function () {
2070
2100
  return this.addition() || entities.keyword() || entities.quoted() || entities.mixinLookup();
2101
+ }).bind(this);
2102
+ if (preparsedCond) {
2103
+ a = preparsedCond;
2104
+ }
2105
+ else {
2106
+ a = cond();
2071
2107
  }
2072
- cond = cond.bind(this);
2073
- a = cond();
2074
2108
  if (a) {
2075
2109
  if (parserInput.$char('>')) {
2076
2110
  if (parserInput.$char('=')) {
@@ -2102,14 +2136,14 @@ var Parser = function Parser(context, imports, fileInfo) {
2102
2136
  if (op) {
2103
2137
  b = cond();
2104
2138
  if (b) {
2105
- c = new (tree_1.default.Condition)(op, a, b, index, false);
2139
+ c = new (tree_1.default.Condition)(op, a, b, index + currentIndex, false);
2106
2140
  }
2107
2141
  else {
2108
2142
  error('expected expression');
2109
2143
  }
2110
2144
  }
2111
- else {
2112
- c = new (tree_1.default.Condition)('=', a, new (tree_1.default.Keyword)('true'), index, false);
2145
+ else if (!preparsedCond) {
2146
+ c = new (tree_1.default.Condition)('=', a, new (tree_1.default.Keyword)('true'), index + currentIndex, false);
2113
2147
  }
2114
2148
  return c;
2115
2149
  }
@@ -2121,7 +2155,7 @@ var Parser = function Parser(context, imports, fileInfo) {
2121
2155
  operand: function () {
2122
2156
  var entities = this.entities;
2123
2157
  var negate;
2124
- if (parserInput.peek(/^-[@\$\(]/)) {
2158
+ if (parserInput.peek(/^-[@$(]/)) {
2125
2159
  negate = parserInput.$char('-');
2126
2160
  }
2127
2161
  var o = this.sub() || entities.dimension() ||
@@ -2160,10 +2194,10 @@ var Parser = function Parser(context, imports, fileInfo) {
2160
2194
  if (e) {
2161
2195
  entities.push(e);
2162
2196
  // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
2163
- if (!parserInput.peek(/^\/[\/*]/)) {
2197
+ if (!parserInput.peek(/^\/[/*]/)) {
2164
2198
  delim = parserInput.$char('/');
2165
2199
  if (delim) {
2166
- entities.push(new (tree_1.default.Anonymous)(delim, index));
2200
+ entities.push(new (tree_1.default.Anonymous)(delim, index + currentIndex));
2167
2201
  }
2168
2202
  }
2169
2203
  }
@@ -2200,7 +2234,7 @@ var Parser = function Parser(context, imports, fileInfo) {
2200
2234
  }
2201
2235
  match(/^(\*?)/);
2202
2236
  while (true) {
2203
- if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) {
2237
+ if (!match(/^((?:[\w-]+)|(?:[@$]\{[\w-]+\}))/)) {
2204
2238
  break;
2205
2239
  }
2206
2240
  }
@@ -2217,8 +2251,8 @@ var Parser = function Parser(context, imports, fileInfo) {
2217
2251
  name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ?
2218
2252
  new (tree_1.default.Keyword)(s) :
2219
2253
  (s.charAt(0) === '@' ?
2220
- new (tree_1.default.Variable)("@" + s.slice(2, -1), index[k], fileInfo) :
2221
- new (tree_1.default.Property)("$" + s.slice(2, -1), index[k], fileInfo));
2254
+ new (tree_1.default.Variable)("@" + s.slice(2, -1), index[k] + currentIndex, fileInfo) :
2255
+ new (tree_1.default.Property)("$" + s.slice(2, -1), index[k] + currentIndex, fileInfo));
2222
2256
  }
2223
2257
  return name;
2224
2258
  }