less 2.1.2 → 2.4.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 (148) 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 +499 -760
  5. package/.jscsrc +73 -0
  6. package/.jshintrc +0 -2
  7. package/.travis.yml +1 -0
  8. package/CHANGELOG.md +59 -0
  9. package/Gruntfile.js +37 -3
  10. package/appveyor.yml +5 -0
  11. package/bin/lessc +383 -316
  12. package/bower.json +1 -1
  13. package/dist/less.js +1638 -1244
  14. package/dist/less.min.js +7 -7
  15. package/lib/less/contexts.js +3 -3
  16. package/lib/less/data/unit-conversions.js +3 -3
  17. package/lib/less/environment/abstract-file-manager.js +8 -8
  18. package/lib/less/environment/environment.js +2 -2
  19. package/lib/less/functions/color-blending.js +3 -3
  20. package/lib/less/functions/color.js +20 -12
  21. package/lib/less/functions/data-uri.js +26 -18
  22. package/lib/less/functions/math.js +1 -1
  23. package/lib/less/functions/number.js +2 -2
  24. package/lib/less/functions/string.js +3 -1
  25. package/lib/less/functions/svg.js +12 -15
  26. package/lib/less/functions/types.js +33 -10
  27. package/lib/less/import-manager.js +14 -9
  28. package/lib/less/index.js +2 -1
  29. package/lib/less/less-error.js +1 -1
  30. package/lib/less/logger.js +2 -2
  31. package/lib/less/parse-tree.js +48 -42
  32. package/lib/less/parse.js +68 -0
  33. package/lib/less/parser/parser-input.js +6 -5
  34. package/lib/less/parser/parser.js +76 -29
  35. package/lib/less/plugin-manager.js +30 -3
  36. package/lib/less/render.js +11 -37
  37. package/lib/less/source-map-builder.js +4 -0
  38. package/lib/less/source-map-output.js +6 -6
  39. package/lib/less/transform-tree.js +4 -4
  40. package/lib/less/tree/anonymous.js +1 -1
  41. package/lib/less/tree/assignment.js +0 -1
  42. package/lib/less/tree/call.js +1 -1
  43. package/lib/less/tree/color.js +6 -6
  44. package/lib/less/tree/condition.js +9 -5
  45. package/lib/less/tree/debug-info.js +6 -2
  46. package/lib/less/tree/dimension.js +5 -5
  47. package/lib/less/tree/directive.js +25 -6
  48. package/lib/less/tree/element.js +1 -1
  49. package/lib/less/tree/expression.js +2 -2
  50. package/lib/less/tree/extend.js +3 -3
  51. package/lib/less/tree/import.js +2 -2
  52. package/lib/less/tree/index.js +1 -0
  53. package/lib/less/tree/javascript.js +2 -2
  54. package/lib/less/tree/media.js +20 -19
  55. package/lib/less/tree/mixin-call.js +5 -6
  56. package/lib/less/tree/mixin-definition.js +33 -11
  57. package/lib/less/tree/quoted.js +3 -3
  58. package/lib/less/tree/rule.js +3 -4
  59. package/lib/less/tree/ruleset.js +290 -177
  60. package/lib/less/tree/selector.js +3 -2
  61. package/lib/less/tree/unit.js +2 -0
  62. package/lib/less/tree/url.js +5 -2
  63. package/lib/less/tree/value.js +2 -2
  64. package/lib/less/tree/variable.js +1 -1
  65. package/lib/less/visitors/extend-visitor.js +72 -36
  66. package/lib/less/visitors/import-sequencer.js +20 -14
  67. package/lib/less/visitors/import-visitor.js +15 -12
  68. package/lib/less/visitors/to-css-visitor.js +41 -9
  69. package/lib/less-browser/add-default-options.js +5 -1
  70. package/lib/less-browser/bootstrap.js +10 -8
  71. package/lib/less-browser/cache.js +3 -3
  72. package/lib/less-browser/file-manager.js +96 -96
  73. package/lib/less-browser/index.js +206 -205
  74. package/lib/less-browser/log-listener.js +2 -2
  75. package/lib/less-browser/utils.js +6 -6
  76. package/lib/less-node/file-manager.js +58 -30
  77. package/lib/less-node/image-size.js +34 -0
  78. package/lib/less-node/index.js +6 -3
  79. package/lib/less-node/lessc-helper.js +3 -2
  80. package/lib/less-node/plugin-loader.js +3 -3
  81. package/lib/less-node/url-file-manager.js +6 -3
  82. package/lib/less-rhino/index.js +15 -13
  83. package/lib/source-map/source-map-0.1.31.js +1 -1
  84. package/package.json +10 -7
  85. package/test/browser/common.js +13 -11
  86. package/test/browser/css/relative-urls/urls.css +1 -0
  87. package/test/browser/css/urls.css +6 -3
  88. package/test/browser/jasmine-jsreporter.js +2 -3
  89. package/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
  90. package/test/browser/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
  91. package/test/browser/less/relative-urls/urls.less +1 -0
  92. package/test/browser/less/urls.less +1 -0
  93. package/test/browser/runner-browser-options.js +23 -23
  94. package/test/browser/runner-errors-options.js +0 -1
  95. package/test/browser/runner-errors-spec.js +1 -2
  96. package/test/browser/runner-global-vars-spec.js +1 -1
  97. package/test/browser/runner-legacy-options.js +0 -1
  98. package/test/browser/runner-main-options.js +5 -5
  99. package/test/browser/runner-main-spec.js +1 -1
  100. package/test/browser/runner-no-js-errors-spec.js +0 -1
  101. package/test/browser/runner-production-options.js +0 -1
  102. package/test/browser/runner-relative-urls-options.js +0 -1
  103. package/test/browser/runner-rootpath-options.js +0 -1
  104. package/test/browser/runner-rootpath-relative-options.js +0 -1
  105. package/test/browser/runner-strict-units-options.js +0 -1
  106. package/test/copy-bom.js +72 -0
  107. package/test/css/comments.css +1 -0
  108. package/test/css/css-3.css +2 -0
  109. package/test/css/functions.css +10 -0
  110. package/test/css/import-interpolation.css +7 -0
  111. package/test/css/import-reference.css +25 -0
  112. package/test/css/include-path/include-path.css +6 -0
  113. package/test/css/mixins-important.css +12 -0
  114. package/test/css/selectors.css +15 -1
  115. package/test/css/static-urls/urls.css +1 -0
  116. package/test/css/url-args/urls.css +3 -3
  117. package/test/css/urls.css +13 -4
  118. package/test/css/variables.css +7 -1
  119. package/test/data/image.svg +3 -0
  120. package/test/index.js +15 -10
  121. package/test/less/comments.less +1 -0
  122. package/test/less/css-3.less +3 -0
  123. package/test/less/css-guards.less +2 -1
  124. package/test/less/errors/detached-ruleset-2.txt +1 -1
  125. package/test/less/errors/import-missing.txt +1 -1
  126. package/test/less/errors/parens-error-1.txt +1 -1
  127. package/test/less/errors/parens-error-2.txt +1 -1
  128. package/test/less/errors/parens-error-3.txt +1 -1
  129. package/test/less/errors/single-character.less +1 -0
  130. package/test/less/errors/single-character.txt +2 -0
  131. package/test/less/functions.less +18 -0
  132. package/test/less/import/import-interpolation.less +1 -0
  133. package/test/less/import/import-reference.less +38 -0
  134. package/test/less/import/imports/logo.less +1 -0
  135. package/test/less/import-reference.less +3 -1
  136. package/test/less/import.less +2 -0
  137. package/test/less/include-path/include-path.less +6 -0
  138. package/test/less/mixins-important.less +28 -0
  139. package/test/less/nested-gradient-with-svg-gradient/mixin-consumer.less +5 -0
  140. package/test/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less +15 -0
  141. package/test/less/selectors.less +29 -4
  142. package/test/less/sourcemaps-empty/empty.less +0 -0
  143. package/test/less/sourcemaps-empty/var-defs.less +1 -0
  144. package/test/less/urls.less +10 -1
  145. package/test/less/variables.less +17 -3
  146. package/test/less-test.js +133 -52
  147. package/test/modify-vars.js +14 -12
  148. package/test/browser/less.js +0 -9473
