less 2.4.0 → 2.5.3

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 (405) hide show
  1. package/.idea/jsLibraryMappings.xml +7 -7
  2. package/.idea/less.js.iml +9 -16
  3. package/.idea/libraries/less_js_node_modules.xml +14 -0
  4. package/.idea/misc.xml +14 -5
  5. package/.idea/modules.xml +8 -9
  6. package/.idea/vcs.xml +6 -7
  7. package/.idea/workspace.xml +592 -806
  8. package/.jscsrc +72 -72
  9. package/.travis.yml +1 -0
  10. package/CHANGELOG.md +54 -8
  11. package/Gruntfile.js +40 -13
  12. package/README.md +2 -0
  13. package/appveyor.yml +0 -6
  14. package/bin/lessc +22 -24
  15. package/bower.json +1 -2
  16. package/dist/less-rolledup.js +8572 -0
  17. package/dist/less.js +807 -401
  18. package/dist/less.min.js +9 -8
  19. package/lib/less/contexts.js +2 -0
  20. package/lib/less/environment/abstract-file-manager.js +5 -1
  21. package/lib/less/functions/color.js +46 -12
  22. package/lib/less/functions/function-caller.js +31 -2
  23. package/lib/less/functions/function-registry.js +28 -17
  24. package/lib/less/functions/math-helper.js +16 -0
  25. package/lib/less/functions/math.js +4 -16
  26. package/lib/less/functions/number.js +7 -2
  27. package/lib/less/functions/string.js +5 -3
  28. package/lib/less/functions/svg.js +19 -11
  29. package/lib/less/functions/types.js +1 -6
  30. package/lib/less/import-manager.js +8 -3
  31. package/lib/less/index.js +1 -1
  32. package/lib/less/parser/parser-input.js +55 -54
  33. package/lib/less/parser/parser.js +168 -52
  34. package/lib/less/plugins/function-importer.js +35 -0
  35. package/lib/less/source-map-output.js +1 -2
  36. package/lib/less/tree/anonymous.js +10 -2
  37. package/lib/less/tree/color.js +4 -1
  38. package/lib/less/tree/comment.js +0 -3
  39. package/lib/less/tree/dimension.js +5 -3
  40. package/lib/less/tree/directive.js +40 -15
  41. package/lib/less/tree/expression.js +5 -0
  42. package/lib/less/tree/import.js +22 -10
  43. package/lib/less/tree/media.js +3 -23
  44. package/lib/less/tree/mixin-call.js +17 -7
  45. package/lib/less/tree/mixin-definition.js +20 -6
  46. package/lib/less/tree/rule.js +19 -1
  47. package/lib/less/tree/ruleset.js +40 -27
  48. package/lib/less/tree/selector.js +8 -1
  49. package/lib/less/visitors/extend-visitor.js +1 -4
  50. package/lib/less/visitors/import-visitor.js +17 -2
  51. package/lib/less/visitors/join-selector-visitor.js +6 -0
  52. package/lib/less/visitors/to-css-visitor.js +48 -14
  53. package/lib/less-browser/bootstrap.js +5 -6
  54. package/lib/less-browser/index.js +20 -12
  55. package/lib/less-node/image-size.js +54 -31
  56. package/lib/less-node/index.js +1 -1
  57. package/lib/less-node/lessc-helper.js +2 -2
  58. package/lib/less-rhino/index.js +12 -8
  59. package/package.json +9 -13
  60. package/test/browser/less/urls.less +7 -1
  61. package/test/browser/less.js +30 -0
  62. package/test/browser/runner-VisitorPlugin-options.js +3 -0
  63. package/test/browser/runner-VisitorPlugin.js +3 -0
  64. package/test/browser/runner-filemanagerPlugin-options.js +4 -0
  65. package/test/browser/runner-filemanagerPlugin.js +3 -0
  66. package/test/browser/runner-global-vars-options.js +2 -1
  67. package/test/browser/runner-main-options.js +11 -11
  68. package/test/browser/runner-postProcessor.js +1 -1
  69. package/test/browser/runner-postProcessorPlugin-options.js +3 -0
  70. package/test/browser/runner-postProcessorPlugin.js +3 -0
  71. package/test/browser/runner-preProcessorPlugin-options.js +3 -0
  72. package/test/browser/runner-preProcessorPlugin.js +3 -0
  73. package/test/css/comments2.css +1 -1
  74. package/test/css/compression/compression.css +1 -1
  75. package/test/css/detached-rulesets.css +5 -0
  76. package/test/css/directives-bubling.css +119 -0
  77. package/test/css/extract-and-length.css +1 -1
  78. package/test/css/filemanagerPlugin/filemanager.css +3 -0
  79. package/test/css/functions.css +17 -1
  80. package/test/css/import-reference.css +5 -1
  81. package/test/css/import.css +4 -0
  82. package/test/css/include-path/include-path.css +4 -1
  83. package/test/css/include-path-string/include-path-string.css +3 -0
  84. package/test/css/legacy/legacy.css +14 -0
  85. package/test/css/media.css +0 -1
  86. package/test/css/mixins-args.css +51 -1
  87. package/test/css/plugin.css +44 -0
  88. package/test/css/postProcessorPlugin/postProcessor.css +4 -0
  89. package/test/css/preProcessorPlugin/preProcessor.css +3 -0
  90. package/test/css/scope.css +1 -1
  91. package/test/css/strings.css +1 -1
  92. package/test/css/url-args/urls.css +5 -5
  93. package/test/css/urls.css +8 -8
  94. package/test/css/variables.css +5 -5
  95. package/test/css/visitorPlugin/visitor.css +3 -0
  96. package/test/data/image.jpg +0 -0
  97. package/test/data/image.svg +2 -1
  98. package/test/data/page.html +1 -1
  99. package/test/index.js +5 -0
  100. package/test/less/detached-rulesets.less +9 -0
  101. package/test/less/directives-bubling.less +142 -0
  102. package/test/less/errors/at-rules-undefined-var.txt +4 -4
  103. package/test/less/errors/css-guard-default-func.txt +4 -4
  104. package/test/less/errors/javascript-undefined-var.txt +4 -4
  105. package/test/less/errors/mixins-guards-default-func-1.txt +4 -4
  106. package/test/less/errors/mixins-guards-default-func-2.txt +4 -4
  107. package/test/less/errors/mixins-guards-default-func-3.txt +4 -4
  108. package/test/less/errors/{parse-error-extra-parens.less → parse-error-media-no-block-1.less} +0 -0
  109. package/test/less/errors/parse-error-media-no-block-1.txt +3 -0
  110. package/test/less/errors/parse-error-media-no-block-2.less +1 -0
  111. package/test/less/errors/parse-error-media-no-block-2.txt +2 -0
  112. package/test/less/errors/parse-error-media-no-block-3.less +4 -0
  113. package/test/less/errors/parse-error-media-no-block-3.txt +3 -0
  114. package/test/less/errors/percentage-non-number-argument.less +3 -0
  115. package/test/less/errors/percentage-non-number-argument.txt +4 -0
  116. package/test/less/errors/property-interp-not-defined.txt +2 -2
  117. package/test/less/errors/svg-gradient2.txt +1 -1
  118. package/test/less/errors/svg-gradient3.txt +1 -1
  119. package/test/less/errors/svg-gradient4.less +4 -0
  120. package/test/less/errors/svg-gradient4.txt +4 -0
  121. package/test/less/errors/svg-gradient5.less +4 -0
  122. package/test/less/errors/svg-gradient5.txt +4 -0
  123. package/test/less/errors/svg-gradient6.less +4 -0
  124. package/test/less/errors/svg-gradient6.txt +4 -0
  125. package/test/less/filemanagerPlugin/colors.test +1 -0
  126. package/test/less/filemanagerPlugin/filemanager.less +4 -0
  127. package/test/less/functions.less +20 -2
  128. package/test/less/import/css-import.less +1 -0
  129. package/test/less/import/import-inline-invalid-css.less +1 -0
  130. package/test/less/import/import-reference.less +10 -1
  131. package/test/less/import/import-test-a.less +1 -0
  132. package/test/less/import-reference.less +4 -1
  133. package/test/less/import.less +1 -0
  134. package/test/less/include-path/include-path.less +3 -1
  135. package/test/less/include-path-string/include-path-string.less +3 -0
  136. package/test/less/legacy/legacy.less +14 -0
  137. package/test/less/mixins-args.less +48 -0
  138. package/test/less/mixins-guards.less +9 -0
  139. package/test/less/no-output.less +1 -1
  140. package/test/less/plugin/plugin-global.js +9 -0
  141. package/test/less/plugin/plugin-local.js +8 -0
  142. package/test/less/plugin/plugin-transitive.js +5 -0
  143. package/test/less/plugin/plugin-transitive.less +5 -0
  144. package/test/less/plugin.less +85 -0
  145. package/test/less/postProcessorPlugin/postProcessor.less +4 -0
  146. package/test/less/preProcessorPlugin/preProcessor.less +3 -0
  147. package/test/less/sourcemaps/imported.css +6 -6
  148. package/test/less/visitorPlugin/visitor.less +4 -0
  149. package/test/less-bom/charsets.less +3 -0
  150. package/test/less-bom/colors.less +98 -0
  151. package/test/less-bom/comments.less +102 -0
  152. package/test/less-bom/comments2.less +20 -0
  153. package/test/less-bom/compression/compression.less +36 -0
  154. package/test/less-bom/css-3.less +154 -0
  155. package/test/less-bom/css-escapes.less +33 -0
  156. package/test/less-bom/css-guards.less +103 -0
  157. package/test/less-bom/css.less +108 -0
  158. package/test/less-bom/debug/import/test.less +25 -0
  159. package/test/less-bom/debug/linenumbers.less +33 -0
  160. package/test/less-bom/detached-rulesets.less +112 -0
  161. package/test/less-bom/directives-bubling.less +142 -0
  162. package/test/less-bom/empty.less +1 -0
  163. package/test/less-bom/errors/add-mixed-units.less +3 -0
  164. package/test/less-bom/errors/add-mixed-units.txt +4 -0
  165. package/test/less-bom/errors/add-mixed-units2.less +3 -0
  166. package/test/less-bom/errors/add-mixed-units2.txt +4 -0
  167. package/test/less-bom/errors/at-rules-undefined-var.less +4 -0
  168. package/test/less-bom/errors/at-rules-undefined-var.txt +4 -0
  169. package/test/less-bom/errors/bad-variable-declaration1.less +1 -0
  170. package/test/less-bom/errors/bad-variable-declaration1.txt +2 -0
  171. package/test/less-bom/errors/color-func-invalid-color.less +3 -0
  172. package/test/less-bom/errors/color-func-invalid-color.txt +4 -0
  173. package/test/less-bom/errors/color-invalid-hex-code.less +3 -0
  174. package/test/less-bom/errors/color-invalid-hex-code.txt +4 -0
  175. package/test/less-bom/errors/color-invalid-hex-code2.less +3 -0
  176. package/test/less-bom/errors/color-invalid-hex-code2.txt +4 -0
  177. package/test/less-bom/errors/css-guard-default-func.less +4 -0
  178. package/test/less-bom/errors/css-guard-default-func.txt +4 -0
  179. package/test/less-bom/errors/detached-ruleset-1.less +6 -0
  180. package/test/less-bom/errors/detached-ruleset-1.txt +4 -0
  181. package/test/less-bom/errors/detached-ruleset-2.less +6 -0
  182. package/test/less-bom/errors/detached-ruleset-2.txt +4 -0
  183. package/test/less-bom/errors/detached-ruleset-3.less +4 -0
  184. package/test/less-bom/errors/detached-ruleset-3.txt +4 -0
  185. package/test/less-bom/errors/detached-ruleset-5.less +4 -0
  186. package/test/less-bom/errors/detached-ruleset-5.txt +3 -0
  187. package/test/less-bom/errors/detached-ruleset-6.less +5 -0
  188. package/test/less-bom/errors/detached-ruleset-6.txt +4 -0
  189. package/test/less-bom/errors/divide-mixed-units.less +3 -0
  190. package/test/less-bom/errors/divide-mixed-units.txt +4 -0
  191. package/test/less-bom/errors/extend-no-selector.less +3 -0
  192. package/test/less-bom/errors/extend-no-selector.txt +3 -0
  193. package/test/less-bom/errors/extend-not-at-end.less +3 -0
  194. package/test/less-bom/errors/extend-not-at-end.txt +3 -0
  195. package/test/less-bom/errors/import-malformed.less +1 -0
  196. package/test/less-bom/errors/import-malformed.txt +3 -0
  197. package/test/less-bom/errors/import-missing.less +6 -0
  198. package/test/less-bom/errors/import-missing.txt +3 -0
  199. package/test/less-bom/errors/import-no-semi.less +1 -0
  200. package/test/less-bom/errors/import-no-semi.txt +2 -0
  201. package/test/less-bom/errors/import-subfolder1.less +1 -0
  202. package/test/less-bom/errors/import-subfolder1.txt +3 -0
  203. package/test/less-bom/errors/import-subfolder2.less +1 -0
  204. package/test/less-bom/errors/import-subfolder2.txt +4 -0
  205. package/test/less-bom/errors/imports/import-subfolder1.less +1 -0
  206. package/test/less-bom/errors/imports/import-subfolder2.less +1 -0
  207. package/test/less-bom/errors/imports/import-test.less +4 -0
  208. package/test/less-bom/errors/imports/subfolder/mixin-not-defined.less +1 -0
  209. package/test/less-bom/errors/imports/subfolder/parse-error-curly-bracket.less +1 -0
  210. package/test/less-bom/errors/javascript-error.less +3 -0
  211. package/test/less-bom/errors/javascript-error.txt +4 -0
  212. package/test/less-bom/errors/javascript-undefined-var.less +3 -0
  213. package/test/less-bom/errors/javascript-undefined-var.txt +4 -0
  214. package/test/less-bom/errors/mixed-mixin-definition-args-1.less +6 -0
  215. package/test/less-bom/errors/mixed-mixin-definition-args-1.txt +4 -0
  216. package/test/less-bom/errors/mixed-mixin-definition-args-2.less +6 -0
  217. package/test/less-bom/errors/mixed-mixin-definition-args-2.txt +4 -0
  218. package/test/less-bom/errors/mixin-not-defined.less +11 -0
  219. package/test/less-bom/errors/mixin-not-defined.txt +3 -0
  220. package/test/less-bom/errors/mixin-not-matched.less +6 -0
  221. package/test/less-bom/errors/mixin-not-matched.txt +3 -0
  222. package/test/less-bom/errors/mixin-not-matched2.less +6 -0
  223. package/test/less-bom/errors/mixin-not-matched2.txt +3 -0
  224. package/test/less-bom/errors/mixin-not-visible-in-scope-1.less +9 -0
  225. package/test/less-bom/errors/mixin-not-visible-in-scope-1.txt +4 -0
  226. package/test/less-bom/errors/mixins-guards-default-func-1.less +9 -0
  227. package/test/less-bom/errors/mixins-guards-default-func-1.txt +4 -0
  228. package/test/less-bom/errors/mixins-guards-default-func-2.less +9 -0
  229. package/test/less-bom/errors/mixins-guards-default-func-2.txt +4 -0
  230. package/test/less-bom/errors/mixins-guards-default-func-3.less +9 -0
  231. package/test/less-bom/errors/mixins-guards-default-func-3.txt +4 -0
  232. package/test/less-bom/errors/multiple-guards-on-css-selectors.less +4 -0
  233. package/test/less-bom/errors/multiple-guards-on-css-selectors.txt +4 -0
  234. package/test/less-bom/errors/multiple-guards-on-css-selectors2.less +4 -0
  235. package/test/less-bom/errors/multiple-guards-on-css-selectors2.txt +4 -0
  236. package/test/less-bom/errors/multiply-mixed-units.less +7 -0
  237. package/test/less-bom/errors/multiply-mixed-units.txt +4 -0
  238. package/test/less-bom/errors/parens-error-1.less +3 -0
  239. package/test/less-bom/errors/parens-error-1.txt +4 -0
  240. package/test/less-bom/errors/parens-error-2.less +3 -0
  241. package/test/less-bom/errors/parens-error-2.txt +4 -0
  242. package/test/less-bom/errors/parens-error-3.less +3 -0
  243. package/test/less-bom/errors/parens-error-3.txt +4 -0
  244. package/test/less-bom/errors/parse-error-curly-bracket.less +4 -0
  245. package/test/less-bom/errors/parse-error-curly-bracket.txt +4 -0
  246. package/test/less-bom/errors/parse-error-media-no-block-1.less +5 -0
  247. package/test/less-bom/errors/parse-error-media-no-block-1.txt +3 -0
  248. package/test/less-bom/errors/parse-error-media-no-block-2.less +1 -0
  249. package/test/less-bom/errors/parse-error-media-no-block-2.txt +2 -0
  250. package/test/less-bom/errors/parse-error-media-no-block-3.less +4 -0
  251. package/test/less-bom/errors/parse-error-media-no-block-3.txt +3 -0
  252. package/test/less-bom/errors/parse-error-missing-bracket.less +2 -0
  253. package/test/less-bom/errors/parse-error-missing-bracket.txt +3 -0
  254. package/test/less-bom/errors/parse-error-missing-parens.less +5 -0
  255. package/test/less-bom/errors/parse-error-missing-parens.txt +3 -0
  256. package/test/less-bom/errors/parse-error-with-import.less +13 -0
  257. package/test/less-bom/errors/parse-error-with-import.txt +4 -0
  258. package/test/less-bom/errors/percentage-missing-space.less +3 -0
  259. package/test/less-bom/errors/percentage-missing-space.txt +4 -0
  260. package/test/less-bom/errors/percentage-non-number-argument.less +3 -0
  261. package/test/less-bom/errors/percentage-non-number-argument.txt +4 -0
  262. package/test/less-bom/errors/property-asterisk-only-name.less +3 -0
  263. package/test/less-bom/errors/property-asterisk-only-name.txt +4 -0
  264. package/test/less-bom/errors/property-ie5-hack.less +3 -0
  265. package/test/less-bom/errors/property-ie5-hack.txt +3 -0
  266. package/test/less-bom/errors/property-in-root.less +4 -0
  267. package/test/less-bom/errors/property-in-root.txt +4 -0
  268. package/test/less-bom/errors/property-in-root2.less +1 -0
  269. package/test/less-bom/errors/property-in-root2.txt +4 -0
  270. package/test/less-bom/errors/property-in-root3.less +4 -0
  271. package/test/less-bom/errors/property-in-root3.txt +3 -0
  272. package/test/less-bom/errors/property-interp-not-defined.less +1 -0
  273. package/test/less-bom/errors/property-interp-not-defined.txt +2 -0
  274. package/test/less-bom/errors/recursive-variable.less +1 -0
  275. package/test/less-bom/errors/recursive-variable.txt +2 -0
  276. package/test/less-bom/errors/single-character.less +1 -0
  277. package/test/less-bom/errors/single-character.txt +2 -0
  278. package/test/less-bom/errors/svg-gradient1.less +3 -0
  279. package/test/less-bom/errors/svg-gradient1.txt +4 -0
  280. package/test/less-bom/errors/svg-gradient2.less +3 -0
  281. package/test/less-bom/errors/svg-gradient2.txt +4 -0
  282. package/test/less-bom/errors/svg-gradient3.less +3 -0
  283. package/test/less-bom/errors/svg-gradient3.txt +4 -0
  284. package/test/less-bom/errors/svg-gradient4.less +4 -0
  285. package/test/less-bom/errors/svg-gradient4.txt +4 -0
  286. package/test/less-bom/errors/svg-gradient5.less +4 -0
  287. package/test/less-bom/errors/svg-gradient5.txt +4 -0
  288. package/test/less-bom/errors/svg-gradient6.less +4 -0
  289. package/test/less-bom/errors/svg-gradient6.txt +4 -0
  290. package/test/less-bom/errors/unit-function.less +3 -0
  291. package/test/less-bom/errors/unit-function.txt +4 -0
  292. package/test/less-bom/extend-chaining.less +91 -0
  293. package/test/less-bom/extend-clearfix.less +19 -0
  294. package/test/less-bom/extend-exact.less +46 -0
  295. package/test/less-bom/extend-media.less +24 -0
  296. package/test/less-bom/extend-nest.less +65 -0
  297. package/test/less-bom/extend-selector.less +99 -0
  298. package/test/less-bom/extend.less +81 -0
  299. package/test/less-bom/extract-and-length.less +133 -0
  300. package/test/less-bom/filemanagerPlugin/colors.test +1 -0
  301. package/test/less-bom/filemanagerPlugin/filemanager.less +4 -0
  302. package/test/less-bom/functions.less +232 -0
  303. package/test/less-bom/globalVars/extended.json +5 -0
  304. package/test/less-bom/globalVars/extended.less +10 -0
  305. package/test/less-bom/globalVars/simple.json +3 -0
  306. package/test/less-bom/globalVars/simple.less +3 -0
  307. package/test/less-bom/ie-filters.less +15 -0
  308. package/test/less-bom/import/css-import.less +1 -0
  309. package/test/less-bom/import/deeper/deeper-2/url-import-2.less +3 -0
  310. package/test/less-bom/import/deeper/deeper-2/url-import.less +1 -0
  311. package/test/less-bom/import/deeper/import-once-test-a.less +1 -0
  312. package/test/less-bom/import/deeper/url-import.less +1 -0
  313. package/test/less-bom/import/import-and-relative-paths-test.less +17 -0
  314. package/test/less-bom/import/import-charset-test.less +1 -0
  315. package/test/less-bom/import/import-inline-invalid-css.less +1 -0
  316. package/test/less-bom/import/import-interpolation.less +2 -0
  317. package/test/less-bom/import/import-interpolation2.less +5 -0
  318. package/test/less-bom/import/import-once-test-c.less +6 -0
  319. package/test/less-bom/import/import-reference.less +98 -0
  320. package/test/less-bom/import/import-test-a.less +5 -0
  321. package/test/less-bom/import/import-test-b.less +8 -0
  322. package/test/less-bom/import/import-test-c.less +6 -0
  323. package/test/less-bom/import/import-test-d.css +1 -0
  324. package/test/less-bom/import/import-test-e.less +2 -0
  325. package/test/less-bom/import/import-test-f.less +5 -0
  326. package/test/less-bom/import/imports/font.less +8 -0
  327. package/test/less-bom/import/imports/logo.less +6 -0
  328. package/test/less-bom/import/interpolation-vars.less +6 -0
  329. package/test/less-bom/import/invalid-css.less +1 -0
  330. package/test/less-bom/import/urls.less +1 -0
  331. package/test/less-bom/import-inline.less +3 -0
  332. package/test/less-bom/import-interpolation.less +8 -0
  333. package/test/less-bom/import-once.less +6 -0
  334. package/test/less-bom/import-reference.less +26 -0
  335. package/test/less-bom/import.less +31 -0
  336. package/test/less-bom/include-path/include-path.less +8 -0
  337. package/test/less-bom/include-path-string/include-path-string.less +3 -0
  338. package/test/less-bom/javascript.less +38 -0
  339. package/test/less-bom/lazy-eval.less +6 -0
  340. package/test/less-bom/legacy/legacy.less +21 -0
  341. package/test/less-bom/media.less +234 -0
  342. package/test/less-bom/merge.less +78 -0
  343. package/test/less-bom/mixins-args.less +263 -0
  344. package/test/less-bom/mixins-closure.less +26 -0
  345. package/test/less-bom/mixins-guards-default-func.less +195 -0
  346. package/test/less-bom/mixins-guards.less +280 -0
  347. package/test/less-bom/mixins-important.less +53 -0
  348. package/test/less-bom/mixins-interpolated.less +75 -0
  349. package/test/less-bom/mixins-named-args.less +36 -0
  350. package/test/less-bom/mixins-nested.less +22 -0
  351. package/test/less-bom/mixins-pattern.less +102 -0
  352. package/test/less-bom/mixins.less +145 -0
  353. package/test/less-bom/modifyVars/extended.json +5 -0
  354. package/test/less-bom/modifyVars/extended.less +11 -0
  355. package/test/less-bom/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
  356. package/test/less-bom/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
  357. package/test/less-bom/no-js-errors/no-js-errors.less +3 -0
  358. package/test/less-bom/no-js-errors/no-js-errors.txt +4 -0
  359. package/test/less-bom/no-output.less +2 -0
  360. package/test/less-bom/operations.less +62 -0
  361. package/test/less-bom/parens.less +45 -0
  362. package/test/less-bom/plugin/plugin-global.js +9 -0
  363. package/test/less-bom/plugin/plugin-local.js +8 -0
  364. package/test/less-bom/plugin/plugin-transitive.js +5 -0
  365. package/test/less-bom/plugin/plugin-transitive.less +5 -0
  366. package/test/less-bom/plugin.less +85 -0
  367. package/test/less-bom/postProcessorPlugin/postProcessor.less +4 -0
  368. package/test/less-bom/preProcessorPlugin/preProcessor.less +3 -0
  369. package/test/less-bom/property-name-interp.less +56 -0
  370. package/test/less-bom/rulesets.less +30 -0
  371. package/test/less-bom/scope.less +104 -0
  372. package/test/less-bom/selectors.less +184 -0
  373. package/test/less-bom/sourcemaps/basic.json +3 -0
  374. package/test/less-bom/sourcemaps/basic.less +27 -0
  375. package/test/less-bom/sourcemaps/imported.css +7 -0
  376. package/test/less-bom/sourcemaps-empty/empty.less +1 -0
  377. package/test/less-bom/sourcemaps-empty/var-defs.less +1 -0
  378. package/test/less-bom/static-urls/urls.less +33 -0
  379. package/test/less-bom/strict-units/strict-units.less +4 -0
  380. package/test/less-bom/strings.less +73 -0
  381. package/test/less-bom/url-args/urls.less +63 -0
  382. package/test/less-bom/urls.less +94 -0
  383. package/test/less-bom/variables-in-at-rules.less +20 -0
  384. package/test/less-bom/variables.less +119 -0
  385. package/test/less-bom/visitorPlugin/visitor.less +4 -0
  386. package/test/less-bom/whitespace.less +44 -0
  387. package/test/less-test.js +9 -5
  388. package/test/plugins/filemanager/index.js +19 -0
  389. package/test/plugins/postprocess/index.js +14 -0
  390. package/test/plugins/preprocess/index.js +19 -0
  391. package/test/plugins/visitor/index.js +24 -0
  392. package/test.less +1 -0
  393. package/.idea/codeStyleSettings.xml +0 -13
  394. package/.idea/encodings.xml +0 -5
  395. package/.idea/inspectionProfiles/Project_Default.xml +0 -8
  396. package/.idea/inspectionProfiles/profiles_settings.xml +0 -7
  397. package/.idea/jsLinters/jscs.xml +0 -4
  398. package/.idea/jsLinters/jshint.xml +0 -70
  399. package/.idea/libraries/sass_stdlib.xml +0 -8
  400. package/.idea/scopes/scope_settings.xml +0 -5
  401. package/projectFilesBackup/.idea/libraries/sass_stdlib.xml +0 -8
  402. package/test/less/errors/detached-ruleset-4.less +0 -5
  403. package/test/less/errors/detached-ruleset-4.txt +0 -4
  404. package/test/less/errors/parse-error-extra-parens.txt +0 -3
  405. package/test/sourcemaps/maps/import-map.map +0 -1
