less 3.10.0-beta.2 → 3.10.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.
- package/.DS_Store +0 -0
- package/bin/lessc +6652 -5505
- package/dist/less.cjs.js +6593 -5448
- package/dist/less.js +10 -6
- package/dist/less.min.js +2 -2
- package/dist/less.min.js.map +1 -1
- package/lib/less/constants.js +13 -0
- package/lib/less/contexts.js +164 -0
- package/lib/less/data/colors.js +150 -0
- package/lib/less/data/index.js +4 -0
- package/lib/less/data/unit-conversions.js +21 -0
- package/lib/less/default-options.js +68 -0
- package/lib/less/environment/abstract-file-manager.js +127 -0
- package/lib/less/environment/abstract-plugin-loader.js +187 -0
- package/lib/less/environment/environment-api.js +25 -0
- package/lib/less/environment/environment.js +59 -0
- package/lib/less/environment/file-manager-api.js +103 -0
- package/lib/less/functions/boolean.js +13 -0
- package/lib/less/functions/color-blending.js +84 -0
- package/lib/less/functions/color.js +417 -0
- package/lib/less/functions/data-uri.js +74 -0
- package/lib/less/functions/default.js +25 -0
- package/lib/less/functions/function-caller.js +49 -0
- package/lib/less/functions/function-registry.js +35 -0
- package/lib/less/functions/index.js +33 -0
- package/lib/less/functions/list.js +143 -0
- package/lib/less/functions/math-helper.js +15 -0
- package/lib/less/functions/math.js +28 -0
- package/lib/less/functions/number.js +89 -0
- package/lib/less/functions/string.js +36 -0
- package/lib/less/functions/svg.js +87 -0
- package/lib/less/functions/types.js +70 -0
- package/lib/less/import-manager.js +169 -0
- package/lib/less/index.js +92 -0
- package/lib/less/less-error.js +140 -0
- package/lib/less/logger.js +34 -0
- package/lib/less/parse-tree.js +66 -0
- package/lib/less/parse.js +89 -0
- package/lib/less/parser/chunker.js +122 -0
- package/lib/less/parser/parser-input.js +390 -0
- package/lib/less/parser/parser.js +2418 -0
- package/lib/less/plugin-manager.js +168 -0
- package/lib/less/render.js +42 -0
- package/lib/less/source-map-builder.js +77 -0
- package/lib/less/source-map-output.js +149 -0
- package/lib/less/transform-tree.js +96 -0
- package/lib/less/tree/anonymous.js +37 -0
- package/lib/less/tree/assignment.js +33 -0
- package/lib/less/tree/atrule.js +165 -0
- package/lib/less/tree/attribute.js +34 -0
- package/lib/less/tree/call.js +105 -0
- package/lib/less/tree/color.js +246 -0
- package/lib/less/tree/combinator.js +29 -0
- package/lib/less/tree/comment.js +29 -0
- package/lib/less/tree/condition.js +43 -0
- package/lib/less/tree/debug-info.js +34 -0
- package/lib/less/tree/declaration.js +115 -0
- package/lib/less/tree/detached-ruleset.js +30 -0
- package/lib/less/tree/dimension.js +179 -0
- package/lib/less/tree/element.js +73 -0
- package/lib/less/tree/expression.js +74 -0
- package/lib/less/tree/extend.js +66 -0
- package/lib/less/tree/import.js +184 -0
- package/lib/less/tree/index.js +54 -0
- package/lib/less/tree/javascript.js +33 -0
- package/lib/less/tree/js-eval-node.js +58 -0
- package/lib/less/tree/keyword.js +21 -0
- package/lib/less/tree/media.js +154 -0
- package/lib/less/tree/mixin-call.js +215 -0
- package/lib/less/tree/mixin-definition.js +229 -0
- package/lib/less/tree/namespace-value.js +87 -0
- package/lib/less/tree/negative.js +26 -0
- package/lib/less/tree/node.js +178 -0
- package/lib/less/tree/operation.js +62 -0
- package/lib/less/tree/paren.js +22 -0
- package/lib/less/tree/property.js +77 -0
- package/lib/less/tree/quoted.js +70 -0
- package/lib/less/tree/ruleset.js +867 -0
- package/lib/less/tree/selector.js +146 -0
- package/lib/less/tree/unicode-descriptor.js +13 -0
- package/lib/less/tree/unit.js +141 -0
- package/lib/less/tree/url.js +65 -0
- package/lib/less/tree/value.js +44 -0
- package/lib/less/tree/variable-call.js +46 -0
- package/lib/less/tree/variable.js +67 -0
- package/lib/less/utils.js +122 -0
- package/lib/less/visitors/extend-visitor.js +505 -0
- package/lib/less/visitors/import-sequencer.js +58 -0
- package/lib/less/visitors/import-visitor.js +189 -0
- package/lib/less/visitors/index.js +15 -0
- package/lib/less/visitors/join-selector-visitor.js +57 -0
- package/lib/less/visitors/set-tree-visibility-visitor.js +45 -0
- package/lib/less/visitors/to-css-visitor.js +363 -0
- package/lib/less/visitors/visitor.js +163 -0
- package/lib/less-browser/add-default-options.js +49 -0
- package/lib/less-browser/bootstrap.js +69 -0
- package/lib/less-browser/browser.js +65 -0
- package/lib/less-browser/cache.js +43 -0
- package/lib/less-browser/error-reporting.js +170 -0
- package/lib/less-browser/file-manager.js +113 -0
- package/lib/less-browser/image-size.js +28 -0
- package/lib/less-browser/index.js +285 -0
- package/lib/less-browser/log-listener.js +42 -0
- package/lib/less-browser/plugin-loader.js +26 -0
- package/lib/less-browser/utils.js +24 -0
- package/lib/less-node/environment.js +16 -0
- package/lib/less-node/file-manager.js +177 -0
- package/lib/less-node/fs.js +10 -0
- package/lib/less-node/image-size.js +58 -0
- package/lib/less-node/index.js +27 -0
- package/lib/less-node/lessc-helper.js +89 -0
- package/lib/less-node/plugin-loader.js +53 -0
- package/lib/less-node/url-file-manager.js +49 -0
- package/lib/lessc.js +557 -0
- package/lib/source-map/source-map-0.1.31.js +1933 -0
- package/lib/source-map/source-map-footer.js +4 -0
- package/lib/source-map/source-map-header.js +3 -0
- package/package.json +1 -1
- package/test/.DS_Store +0 -0
- package/test/browser/less.min.js +11 -0
- package/test/browser/less.min.js.map +1 -0
- package/test/css/css-escapes.css +1 -0
- package/test/less/css-escapes.less +3 -1
- package/.git/index +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
import functionRegistry from './../less/functions/function-registry';
|
|
3
|
+
|
|
4
|
+
export default () => {
|
|
5
|
+
function imageSize() {
|
|
6
|
+
throw {
|
|
7
|
+
type: 'Runtime',
|
|
8
|
+
message: 'Image size functions are not supported in browser version of less'
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const imageFunctions = {
|
|
13
|
+
'image-size': function(filePathNode) {
|
|
14
|
+
imageSize(this, filePathNode);
|
|
15
|
+
return -1;
|
|
16
|
+
},
|
|
17
|
+
'image-width': function(filePathNode) {
|
|
18
|
+
imageSize(this, filePathNode);
|
|
19
|
+
return -1;
|
|
20
|
+
},
|
|
21
|
+
'image-height': function(filePathNode) {
|
|
22
|
+
imageSize(this, filePathNode);
|
|
23
|
+
return -1;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
functionRegistry.addMultiple(imageFunctions);
|
|
28
|
+
};
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
//
|
|
2
|
+
// index.js
|
|
3
|
+
// Should expose the additional browser functions on to the less object
|
|
4
|
+
//
|
|
5
|
+
import {addDataAttr} from './utils';
|
|
6
|
+
import lessRoot from '../less';
|
|
7
|
+
import browser from './browser';
|
|
8
|
+
import FM from './file-manager';
|
|
9
|
+
import PluginLoader from './plugin-loader';
|
|
10
|
+
import LogListener from './log-listener';
|
|
11
|
+
import ErrorReporting from './error-reporting';
|
|
12
|
+
import Cache from './cache';
|
|
13
|
+
import ImageSize from './image-size';
|
|
14
|
+
|
|
15
|
+
export default (window, options) => {
|
|
16
|
+
const document = window.document;
|
|
17
|
+
const less = lessRoot();
|
|
18
|
+
|
|
19
|
+
less.options = options;
|
|
20
|
+
const environment = less.environment;
|
|
21
|
+
const FileManager = FM(options, less.logger);
|
|
22
|
+
const fileManager = new FileManager();
|
|
23
|
+
environment.addFileManager(fileManager);
|
|
24
|
+
less.FileManager = FileManager;
|
|
25
|
+
less.PluginLoader = PluginLoader;
|
|
26
|
+
|
|
27
|
+
LogListener(less, options);
|
|
28
|
+
const errors = ErrorReporting(window, less, options);
|
|
29
|
+
const cache = less.cache = options.cache || Cache(window, options, less.logger);
|
|
30
|
+
ImageSize(less.environment);
|
|
31
|
+
|
|
32
|
+
// Setup user functions - Deprecate?
|
|
33
|
+
if (options.functions) {
|
|
34
|
+
less.functions.functionRegistry.addMultiple(options.functions);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const typePattern = /^text\/(x-)?less$/;
|
|
38
|
+
|
|
39
|
+
function clone(obj) {
|
|
40
|
+
const cloned = {};
|
|
41
|
+
for (const prop in obj) {
|
|
42
|
+
if (obj.hasOwnProperty(prop)) {
|
|
43
|
+
cloned[prop] = obj[prop];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return cloned;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// only really needed for phantom
|
|
50
|
+
function bind(func, thisArg) {
|
|
51
|
+
const curryArgs = Array.prototype.slice.call(arguments, 2);
|
|
52
|
+
return function() {
|
|
53
|
+
const args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));
|
|
54
|
+
return func.apply(thisArg, args);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function loadStyles(modifyVars) {
|
|
59
|
+
const styles = document.getElementsByTagName('style');
|
|
60
|
+
let style;
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < styles.length; i++) {
|
|
63
|
+
style = styles[i];
|
|
64
|
+
if (style.type.match(typePattern)) {
|
|
65
|
+
const instanceOptions = clone(options);
|
|
66
|
+
instanceOptions.modifyVars = modifyVars;
|
|
67
|
+
const lessText = style.innerHTML || '';
|
|
68
|
+
instanceOptions.filename = document.location.href.replace(/#.*$/, '');
|
|
69
|
+
|
|
70
|
+
/* jshint loopfunc:true */
|
|
71
|
+
// use closure to store current style
|
|
72
|
+
less.render(lessText, instanceOptions,
|
|
73
|
+
bind((style, e, result) => {
|
|
74
|
+
if (e) {
|
|
75
|
+
errors.add(e, 'inline');
|
|
76
|
+
} else {
|
|
77
|
+
style.type = 'text/css';
|
|
78
|
+
if (style.styleSheet) {
|
|
79
|
+
style.styleSheet.cssText = result.css;
|
|
80
|
+
} else {
|
|
81
|
+
style.innerHTML = result.css;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}, null, style));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
|
|
90
|
+
|
|
91
|
+
const instanceOptions = clone(options);
|
|
92
|
+
addDataAttr(instanceOptions, sheet);
|
|
93
|
+
instanceOptions.mime = sheet.type;
|
|
94
|
+
|
|
95
|
+
if (modifyVars) {
|
|
96
|
+
instanceOptions.modifyVars = modifyVars;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function loadInitialFileCallback(loadedFile) {
|
|
100
|
+
const data = loadedFile.contents;
|
|
101
|
+
const path = loadedFile.filename;
|
|
102
|
+
const webInfo = loadedFile.webInfo;
|
|
103
|
+
|
|
104
|
+
const newFileInfo = {
|
|
105
|
+
currentDirectory: fileManager.getPath(path),
|
|
106
|
+
filename: path,
|
|
107
|
+
rootFilename: path,
|
|
108
|
+
rewriteUrls: instanceOptions.rewriteUrls
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
newFileInfo.entryPath = newFileInfo.currentDirectory;
|
|
112
|
+
newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
|
|
113
|
+
|
|
114
|
+
if (webInfo) {
|
|
115
|
+
webInfo.remaining = remaining;
|
|
116
|
+
|
|
117
|
+
const css = cache.getCSS(path, webInfo, instanceOptions.modifyVars);
|
|
118
|
+
if (!reload && css) {
|
|
119
|
+
webInfo.local = true;
|
|
120
|
+
callback(null, css, data, sheet, webInfo, path);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// TODO add tests around how this behaves when reloading
|
|
127
|
+
errors.remove(path);
|
|
128
|
+
|
|
129
|
+
instanceOptions.rootFileInfo = newFileInfo;
|
|
130
|
+
less.render(data, instanceOptions, (e, result) => {
|
|
131
|
+
if (e) {
|
|
132
|
+
e.href = path;
|
|
133
|
+
callback(e);
|
|
134
|
+
} else {
|
|
135
|
+
cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css);
|
|
136
|
+
callback(null, result.css, data, sheet, webInfo, path);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fileManager.loadFile(sheet.href, null, instanceOptions, environment)
|
|
142
|
+
.then(loadedFile => {
|
|
143
|
+
loadInitialFileCallback(loadedFile);
|
|
144
|
+
}).catch(err => {
|
|
145
|
+
console.log(err);
|
|
146
|
+
callback(err);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function loadStyleSheets(callback, reload, modifyVars) {
|
|
152
|
+
for (let i = 0; i < less.sheets.length; i++) {
|
|
153
|
+
loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function initRunningMode() {
|
|
158
|
+
if (less.env === 'development') {
|
|
159
|
+
less.watchTimer = setInterval(() => {
|
|
160
|
+
if (less.watchMode) {
|
|
161
|
+
fileManager.clearFileCache();
|
|
162
|
+
loadStyleSheets((e, css, _, sheet, webInfo) => {
|
|
163
|
+
if (e) {
|
|
164
|
+
errors.add(e, e.href || sheet.href);
|
|
165
|
+
} else if (css) {
|
|
166
|
+
browser.createCSS(window.document, css, sheet);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}, options.poll);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
//
|
|
175
|
+
// Watch mode
|
|
176
|
+
//
|
|
177
|
+
less.watch = function () {
|
|
178
|
+
if (!less.watchMode ) {
|
|
179
|
+
less.env = 'development';
|
|
180
|
+
initRunningMode();
|
|
181
|
+
}
|
|
182
|
+
this.watchMode = true;
|
|
183
|
+
return true;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };
|
|
187
|
+
|
|
188
|
+
//
|
|
189
|
+
// Synchronously get all <link> tags with the 'rel' attribute set to
|
|
190
|
+
// "stylesheet/less".
|
|
191
|
+
//
|
|
192
|
+
less.registerStylesheetsImmediately = () => {
|
|
193
|
+
const links = document.getElementsByTagName('link');
|
|
194
|
+
less.sheets = [];
|
|
195
|
+
|
|
196
|
+
for (let i = 0; i < links.length; i++) {
|
|
197
|
+
if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
|
|
198
|
+
(links[i].type.match(typePattern)))) {
|
|
199
|
+
less.sheets.push(links[i]);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
//
|
|
205
|
+
// Asynchronously get all <link> tags with the 'rel' attribute set to
|
|
206
|
+
// "stylesheet/less", returning a Promise.
|
|
207
|
+
//
|
|
208
|
+
less.registerStylesheets = () => new Promise((resolve, reject) => {
|
|
209
|
+
less.registerStylesheetsImmediately();
|
|
210
|
+
resolve();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
//
|
|
214
|
+
// With this function, it's possible to alter variables and re-render
|
|
215
|
+
// CSS without reloading less-files
|
|
216
|
+
//
|
|
217
|
+
less.modifyVars = record => less.refresh(true, record, false);
|
|
218
|
+
|
|
219
|
+
less.refresh = (reload, modifyVars, clearFileCache) => {
|
|
220
|
+
if ((reload || clearFileCache) && clearFileCache !== false) {
|
|
221
|
+
fileManager.clearFileCache();
|
|
222
|
+
}
|
|
223
|
+
return new Promise((resolve, reject) => {
|
|
224
|
+
let startTime;
|
|
225
|
+
let endTime;
|
|
226
|
+
let totalMilliseconds;
|
|
227
|
+
let remainingSheets;
|
|
228
|
+
startTime = endTime = new Date();
|
|
229
|
+
|
|
230
|
+
// Set counter for remaining unprocessed sheets
|
|
231
|
+
remainingSheets = less.sheets.length;
|
|
232
|
+
|
|
233
|
+
if (remainingSheets === 0) {
|
|
234
|
+
|
|
235
|
+
endTime = new Date();
|
|
236
|
+
totalMilliseconds = endTime - startTime;
|
|
237
|
+
less.logger.info('Less has finished and no sheets were loaded.');
|
|
238
|
+
resolve({
|
|
239
|
+
startTime,
|
|
240
|
+
endTime,
|
|
241
|
+
totalMilliseconds,
|
|
242
|
+
sheets: less.sheets.length
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
} else {
|
|
246
|
+
// Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array
|
|
247
|
+
loadStyleSheets((e, css, _, sheet, webInfo) => {
|
|
248
|
+
if (e) {
|
|
249
|
+
errors.add(e, e.href || sheet.href);
|
|
250
|
+
reject(e);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (webInfo.local) {
|
|
254
|
+
less.logger.info(`Loading ${sheet.href} from cache.`);
|
|
255
|
+
} else {
|
|
256
|
+
less.logger.info(`Rendered ${sheet.href} successfully.`);
|
|
257
|
+
}
|
|
258
|
+
browser.createCSS(window.document, css, sheet);
|
|
259
|
+
less.logger.info(`CSS for ${sheet.href} generated in ${new Date() - endTime}ms`);
|
|
260
|
+
|
|
261
|
+
// Count completed sheet
|
|
262
|
+
remainingSheets--;
|
|
263
|
+
|
|
264
|
+
// Check if the last remaining sheet was processed and then call the promise
|
|
265
|
+
if (remainingSheets === 0) {
|
|
266
|
+
totalMilliseconds = new Date() - startTime;
|
|
267
|
+
less.logger.info(`Less has finished. CSS generated in ${totalMilliseconds}ms`);
|
|
268
|
+
resolve({
|
|
269
|
+
startTime,
|
|
270
|
+
endTime,
|
|
271
|
+
totalMilliseconds,
|
|
272
|
+
sheets: less.sheets.length
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
endTime = new Date();
|
|
276
|
+
}, reload, modifyVars);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
loadStyles(modifyVars);
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
less.refreshStyles = loadStyles;
|
|
284
|
+
return less;
|
|
285
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export default (less, options) => {
|
|
2
|
+
const logLevel_debug = 4;
|
|
3
|
+
const logLevel_info = 3;
|
|
4
|
+
const logLevel_warn = 2;
|
|
5
|
+
const logLevel_error = 1;
|
|
6
|
+
|
|
7
|
+
// The amount of logging in the javascript console.
|
|
8
|
+
// 3 - Debug, information and errors
|
|
9
|
+
// 2 - Information and errors
|
|
10
|
+
// 1 - Errors
|
|
11
|
+
// 0 - None
|
|
12
|
+
// Defaults to 2
|
|
13
|
+
options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ? logLevel_info : logLevel_error);
|
|
14
|
+
|
|
15
|
+
if (!options.loggers) {
|
|
16
|
+
options.loggers = [{
|
|
17
|
+
debug: function(msg) {
|
|
18
|
+
if (options.logLevel >= logLevel_debug) {
|
|
19
|
+
console.log(msg);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
info: function(msg) {
|
|
23
|
+
if (options.logLevel >= logLevel_info) {
|
|
24
|
+
console.log(msg);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
warn: function(msg) {
|
|
28
|
+
if (options.logLevel >= logLevel_warn) {
|
|
29
|
+
console.warn(msg);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
error: function(msg) {
|
|
33
|
+
if (options.logLevel >= logLevel_error) {
|
|
34
|
+
console.error(msg);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}];
|
|
38
|
+
}
|
|
39
|
+
for (let i = 0; i < options.loggers.length; i++) {
|
|
40
|
+
less.logger.addListener(options.loggers[i]);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// TODO: Add tests for browser @plugin
|
|
2
|
+
/* global window */
|
|
3
|
+
|
|
4
|
+
import AbstractPluginLoader from '../less/environment/abstract-plugin-loader.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Browser Plugin Loader
|
|
8
|
+
*/
|
|
9
|
+
class PluginLoader extends AbstractPluginLoader {
|
|
10
|
+
constructor(less) {
|
|
11
|
+
super();
|
|
12
|
+
|
|
13
|
+
this.less = less;
|
|
14
|
+
// Should we shim this.require for browser? Probably not?
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
loadPlugin(filename, basePath, context, environment, fileManager) {
|
|
18
|
+
return new Promise((fulfill, reject) => {
|
|
19
|
+
fileManager.loadFile(filename, basePath, context, environment)
|
|
20
|
+
.then(fulfill).catch(reject);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default PluginLoader;
|
|
26
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
export function extractId(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)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function addDataAttr(options, tag) {
|
|
12
|
+
for (const opt in tag.dataset) {
|
|
13
|
+
if (tag.dataset.hasOwnProperty(opt)) {
|
|
14
|
+
if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') {
|
|
15
|
+
options[opt] = tag.dataset[opt];
|
|
16
|
+
} else {
|
|
17
|
+
try {
|
|
18
|
+
options[opt] = JSON.parse(tag.dataset[opt]);
|
|
19
|
+
}
|
|
20
|
+
catch (_) {}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
encodeBase64: function encodeBase64(str) {
|
|
3
|
+
// Avoid Buffer constructor on newer versions of Node.js.
|
|
4
|
+
const buffer = (Buffer.from ? Buffer.from(str) : (new Buffer(str)));
|
|
5
|
+
return buffer.toString('base64');
|
|
6
|
+
},
|
|
7
|
+
mimeLookup: function (filename) {
|
|
8
|
+
return require('mime').lookup(filename);
|
|
9
|
+
},
|
|
10
|
+
charsetLookup: function (mime) {
|
|
11
|
+
return require('mime').charsets.lookup(mime);
|
|
12
|
+
},
|
|
13
|
+
getSourceMapGenerator: function getSourceMapGenerator() {
|
|
14
|
+
return require('source-map').SourceMapGenerator;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from './fs';
|
|
3
|
+
import AbstractFileManager from '../less/environment/abstract-file-manager.js';
|
|
4
|
+
|
|
5
|
+
class FileManager extends AbstractFileManager {
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
|
|
9
|
+
this.contents = {};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
supports(filename, currentDirectory, options, environment) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
supportsSync(filename, currentDirectory, options, environment) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
loadFile(filename, currentDirectory, options, environment, callback) {
|
|
21
|
+
let fullFilename;
|
|
22
|
+
const isAbsoluteFilename = this.isPathAbsolute(filename);
|
|
23
|
+
const filenamesTried = [];
|
|
24
|
+
const self = this;
|
|
25
|
+
const prefix = filename.slice(0, 1);
|
|
26
|
+
const explicit = prefix === '.' || prefix === '/';
|
|
27
|
+
let result = null;
|
|
28
|
+
let isNodeModule = false;
|
|
29
|
+
const npmPrefix = 'npm://';
|
|
30
|
+
|
|
31
|
+
options = options || {};
|
|
32
|
+
|
|
33
|
+
const paths = isAbsoluteFilename ? [''] : [currentDirectory];
|
|
34
|
+
|
|
35
|
+
if (options.paths) { paths.push(...options.paths); }
|
|
36
|
+
|
|
37
|
+
if (!isAbsoluteFilename && paths.indexOf('.') === -1) { paths.push('.'); }
|
|
38
|
+
|
|
39
|
+
const prefixes = options.prefixes || [''];
|
|
40
|
+
const fileParts = this.extractUrlParts(filename);
|
|
41
|
+
|
|
42
|
+
if (options.syncImport) {
|
|
43
|
+
getFileData(returnData, returnData);
|
|
44
|
+
if (callback) {
|
|
45
|
+
callback(result.error, result);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// promise is guaranteed to be asyncronous
|
|
53
|
+
// which helps as it allows the file handle
|
|
54
|
+
// to be closed before it continues with the next file
|
|
55
|
+
return new Promise(getFileData);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function returnData(data) {
|
|
59
|
+
if (!data.filename) {
|
|
60
|
+
result = { error: data };
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
result = data;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getFileData(fulfill, reject) {
|
|
68
|
+
(function tryPathIndex(i) {
|
|
69
|
+
if (i < paths.length) {
|
|
70
|
+
(function tryPrefix(j) {
|
|
71
|
+
if (j < prefixes.length) {
|
|
72
|
+
isNodeModule = false;
|
|
73
|
+
fullFilename = fileParts.rawPath + prefixes[j] + fileParts.filename;
|
|
74
|
+
|
|
75
|
+
if (paths[i]) {
|
|
76
|
+
fullFilename = path.join(paths[i], fullFilename);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!explicit && paths[i] === '.') {
|
|
80
|
+
try {
|
|
81
|
+
fullFilename = require.resolve(fullFilename);
|
|
82
|
+
isNodeModule = true;
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
filenamesTried.push(npmPrefix + fullFilename);
|
|
86
|
+
tryWithExtension();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
tryWithExtension();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function tryWithExtension() {
|
|
94
|
+
const extFilename = options.ext ? self.tryAppendExtension(fullFilename, options.ext) : fullFilename;
|
|
95
|
+
|
|
96
|
+
if (extFilename !== fullFilename && !explicit && paths[i] === '.') {
|
|
97
|
+
try {
|
|
98
|
+
fullFilename = require.resolve(extFilename);
|
|
99
|
+
isNodeModule = true;
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
filenamesTried.push(npmPrefix + extFilename);
|
|
103
|
+
fullFilename = extFilename;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
fullFilename = extFilename;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let modified = false;
|
|
112
|
+
|
|
113
|
+
if (self.contents[fullFilename]) {
|
|
114
|
+
try {
|
|
115
|
+
var stat = fs.statSync.apply(this, [fullFilename]);
|
|
116
|
+
if (stat.mtime.getTime() === self.contents[fullFilename].mtime.getTime()) {
|
|
117
|
+
fulfill({ contents: self.contents[fullFilename].data, filename: fullFilename});
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
modified = true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
modified = true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (modified || !self.contents[fullFilename]) {
|
|
128
|
+
const readFileArgs = [fullFilename];
|
|
129
|
+
if (!options.rawBuffer) {
|
|
130
|
+
readFileArgs.push('utf-8');
|
|
131
|
+
}
|
|
132
|
+
if (options.syncImport) {
|
|
133
|
+
try {
|
|
134
|
+
const data = fs.readFileSync.apply(this, readFileArgs);
|
|
135
|
+
var stat = fs.statSync.apply(this, [fullFilename]);
|
|
136
|
+
self.contents[fullFilename] = { data, mtime: stat.mtime };
|
|
137
|
+
fulfill({ contents: data, filename: fullFilename});
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename);
|
|
141
|
+
return tryPrefix(j + 1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
readFileArgs.push(function(e, data) {
|
|
146
|
+
if (e) {
|
|
147
|
+
filenamesTried.push(isNodeModule ? npmPrefix + fullFilename : fullFilename);
|
|
148
|
+
return tryPrefix(j + 1);
|
|
149
|
+
}
|
|
150
|
+
const stat = fs.statSync.apply(this, [fullFilename]);
|
|
151
|
+
self.contents[fullFilename] = { data, mtime: stat.mtime };
|
|
152
|
+
fulfill({ contents: data, filename: fullFilename});
|
|
153
|
+
});
|
|
154
|
+
fs.readFile.apply(this, readFileArgs);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
tryPathIndex(i + 1);
|
|
162
|
+
}
|
|
163
|
+
})(0);
|
|
164
|
+
} else {
|
|
165
|
+
reject({ type: 'File', message: `'${filename}' wasn't found. Tried - ${filenamesTried.join(',')}` });
|
|
166
|
+
}
|
|
167
|
+
}(0));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
loadFileSync(filename, currentDirectory, options, environment) {
|
|
172
|
+
options.syncImport = true;
|
|
173
|
+
return this.loadFile(filename, currentDirectory, options, environment);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export default FileManager;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Dimension from '../less/tree/dimension';
|
|
2
|
+
import Expression from '../less/tree/expression';
|
|
3
|
+
import functionRegistry from './../less/functions/function-registry';
|
|
4
|
+
|
|
5
|
+
export default environment => {
|
|
6
|
+
|
|
7
|
+
function imageSize(functionContext, filePathNode) {
|
|
8
|
+
let filePath = filePathNode.value;
|
|
9
|
+
const currentFileInfo = functionContext.currentFileInfo;
|
|
10
|
+
const currentDirectory = currentFileInfo.rewriteUrls ?
|
|
11
|
+
currentFileInfo.currentDirectory : currentFileInfo.entryPath;
|
|
12
|
+
|
|
13
|
+
const fragmentStart = filePath.indexOf('#');
|
|
14
|
+
let fragment = '';
|
|
15
|
+
if (fragmentStart !== -1) {
|
|
16
|
+
fragment = filePath.slice(fragmentStart);
|
|
17
|
+
filePath = filePath.slice(0, fragmentStart);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const fileManager = environment.getFileManager(filePath, currentDirectory, functionContext.context, environment, true);
|
|
21
|
+
|
|
22
|
+
if (!fileManager) {
|
|
23
|
+
throw {
|
|
24
|
+
type: 'File',
|
|
25
|
+
message: `Can not set up FileManager for ${filePathNode}`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const fileSync = fileManager.loadFileSync(filePath, currentDirectory, functionContext.context, environment);
|
|
30
|
+
|
|
31
|
+
if (fileSync.error) {
|
|
32
|
+
throw fileSync.error;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const sizeOf = require('image-size');
|
|
36
|
+
return sizeOf(fileSync.filename);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const imageFunctions = {
|
|
40
|
+
'image-size': function(filePathNode) {
|
|
41
|
+
const size = imageSize(this, filePathNode);
|
|
42
|
+
return new Expression([
|
|
43
|
+
new Dimension(size.width, 'px'),
|
|
44
|
+
new Dimension(size.height, 'px')
|
|
45
|
+
]);
|
|
46
|
+
},
|
|
47
|
+
'image-width': function(filePathNode) {
|
|
48
|
+
const size = imageSize(this, filePathNode);
|
|
49
|
+
return new Dimension(size.width, 'px');
|
|
50
|
+
},
|
|
51
|
+
'image-height': function(filePathNode) {
|
|
52
|
+
const size = imageSize(this, filePathNode);
|
|
53
|
+
return new Dimension(size.height, 'px');
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
functionRegistry.addMultiple(imageFunctions);
|
|
58
|
+
};
|