PageRenderTime 57ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/grunt-beautify/node_modules/grunt/tasks/watch.js

https://bitbucket.org/jollyscience/grunt-bbb
JavaScript | 168 lines | 90 code | 16 blank | 62 comment | 13 complexity | f65f3c628c0dea03e68f96f338e0a6da MD5 | raw file
  1. /*
  2. * grunt
  3. * https://github.com/cowboy/grunt
  4. *
  5. * Copyright (c) 2012 "Cowboy" Ben Alman
  6. * Licensed under the MIT license.
  7. * http://benalman.com/about/license/
  8. */
  9. module.exports = function(grunt) {
  10. // Nodejs libs.
  11. var fs = require('fs');
  12. var path = require('path');
  13. // In Nodejs 0.8.0, existsSync moved from path -> fs.
  14. var existsSync = fs.existsSync || path.existsSync;
  15. // ==========================================================================
  16. // TASKS
  17. // ==========================================================================
  18. // Keep track of last modified times of files, in case files are reported to
  19. // have changed incorrectly.
  20. var mtimes = {};
  21. grunt.registerTask('watch', 'Run predefined tasks whenever watched files change.', function(target) {
  22. this.requiresConfig('watch');
  23. // Build an array of files/tasks objects.
  24. var watch = grunt.config('watch');
  25. var targets = target ? [target] : Object.keys(watch).filter(function(key) {
  26. return typeof watch[key] !== 'string' && !Array.isArray(watch[key]);
  27. });
  28. targets = targets.map(function(target) {
  29. // Fail if any required config properties have been omitted.
  30. target = ['watch', target];
  31. this.requiresConfig(target.concat('files'), target.concat('tasks'));
  32. return grunt.config(target);
  33. }, this);
  34. // Allow "basic" non-target format.
  35. if (typeof watch.files === 'string' || Array.isArray(watch.files)) {
  36. targets.push({files: watch.files, tasks: watch.tasks});
  37. }
  38. grunt.log.write('Waiting...');
  39. // This task is asynchronous.
  40. var taskDone = this.async();
  41. // Get a list of files to be watched.
  42. var patterns = grunt.utils._.chain(targets).pluck('files').flatten().uniq().value();
  43. var getFiles = grunt.file.expandFiles.bind(grunt.file, patterns);
  44. // The tasks to be run.
  45. var tasks = []; //grunt.config(tasksProp);
  46. // This task's name + optional args, in string format.
  47. var nameArgs = this.nameArgs;
  48. // An ID by which the setInterval can be canceled.
  49. var intervalId;
  50. // Files that are being watched.
  51. var watchedFiles = {};
  52. // File changes to be logged.
  53. var changedFiles = {};
  54. // Define an alternate fail "warn" behavior.
  55. grunt.fail.warnAlternate = function() {
  56. grunt.task.clearQueue({untilMarker: true}).run(nameArgs);
  57. };
  58. // Cleanup when files have changed. This is debounced to handle situations
  59. // where editors save multiple files "simultaneously" and should wait until
  60. // all the files are saved.
  61. var done = grunt.utils._.debounce(function() {
  62. // Clear the files-added setInterval.
  63. clearInterval(intervalId);
  64. // Ok!
  65. grunt.log.ok();
  66. var fileArray = Object.keys(changedFiles);
  67. fileArray.forEach(function(filepath) {
  68. // Log which file has changed, and how.
  69. grunt.log.ok('File "' + filepath + '" ' + changedFiles[filepath] + '.');
  70. // Clear the modified file's cached require data.
  71. grunt.file.clearRequireCache(filepath);
  72. });
  73. // Unwatch all watched files.
  74. Object.keys(watchedFiles).forEach(unWatchFile);
  75. // For each specified target, test to see if any files matching that
  76. // target's file patterns were modified.
  77. targets.forEach(function(target) {
  78. var files = grunt.file.expandFiles(target.files);
  79. var intersection = grunt.utils._.intersection(fileArray, files);
  80. // Enqueue specified tasks if a matching file was found.
  81. if (intersection.length > 0 && target.tasks) {
  82. grunt.task.run(target.tasks).mark();
  83. }
  84. });
  85. // Enqueue the watch task, so that it loops.
  86. grunt.task.run(nameArgs);
  87. // Continue task queue.
  88. taskDone();
  89. }, 250);
  90. // Handle file changes.
  91. function fileChanged(status, filepath) {
  92. // If file was deleted and then re-added, consider it changed.
  93. if (changedFiles[filepath] === 'deleted' && status === 'added') {
  94. status = 'changed';
  95. }
  96. // Keep track of changed status for later.
  97. changedFiles[filepath] = status;
  98. // Execute debounced done function.
  99. done();
  100. }
  101. // Watch a file.
  102. function watchFile(filepath) {
  103. if (!watchedFiles[filepath]) {
  104. // Watch this file for changes. This probably won't scale to hundreds of
  105. // files.. but I bet someone will try it!
  106. watchedFiles[filepath] = fs.watch(filepath, function(event) {
  107. var mtime;
  108. // Has the file been deleted?
  109. var deleted = !existsSync(filepath);
  110. if (deleted) {
  111. // If file was deleted, stop watching file.
  112. unWatchFile(filepath);
  113. // Remove from mtimes.
  114. delete mtimes[filepath];
  115. } else {
  116. // Get last modified time of file.
  117. mtime = +fs.statSync(filepath).mtime;
  118. // If same as stored mtime, the file hasn't changed.
  119. if (mtime === mtimes[filepath]) { return; }
  120. // Otherwise it has, store mtime for later use.
  121. mtimes[filepath] = mtime;
  122. }
  123. // Call "change" for this file, setting status appropriately (rename ->
  124. // renamed, change -> changed).
  125. fileChanged(deleted ? 'deleted' : event + 'd', filepath);
  126. });
  127. }
  128. }
  129. // Unwatch a file.
  130. function unWatchFile(filepath) {
  131. if (watchedFiles[filepath]) {
  132. // Close watcher.
  133. watchedFiles[filepath].close();
  134. // Remove from watched files.
  135. delete watchedFiles[filepath];
  136. }
  137. }
  138. // Watch all currently existing files for changes.
  139. getFiles().forEach(watchFile);
  140. // Watch for files to be added.
  141. intervalId = setInterval(function() {
  142. // Files that have been added since last interval execution.
  143. var added = grunt.utils._.difference(getFiles(), Object.keys(watchedFiles));
  144. added.forEach(function(filepath) {
  145. // This file has been added.
  146. fileChanged('added', filepath);
  147. // Watch this file.
  148. watchFile(filepath);
  149. });
  150. }, 200);
  151. });
  152. };