2024-09-19 14:32:48 +00:00
|
|
|
// 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"
|
2024-10-11 20:09:51 +00:00
|
|
|
"io"
|
2024-09-19 14:32:48 +00:00
|
|
|
"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,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-11 20:09:51 +00:00
|
|
|
type MemoryFileHandle struct {
|
|
|
|
|
*MemoryFile
|
|
|
|
|
offset int
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-19 14:32:48 +00:00
|
|
|
func (mfs *MemoryFS) Open(name string) (fs.File, error) {
|
|
|
|
|
file, ok := mfs.files[filepath.Clean(name)]
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, fs.ErrNotExist
|
|
|
|
|
}
|
2024-10-11 20:09:51 +00:00
|
|
|
return &MemoryFileHandle{MemoryFile: file}, nil
|
2024-09-19 14:32:48 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-11 20:09:51 +00:00
|
|
|
func (fh *MemoryFileHandle) Stat() (fs.FileInfo, error) { return fh.MemoryFile, nil }
|
|
|
|
|
|
|
|
|
|
func (fh *MemoryFileHandle) Read(b []byte) (int, error) {
|
|
|
|
|
if fh.isDir {
|
|
|
|
|
return 0, errors.New("cannot read a directory")
|
|
|
|
|
}
|
|
|
|
|
if fh.offset >= len(fh.content) {
|
|
|
|
|
return 0, io.EOF
|
|
|
|
|
}
|
|
|
|
|
n := copy(b, fh.content[fh.offset:])
|
|
|
|
|
fh.offset += n
|
|
|
|
|
return n, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (fh *MemoryFileHandle) Close() error { return nil }
|
|
|
|
|
|
2024-09-19 14:32:48 +00:00
|
|
|
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 }
|