node package manager
Stop wasting time. Easily manage code sharing in your team. Create a free org »

atma-io

Atma Node.js FileSystem Module

Build Status NPM version

Features:

  • File Class
  • Directory Class
  • File read/write Middleware
  • Sync + Async

In comparison to NodeJS sync-async contract: all functions with generic name are synchronous, and the **Async are asynchronous with the same interface and return deferred object. Sync versions never throw exceptions and are designed to be used in not performance critical applications, like bash scripts, etc.

This library is included into Atma.Toolkit, so creating custom scripts, you can use this API.

File

File methods

File constructor
var file = new io.File('test.txt');

Path is always relative to the cwd (except windows os, when drive letter is used). To specify system absolute path, use file:// protocol.

read

Read file's content. If encoding is set to null raw Buffer is returned. For each read middleware pipeline is used, to skip it, set skipHooks to true.

var content = file.read( <?Object> {
    encoding: String | null, //> 'utf8'
    skipHooks: Boolean //> false
});
readAsync
file
    .readAsync( <?Object> {
        encoding: String | null, //> 'utf8'
        skipHooks: Boolean //> false
    })
    .done(function(content, file))
    .fail(function(error))
write
file.write(String | Buffer, <?Object>{
    skipHooks: Boolean
})
writeAsync
file
    .writeAsync(String | Buffer, <?Object>{
        skipHooks: Boolean
    })
    .done(function())
    .fail(function(error))
exists
file.exists() //> Boolean;
copyTo
file.copyTo(<String> path) //> Boolean;
copyToAsync
file.copyToAsync(<String> path) //> Deferred;
rename
file.rename(<String> filename)
renameAsync
file.renameAsync(<String> filename) //> Deferred
 
##### replace
Reads the content as string, replaces the matches and writes the result.
 
`@arguments`: same as for JavaScripts String `replace`.
 
`@return`: new content
```javascript
var str = file.replace('foo', 'bar');
replaceAsync
file
    .replaceAsync('foo', 'bar')
    .done(function(newContent) {})
    .fail(function(error) {});
##### remove
```javascript
file.remove()
removeAsync
file.removeAsync() //> Deferred
watch
file.watch(callback)

Watch file for changes

unwatch
file.unwatch(callback) //> Boolean;

Cache

Each read will be cached. To control cache behaviour use next methods:

clearCache
io.File.clearCache(<?String> path);

When path is null, then all cache is dropped.

disableCache
io.File.disableCache();
enableCache
io.File.disableCache();

short forms

There are some static methods, so that there is no need to initialize the File instance.

io.File[method] //> Function(filepath, [..args])
// methods:
        'exists'
        'existsAsync'
        'read'
        'readAsync'
        'write'
        'writeAsync'
        'remove'
        'removeAsync',
        'replace',
        'replaceAsync',
        'rename'
        'renameAsync'
        'copyTo'
        'copyToAsync'
 
// sample
io
    .File
    .readAsync('/baz.txt')
    .done(function(content){
        console.log(content);
    })
    .fail(function(error){
        console.error(error);
    })
    ;

File Middleware

Middleware pattern is used for all reads and writes. It can be used, for example, to compile coffee script to javascript on the fly. Or when reading *.yml file, the resulted content is not a YAML string, but already parsed object.

Extensions

To get the idea, look at the hook definition sample:

io.File.registerExtensions({
    'coffee':[
        'conditions:read',
        'coffee-compiler:read',
        'uglify:write'
    ]
});

Each middleware has unique name and is registerd in this way:

io.File.middleware['coffee'] = {
    read: function(<io.File> file, <Object> config){
        var coffee = require('coffee-script');
        file.content = coffee.compile(file.content);
    },
    write: function(<io.File> file, <Object> config){
        // ... do smth with `content` before disk write
    }
};

Advanced middleware

io
    .File
    .getHookHandler()
    .register({
        regexp: <RegExp>,
        method: <'read'|'write'>,
        handler: <Function | Object> handler,
        zIndex: <?Number> // default: 0
    });

Path is matched by the regexp. The greater zIndex ist the later it is called in a pipeline, otherwise the handlers are called in the order they were registerd.

Embedded middlewares

Lately will be converted into plugins, @see Plugins

  • read

    • coffee ( -> javascript )
    • markdown ( -> html )
    • jshint ( -> run jshint )
    • json ( -> JSON.parse is used )
    • yml ( -> YAML parser is used )
  • write

    • uglify ( -> Minify source before write)
    • cssmin ( -> Minify source before write)
    • yml ( -> Stringify object to yml string )
    • json ( -> Stringify object to json )

Middleware Plugins

There additional read/write middlewares as atma plugins:

atma plugin install NAME
  • atma-loader-traceur - Traceur
  • atma-loader-less - Less
Combined middlewares

For example, you want to use Traceur middelware and jshint for reading js files: via javascript

io.File.registerExtensions({
    js: ['hint:read', 'atma-loader-traceur:read' /* ... */],
})

via package.json

...
"atma"{
    "settings" : {
        "io": {
            "extensions": {
                "js": [ "hint:read", "atma-loader-traceur:read" ]
            }
        }
    }
}

Virtual Files

Define with RegExp a File Handler to completely override the read/write/exists/remove behaviour.

io
    .File
    .getFactory()
    .registerHandler(/defaults\.json$/i, Class({
        exists: function(){
            return true;
        },
        read: function(){
            return { foo: 'bar' };
        }
    }));
 

Directory

Directory methods

Constructor
var dir = new io.Directory('src/');

Path is always relative to the cwd (except windows os, when drive letter is used). To specify system absolute path, use file:// protocol.

exists
dir.exists()//> Boolean
existsAsync
dir.existsAsync()//> Deferred
readFiles
dir.readFiles(<?String> pattern).files // Array<io.Files>

Get list of all files in the directory. pattern is a glob pattern.

// all javascript files, also from sub-directories
pattern = '*.js';
// only from base directory
pattern = '/*.js'
// only from sub-directories
pattern = '**/*.js'
 
dir.readFiles(pattern).files
readFilesAsync
dir
    .readFilesAsync(<?String> pattern)
    .done(function(files))
    .fail(function(error))
copyTo

Copy files to destination directory. Before copying dir.readFiles can be called to copy only specific files.

dir.copyTo(<String> destination)
copyToAsync
dir.copyToAsync(<String> destination) //> Deferred
rename
dir.rename(<String> folderName);
renameAsync
dir.renameAsync(<String> folderName) //> Deferred
remove

Removes all content recursively and the folder itself

dir.remove() //> Boolean
removeAsync
dir.removeAsync()
ensure
dir.ensure()

Creates directory structure, if not already exists.

ensureAsync
dir.ensureAsync()
watch
dir.watch(callback)

Watch directory for changes

unwatch
dir.unwatch(callback)
short forms

There are some static methods, so that there is no need to initialize the Directory instance.

io.Directory[method] //> Function(dirpath, [..args])
// methods:
    'exists'
    'existsAsync'
    'readFiles'
    'readFilesAsync'
    'ensure'
    'ensureAsync'
    'remove'
    'removeAsync'
    'copyTo'
    'copyToAsync'
    
// sample
io
    .Directory
    .readFilesAsync('sub/', '**.js')
    .done(function(files))
    .fail(function(error))

(c) MIT - Atma.js Project