less 2.4.0 → 2.5.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 (265) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +4 -0
  3. data/Gemfile +1 -1
  4. data/less.gemspec +1 -1
  5. data/lib/less/defaults.rb +3 -3
  6. data/lib/less/java_script/v8_context.rb +1 -1
  7. data/lib/less/js/.gitattributes +3 -2
  8. data/lib/less/js/.gitignore +18 -2
  9. data/lib/less/js/.jshintrc +11 -0
  10. data/lib/less/js/CHANGELOG.md +87 -2
  11. data/lib/less/js/CONTRIBUTING.md +4 -3
  12. data/lib/less/js/Gruntfile.js +290 -0
  13. data/lib/less/js/README.md +342 -12
  14. data/lib/less/js/benchmark/benchmark.less +194 -194
  15. data/lib/less/js/benchmark/less-benchmark.js +9 -10
  16. data/lib/less/js/bin/lessc +154 -12
  17. data/lib/less/js/bower.json +18 -0
  18. data/lib/less/js/build.gradle +347 -0
  19. data/lib/less/js/build/README.md +350 -0
  20. data/lib/less/js/build/browser-header.js +4 -0
  21. data/lib/less/js/build/build.yml +160 -0
  22. data/lib/less/js/build/require-rhino.js +7 -2
  23. data/lib/less/js/build/rhino-header.js +4 -0
  24. data/lib/less/js/build/rhino-modules.js +131 -0
  25. data/lib/less/js/build/tasks/.gitkeep +1 -0
  26. data/lib/less/js/dist/less-1.5.0.js +6914 -0
  27. data/lib/less/js/dist/less-1.5.0.min.js +13 -0
  28. data/lib/less/js/dist/less-1.5.1.js +6941 -0
  29. data/lib/less/js/dist/less-1.5.1.min.js +13 -0
  30. data/lib/less/js/dist/less-1.6.0.js +7485 -0
  31. data/lib/less/js/dist/less-1.6.0.min.js +16 -0
  32. data/lib/less/js/dist/less-1.6.1.js +7513 -0
  33. data/lib/less/js/dist/less-1.6.1.min.js +16 -0
  34. data/lib/less/js/dist/less-1.6.2.js +7624 -0
  35. data/lib/less/js/dist/less-1.6.2.min.js +16 -0
  36. data/lib/less/js/dist/less-rhino-1.5.1.js +6831 -0
  37. data/lib/less/js/dist/less-rhino-1.6.2.js +9017 -0
  38. data/lib/less/js/dist/lessc-rhino-1.6.2.js +449 -0
  39. data/lib/less/js/gradle/wrapper/gradle-wrapper.jar +0 -0
  40. data/lib/less/js/gradle/wrapper/gradle-wrapper.properties +6 -0
  41. data/lib/less/js/gradlew +164 -0
  42. data/lib/less/js/gradlew.bat +90 -0
  43. data/lib/less/js/lib/less/browser.js +482 -367
  44. data/lib/less/js/lib/less/colors.js +0 -1
  45. data/lib/less/js/lib/less/encoder.js +4 -0
  46. data/lib/less/js/lib/less/env.js +50 -19
  47. data/lib/less/js/lib/less/extend-visitor.js +66 -41
  48. data/lib/less/js/lib/less/functions.js +309 -104
  49. data/lib/less/js/lib/less/import-visitor.js +21 -10
  50. data/lib/less/js/lib/less/index.js +90 -68
  51. data/lib/less/js/lib/less/join-selector-visitor.js +11 -4
  52. data/lib/less/js/lib/less/lessc_helper.js +56 -45
  53. data/lib/less/js/lib/less/parser.js +830 -460
  54. data/lib/less/js/lib/less/rhino.js +380 -58
  55. data/lib/less/js/lib/less/source-map-output.js +141 -0
  56. data/lib/less/js/lib/less/to-css-visitor.js +215 -0
  57. data/lib/less/js/lib/less/tree.js +57 -5
  58. data/lib/less/js/lib/less/tree/alpha.js +13 -5
  59. data/lib/less/js/lib/less/tree/anonymous.js +11 -5
  60. data/lib/less/js/lib/less/tree/assignment.js +11 -5
  61. data/lib/less/js/lib/less/tree/call.js +19 -8
  62. data/lib/less/js/lib/less/tree/color.js +59 -36
  63. data/lib/less/js/lib/less/tree/comment.js +17 -4
  64. data/lib/less/js/lib/less/tree/condition.js +3 -3
  65. data/lib/less/js/lib/less/tree/dimension.js +161 -153
  66. data/lib/less/js/lib/less/tree/directive.js +39 -18
  67. data/lib/less/js/lib/less/tree/element.js +41 -18
  68. data/lib/less/js/lib/less/tree/expression.js +11 -5
  69. data/lib/less/js/lib/less/tree/extend.js +11 -1
  70. data/lib/less/js/lib/less/tree/import.js +34 -20
  71. data/lib/less/js/lib/less/tree/javascript.js +16 -10
  72. data/lib/less/js/lib/less/tree/keyword.js +5 -2
  73. data/lib/less/js/lib/less/tree/media.js +39 -22
  74. data/lib/less/js/lib/less/tree/mixin.js +135 -56
  75. data/lib/less/js/lib/less/tree/negative.js +4 -2
  76. data/lib/less/js/lib/less/tree/operation.js +17 -12
  77. data/lib/less/js/lib/less/tree/paren.js +5 -2
  78. data/lib/less/js/lib/less/tree/quoted.js +9 -6
  79. data/lib/less/js/lib/less/tree/rule.js +39 -21
  80. data/lib/less/js/lib/less/tree/ruleset.js +229 -145
  81. data/lib/less/js/lib/less/tree/selector.js +101 -34
  82. data/lib/less/js/lib/less/tree/unicode-descriptor.js +4 -3
  83. data/lib/less/js/lib/less/tree/url.js +33 -11
  84. data/lib/less/js/lib/less/tree/value.js +13 -6
  85. data/lib/less/js/lib/less/tree/variable.js +13 -8
  86. data/lib/less/js/lib/less/visitor.js +117 -25
  87. data/lib/less/js/lib/source-map/source-map-0.1.31.js +1933 -0
  88. data/lib/less/js/lib/source-map/source-map-footer.js +4 -0
  89. data/lib/less/js/lib/source-map/source-map-header.js +3 -0
  90. data/lib/less/js/package.json +30 -15
  91. data/lib/less/js/test/browser/common.js +131 -56
  92. data/lib/less/js/test/browser/css/global-vars/simple.css +3 -0
  93. data/lib/less/js/test/browser/css/modify-vars/simple.css +8 -0
  94. data/lib/less/js/test/browser/css/relative-urls/urls.css +8 -9
  95. data/lib/less/js/test/browser/css/rootpath-relative/urls.css +0 -1
  96. data/lib/less/js/test/browser/css/rootpath/urls.css +0 -1
  97. data/lib/less/js/test/browser/css/urls.css +18 -14
  98. data/lib/less/js/test/browser/es5.js +27 -0
  99. data/lib/less/js/test/{less/errors/color-operation-error.less → browser/less/console-errors/test-error.less} +0 -0
  100. data/lib/less/js/test/browser/less/console-errors/test-error.txt +2 -0
  101. data/lib/less/js/test/browser/less/global-vars/simple.less +3 -0
  102. data/lib/less/js/test/browser/less/modify-vars/imports/simple2.less +4 -0
  103. data/lib/less/js/test/browser/less/modify-vars/simple.less +8 -0
  104. data/lib/less/js/test/browser/less/relative-urls/urls.less +1 -1
  105. data/lib/less/js/test/browser/less/rootpath-relative/urls.less +1 -1
  106. data/lib/less/js/test/browser/less/rootpath/urls.less +1 -1
  107. data/lib/less/js/test/browser/less/urls.less +9 -1
  108. data/lib/less/js/test/browser/phantom-runner.js +112 -103
  109. data/lib/less/js/test/browser/runner-browser-options.js +42 -0
  110. data/lib/less/js/test/browser/{runner-browser.js → runner-browser-spec.js} +7 -2
  111. data/lib/less/js/test/browser/runner-console-errors.js +5 -0
  112. data/lib/less/js/test/browser/runner-errors-options.js +5 -0
  113. data/lib/less/js/test/browser/runner-errors-spec.js +4 -0
  114. data/lib/less/js/test/browser/runner-global-vars-options.js +4 -0
  115. data/lib/less/js/test/browser/runner-global-vars-spec.js +3 -0
  116. data/lib/less/js/test/browser/runner-legacy-options.js +4 -0
  117. data/lib/less/js/test/browser/{runner-legacy.js → runner-legacy-spec.js} +1 -4
  118. data/lib/less/js/test/browser/runner-main-options.js +15 -0
  119. data/lib/less/js/test/browser/runner-main-spec.js +3 -0
  120. data/lib/less/js/test/browser/runner-modify-vars-options.js +2 -0
  121. data/lib/less/js/test/browser/runner-modify-vars-spec.js +43 -0
  122. data/lib/less/js/test/browser/runner-no-js-errors-options.js +4 -0
  123. data/lib/less/js/test/browser/runner-no-js-errors-spec.js +4 -0
  124. data/lib/less/js/test/browser/runner-production-options.js +3 -0
  125. data/lib/less/js/test/browser/{runner-production.js → runner-production-spec.js} +1 -3
  126. data/lib/less/js/test/browser/runner-relative-urls-options.js +3 -0
  127. data/lib/less/js/test/browser/{runner-relative-urls.js → runner-relative-urls-spec.js} +1 -2
  128. data/lib/less/js/test/browser/runner-rootpath-options.js +3 -0
  129. data/lib/less/js/test/browser/runner-rootpath-relative-options.js +4 -0
  130. data/lib/less/js/test/browser/{runner-rootpath-relative.js → runner-rootpath-relative-spec.js} +1 -3
  131. data/lib/less/js/test/browser/{runner-rootpath.js → runner-rootpath-spec.js} +1 -2
  132. data/lib/less/js/test/browser/test-runner-template.tmpl +47 -0
  133. data/lib/less/js/test/css/colors.css +7 -0
  134. data/lib/less/js/test/css/comments.css +9 -4
  135. data/lib/less/js/test/css/compression/compression.css +3 -2
  136. data/lib/less/js/test/css/css-3.css +17 -5
  137. data/lib/less/js/test/css/css-guards.css +37 -0
  138. data/lib/less/js/test/css/debug/linenumbers-all.css +6 -0
  139. data/lib/less/js/test/css/debug/linenumbers-comments.css +5 -0
  140. data/lib/less/js/test/css/debug/linenumbers-mediaquery.css +5 -0
  141. data/lib/less/js/test/css/empty.css +0 -0
  142. data/lib/less/js/test/css/extend-chaining.css +9 -0
  143. data/lib/less/js/test/css/extend-selector.css +10 -2
  144. data/lib/less/js/test/css/extract-and-length.css +133 -0
  145. data/lib/less/js/test/css/functions.css +23 -10
  146. data/lib/less/js/test/css/globalVars/extended.css +12 -0
  147. data/lib/less/js/test/css/globalVars/simple.css +6 -0
  148. data/lib/less/js/test/css/import-inline.css +5 -0
  149. data/lib/less/js/test/css/import-once.css +12 -0
  150. data/lib/less/js/test/css/import-reference.css +49 -0
  151. data/lib/less/js/test/css/import.css +0 -2
  152. data/lib/less/js/test/css/media.css +21 -5
  153. data/lib/less/js/test/css/merge.css +26 -0
  154. data/lib/less/js/test/css/mixins-guards-default-func.css +129 -0
  155. data/lib/less/js/test/css/mixins-guards.css +6 -0
  156. data/lib/less/js/test/css/mixins-important.css +7 -0
  157. data/lib/less/js/test/css/mixins-interpolated.css +39 -0
  158. data/lib/less/js/test/css/mixins.css +20 -0
  159. data/lib/less/js/test/css/modifyVars/extended.css +9 -0
  160. data/lib/less/js/test/css/no-output.css +0 -0
  161. data/lib/less/js/test/css/parens.css +3 -0
  162. data/lib/less/js/test/css/property-name-interp.css +20 -0
  163. data/lib/less/js/test/css/selectors.css +12 -0
  164. data/lib/less/js/test/css/static-urls/urls.css +7 -4
  165. data/lib/less/js/test/css/strings.css +3 -0
  166. data/lib/less/js/test/css/url-args/urls.css +56 -0
  167. data/lib/less/js/test/css/urls.css +21 -9
  168. data/lib/less/js/test/index.js +45 -0
  169. data/lib/less/js/test/less-test.js +234 -191
  170. data/lib/less/js/test/less/colors.less +6 -0
  171. data/lib/less/js/test/less/comments.less +7 -1
  172. data/lib/less/js/test/less/compression/compression.less +21 -1
  173. data/lib/less/js/test/less/css-3.less +12 -0
  174. data/lib/less/js/test/less/css-guards.less +99 -0
  175. data/lib/less/js/test/less/debug/linenumbers.less +11 -1
  176. data/lib/less/js/test/less/empty.less +0 -0
  177. data/lib/less/js/test/less/errors/add-mixed-units.txt +4 -2
  178. data/lib/less/js/test/less/errors/add-mixed-units2.txt +4 -2
  179. data/lib/less/js/test/less/errors/color-func-invalid-color.less +3 -0
  180. data/lib/less/js/test/less/errors/color-func-invalid-color.txt +4 -0
  181. data/lib/less/js/test/less/errors/css-guard-default-func.less +4 -0
  182. data/lib/less/js/test/less/errors/css-guard-default-func.txt +4 -0
  183. data/lib/less/js/test/less/errors/import-subfolder2.txt +4 -2
  184. data/lib/less/js/test/less/errors/javascript-undefined-var.less +3 -0
  185. data/lib/less/js/test/less/errors/javascript-undefined-var.txt +4 -0
  186. data/lib/less/js/test/less/errors/mixins-guards-default-func-1.less +9 -0
  187. data/lib/less/js/test/less/errors/mixins-guards-default-func-1.txt +4 -0
  188. data/lib/less/js/test/less/errors/mixins-guards-default-func-2.less +9 -0
  189. data/lib/less/js/test/less/errors/mixins-guards-default-func-2.txt +4 -0
  190. data/lib/less/js/test/less/errors/mixins-guards-default-func-3.less +9 -0
  191. data/lib/less/js/test/less/errors/mixins-guards-default-func-3.txt +4 -0
  192. data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors.less +4 -0
  193. data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors.txt +4 -0
  194. data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors2.less +4 -0
  195. data/lib/less/js/test/less/errors/multiple-guards-on-css-selectors2.txt +4 -0
  196. data/lib/less/js/test/less/errors/parse-error-curly-bracket.less +4 -1
  197. data/lib/less/js/test/less/errors/parse-error-curly-bracket.txt +4 -2
  198. data/lib/less/js/test/less/errors/parse-error-extra-parens.less +5 -0
  199. data/lib/less/js/test/less/errors/parse-error-extra-parens.txt +3 -0
  200. data/lib/less/js/test/less/errors/parse-error-missing-bracket.txt +2 -2
  201. data/lib/less/js/test/less/errors/parse-error-missing-parens.less +5 -0
  202. data/lib/less/js/test/less/errors/parse-error-missing-parens.txt +3 -0
  203. data/lib/less/js/test/less/errors/property-asterisk-only-name.less +3 -0
  204. data/lib/less/js/test/less/errors/property-asterisk-only-name.txt +4 -0
  205. data/lib/less/js/test/less/errors/property-interp-not-defined.less +1 -0
  206. data/lib/less/js/test/less/errors/property-interp-not-defined.txt +2 -0
  207. data/lib/less/js/test/less/errors/svg-gradient1.less +3 -0
  208. data/lib/less/js/test/less/errors/svg-gradient1.txt +4 -0
  209. data/lib/less/js/test/less/errors/svg-gradient2.less +3 -0
  210. data/lib/less/js/test/less/errors/svg-gradient2.txt +4 -0
  211. data/lib/less/js/test/less/errors/svg-gradient3.less +3 -0
  212. data/lib/less/js/test/less/errors/svg-gradient3.txt +4 -0
  213. data/lib/less/js/test/less/errors/unit-function.less +3 -0
  214. data/lib/less/js/test/less/errors/unit-function.txt +4 -0
  215. data/lib/less/js/test/less/extend-chaining.less +12 -0
  216. data/lib/less/js/test/less/extend-selector.less +15 -0
  217. data/lib/less/js/test/less/extract-and-length.less +133 -0
  218. data/lib/less/js/test/less/functions.less +15 -2
  219. data/lib/less/js/test/less/globalVars/extended.json +5 -0
  220. data/lib/less/js/test/less/globalVars/extended.less +10 -0
  221. data/lib/less/js/test/less/globalVars/simple.json +3 -0
  222. data/lib/less/js/test/less/globalVars/simple.less +3 -0
  223. data/lib/less/js/test/less/import-inline.less +2 -0
  224. data/lib/less/js/test/less/import-once.less +2 -0
  225. data/lib/less/js/test/less/import-reference.less +18 -0
  226. data/lib/less/js/test/less/import/import-and-relative-paths-test.less +11 -0
  227. data/lib/less/js/test/less/import/import-reference.less +43 -0
  228. data/lib/less/js/test/less/import/import-test-f.less +5 -0
  229. data/lib/less/js/test/less/import/invalid-css.less +1 -0
  230. data/lib/less/js/test/less/media.less +25 -1
  231. data/lib/less/js/test/less/merge.less +59 -0
  232. data/lib/less/js/test/less/mixins-args.less +10 -0
  233. data/lib/less/js/test/less/mixins-guards-default-func.less +195 -0
  234. data/lib/less/js/test/less/mixins-guards.less +16 -0
  235. data/lib/less/js/test/less/mixins-important.less +4 -1
  236. data/lib/less/js/test/less/mixins-interpolated.less +69 -0
  237. data/lib/less/js/test/less/mixins.less +27 -0
  238. data/lib/less/js/test/less/modifyVars/extended.json +5 -0
  239. data/lib/less/js/test/less/modifyVars/extended.less +11 -0
  240. data/lib/less/js/test/less/no-js-errors/no-js-errors.less +3 -0
  241. data/lib/less/js/test/less/no-js-errors/no-js-errors.txt +4 -0
  242. data/lib/less/js/test/less/no-output.less +2 -0
  243. data/lib/less/js/test/less/parens.less +4 -0
  244. data/lib/less/js/test/less/property-name-interp.less +53 -0
  245. data/lib/less/js/test/less/selectors.less +13 -0
  246. data/lib/less/js/test/less/sourcemaps/basic.json +3 -0
  247. data/lib/less/js/test/less/sourcemaps/basic.less +27 -0
  248. data/lib/less/js/test/less/sourcemaps/imported.css +7 -0
  249. data/lib/less/js/test/less/strings.less +6 -0
  250. data/lib/less/js/test/less/url-args/urls.less +63 -0
  251. data/lib/less/js/test/less/urls.less +15 -0
  252. data/lib/less/js/test/rhino/test-header.js +15 -0
  253. data/lib/less/js/test/sourcemaps/basic.json +1 -0
  254. data/lib/less/js/test/sourcemaps/index.html +17 -0
  255. data/lib/less/loader.rb +48 -40
  256. data/lib/less/version.rb +1 -1
  257. data/spec/less/parser_spec.rb +15 -15
  258. metadata +146 -40
  259. data/lib/less/js/Makefile +0 -102
  260. data/lib/less/js/build/header.js +0 -9
  261. data/lib/less/js/test/browser-test-prepare.js +0 -46
  262. data/lib/less/js/test/browser/runner-errors.js +0 -5
  263. data/lib/less/js/test/browser/runner-main.js +0 -15
  264. data/lib/less/js/test/browser/template.htm +0 -10
  265. data/lib/less/js/test/less/errors/color-operation-error.txt +0 -2
