batman-rails-flo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +29 -0
  3. data/Rakefile +2 -0
  4. data/lib/batman-rails-flo.rb +5 -0
  5. data/lib/batman_rails_flo/railtie.rb +9 -0
  6. data/lib/batman_rails_flo/tasks.rake +14 -0
  7. data/lib/batman_rails_flo/version.rb +3 -0
  8. data/vendor/assets/javascripts/batman_rails_flo/flo_server.js +67 -0
  9. data/vendor/assets/javascripts/batman_rails_flo/live_reload.js.coffee +129 -0
  10. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/CNAME +1 -0
  11. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/CONTRIBUTING.md +9 -0
  12. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/LICENSE +22 -0
  13. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/README +50 -0
  14. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/bin/cake +7 -0
  15. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/bin/coffee +7 -0
  16. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/browser.js +134 -0
  17. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/cake.js +112 -0
  18. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/coffee-script.js +335 -0
  19. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/command.js +569 -0
  20. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/grammar.js +631 -0
  21. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/helpers.js +252 -0
  22. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/index.js +11 -0
  23. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/lexer.js +926 -0
  24. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/nodes.js +3158 -0
  25. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/optparse.js +139 -0
  26. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/parser.js +724 -0
  27. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/register.js +66 -0
  28. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/repl.js +163 -0
  29. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/rewriter.js +475 -0
  30. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/scope.js +146 -0
  31. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/lib/coffee-script/sourcemap.js +161 -0
  32. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/LICENSE +21 -0
  33. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/examples/pow.js +6 -0
  34. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/index.js +82 -0
  35. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/package.json +34 -0
  36. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/readme.markdown +63 -0
  37. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/chmod.js +38 -0
  38. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/clobber.js +37 -0
  39. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/mkdirp.js +28 -0
  40. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/perm.js +32 -0
  41. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/perm_sync.js +39 -0
  42. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/race.js +41 -0
  43. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/rel.js +32 -0
  44. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/return.js +25 -0
  45. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/return_sync.js +24 -0
  46. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/root.js +18 -0
  47. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/sync.js +32 -0
  48. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/umask.js +28 -0
  49. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/node_modules/mkdirp/test/umask_sync.js +32 -0
  50. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/package.json +50 -0
  51. data/vendor/assets/javascripts/batman_rails_flo/node_modules/coffee-script/register.js +1 -0
  52. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/LICENSE +30 -0
  53. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/PATENTS +23 -0
  54. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/README.md +124 -0
  55. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/bin/flo +26 -0
  56. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/configure/configure.html +57 -0
  57. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/configure/configure.js +205 -0
  58. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/configure/style.css +334 -0
  59. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/connection.js +235 -0
  60. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/devtools.html +12 -0
  61. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/index.js +323 -0
  62. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/logger.js +42 -0
  63. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/logo.png +0 -0
  64. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/manifest.json +13 -0
  65. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/client/session.js +305 -0
  66. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/index.js +10 -0
  67. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/lib/flo.js +226 -0
  68. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/lib/server.js +94 -0
  69. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/README.md +66 -0
  70. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/index.js +437 -0
  71. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/LICENSE +23 -0
  72. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/README.md +218 -0
  73. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/minimatch.js +1055 -0
  74. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS +14 -0
  75. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/LICENSE +23 -0
  76. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/README.md +97 -0
  77. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js +252 -0
  78. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/package.json +33 -0
  79. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/test/basic.js +369 -0
  80. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/test/foreach.js +52 -0
  81. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js +50 -0
  82. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/LICENSE +27 -0
  83. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/README.md +53 -0
  84. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/bench.js +283 -0
  85. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/package.json +42 -0
  86. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/sigmund.js +39 -0
  87. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/node_modules/sigmund/test/basic.js +24 -0
  88. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/package.json +40 -0
  89. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/basic.js +399 -0
  90. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/brace-expand.js +33 -0
  91. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/caching.js +14 -0
  92. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/defaults.js +274 -0
  93. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/minimatch/test/extglob-ending-with-state-char.js +8 -0
  94. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/lib/walker.js +111 -0
  95. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/license +13 -0
  96. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/lib/makeerror.js +87 -0
  97. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/node_modules/tmpl/lib/tmpl.js +17 -0
  98. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/node_modules/tmpl/package.json +31 -0
  99. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/node_modules/tmpl/readme.md +10 -0
  100. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/package.json +34 -0
  101. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/node_modules/makeerror/readme.md +77 -0
  102. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/package.json +36 -0
  103. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/walker/readme.md +52 -0
  104. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/LICENSE +55 -0
  105. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/main.js +128 -0
  106. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/package.json +34 -0
  107. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/readme.mkd +72 -0
  108. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/d/d/t +0 -0
  109. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/d/t +0 -0
  110. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/test_monitor.js +31 -0
  111. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/test_monitorRootDirectory.js +28 -0
  112. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/node_modules/watch/test/test_watchTree.js +20 -0
  113. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/package.json +45 -0
  114. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/sane/test/test.js +243 -0
  115. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/CHANGELOG.md +81 -0
  116. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/LICENSE +177 -0
  117. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/Makefile +11 -0
  118. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/README.md +245 -0
  119. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/binding.gyp +14 -0
  120. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Makefile +355 -0
  121. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/linker.lock +0 -0
  122. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/obj.target/validation/src/validation.o +0 -0
  123. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/obj.target/xor/src/xor.o +0 -0
  124. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/validation.node +0 -0
  125. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/Release/xor.node +0 -0
  126. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/binding.Makefile +6 -0
  127. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/config.gypi +115 -0
  128. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/gyp-mac-tool +512 -0
  129. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/validation.target.mk +154 -0
  130. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/build/xor.target.mk +154 -0
  131. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/index.js +1 -0
  132. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/install.js +31 -0
  133. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Constants.js +23 -0
  134. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Deprecation.js +38 -0
  135. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Validation.fallback.js +12 -0
  136. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/Validation.js +18 -0
  137. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketClient.js +359 -0
  138. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketConnection.js +717 -0
  139. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketFrame.js +282 -0
  140. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketRequest.js +478 -0
  141. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketRouter.js +154 -0
  142. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketRouterRequest.js +59 -0
  143. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/WebSocketServer.js +216 -0
  144. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/utils.js +7 -0
  145. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/websocket.js +11 -0
  146. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/xor.fallback.js +13 -0
  147. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/lib/xor.js +18 -0
  148. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/package.json +43 -0
  149. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/src/validation.cc +144 -0
  150. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/src/xor.cpp +86 -0
  151. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/vendor/FastBufferList.js +192 -0
  152. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/vendor/node-ctype/LICENSE +18 -0
  153. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/node_modules/websocket/vendor/node-ctype/ctio-faster.js +1126 -0
  154. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/package.json +25 -0
  155. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/browser_websocket.js +63 -0
  156. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/connection_test.js +57 -0
  157. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/logger_mock.js +15 -0
  158. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/client/session_test.js +194 -0
  159. data/vendor/assets/javascripts/batman_rails_flo/node_modules/fb-flo/test/server/flo_test.js +211 -0
  160. data/vendor/assets/javascripts/batman_rails_flo/package.json +15 -0
  161. data/vendor/assets/javascripts/batman_rails_flo/reload_event_handler.js.coffee +56 -0
  162. metadata +232 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) 2014, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ */
9
+
10
+ module.exports = require('./lib/flo');
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Copyright (c) 2014, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ var fs = require('fs');
13
+ var path = require('path');
14
+ var sane = require('sane');
15
+ var assert = require('assert');
16
+ var Server = require('./server');
17
+ var EventEmitter = require('events').EventEmitter;
18
+
19
+ module.exports = flo;
20
+
21
+ /**
22
+ * Top-level API for flo. Defaults params and instantiates `Flo`.
23
+ *
24
+ * @param {string} dir
25
+ * @param {object} options
26
+ * @param {function} callback
27
+ * @return {Flo}
28
+ * @public
29
+ */
30
+
31
+ function flo(dir, options, callback) {
32
+ if (typeof options === 'function') {
33
+ callback = options;
34
+ options = null;
35
+ }
36
+
37
+ dir = path.resolve(dir);
38
+
39
+ options = options || {};
40
+ options = {
41
+ port: options.port || 8888,
42
+ host: options.host || 'localhost',
43
+ verbose: options.verbose || false,
44
+ glob: options.glob || [],
45
+ useFilePolling: options.useFilePolling || false,
46
+ pollingInterval: options.pollingInterval
47
+ };
48
+
49
+ callback = callback || noBuildCallback(dir);
50
+
51
+ return new Flo(dir, options, callback);
52
+ }
53
+
54
+ /**
55
+ * Time before we emit the ready event.
56
+ */
57
+
58
+ var DELAY = 200;
59
+
60
+ /**
61
+ * Starts the server and the watcher and handles the piping between both and the
62
+ * resolver callback.
63
+ *
64
+ * @param {string} dir
65
+ * @param {object} options
66
+ * @param {function} callback
67
+ * @class Flo
68
+ * @private
69
+ */
70
+
71
+ function Flo(dir, options, callback) {
72
+ this.log = logger(options.verbose, 'Flo');
73
+ this.dir = dir;
74
+ this.realpathdir = fs.realpathSync(dir);
75
+ this.resolver = callback;
76
+ this.server = new Server({
77
+ port: options.port,
78
+ host: options.host,
79
+ log: logger(options.verbose, 'Server')
80
+ });
81
+
82
+ this.watcher = new sane.Watcher(dir, {
83
+ glob: options.glob,
84
+ poll: options.useFilePolling,
85
+ pollingInterval: options.pollingInterval
86
+ });
87
+ this.watcher.on('change', this.onFileChange.bind(this));
88
+ this.watcher.on(
89
+ 'ready',
90
+ this.emit.bind(this, 'ready')
91
+ );
92
+ }
93
+
94
+ Flo.prototype.__proto__ = EventEmitter.prototype;
95
+
96
+ /**
97
+ * Handles file changes.
98
+ *
99
+ * @param {string} filepath
100
+ * @private
101
+ */
102
+
103
+ Flo.prototype.onFileChange = function(filepath) {
104
+ this.log('File changed', filepath);
105
+ var server = this.server;
106
+ this.resolver(filepath, function(resource) {
107
+ resource = normalizeResource(resource);
108
+ server.broadcast(resource);
109
+ });
110
+ };
111
+
112
+ /**
113
+ * Closes the server and the watcher.
114
+ *
115
+ * @public
116
+ */
117
+
118
+ Flo.prototype.close = function() {
119
+ this.log('Shutting down flo');
120
+ this.watcher.close();
121
+ this.server.close();
122
+ };
123
+
124
+ /**
125
+ * Creates a logger for a given module.
126
+ *
127
+ * @param {boolean} verbose
128
+ * @param {string} moduleName
129
+ * @private
130
+ */
131
+
132
+ function logger(verbose, moduleName) {
133
+ var slice = [].slice;
134
+ return function() {
135
+ var args = slice.call(arguments);
136
+ args[0] = '[' + moduleName + '] ' + args[0];
137
+ if (verbose) {
138
+ console.log.apply(console, args);
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Check if an object is of type RegExp.
145
+ *
146
+ * @param {*} o
147
+ * @return {boolean}
148
+ * @private
149
+ */
150
+
151
+ function isRegExp(o) {
152
+ return o && typeof o === 'object' &&
153
+ Object.prototype.toString.call(o) === '[object RegExp]';
154
+ }
155
+
156
+ /**
157
+ * Given a resource, enforce type checks, default params, and prepare for
158
+ * serialization.
159
+ *
160
+ * @param {*} o
161
+ * @return {boolean}
162
+ * @private
163
+ */
164
+
165
+ function normalizeResource(resource) {
166
+ if (resource.reload) {
167
+ return resource;
168
+ }
169
+
170
+ assert(resource.resourceURL, 'expecting resourceURL');
171
+ assert(resource.contents != null, 'expecting contents');
172
+
173
+ var ret = {};
174
+
175
+ ret.match = resource.match || 'indexOf';
176
+ ret.contents = resource.contents.toString();
177
+ ret.resourceURL = resource.resourceURL;
178
+
179
+ if (path.sep === '\\') {
180
+ ret.resourceURL = ret.resourceURL.replace(/\\/g, '/');
181
+ }
182
+
183
+ assert.ok(
184
+ isRegExp(ret.match) ||
185
+ ['indexOf', 'equal'].indexOf(ret.match) > -1,
186
+ 'resource.match must be of type function, or regexp, ' +
187
+ 'or a string either "indexOf" or "equal'
188
+ );
189
+
190
+ if (isRegExp(ret.match)) {
191
+ var r = ret.match;
192
+ ret.match = {
193
+ type: 'regexp',
194
+ source: r.source,
195
+ global: r.global,
196
+ multiline: r.multiline,
197
+ ignoreCase: r.ignoreCase
198
+ };
199
+ }
200
+
201
+ return ret;
202
+ }
203
+
204
+ /**
205
+ * Default resolver callback that will simply read the file and pass back the
206
+ * filename relative to the watched dir as the url.
207
+ *
208
+ * @param {string} dir
209
+ * @return {function}
210
+ * @private
211
+ */
212
+
213
+ function noBuildCallback(dir) {
214
+ return function(filepath, callback) {
215
+ fs.readFile(path.join(dir, filepath), function(err, data) {
216
+ // Todo better error handling.
217
+ if (err) {
218
+ throw err;
219
+ }
220
+ callback({
221
+ resourceURL: filepath,
222
+ contents: data.toString()
223
+ });
224
+ });
225
+ };
226
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Copyright (c) 2014, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ var http = require('http');
13
+ var WSS = require('websocket').server;
14
+
15
+ module.exports = Server;
16
+
17
+ /**
18
+ * Starts an http server with the given options and attaches a websocket server
19
+ * to it.
20
+ *
21
+ * @class Server
22
+ * @param {object} options
23
+ */
24
+
25
+ function Server(options) {
26
+ this.log = options.log || function() {};
27
+ this.httpServer = http.createServer(function(req, res) {
28
+ res.writeHead(404);
29
+ res.end();
30
+ });
31
+ this.httpServer.listen(options.port);
32
+ this.wsServer = new WSS({
33
+ httpServer: this.httpServer,
34
+ autoAcceptConnections: false
35
+ });
36
+ this.wsServer.on('request', this.onRequest.bind(this));
37
+ this.connections = [];
38
+ }
39
+
40
+ /**
41
+ * Request handler.
42
+ *
43
+ * @param {object} req
44
+ * @private
45
+ */
46
+
47
+ Server.prototype.onRequest = function(req) {
48
+ this.log('Client connected', req.socket.address());
49
+ var ws = req.accept();
50
+ this.connections.push(ws);
51
+ ws.on('close', this.onClose.bind(this, ws));
52
+ };
53
+
54
+ /**
55
+ * Websocket connection close handler.
56
+ *
57
+ * @param {object} ws
58
+ * @private
59
+ */
60
+
61
+ Server.prototype.onClose = function(ws) {
62
+ this.log('Client disconnected', ws.remoteAddress);
63
+ if (this.connections) {
64
+ this.connections.splice(this.connections.indexOf(ws), 1);
65
+ }
66
+ };
67
+
68
+ /**
69
+ * Message handler.
70
+ *
71
+ * @param {object} msg
72
+ * @public
73
+ */
74
+
75
+ Server.prototype.broadcast = function(msg) {
76
+ this.log('Broadcasting', msg);
77
+ msg = JSON.stringify(msg);
78
+ this.connections.forEach(function(ws) {
79
+ ws.send(msg);
80
+ });
81
+ };
82
+
83
+ /**
84
+ * Close the server.
85
+ *
86
+ * @public
87
+ */
88
+
89
+ Server.prototype.close = function() {
90
+ this.log('Shutting down WebSocket server');
91
+ this.connections = null;
92
+ this.wsServer.shutDown();
93
+ this.httpServer.close();
94
+ };
@@ -0,0 +1,66 @@
1
+ sane
2
+ ----
3
+
4
+ I've been driven to insanity by node filesystem watcher wrappers.
5
+ Sane aims to be fast, small, and reliable file system watcher. It does that by:
6
+
7
+ * Always use fs.watch (unless polling is forced) and sensibly workaround the various issues with it
8
+ * Sane is all JavaScript, no native components
9
+ * Stay away from polling because it's very slow and cpu intensive
10
+ * Support polling for environments like Vagrant shared directory where there are no native filesystem events
11
+
12
+ ## Install
13
+
14
+ Requires node >= v0.10.0.
15
+
16
+ ```
17
+ $ npm install sane
18
+ ```
19
+
20
+ ## API
21
+
22
+ ### sane(dir, globs, options)
23
+
24
+ Watches a directory and all it's descendant directorys for changes, deletions, and additions on files and directories.
25
+ Shortcut for `new sane.Watcher(dir, {glob: globs, ..options})`.
26
+
27
+ ```js
28
+ var watcher = sane('path/to/dir', ['**/*.js, '**/*.css']);
29
+ watcher.on('ready', function () { console.log('ready') });
30
+ watcher.on('change', function (filepath) { console.log('file changed', filepath); });
31
+ watcher.on('add', function (filepath) { console.log('file added', filepath); });
32
+ watcher.on('delete', function (filepath) { console.log('file deleted', filepath); });
33
+ // close
34
+ watcher.close();
35
+ ```
36
+
37
+ For `options` see `sane.Watcher`.
38
+
39
+ ### sane.Watcher(dir, options)
40
+
41
+ options:
42
+
43
+ * `persistent`: boolean indicating that the process shouldn't die while we're watching files.
44
+ * `glob`: a single string glob pattern or an array of them.
45
+ * `poll`: puts the watcher in polling mode. Under the hood that means `fs.watchFile`.
46
+ * `interval`: indicates how often the files should be polled. (passed to `fs.watchFile`)
47
+
48
+ For the glob pattern documentation, see [minimatch](https://github.com/isaacs/minimatch).
49
+
50
+ ### sane.Watcher#close
51
+
52
+ Stops watching.
53
+
54
+ ### sane.Watcher events
55
+
56
+ Emits the following events:
57
+
58
+ All events are passed the file/dir path relative to the root directory
59
+ * `ready` when the program is ready to detect events in the directory
60
+ * `change` when a file changes
61
+ * `add` when a file or directory has been added
62
+ * `delete` when a file or directory has been deleted
63
+
64
+ ## License
65
+
66
+ MIT
@@ -0,0 +1,437 @@
1
+ var fs = require('fs');
2
+ var path = require('path');
3
+ var watch = require('watch');
4
+ var walker = require('walker');
5
+ var platform = require('os').platform();
6
+ var minimatch = require('minimatch');
7
+ var EventEmitter = require('events').EventEmitter;
8
+
9
+ module.exports = sane;
10
+
11
+ /**
12
+ * Sugar for creating a watcher.
13
+ *
14
+ * @param {String} dir
15
+ * @param {Array<String>} glob
16
+ * @param {Object} opts
17
+ * @return {Watcher}
18
+ * @public
19
+ */
20
+
21
+ function sane(dir, glob, opts) {
22
+ opts = opts || {};
23
+ opts.glob = glob;
24
+ return new Watcher(dir, opts);
25
+ }
26
+
27
+ /**
28
+ * Export `Watcher` class.
29
+ */
30
+
31
+ sane.Watcher = Watcher;
32
+
33
+ /**
34
+ * Watches `dir`.
35
+ *
36
+ * @class Watcher
37
+ * @param String dir
38
+ * @param {Object} opts
39
+ * @public
40
+ */
41
+
42
+ function Watcher(dir, opts) {
43
+ opts = opts || {};
44
+ this.persistent = opts.persistent != null
45
+ ? opts.persistent
46
+ : true;
47
+ this.globs = opts.glob || [];
48
+ if (!Array.isArray(this.globs)) this.globs = [this.globs];
49
+ this.watched = Object.create(null);
50
+ this.changeTimers = Object.create(null);
51
+ this.dirRegistery = Object.create(null);
52
+ this.root = path.resolve(dir);
53
+ this.watchdir = this.watchdir.bind(this);
54
+ this.register = this.register.bind(this);
55
+ this.stopWatching = this.stopWatching.bind(this);
56
+ this.filter = this.filter.bind(this);
57
+
58
+ if (opts.poll) {
59
+ this.polling = true;
60
+ watch.createMonitor(
61
+ dir,
62
+ { interval: opts.interval || DEFAULT_DELAY , filter: this.filter },
63
+ this.initPoller.bind(this)
64
+ );
65
+ } else {
66
+ this.watchdir(dir);
67
+ recReaddir(
68
+ dir,
69
+ this.watchdir,
70
+ this.register,
71
+ this.emit.bind(this, 'ready')
72
+ );
73
+ }
74
+ }
75
+
76
+ Watcher.prototype.__proto__ = EventEmitter.prototype;
77
+
78
+ /**
79
+ * Checks a file relative path against the globs array.
80
+ *
81
+ * @param {string} relativePath
82
+ * @return {boolean}
83
+ * @private
84
+ */
85
+
86
+ Watcher.prototype.isFileIncluded = function(relativePath) {
87
+ var globs = this.globs;
88
+ var matched;
89
+ if (globs.length) {
90
+ for (var i = 0; i < globs.length; i++) {
91
+ if (minimatch(relativePath, globs[i])) {
92
+ matched = true;
93
+ break;
94
+ }
95
+ }
96
+ } else {
97
+ matched = true;
98
+ }
99
+ return matched;
100
+ };
101
+
102
+ /**
103
+ * Register files that matches our globs to know what to type of event to
104
+ * emit in the future.
105
+ *
106
+ * Registery looks like the following:
107
+ *
108
+ * dirRegister => Map {
109
+ * dirpath => Map {
110
+ * filename => true
111
+ * }
112
+ * }
113
+ *
114
+ * @param {string} filepath
115
+ * @return {boolean} whether or not we have registered the file.
116
+ * @private
117
+ */
118
+
119
+ Watcher.prototype.register = function(filepath) {
120
+ var relativePath = path.relative(this.root, filepath);
121
+ if (!this.isFileIncluded(relativePath)) {
122
+ return false;
123
+ }
124
+
125
+ var dir = path.dirname(filepath);
126
+ if (!this.dirRegistery[dir]) {
127
+ this.dirRegistery[dir] = Object.create(null);
128
+ }
129
+
130
+ var filename = path.basename(filepath);
131
+ this.dirRegistery[dir][filename] = true;
132
+
133
+ return true;
134
+ };
135
+
136
+ /**
137
+ * Removes a file from the registery.
138
+ *
139
+ * @param {string} filepath
140
+ * @private
141
+ */
142
+
143
+ Watcher.prototype.unregister = function(filepath) {
144
+ var dir = path.dirname(filepath);
145
+ if (this.dirRegistery[dir]) {
146
+ var filename = path.basename(filepath);
147
+ delete this.dirRegistery[dir][filename];
148
+ }
149
+ };
150
+
151
+ /**
152
+ * Removes a dir from the registery.
153
+ *
154
+ * @param {string} dirpath
155
+ * @private
156
+ */
157
+
158
+ Watcher.prototype.unregisterDir = function(dirpath) {
159
+ if (this.dirRegistery[dirpath]) {
160
+ delete this.dirRegistery[dirpath];
161
+ }
162
+ };
163
+
164
+ /**
165
+ * Checks if a file or directory exists in the registery.
166
+ *
167
+ * @param {string} fullpath
168
+ * @return {boolean}
169
+ * @private
170
+ */
171
+
172
+ Watcher.prototype.registered = function(fullpath) {
173
+ var dir = path.dirname(fullpath);
174
+ return this.dirRegistery[fullpath] ||
175
+ this.dirRegistery[dir] && this.dirRegistery[dir][path.basename(fullpath)];
176
+ };
177
+
178
+ /**
179
+ * Watch a directory.
180
+ *
181
+ * @param {string} dir
182
+ * @private
183
+ */
184
+
185
+ Watcher.prototype.watchdir = function(dir) {
186
+ if (this.watched[dir]) return;
187
+ var watcher = fs.watch(
188
+ dir,
189
+ { persistent: this.persistent },
190
+ this.normalizeChange.bind(this, dir)
191
+ );
192
+ this.watched[dir] = watcher;
193
+
194
+ // Workaround Windows node issue #4337.
195
+ if (platform === 'win32') {
196
+ watcher.on('error', function(error) {
197
+ if (error.code !== 'EPERM') throw error;
198
+ });
199
+ }
200
+
201
+ if (this.root !== dir) {
202
+ this.register(dir);
203
+ }
204
+ };
205
+
206
+ /**
207
+ * In polling mode stop watching files and directories, in normal mode, stop
208
+ * watching files.
209
+ *
210
+ * @param {string} filepath
211
+ * @private
212
+ */
213
+
214
+ Watcher.prototype.stopWatching = function(filepath) {
215
+ if (this.polling) {
216
+ fs.unwatchFile(filepath);
217
+ } else if (this.watched[filepath]) {
218
+ this.watched[filepath].close();
219
+ delete this.watched[filepath];
220
+ }
221
+ };
222
+
223
+ /**
224
+ * End watching.
225
+ *
226
+ * @public
227
+ */
228
+
229
+ Watcher.prototype.close = function() {
230
+ Object.keys(this.watched).forEach(this.stopWatching);
231
+ this.removeAllListeners();
232
+ };
233
+
234
+ /**
235
+ * On some platforms, as pointed out on the fs docs (most likely just win32)
236
+ * the file argument might be missing from the fs event. Try to detect what
237
+ * change by detecting if something was deleted or the most recent file change.
238
+ *
239
+ * @param {string} dir
240
+ * @param {string} event
241
+ * @param {string} file
242
+ * @public
243
+ */
244
+
245
+ Watcher.prototype.detectChangedFile = function(dir, event, callback) {
246
+ var found = false;
247
+ var closest = {mtime: 0};
248
+ var c = 0;
249
+ Object.keys(this.dirRegistery[dir]).forEach(function(file, i, arr) {
250
+ fs.stat(path.join(dir, file), function(error, stat) {
251
+ if (found) return;
252
+ if (error) {
253
+ if (error.code === 'ENOENT') {
254
+ found = true;
255
+ callback(file);
256
+ } else {
257
+ this.emit('error', error);
258
+ }
259
+ } else {
260
+ if (stat.mtime > closest.mtime) {
261
+ stat.file = file;
262
+ closest = stat;
263
+ }
264
+ if (arr.length === ++c) {
265
+ callback(closest.file);
266
+ }
267
+ }
268
+ }.bind(this));
269
+ }, this);
270
+ };
271
+
272
+ /**
273
+ * Normalize fs events and pass it on to be processed.
274
+ *
275
+ * @param {string} dir
276
+ * @param {string} event
277
+ * @param {string} file
278
+ * @public
279
+ */
280
+
281
+ Watcher.prototype.normalizeChange = function(dir, event, file) {
282
+ if (!file) {
283
+ this.detectChangedFile(dir, event, function(actualFile) {
284
+ if (actualFile) {
285
+ this.processChange(dir, event, actualFile);
286
+ }
287
+ }.bind(this));
288
+ } else {
289
+ this.processChange(dir, event, path.normalize(file));
290
+ }
291
+ };
292
+
293
+ /**
294
+ * Process changes.
295
+ *
296
+ * @param {string} dir
297
+ * @param {string} event
298
+ * @param {string} file
299
+ * @public
300
+ */
301
+
302
+ Watcher.prototype.processChange = function(dir, event, file) {
303
+ var fullPath = path.join(dir, file);
304
+ var relativePath = path.join(path.relative(this.root, dir), file);
305
+ fs.stat(fullPath, function(error, stat) {
306
+ if (error && error.code !== 'ENOENT') {
307
+ this.emit('error', error);
308
+ } else if (!error && stat.isDirectory()) {
309
+ // win32 emits usless change events on dirs.
310
+ if (event !== 'change') {
311
+ this.watchdir(fullPath);
312
+ this.emitEvent(ADD_EVENT, relativePath);
313
+ }
314
+ } else {
315
+ var registered = this.registered(fullPath);
316
+ if (error && error.code === 'ENOENT') {
317
+ this.unregister(fullPath);
318
+ this.stopWatching(fullPath);
319
+ this.unregisterDir(fullPath);
320
+ if (registered) {
321
+ this.emitEvent(DELETE_EVENT, relativePath);
322
+ }
323
+ } else if (registered) {
324
+ this.emitEvent(CHANGE_EVENT, relativePath);
325
+ } else {
326
+ if (this.register(fullPath)) {
327
+ this.emitEvent(ADD_EVENT, relativePath);
328
+ }
329
+ }
330
+ }
331
+ }.bind(this));
332
+ };
333
+
334
+ /**
335
+ * Triggers a 'change' event after debounding it to take care of duplicate
336
+ * events on os x.
337
+ *
338
+ * @private
339
+ */
340
+
341
+ Watcher.prototype.emitEvent = function(type, file) {
342
+ var key = type + '-' + file;
343
+ clearTimeout(this.changeTimers[key]);
344
+ this.changeTimers[key] = setTimeout(function() {
345
+ delete this.changeTimers[key];
346
+ this.emit(type, file);
347
+ }.bind(this), DEFAULT_DELAY);
348
+ };
349
+
350
+ /**
351
+ * Initiate the polling file watcher with the event emitter passed from
352
+ * `watch.watchTree`.
353
+ *
354
+ * @param {EventEmitter} monitor
355
+ * @public
356
+ */
357
+
358
+ Watcher.prototype.initPoller = function(monitor) {
359
+ this.watched = monitor.files;
360
+ monitor.on('changed', this.pollerEmit.bind(this, CHANGE_EVENT));
361
+ monitor.on('removed', this.pollerEmit.bind(this, DELETE_EVENT));
362
+ monitor.on('created', this.pollerEmit.bind(this, ADD_EVENT));
363
+ // 1 second wait because mtime is second-based.
364
+ setTimeout(this.emit.bind(this, 'ready'), 1000);
365
+ };
366
+
367
+ /**
368
+ * Transform and emit an event comming from the poller.
369
+ *
370
+ * @param {EventEmitter} monitor
371
+ * @public
372
+ */
373
+
374
+ Watcher.prototype.pollerEmit = function(type, file) {
375
+ file = path.relative(this.root, file);
376
+ this.emit(type, file);
377
+ };
378
+
379
+ /**
380
+ * Given a fullpath of a file or directory check if we need to watch it.
381
+ *
382
+ * @param {string} filepath
383
+ * @param {object} stat
384
+ * @public
385
+ */
386
+
387
+ Watcher.prototype.filter = function(filepath, stat) {
388
+ return stat.isDirectory() || this.isFileIncluded(
389
+ path.relative(this.root, filepath)
390
+ );
391
+ };
392
+
393
+ /**
394
+ * Constants
395
+ */
396
+
397
+ var DEFAULT_DELAY = 100;
398
+ var CHANGE_EVENT = 'change';
399
+ var DELETE_EVENT = 'delete';
400
+ var ADD_EVENT = 'add';
401
+
402
+ /**
403
+ * Traverse a directory recursively calling `callback` on every directory.
404
+ *
405
+ * @param {string} dir
406
+ * @param {function} callback
407
+ * @param {function} endCallback
408
+ * @private
409
+ */
410
+
411
+ function recReaddir(dir, dirCallback, fileCallback, endCallback) {
412
+ walker(dir)
413
+ .on('dir', normalizeProxy(dirCallback))
414
+ .on('file', normalizeProxy(fileCallback))
415
+ .on('end', function() {
416
+ if (platform === 'win32') {
417
+ setTimeout(endCallback, 1000);
418
+ } else {
419
+ endCallback();
420
+ }
421
+ });
422
+ }
423
+
424
+ /**
425
+ * Returns a callback that when called will normalize a path and call the
426
+ * original callback
427
+ *
428
+ * @param {function} callback
429
+ * @return {function}
430
+ * @private
431
+ */
432
+
433
+ function normalizeProxy(callback) {
434
+ return function(filepath) {
435
+ return callback(path.normalize(filepath));
436
+ }
437
+ }