UNPKG

11.1 kBJavaScriptView Raw
1var _ = require('underscore');
2var fs = require('fs');
3var path = require('path');
4var async = require('async');
5
6var 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
14AssetCollector.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// console.log('parseSection', assetConfig.pattern)
56 switch(assetConfig.pattern)
57 {
58 case 'file':
59 if( this.tags.length )
60 {
61 callback([]);
62 break;
63 // Tags not supported at the moment
64 }
65
66 if( !fs.existsSync(assetPath) )
67 {
68 callback([]);
69 break;
70 // Tags not supported at the moment
71 }
72 if( !this.hasValidFileEnd(assetPath, this.fileExtension) )
73 {
74 callback([]);
75 break;
76 // Tags not supported at the moment
77 }
78 if( !this.isFileIncluded(assetPath, modifier) )
79 {
80 callback([]);
81 break;
82 // Tags not supported at the moment
83 }
84
85 callback([assetPath]);
86 break;
87
88 case 'folder':
89// if( this.tags.length ) break; // Tags not supported at the moment
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 // results is now an array of stats for each file
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 // ENOENT -> No such file or directory
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); // max depth reached
227 }
228 else
229 {
230 this.collectSubDirs(folder, (function(dirEntries)
231 {
232 if( dirEntries.length === 0)
233 {
234 callback(fullPathEntries); // no more deeper folder
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 // only pick files
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 // sort out dirs
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 //find all files with at least one tag
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 /* || tagmode == 'join' */)
402 {
403 // remove files with tags from selection
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(); //remove file basename
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// node.js module export
479module.exports = AssetCollector;