@@ -9,14 +9,34 @@ tree.Ruleset = function (selectors, rules, strictImports) {
9
9
  tree.Ruleset.prototype = {
10
10
  type: "Ruleset",
11
11
  accept: function (visitor) {
12
- this.selectors = visitor.visit(this.selectors);
13
- this.rules = visitor.visit(this.rules);
12
+ if (this.paths) {
13
+ visitor.visitArray(this.paths, true);
14
+ } else if (this.selectors) {
15
+ this.selectors = visitor.visitArray(this.selectors);
16
+ }
17
+ if (this.rules && this.rules.length) {
18
+ this.rules = visitor.visitArray(this.rules);
19
+ }
14
20
  },
15
21
  eval: function (env) {
16
- var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
17
- var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
18
- var rules;
19
-
22
+ var thisSelectors = this.selectors, selectors,
23
+ selCnt, i, defaultFunc = tree.defaultFunc;
24
+ if (thisSelectors && (selCnt = thisSelectors.length)) {
25
+ selectors = [];
26
+ defaultFunc.error({
27
+ type: "Syntax",
28
+ message: "it is currently only allowed in parametric mixin guards,"
29
+ });
30
+ for (i = 0; i < selCnt; i++) {
31
+ selectors.push(thisSelectors[i].eval(env));
32
+ }
33
+ defaultFunc.reset();
34
+ }
35
+
36
+ var rules = this.rules ? this.rules.slice(0) : null,
37
+ ruleset = new(tree.Ruleset)(selectors, rules, this.strictImports),
38
+ rule, subRule;
39
+
20
40
  ruleset.originalRuleset = this;
21
41
  ruleset.root = this.root;
22
42
  ruleset.firstRoot = this.firstRoot;
@@ -27,13 +47,15 @@ tree.Ruleset.prototype = {
27
47
  }
28
48
 
29
49
  // push the current ruleset to the frames stack
30
- env.frames.unshift(ruleset);
50
+ var envFrames = env.frames;
51
+ envFrames.unshift(ruleset);
31
52
 
32
53
  // currrent selectors
33
- if (!env.selectors) {
34
- env.selectors = [];
54
+ var envSelectors = env.selectors;
55
+ if (!envSelectors) {
56
+ env.selectors = envSelectors = [];
35
57
  }
36
- env.selectors.unshift(this.selectors);
58
+ envSelectors.unshift(this.selectors);
37
59
 
38
60
  // Evaluate imports
39
61
  if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
@@ -42,18 +64,20 @@ tree.Ruleset.prototype = {
42
64
 
43
65
  // Store the frames around mixin definitions,
44
66
  // so they can be evaluated like closures when the time comes.
45
- for (var i = 0; i < ruleset.rules.length; i++) {
46
- if (ruleset.rules[i] instanceof tree.mixin.Definition) {
47
- ruleset.rules[i].frames = env.frames.slice(0);
67
+ var rsRules = ruleset.rules, rsRuleCnt = rsRules ? rsRules.length : 0;
68
+ for (i = 0; i < rsRuleCnt; i++) {
69
+ if (rsRules[i] instanceof tree.mixin.Definition) {
70
+ rsRules[i].frames = envFrames.slice(0);
48
71
  }
49
72
  }
50
-
73
+
51
74
  var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
52
75
 
53
76
  // Evaluate mixin calls.
54
- for (var i = 0; i < ruleset.rules.length; i++) {
55
- if (ruleset.rules[i] instanceof tree.mixin.Call) {
56
- rules = ruleset.rules[i].eval(env).filter(function(r) {
77
+ for (i = 0; i < rsRuleCnt; i++) {
78
+ if (rsRules[i] instanceof tree.mixin.Call) {
79
+ /*jshint loopfunc:true */
80
+ rules = rsRules[i].eval(env).filter(function(r) {
57
81
  if ((r instanceof tree.Rule) && r.variable) {
58
82
  // do not pollute the scope if the variable is
59
83
  // already there. consider returning false here
@@ -62,27 +86,44 @@ tree.Ruleset.prototype = {
62
86
  }
63
87
  return true;
64
88
  });
65
- ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules));
89
+ rsRules.splice.apply(rsRules, [i, 1].concat(rules));
90
+ rsRuleCnt += rules.length - 1;
66
91
  i += rules.length-1;
67
92
  ruleset.resetCache();
68
93
  }
69
94
  }
70
-
71
- // Evaluate everything else
72
- for (var i = 0, rule; i < ruleset.rules.length; i++) {
73
- rule = ruleset.rules[i];
74
95
 
96
+ // Evaluate everything else
97
+ for (i = 0; i < rsRules.length; i++) {
98
+ rule = rsRules[i];
75
99
  if (! (rule instanceof tree.mixin.Definition)) {
76
- ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
100
+ rsRules[i] = rule = rule.eval ? rule.eval(env) : rule;
101
+ // for rulesets, check if it is a css guard and can be removed
102
+ if (rule instanceof tree.Ruleset && rule.selectors && rule.selectors.length === 1) {
103
+ // check if it can be folded in (e.g. & where)
104
+ if (rule.selectors[0].isJustParentSelector()) {
105
+ rsRules.splice(i--, 1);
106
+ // cannot call if there is no selector, so we can just continue
107
+ if (!rule.selectors[0].evaldCondition) {
108
+ continue;
109
+ }
110
+ for(var j = 0; j < rule.rules.length; j++) {
111
+ subRule = rule.rules[j];
112
+ if (!(subRule instanceof tree.Rule) || !subRule.variable) {
113
+ rsRules.splice(++i, 0, subRule);
114
+ }
115
+ }
116
+ }
117
+ }
77
118
  }
78
119
  }
79
120
 
80
121
  // Pop the stack
81
- env.frames.shift();
82
- env.selectors.shift();
122
+ envFrames.shift();
123
+ envSelectors.shift();
83
124
 
84
125
  if (env.mediaBlocks) {
85
- for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
126
+ for (i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
86
127
  env.mediaBlocks[i].bubbleSelectors(selectors);
87
128
  }
88
129
  }
@@ -90,15 +131,17 @@ tree.Ruleset.prototype = {
90
131
  return ruleset;
91
132
  },
92
133
  evalImports: function(env) {
93
- var i, rules;
94
- for (i = 0; i < this.rules.length; i++) {
95
- if (this.rules[i] instanceof tree.Import) {
96
- rules = this.rules[i].eval(env);
97
- if (typeof rules.length === "number") {
98
- this.rules.splice.apply(this.rules, [i, 1].concat(rules));
99
- i+= rules.length-1;
134
+ var rules = this.rules, i, importRules;
135
+ if (!rules) { return; }
136
+
137
+ for (i = 0; i < rules.length; i++) {
138
+ if (rules[i] instanceof tree.Import) {
139
+ importRules = rules[i].eval(env);
140
+ if (importRules && importRules.length) {
141
+ rules.splice.apply(rules, [i, 1].concat(importRules));
142
+ i+= importRules.length-1;
100
143
  } else {
101
- this.rules.splice(i, 1, rules);
144
+ rules.splice(i, 1, importRules);
102
145
  }
103
146
  this.resetCache();
104
147
  }
@@ -116,44 +159,74 @@ tree.Ruleset.prototype = {
116
159
  matchArgs: function (args) {
117
160
  return !args || args.length === 0;
118
161
  },
162
+ // lets you call a css selector with a guard
163
+ matchCondition: function (args, env) {
164
+ var lastSelector = this.selectors[this.selectors.length-1];
165
+ if (!lastSelector.evaldCondition) {
166
+ return false;
167
+ }
168
+ if (lastSelector.condition &&
169
+ !lastSelector.condition.eval(
170
+ new(tree.evalEnv)(env,
171
+ env.frames))) {
172
+ return false;
173
+ }
174
+ return true;
175
+ },
119
176
  resetCache: function () {
120
177
  this._rulesets = null;
121
178
  this._variables = null;
122
179
  this._lookups = {};
123
180
  },
124
181
  variables: function () {
125
- if (this._variables) { return this._variables }
126
- else {
127
- return this._variables = this.rules.reduce(function (hash, r) {
182
+ if (!this._variables) {
183
+ this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) {
128
184
  if (r instanceof tree.Rule && r.variable === true) {
129
185
  hash[r.name] = r;
130
186
  }
131
187
  return hash;
132
188
  }, {});
133
189
  }
190
+ return this._variables;
134
191
  },
135
192
  variable: function (name) {
136
193
  return this.variables()[name];
137
194
  },
138
195
  rulesets: function () {
139
- return this.rules.filter(function (r) {
140
- return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
141
- });
196
+ if (!this.rules) { return null; }
197
+
198
+ var _Ruleset = tree.Ruleset, _MixinDefinition = tree.mixin.Definition,
199
+ filtRules = [], rules = this.rules, cnt = rules.length,
200
+ i, rule;
201
+
202
+ for (i = 0; i < cnt; i++) {
203
+ rule = rules[i];
204
+ if ((rule instanceof _Ruleset) || (rule instanceof _MixinDefinition)) {
205
+ filtRules.push(rule);
206
+ }
207
+ }
208
+
209
+ return filtRules;
210
+ },
211
+ prependRule: function (rule) {
212
+ var rules = this.rules;
213
+ if (rules) { rules.unshift(rule); } else { this.rules = [ rule ]; }
142
214
  },
143
215
  find: function (selector, self) {
144
216
  self = self || this;
145
- var rules = [], rule, match,
217
+ var rules = [], match,
146
218
  key = selector.toCSS();
147
219
 
148
- if (key in this._lookups) { return this._lookups[key] }
220
+ if (key in this._lookups) { return this._lookups[key]; }
149
221
 
150
222
  this.rulesets().forEach(function (rule) {
151
223
  if (rule !== self) {
152
224
  for (var j = 0; j < rule.selectors.length; j++) {
153
- if (match = selector.match(rule.selectors[j])) {
154
- if (selector.elements.length > rule.selectors[j].elements.length) {
225
+ match = selector.match(rule.selectors[j]);
226
+ if (match) {
227
+ if (selector.elements.length > match) {
155
228
  Array.prototype.push.apply(rules, rule.find(
156
- new(tree.Selector)(selector.elements.slice(1)), self));
229
+ new(tree.Selector)(selector.elements.slice(match)), self));
157
230
  } else {
158
231
  rules.push(rule);
159
232
  }
@@ -162,108 +235,119 @@ tree.Ruleset.prototype = {
162
235
  }
163
236
  }
164
237
  });
165
- return this._lookups[key] = rules;
238
+ this._lookups[key] = rules;
239
+ return rules;
166
240
  },
167
- //
168
- // Entry point for code generation
169
- //
170
- // `context` holds an array of arrays.
171
- //
172
- toCSS: function (env) {
173
- var css = [], // The CSS output
174
- rules = [], // node.Rule instances
175
- _rules = [], //
176
- rulesets = [], // node.Ruleset instances
177
- selector, // The fully rendered selector
241
+ genCSS: function (env, output) {
242
+ var i, j,
243
+ ruleNodes = [],
244
+ rulesetNodes = [],
245
+ rulesetNodeCnt,
178
246
  debugInfo, // Line number debugging
179
- rule;
247
+ rule,
248
+ path;
180
249
 
181
- // Compile rules and rulesets
182
- for (var i = 0; i < this.rules.length; i++) {
183
- rule = this.rules[i];
250
+ env.tabLevel = (env.tabLevel || 0);
184
251
 
185
- if (rule.rules || (rule instanceof tree.Media)) {
186
- rulesets.push(rule.toCSS(env));
187
- } else if (rule instanceof tree.Directive) {
188
- var cssValue = rule.toCSS(env);
189
- // Output only the first @charset definition as such - convert the others
190
- // to comments in case debug is enabled
191
- if (rule.name === "@charset") {
192
- // Only output the debug info together with subsequent @charset definitions
193
- // a comment (or @media statement) before the actual @charset directive would
194
- // be considered illegal css as it has to be on the first line
195
- if (env.charset) {
196
- if (rule.debugInfo) {
197
- rulesets.push(tree.debugInfo(env, rule));
198
- rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env));
199
- }
200
- continue;
201
- }
202
- env.charset = true;
203
- }
204
- rulesets.push(cssValue);
205
- } else if (rule instanceof tree.Comment) {
206
- if (!rule.silent) {
207
- if (this.root) {
208
- rulesets.push(rule.toCSS(env));
209
- } else {
210
- rules.push(rule.toCSS(env));
211
- }
212
- }
213
- } else {
214
- if (rule.toCSS && !rule.variable) {
215
- if (this.firstRoot && rule instanceof tree.Rule) {
216
- throw { message: "properties must be inside selector blocks, they cannot be in the root.",
217
- index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null};
218
- }
219
- rules.push(rule.toCSS(env));
220
- } else if (rule.value && !rule.variable) {
221
- rules.push(rule.value.toString());
222
- }
223
- }
224
- }
252
+ if (!this.root) {
253
+ env.tabLevel++;
254
+ }
255
+
256
+ var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
257
+ tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" "),
258
+ sep;
225
259
 
226
- // Remove last semicolon
227
- if (env.compress && rules.length) {
228
- rule = rules[rules.length - 1];
229
- if (rule.charAt(rule.length - 1) === ';') {
230
- rules[rules.length - 1] = rule.substring(0, rule.length - 1);
260
+ for (i = 0; i < this.rules.length; i++) {
261
+ rule = this.rules[i];
262
+ if (rule.rules || (rule instanceof tree.Media) || rule instanceof tree.Directive || (this.root && rule instanceof tree.Comment)) {
263
+ rulesetNodes.push(rule);
264
+ } else {
265
+ ruleNodes.push(rule);
231
266
  }
232
267
  }
233
268
 
234
- rulesets = rulesets.join('');
235
-
236
269
  // If this is the root node, we don't render
237
270
  // a selector, or {}.
238
- // Otherwise, only output if this ruleset has rules.
239
- if (this.root) {
240
- css.push(rules.join(env.compress ? '' : '\n'));
241
- } else {
242
- if (rules.length > 0) {
243
- debugInfo = tree.debugInfo(env, this);
244
- selector = this.paths.map(function (p) {
245
- return p.map(function (s) {
246
- return s.toCSS(env);
247
- }).join('').trim();
248
- }).join(env.compress ? ',' : ',\n');
249
-
250
- // Remove duplicates
251
- for (var i = rules.length - 1; i >= 0; i--) {
252
- if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) {
253
- _rules.unshift(rules[i]);
254
- }
271
+ if (!this.root) {
272
+ debugInfo = tree.debugInfo(env, this, tabSetStr);
273
+
274
+ if (debugInfo) {
275
+ output.add(debugInfo);
276
+ output.add(tabSetStr);
277
+ }
278
+
279
+ var paths = this.paths, pathCnt = paths.length,
280
+ pathSubCnt;
281
+
282
+ sep = env.compress ? ',' : (',\n' + tabSetStr);
283
+
284
+ for (i = 0; i < pathCnt; i++) {
285
+ path = paths[i];
286
+ if (!(pathSubCnt = path.length)) { continue; }
287
+ if (i > 0) { output.add(sep); }
288
+
289
+ env.firstSelector = true;
290
+ path[0].genCSS(env, output);
291
+
292
+ env.firstSelector = false;
293
+ for (j = 1; j < pathSubCnt; j++) {
294
+ path[j].genCSS(env, output);
255
295
  }
256
- rules = _rules;
296
+ }
257
297
 
258
- css.push(debugInfo + selector +
259
- (env.compress ? '{' : ' {\n ') +
260
- rules.join(env.compress ? '' : '\n ') +
261
- (env.compress ? '}' : '\n}\n'));
298
+ output.add((env.compress ? '{' : ' {\n') + tabRuleStr);
299
+ }
300
+
301
+ // Compile rules and rulesets
302
+ for (i = 0; i < ruleNodes.length; i++) {
303
+ rule = ruleNodes[i];
304
+
305
+ // @page{ directive ends up with root elements inside it, a mix of rules and rulesets
306
+ // In this instance we do not know whether it is the last property
307
+ if (i + 1 === ruleNodes.length && (!this.root || rulesetNodes.length === 0 || this.firstRoot)) {
308
+ env.lastRule = true;
309
+ }
310
+
311
+ if (rule.genCSS) {
312
+ rule.genCSS(env, output);
313
+ } else if (rule.value) {
314
+ output.add(rule.value.toString());
315
+ }
316
+
317
+ if (!env.lastRule) {
318
+ output.add(env.compress ? '' : ('\n' + tabRuleStr));
319
+ } else {
320
+ env.lastRule = false;
321
+ }
322
+ }
323
+
324
+ if (!this.root) {
325
+ output.add((env.compress ? '}' : '\n' + tabSetStr + '}'));
326
+ env.tabLevel--;
327
+ }
328
+
329
+ sep = (env.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr);
330
+ rulesetNodeCnt = rulesetNodes.length;
331
+ if (rulesetNodeCnt) {
332
+ if (ruleNodes.length && sep) { output.add(sep); }
333
+ rulesetNodes[0].genCSS(env, output);
334
+ for (i = 1; i < rulesetNodeCnt; i++) {
335
+ if (sep) { output.add(sep); }
336
+ rulesetNodes[i].genCSS(env, output);
262
337
  }
263
338
  }
264
- css.push(rulesets);
265
339
 
266
- return css.join('') + (env.compress ? '\n' : '');
340
+ if (!output.isEmpty() && !env.compress && this.firstRoot) {
341
+ output.add('\n');
342
+ }
343
+ },
344
+
345
+ toCSS: tree.toCSS,
346
+
347
+ markReferenced: function () {
348
+ for (var s = 0; s < this.selectors.length; s++) {
349
+ this.selectors[s].markReferenced();
350
+ }
267
351
  },
268
352
 
269
353
  joinSelectors: function (paths, context, selectors) {
@@ -289,7 +373,7 @@ tree.Ruleset.prototype = {
289
373
 
290
374
  if (!hasParentSelector) {
291
375
  if (context.length > 0) {
292
- for(i = 0; i < context.length; i++) {
376
+ for (i = 0; i < context.length; i++) {
293
377
  paths.push(context[i].concat(selector));
294
378
  }
295
379
  }
@@ -333,22 +417,22 @@ tree.Ruleset.prototype = {
333
417
  }
334
418
 
335
419
  // loop through our current selectors
336
- for(j = 0; j < newSelectors.length; j++) {
420
+ for (j = 0; j < newSelectors.length; j++) {
337
421
  sel = newSelectors[j];
338
422
  // if we don't have any parent paths, the & might be in a mixin so that it can be used
339
423
  // whether there are parents or not
340
- if (context.length == 0) {
424
+ if (context.length === 0) {
341
425
  // the combinator used on el should now be applied to the next element instead so that
342
426
  // it is not lost
343
427
  if (sel.length > 0) {
344
428
  sel[0].elements = sel[0].elements.slice(0);
345
- sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator, ""));
429
+ sel[0].elements.push(new(tree.Element)(el.combinator, '', el.index, el.currentFileInfo));
346
430
  }
347
431
  selectorsMultiplied.push(sel);
348
432
  }
349
433
  else {
350
434
  // and the parent selectors
351
- for(k = 0; k < context.length; k++) {
435
+ for (k = 0; k < context.length; k++) {
352
436
  parentSel = context[k];
353
437
  // We need to put the current selectors
354
438
  // then join the last selector's elements on to the parents selectors
@@ -364,11 +448,11 @@ tree.Ruleset.prototype = {
364
448
  if (sel.length > 0) {
365
449
  newSelectorPath = sel.slice(0);
366
450
  lastSelector = newSelectorPath.pop();
367
- newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList);
451
+ newJoinedSelector = selector.createDerived(lastSelector.elements.slice(0));
368
452
  newJoinedSelectorEmpty = false;
369
453
  }
370
454
  else {
371
- newJoinedSelector = new(tree.Selector)([], selector.extendList);
455
+ newJoinedSelector = selector.createDerived([]);
372
456
  }
373
457
 
374
458
  //put together the parent selectors after the join
@@ -380,7 +464,7 @@ tree.Ruleset.prototype = {
380
464
  newJoinedSelectorEmpty = false;
381
465
 
382
466
  // join the elements so far with the first part of the parent
383
- newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0));
467
+ newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, el.index, el.currentFileInfo));
384
468
  newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
385
469
  }
386
470
 
@@ -410,7 +494,7 @@ tree.Ruleset.prototype = {
410
494
  this.mergeElementsOnToSelectors(currentElements, newSelectors);
411
495
  }
412
496
 
413
- for(i = 0; i < newSelectors.length; i++) {
497
+ for (i = 0; i < newSelectors.length; i++) {
414
498
  if (newSelectors[i].length > 0) {
415
499
  paths.push(newSelectors[i]);
416
500
  }
@@ -418,19 +502,19 @@ tree.Ruleset.prototype = {
418
502
  },
419
503
 
420
504
  mergeElementsOnToSelectors: function(elements, selectors) {
421
- var i, sel, extendList;
505
+ var i, sel;
422
506
 
423
- if (selectors.length == 0) {
507
+ if (selectors.length === 0) {
424
508
  selectors.push([ new(tree.Selector)(elements) ]);
425
509
  return;
426
510
  }
427
511
 
428
- for(i = 0; i < selectors.length; i++) {
512
+ for (i = 0; i < selectors.length; i++) {
429
513
  sel = selectors[i];
430
514
 
431
515
  // if the previous thing in sel is a parent this needs to join on to it
432
516
  if (sel.length > 0) {
433
- sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList);
517
+ sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
434
518
  }
435
519
  else {
436
520
  sel.push(new(tree.Selector)(elements));