// memfs implements an in-memory fs.FS implementation // This is useful in for running d2 in javascript environments where native file calls are not available package memfs import ( "errors" "io/fs" "path" "path/filepath" "time" ) type MemoryFile struct { name string content []byte modTime time.Time isDir bool } type MemoryFS struct { files map[string]*MemoryFile } func New(m map[string]string) (*MemoryFS, error) { memFS := &MemoryFS{files: make(map[string]*MemoryFile)} for p, s := range m { p = filepath.Clean(p) dirPath := path.Dir(p) memFS.addFile(dirPath, nil, true) memFS.addFile(p, []byte(s), false) } return memFS, nil } func (mfs *MemoryFS) addFile(p string, content []byte, isDir bool) { mfs.files[p] = &MemoryFile{ name: filepath.Base(p), content: content, modTime: time.Now(), isDir: isDir, } } func (mfs *MemoryFS) Open(name string) (fs.File, error) { file, ok := mfs.files[filepath.Clean(name)] if !ok { return nil, fs.ErrNotExist } return file, nil } func (mf *MemoryFile) Stat() (fs.FileInfo, error) { return mf, nil } func (mf *MemoryFile) Read(b []byte) (int, error) { if mf.isDir { return 0, errors.New("cannot read a directory") } copy(b, mf.content) return len(mf.content), nil } func (mf *MemoryFile) Close() error { return nil } func (mf *MemoryFile) Name() string { return mf.name } func (mf *MemoryFile) Size() int64 { return int64(len(mf.content)) } func (mf *MemoryFile) Mode() fs.FileMode { return 0644 } func (mf *MemoryFile) ModTime() time.Time { return mf.modTime } func (mf *MemoryFile) IsDir() bool { return mf.isDir } func (mf *MemoryFile) Sys() interface{} { return nil }