node package manager

atma-io

File / Directory Classes

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