@@ -1,17 +1,28 @@
1
1
  var Node = require("./node"),
2
+ Selector = require("./selector"),
2
3
  Ruleset = require("./ruleset");
3
4
 
4
- var Directive = function (name, value, rules, index, currentFileInfo, debugInfo, isReferenced) {
5
+ var Directive = function (name, value, rules, index, currentFileInfo, debugInfo, isReferenced, isRooted) {
6
+ var i;
7
+
5
8
  this.name = name;
6
9
  this.value = value;
7
10
  if (rules) {
8
- this.rules = rules;
9
- this.rules.allowImports = true;
11
+ if (Array.isArray(rules)) {
12
+ this.rules = rules;
13
+ } else {
14
+ this.rules = [rules];
15
+ this.rules[0].selectors = (new Selector([], null, null, this.index, currentFileInfo)).createEmptySelectors();
16
+ }
17
+ for (i = 0; i < this.rules.length; i++) {
18
+ this.rules[i].allowImports = true;
19
+ }
10
20
  }
11
21
  this.index = index;
12
22
  this.currentFileInfo = currentFileInfo;
13
23
  this.debugInfo = debugInfo;
14
24
  this.isReferenced = isReferenced;
25
+ this.isRooted = isRooted || false;
15
26
  };
16
27
 
17
28
  Directive.prototype = new Node();
@@ -19,7 +30,7 @@ Directive.prototype.type = "Directive";
19
30
  Directive.prototype.accept = function (visitor) {
20
31
  var value = this.value, rules = this.rules;
21
32
  if (rules) {
22
- this.rules = visitor.visit(rules);
33
+ this.rules = visitor.visitArray(rules);
23
34
  }
24
35
  if (value) {
25
36
  this.value = visitor.visit(value);
@@ -39,46 +50,60 @@ Directive.prototype.genCSS = function (context, output) {
39
50
  value.genCSS(context, output);
40
51
  }
41
52
  if (rules) {
42
- if (rules.type === "Ruleset") {
43
- rules = [rules];
44
- }
45
53
  this.outputRuleset(context, output, rules);
46
54
  } else {
47
55
  output.add(';');
48
56
  }
49
57
  };
50
58
  Directive.prototype.eval = function (context) {
51
- var value = this.value, rules = this.rules;
59
+ var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules;
60
+
61
+ //media stored inside other directive should not bubble over it
62
+ //backpup media bubbling information
63
+ mediaPathBackup = context.mediaPath;
64
+ mediaBlocksBackup = context.mediaBlocks;
65
+ //deleted media bubbling information
66
+ context.mediaPath = [];
67
+ context.mediaBlocks = [];
68
+
52
69
  if (value) {
53
70
  value = value.eval(context);
54
71
  }
55
72
  if (rules) {
56
- rules = rules.eval(context);
57
- rules.root = true;
73
+ // assuming that there is only one rule at this point - that is how parser constructs the rule
74
+ rules = [rules[0].eval(context)];
75
+ rules[0].root = true;
58
76
  }
77
+ //restore media bubbling information
78
+ context.mediaPath = mediaPathBackup;
79
+ context.mediaBlocks = mediaBlocksBackup;
80
+
59
81
  return new Directive(this.name, value, rules,
60
- this.index, this.currentFileInfo, this.debugInfo, this.isReferenced);
82
+ this.index, this.currentFileInfo, this.debugInfo, this.isReferenced, this.isRooted);
61
83
  };
62
84
  Directive.prototype.variable = function (name) {
63
85
  if (this.rules) {
64
- return Ruleset.prototype.variable.call(this.rules, name);
86
+ // assuming that there is only one rule at this point - that is how parser constructs the rule
87
+ return Ruleset.prototype.variable.call(this.rules[0], name);
65
88
  }
66
89
  };
67
90
  Directive.prototype.find = function () {
68
91
  if (this.rules) {
69
- return Ruleset.prototype.find.apply(this.rules, arguments);
92
+ // assuming that there is only one rule at this point - that is how parser constructs the rule
93
+ return Ruleset.prototype.find.apply(this.rules[0], arguments);
70
94
  }
71
95
  };
72
96
  Directive.prototype.rulesets = function () {
73
97
  if (this.rules) {
74
- return Ruleset.prototype.rulesets.apply(this.rules);
98
+ // assuming that there is only one rule at this point - that is how parser constructs the rule
99
+ return Ruleset.prototype.rulesets.apply(this.rules[0]);
75
100
  }
76
101
  };
77
102
  Directive.prototype.markReferenced = function () {
78
103
  var i, rules;
79
104
  this.isReferenced = true;
80
105
  if (this.rules) {
81
- rules = this.rules.rules;
106
+ rules = this.rules;
82
107
  for (i = 0; i < rules.length; i++) {
83
108
  if (rules[i].markReferenced) {
84
109
  rules[i].markReferenced();
@@ -53,4 +53,9 @@ Expression.prototype.throwAwayComments = function () {
53
53
  return !(v instanceof Comment);
54
54
  });
55
55
  };
56
+ Expression.prototype.markReferenced = function () {
57
+ this.value.forEach(function (value) {
58
+ if (value.markReferenced) { value.markReferenced(); }
59
+ });
60
+ };
56
61
  module.exports = Expression;
@@ -50,12 +50,12 @@ Import.prototype.accept = function (visitor) {
50
50
  this.features = visitor.visit(this.features);
51
51
  }
52
52
  this.path = visitor.visit(this.path);
53
- if (!this.options.inline && this.root) {
53
+ if (!this.options.plugin && !this.options.inline && this.root) {
54
54
  this.root = visitor.visit(this.root);
55
55
  }
56
56
  };
57
57
  Import.prototype.genCSS = function (context, output) {
58
- if (this.css) {
58
+ if (this.css && this.path.currentFileInfo.reference === undefined) {
59
59
  output.add("@import ", this.currentFileInfo, this.index);
60
60
  this.path.genCSS(context, output);
61
61
  if (this.features) {
@@ -66,12 +66,8 @@ Import.prototype.genCSS = function (context, output) {
66
66
  }
67
67
  };
68
68
  Import.prototype.getPath = function () {
69
- if (this.path instanceof Quoted) {
70
- return this.path.value;
71
- } else if (this.path instanceof URL) {
72
- return this.path.value.value;
73
- }
74
- return null;
69
+ return (this.path instanceof URL) ?
70
+ this.path.value.value : this.path.value;
75
71
  };
76
72
  Import.prototype.isVariableImport = function () {
77
73
  var path = this.path;
@@ -86,9 +82,11 @@ Import.prototype.isVariableImport = function () {
86
82
  };
87
83
  Import.prototype.evalForImport = function (context) {
88
84
  var path = this.path;
85
+
89
86
  if (path instanceof URL) {
90
87
  path = path.value;
91
88
  }
89
+
92
90
  return new Import(path.eval(context), this.features, this.options, this.index, this.currentFileInfo);
93
91
  };
94
92
  Import.prototype.evalPath = function (context) {
@@ -109,7 +107,16 @@ Import.prototype.evalPath = function (context) {
109
107
  return path;
110
108
  };
111
109
  Import.prototype.eval = function (context) {
112
- var ruleset, features = this.features && this.features.eval(context);
110
+ var ruleset, registry,
111
+ features = this.features && this.features.eval(context);
112
+
113
+ if (this.options.plugin) {
114
+ registry = context.frames[0] && context.frames[0].functionRegistry;
115
+ if ( registry && this.root && this.root.functions ) {
116
+ registry.addMultiple( this.root.functions );
117
+ }
118
+ return [];
119
+ }
113
120
 
114
121
  if (this.skip) {
115
122
  if (typeof this.skip === "function") {
@@ -121,7 +128,12 @@ Import.prototype.eval = function (context) {
121
128
  }
122
129
 
123
130
  if (this.options.inline) {
124
- var contents = new Anonymous(this.root, 0, {filename: this.importedFilename}, true, true);
131
+ var contents = new Anonymous(this.root, 0,
132
+ {
133
+ filename: this.importedFilename,
134
+ reference: this.path.currentFileInfo && this.path.currentFileInfo.reference
135
+ }, true, true, false);
136
+
125
137
  return this.features ? new Media([contents], this.features.value) : [contents];
126
138
  } else if (this.css) {
127
139
  var newImport = new Import(this.evalPath(context), features, this.options, this.index);
@@ -1,6 +1,5 @@
1
1
  var Ruleset = require("./ruleset"),
2
2
  Value = require("./value"),
3
- Element = require("./element"),
4
3
  Selector = require("./selector"),
5
4
  Anonymous = require("./anonymous"),
6
5
  Expression = require("./expression"),
@@ -10,7 +9,7 @@ var Media = function (value, features, index, currentFileInfo) {
10
9
  this.index = index;
11
10
  this.currentFileInfo = currentFileInfo;
12
11
 
13
- var selectors = this.emptySelectors();
12
+ var selectors = (new Selector([], null, null, this.index, this.currentFileInfo)).createEmptySelectors();
14
13
 
15
14
  this.features = new Value(features);
16
15
  this.rules = [new Ruleset(selectors, value)];
@@ -60,6 +59,7 @@ Media.prototype.eval = function (context) {
60
59
  context.mediaPath.push(media);
61
60
  context.mediaBlocks.push(media);
62
61
 
62
+ this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit();
63
63
  context.frames.unshift(this.rules[0]);
64
64
  media.rules = [this.rules[0].eval(context)];
65
65
  context.frames.shift();
@@ -69,32 +69,12 @@ Media.prototype.eval = function (context) {
69
69
  return context.mediaPath.length === 0 ? media.evalTop(context) :
70
70
  media.evalNested(context);
71
71
  };
72
- //TODO merge with directive
73
- Media.prototype.variable = function (name) { return Ruleset.prototype.variable.call(this.rules[0], name); };
74
- Media.prototype.find = function () { return Ruleset.prototype.find.apply(this.rules[0], arguments); };
75
- Media.prototype.rulesets = function () { return Ruleset.prototype.rulesets.apply(this.rules[0]); };
76
- Media.prototype.emptySelectors = function() {
77
- var el = new Element('', '&', this.index, this.currentFileInfo),
78
- sels = [new Selector([el], null, null, this.index, this.currentFileInfo)];
79
- sels[0].mediaEmpty = true;
80
- return sels;
81
- };
82
- Media.prototype.markReferenced = function () {
83
- var i, rules = this.rules[0].rules;
84
- this.rules[0].markReferenced();
85
- this.isReferenced = true;
86
- for (i = 0; i < rules.length; i++) {
87
- if (rules[i].markReferenced) {
88
- rules[i].markReferenced();
89
- }
90
- }
91
- };
92
72
  Media.prototype.evalTop = function (context) {
93
73
  var result = this;
94
74
 
95
75
  // Render all dependent Media blocks.
96
76
  if (context.mediaBlocks.length > 1) {
97
- var selectors = this.emptySelectors();
77
+ var selectors = (new Selector([], null, null, this.index, this.currentFileInfo)).createEmptySelectors();
98
78
  result = new Ruleset(selectors, context.mediaBlocks);
99
79
  result.multiMedia = true;
100
80
  }
@@ -5,7 +5,7 @@ var Node = require("./node"),
5
5
 
6
6
  var MixinCall = function (elements, args, index, currentFileInfo, important) {
7
7
  this.selector = new Selector(elements);
8
- this.arguments = (args && args.length) ? args : null;
8
+ this.arguments = args || [];
9
9
  this.index = index;
10
10
  this.currentFileInfo = currentFileInfo;
11
11
  this.important = important;
@@ -16,17 +16,18 @@ MixinCall.prototype.accept = function (visitor) {
16
16
  if (this.selector) {
17
17
  this.selector = visitor.visit(this.selector);
18
18
  }
19
- if (this.arguments) {
19
+ if (this.arguments.length) {
20
20
  this.arguments = visitor.visitArray(this.arguments);
21
21
  }
22
22
  };
23
23
  MixinCall.prototype.eval = function (context) {
24
- var mixins, mixin, mixinPath, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule,
24
+ var mixins, mixin, mixinPath, args = [], arg, argValue,
25
+ rules = [], rule, match = false, i, m, f, isRecursive, isOneFound,
25
26
  candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1,
26
27
  defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter;
27
28
 
28
29
  function calcDefGroup(mixin, mixinPath) {
29
- var p, namespace;
30
+ var f, p, namespace;
30
31
 
31
32
  for (f = 0; f < 2; f++) {
32
33
  conditionResult[f] = true;
@@ -52,9 +53,18 @@ MixinCall.prototype.eval = function (context) {
52
53
  return defFalseEitherCase;
53
54
  }
54
55
 
55
- args = this.arguments && this.arguments.map(function (a) {
56
- return { name: a.name, value: a.value.eval(context) };
57
- });
56
+ for (i = 0; i < this.arguments.length; i++) {
57
+ arg = this.arguments[i];
58
+ argValue = arg.value.eval(context);
59
+ if (arg.expand && Array.isArray(argValue.value)) {
60
+ argValue = argValue.value;
61
+ for (m = 0; m < argValue.length; m++) {
62
+ args.push({value: argValue[m]});
63
+ }
64
+ } else {
65
+ args.push({name: arg.name, value: argValue});
66
+ }
67
+ }
58
68
 
59
69
  noArgumentsFilter = function(rule) {return rule.matchArgs(null, context);};
60
70
 
@@ -14,14 +14,17 @@ var Definition = function (name, params, rules, condition, variadic, frames) {
14
14
  this.arity = params.length;
15
15
  this.rules = rules;
16
16
  this._lookups = {};
17
+ var optionalParameters = [];
17
18
  this.required = params.reduce(function (count, p) {
18
19
  if (!p.name || (p.name && !p.value)) {
19
20
  return count + 1;
20
21
  }
21
22
  else {
23
+ optionalParameters.push(p.name);
22
24
  return count;
23
25
  }
24
26
  }, 0);
27
+ this.optionalParameters = optionalParameters;
25
28
  this.frames = frames;
26
29
  };
27
30
  Definition.prototype = new Ruleset();
@@ -43,6 +46,9 @@ Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArgume
43
46
  params = this.params.slice(0),
44
47
  i, j, val, name, isNamedFound, argIndex, argsLength = 0;
45
48
 
49
+ if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) {
50
+ frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit();
51
+ }
46
52
  mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames));
47
53
 
48
54
  if (args) {
@@ -149,29 +155,37 @@ Definition.prototype.matchCondition = function (args, context) {
149
155
  new contexts.Eval(context,
150
156
  [this.evalParams(context, /* the parameter variables*/
151
157
  new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]
152
- .concat(this.frames) // the parent namespace/mixin frames
158
+ .concat(this.frames || []) // the parent namespace/mixin frames
153
159
  .concat(context.frames)))) { // the current environment frames
154
160
  return false;
155
161
  }
156
162
  return true;
157
163
  };
158
164
  Definition.prototype.matchArgs = function (args, context) {
159
- var argsLength = (args && args.length) || 0, len;
165
+ var allArgsCnt = (args && args.length) || 0, len, optionalParameters = this.optionalParameters;
166
+ var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) {
167
+ if (optionalParameters.indexOf(p.name) < 0) {
168
+ return count + 1;
169
+ } else {
170
+ return count;
171
+ }
172
+ }, 0);
160
173
 
161
174
  if (! this.variadic) {
162
- if (argsLength < this.required) {
175
+ if (requiredArgsCnt < this.required) {
163
176
  return false;
164
177
  }
165
- if (argsLength > this.params.length) {
178
+ if (allArgsCnt > this.params.length) {
166
179
  return false;
167
180
  }
168
181
  } else {
169
- if (argsLength < (this.required - 1)) {
182
+ if (requiredArgsCnt < (this.required - 1)) {
170
183
  return false;
171
184
  }
172
185
  }
173
186
 
174
- len = Math.min(argsLength, this.arity);
187
+ // check patterns
188
+ len = Math.min(requiredArgsCnt, this.arity);
175
189
 
176
190
  for (var i = 0; i < len; i++) {
177
191
  if (!this.params[i].name && !this.params[i].variadic) {
@@ -92,4 +92,22 @@ Rule.prototype.makeImportant = function () {
92
92
  this.index, this.currentFileInfo, this.inline);
93
93
  };
94
94
 
95
- module.exports = Rule;
95
+ // Recursive marking for rules
96
+ var mark = function(value) {
97
+ if (!Array.isArray(value)) {
98
+ if (value.markReferenced) {
99
+ value.markReferenced();
100
+ }
101
+ } else {
102
+ value.forEach(function (ar) {
103
+ mark(ar);
104
+ });
105
+ }
106
+ };
107
+ Rule.prototype.markReferenced = function () {
108
+ if (this.value) {
109
+ mark(this.value);
110
+ }
111
+ };
112
+
113
+ module.exports = Rule;
@@ -4,6 +4,7 @@ var Node = require("./node"),
4
4
  Element = require("./element"),
5
5
  Paren = require("./paren"),
6
6
  contexts = require("../contexts"),
7
+ globalFunctionRegistry = require("../functions/function-registry"),
7
8
  defaultFunc = require("../functions/default"),
8
9
  getDebugInfo = require("./debug-info");
9
10
 
@@ -66,6 +67,19 @@ Ruleset.prototype.eval = function (context) {
66
67
  rules.length = 0;
67
68
  }
68
69
 
70
+ // inherit a function registry from the frames stack when possible;
71
+ // otherwise from the global registry
72
+ ruleset.functionRegistry = (function (frames) {
73
+ var i = 0,
74
+ n = frames.length,
75
+ found;
76
+ for ( ; i !== n ; ++i ) {
77
+ found = frames[ i ].functionRegistry;
78
+ if ( found ) { return found; }
79
+ }
80
+ return globalFunctionRegistry;
81
+ }(context.frames)).inherit();
82
+
69
83
  // push the current ruleset to the frames stack
70
84
  var ctxFrames = context.frames;
71
85
  ctxFrames.unshift(ruleset);
@@ -241,7 +255,7 @@ Ruleset.prototype.variable = function (name) {
241
255
  return this.variables()[name];
242
256
  };
243
257
  Ruleset.prototype.rulesets = function () {
244
- if (!this.rules) { return null; }
258
+ if (!this.rules) { return []; }
245
259
 
246
260
  var filtRules = [], rules = this.rules, cnt = rules.length,
247
261
  i, rule;
@@ -298,8 +312,6 @@ Ruleset.prototype.genCSS = function (context, output) {
298
312
  var i, j,
299
313
  charsetRuleNodes = [],
300
314
  ruleNodes = [],
301
- rulesetNodes = [],
302
- rulesetNodeCnt,
303
315
  debugInfo, // Line number debugging
304
316
  rule,
305
317
  path;
@@ -314,31 +326,38 @@ Ruleset.prototype.genCSS = function (context, output) {
314
326
  tabSetStr = context.compress ? '' : Array(context.tabLevel).join(" "),
315
327
  sep;
316
328
 
317
- function isRulesetLikeNode(rule, root) {
329
+ function isRulesetLikeNode(rule) {
318
330
  // if it has nested rules, then it should be treated like a ruleset
319
331
  // medias and comments do not have nested rules, but should be treated like rulesets anyway
320
332
  // some directives and anonymous nodes are ruleset like, others are not
321
333
  if (typeof rule.isRulesetLike === "boolean") {
322
334
  return rule.isRulesetLike;
323
335
  } else if (typeof rule.isRulesetLike === "function") {
324
- return rule.isRulesetLike(root);
336
+ return rule.isRulesetLike();
325
337
  }
326
338
 
327
339
  //anything else is assumed to be a rule
328
340
  return false;
329
341
  }
330
342
 
343
+ var charsetNodeIndex = 0;
344
+ var importNodeIndex = 0;
331
345
  for (i = 0; i < this.rules.length; i++) {
332
346
  rule = this.rules[i];
333
- if (isRulesetLikeNode(rule, this.root)) {
334
- rulesetNodes.push(rule);
335
- } else {
336
- //charsets should float on top of everything
337
- if (rule.isCharset && rule.isCharset()) {
338
- charsetRuleNodes.push(rule);
339
- } else {
340
- ruleNodes.push(rule);
347
+ if (rule.type === "Comment") {
348
+ if (importNodeIndex === i) {
349
+ importNodeIndex++;
341
350
  }
351
+ ruleNodes.push(rule);
352
+ } else if (rule.isCharset && rule.isCharset()) {
353
+ ruleNodes.splice(charsetNodeIndex, 0, rule);
354
+ charsetNodeIndex++;
355
+ importNodeIndex++;
356
+ } else if (rule.type === "Import") {
357
+ ruleNodes.splice(importNodeIndex, 0, rule);
358
+ importNodeIndex++;
359
+ } else {
360
+ ruleNodes.push(rule);
342
361
  }
343
362
  }
344
363
  ruleNodes = charsetRuleNodes.concat(ruleNodes);
@@ -379,18 +398,23 @@ Ruleset.prototype.genCSS = function (context, output) {
379
398
  for (i = 0; i < ruleNodes.length; i++) {
380
399
  rule = ruleNodes[i];
381
400
 
382
- // @page{ directive ends up with root elements inside it, a mix of rules and rulesets
383
- // In this instance we do not know whether it is the last property
384
- if (i + 1 === ruleNodes.length && (!this.root || rulesetNodes.length === 0 || this.firstRoot)) {
401
+ if (i + 1 === ruleNodes.length) {
385
402
  context.lastRule = true;
386
403
  }
387
404
 
405
+ var currentLastRule = context.lastRule;
406
+ if (isRulesetLikeNode(rule)) {
407
+ context.lastRule = false;
408
+ }
409
+
388
410
  if (rule.genCSS) {
389
411
  rule.genCSS(context, output);
390
412
  } else if (rule.value) {
391
413
  output.add(rule.value.toString());
392
414
  }
393
415
 
416
+ context.lastRule = currentLastRule;
417
+
394
418
  if (!context.lastRule) {
395
419
  output.add(context.compress ? '' : ('\n' + tabRuleStr));
396
420
  } else {
@@ -403,17 +427,6 @@ Ruleset.prototype.genCSS = function (context, output) {
403
427
  context.tabLevel--;
404
428
  }
405
429
 
406
- sep = (context.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr);
407
- rulesetNodeCnt = rulesetNodes.length;
408
- if (rulesetNodeCnt) {
409
- if (ruleNodes.length && sep) { output.add(sep); }
410
- rulesetNodes[0].genCSS(context, output);
411
- for (i = 1; i < rulesetNodeCnt; i++) {
412
- if (sep) { output.add(sep); }
413
- rulesetNodes[i].genCSS(context, output);
414
- }
415
- }
416
-
417
430
  if (!output.isEmpty() && !context.compress && this.firstRoot) {
418
431
  output.add('\n');
419
432
  }
@@ -1,4 +1,5 @@
1
- var Node = require("./node");
1
+ var Node = require("./node"),
2
+ Element = require("./element");
2
3
 
3
4
  var Selector = function (elements, extendList, condition, index, currentFileInfo, isReferenced) {
4
5
  this.elements = elements;
@@ -30,6 +31,12 @@ Selector.prototype.createDerived = function(elements, extendList, evaldCondition
30
31
  newSelector.mediaEmpty = this.mediaEmpty;
31
32
  return newSelector;
32
33
  };
34
+ Selector.prototype.createEmptySelectors = function() {
35
+ var el = new Element('', '&', this.index, this.currentFileInfo),
36
+ sels = [new Selector([el], null, null, this.index, this.currentFileInfo)];
37
+ sels[0].mediaEmpty = true;
38
+ return sels;
39
+ };
33
40
  Selector.prototype.match = function (other) {
34
41
  var elements = this.elements,
35
42
  len = elements.length,
@@ -198,8 +198,7 @@ ProcessExtendsVisitor.prototype = {
198
198
  if (iterationCount > 100) {
199
199
  var selectorOne = "{unable to calculate}";
200
200
  var selectorTwo = "{unable to calculate}";
201
- try
202
- {
201
+ try {
203
202
  selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
204
203
  selectorTwo = extendsToAdd[0].selector.toCSS();
205
204
  }
@@ -436,7 +435,6 @@ ProcessExtendsVisitor.prototype = {
436
435
  },
437
436
  visitMediaOut: function (mediaNode) {
438
437
  var lastIndex = this.allExtendsStack.length - 1;
439
- this.checkExtendsForNonMatched(this.allExtendsStack[lastIndex]);
440
438
  this.allExtendsStack.length = lastIndex;
441
439
  },
442
440
  visitDirective: function (directiveNode, visitArgs) {
@@ -446,7 +444,6 @@ ProcessExtendsVisitor.prototype = {
446
444
  },
447
445
  visitDirectiveOut: function (directiveNode) {
448
446
  var lastIndex = this.allExtendsStack.length - 1;
449
- this.checkExtendsForNonMatched(this.allExtendsStack[lastIndex]);
450
447
  this.allExtendsStack.length = lastIndex;
451
448
  }
452
449
  };
@@ -103,6 +103,8 @@ ImportVisitor.prototype = {
103
103
 
104
104
  var importVisitor = this,
105
105
  inlineCSS = importNode.options.inline,
106
+ isPlugin = importNode.options.plugin,
107
+ isOptional = importNode.options.optional,
106
108
  duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;
107
109
 
108
110
  if (!context.importMultiple) {
@@ -119,11 +121,15 @@ ImportVisitor.prototype = {
119
121
  }
120
122
  }
121
123
 
124
+ if (!fullPath && isOptional) {
125
+ importNode.skip = true;
126
+ }
127
+
122
128
  if (root) {
123
129
  importNode.root = root;
124
130
  importNode.importedFilename = fullPath;
125
131
 
126
- if (!inlineCSS && (context.importMultiple || !duplicateImport)) {
132
+ if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) {
127
133
  importVisitor.recursionDetector[fullPath] = true;
128
134
 
129
135
  var oldContext = this.context;
@@ -144,7 +150,16 @@ ImportVisitor.prototype = {
144
150
  }
145
151
  },
146
152
  visitRule: function (ruleNode, visitArgs) {
147
- visitArgs.visitDeeper = false;
153
+ if (ruleNode.value.type === "DetachedRuleset") {
154
+ this.context.frames.unshift(ruleNode);
155
+ } else {
156
+ visitArgs.visitDeeper = false;
157
+ }
158
+ },
159
+ visitRuleOut : function(ruleNode) {
160
+ if (ruleNode.value.type === "DetachedRuleset") {
161
+ this.context.frames.shift();
162
+ }
148
163
  },
149
164
  visitDirective: function (directiveNode, visitArgs) {
150
165
  this.context.frames.unshift(directiveNode);
@@ -39,6 +39,12 @@ JoinSelectorVisitor.prototype = {
39
39
  visitMedia: function (mediaNode, visitArgs) {
40
40
  var context = this.contexts[this.contexts.length - 1];
41
41
  mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
42
+ },
43
+ visitDirective: function (directiveNode, visitArgs) {
44
+ var context = this.contexts[this.contexts.length - 1];
45
+ if (directiveNode.rules && directiveNode.rules.length) {
46
+ directiveNode.rules[0].root = (directiveNode.isRooted || context.length === 0 || null);
47
+ }
42
48
  }
43
49
  };
44
50