less 2.3.0 → 2.3.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 (268) hide show
  1. package/.idea/inspectionProfiles/Project_Default.xml +1 -0
  2. package/.idea/jsLinters/jscs.xml +4 -0
  3. package/.idea/jsLinters/jshint.xml +58 -4
  4. package/.idea/workspace.xml +427 -892
  5. package/.jscsrc +34 -2
  6. package/.jshintrc +0 -1
  7. package/CHANGELOG.md +7 -0
  8. package/bin/lessc +8 -3
  9. package/bower.json +1 -1
  10. package/dist/less.js +362 -245
  11. package/dist/less.min.js +5 -5
  12. package/lib/less/data/unit-conversions.js +3 -3
  13. package/lib/less/environment/abstract-file-manager.js +4 -4
  14. package/lib/less/functions/color-blending.js +3 -3
  15. package/lib/less/functions/color.js +7 -7
  16. package/lib/less/functions/data-uri.js +3 -2
  17. package/lib/less/functions/string.js +3 -1
  18. package/lib/less/functions/svg.js +6 -3
  19. package/lib/less/functions/types.js +3 -1
  20. package/lib/less/import-manager.js +4 -1
  21. package/lib/less/index.js +1 -1
  22. package/lib/less/parser/parser.js +12 -7
  23. package/lib/less/source-map-output.js +3 -3
  24. package/lib/less/transform-tree.js +1 -1
  25. package/lib/less/tree/condition.js +1 -1
  26. package/lib/less/tree/debug-info.js +6 -2
  27. package/lib/less/tree/dimension.js +1 -1
  28. package/lib/less/tree/directive.js +15 -3
  29. package/lib/less/tree/import.js +1 -1
  30. package/lib/less/tree/media.js +3 -2
  31. package/lib/less/tree/mixin-call.js +3 -4
  32. package/lib/less/tree/mixin-definition.js +4 -3
  33. package/lib/less/tree/quoted.js +1 -1
  34. package/lib/less/tree/rule.js +2 -3
  35. package/lib/less/tree/ruleset.js +223 -149
  36. package/lib/less/tree/selector.js +2 -1
  37. package/lib/less/tree/url.js +1 -1
  38. package/lib/less/tree/value.js +1 -1
  39. package/lib/less/tree/variable.js +1 -1
  40. package/lib/less/visitors/extend-visitor.js +30 -22
  41. package/lib/less/visitors/import-visitor.js +2 -1
  42. package/lib/less/visitors/to-css-visitor.js +5 -4
  43. package/lib/less-browser/utils.js +5 -5
  44. package/lib/less-node/file-manager.js +8 -4
  45. package/lib/less-node/url-file-manager.js +2 -2
  46. package/lib/less-rhino/index.js +2 -2
  47. package/package.json +3 -3
  48. package/test/browser/common.js +3 -3
  49. package/test/browser/jasmine-jsreporter.js +2 -2
  50. package/test/browser/less.js +29 -0
  51. package/test/copy-bom.js +14 -8
  52. package/test/css/selectors.css +9 -0
  53. package/test/index.js +1 -1
  54. package/test/less/selectors.less +18 -3
  55. package/test/less-bom/charsets.less +3 -0
  56. package/test/less-bom/colors.less +98 -0
  57. package/test/less-bom/comments.less +102 -0
  58. package/test/less-bom/comments2.less +20 -0
  59. package/test/less-bom/compression/compression.less +36 -0
  60. package/test/less-bom/css-3.less +154 -0
  61. package/test/less-bom/css-escapes.less +33 -0
  62. package/test/less-bom/css-guards.less +103 -0
  63. package/test/less-bom/css.less +108 -0
  64. package/test/less-bom/debug/import/test.less +25 -0
  65. package/test/less-bom/debug/linenumbers.less +33 -0
  66. package/test/less-bom/detached-rulesets.less +103 -0
  67. package/test/less-bom/empty.less +1 -0
  68. package/test/less-bom/errors/add-mixed-units.less +3 -0
  69. package/test/less-bom/errors/add-mixed-units.txt +4 -0
  70. package/test/less-bom/errors/add-mixed-units2.less +3 -0
  71. package/test/less-bom/errors/add-mixed-units2.txt +4 -0
  72. package/test/less-bom/errors/at-rules-undefined-var.less +4 -0
  73. package/test/less-bom/errors/at-rules-undefined-var.txt +4 -0
  74. package/test/less-bom/errors/bad-variable-declaration1.less +1 -0
  75. package/test/less-bom/errors/bad-variable-declaration1.txt +2 -0
  76. package/test/less-bom/errors/color-func-invalid-color.less +3 -0
  77. package/test/less-bom/errors/color-func-invalid-color.txt +4 -0
  78. package/test/less-bom/errors/color-invalid-hex-code.less +3 -0
  79. package/test/less-bom/errors/color-invalid-hex-code.txt +4 -0
  80. package/test/less-bom/errors/color-invalid-hex-code2.less +3 -0
  81. package/test/less-bom/errors/color-invalid-hex-code2.txt +4 -0
  82. package/test/less-bom/errors/css-guard-default-func.less +4 -0
  83. package/test/less-bom/errors/css-guard-default-func.txt +4 -0
  84. package/test/less-bom/errors/detached-ruleset-1.less +6 -0
  85. package/test/less-bom/errors/detached-ruleset-1.txt +4 -0
  86. package/test/less-bom/errors/detached-ruleset-2.less +6 -0
  87. package/test/less-bom/errors/detached-ruleset-2.txt +4 -0
  88. package/test/less-bom/errors/detached-ruleset-3.less +4 -0
  89. package/test/less-bom/errors/detached-ruleset-3.txt +4 -0
  90. package/test/less-bom/errors/detached-ruleset-4.less +5 -0
  91. package/test/less-bom/errors/detached-ruleset-4.txt +4 -0
  92. package/test/less-bom/errors/detached-ruleset-5.less +4 -0
  93. package/test/less-bom/errors/detached-ruleset-5.txt +3 -0
  94. package/test/less-bom/errors/detached-ruleset-6.less +5 -0
  95. package/test/less-bom/errors/detached-ruleset-6.txt +4 -0
  96. package/test/less-bom/errors/divide-mixed-units.less +3 -0
  97. package/test/less-bom/errors/divide-mixed-units.txt +4 -0
  98. package/test/less-bom/errors/extend-no-selector.less +3 -0
  99. package/test/less-bom/errors/extend-no-selector.txt +3 -0
  100. package/test/less-bom/errors/extend-not-at-end.less +3 -0
  101. package/test/less-bom/errors/extend-not-at-end.txt +3 -0
  102. package/test/less-bom/errors/import-malformed.less +1 -0
  103. package/test/less-bom/errors/import-malformed.txt +3 -0
  104. package/test/less-bom/errors/import-missing.less +6 -0
  105. package/test/less-bom/errors/import-missing.txt +3 -0
  106. package/test/less-bom/errors/import-no-semi.less +1 -0
  107. package/test/less-bom/errors/import-no-semi.txt +2 -0
  108. package/test/less-bom/errors/import-subfolder1.less +1 -0
  109. package/test/less-bom/errors/import-subfolder1.txt +3 -0
  110. package/test/less-bom/errors/import-subfolder2.less +1 -0
  111. package/test/less-bom/errors/import-subfolder2.txt +4 -0
  112. package/test/less-bom/errors/imports/import-subfolder1.less +1 -0
  113. package/test/less-bom/errors/imports/import-subfolder2.less +1 -0
  114. package/test/less-bom/errors/imports/import-test.less +4 -0
  115. package/test/less-bom/errors/imports/subfolder/mixin-not-defined.less +1 -0
  116. package/test/less-bom/errors/imports/subfolder/parse-error-curly-bracket.less +1 -0
  117. package/test/less-bom/errors/javascript-error.less +3 -0
  118. package/test/less-bom/errors/javascript-error.txt +4 -0
  119. package/test/less-bom/errors/javascript-undefined-var.less +3 -0
  120. package/test/less-bom/errors/javascript-undefined-var.txt +4 -0
  121. package/test/less-bom/errors/mixed-mixin-definition-args-1.less +6 -0
  122. package/test/less-bom/errors/mixed-mixin-definition-args-1.txt +4 -0
  123. package/test/less-bom/errors/mixed-mixin-definition-args-2.less +6 -0
  124. package/test/less-bom/errors/mixed-mixin-definition-args-2.txt +4 -0
  125. package/test/less-bom/errors/mixin-not-defined.less +11 -0
  126. package/test/less-bom/errors/mixin-not-defined.txt +3 -0
  127. package/test/less-bom/errors/mixin-not-matched.less +6 -0
  128. package/test/less-bom/errors/mixin-not-matched.txt +3 -0
  129. package/test/less-bom/errors/mixin-not-matched2.less +6 -0
  130. package/test/less-bom/errors/mixin-not-matched2.txt +3 -0
  131. package/test/less-bom/errors/mixin-not-visible-in-scope-1.less +9 -0
  132. package/test/less-bom/errors/mixin-not-visible-in-scope-1.txt +4 -0
  133. package/test/less-bom/errors/mixins-guards-default-func-1.less +9 -0
  134. package/test/less-bom/errors/mixins-guards-default-func-1.txt +4 -0
  135. package/test/less-bom/errors/mixins-guards-default-func-2.less +9 -0
  136. package/test/less-bom/errors/mixins-guards-default-func-2.txt +4 -0
  137. package/test/less-bom/errors/mixins-guards-default-func-3.less +9 -0
  138. package/test/less-bom/errors/mixins-guards-default-func-3.txt +4 -0
  139. package/test/less-bom/errors/multiple-guards-on-css-selectors.less +4 -0
  140. package/test/less-bom/errors/multiple-guards-on-css-selectors.txt +4 -0
  141. package/test/less-bom/errors/multiple-guards-on-css-selectors2.less +4 -0
  142. package/test/less-bom/errors/multiple-guards-on-css-selectors2.txt +4 -0
  143. package/test/less-bom/errors/multiply-mixed-units.less +7 -0
  144. package/test/less-bom/errors/multiply-mixed-units.txt +4 -0
  145. package/test/less-bom/errors/parens-error-1.less +3 -0
  146. package/test/less-bom/errors/parens-error-1.txt +4 -0
  147. package/test/less-bom/errors/parens-error-2.less +3 -0
  148. package/test/less-bom/errors/parens-error-2.txt +4 -0
  149. package/test/less-bom/errors/parens-error-3.less +3 -0
  150. package/test/less-bom/errors/parens-error-3.txt +4 -0
  151. package/test/less-bom/errors/parse-error-curly-bracket.less +4 -0
  152. package/test/less-bom/errors/parse-error-curly-bracket.txt +4 -0
  153. package/test/less-bom/errors/parse-error-extra-parens.less +5 -0
  154. package/test/less-bom/errors/parse-error-extra-parens.txt +3 -0
  155. package/test/less-bom/errors/parse-error-missing-bracket.less +2 -0
  156. package/test/less-bom/errors/parse-error-missing-bracket.txt +3 -0
  157. package/test/less-bom/errors/parse-error-missing-parens.less +5 -0
  158. package/test/less-bom/errors/parse-error-missing-parens.txt +3 -0
  159. package/test/less-bom/errors/parse-error-with-import.less +13 -0
  160. package/test/less-bom/errors/parse-error-with-import.txt +4 -0
  161. package/test/less-bom/errors/percentage-missing-space.less +3 -0
  162. package/test/less-bom/errors/percentage-missing-space.txt +4 -0
  163. package/test/less-bom/errors/property-asterisk-only-name.less +3 -0
  164. package/test/less-bom/errors/property-asterisk-only-name.txt +4 -0
  165. package/test/less-bom/errors/property-ie5-hack.less +3 -0
  166. package/test/less-bom/errors/property-ie5-hack.txt +3 -0
  167. package/test/less-bom/errors/property-in-root.less +4 -0
  168. package/test/less-bom/errors/property-in-root.txt +4 -0
  169. package/test/less-bom/errors/property-in-root2.less +1 -0
  170. package/test/less-bom/errors/property-in-root2.txt +4 -0
  171. package/test/less-bom/errors/property-in-root3.less +4 -0
  172. package/test/less-bom/errors/property-in-root3.txt +3 -0
  173. package/test/less-bom/errors/property-interp-not-defined.less +1 -0
  174. package/test/less-bom/errors/property-interp-not-defined.txt +2 -0
  175. package/test/less-bom/errors/recursive-variable.less +1 -0
  176. package/test/less-bom/errors/recursive-variable.txt +2 -0
  177. package/test/less-bom/errors/single-character.less +1 -0
  178. package/test/less-bom/errors/single-character.txt +2 -0
  179. package/test/less-bom/errors/svg-gradient1.less +3 -0
  180. package/test/less-bom/errors/svg-gradient1.txt +4 -0
  181. package/test/less-bom/errors/svg-gradient2.less +3 -0
  182. package/test/less-bom/errors/svg-gradient2.txt +4 -0
  183. package/test/less-bom/errors/svg-gradient3.less +3 -0
  184. package/test/less-bom/errors/svg-gradient3.txt +4 -0
  185. package/test/less-bom/errors/unit-function.less +3 -0
  186. package/test/less-bom/errors/unit-function.txt +4 -0
  187. package/test/less-bom/extend-chaining.less +91 -0
  188. package/test/less-bom/extend-clearfix.less +19 -0
  189. package/test/less-bom/extend-exact.less +46 -0
  190. package/test/less-bom/extend-media.less +24 -0
  191. package/test/less-bom/extend-nest.less +65 -0
  192. package/test/less-bom/extend-selector.less +99 -0
  193. package/test/less-bom/extend.less +81 -0
  194. package/test/less-bom/extract-and-length.less +133 -0
  195. package/test/less-bom/functions.less +201 -0
  196. package/test/less-bom/globalVars/extended.json +5 -0
  197. package/test/less-bom/globalVars/extended.less +10 -0
  198. package/test/less-bom/globalVars/simple.json +3 -0
  199. package/test/less-bom/globalVars/simple.less +3 -0
  200. package/test/less-bom/ie-filters.less +15 -0
  201. package/test/less-bom/import/deeper/deeper-2/url-import-2.less +3 -0
  202. package/test/less-bom/import/deeper/deeper-2/url-import.less +1 -0
  203. package/test/less-bom/import/deeper/import-once-test-a.less +1 -0
  204. package/test/less-bom/import/deeper/url-import.less +1 -0
  205. package/test/less-bom/import/import-and-relative-paths-test.less +17 -0
  206. package/test/less-bom/import/import-charset-test.less +1 -0
  207. package/test/less-bom/import/import-interpolation.less +2 -0
  208. package/test/less-bom/import/import-interpolation2.less +5 -0
  209. package/test/less-bom/import/import-once-test-c.less +6 -0
  210. package/test/less-bom/import/import-reference.less +89 -0
  211. package/test/less-bom/import/import-test-a.less +4 -0
  212. package/test/less-bom/import/import-test-b.less +8 -0
  213. package/test/less-bom/import/import-test-c.less +6 -0
  214. package/test/less-bom/import/import-test-d.css +1 -0
  215. package/test/less-bom/import/import-test-e.less +2 -0
  216. package/test/less-bom/import/import-test-f.less +5 -0
  217. package/test/less-bom/import/imports/font.less +8 -0
  218. package/test/less-bom/import/imports/logo.less +5 -0
  219. package/test/less-bom/import/interpolation-vars.less +6 -0
  220. package/test/less-bom/import/invalid-css.less +1 -0
  221. package/test/less-bom/import/urls.less +1 -0
  222. package/test/less-bom/import-inline.less +3 -0
  223. package/test/less-bom/import-interpolation.less +8 -0
  224. package/test/less-bom/import-once.less +6 -0
  225. package/test/less-bom/import-reference.less +23 -0
  226. package/test/less-bom/import.less +30 -0
  227. package/test/less-bom/include-path/include-path.less +6 -0
  228. package/test/less-bom/javascript.less +38 -0
  229. package/test/less-bom/lazy-eval.less +6 -0
  230. package/test/less-bom/legacy/legacy.less +7 -0
  231. package/test/less-bom/media.less +234 -0
  232. package/test/less-bom/merge.less +78 -0
  233. package/test/less-bom/mixins-args.less +215 -0
  234. package/test/less-bom/mixins-closure.less +26 -0
  235. package/test/less-bom/mixins-guards-default-func.less +195 -0
  236. package/test/less-bom/mixins-guards.less +271 -0
  237. package/test/less-bom/mixins-important.less +37 -0
  238. package/test/less-bom/mixins-interpolated.less +75 -0
  239. package/test/less-bom/mixins-named-args.less +36 -0
  240. package/test/less-bom/mixins-nested.less +22 -0
  241. package/test/less-bom/mixins-pattern.less +102 -0
  242. package/test/less-bom/mixins.less +145 -0
  243. package/test/less-bom/modifyVars/extended.json +5 -0
  244. package/test/less-bom/modifyVars/extended.less +11 -0
  245. package/test/less-bom/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
  246. package/test/less-bom/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
  247. package/test/less-bom/no-js-errors/no-js-errors.less +3 -0
  248. package/test/less-bom/no-js-errors/no-js-errors.txt +4 -0
  249. package/test/less-bom/no-output.less +2 -0
  250. package/test/less-bom/operations.less +62 -0
  251. package/test/less-bom/parens.less +45 -0
  252. package/test/less-bom/property-name-interp.less +56 -0
  253. package/test/less-bom/rulesets.less +30 -0
  254. package/test/less-bom/scope.less +104 -0
  255. package/test/less-bom/selectors.less +174 -0
  256. package/test/less-bom/sourcemaps/basic.json +3 -0
  257. package/test/less-bom/sourcemaps/basic.less +27 -0
  258. package/test/less-bom/sourcemaps/imported.css +7 -0
  259. package/test/less-bom/static-urls/urls.less +33 -0
  260. package/test/less-bom/strict-units/strict-units.less +4 -0
  261. package/test/less-bom/strings.less +73 -0
  262. package/test/less-bom/url-args/urls.less +63 -0
  263. package/test/less-bom/urls.less +94 -0
  264. package/test/less-bom/variables-in-at-rules.less +20 -0
  265. package/test/less-bom/variables.less +119 -0
  266. package/test/less-bom/whitespace.less +44 -0
  267. package/test/less-test.js +2 -2
  268. package/test/modify-vars.js +6 -4
