Skip to content

Commit

Permalink
feat(volume): fromJSON now accepts Buffer as volume content (#880)
Browse files Browse the repository at this point in the history
This commit resolves cases when you want to inject raw binary (`Buffer`)
data into your virtual volumes. For example when you want to validate
an archive extracts files correctly.
  • Loading branch information
shorwood authored Sep 25, 2023
1 parent d1d66f6 commit 9c0a6ff
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
1 change: 1 addition & 0 deletions docs/node/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ vol.fromJSON(
{
'./index.js': '...',
'./package.json': '...',
'./index.node': new Buffer(),
},
'/app',
);
Expand Down
10 changes: 10 additions & 0 deletions src/__tests__/volume.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,16 @@ describe('volume', () => {
expect(stat.isDirectory()).toBe(true);
expect(vol.readdirSync('/dir')).toEqual([]);
});

it('supports using buffers for file content', () => {
const vol = new Volume();
const text = 'bip-boup';
const buffer = Buffer.from(text, 'utf-8');
vol.fromJSON({ '/buffer': buffer });
expect(vol.toJSON()).toStrictEqual({ '/buffer': text });
expect(vol.readFileSync('/buffer')).toStrictEqual(buffer);
expect(vol.readFileSync('/buffer', 'utf-8')).toStrictEqual(text);
});
});

describe('.fromNestedJSON(nestedJSON[, cwd])', () => {
Expand Down
18 changes: 9 additions & 9 deletions src/volume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,13 @@ function validateGid(gid: number) {
}

// ---------------------------------------- Volume
type DirectoryContent = string | null;
type DirectoryContent = string | Buffer | null;

export interface DirectoryJSON {
[key: string]: DirectoryContent;
export interface DirectoryJSON<T extends DirectoryContent = DirectoryContent> {
[key: string]: T;
}
export interface NestedDirectoryJSON {
[key: string]: DirectoryContent | NestedDirectoryJSON;
export interface NestedDirectoryJSON<T extends DirectoryContent = DirectoryContent> {
[key: string]: T | NestedDirectoryJSON;
}

function flattenJSON(nestedJSON: NestedDirectoryJSON): DirectoryJSON {
Expand All @@ -206,7 +206,7 @@ function flattenJSON(nestedJSON: NestedDirectoryJSON): DirectoryJSON {

const joinedPath = join(pathPrefix, path);

if (typeof contentOrNode === 'string') {
if (typeof contentOrNode === 'string' || contentOrNode instanceof Buffer) {
flatJSON[joinedPath] = contentOrNode;
} else if (typeof contentOrNode === 'object' && contentOrNode !== null && Object.keys(contentOrNode).length > 0) {
// empty directories need an explicit entry and therefore get handled in `else`, non-empty ones are implicitly considered
Expand Down Expand Up @@ -526,7 +526,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
});
}

private _toJSON(link = this.root, json = {}, path?: string, asBuffer?: boolean): DirectoryJSON {
private _toJSON(link = this.root, json = {}, path?: string, asBuffer?: boolean): DirectoryJSON<string | null> {
let isEmpty = true;

let children = link.children;
Expand Down Expand Up @@ -568,7 +568,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
return json;
}

toJSON(paths?: PathLike | PathLike[], json = {}, isRelative = false, asBuffer = false): DirectoryJSON {
toJSON(paths?: PathLike | PathLike[], json = {}, isRelative = false, asBuffer = false): DirectoryJSON<string | null> {
const links: Link[] = [];

if (paths) {
Expand All @@ -595,7 +595,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {

filename = resolve(filename, cwd);

if (typeof data === 'string') {
if (typeof data === 'string' || data instanceof Buffer) {
const dir = dirname(filename);
this.mkdirpBase(dir, MODE.DIR);

Expand Down

0 comments on commit 9c0a6ff

Please sign in to comment.