npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fs-adapters

v7.0.2

Published

Minimal interfaces for file system abstraction

Downloads

1,497

Readme

fs-adapters

CI Test Coverage Maintainability

This package provides minimal JavaScript / TypeScript interfaces for file system abstraction. It tries to include enough to be comfortable for users, without being a burden on implementers.

The main use case is test instrumentation via dependency injection. Production code could use the directory adapter for persistent storage, while unit tests might use the memory adapter instead.

Still, at its heart this is just an interface, and can be implemented to fit any number of backends. Creating custom adapter types might enable you to swap cloud with local storage on the fly, for example.

Install

npm i fs-adapters

Specification

async init()

Initialize the adapter. This would create the underlying directory, for example, or connect to the storage API, etc.

  • Returns: <Promise> A Promise for when initialization is done.

async listFiles()

Obtain a list of file names accessible through the adapter.

  • Returns: <Promise<string[]>> A Promise resolving to a file name array.

async exists(fileName)

Checks whether the given file name exists.

  • fileName <string>: The name of the file to check.
  • Returns: <Promise<boolean>> A promise resolving to whether or not this file exists.

async rename(fileName, newFileName)

Rename a file.

  • fileName <string>: The old file name.
  • newFileName <string>: The new file name.
  • Returns: <Promise> A Promise that resolves when done, or rejects on error.

async delete(fileName)

Delete a file.

  • fileName <string> The name of the file to delete.
  • Returns: <Promise> A Promise that resolves when done, or rejects on error.

createReadStream(fileName)

Create a read-stream for the given file name. This should be preferred over read() when the file is potentially large or does not need to be in memory all at once.

  • fileName <string> The name of the file to read.
  • Returns: <stream.Readable> A readable stream for the file.

createWriteStream(fileName)

Create a write-stream for the given file name.

  • fileName <string> The name of the file to write.
  • Returns: <stream.Readable> A writable stream for the file.

async read(fileName[, options])

Read the file whole, resolving to its contents as a Buffer. If an encoding is specified, this will convert the buffer to a string and resolve to that.

  • fileName <string> The name of the file to read.
  • options <object|string>
    • encoding <string|null>: encoding to use for string conversion. Default: null
  • Returns: <Promise<Buffer|string>> A Promise that resolves to the file contents, or rejects on error.

If options is a string, it is treated as the encoding.

async write(fileName, data[, options])

Write to the given file name in one go.

  • fileName <string> The name of the file to read.
  • data <Buffer|string> The file contents to write.
  • options <object|string>
    • encoding <string>: encoding to use if data is a string. Default: 'utf8'
  • Returns: <Promise> A Promise that resolves when done, or rejects on error.

If options is a string, it is treated as the encoding.

Implementations

MemoryAdapter

This adapter implements the above specification by storing all data and metadata in the process memory. It is therefore not dependent on the actual file system and highly suitable for test scenarios, for example.

Constructors

new MemoryAdapter()
new MemoryAdapter(initialFiles)
  • initialFiles <object | Map | Array[]> (optional) A mapping from file names to their contents (instances of Buffer or string data).

Usage Example

const { MemoryAdapter } = require('fs-adapters')

const adapter = new MemoryAdapter({
  'foo.txt': Buffer.from('hello world', 'utf8'),
  'empty.bin': Buffer.alloc(0)
})

// alternatively:
new MemoryAdapter(new Map([
  ['foo.txt', Buffer.from('hello world', 'utf8')],
  ['empty.bin', Buffer.alloc(0)]
]))

// or even:
new MemoryAdapter([
  ['foo.txt', 'hello world'],
  ['empty.bin', Buffer.alloc(0)]
])

adapter.init().then(() => {
  adapter.listFiles().then((files) => {
    console.log(files) // ['foo.txt', 'empty.bin']
  })
})

DirectoryAdapter

This adapter reads from and writes to a specific base directory. All file names are interpreted as relative to the base directory, and navigating outside that directory (e.g. via ..) or accessing the directory itself (e.g. via .) results in an error.

Note that creating or accessing sub-directories is not (yet) supported. This might be added in the future, please feel free to make a Pull Request!

Constructors

new DirectoryAdapter(directory)
  • directory <string> The absolute path to the base directory.

Usage Example

const { DirectoryAdapter } = require('fs-adapters')
const path = require('path')

const directory = path.join(__dirname, 'data')
const adapter = new DirectoryAdapter(directory)

adapter.init().then(() => {
  // do something with adapter
})

Extending

This is a loose specification. As such, creating a new adapter is as simple as writing a class with the specified methods. If you only need your adapter to work with plain JavaScript (not TypeScript) and want to skip practical hints from your IDE, this will be enough.

Yet, to facilitate implementation and ensure perfect interoperability between adapters, you should extend the common superclass Adapter. This has benefits even in plain JavaScript but is basically mandatory in TypeScript. All implementations supplied with this package (MemoryAdapter, DirectoryAdapter) do this.

Example:

import { Adapter } from 'fs-adapters'

class CustomAdapter extends FSAdapter {
  // implement methods here
}

The Adapter class provides default implementations for the following methods:

  • init(): does nothing by default
  • read(...): creates a read-stream and wraps it into a promise
  • write(...): creates a write-stream and wraps it into a promise

It is recommended that implementers override these default implementations when they can provide something more efficient.