JSPM

  • Created
  • Published
  • Downloads 19001
  • Score
    100M100P100Q136273F
  • License BSD

Promise to make a better fs lib.

Package Exports

  • nofs

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (nofs) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

nofs

Overview

nofs extends Node's native fs module with some useful methods. It tries to make your function programming experience better.

NPM version Build Status Build status Deps Up to Date

Features

  • Introduce map and reduce to folders.
  • Recursive move, copy, remove, etc.
  • Promise by default.
  • Unified API. Support Promise, Sync and Callback paradigms.

Install

npm install nofs

API Convention

Unix Path Separator

When the system is Windows and process.env.force_unix_sep != 'off', nofs will force all the path separator to /, such as C:\a\b will be transformed to C:/a/b.

Promise, Sync and Callback

Any function that has a Sync version will has a promise version that ends with P. For example the fs.remove will have fs.removeSync for sync IO, and fs.removeP for Promise.

eachDir

It is the core function for directory manipulation. Other abstract functions like mapDir, reduceDir, readDirs are built on top of it. You can play with it if you don't like other functions.

nofs vs Node Native fs

nofs only extends the native module, no pollution will be found. You can still call nofs.readFile as easy as pie.

Inheritance of Options

A Function's options may inherit other function's, especially the functions it calls internally. Such as the readDirs extends the eachDir's option, therefore readDirs also has a filter option.

Quick Start

# You can replace "require('fs')" with "require('nofs')"
fs = require 'nofs'

# Callback
fs.outputFile 'x.txt', 'test', (err) ->
    console.log 'done'

# Sync
fs.readFileSync 'x.txt'
fs.copySync 'dir/a', 'dir/b'

# Promise
fs.mkdirsP 'deep/dir/path'
.then ->
    fs.outputFileP 'a.txt', 'hello world'
.then ->
    fs.moveP 'a.txt', 'b.txt'
.then ->
    fs.copyP 'b.txt', 'c.js'
.then ->
    # Get all txt files.
    fs.readDirsP 'deep', { filter: /\.txt$/ }
.then (list) ->
    console.log list
.then ->
    fs.removeP 'deep'

Changelog

Goto changelog

API

No native fs funtion will be listed.