@@ -6,250 +6,251 @@ var addDataAttr = require("./utils").addDataAttr,
6
6
  browser = require("./browser");
7
7
 
8
8
  module.exports = function(window, options) {
9
- var document = window.document;
10
- var less = require('../less')();
11
- module.exports = less;
12
- less.options = options;
13
- var environment = less.environment,
14
- FileManager = require("./file-manager")(options, less.logger),
15
- fileManager = new FileManager();
16
- environment.addFileManager(fileManager);
17
- less.FileManager = FileManager;
18
-
19
- require("./log-listener")(less, options);
20
- var errors = require("./error-reporting")(window, less, options);
21
- var cache = less.cache = options.cache || require("./cache")(window, options, less.logger);
22
-
23
- //Setup user functions
24
- if (options.functions) {
25
- less.functions.functionRegistry.addMultiple(options.functions);
26
- }
27
-
28
- var typePattern = /^text\/(x-)?less$/;
29
-
30
- function postProcessCSS(styles) {
31
- if (options.postProcessor && typeof options.postProcessor === 'function') {
32
- styles = options.postProcessor.call(styles, styles) || styles;
9
+ var document = window.document;
10
+ var less = require('../less')();
11
+ //module.exports = less;
12
+ less.options = options;
13
+ var environment = less.environment,
14
+ FileManager = require("./file-manager")(options, less.logger),
15
+ fileManager = new FileManager();
16
+ environment.addFileManager(fileManager);
17
+ less.FileManager = FileManager;
18
+
19
+ require("./log-listener")(less, options);
20
+ var errors = require("./error-reporting")(window, less, options);
21
+ var cache = less.cache = options.cache || require("./cache")(window, options, less.logger);
22
+
23
+ //Setup user functions
24
+ if (options.functions) {
25
+ less.functions.functionRegistry.addMultiple(options.functions);
33
26
  }
34
- return styles;
35
- }
36
-
37
- function clone(obj) {
38
- var cloned = {};
39
- for(var prop in obj) {
40
- if (obj.hasOwnProperty(prop)) {
41
- cloned[prop] = obj[prop];
27
+
28
+ var typePattern = /^text\/(x-)?less$/;
29
+
30
+ function postProcessCSS(styles) {
31
+ if (options.postProcessor && typeof options.postProcessor === 'function') {
32
+ styles = options.postProcessor.call(styles, styles) || styles;
42
33
  }
34
+ return styles;
43
35
  }
44
- return cloned;
45
- }
46
-
47
- // only really needed for phantom
48
- function bind(func, thisArg) {
49
- var curryArgs = Array.prototype.slice.call(arguments, 2);
50
- return function() {
51
- var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));
52
- return func.apply(thisArg, args);
53
- };
54
- }
55
36
 
56
- function loadStyles(modifyVars) {
57
- var styles = document.getElementsByTagName('style'),
58
- style;
37
+ function clone(obj) {
38
+ var cloned = {};
39
+ for (var prop in obj) {
40
+ if (obj.hasOwnProperty(prop)) {
41
+ cloned[prop] = obj[prop];
42
+ }
43
+ }
44
+ return cloned;
45
+ }
59
46
 
60
- for (var i = 0; i < styles.length; i++) {
61
- style = styles[i];
62
- if (style.type.match(typePattern)) {
63
- var instanceOptions = clone(options);
64
- instanceOptions.modifyVars = modifyVars;
65
- var lessText = style.innerHTML || '';
66
- instanceOptions.filename = document.location.href.replace(/#.*$/, '');
47
+ // only really needed for phantom
48
+ function bind(func, thisArg) {
49
+ var curryArgs = Array.prototype.slice.call(arguments, 2);
50
+ return function() {
51
+ var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));
52
+ return func.apply(thisArg, args);
53
+ };
54
+ }
67
55
 
68
- /*jshint loopfunc:true */
69
- // use closure to store current style
70
- less.render(lessText, instanceOptions,
71
- bind(function(style, e, result) {
72
- if (e) {
73
- errors.add(e, "inline");
74
- } else {
75
- style.type = 'text/css';
76
- if (style.styleSheet) {
77
- style.styleSheet.cssText = result.css;
56
+ function loadStyles(modifyVars) {
57
+ var styles = document.getElementsByTagName('style'),
58
+ style;
59
+
60
+ for (var i = 0; i < styles.length; i++) {
61
+ style = styles[i];
62
+ if (style.type.match(typePattern)) {
63
+ var instanceOptions = clone(options);
64
+ instanceOptions.modifyVars = modifyVars;
65
+ var lessText = style.innerHTML || '';
66
+ instanceOptions.filename = document.location.href.replace(/#.*$/, '');
67
+
68
+ /*jshint loopfunc:true */
69
+ // use closure to store current style
70
+ less.render(lessText, instanceOptions,
71
+ bind(function(style, e, result) {
72
+ if (e) {
73
+ errors.add(e, "inline");
78
74
  } else {
79
- style.innerHTML = result.css;
75
+ style.type = 'text/css';
76
+ if (style.styleSheet) {
77
+ style.styleSheet.cssText = result.css;
78
+ } else {
79
+ style.innerHTML = result.css;
80
+ }
80
81
  }
81
- }
82
- }, null, style));
82
+ }, null, style));
83
+ }
83
84
  }
84
85
  }
85
- }
86
86
 
87
- function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
87
+ function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
88
88
 
89
- var instanceOptions = clone(options);
90
- addDataAttr(instanceOptions, sheet);
91
- instanceOptions.mime = sheet.type;
89
+ var instanceOptions = clone(options);
90
+ addDataAttr(instanceOptions, sheet);
91
+ instanceOptions.mime = sheet.type;
92
92
 
93
- if (modifyVars) {
94
- instanceOptions.modifyVars = modifyVars;
95
- }
93
+ if (modifyVars) {
94
+ instanceOptions.modifyVars = modifyVars;
95
+ }
96
96
 
97
- function loadInitialFileCallback(loadedFile) {
97
+ function loadInitialFileCallback(loadedFile) {
98
98
 
99
- var data = loadedFile.contents,
100
- path = loadedFile.filename,
101
- webInfo = loadedFile.webInfo;
99
+ var data = loadedFile.contents,
100
+ path = loadedFile.filename,
101
+ webInfo = loadedFile.webInfo;
102
102
 
103
- var newFileInfo = {
104
- currentDirectory: fileManager.getPath(path),
105
- filename: path,
106
- rootFilename: path,
107
- relativeUrls: instanceOptions.relativeUrls};
103
+ var newFileInfo = {
104
+ currentDirectory: fileManager.getPath(path),
105
+ filename: path,
106
+ rootFilename: path,
107
+ relativeUrls: instanceOptions.relativeUrls};
108
108
 
109
- newFileInfo.entryPath = newFileInfo.currentDirectory;
110
- newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
109
+ newFileInfo.entryPath = newFileInfo.currentDirectory;
110
+ newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
111
111
 
112
- if (webInfo) {
113
- webInfo.remaining = remaining;
112
+ if (webInfo) {
113
+ webInfo.remaining = remaining;
114
114
 
115
- var css = cache.getCSS(path, webInfo);
116
- if (!reload && css) {
117
- browser.createCSS(window.document, css, sheet);
118
- webInfo.local = true;
119
- callback(null, null, data, sheet, webInfo, path);
120
- return;
115
+ if (!instanceOptions.modifyVars) {
116
+ var css = cache.getCSS(path, webInfo);
117
+ if (!reload && css) {
118
+ webInfo.local = true;
119
+ callback(null, css, data, sheet, webInfo, path);
120
+ return;
121
+ }
122
+ }
121
123
  }
122
- }
123
124
 
124
- //TODO add tests around how this behaves when reloading
125
- errors.remove(path);
125
+ //TODO add tests around how this behaves when reloading
126
+ errors.remove(path);
127
+
128
+ instanceOptions.rootFileInfo = newFileInfo;
129
+ less.render(data, instanceOptions, function(e, result) {
130
+ if (e) {
131
+ e.href = path;
132
+ callback(e);
133
+ } else {
134
+ result.css = postProcessCSS(result.css);
135
+ if (!instanceOptions.modifyVars) {
136
+ cache.setCSS(sheet.href, webInfo.lastModified, result.css);
137
+ }
138
+ callback(null, result.css, data, sheet, webInfo, path);
139
+ }
140
+ });
141
+ }
126
142
 
127
- instanceOptions.rootFileInfo = newFileInfo;
128
- less.render(data, instanceOptions, function(e, result) {
143
+ fileManager.loadFile(sheet.href, null, instanceOptions, environment, function(e, loadedFile) {
129
144
  if (e) {
130
- e.href = path;
131
145
  callback(e);
132
- } else {
133
- callback(null, result.css, data, sheet, webInfo, path);
146
+ return;
134
147
  }
148
+ loadInitialFileCallback(loadedFile);
135
149
  });
136
150
  }
137
151
 
138
- fileManager.loadFile(sheet.href, null, instanceOptions, environment, function(e, loadedFile) {
139
- if (e) {
140
- callback(e);
141
- return;
152
+ function loadStyleSheets(callback, reload, modifyVars) {
153
+ for (var i = 0; i < less.sheets.length; i++) {
154
+ loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);
142
155
  }
143
- loadInitialFileCallback(loadedFile);
144
- });
145
- }
146
-
147
- function loadStyleSheets(callback, reload, modifyVars) {
148
- for (var i = 0; i < less.sheets.length; i++) {
149
- loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);
150
- }
151
- }
152
-
153
- function initRunningMode(){
154
- if (less.env === 'development') {
155
- less.watchTimer = setInterval(function () {
156
- if (less.watchMode) {
157
- fileManager.clearFileCache();
158
- loadStyleSheets(function (e, css, _, sheet, context) {
159
- if (e) {
160
- errors.add(e, e.href || sheet.href);
161
- } else if (css) {
162
- css = postProcessCSS(css);
163
- browser.createCSS(window.document, css, sheet);
164
- cache.setCSS(sheet.href, context.lastModified, css);
165
- }
166
- });
167
- }
168
- }, options.poll);
169
156
  }
170
- }
171
157
 
172
- //
173
- // Watch mode
174
- //
175
- less.watch = function () {
176
- if (!less.watchMode ){
177
- less.env = 'development';
178
- initRunningMode();
158
+ function initRunningMode() {
159
+ if (less.env === 'development') {
160
+ less.watchTimer = setInterval(function () {
161
+ if (less.watchMode) {
162
+ fileManager.clearFileCache();
163
+ loadStyleSheets(function (e, css, _, sheet, webInfo) {
164
+ if (e) {
165
+ errors.add(e, e.href || sheet.href);
166
+ } else if (css) {
167
+ browser.createCSS(window.document, css, sheet);
168
+ }
169
+ });
170
+ }
171
+ }, options.poll);
172
+ }
179
173
  }
180
- this.watchMode = true;
181
- return true;
182
- };
183
-
184
- less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };
185
174
 
186
- //
187
- // Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
188
- //
189
- less.registerStylesheets = function() {
190
- return new Promise(function(resolve, reject) {
191
- var links = document.getElementsByTagName('link');
192
- less.sheets = [];
193
-
194
- for (var i = 0; i < links.length; i++) {
195
- if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
196
- (links[i].type.match(typePattern)))) {
197
- less.sheets.push(links[i]);
198
- }
175
+ //
176
+ // Watch mode
177
+ //
178
+ less.watch = function () {
179
+ if (!less.watchMode ) {
180
+ less.env = 'development';
181
+ initRunningMode();
199
182
  }
183
+ this.watchMode = true;
184
+ return true;
185
+ };
200
186
 
201
- resolve();
202
- });
203
- };
187
+ less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };
188
+
189
+ //
190
+ // Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
191
+ //
192
+ less.registerStylesheets = function() {
193
+ return new Promise(function(resolve, reject) {
194
+ var links = document.getElementsByTagName('link');
195
+ less.sheets = [];
196
+
197
+ for (var i = 0; i < links.length; i++) {
198
+ if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
199
+ (links[i].type.match(typePattern)))) {
200
+ less.sheets.push(links[i]);
201
+ }
202
+ }
204
203
 
205
- //
206
- // With this function, it's possible to alter variables and re-render
207
- // CSS without reloading less-files
208
- //
209
- less.modifyVars = function(record) {
210
- return less.refresh(true, record, false);
211
- };
204
+ resolve();
205
+ });
206
+ };
212
207
 
213
- less.refresh = function (reload, modifyVars, clearFileCache) {
214
- if ((reload || clearFileCache) && clearFileCache !== false) {
215
- fileManager.clearFileCache();
216
- }
217
- return new Promise(function (resolve, reject) {
218
- var startTime, endTime, totalMilliseconds;
219
- startTime = endTime = new Date();
208
+ //
209
+ // With this function, it's possible to alter variables and re-render
210
+ // CSS without reloading less-files
211
+ //
212
+ less.modifyVars = function(record) {
213
+ return less.refresh(true, record, false);
214
+ };
220
215
 
221
- loadStyleSheets(function (e, css, _, sheet, webInfo) {
222
- if (e) {
223
- errors.add(e, e.href || sheet.href);
224
- reject(e);
225
- return;
226
- }
227
- if (webInfo.local) {
228
- less.logger.info("loading " + sheet.href + " from cache.");
229
- } else {
230
- less.logger.info("rendered " + sheet.href + " successfully.");
231
- css = postProcessCSS(css);
216
+ less.refresh = function (reload, modifyVars, clearFileCache) {
217
+ if ((reload || clearFileCache) && clearFileCache !== false) {
218
+ fileManager.clearFileCache();
219
+ }
220
+ return new Promise(function (resolve, reject) {
221
+ var startTime, endTime, totalMilliseconds;
222
+ startTime = endTime = new Date();
223
+
224
+ loadStyleSheets(function (e, css, _, sheet, webInfo) {
225
+ if (e) {
226
+ errors.add(e, e.href || sheet.href);
227
+ reject(e);
228
+ return;
229
+ }
230
+ if (webInfo.local) {
231
+ less.logger.info("loading " + sheet.href + " from cache.");
232
+ } else {
233
+ less.logger.info("rendered " + sheet.href + " successfully.");
234
+ }
232
235
  browser.createCSS(window.document, css, sheet);
233
- cache.setCSS(sheet.href, webInfo.lastModified, css);
234
- }
235
- less.logger.info("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
236
- if (webInfo.remaining === 0) {
237
- totalMilliseconds = new Date() - startTime;
238
- less.logger.info("less has finished. css generated in " + totalMilliseconds + 'ms');
239
- resolve({
240
- startTime: startTime,
241
- endTime: endTime,
242
- totalMilliseconds: totalMilliseconds,
243
- sheets: less.sheets.length
244
- });
245
- }
246
- endTime = new Date();
247
- }, reload, modifyVars);
248
-
249
- loadStyles(modifyVars);
250
- });
251
- };
236
+ less.logger.info("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms');
237
+ if (webInfo.remaining === 0) {
238
+ totalMilliseconds = new Date() - startTime;
239
+ less.logger.info("less has finished. css generated in " + totalMilliseconds + 'ms');
240
+ resolve({
241
+ startTime: startTime,
242
+ endTime: endTime,
243
+ totalMilliseconds: totalMilliseconds,
244
+ sheets: less.sheets.length
245
+ });
246
+ }
247
+ endTime = new Date();
248
+ }, reload, modifyVars);
249
+
250
+ loadStyles(modifyVars);
251
+ });
252
+ };
252
253
 
253
- less.refreshStyles = loadStyles;
254
+ less.refreshStyles = loadStyles;
254
255
  return less;
255
256
  };
@@ -11,7 +11,7 @@ module.exports = function(less, options) {
11
11
  // 1 - Errors
12
12
  // 0 - None
13
13
  // Defaults to 2
14
- options.logLevel = typeof(options.logLevel) !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error);
14
+ options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error);
15
15
 
16
16
  if (!options.loggers) {
17
17
  options.loggers = [{
@@ -37,7 +37,7 @@ module.exports = function(less, options) {
37
37
  }
38
38
  }];
39
39
  }
40
- for(var i = 0; i < options.loggers.length; i++) {
40
+ for (var i = 0; i < options.loggers.length; i++) {
41
41
  less.logger.addListener(options.loggers[i]);
42
42
  }
43
43
  };
@@ -1,11 +1,11 @@
1
1
  module.exports = {
2
2
  extractId: function(href) {
3
- return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain
4
- .replace(/[\?\&]livereload=\w+/,'' ) // Remove LiveReload cachebuster
5
- .replace(/^\//, '' ) // Remove root /
6
- .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension
7
- .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
8
- .replace(/\./g, ':'); // Replace dots with colons(for valid id)
3
+ return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain
4
+ .replace(/[\?\&]livereload=\w+/, '') // Remove LiveReload cachebuster
5
+ .replace(/^\//, '') // Remove root /
6
+ .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension
7
+ .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
8
+ .replace(/\./g, ':'); // Replace dots with colons(for valid id)
9
9
  },
10
10
  addDataAttr: function(options, tag) {
11
11
  for (var opt in tag.dataset) {
@@ -1,8 +1,13 @@
1
1
  var path = require('path'),
2
2
  fs = require('./fs'),
3
- PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise,
3
+ PromiseConstructor,
4
4
  AbstractFileManager = require("../less/environment/abstract-file-manager.js");
5
5
 
6
+ try {
7
+ PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
8
+ } catch(e) {
9
+ }
10
+
6
11
  var FileManager = function() {
7
12
  };
8
13
 
@@ -17,45 +22,35 @@ FileManager.prototype.supportsSync = function(filename, currentDirectory, option
17
22
 
18
23
  FileManager.prototype.loadFile = function(filename, currentDirectory, options, environment, callback) {
19
24
  var fullFilename,
20
- data;
25
+ data,
26
+ isAbsoluteFilename = this.isPathAbsolute(filename),
27
+ filenamesTried = [];
21
28
 
22
29
  options = options || {};
23
30
 
24
- var paths = [currentDirectory];
25
- if (options.paths) paths.push.apply(paths, options.paths);
26
- if (paths.indexOf('.') === -1) paths.push('.');
27
-
28
- if (options.syncImport) {
29
- var err, result;
30
- for (var i = 0; i < paths.length; i++) {
31
- try {
32
- fullFilename = path.join(paths[i], filename);
33
- fs.statSync(fullFilename);
34
- break;
35
- } catch (e) {
36
- fullFilename = null;
37
- }
38
- }
39
-
40
- if (!fullFilename) {
41
- err = { type: 'File', message: "'" + filename + "' wasn't found" };
42
- } else {
43
- data = fs.readFileSync(fullFilename, 'utf-8');
44
- result = { contents: data, filename: fullFilename};
45
- }
46
- callback(err, result);
31
+ if (options.syncImport || !PromiseConstructor) {
32
+ data = this.loadFileSync(filename, currentDirectory, options, environment, 'utf-8');
33
+ callback(data.error, data);
47
34
  return;
48
35
  }
49
36
 
37
+ var paths = isAbsoluteFilename ? [""] : [currentDirectory];
38
+ if (options.paths) { paths.push.apply(paths, options.paths); }
39
+ if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); }
40
+
50
41
  // promise is guarenteed to be asyncronous
51
42
  // which helps as it allows the file handle
52
43
  // to be closed before it continues with the next file
53
44
  return new PromiseConstructor(function(fulfill, reject) {
54
45
  (function tryPathIndex(i) {
55
46
  if (i < paths.length) {
56
- fullFilename = path.join(paths[i], filename);
47
+ fullFilename = filename;
48
+ if (paths[i]) {
49
+ fullFilename = path.join(paths[i], fullFilename);
50
+ }
57
51
  fs.stat(fullFilename, function (err) {
58
52
  if (err) {
53
+ filenamesTried.push(fullFilename);
59
54
  tryPathIndex(i + 1);
60
55
  } else {
61
56
  fs.readFile(fullFilename, 'utf-8', function(e, data) {
@@ -66,15 +61,48 @@ FileManager.prototype.loadFile = function(filename, currentDirectory, options, e
66
61
  }
67
62
  });
68
63
  } else {
69
- reject({ type: 'File', message: "'" + filename + "' wasn't found" });
64
+ reject({ type: 'File', message: "'" + filename + "' wasn't found. Tried - " + filenamesTried.join(",") });
70
65
  }
71
66
  }(0));
72
67
  });
73
68
  };
74
69
 
75
- FileManager.prototype.loadFileSync = function(filename, currentDirectory, options, environment) {
76
- filename = path.join(currentDirectory, filename);
77
- return { contents: fs.readFileSync(filename), filename: filename };
70
+ FileManager.prototype.loadFileSync = function(filename, currentDirectory, options, environment, encoding) {
71
+ var fullFilename, paths, filenamesTried = [], isAbsoluteFilename = this.isPathAbsolute(filename) , data;
72
+ options = options || {};
73
+
74
+ paths = isAbsoluteFilename ? [""] : [currentDirectory];
75
+ if (options.paths) {
76
+ paths.push.apply(paths, options.paths);
77
+ }
78
+ if (!isAbsoluteFilename && paths.indexOf('.') === -1) {
79
+ paths.push('.');
80
+ }
81
+
82
+ var err, result;
83
+ for (var i = 0; i < paths.length; i++) {
84
+ try {
85
+ fullFilename = filename;
86
+ if (paths[i]) {
87
+ fullFilename = path.join(paths[i], fullFilename);
88
+ }
89
+ filenamesTried.push(fullFilename);
90
+ fs.statSync(fullFilename);
91
+ break;
92
+ } catch (e) {
93
+ fullFilename = null;
94
+ }
95
+ }
96
+
97
+ if (!fullFilename) {
98
+ err = { type: 'File', message: "'" + filename + "' wasn't found. Tried - " + filenamesTried.join(",") };
99
+ result = { error: err };
100
+ } else {
101
+ data = fs.readFileSync(fullFilename, encoding);
102
+ result = { contents: data, filename: fullFilename};
103
+ }
104
+
105
+ return result;
78
106
  };
79
107
 
80
108
  module.exports = FileManager;
@@ -0,0 +1,34 @@
1
+ var Dimension = require("../less/tree/dimension"),
2
+ Expression = require("../less/tree/expression"),
3
+ functionRegistry = require("./../less/functions/function-registry"),
4
+ path = require("path");
5
+
6
+ function imageSize(filePathNode) {
7
+ var filePath = filePathNode.value;
8
+ var currentDirectory = filePathNode.currentFileInfo.relativeUrls ?
9
+ filePathNode.currentFileInfo.currentDirectory : filePathNode.currentFileInfo.entryPath;
10
+
11
+ var sizeOf = require('image-size');
12
+ filePath = path.join(currentDirectory, filePath);
13
+ return sizeOf(filePath);
14
+ }
15
+
16
+ var imageFunctions = {
17
+ "image-size": function(filePathNode) {
18
+ var size = imageSize(filePathNode);
19
+ return new Expression([
20
+ new Dimension(size.width, "px"),
21
+ new Dimension(size.height, "px")
22
+ ]);
23
+ },
24
+ "image-width": function(filePathNode) {
25
+ var size = imageSize(filePathNode);
26
+ return new Dimension(size.width, "px");
27
+ },
28
+ "image-height": function(filePathNode) {
29
+ var size = imageSize(filePathNode);
30
+ return new Dimension(size.height, "px");
31
+ }
32
+ };
33
+
34
+ functionRegistry.addMultiple(imageFunctions);