# @putout/operator-filesystem [![NPM version][NPMIMGURL]][NPMURL]

[NPMIMGURL]: https://img.shields.io/npm/v/@putout/operator-filesystem.svg?style=flat&longCache=true
[NPMURL]: https://npmjs.org/package/@putout/operator-filesystem "npm"

🐊[**Putout**](https://github.com/coderaiser/putout) operator adds ability to lint filesystem.

## Install

```
npm i putout @putout/operator-filesystem
```

## API

### `createFile(directoryPath: DirectoryPath, name: string, content?: string): FilePath`

```js
const {operator} = require('putout');
const {findFile, createFile} = operator;

const [dirPath] = findFile(ast, 'hello');
const filePath = createFile(dirPath, 'world.txt', 'hello world');
```

### `createDirectory(directoryPath: DirectoryPath, name: string): DirectoryPath`

```js
const {operator} = require('putout');
const {
    createDirectory,
    findFile,
} = operator;

const [dirPath] = findFile(ast, 'hello');

const newDirectoryPath = createDirectory(dirPath, 'world');
```

### `createNestedDirectory(path: FilePath|DirectoryPath, name: string): DirectoryPath`

```js
const {operator} = require('putout');
const {
    createDirectory,
    findFile,
    createNestedDirectory,
} = operator;

const newDirectoryPath = createNestedDirectory(ast, '/hello/world');
```

### `removeEmptyDirectory(DirectoryPath)`

```js
const {operator} = require('putout');
const {
    removeEmptyDirectory,
    createNestedDirectory,
} = operator;

const newDirectoryPath = createNestedDirectory(ast, '/hello/world');

removeEmptyDirectory(newDirectoryPath);
```

### `readDirectory(directoryPath: DirectoryPath): (FilePath | DirectoryPath)[]`

```js
const {operator} = require('putout');
const {
    finedFiles,
    findFile,
    readDirectory,
} = operator;

const [dirPath] = findFile(ast, '/bin');

readDirectory(dirPath);
// returns list of files
[];
```

### `findFile(directoryPath: DirectoryPath, name: string | string[] | Set<string>, exclude?: string[]): (FilePath | DirectoryPath)[]`

Traverse filesystem to search one or more files:

```js
const {operator} = require('putout');
const {findFile} = operator;

const [filePath] = findFile(ast, 'hello');
```

You can also pass array of file masks:

```js
import {operator} from 'putout';

const {findFile} = operator;
const coupleFiles = findFile(ast, ['*.js', '*.ts']);
```

Or `exclude` some files:

```js
import {operator} from 'putout';

const {findFile, getFilename} = operator;

const coupleFilesWithExcludeArray = findFile(ast, '*.ts', ['*.d.ts']);
```

And even search for a directory:

```js
import {operator} from 'putout';

const {findFile} = operator;
const coupleFiles = findFile(root, ['/home/coderaiser', '/home/coderaiser/putout']);
```

Each 🐊**Putout** plugin should use `findFile` independently since AST can change: files renamed, removed etc.
Anyways inside one plugin while you applying changes related to one plugin you can speed things drastically crawling file system once. It works good if plugin do not mutates the file tree, only file content.

☝️ *`findFile` expensive, when you need to call it often use `crawlDirectory()`*

### `crawlDirectory(directoryPath: directoryPath): Crawled`

```js
import {operator} from 'putout';

const {findFile} = operator;
const crawled = crawlDirectory(rootPath);

const [file] = findFile(root, 'hello', {
    crawled,
});
```

### `getFile(directoryPath: DirectoryPath, name: string | string[], options?: Options): FilePath[]`

```ts
type Options = {
    type?: 'file' | 'directory';
};
```

Get file named `name` from `directoryPath`

```js
const {operator} = require('putout');
const {getFile} = operator;

const [filePath] = getFile(root, 'package.json');
```

When you need a couple files use:

```js
import {operator} from 'putout';

const {getFile} = operator;
const [index, indexSpec] = getFile(root, ['index.js', 'index.spec.js']);
```

### `getParentDirectory(path: FilePath | DirectoryPath): FilePath | null`

```js
const {operator} = require('putout');
const {
    createDirectory,
    findFile,
    getParentDirectory,
} = operator;

const [dirPath] = findFile(ast, 'hello');

const newDirectoryPath = createDirectory(dirPath, 'world');

dirPath === getParentDirectory(newDirectoryPath);
// returns
true;
```

### `getRootDirectory(path: FilePath | DirectoryPath | File): DrectoryPath`

```js
const {operator} = require('putout');
const {
    findFile,
    getRootDirectory,
} = operator;

const [filePath] = findFile(ast, 'hello');

getRootDirectory(dirPath);
```

### `getFilename(path: FilePath | DirectoryPath): string`

```js
const {operator} = require('putout');
const {getFilename} = operator;

const name = getFilename(filePath);
```

### `getFileType(path: FilePath): string`

```js
const {operator} = require('putout');
const {getFilename, getFileType} = operator;

getFileType(filePath);
// returns
'file';
```

### `removeFile(filePath: Path)`

```js
const {operator} = require('putout');
const {removeFile} = operator;

removeFile(filePath);
```

### `copyFile(path: FilePath | DirectoryPath, directoryPath: DirectoryPath)`

```js
const {operator} = require('putout');
const {moveFile, copyFile} = operator;

copyFile(filePath, dirPath);
```

### `moveFile(path: FilePath | DirectoryPath, directoryPath: DirectoryPath)`

```js
const {operator} = require('putout');
const {moveFile} = operator;

moveFile(filePath, dirPath);
```

### `readFileContent(filePath: FilePath): string`

```js
const {operator} = require('putout');
const {readFileContent} = operator;

readFileContent(filePath);
// returns
'hello';
```

### `writeFileContent(filePath: FilePath, content: string)`

```js
const {operator} = require('putout');
const {
    writeFileContent,
    readFileContent,
} = operator;

writeFileContent(filePath, 'hello');
readFileContent(filePath);
// returns
'hello';
```

### `renameFile(path: FilePath | DirectoryPath, name: string)`

```js
const {operator} = require('putout');
const {renameFile, findFile} = operator;

const [filePath] = findFile(path, 'README.md');

renameFile(filePath, 'readme.md');
```

this is the same as:

```
renameFile(filePath, '/any/path/here/readme.md');
```

Since `basename` is used.

> The `path.basename()` method returns the last portion of a path, similar to the Unix basename command. Trailing directory separators are ignored.
>
> (c) [nodejs.org](https://nodejs.org/api/path.html#pathbasenamepath-suffix)

To move file use [`moveFile()`](#movefilefilepath-filepath-dirpath-filepath).

### `inject`

Inject filesystem API with methods:

- ✅ `renameFile`;
- ✅ `copyFile`;
- ✅ `removeFile;
- ✅ `createDirectory;
- ✅ `readFileContent;
- ✅ `writeFileContent;

To have ability to interact with any kind of filesystem representation.

```js
import {inject} from '@putout/operator-filesystem/maybe';
import * as filesystemCLI from '@putout/cli-filesystem';

inject(filesystemCLI);
```

### `eject`

```js
import {eject} from '@putout/operator-filesystem/maybe';

eject();
```

### `pause`

Pause currently injected filesystem API

```js
import {pause} from '@putout/operator-filesystem/maybe';

pause();
```

### `start`

Start currently paused injected filesystem API.

```js
import {start} from '@putout/operator-filesystem/maybe';

start();
```

## Example

```js
const montag = require('montag');
const {
    parse,
    print,
    operator,
} = require('putout');

const {renameFile, findFile} = operator;

const ast = parse(montag`
    putout_processor_filesystem({
        "type": "directory",
        "filename": "/hello",
        "files": []
    });
`);

const [filePath] = findFile(ast, 'hello');

renameFile(filePath, 'world');

print(ast);
// returns
`
putout_processor_filesystem({
    "type": "directory",
    "filename": "/hello",
    "files": []
});
`;
```

## License

MIT
