|  | // @ts-check | 
        
          |  |  | 
        
          |  | // Script to either host a local web server or run npm scripts | 
        
          |  |  | 
        
          |  | const http = require("http"); | 
        
          |  | const fs = require("fs"); | 
        
          |  | const path = require("path"); | 
        
          |  | const cp = require("child_process"); | 
        
          |  |  | 
        
          |  | const folder = process.argv.length <= 2 ? process.cwd() : path.resolve(process.argv[2]); | 
        
          |  |  | 
        
          |  | console.log(folder); | 
        
          |  |  | 
        
          |  | if (!fs.existsSync(folder)) { | 
        
          |  | console.log("Error: Path does not exist"); | 
        
          |  | process.exit(1); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | if (fs.existsSync(folder + "/package.json")) { | 
        
          |  | let obj; | 
        
          |  | try { | 
        
          |  | obj = JSON.parse(fs.readFileSync(folder + "/package.json", "utf8")); | 
        
          |  | } catch (err) { | 
        
          |  | console.log("Could not interpret package json:"); | 
        
          |  | console.log(err); | 
        
          |  | } | 
        
          |  | if (!obj) { | 
        
          |  | startLocalWebServer(); | 
        
          |  | } else { | 
        
          |  | const npmArgs = ["run"]; | 
        
          |  | if (obj.scripts && obj.scripts.start) { | 
        
          |  | npmArgs.push('start'); | 
        
          |  | } else if (obj.scripts && obj.scripts.serve) { | 
        
          |  | npmArgs.push('serve'); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | if (npmArgs.length > 1) { | 
        
          |  | startNPMScript(npmArgs); | 
        
          |  | } else { | 
        
          |  | startLocalWebServer(); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | } else { | 
        
          |  | startLocalWebServer(); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * Returns a UTC-3 datetime string in the format "yyyy-mm-dd hh/mm/ss" | 
        
          |  | * @param {Date} date | 
        
          |  | */ | 
        
          |  | function getBrazilianDateTimeString(date = new Date()) { | 
        
          |  | date.setTime(date.getTime() - 3 * 60 * 60 * 1000); | 
        
          |  | return date.toISOString().replace("T", " ").split(".")[0]; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | function getLogPrefix() { | 
        
          |  | return "[" + getBrazilianDateTimeString() + "]"; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | function startLocalWebServer() { | 
        
          |  | const server = http.createServer(onRequestStart); | 
        
          |  |  | 
        
          |  | server.listen(8080, onStartListening); | 
        
          |  |  | 
        
          |  | function onStartListening() { | 
        
          |  | const htmlFiles = fs.readdirSync(folder).filter(file => file.endsWith(".html")); | 
        
          |  | let startScript = "start http://localhost:8080/"; | 
        
          |  | if (htmlFiles.length > 0 && !htmlFiles.includes("index.html")) { | 
        
          |  | startScript = "start http://localhost:8080/"+htmlFiles[0]; | 
        
          |  | } | 
        
          |  | cp.execSync(startScript); | 
        
          |  | console.log(getLogPrefix(), "Started web server at http://localhost:8080/"); | 
        
          |  | } | 
        
          |  |  | 
        
          |  |  | 
        
          |  | function getMimeTypeFromExtension(extension = "txt") { | 
        
          |  | if (extension[0] === ".") { | 
        
          |  | extension = extension.substr(1); | 
        
          |  | } | 
        
          |  | return { | 
        
          |  | "aac": "audio/aac", | 
        
          |  | "abw": "application/x-abiword", | 
        
          |  | "arc": "application/x-freearc", | 
        
          |  | "avi": "video/x-msvideo", | 
        
          |  | "azw": "application/vnd.amazon.ebook", | 
        
          |  | "bin": "application/octet-stream", | 
        
          |  | "bmp": "image/bmp", | 
        
          |  | "bz": "application/x-bzip", | 
        
          |  | "bz2": "application/x-bzip2", | 
        
          |  | "cda": "application/x-cdf", | 
        
          |  | "csh": "application/x-csh", | 
        
          |  | "css": "text/css", | 
        
          |  | "csv": "text/csv", | 
        
          |  | "doc": "application/msword", | 
        
          |  | "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", | 
        
          |  | "eot": "application/vnd.ms-fontobject", | 
        
          |  | "epub": "application/epub+zip", | 
        
          |  | "gz": "application/gzip", | 
        
          |  | "gif": "image/gif", | 
        
          |  | "htm": "text/html", | 
        
          |  | "html": "text/html", | 
        
          |  | "ico": "image/vnd.microsoft.icon", | 
        
          |  | "ics": "text/calendar", | 
        
          |  | "jar": "application/java-archive", | 
        
          |  | "jpeg": "image/jpeg", | 
        
          |  | "jpg": "image/jpeg", | 
        
          |  | "js": "text/javascript", | 
        
          |  | "json": "application/json", | 
        
          |  | "jsonld": "application/ld+json", | 
        
          |  | "mid": "audio/midi audio/x-midi", | 
        
          |  | "midi": "audio/midi audio/x-midi", | 
        
          |  | "mjs": "text/javascript", | 
        
          |  | "mp3": "audio/mpeg", | 
        
          |  | "mp4": "video/mp4", | 
        
          |  | "mpeg": "video/mpeg", | 
        
          |  | "mpkg": "application/vnd.apple.installer+xml", | 
        
          |  | "odp": "application/vnd.oasis.opendocument.presentation", | 
        
          |  | "ods": "application/vnd.oasis.opendocument.spreadsheet", | 
        
          |  | "odt": "application/vnd.oasis.opendocument.text", | 
        
          |  | "oga": "audio/ogg", | 
        
          |  | "ogv": "video/ogg", | 
        
          |  | "ogx": "application/ogg", | 
        
          |  | "opus": "audio/opus", | 
        
          |  | "otf": "font/otf", | 
        
          |  | "png": "image/png", | 
        
          |  | "pdf": "application/pdf", | 
        
          |  | "php": "application/x-httpd-php", | 
        
          |  | "ppt": "application/vnd.ms-powerpoint", | 
        
          |  | "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", | 
        
          |  | "rar": "application/vnd.rar", | 
        
          |  | "rtf": "application/rtf", | 
        
          |  | "sh": "application/x-sh", | 
        
          |  | "svg": "image/svg+xml", | 
        
          |  | "swf": "application/x-shockwave-flash", | 
        
          |  | "tar": "application/x-tar", | 
        
          |  | "tif": "image/tiff", | 
        
          |  | "tiff": "image/tiff", | 
        
          |  | "ts": "video/mp2t", | 
        
          |  | "ttf": "font/ttf", | 
        
          |  | "txt": "text/plain", | 
        
          |  | "vsd": "application/vnd.visio", | 
        
          |  | "wav": "audio/wav", | 
        
          |  | "weba": "audio/webm", | 
        
          |  | "webm": "video/webm", | 
        
          |  | "webp": "image/webp", | 
        
          |  | "woff": "font/woff", | 
        
          |  | "woff2": "font/woff2", | 
        
          |  | "xhtml": "application/xhtml+xml", | 
        
          |  | "xls": "application/vnd.ms-excel", | 
        
          |  | "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | 
        
          |  | "xml": "application/xml", | 
        
          |  | "xul": "application/vnd.mozilla.xul+xml", | 
        
          |  | "zip": "application/zip", | 
        
          |  | "3gp": "video/3gpp", | 
        
          |  | "3g2": "video/3gpp2", | 
        
          |  | "7z": "application/x-7z-compressed" | 
        
          |  | }[extension] || "application/octet-stream"; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * @param {http.IncomingMessage} req | 
        
          |  | * @param {http.ServerResponse} res | 
        
          |  | */ | 
        
          |  | function onRequestStart(req, res) { | 
        
          |  | console.log(getLogPrefix(), req.method + " request from", req.socket.address(), "for", req.url); | 
        
          |  | if (req.method !== "GET") { | 
        
          |  | res.writeHead(405, "Method Not Allowed"); | 
        
          |  | return res.end(); | 
        
          |  | } | 
        
          |  | const target = path.resolve(folder + req.url); | 
        
          |  | if (!fs.existsSync(target)) { | 
        
          |  | res.writeHead(404, "Not Found"); | 
        
          |  | return res.end(); | 
        
          |  | } | 
        
          |  | res.setHeader("Content-type", getMimeTypeFromExtension(path.extname(target) || ".html")); | 
        
          |  | if (fs.statSync(target).isDirectory()) { | 
        
          |  | if (fs.existsSync(target + "/index.html")) { | 
        
          |  | res.write(fs.readFileSync(target + "/index.html"), (err) => { | 
        
          |  | if (err) { | 
        
          |  | console.log(err); | 
        
          |  | } | 
        
          |  | res.end(); | 
        
          |  | }); | 
        
          |  | return; | 
        
          |  | } else { | 
        
          |  | res.writeHead(404, "Not Found"); | 
        
          |  | return res.end(); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | res.write(fs.readFileSync(target), (err) => { | 
        
          |  | if (err) { | 
        
          |  | console.log(err); | 
        
          |  | } | 
        
          |  | res.end(); | 
        
          |  | }); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | function startNPMScript(npmArgs) { | 
        
          |  | const npmPath = "C:\\Program Files\\nodejs\\npm"; | 
        
          |  | if (!fs.existsSync(npmPath)) { | 
        
          |  | console.log("Could not find npm at " + npmPath); | 
        
          |  | return process.exit(1); | 
        
          |  | } | 
        
          |  | const child = cp.spawn( | 
        
          |  | "\"" + npmPath + "\"", | 
        
          |  | npmArgs, | 
        
          |  | { stdio: "inherit", cwd: folder, env: undefined, shell: true } | 
        
          |  | ); | 
        
          |  | child.on("error", function(err) { | 
        
          |  | console.log(err); | 
        
          |  | process.exit(1); | 
        
          |  | }); | 
        
          |  | child.on("close", function(code) { | 
        
          |  | process.exit(code); | 
        
          |  | }); | 
        
          |  | } |