nofs

  • Overview

    I hate to reinvent the wheel. But to purely use promise, I don't have many choices.

  • Promise

    Here I use [Bluebird][Bluebird] only as an ES6 shim for Promise. No APIs other than ES6 spec will be used. In the future it will be removed. [Bluebird]: https://github.com/petkaantonov/bluebird

  • copyDirP

    Copy an empty directory.

    • param: src { String }

    • param: dest { String }

    • param: opts { Object }

      {
          isForce: false
          mode: auto
      }
    • return: { Promise }

  • copyDirSync

    See copyDirP.

  • copyFileP

    Copy a single file.

    • param: src { String }

    • param: dest { String }

    • param: opts { Object }

      {
          isForce: false
          mode: auto
      }
    • return: { Promise }

  • copyFileSync

    See copyDirP.

  • copyP

    Like cp -r.

    • param: from { String }

      Source path.

    • param: to { String }

      Destination path.

    • param: opts { Object }

      Extends the options of eachDir. Defaults:

      {
          # Overwrite file if exists.
          isForce: false
      }
    • return: { Promise }

  • copySync

    See copyP.

  • dirExistsP

    Check if a path exists, and if it is a directory.

    • param: path { String }

    • return: { Promise }

      Resolves a boolean value.

  • dirExistsSync

    Check if a path exists, and if it is a directory.

    • param: path { String }

    • return: { boolean }

  • eachDirP

    Walk through a path recursively with a callback. The callback can return a Promise to continue the sequence. The resolving order is also recursive, a directory path resolves after all its children are resolved.

    • param: spath { String }

      The path may point to a directory or a file.

    • param: opts { Object }

      Optional. Defaults:

      {
          # Include entries whose names begin with a dot (.).
          all: false
      
          # To filter paths. It can also be a RegExp or a glob pattern string.
          # When it's a string, it extends the Minimatch's options.
          filter: (fileInfo) -> true
      
          # The current working directory to search.
          cwd: ''
      
          # Whether to include the root directory or not.
          isIncludeRoot: true
      
          # Whehter to follow symbol links or not.
          isFollowLink: true
      
          # Iterate children first, then parent folder.
          isReverse: false
      
          # When isReverse is false, it will be the previous fn resolve value.
          val: any
      
          # If it return false, sub-entries won't be searched.
          # When the `filter` option returns false, its children will
          # still be itered. But when `searchFilter` returns false, children
          # won't be itered by the fn.
          searchFilter: (fileInfo) -> true
      
          # Such as force `C:\test\path` to `C:/test/path`.
          # This option only works on Windows.
          isForceUnixSep: isWin and process.env.force_unix_sep == 'off'
      }
    • param: fn { Function }

      (fileInfo) -> Promise | Any. The fileInfo object has these properties: { path, isDir, children, stats }. Assume the fn is (f) -> f, the directory object array may look like:

      {
          path: 'dir/path'
          name: 'path'
          isDir: true
          val: 'test'
          children: [
              { path: 'dir/path/a.txt', name: 'a.txt', isDir: false, stats: { ... } }
              { path: 'dir/path/b.txt', name: 'b.txt', isDir: false, stats: { ... } }
          ]
          stats: {
              size: 527
              atime: Mon, 10 Oct 2011 23:24:11 GMT
              mtime: Mon, 10 Oct 2011 23:24:11 GMT
              ctime: Mon, 10 Oct 2011 23:24:11 GMT
              ...
          }
      }

      The stats is a native nofs.Stats object.

    • return: { Promise }

      Resolves a directory tree object.

    • example:

      # Print all file and directory names, and the modification time.
      nofs.eachDirP 'dir/path', (obj, stats) ->
          console.log obj.path, stats.mtime
      
      # Print path name list.
      nofs.eachDirP 'dir/path', (curr) -> curr
      .then (tree) ->
          console.log tree
      
      # Find all js files.
      nofs.eachDirP 'dir/path', {
          filter: '**/*.js', nocase: true
      }, ({ path }) ->
          console.log paths
      
      # Find all js files.
      nofs.eachDirP 'dir/path', { filter: /\.js$/ }, ({ path }) ->
          console.log paths
      
      # Custom filter
      nofs.eachDirP 'dir/path', {
          filter: ({ path, stats }) ->
              path.slice(-1) != '/' and stats.size > 1000
      }, (path) ->
          console.log path
  • eachDirSync

    See eachDirP.

    • return: { Object | Array }

      A tree data structure that represents the files recursively.

  • fileExistsP

    Check if a path exists, and if it is a file.

    • param: path { String }

    • return: { Promise }

      Resolves a boolean value.

  • fileExistsSync

    Check if a path exists, and if it is a file.

    • param: path { String }

    • return: { boolean }

  • globP

    Get files by patterns.

    • param: pattern { String | Array }

      The minimatch pattern.

    • param: opts { Object }

      Extends the options of eachDir. But the filter property will be fixed with the pattern. Defaults:

      {
          all: false
      
          # The minimatch option object.
          minimatch: {}
      }
    • param: fn { Function }

      (fileInfo, list) -> Promise | Any. It will be called after each match. By default it is: (fileInfo, list) -> list.push fileInfo.path

    • return: { Promise }

      Resolves the list array.

    • example:

      # Get all js files.
      nofs.globP('**/*.js').then (paths) ->
          console.log paths
      
      # Custom the iterator. Append '/' to each directory path.
      nofs.globP('**/*.js', (info, list) ->
          list.push if info.isDir
              info.path + '/'
          else
              info.path
      ).then (paths) ->
          console.log paths
  • globSync

    See globP.

    • return: { Array }

      The list array.

  • mapDirP

    Map file from a directory to another recursively with a callback.

    • param: from { String }

      The root directory to start with.

    • param: to { String }

      This directory can be a non-exists path.

    • param: opts { Object }

      Extends the options of eachDir. But cwd is fixed with the same as the from parameter.

    • param: fn { Function }

      (src, dest, fileInfo) -> Promise | Any The callback will be called with each path. The callback can return a Promise to keep the async sequence go on.

    • return: { Promise }

      Resolves a tree object.

    • example:

      # Copy and add license header for each files
      # from a folder to another.
      nofs.mapDirP(
          'from'
          'to'
          (src, dest, fileInfo) ->
              return if fileInfo.isDir
              nofs.readFileP(src).then (buf) ->
                  buf += 'License MIT\n' + buf
                  nofs.writeFileP dest, buf
      )
  • mapDirSync

    See mapDirP.

    • return: { Object | Array }

      A tree object.

  • minimatch

    The minimatch lib. Documentation Offline Documentation

    • type: { Funtion }
  • mkdirsP

    Recursively create directory path, like mkdir -p.

    • param: path { String }

    • param: mode { String }

      Defaults: 0o777 & ~process.umask()

    • return: { Promise }

  • mkdirsSync

    See mkdirsP.

  • moveP

    Moves a file or directory. Also works between partitions. Behaves like the Unix mv.

    • param: from { String }

      Source path.

    • param: to { String }

      Destination path.

    • param: opts { Object }

      Extends the options of eachDir. Defaults:

      {
          isForce: false
      }
    • return: { Promise }

      It will resolve a boolean value which indicates whether this action is taken between two partitions.

  • moveSync

    See moveP.

  • outputFileP

    Almost the same as writeFile, except that if its parent directories do not exist, they will be created.

    • param: path { String }

    • param: data { String | Buffer }

    • param: opts { String | Object }

      Same with the nofs.writeFile.

    • return: { Promise }

  • outputFileSync

    See outputFileP.

  • outputJsonP

    Write a object to a file, if its parent directory doesn't exists, it will be created.

    • param: path { String }

    • param: obj { Any }

      The data object to save.

    • param: opts { Object | String }

      Extends the options of outputFileP. Defaults:

      {
          replacer: null
          space: null
      }
    • return: { Promise }

  • outputJsonSync

    See outputJSONP.

  • readDirsP

    Read directory recursively.

    • param: root { String }

    • param: opts { Object }

      Extends the options of eachDir. Defaults:

      {
          # Don't include the root directory.
          isIncludeRoot: false
      
          isCacheStats: false
      }

      If isCacheStats is set true, the returned list array will have an extra property statsCache, it is something like:

      {
          'path/to/entity': {
              dev: 16777220
              mode: 33188
              ...
          }
      }

      The key is the entity path, the value is the nofs.Stats object.

    • return: { Promise }

      Resolves an path array.

    • example:

      # Basic
      nofs.readDirsP 'dir/path'
      .then (paths) ->
          console.log paths # output => ['dir/path/a', 'dir/path/b/c']
      
      # Same with the above, but cwd is changed.
      nofs.readDirsP 'path', { cwd: 'dir' }
      .then (paths) ->
          console.log paths # output => ['path/a', 'path/b/c']
      
      # CacheStats
      nofs.readDirsP 'dir/path', { isCacheStats: true }
      .then (paths) ->
          console.log paths.statsCache['path/a']
  • readDirsSync

    See readDirsP.

    • return: { Array }

      Path string array.

  • readJsonP

    Read A Json file and parse it to a object.

    • param: path { String }

    • param: opts { Object | String }

      Same with the native nofs.readFile.

    • return: { Promise }

      Resolves a parsed object.

    • example:

      nofs.readJsonP('a.json').then (obj) ->
          console.log obj.name, obj.age
  • readJsonSync

    See readJSONP.

    • return: { Any }

      The parsed object.

  • reduceDirP

    Walk through directory recursively with a callback.

    • param: path { String }

    • param: opts { Object }

      Extends the options of eachDir, with some extra options:

      {
          # The init value of the walk.
          init: undefined
      }
    • param: fn { Function }

      (prev, path, isDir, stats) -> Promise

    • return: { Promise }

      Final resolved value.

    • example:

      # Concat all files.
      nofs.reduceDirP 'dir/path', { init: '' }, (val, info) ->
          return val if info.isDir
          nofs.readFileP(info.path).then (str) ->
              val += str + '\n'
      .then (ret) ->
          console.log ret
  • reduceDirSync

    See reduceDirP

    • return: { Any }

      Final value.

  • removeP

    Remove a file or directory peacefully, same with the rm -rf.

    • param: path { String }

    • param: opts { Object }

      Extends the options of eachDir. But the isReverse is fixed with true.

    • return: { Promise }

  • removeSync

    See removeP.

  • touchP

    Change file access and modification times. If the file does not exist, it is created.

    • param: path { String }

    • param: opts { Object }

      Default:

      {
          atime: Date.now()
          mtime: Date.now()
          mode: undefined
      }
    • return: { Promise }

      If new file created, resolves true.

  • touchSync

    See touchP.

    • return: { Boolean }

      Whether a new file is created or not.

  • watchFileP

    Watch a file. If the file changes, the handler will be invoked. You can change the polling interval by using process.env.pollingWatch. Use process.env.watchPersistent = 'off' to disable the persistent. Why not use nofs.watch? Because nofs.watch is unstable on some file systems, such as Samba or OSX.

    • param: path { String }

      The file path

    • param: handler { Function }

      Event listener. The handler has these params:

      • file path
      • current nofs.Stats
      • previous nofs.Stats
      • if its a deletion
    • param: autoUnwatch { Boolean }

      Auto unwatch the file while file deletion. Default is true.

    • return: { Promise }

      It resolves the wrapped watch listener.

    • example:

      process.env.watchPersistent = 'off'
      nofs.watchFileP 'a.js', (path, curr, prev, isDeletion) ->
          if curr.mtime != prev.mtime
              console.log path
  • watchFilesP

    Watch files, when file changes, the handler will be invoked. It is build on the top of nofs.watchFileP.

    • param: patterns { Array }

      String array with minimatch syntax. Such as ['*/**.css', 'lib/**/*.js'].

    • param: handler { Function }

    • return: { Promise }

      It contains the wrapped watch listeners.

    • example:

      nofs.watchFiles '*.js', (path, curr, prev, isDeletion) ->
          console.log path
  • watchDirP

    Watch directory and all the files in it. It supports three types of change: create, modify, move, delete. By default, move event is disabled. It is build on the top of nofs.watchFileP.

    • param: opts { Object }

      Defaults:

      {
          dir: '.'
          pattern: '**' # minimatch, string or array
      
          # Whether to watch POSIX hidden file.
          dot: false
      
          # If the "path" ends with '/' it's a directory, else a file.
          handler: (type, path, oldPath) ->
      
          # The minimatch options.
          minimatch: {}
      
          isEnableMoveEvent: false
      }
    • return: { Promise }

      Resolves a object that keys are paths, values are listeners.

    • example:

      # Only current folder, and only watch js and css file.
      nofs.watchDir {
          dir: 'lib'
          pattern: '*.+(js|css)'
          handler: (type, path) ->
              console.log type
              console.log path
      }
  • writeFileP

    A writeFile shim for < Node v0.10.

    • param: path { String }

    • param: data { String | Buffer }

    • param: opts { String | Object }

    • return: { Promise }

  • writeFileSync

    See writeFileP

Function Alias

For some naming convention reasons, nofs also uses some common alias for fucntions. See src/alias.coffee.

Benckmark

nofs.copy vs ncp

Lisence

MIT