Skip to content

Commit

Permalink
feat: 🎸 implement keys() method
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 20, 2023
1 parent 8b27695 commit 33f9af0
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 3 deletions.
19 changes: 18 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,29 @@ export function createFsFromVolume(vol: _Volume): IFs {
fs.promises = vol.promises;

fs._toUnixTimestamp = toUnixTimestamp;
(fs as any).__vol = vol;

return fs;
}

export const fs: IFs = createFsFromVolume(vol);

/**
* Creates a new file system instance.
*
* @param json File system structure expressed as a JSON object.
* Use `null` for empty directories and empty string for empty files.
* @param cwd Current working directory. The JSON structure will be created
* relative to this path.
* @returns A `memfs` file system instance, which is a drop-in replacement for
* the `fs` module.
*/
export const memfs = (json: DirectoryJSON = {}, cwd: string = '/') => {
const volume = Volume.fromJSON(json, cwd);
const fs = createFsFromVolume(volume);
return fs as IFs & typeof import('fs');
};

declare let module;
module.exports = { ...module.exports, ...fs };

module.exports.semantic = true;
114 changes: 114 additions & 0 deletions src/node-to-fsa/NodeFileSystemDirectoryHandle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {NodeFileSystemHandle} from "./NodeFileSystemHandle";
import {basename} from "./util";
import type {FsaNodeFs} from "./types";

/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle
*/
export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle {
constructor (
protected readonly fs: FsaNodeFs,
protected readonly path: string,
) {
super('directory', basename(path));
}

/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/entries
*/
public entries(): AsyncIterableIterator<[string, NodeFileSystemHandle]> {
throw new Error('Not implemented');
}

/**
* Returns a new array iterator containing the keys for each item in
* {@link NodeFileSystemDirectoryHandle} object.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/keys
*/
public keys(): AsyncIterableIterator<string> {
const {path, fs} = this;
return (async function*() {
const list = await fs.promises.readdir(path);
for (const name of list) yield name;
})();
}

/**
* Returns a new array iterator containing the values for each index in the
* {@link FileSystemDirectoryHandle} object.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/values
*/
public values(): AsyncIterableIterator<NodeFileSystemHandle> {
throw new Error('Not implemented');
}

/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/getDirectoryHandle
* @param name A string representing the {@link NodeFileSystemHandle} name of
* the subdirectory you wish to retrieve.
* @param options An optional object containing options for the retrieved
* subdirectory.
*/
public getDirectoryHandle(name: string, options?: GetDirectoryHandleOptions): Promise<NodeFileSystemDirectoryHandle> {
throw new Error('Not implemented');
}

/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/getFileHandle
* @param name A string representing the {@link NodeFileSystemHandle} name of
* the file you wish to retrieve.
* @param options An optional object containing options for the retrieved file.
*/
public getFileHandle(name: string, options?: GetFileHandleOptions): Promise<NodeFileSystemDirectoryHandle> {
throw new Error('Not implemented');
}

/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/removeEntry
* @param name A string representing the {@link FileSystemHandle} name of the
* entry you wish to remove.
* @param options An optional object containing options.
*/
public removeEntry(name: string, options?: RemoveEntryOptions): Promise<void> {
throw new Error('Not implemented');
}

/**
* The `resolve()` method of the {@link FileSystemDirectoryHandle} interface
* returns an {@link Array} of directory names from the parent handle to the specified
* child entry, with the name of the child entry as the last array item.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/resolve
* @param possibleDescendant The {@link NodeFileSystemFileHandle} from which
* to return the relative path.
*/
public resolve(possibleDescendant: NodeFileSystemHandle): Promise<string[] | null> {
throw new Error('Not implemented');
}
}

export interface GetDirectoryHandleOptions {
/**
* A boolean value, which defaults to `false`. When set to `true` if the directory
* is not found, one with the specified name will be created and returned.
*/
create?: boolean;
}

export interface GetFileHandleOptions {
/**
* A Boolean. Default `false`. When set to `true` if the file is not found,
* one with the specified name will be created and returned.
*/
create?: boolean;
}

export interface RemoveEntryOptions {
/**
* A boolean value, which defaults to `false`. When set to true entries will
* be removed recursively.
*/
recursive?: boolean;
}
6 changes: 5 additions & 1 deletion src/node-to-fsa/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
This adapter code converts an instance of [Node.js FS API](https://nodejs.org/api/fs.html) to a [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) (FSA) instance.
This adapter code converts an instance of [Node.js FS API][node-fs] to a
[File System Access API][fsa] (FSA) instance.

[node-fs]: https://nodejs.org/api/fs.html
[fsa]: https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API
47 changes: 47 additions & 0 deletions src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {DirectoryJSON, memfs} from '../..';
import {NodeFileSystemDirectoryHandle} from '../NodeFileSystemDirectoryHandle';

const setup = (json: DirectoryJSON = {}) => {
const fs = memfs(json, '/');
const dir = new NodeFileSystemDirectoryHandle(fs, '/');
return {dir, fs};
};

test('can instantiate', () => {
const {dir} = setup();
expect(dir).toBeInstanceOf(NodeFileSystemDirectoryHandle);
});

describe('.keys()', () => {
test('returns an empty iterator for an empty directory', async () => {
const {dir} = setup();
const keys = dir.keys();
expect(await keys.next()).toEqual({done: true, value: undefined});
});

test('returns a folder', async () => {
const {dir} = setup({folder: null});
const list: string [] = [];
for await (const key of dir.keys()) list.push(key);
expect(list).toEqual(['folder']);
});

test('returns two folders', async () => {
const {dir} = setup({
folder: null,
'another/folder': null,
});
const list: string [] = [];
for await (const key of dir.keys()) list.push(key);
expect(list.length).toBe(2);
});

test('returns a file', async () => {
const {dir} = setup({
'file.txt': 'Hello, world!',
});
const list: string [] = [];
for await (const key of dir.keys()) list.push(key);
expect(list).toEqual(['file.txt']);
});
});
5 changes: 5 additions & 0 deletions src/node-to-fsa/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Required Node.js `fs` module functions for File System Access API.
*/
export type FsaNodeFs = Pick<typeof import('fs'), 'promises'>;

export interface NodeFileSystemHandlePermissionDescriptor {
mode: 'read' | 'readwrite';
}
3 changes: 2 additions & 1 deletion src/volume.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as pathModule from 'path';
import { PathLike, symlink } from 'fs';
import { Node, Link, File } from './node';
import Stats from './Stats';
import Dirent from './Dirent';
Expand All @@ -14,6 +13,7 @@ import { TEncodingExtended, TDataOut, assertEncoding, strToEncoding, ENCODING_UT
import * as errors from './internal/errors';
import util = require('util');
import createPromisesApi from './promises';
import type { PathLike, symlink } from 'fs';

const resolveCrossPlatform = pathModule.resolve;
const {
Expand Down Expand Up @@ -930,6 +930,7 @@ export class Volume {
return json;
}

// TODO: `cwd` should probably not invoke `process.cwd()`.
fromJSON(json: DirectoryJSON, cwd: string = process.cwd()) {
for (let filename in json) {
const data = json[filename];
Expand Down

0 comments on commit 33f9af0

Please sign in to comment.