import{Path}from"../../utils/path";import{readFile}from"file";importDirectoryfrom"../filetype/directory";importtype{PageSettings}from"../../types/site";/** * Any file on the system. */classFile{// the full path to the filepublicpath: Path;// The page settings config used within this file's lifetimepubliccachedConfig: PageSettings;// If this file is 'pretending' to be another file,// the file that this was wrapped around is accessible here.// This allows us to pull tricks like asking questions about a// javascript file when the actual file is written in typescript,// converting configuration files into others on the fly,// reading SCSS as CSS, etc.publicfakeFileOf?: File;/** * Construct a file. */constructor(pathArg: Path,cfg: PageSettings){constfilePath=Path.create(pathArg);if(!filePath.exists()){thrownewError(`from File constructor: File at path '${pathArg}' does not exist`);}this.path=filePath;this.cachedConfig=cfg;}staticcreate(path: Path,cfg: PageSettings){returnnewthis(path,cfg);}/** * Two files are equal if their paths are equal. */equals(file: File){returnthis.path.equals(file.path);}clone(): typeofthis{// note: `this.constructor` is always callable as a constructor,// but TypeScript doesn't seem to have a special notion of a 'constructor'// function that can be invoked like an arbitrary function.// Not even sure it's possible with the JS spec.returnnew(this.constructorasany)(this.path);}// read the file at the pathread(){thrownewError("File.read() is not implemented");}// the title of the file does notgettitle(){returnthis.name.split(".")[0];}// the name of a file includes the extensiongetname(){returnthis.path.name;}// the type of the file is the extension (for now?)getextension(){returnthis.path.extension;}// get the mime type of the filegetmimeType(){returnthis.path.mimeType;}/** * By default, files haven o text. * * Maybe I'll discover a way to render as text at some point. * This is necessary because overrides for serve() rely on overriding this.text * so that e.g. an HTML file can return '' for the text */text(cfg: PageSettings){return"";}/** * Get the parent directory of this file. */directory(cfg?: PageSettings): Directory{// A `parent` file, by definition, is a directory that contains this one.returnreadFile(this.path.parent,this.cachedConfig)asunknownasDirectory;}/** * Determine if the file is a directory. * Always false here; directory subclass reimplements this. */isDirectory(): this is Directory{returnfalse;}write(config: PageSettings): typeofthis{console.error(`file.write() is not implemented for file at '${this.path.toString()}'`);returnthis;}// get the url to the html page with this file// if provided a directory, get the url to the directory with index.html postfixed (?)htmlUrl({ rootUrl, sourceDir }: {rootUrl: string;sourceDir: string}){constrelativeToSource=this.path.relativeTo(sourceDir);returnrootUrl+relativeToSource.addExtension("html");}getrepo(){constrepoAtPath=this.path.repo;if(!repoAtPath){console.log(`From File.repo: File at path '${this.path}' is not in a repo`);returnnull;}returnrepoAtPath;}getlastLog(){returnthis.repo?.getFile(this.path)?.lastLog;}getlog(){returnthis.repo?.getFile(this.path)?.log??[];}getlastTimestamp(){returnthis.repo?.getFile(this.path).lastTimestamp;}// by default, files do not depend on any other files.dependencies(settings: PageSettings): File[]{return[];}/** * Serve the file as HTML. * By default, assume the file has some text output and try to get that. */serve(args: PageSettings){return{contents: this.text(args),mimeType: this.mimeType};}/** * Watch the file, attaching an event listener to pick up on file events. */watch(callback: (eventType: string,file: File)=>void){constcloseWatcher=this.path.watch((eventType: string,filename: string)=>{callback(eventType,this);});returncloseWatcher;}}exportdefaultFile;