package filesystem import ( "encoding/json" "os" "time" ) type FS interface { ReadDir(path string) ([]os.FileInfo, error) Read(path string) ([]byte, error) Stat(path string) (os.FileInfo, error) } type FileInfo interface { os.FileInfo ContentType() string Path() string } // File implements FileInfo type File struct { name string size int64 mode os.FileMode modTime time.Time isDir bool contentType string path string } func (f File) Name() string { return f.name } func (f File) Size() int64 { return f.size } func (f File) Mode() os.FileMode { return f.mode } func (f File) ModTime() time.Time { return f.modTime } func (f File) IsDir() bool { return f.isDir } func (f File) Sys() any { return nil } func (f File) ContentType() string { return f.contentType } func (f File) Path() string { return f.path } type serializableFile struct { Name string `json:"name"` Size int64 `json:"size"` Mode os.FileMode `json:"mode"` ModTime time.Time `json:"modTime"` IsDir bool `json:"isDir"` ContentType string `json:"contentType"` Path string `json:"path"` } // MarshalJSON implements json.Marshaler func (f File) MarshalJSON() ([]byte, error) { // Create a local shadow struct with exported fields for the JSON package return json.Marshal(serializableFile{ Name: f.name, Size: f.size, Mode: f.mode, ModTime: f.modTime, IsDir: f.isDir, ContentType: f.contentType, Path: f.path, }) } // UnmarshalJSON implements json.Unmarshaler func (f *File) UnmarshalJSON(data []byte) error { // Define a shadow struct to capture the incoming JSON shadow := serializableFile{} if err := json.Unmarshal(data, &shadow); err != nil { return err } // Transfer values to the actual struct f.name = shadow.Name f.size = shadow.Size f.mode = shadow.Mode f.modTime = shadow.ModTime f.isDir = shadow.IsDir f.contentType = shadow.ContentType f.path = shadow.Path return nil } func ParseToFile(file os.FileInfo) File { if fi, ok := file.(FileInfo); ok { return File{ name: fi.Name(), size: fi.Size(), mode: fi.Mode(), modTime: fi.ModTime(), isDir: fi.IsDir(), contentType: fi.ContentType(), path: fi.Path(), } } else { // Fallback if underlying impl returns generic os.FileInfo return File{ name: file.Name(), size: file.Size(), mode: file.Mode(), modTime: file.ModTime(), isDir: file.IsDir(), } } }