Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/atmajs/atma-io

NodeJS IO Classes
https://github.com/atmajs/atma-io

filesystem io middleware

Last synced: 6 days ago
JSON representation

NodeJS IO Classes

Awesome Lists containing this project

README

        

## FileSystem Module

----



----

[![Build Status](https://dl.circleci.com/status-badge/img/gh/atmajs/atma-io/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/atmajs/atma-io/tree/master)
[![NPM version](https://badge.fury.io/js/atma-io.svg)](http://badge.fury.io/js/atma-io)

Features:

- File Class.
- Directory Class.
- File IO Middlewares to preprocess reads and writes actions.
- File Transport middleware for custom file protocols, e.g. `s3://uploads/avatar.png`
- Sync and Async
- Safe Files to ensure thread-safe and process-safe file writes.
- File-locks to make custom process-safe actions easy to implement.
- File watcher: cross-platform file watchers.
- AES-256 Encryption
- HTTP Transport: `get`, `post`, `put`, `head` and `delete` methods to handle files.

----
[📚 API Documentation](https://docs.atma.dev/atma-io)
----

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

- [File](#file)
- [API](#file-methods)
- [Cache](#cache)
- [Middleware](#file-middleware)
- [Virtual File](#virtual-files)
- [Directory](#directory)
- [API](#directory-methods)

### File

#### File methods

##### File constructor
```ts
import { File } from 'atma-io'

const file = new File('./test.txt');
```

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

##### `read` `readAsync`
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.

> Hooks will be per default executed. For example, when reading from `*.json` file the string will be deserialized to json object

```ts
let content = file.read( options?: {
encoding?: 'buffer' | 'utf8' //> default 'utf8'
skipHooks?: boolean //> false
aes256?: { secret: string }
});

let content = await file.readAsync (options?: {
encoding?: 'buffer' | 'utf8', //> 'utf8'
skipHooks?: boolean //> false
aes256?: { secret: string }
});
```

##### `readRange` `readRangeAsync`
Get bytes or string for a range from the file

```ts
let content = file.readRange(position, length);

let content = await file.readRangeAsync(position, length)
```

##### `write` `writeAsync`

> Hooks will be per default executed. For example, when writing to `*.json` file and providing an object, this object will be serialized to json string

```ts
file.write(string | Buffer | any, options?: {
skipHooks?: boolean
aes256?: { secret: string }
})

file
.writeAsync(content: string | Buffer | any, options?: {
skipHooks?: boolean
aes256?: { secret: string }
})
.then(() => {}, (err) => {})
```

##### `append` `appendAsync`
```ts
file.append(content: string)

await file.appendAsync(string);
```

##### `exists` `existsAsync`
```ts
let b: boolean = file.exists()

let b: boolean = await file.existsAsync();
```

##### `copyTo` `copyToAsync`
```ts
interface IFileCopyOpts {
silent?: boolean
baseSource?: string
}
/**
* @param path: Target file path or directory, when ends with slash
*/
file.copyTo(path: string, opts?: IFileCopyOpts): boolean

file.copyToAsync(path: string, opts?: IFileCopyOpts): Promise
```

##### `rename` `renameAsync`
```ts
file.rename(filename: string)

file.renameAsync(filename: string): Promise
```

##### `replace` `replaceAsync`
Reads the content as string, replaces the matches and writes the result.
Expected arguments are the same as for JavaScripts string `replace`.
Returns new content.

```ts
file.replace(search: string | RegExp, replacer: string | Function): string

file.replaceAsync(search: string | RegExp, replacer: string | Function): Promise
```

##### `remove` `removeAsync`
```ts
file.remove(): boolean

file.removeAsync(): Promise
```

##### `watch`

Watch file for changes

```ts
file.watch(cb: (path) => void)
```

##### unwatch
```ts
file.unwatch(cb?: (path) => void): boolean
```

#### Cache
Each `read` will be cached. To control cache behavior use next methods:

##### clearCache
```ts
File.clearCache( path);
```
When `path` is `null`, then all cache is dropped.
##### disableCache
```ts
File.disableCache();
```
##### enableCache
```ts
File.disableCache();
```

#### short forms
There are some static methods, so that there is no need to initialize the File instance.
```ts
File[method] //> Function(filepath, [..args])
// methods:
'exists'
'existsAsync'
'read'
'readAsync'
'readRange'
'readRangeAsync'
'write'
'writeAsync'
'append'
'appendAsync'
'remove'
'removeAsync'
'replace'
'replaceAsync'
'rename'
'renameAsync'
'copyTo'
'copyToAsync'

// sample
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:
```ts
import { File } from 'atma-io'
File.registerExtensions({
'coffee':[
'conditions:read',
'coffee-compiler:read',
'uglify:write'
]
});
```
Each middleware has unique name and is registered in this way:
```ts
import { File } from 'atma-io'
File.middleware['coffee'] = {
read: function( file, config){
let coffee = require('coffee-script');
file.content = coffee.compile(file.content);
},
write: function( file, config){
// ... do smth with `content` before disk write
}
};
```

#### Advanced middleware
```ts
import { File } from 'atma-io'
File
.getHookHandler()
.register({
regexp: ,
method: <'read'|'write'>,
handler: handler,
zIndex: // default: 0
});
```

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

#### Embedded middlewares
_Lately will be converted into plugins, @see [Plugins](#middleware-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-ts`](https://github.com/tenbits/atma-loader-ts) - Compiles [Typescript]
- [`atma-loader-less`](https://github.com/atmajs/atma-loader-less) - Compiles Less
- [`atma-loader-sass`](https://github.com/atmajs/atma-loader-sass) - Compiles SASS
- [`atma-io-middleware-yml`](https://github.com/tenbits/atma-io-middleware-yml) - Parse YML and returns the Object
- [`atma-io-transport-s3`](https://github.com/atmajs/atma-io-transport-s3) - Read/Save `s3://` files paths from/to S3 storage

###### Combined middlewares
For example, you want to use Traceur middelware and jshint for reading `js` files:
_via javascript_
```ts
File.registerExtensions({
js: ['hint:read', 'atma-loader-ts:read' /* ... */],
})
```
_via `package.json`_
```json
...
"atma": {
"settings" : {
"io": {
"extensions": {
"js": [ "hint:read", "atma-loader-ts:read" ]
}
}
}
}
```

### **Virtual** Files

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

```ts
import { File } from 'atma-io'
File
.getFactory()
.registerHandler(/defaults\.json$/i, class {
exists (){
return true;
},
read (){
return { foo: 'bar' };
}
});

```

### Directory

#### Directory methods

##### Constructor
```ts
import { Directory } from 'atma-io'
let dir = new 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
```ts
dir.exists()//> boolean
```
##### existsAsync
```ts
dir.existsAsync()//> Deferred
```
##### readFiles
```ts
dir.readFiles( pattern).files // Array
```
Get list of all files in the directory. `pattern` is a glob pattern.
```ts
// 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
```ts
let files: File[] = await dir.readFilesAsync(globPattern?);
```

##### copyTo
Copy `files` to destination directory. Before copying `dir.readFiles` can be called to copy only specific files.
```ts
dir.copyTo(destination: string)
```
##### copyToAsync
```ts
dir.copyToAsync(destination: string) //> Deferred
```

##### rename
```ts
dir.rename( folderName);
```
##### renameAsync
```ts
dir.renameAsync( folderName) //> Deferred
```
##### remove
Removes all content recursively and the folder itself
```ts
dir.remove() //> boolean
```

##### removeAsync
```ts
dir.removeAsync()
```

##### ensure
```ts
dir.ensure()
```
Creates directory structure, if not already exists.
##### ensureAsync
```ts
dir.ensureAsync()
```

##### watch
```ts
dir.watch(callback)
```
Watch directory for changes
##### unwatch
```ts
dir.unwatch(callback)
```

##### short forms
There are some static methods, so that there is no need to initialize the Directory instance.
```ts
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