Adds YAML support to readJSONFilesAsync
authorDavid Schoonover <dsc@wikimedia.org>
Thu, 12 Jul 2012 19:09:36 +0000 (12:09 -0700)
committerDavid Schoonover <dsc@wikimedia.org>
Thu, 12 Jul 2012 19:09:36 +0000 (12:09 -0700)
src/server/files.co

index bb815a3..b07f73e 100644 (file)
@@ -3,12 +3,14 @@
  */
 
 
-fs   = require 'fs'
-path = require 'path'
+fs     = require 'fs'
+path   = require 'path'
+exists = fs.existsSync or path.existsSync
 
 _    = require 'underscore'
 Seq  = require 'seq'
 glob = require 'glob'
+yaml = require 'js-yaml'
 
 
 /**
@@ -16,13 +18,17 @@ glob = require 'glob'
  * globs supplied, returning a map from filepath to contents.
  * 
  * @param {String|Array<String>} patterns List of file-paths and/or glob-patterns to read.
+ * @param {Object} [opts={}] Options:
+ * @param {Boolean} [opts.verbose=false] Be chatty about errors.
  * @param {Function} cb Callback taking `(error, data)` where `data` is a map
  *  from filepath to contents. As always, `error` will be null on success.
  * @returns {Seq} The Seq object representing the async operation chain. (You
  *  can usually ignore this.)
  */
-readFilesAsync = exports.readFilesAsync = (patterns, cb) ->
+readFilesAsync = exports.readFilesAsync = (patterns, opts, cb) ->
     patterns = [patterns] if typeof patterns is 'string'
+    [cb, opts] = [opts, {}] if typeof opts is 'function'
+    opts = {-verbose, ...opts or {}}
     files = []
     data = {}
     Seq patterns
@@ -45,21 +51,35 @@ readFilesAsync = exports.readFilesAsync = (patterns, cb) ->
  * globs supplied, returning a map from filepath to contents.
  * 
  * @param {String|Array<String>} patterns List of filepaths and/or glob-patterns to read.
+ * @param {Object} [opts={}] Options:
+ * @param {Boolean} [opts.verbose=false] Be chatty about errors.
+ * @param {Boolean} [opts.yaml=false] Also search for and include YAML files.
+ * @param {Boolean} [opts.appendExt=true] Treat the patterns as directories, and append
+ *  the appropriate file extension glob-patterns.
  * @param {Function} cb Callback taking `(error, data)` where `data` is a map
  *  from filepath to contents. As always, `error` will be null on success.
  * @returns {Seq} The Seq object representing the async operation chain. (You
  *  can usually ignore this.)
  */
-readJSONFilesAsync = exports.readJSONFilesAsync = (patterns, cb) ->
+readJSONFilesAsync = exports.readJSONFilesAsync = (patterns, opts, cb) ->
+    patterns = [patterns] if typeof patterns is 'string'
+    [cb, opts] = [opts, {}] if typeof opts is 'function'
+    opts = {-yaml, +appendExt, -verbose, ...opts or {}}
     data = {}
+    
+    if opts.appendExt
+        ext = if opts.yaml then '@(yaml|json)' else 'json'
+        patterns .= map -> path.join it, "*.#ext"
+    
     Seq()
-        .seq -> readFilesAsync patterns, this
+        .seq readFilesAsync, patterns, {opts.verbose}, Seq
         .seq (data) ->
             @ok _.map data, (text, f) -> [f, text]
         .flatten false # flatten one level
         .parMap ([f, text]) ->
+            parser = if /\.yaml$/i.test f then yaml.load else JSON.parse
             try
-                data[f] = JSON.parse text
+                data[f] = parser text
                 @ok()
             catch err
                 err.file = f
@@ -70,6 +90,8 @@ readJSONFilesAsync = exports.readJSONFilesAsync = (patterns, cb) ->
             console.error err.file, err
             cb err
 
+
+
 logErrorsAnd = exports.logErrorsAnd = (cb) ->
     (err, ...args) ->
         global.args = arguments
@@ -78,6 +100,7 @@ logErrorsAnd = exports.logErrorsAnd = (cb) ->
         else
             cb ...args if cb
 
+
 ## Test Code
 if require.main is module
     files = exports
@@ -89,8 +112,5 @@ if require.main is module
         else console.log '\n\n', global.data = u.map data, (txt, f) -> "#f: #{txt.length}"
     
     # u = require 'limn/util/underscore'; files = require 'limn/server/files'
-    # files.readJSONFilesAsync 'data/**/*.json', files.logErrorsAnd()
-
-
-
+    # files.readJSONFilesAsync 'data/**', {+yaml}, files.logErrorsAnd()