@@ -2,6 +2,7 @@ var Node = require("./node"),
2
2
  Rule = require("./rule"),
3
3
  Selector = require("./selector"),
4
4
  Element = require("./element"),
5
+ Paren = require("./paren"),
5
6
  contexts = require("../contexts"),
6
7
  defaultFunc = require("../functions/default"),
7
8
  getDebugInfo = require("./debug-info");
@@ -107,7 +108,7 @@ Ruleset.prototype.eval = function (context) {
107
108
  });
108
109
  rsRules.splice.apply(rsRules, [i, 1].concat(rules));
109
110
  rsRuleCnt += rules.length - 1;
110
- i += rules.length-1;
111
+ i += rules.length - 1;
111
112
  ruleset.resetCache();
112
113
  } else if (rsRules[i].type === "RulesetCall") {
113
114
  /*jshint loopfunc:true */
@@ -120,7 +121,7 @@ Ruleset.prototype.eval = function (context) {
120
121
  });
121
122
  rsRules.splice.apply(rsRules, [i, 1].concat(rules));
122
123
  rsRuleCnt += rules.length - 1;
123
- i += rules.length-1;
124
+ i += rules.length - 1;
124
125
  ruleset.resetCache();
125
126
  }
126
127
  }
@@ -173,7 +174,7 @@ Ruleset.prototype.evalImports = function(context) {
173
174
  importRules = rules[i].eval(context);
174
175
  if (importRules && importRules.length) {
175
176
  rules.splice.apply(rules, [i, 1].concat(importRules));
176
- i+= importRules.length-1;
177
+ i+= importRules.length - 1;
177
178
  } else {
178
179
  rules.splice(i, 1, importRules);
179
180
  }
@@ -195,7 +196,7 @@ Ruleset.prototype.makeImportant = function() {
195
196
  };
196
197
  // lets you call a css selector with a guard
197
198
  Ruleset.prototype.matchCondition = function (args, context) {
198
- var lastSelector = this.selectors[this.selectors.length-1];
199
+ var lastSelector = this.selectors[this.selectors.length - 1];
199
200
  if (!lastSelector.evaldCondition) {
200
201
  return false;
201
202
  }
@@ -423,8 +424,9 @@ Ruleset.prototype.markReferenced = function () {
423
424
 
424
425
  if (this.rules) {
425
426
  for (s = 0; s < this.rules.length; s++) {
426
- if (this.rules[s].markReferenced)
427
+ if (this.rules[s].markReferenced) {
427
428
  this.rules[s].markReferenced();
429
+ }
428
430
  }
429
431
  }
430
432
  };
@@ -432,20 +434,22 @@ Ruleset.prototype.getIsReferenced = function() {
432
434
  var i, j, path, selector;
433
435
 
434
436
  if (this.paths) {
435
- for (i=0; i<this.paths.length; i++) {
437
+ for (i = 0; i < this.paths.length; i++) {
436
438
  path = this.paths[i];
437
- for (j=0; j<path.length; j++) {
438
- if (path[j].getIsReferenced && path[j].getIsReferenced())
439
+ for (j = 0; j < path.length; j++) {
440
+ if (path[j].getIsReferenced && path[j].getIsReferenced()) {
439
441
  return true;
442
+ }
440
443
  }
441
444
  }
442
445
  }
443
446
 
444
447
  if (this.selectors) {
445
- for (i=0;i<this.selectors.length;i++) {
448
+ for (i = 0; i < this.selectors.length; i++) {
446
449
  selector = this.selectors[i];
447
- if (selector.getIsReferenced && selector.getIsReferenced())
450
+ if (selector.getIsReferenced && selector.getIsReferenced()) {
448
451
  return true;
452
+ }
449
453
  }
450
454
  }
451
455
  return false;
@@ -459,175 +463,245 @@ Ruleset.prototype.joinSelectors = function (paths, context, selectors) {
459
463
 
460
464
  Ruleset.prototype.joinSelector = function (paths, context, selector) {
461
465
 
462
- var i, j, k,
463
- hasParentSelector, newSelectors, el, sel, parentSel,
464
- newSelectorPath, afterParentJoin, newJoinedSelector,
465
- newJoinedSelectorEmpty, lastSelector, currentElements,
466
- selectorsMultiplied;
467
-
468
- for (i = 0; i < selector.elements.length; i++) {
469
- el = selector.elements[i];
470
- if (el.value === '&') {
471
- hasParentSelector = true;
472
- }
473
- }
474
-
475
- if (!hasParentSelector) {
476
- if (context.length > 0) {
477
- for (i = 0; i < context.length; i++) {
478
- paths.push(context[i].concat(selector));
466
+ function createParenthesis(elementsToPak, originalElement) {
467
+ var replacementParen, j;
468
+ if (elementsToPak.length === 0) {
469
+ replacementParen = new Paren(elementsToPak[0]);
470
+ } else {
471
+ var insideParent = [];
472
+ for (j = 0; j < elementsToPak.length; j++) {
473
+ insideParent.push(new Element(null, elementsToPak[j], originalElement.index, originalElement.currentFileInfo));
479
474
  }
475
+ replacementParen = new Paren(new Selector(insideParent));
480
476
  }
481
- else {
482
- paths.push([selector]);
483
- }
484
- return;
485
- }
486
-
487
- // The paths are [[Selector]]
488
- // The first list is a list of comma separated selectors
489
- // The inner list is a list of inheritance separated selectors
490
- // e.g.
491
- // .a, .b {
492
- // .c {
493
- // }
494
- // }
495
- // == [[.a] [.c]] [[.b] [.c]]
496
- //
497
-
498
- // the elements from the current selector so far
499
- currentElements = [];
500
- // the current list of new selectors to add to the path.
501
- // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
502
- // by the parents
503
- newSelectors = [[]];
504
-
505
- for (i = 0; i < selector.elements.length; i++) {
506
- el = selector.elements[i];
507
- // non parent reference elements just get added
508
- if (el.value !== "&") {
509
- currentElements.push(el);
510
- } else {
511
- // the new list of selectors to add
512
- selectorsMultiplied = [];
477
+ return replacementParen;
478
+ }
479
+
480
+ function createSelector(containedElement, originalElement) {
481
+ var element, selector;
482
+ element = new Element(null, containedElement, originalElement.index, originalElement.currentFileInfo);
483
+ selector = new Selector([element]);
484
+ return selector;
485
+ }
486
+
487
+ // replace all parent selectors inside `inSelector` by content of `context` array
488
+ // resulting selectors are returned inside `paths` array
489
+ // returns true if `inSelector` contained at least one parent selector
490
+ function replaceParentSelector(paths, context, inSelector) {
491
+ // The paths are [[Selector]]
492
+ // The first list is a list of comma separated selectors
493
+ // The inner list is a list of inheritance separated selectors
494
+ // e.g.
495
+ // .a, .b {
496
+ // .c {
497
+ // }
498
+ // }
499
+ // == [[.a] [.c]] [[.b] [.c]]
500
+ //
501
+ var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false;
502
+ function findNestedSelector(element) {
503
+ var maybeSelector;
504
+ if (element.value.type !== 'Paren') {
505
+ return null;
506
+ }
513
507
 
514
- // merge the current list of non parent selector elements
515
- // on to the current list of selectors to add
516
- if (currentElements.length > 0) {
517
- this.mergeElementsOnToSelectors(currentElements, newSelectors);
508
+ maybeSelector = element.value.value;
509
+ if (maybeSelector.type !== 'Selector') {
510
+ return null;
518
511
  }
519
512
 
520
- // loop through our current selectors
521
- for (j = 0; j < newSelectors.length; j++) {
522
- sel = newSelectors[j];
523
- // if we don't have any parent paths, the & might be in a mixin so that it can be used
524
- // whether there are parents or not
525
- if (context.length === 0) {
526
- // the combinator used on el should now be applied to the next element instead so that
527
- // it is not lost
528
- if (sel.length > 0) {
529
- sel[0].elements = sel[0].elements.slice(0);
530
- sel[0].elements.push(new Element(el.combinator, '', el.index, el.currentFileInfo));
513
+ return maybeSelector;
514
+ }
515
+
516
+ // the elements from the current selector so far
517
+ currentElements = [];
518
+ // the current list of new selectors to add to the path.
519
+ // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
520
+ // by the parents
521
+ newSelectors = [
522
+ []
523
+ ];
524
+
525
+ for (i = 0; i < inSelector.elements.length; i++) {
526
+ el = inSelector.elements[i];
527
+ // non parent reference elements just get added
528
+ if (el.value !== "&") {
529
+ var nestedSelector = findNestedSelector(el);
530
+ if (nestedSelector != null) {
531
+ // merge the current list of non parent selector elements
532
+ // on to the current list of selectors to add
533
+ mergeElementsOnToSelectors(currentElements, newSelectors);
534
+
535
+ var nestedPaths = [], replaced, replacedNewSelectors = [];
536
+ replaced = replaceParentSelector(nestedPaths, context, nestedSelector);
537
+ hadParentSelector = hadParentSelector || replaced;
538
+ //the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
539
+ for (k = 0; k < nestedPaths.length; k++) {
540
+ var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);
541
+ addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
531
542
  }
532
- selectorsMultiplied.push(sel);
543
+ newSelectors = replacedNewSelectors;
544
+ currentElements = [];
545
+
546
+ } else {
547
+ currentElements.push(el);
533
548
  }
534
- else {
535
- // and the parent selectors
536
- for (k = 0; k < context.length; k++) {
537
- parentSel = context[k];
538
- // We need to put the current selectors
539
- // then join the last selector's elements on to the parents selectors
540
-
541
- // our new selector path
542
- newSelectorPath = [];
543
- // selectors from the parent after the join
544
- afterParentJoin = [];
545
- newJoinedSelectorEmpty = true;
546
-
547
- //construct the joined selector - if & is the first thing this will be empty,
548
- // if not newJoinedSelector will be the last set of elements in the selector
549
+
550
+ } else {
551
+ hadParentSelector = true;
552
+ // the new list of selectors to add
553
+ selectorsMultiplied = [];
554
+
555
+ // merge the current list of non parent selector elements
556
+ // on to the current list of selectors to add
557
+ mergeElementsOnToSelectors(currentElements, newSelectors);
558
+
559
+ // loop through our current selectors
560
+ for (j = 0; j < newSelectors.length; j++) {
561
+ sel = newSelectors[j];
562
+ // if we don't have any parent paths, the & might be in a mixin so that it can be used
563
+ // whether there are parents or not
564
+ if (context.length === 0) {
565
+ // the combinator used on el should now be applied to the next element instead so that
566
+ // it is not lost
549
567
  if (sel.length > 0) {
550
- newSelectorPath = sel.slice(0);
551
- lastSelector = newSelectorPath.pop();
552
- newJoinedSelector = selector.createDerived(lastSelector.elements.slice(0));
553
- newJoinedSelectorEmpty = false;
568
+ sel[0].elements.push(new Element(el.combinator, '', el.index, el.currentFileInfo));
554
569
  }
555
- else {
556
- newJoinedSelector = selector.createDerived([]);
570
+ selectorsMultiplied.push(sel);
571
+ }
572
+ else {
573
+ // and the parent selectors
574
+ for (k = 0; k < context.length; k++) {
575
+ // We need to put the current selectors
576
+ // then join the last selector's elements on to the parents selectors
577
+ var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector);
578
+ // add that to our new set of selectors
579
+ selectorsMultiplied.push(newSelectorPath);
557
580
  }
581
+ }
582
+ }
558
583
 
559
- //put together the parent selectors after the join
560
- if (parentSel.length > 1) {
561
- afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
562
- }
584
+ // our new selectors has been multiplied, so reset the state
585
+ newSelectors = selectorsMultiplied;
586
+ currentElements = [];
587
+ }
588
+ }
563
589
 
564
- if (parentSel.length > 0) {
565
- newJoinedSelectorEmpty = false;
566
-
567
- // /deep/ is a combinator that is valid without anything in front of it
568
- // so if the & does not have a combinator that is "" or " " then
569
- // and there is a combinator on the parent, then grab that.
570
- // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
571
- var combinator = el.combinator,
572
- parentEl = parentSel[0].elements[0];
573
- if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
574
- combinator = parentEl.combinator;
575
- }
576
- // join the elements so far with the first part of the parent
577
- newJoinedSelector.elements.push(new Element(combinator, parentEl.value, el.index, el.currentFileInfo));
578
- newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
579
- }
590
+ // if we have any elements left over (e.g. .a& .b == .b)
591
+ // add them on to all the current selectors
592
+ mergeElementsOnToSelectors(currentElements, newSelectors);
580
593
 
581
- if (!newJoinedSelectorEmpty) {
582
- // now add the joined selector
583
- newSelectorPath.push(newJoinedSelector);
584
- }
594
+ for (i = 0; i < newSelectors.length; i++) {
595
+ if (newSelectors[i].length > 0) {
596
+ paths.push(newSelectors[i]);
597
+ }
598
+ }
585
599
 
586
- // and the rest of the parent
587
- newSelectorPath = newSelectorPath.concat(afterParentJoin);
600
+ return hadParentSelector;
601
+ }
588
602
 
589
- // add that to our new set of selectors
590
- selectorsMultiplied.push(newSelectorPath);
591
- }
592
- }
603
+ // joins selector path from `beginningPath` with selector path in `addPath`
604
+ // `replacedElement` contains element that is being replaced by `addPath`
605
+ // returns concatenated path
606
+ function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
607
+ var newSelectorPath, lastSelector, newJoinedSelector;
608
+ // our new selector path
609
+ newSelectorPath = [];
610
+
611
+ //construct the joined selector - if & is the first thing this will be empty,
612
+ // if not newJoinedSelector will be the last set of elements in the selector
613
+ if (beginningPath.length > 0) {
614
+ newSelectorPath = beginningPath.slice(0);
615
+ lastSelector = newSelectorPath.pop();
616
+ newJoinedSelector = originalSelector.createDerived(lastSelector.elements.slice(0));
617
+ }
618
+ else {
619
+ newJoinedSelector = originalSelector.createDerived([]);
620
+ }
621
+
622
+ if (addPath.length > 0) {
623
+ // /deep/ is a combinator that is valid without anything in front of it
624
+ // so if the & does not have a combinator that is "" or " " then
625
+ // and there is a combinator on the parent, then grab that.
626
+ // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
627
+ var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0];
628
+ if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
629
+ combinator = parentEl.combinator;
593
630
  }
631
+ // join the elements so far with the first part of the parent
632
+ newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement.index, replacedElement.currentFileInfo));
633
+ newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
634
+ }
594
635
 
595
- // our new selectors has been multiplied, so reset the state
596
- newSelectors = selectorsMultiplied;
597
- currentElements = [];
636
+ // now add the joined selector - but only if it is not empty
637
+ if (newJoinedSelector.elements.length !== 0) {
638
+ newSelectorPath.push(newJoinedSelector);
598
639
  }
599
- }
600
640
 
601
- // if we have any elements left over (e.g. .a& .b == .b)
602
- // add them on to all the current selectors
603
- if (currentElements.length > 0) {
604
- this.mergeElementsOnToSelectors(currentElements, newSelectors);
641
+ //put together the parent selectors after the join (e.g. the rest of the parent)
642
+ if (addPath.length > 1) {
643
+ newSelectorPath = newSelectorPath.concat(addPath.slice(1));
644
+ }
645
+ return newSelectorPath;
605
646
  }
606
647
 
607
- for (i = 0; i < newSelectors.length; i++) {
608
- if (newSelectors[i].length > 0) {
609
- paths.push(newSelectors[i]);
648
+ // joins selector path from `beginningPath` with every selector path in `addPaths` array
649
+ // `replacedElement` contains element that is being replaced by `addPath`
650
+ // returns array with all concatenated paths
651
+ function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
652
+ var j;
653
+ for (j = 0; j < beginningPath.length; j++) {
654
+ var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
655
+ result.push(newSelectorPath);
610
656
  }
657
+ return result;
611
658
  }
612
- };
613
- Ruleset.prototype.mergeElementsOnToSelectors = function(elements, selectors) {
614
- var i, sel;
615
659
 
616
- if (selectors.length === 0) {
617
- selectors.push([ new Selector(elements) ]);
618
- return;
660
+ function mergeElementsOnToSelectors(elements, selectors) {
661
+ var i, sel;
662
+
663
+ if (elements.length === 0) {
664
+ return ;
665
+ }
666
+ if (selectors.length === 0) {
667
+ selectors.push([ new Selector(elements) ]);
668
+ return;
669
+ }
670
+
671
+ for (i = 0; i < selectors.length; i++) {
672
+ sel = selectors[i];
673
+
674
+ // if the previous thing in sel is a parent this needs to join on to it
675
+ if (sel.length > 0) {
676
+ sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
677
+ }
678
+ else {
679
+ sel.push(new Selector(elements));
680
+ }
681
+ }
619
682
  }
620
683
 
621
- for (i = 0; i < selectors.length; i++) {
622
- sel = selectors[i];
684
+ // joinSelector code follows
685
+ var i, newPaths, hadParentSelector;
686
+
687
+ newPaths = [];
688
+ hadParentSelector = replaceParentSelector(newPaths, context, selector);
623
689
 
624
- // if the previous thing in sel is a parent this needs to join on to it
625
- if (sel.length > 0) {
626
- sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
690
+ if (!hadParentSelector) {
691
+ if (context.length > 0) {
692
+ newPaths = [];
693
+ for (i = 0; i < context.length; i++) {
694
+ newPaths.push(context[i].concat(selector));
695
+ }
627
696
  }
628
697
  else {
629
- sel.push(new Selector(elements));
698
+ newPaths = [[selector]];
630
699
  }
631
700
  }
701
+
702
+ for (i = 0; i < newPaths.length; i++) {
703
+ paths.push(newPaths[i]);
704
+ }
705
+
632
706
  };
633
707
  module.exports = Ruleset;
@@ -51,8 +51,9 @@ Selector.prototype.match = function (other) {
51
51
  return olen; // return number of matched elements
52
52
  };
53
53
  Selector.prototype.CacheElements = function() {
54
- if (this._elements)
54
+ if (this._elements) {
55
55
  return;
56
+ }
56
57
 
57
58
  var elements = this.elements.map( function(v) {
58
59
  return v.combinator.value + (v.value.value || v.value);
@@ -28,7 +28,7 @@ URL.prototype.eval = function (context) {
28
28
  context.isPathRelative(val.value)) {
29
29
 
30
30
  if (!val.quote) {
31
- rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; });
31
+ rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\" + match; });
32
32
  }
33
33
  val.value = rootpath + val.value;
34
34
  }
@@ -26,7 +26,7 @@ Value.prototype.genCSS = function (context, output) {
26
26
  var i;
27
27
  for(i = 0; i < this.value.length; i++) {
28
28
  this.value[i].genCSS(context, output);
29
- if (i+1 < this.value.length) {
29
+ if (i + 1 < this.value.length) {
30
30
  output.add((context && context.compress) ? ',' : ', ');
31
31
  }
32
32
  }
@@ -27,7 +27,7 @@ Variable.prototype.eval = function (context) {
27
27
  var v = frame.variable(name);
28
28
  if (v) {
29
29
  if (v.important) {
30
- var importantScope = context.importantScope[context.importantScope.length-1];
30
+ var importantScope = context.importantScope[context.importantScope.length - 1];
31
31
  importantScope.important = v.important;
32
32
  }
33
33
  return v.value.eval(context);