1 | var _ = require('underscore');
|
2 | var fs = require('fs');
|
3 | var path = require('path');
|
4 | var async = require('async');
|
5 |
|
6 | var AssetCollector = function(type, collection, tags, brand)
|
7 | {
|
8 | this.fileExtension = type;
|
9 | this.collection = collection;
|
10 | this.tags = tags || [];
|
11 | this.brand = brand;
|
12 | };
|
13 |
|
14 | AssetCollector.prototype = {
|
15 |
|
16 | collect : function(callback)
|
17 | {
|
18 | var locationList = [];
|
19 | var resultList = {};
|
20 | _.each(this.collection.locations, function(entry, key){
|
21 | locationList.push(_.extend(entry, {
|
22 | path: key
|
23 | }));
|
24 | resultList[key] = {};
|
25 | });
|
26 |
|
27 | async.each(locationList,
|
28 | (function(item, callback){
|
29 | this.parseSection(item, item.path, function(files){
|
30 | resultList[item.path] = files;
|
31 | callback();
|
32 | });
|
33 | }).bind(this), function(assetConfig, assetPath)
|
34 | {
|
35 | var result = _.reduce(resultList, function(memo, num){
|
36 | return memo.concat(num);
|
37 | }, []);
|
38 |
|
39 | callback(result);
|
40 | });
|
41 | },
|
42 |
|
43 | parseSection : function(assetConfig, assetPath, callback)
|
44 | {
|
45 | var modifier = _.pick(assetConfig, 'include', 'exclude');
|
46 |
|
47 | fs.realpath(path.join(process.cwd(), assetPath), (function(err, assetPath){
|
48 |
|
49 | if( err )
|
50 | {
|
51 | callback([]);
|
52 | }
|
53 | else
|
54 | {
|
55 |
|
56 | switch(assetConfig.pattern)
|
57 | {
|
58 | case 'file':
|
59 | if( this.tags.length )
|
60 | {
|
61 | callback([]);
|
62 | break;
|
63 |
|
64 | }
|
65 |
|
66 | if( !fs.existsSync(assetPath) )
|
67 | {
|
68 | callback([]);
|
69 | break;
|
70 |
|
71 | }
|
72 | if( !this.hasValidFileEnd(assetPath, this.fileExtension) )
|
73 | {
|
74 | callback([]);
|
75 | break;
|
76 |
|
77 | }
|
78 | if( !this.isFileIncluded(assetPath, modifier) )
|
79 | {
|
80 | callback([]);
|
81 | break;
|
82 |
|
83 | }
|
84 |
|
85 | callback([assetPath]);
|
86 | break;
|
87 |
|
88 | case 'folder':
|
89 |
|
90 |
|
91 | this.getFolderAssets(assetPath, this.fileExtension, null, null, (function(files){
|
92 |
|
93 | callback(this.filterAssets(files, assetPath, modifier, this.fileExtension));
|
94 | }).bind(this));
|
95 | break;
|
96 |
|
97 | case 'module_flat':
|
98 | files = this.getModuleAssets(assetPath, this.fileExtension);
|
99 | files = this.filterAssets(files, assetPath, modifier, this.fileExtension);
|
100 | callback(files);
|
101 | break;
|
102 |
|
103 | case 'module':
|
104 | this.getModuleAssets(assetPath, this.fileExtension, this.fileExtension, modifier, callback);
|
105 | break;
|
106 |
|
107 | case 'package':
|
108 | this.getPackageAssets(assetPath, this.fileExtension, this.fileExtension, modifier, callback);
|
109 | break;
|
110 |
|
111 | default:
|
112 | callback([]);
|
113 | break;
|
114 | }
|
115 | }
|
116 | }).bind(this));
|
117 | },
|
118 |
|
119 | getModuleAssets : function(assetPath, fileExtension, subfolder, modifier, callback)
|
120 | {
|
121 | subfolder = subfolder || '';
|
122 | modifier = modifier || {};
|
123 |
|
124 | if( this.isFileIncluded(assetPath, modifier) )
|
125 | {
|
126 | this.getFolderAssets(assetPath, fileExtension, '', subfolder, (function(defaultFiles){
|
127 |
|
128 | var brandFiles;
|
129 | if( this.brand )
|
130 | {
|
131 | this.getFolderAssets(assetPath, fileExtension, this.brand, subfolder, (function(brandFiles){
|
132 | callback(this.mergeDefaultAndBrandFiles(defaultFiles, brandFiles, assetPath));
|
133 | }).bind(this));
|
134 | }
|
135 | else
|
136 | {
|
137 | callback(this.mergeDefaultAndBrandFiles(defaultFiles, [], assetPath));
|
138 | }
|
139 | }).bind(this));
|
140 | }
|
141 | else
|
142 | {
|
143 | callback([]);
|
144 | }
|
145 | },
|
146 |
|
147 | getPackageAssets : function(folder, fileExtension, subfolder, modifier, callback)
|
148 | {
|
149 | fs.exists(folder, (function(exists)
|
150 | {
|
151 | if( exists )
|
152 | {
|
153 | fs.readdir(folder, (function(err, files)
|
154 | {
|
155 | async.filter(files, function(moduleFolder, cb)
|
156 | {
|
157 | fs.stat(path.join(folder, moduleFolder), function(err, stats){
|
158 | cb(stats.isDirectory());
|
159 | });
|
160 | }, (function(modules){
|
161 |
|
162 | var sortedModules = modules.sort();
|
163 | async.map(sortedModules, (function(mod, cb){
|
164 | this.getModuleAssets(path.join(folder, mod), fileExtension, subfolder, modifier, function(modFiles){
|
165 | cb(null, modFiles);
|
166 | });
|
167 | }).bind(this), function(err, results){
|
168 | var packageContent = [];
|
169 | _.each(results, function(modItems)
|
170 | {
|
171 | packageContent = _.union(packageContent, modItems);
|
172 | });
|
173 |
|
174 | callback(packageContent);
|
175 | });
|
176 | }).bind(this));
|
177 | }).bind(this));
|
178 | }
|
179 | else
|
180 | {
|
181 | callback([]);
|
182 | }
|
183 | }).bind(this))
|
184 | },
|
185 |
|
186 | getFolderAssets : function(assetFolder, fileExtension, brand, subfolder, callback)
|
187 | {
|
188 | brand = brand || '';
|
189 | subfolder = subfolder || '';
|
190 |
|
191 | if( brand )
|
192 | {
|
193 | assetFolder = path.join(assetFolder, 'brands', brand);
|
194 | }
|
195 |
|
196 | if( subfolder )
|
197 | {
|
198 | assetFolder = path.join(assetFolder, subfolder);
|
199 | }
|
200 |
|
201 | this.collectDirContentByType(assetFolder, fileExtension, -1, (function(assets){
|
202 | callback(this.filterFilesByTags(assets, fileExtension));
|
203 | }).bind(this));
|
204 | },
|
205 |
|
206 | collectDirContentByType : function(folder, fileExtension, depth, callback)
|
207 | {
|
208 | this.collectFiles(folder, fileExtension, (function(err, entries)
|
209 | {
|
210 | if( err )
|
211 | {
|
212 |
|
213 | if( err.code !== 'ENOENT')
|
214 | {
|
215 | console.log(err)
|
216 | }
|
217 |
|
218 | callback([]);
|
219 | }
|
220 | else
|
221 | {
|
222 | var fullPathEntries = this.getFullPath(folder, entries.sort());
|
223 |
|
224 | if( depth === 0 )
|
225 | {
|
226 | callback(fullPathEntries);
|
227 | }
|
228 | else
|
229 | {
|
230 | this.collectSubDirs(folder, (function(dirEntries)
|
231 | {
|
232 | if( dirEntries.length === 0)
|
233 | {
|
234 | callback(fullPathEntries);
|
235 | }
|
236 | else
|
237 | {
|
238 | dirEntries.sort();
|
239 |
|
240 | async.map(dirEntries, (function(dir, callbackDirContent)
|
241 | {
|
242 | var subFolder = path.join(folder + path.sep + dir);
|
243 | this.collectDirContentByType(subFolder, fileExtension, depth - 1, function(subFiles)
|
244 | {
|
245 | callbackDirContent(null, subFiles);
|
246 | });
|
247 | }).bind(this), (function(err, results)
|
248 | {
|
249 | var combined = _.reduce(results, function(memo, entry){
|
250 | return memo.concat(entry);
|
251 | }, fullPathEntries);
|
252 |
|
253 | callback(combined);
|
254 | }).bind(this))
|
255 | }
|
256 | }).bind(this));
|
257 | }
|
258 | }
|
259 | }).bind(this));
|
260 | },
|
261 |
|
262 | getFullPath : function(folder, entries)
|
263 | {
|
264 | return _.map(entries, function(entry)
|
265 | {
|
266 | return path.join(folder, entry);
|
267 | });
|
268 | },
|
269 |
|
270 | collectFiles : function(dir, fileExtension, callback)
|
271 | {
|
272 | fs.readdir(dir, (function(err, files)
|
273 | {
|
274 | if( !err )
|
275 | {
|
276 | async.filter(files, (function(item, callbackFileFilter)
|
277 | {
|
278 | fs.stat(path.join(dir, item), (function(err, stats)
|
279 | {
|
280 |
|
281 | callbackFileFilter(stats.isFile() && this.hasValidFileEnd(item, fileExtension));
|
282 | }).bind(this));
|
283 | }).bind(this), (function(entries){
|
284 |
|
285 | callback(null, entries);
|
286 |
|
287 | }).bind(this));
|
288 | }
|
289 | else
|
290 | {
|
291 | callback(err, []);
|
292 | }
|
293 | }).bind(this));
|
294 | },
|
295 |
|
296 | collectSubDirs : function(dir, callback){
|
297 |
|
298 | fs.readdir(dir, (function(err, subDirs)
|
299 | {
|
300 | if( err )
|
301 | {
|
302 | console.log(err);
|
303 | }
|
304 |
|
305 | async.filter(subDirs, (function(item, callbackDirFilter)
|
306 | {
|
307 |
|
308 | fs.stat(path.join(dir, item), function(err, stats)
|
309 | {
|
310 | callbackDirFilter(stats.isDirectory() && item != 'brands' && !/^\./.test(item) );
|
311 | });
|
312 | }).bind(this), (function(dirEntries)
|
313 | {
|
314 | callback(dirEntries);
|
315 |
|
316 | }).bind(this));
|
317 | }).bind(this));
|
318 | },
|
319 |
|
320 | isFileIncluded : function(fileName, modifier)
|
321 | {
|
322 | var include;
|
323 | var exclude;
|
324 |
|
325 | if( _.isArray(modifier.include) )
|
326 | {
|
327 | include = modifier.include;
|
328 | }
|
329 | else if( _.isObject(modifier.include) )
|
330 | {
|
331 | include = modifier.include[fileName];
|
332 | }
|
333 |
|
334 | if( _.isArray(modifier.exclude) )
|
335 | {
|
336 | exclude = modifier.exclude;
|
337 | }
|
338 | else if( _.isObject(modifier.exclude) )
|
339 | {
|
340 | exclude = modifier.exclude[fileName];
|
341 | }
|
342 |
|
343 |
|
344 | if( include )
|
345 | {
|
346 | return _.contains(include, this.brand);
|
347 | }
|
348 | else if( exclude )
|
349 | {
|
350 | return !_.contains(exclude, this.brand);
|
351 | }
|
352 | else
|
353 | {
|
354 | return true;
|
355 | }
|
356 | },
|
357 |
|
358 | hasValidFileEnd : function(fileName, fileExtension)
|
359 | {
|
360 | fileExtension = '.' + fileExtension;
|
361 |
|
362 | return fileName.substr(-fileExtension.length) === fileExtension;
|
363 | },
|
364 |
|
365 | |
366 |
|
367 |
|
368 | filterAssets : function(files, folder, modifier, fileExtension)
|
369 | {
|
370 | fileExtension = fileExtension || '';
|
371 |
|
372 | var result = [];
|
373 | _.each(files, function(file)
|
374 | {
|
375 | var fileName = file.replace(folder + path.sep, '');
|
376 | var nameWithoutExtension = this.getPathWithoutExtension(fileName, fileExtension);
|
377 | var fileTags = nameWithoutExtension.split('@');
|
378 |
|
379 | fileName = fileTags[0]+'.'+fileExtension;
|
380 |
|
381 | if( this.isFileIncluded(fileName, modifier) )
|
382 | {
|
383 | result.push(file);
|
384 | }
|
385 | }, this);
|
386 |
|
387 | return result;
|
388 | },
|
389 |
|
390 | filterFilesByTags : function(files, fileExtension/* , tagmode='join' */)
|
391 | {
|
392 | var result = [];
|
393 |
|
394 |
|
395 | var tagRegex = new RegExp('\@(.*?)\.' + fileExtension + '$');
|
396 | var taggedFiles = _.filter(files, function(file)
|
397 | {
|
398 | return tagRegex.test(file);
|
399 | }, this);
|
400 |
|
401 | if( !this.tags.length )
|
402 | {
|
403 |
|
404 | result = _.union(result, _.difference(files, taggedFiles));
|
405 | }
|
406 |
|
407 | if( this.tags.length )
|
408 | {
|
409 | var filesWithRequiredTags = [];
|
410 | _.each(taggedFiles, function(fileName)
|
411 | {
|
412 | var nameWithoutExtension = this.getPathWithoutExtension(fileName, fileExtension);
|
413 |
|
414 | var fileTags = nameWithoutExtension.split('@');
|
415 | fileTags.shift();
|
416 |
|
417 | if( this.areTagsEqual(this.tags, fileTags) ) filesWithRequiredTags.push(fileName);
|
418 | }, this);
|
419 |
|
420 | result = _.union(result, filesWithRequiredTags);
|
421 | }
|
422 |
|
423 | return result;
|
424 | },
|
425 |
|
426 | mergeDefaultAndBrandFiles : function(defauls, brand, assetPath, subfolder)
|
427 | {
|
428 | subfolder = subfolder || '';
|
429 | var result = [];
|
430 |
|
431 | var brandPath = assetPath + path.sep + 'brands' + path.sep + this.brand + path.sep;
|
432 | if( subfolder ) brandPath += subfolder + path.sep;
|
433 |
|
434 | var defaultPath = assetPath + path.sep;
|
435 | if( subfolder ) defaultPath += subfolder + path.sep;
|
436 |
|
437 | _.each(defauls, function(defaultValue)
|
438 | {
|
439 | var match = false;
|
440 | var defaultBasename = defaultValue.replace(defaultPath, '');
|
441 |
|
442 | _.each(brand, function(brandValue, bKey)
|
443 | {
|
444 | var brandBasename = brandValue.replace(brandPath, '');
|
445 |
|
446 | if( defaultBasename == brandBasename )
|
447 | {
|
448 | match = true;
|
449 | result.push(brandValue);
|
450 | delete brand[bKey];
|
451 | }
|
452 | }, this);
|
453 |
|
454 | if( !match ) result.push(defaultValue);
|
455 | }, this);
|
456 |
|
457 | result = _.union(result, brand);
|
458 |
|
459 | return result;
|
460 | },
|
461 |
|
462 | areTagsEqual : function(requiredTags, fileTags)
|
463 | {
|
464 | var delta1 = _.difference(requiredTags, fileTags).length;
|
465 | var delta2 = _.difference(fileTags, requiredTags).length;
|
466 |
|
467 | return delta1 === 0 && delta2 === 0;
|
468 | },
|
469 |
|
470 | getPathWithoutExtension : function(filePath, fileExtension)
|
471 | {
|
472 | var extensionRegex = new RegExp('\.' + fileExtension + '$');
|
473 |
|
474 | return filePath.replace(extensionRegex, '');
|
475 | }
|
476 | };
|
477 |
|
478 |
|
479 | module.exports = AssetCollector;
|