Tizen 2.0 Release
[platform/framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.2.0 / node_modules / grunt / lib / grunt / task.js
1 /*
2  * grunt
3  * http://gruntjs.com/
4  *
5  * Copyright (c) 2012 "Cowboy" Ben Alman
6  * Licensed under the MIT license.
7  * https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
8  */
9
10 var grunt = require('../grunt');
11
12 // Nodejs libs.
13 var path = require('path');
14 var fs = require('fs');
15 // In Nodejs 0.8.0, existsSync moved from path -> fs.
16 var existsSync = fs.existsSync || path.existsSync;
17
18 // Extend generic "task" utils lib.
19 var parent = grunt.utils.task.create();
20
21 // The module to be exported.
22 var task = module.exports = Object.create(parent);
23
24 // An internal registry of tasks and handlers.
25 var registry = {};
26
27 // Keep track of the number of log.error() calls.
28 var errorcount;
29
30 // Override built-in registerTask.
31 task.registerTask = function(name, info, fn) {
32   // Add task to registry.
33   registry.tasks.push(name);
34   // Register task.
35   parent.registerTask.apply(task, arguments);
36   // This task, now that it's been registered.
37   var thisTask = task._tasks[name];
38   // Override task function.
39   var _fn = thisTask.fn;
40   thisTask.fn = function(arg) {
41     // Initialize the errorcount for this task.
42     errorcount = grunt.fail.errorcount;
43     // Return the number of errors logged during this task.
44     this.__defineGetter__('errorCount', function() {
45       return grunt.fail.errorcount - errorcount;
46     });
47     // Expose task.requires on `this`.
48     this.requires = task.requires.bind(task);
49     // Expose config.requires on `this`.
50     this.requiresConfig = grunt.config.requires;
51     // If this task was an alias or a multi task called without a target,
52     // only log if in verbose mode.
53     var logger = _fn.alias || (thisTask.multi && (!arg || arg === '*')) ? 'verbose' : 'log';
54     // Actually log.
55     grunt[logger].header('Running "' + this.nameArgs + '"' +
56       (this.name !== this.nameArgs ? ' (' + this.name + ')' : '') + ' task');
57     // Actually run the task.
58     return _fn.apply(this, arguments);
59   };
60   return task;
61 };
62
63 // This is the most common "multi task" pattern.
64 task.registerMultiTask = function(name, info, fn) {
65   // Store a reference to the task object, in case the task gets renamed.
66   var thisTask;
67   task.registerTask(name, info, function(target) {
68     // Guaranteed to always be the actual task name.
69     var name = thisTask.name;
70     // If a target wasn't specified, run this task once for each target.
71     if (!target || target === '*') {
72       return task.runAllTargets(name, grunt.utils.toArray(arguments).slice(1));
73     }
74     // Fail if any required config properties have been omitted.
75     this.requiresConfig([name, target]);
76     // Expose data on `this` (as well as task.current).
77     this.data = grunt.config([name, target]);
78     // Expose file object on `this` (as well as task.current).
79     this.file = {};
80     // Handle data structured like either:
81     //   'prop': [srcfiles]
82     //   {prop: {src: [srcfiles], dest: 'destfile'}}.
83     if (grunt.utils.kindOf(this.data) === 'object') {
84       if ('src' in this.data) { this.file.src = this.data.src; }
85       if ('dest' in this.data) { this.file.dest = this.data.dest; }
86     } else {
87       this.file.src = this.data;
88       this.file.dest = target;
89     }
90     // Process src as a template (recursively, if necessary).
91     if (this.file.src) {
92       this.file.src = grunt.utils.recurse(this.file.src, function(src) {
93         if (typeof src !== 'string') { return src; }
94         return grunt.template.process(src);
95       });
96     }
97     // Process dest as a template.
98     if (this.file.dest) {
99       this.file.dest = grunt.template.process(this.file.dest);
100     }
101     // Expose the current target.
102     this.target = target;
103     // Remove target from args.
104     this.args = grunt.utils.toArray(arguments).slice(1);
105     // Recreate flags object so that the target isn't set as a flag.
106     this.flags = {};
107     this.args.forEach(function(arg) { this.flags[arg] = true; }, this);
108     // Call original task function, passing in the target and any other args.
109     return fn.apply(this, this.args);
110   });
111   thisTask = task._tasks[name];
112   thisTask.multi = true;
113 };
114
115 // Init tasks don't require properties in config, and as such will preempt
116 // config loading errors.
117 task.registerInitTask = function(name, info, fn) {
118   task.registerTask(name, info, fn);
119   task._tasks[name].init = true;
120 };
121
122 // Override built-in registerHelper to use the registry.
123 task.registerHelper = function(name, fn) {
124   // Add task to registry.
125   registry.helpers.push(name);
126   // Actually register task.
127   return parent.registerHelper.apply(task, arguments);
128 };
129
130 // If a property wasn't passed, run all task targets in turn.
131 task.runAllTargets = function(taskname, args) {
132   // Get an array of sub-property keys under the given config object.
133   var targets = Object.keys(grunt.config(taskname) || {});
134   // Fail if there are no actual properties to iterate over.
135   if (targets.length === 0) {
136     grunt.log.error('No "' + taskname + '" targets found.');
137     return false;
138   }
139   // Iterate over all properties not starting with _, running a task for each.
140   targets.filter(function(target) {
141     return !/^_/.test(target);
142   }).forEach(function(target) {
143     // Be sure to pass in any additionally specified args.
144     task.run([taskname, target].concat(args || []).join(':'));
145   });
146 };
147
148 // Load tasks and handlers from a given tasks file.
149 var loadTaskStack = [];
150 function loadTask(filepath) {
151   // In case this was called recursively, save registry for later.
152   loadTaskStack.push({tasks: registry.tasks, helpers: registry.helpers});
153   // Reset registry.
154   registry.tasks = [];
155   registry.helpers = [];
156   var filename = path.basename(filepath);
157   var msg = 'Loading "' + filename + '" tasks and helpers...';
158   var fn;
159   try {
160     // Load taskfile.
161     fn = require(path.resolve(filepath));
162     if (typeof fn === 'function') {
163       fn.call(grunt, grunt);
164     }
165     grunt.verbose.write(msg).ok();
166     if (registry.tasks.length === 0 && registry.helpers.length === 0) {
167       grunt.verbose.error('No new tasks or helpers found.');
168     } else {
169       if (registry.tasks.length > 0) {
170         grunt.verbose.writeln('Tasks: ' + grunt.log.wordlist(registry.tasks));
171       }
172       if (registry.helpers.length > 0) {
173         grunt.verbose.writeln('Helpers: ' + grunt.log.wordlist(registry.helpers));
174       }
175     }
176   } catch(e) {
177     // Something went wrong.
178     grunt.log.write(msg).error().verbose.error(e.stack).or.error(e);
179   }
180   // Restore registry.
181   var obj = loadTaskStack.pop() || {};
182   registry.tasks = obj.tasks || [];
183   registry.helpers = obj.helpers || [];
184 }
185
186 // Log a message when loading tasks.
187 function loadTasksMessage(info) {
188   grunt.verbose.subhead('Registering ' + info + ' tasks.');
189 }
190
191 // Load tasks and handlers from a given directory.
192 function loadTasks(tasksdir) {
193   try {
194     fs.readdirSync(tasksdir).filter(function(filename) {
195       // Filter out non-.js files.
196       return path.extname(filename).toLowerCase() === '.js';
197     }).forEach(function(filename) {
198       // Load task.
199       loadTask(path.join(tasksdir, filename));
200     });
201   } catch(e) {
202     grunt.log.verbose.error(e.stack).or.error(e);
203   }
204 }
205
206 // Directories to be searched for tasks files and "extra" files.
207 task.searchDirs = [];
208
209 // Return an array of all task-specific file paths that match the given
210 // wildcard patterns. Instead of returing a string for each file path, return
211 // an object with useful properties. When coerced to String, each object will
212 // yield its absolute path.
213 function expandByMethod(method) {
214   var args = grunt.utils.toArray(arguments).slice(1);
215   // If the first argument is an options object, remove and save it for later.
216   var options = grunt.utils.kindOf(args[0]) === 'object' ? args.shift() : {};
217   // Use the first argument if it's an Array, otherwise convert the arguments
218   // object to an array and use that.
219   var patterns = Array.isArray(args[0]) ? args[0] : args;
220   var filepaths = {};
221   // When any returned array item is used in a string context, return the
222   // absolute path.
223   var toString = function() { return this.abs; };
224   // Iterate over all searchDirs.
225   task.searchDirs.forEach(function(dirpath) {
226     // Create an array of absolute patterns.
227     var args = patterns.map(function(pattern) {
228       return path.join(dirpath, pattern);
229     });
230     // Add the options object back onto the beginning of the arguments array.
231     args.unshift(options);
232     // Expand the paths in case a wildcard was passed.
233     grunt.file[method].apply(null, args).forEach(function(abspath) {
234       var relpath = abspath.slice(dirpath.length + 1);
235       if (relpath in filepaths) { return; }
236       // Update object at this relpath only if it doesn't already exist.
237       filepaths[relpath] = {
238         abs: abspath,
239         rel: relpath,
240         base: abspath.slice(0, dirpath.length),
241         toString: toString
242       };
243     });
244   });
245   // Return an array of objects.
246   return Object.keys(filepaths).map(function(relpath) {
247     return filepaths[relpath];
248   });
249 }
250
251 // A few type-specific task expansion methods. These methods all return arrays
252 // of file objects.
253 task.expand = expandByMethod.bind(task, 'expand');
254 task.expandDirs = expandByMethod.bind(task, 'expandDirs');
255 task.expandFiles = expandByMethod.bind(task, 'expandFiles');
256
257 // Get a single task file path.
258 task.getFile = function() {
259   var filepath = path.join.apply(path, arguments);
260   var fileobj = task.expand(filepath)[0];
261   return fileobj ? String(fileobj) : null;
262 };
263
264 // Read JSON defaults from task files (if they exist), merging them into one.
265 // data object.
266 var readDefaults = {};
267 task.readDefaults = function() {
268   var filepath = path.join.apply(path, arguments);
269   var result = readDefaults[filepath];
270   var filepaths;
271   if (!result) {
272     result = readDefaults[filepath] = {};
273     // Find all matching taskfiles.
274     filepaths = task.searchDirs.map(function(dirpath) {
275       return path.join(dirpath, filepath);
276     }).filter(function(filepath) {
277       return existsSync(filepath) && fs.statSync(filepath).isFile();
278     });
279     // Load defaults data.
280     if (filepaths.length) {
281       grunt.verbose.subhead('Loading data from ' + filepath);
282       // Since extras path order goes from most-specific to least-specific, only
283       // add-in properties that don't already exist.
284       filepaths.forEach(function(filepath) {
285         grunt.utils._.defaults(result, grunt.file.readJSON(filepath));
286       });
287     }
288   }
289   return result;
290 };
291
292 // Load tasks and handlers from a given directory.
293 task.loadTasks = function(tasksdir) {
294   loadTasksMessage('"' + tasksdir + '"');
295   if (existsSync(tasksdir)) {
296     task.searchDirs.unshift(tasksdir);
297     loadTasks(tasksdir);
298   } else {
299     grunt.log.error('Tasks directory "' + tasksdir + '" not found.');
300   }
301 };
302
303 // Load tasks and handlers from a given locally-installed Npm module (installed
304 // relative to the base dir).
305 task.loadNpmTasks = function(name) {
306   loadTasksMessage('"' + name + '" local Npm module');
307   var root = path.resolve('node_modules');
308   var pkgfile = path.join(root, name, 'package.json');
309   var pkg = existsSync(pkgfile) ? grunt.file.readJSON(pkgfile) : {};
310
311   // Process collection plugins.
312   if (pkg.keywords && pkg.keywords.indexOf('gruntcollection') !== -1) {
313     Object.keys(pkg.dependencies).forEach(function(depName) {
314       // Npm sometimes pulls dependencies out if they're shared, so find
315       // upwards if not found locally.
316       var filepath = grunt.file.findup(path.resolve('node_modules', name),
317         'node_modules/' + depName);
318       if (filepath) {
319         // Load this task plugin recursively.
320         task.loadNpmTasks(path.relative(root, filepath));
321       }
322     });
323     return;
324   }
325
326   // Process task plugins.
327   var tasksdir = path.join(root, name, 'tasks');
328   if (existsSync(tasksdir)) {
329     task.searchDirs.unshift(tasksdir);
330     loadTasks(tasksdir);
331   } else {
332     grunt.log.error('Local Npm module "' + name + '" not found. Is it installed?');
333   }
334 };
335
336 // Load tasks and handlers from a given Npm module, installed relative to the
337 // version of grunt being run.
338 function loadNpmTasksWithRequire(name) {
339   loadTasksMessage('"' + name + '" npm module');
340   var dirpath;
341   try {
342     dirpath = require.resolve(name);
343     dirpath = path.resolve(path.join(path.dirname(dirpath), 'tasks'));
344     if (existsSync(dirpath)) {
345       task.searchDirs.unshift(dirpath);
346       loadTasks(dirpath);
347       return;
348     }
349   } catch (e) {}
350
351   grunt.log.error('Npm module "' + name + '" not found. Is it installed?');
352 }
353
354 // Initialize tasks.
355 task.init = function(tasks, options) {
356   if (!options) { options = {}; }
357
358   // Load all built-in tasks.
359   var tasksdir = path.resolve(__dirname, '../../tasks');
360   task.searchDirs.unshift(tasksdir);
361   loadTasksMessage('built-in');
362   loadTasks(tasksdir);
363
364   // Grunt was loaded from a Npm-installed plugin bin script. Load any tasks
365   // that were specified via grunt.npmTasks.
366   grunt._npmTasks.forEach(loadNpmTasksWithRequire);
367
368   // Were only init tasks specified?
369   var allInit = tasks.length > 0 && tasks.every(function(name) {
370     var obj = task._taskPlusArgs(name).task;
371     return obj && obj.init;
372   });
373
374   // Get any local configfile or tasks that might exist. Use --config override
375   // if specified, otherwise search the current directory or any parent.
376   var configfile = allInit ? null : grunt.option('config') ||
377     grunt.file.findup(process.cwd(), 'grunt.js');
378
379   var msg = 'Reading "' + path.basename(configfile) + '" config file...';
380   if (configfile && existsSync(configfile)) {
381     grunt.verbose.writeln().write(msg).ok();
382     // Change working directory so that all paths are relative to the
383     // configfile's location (or the --base option, if specified).
384     process.chdir(grunt.option('base') || path.dirname(configfile));
385     // Load local tasks, if the file exists.
386     loadTask(configfile);
387   } else if (options.help || allInit) {
388     // Don't complain about missing config file.
389   } else if (grunt.option('config')) {
390     // If --config override was specified and it doesn't exist, complain.
391     grunt.log.writeln().write(msg).error();
392     grunt.fatal('Unable to find "' + configfile + '" config file.', 2);
393   } else if (!grunt.option('help')) {
394     grunt.verbose.writeln().write(msg).error();
395     grunt.fatal('Unable to find "grunt.js" config file. Do you need any --help?', 2);
396   }
397
398   // Load all user-specified --npm tasks.
399   (grunt.option('npm') || []).forEach(task.loadNpmTasks);
400   // Load all user-specified --tasks.
401   (grunt.option('tasks') || []).forEach(task.loadTasks);
402
403   // Load user .grunt tasks.
404   tasksdir = grunt.file.userDir('tasks');
405   if (tasksdir) {
406     task.searchDirs.unshift(tasksdir);
407     loadTasksMessage('user');
408     loadTasks(tasksdir);
409   }
410
411   // Search dirs should be unique and fully normalized absolute paths.
412   task.searchDirs = grunt.utils._.uniq(task.searchDirs).map(function(filepath) {
413     return path.resolve(filepath);
414   });
415 };