New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add support for nested objects to fromJSON()
#535
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, this will be cool.
I actually wrote a utility function for this back when I first started using memfs that I meant to pr back, and it looks very similar aside from using the array methods for looping.
I'll include it here if you want to have a look - looking over it I'm pretty sure they're identical in logic 😂
code
import * as path from 'path';
type Contents = string | null;
export interface Directory {
[key: string]: Directory | Contents;
}
/**
* Flattens an object representing nested directories, so that it can be used with `memfs`.
*
* `memfs` expects a single level JSON object, with directories being represented by slashes.
* This function generates such an object from a nested object.
*
* `root` is the "root" of the dir - by default this is the actual root ('/').
* You should only have to manually set this if you merge directories, using the spread operator.
*
* @example
* vol.fromJSON(
* flatDirJSON({
* dir: {
* 'file.txt': 'contents'
* }
* })
* );
*
* @param {Directory | null} dir
* @param {string} [root='/']
*
* @return {Record<string, string>}
*/
export const flatDirJSON = (dir: Directory | null, root = '/'): Record<string, Contents> => {
if (dir === null) {
return { [root]: dir };
}
const flattenDir: Record<string, Contents> = {};
Object.keys(dir).reduce<Array<[string, Contents]>>((files, folderName) => {
const flattenName = path.posix.join(root, folderName);
const folderValue = dir[folderName];
const directory: Array<[string, Contents]> = (
typeof folderValue !== 'string'
? Object.entries(flatDirJSON(folderValue, flattenName))
: [[flattenName, folderValue]]
);
return files.concat(directory);
}, []).forEach(([name, value]) => flattenDir[name] = value);
return flattenDir;
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it could be a separate function or a separate library that given nested object keys flattens it?
const data = {
dir1: {
file: 'foobar',
},
};
flattenObject(data);
/*
{
'dir1/file': 'foobar'
}
*/
@G-Rath ah, you beat me :D |
I think we clicked submit on the same second 😂
I don't have a strong preference - I think it's nice to have I feel while it's not a big deal, it's still a deal that Maybe the answer is I did just think of a good question tho: what happens when you pass in an array, since that's an object 😬 |
For me the best two options are integrating it into Regarding passing an array: well, it will not really work as expected - but that's the case right now too :D |
I did some general cleanup to the |
I'm a bit concerned about overloading fromNestedJSON(dir) {
return this.fromJSON(flatDirJSON(dir));
} |
Ok, I think its more intuitive that way but it's of course your decision ;) |
@FlorianLoch We can do only the static method, without the instance method. Let's not expose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Looks good, just one questions and a nit see below.
fromNestedJSON(json: NestedDirectoryJSON, cwd?: string) { | ||
this.fromJSON(flattenJSON(json), cwd); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we have a similar static method, do we need this one on the instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just thought it would be more consistent this way two have both methods as static and as member ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
🎉 This PR is included in version 3.2.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This adds support for nested object (literals) to
fromJSON()
. It reads much nicer and makes tests look cleaner (at least that is my personal opinion). One of the features I miss most not being able to usemock-fs
.I added this functionality to
fromJSON()
itself, one could argue having an additional method likefromNestedJSON()
might be better regarding to backward compatibility. I don't think this is a problem at all, but the rather exotic corner case of callingfromJSON()
with something like{'dir1': {'dir2'}}
just createddir1
so far, but would also createdir2
from now on...Feedback on this is highly appreciated!
Additionally this fixes a bug (at least I think it's one): so far
fromJSON()
only took thecwd
parameter into account when creating files, not when creating directories.