const fs=require("fs"); const path=require("path"); class CntEvent{ constructor(){ this.cnt=0; this.emptyEvent=[]; this.encount=this.encount.bind(this); this.decount=this.decount.bind(this); this.add=this.add.bind(this); } encount(delta=1){ this.cnt+=delta; } decount(){ if(this.cnt>0)--this.cnt; if(this.cnt==0){ for(let info of this.emptyEvent)info[0](...info[1]); this.emptyEvent=[]; } } add(cb,...attach){ this.emptyEvent.push([cb,attach]); } check(cb,...attach){ if(this.cnt==0)cb(...attach); else this.add(cb,...attach); } } class LimitedRunner{ constructor(limit){ this.limit=limit; this.cnt=0; this.funcs=[]; } run(func){ if(this.cnt0)this.cnt--; if(this.funcs.length>0){ this.cnt++; setTimeout(this.funcs.shift(),0); } } runWithCb(func,...args){ let cb=args.pop(),self=this; function agent(...args){ self.done(); return cb.apply(this,args); } args.push(agent); this.run(()=>func(...args)); } } let ioEvent=new CntEvent; let ioLimit=new LimitedRunner(4096); function mkdirs(dir,cb){ ioLimit.runWithCb(fs.stat.bind(fs),dir,(err,stats)=>{ if(err)mkdirs(path.dirname(dir),()=>fs.mkdir(dir,cb)); else if(stats.isFile())throw Error(dir+" was created as a file, so we cannot put file into it."); else cb(); }); } function save(name,content){ ioEvent.encount(); mkdirs(path.dirname(name),()=>ioLimit.runWithCb(fs.writeFile.bind(fs),name,content,err=>{ if(err)throw Error("Save file error: "+err); ioEvent.decount(); })); } function get(name,cb,opt={encoding:'utf8'}){ ioEvent.encount(); ioLimit.runWithCb(fs.readFile.bind(fs),name,opt,(err,data)=>{ if(err)throw Error("Read file error: "+err); else cb(data); ioEvent.decount(); }); } function del(name){ ioEvent.encount(); ioLimit.runWithCb(fs.unlink.bind(fs),name,ioEvent.decount); } function changeExt(name,ext=""){ return name.slice(0,name.lastIndexOf("."))+ext; } function scanDirByExt(dir,ext,cb){ let result=[],scanEvent=new CntEvent; function helper(dir){ scanEvent.encount(); ioLimit.runWithCb(fs.readdir.bind(fs),dir,(err,files)=>{ if(err)throw Error("Scan dir error: "+err); for(let file of files){ scanEvent.encount(); let name=path.resolve(dir,file); fs.stat(name,(err,stats)=>{ if(err)throw Error("Scan dir error: "+err); if(stats.isDirectory())helper(name); else if(stats.isFile()&&name.endsWith(ext))result.push(name); scanEvent.decount(); }); } scanEvent.decount(); }); } scanEvent.add(cb,result); helper(dir,ext,scanEvent); } function toDir(to,from){//get relative path without posix/win32 problem if(from[0]==".")from=from.slice(1); if(to[0]==".")to=to.slice(1); from=from.replace(/\\/g,'/');to=to.replace(/\\/g,'/'); let a=Math.min(to.length,from.length); for(let i=1,m=Math.min(to.length,from.length);i<=m;i++)if(!to.startsWith(from.slice(0,i))){a=i-1;break;} let pub=from.slice(0,a); let len=pub.lastIndexOf("/")+1; let k=from.slice(len); let ret=""; for(let i=0;iconsole.timeEnd("Total use")); } let orders=[]; for(let order of process.argv)if(order.startsWith("-"))orders.push(order.slice(1)); let iter=process.argv[Symbol.iterator](),nxt=iter.next(),called=false,faster=orders.includes("f"),fastCnt; if(faster){ fastCnt=new CntEvent; fastCnt.add(endTime); } function doNext(){ let nxt=iter.next(); while(!nxt.done&&nxt.value.startsWith("-"))nxt=iter.next(); if(nxt.done){ if(!called)console.log("Command Line Helper:\n\n"+helper); else if(!faster)endTime(); }else{ called=true; if(faster)fastCnt.encount(),cb(nxt.value,fastCnt.decount,orders),doNext(); else cb(nxt.value,doNext,orders); } } while(!nxt.done&&!nxt.value.endsWith(".js"))nxt=iter.next(); doNext(); } module.exports={mkdirs:mkdirs,get:get,save:save,toDir:toDir,del:del,addIO:ioEvent.add, changeExt:changeExt,CntEvent:CntEvent,scanDirByExt:scanDirByExt,commonDir:commonDir, commandExecute:commandExecute};