wuWxss.js 8.1 KB
Newer Older
C
Cherrison 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
const wu=require("./wuLib.js");
const path=require("path");
const fs=require("fs");
const {VM}=require('vm2');
const cssbeautify=require('cssbeautify');
const csstree=require('css-tree');
function doWxss(dir,cb){
	function GwxCfg(){}
	GwxCfg.prototype={$gwx(){}};
	for(let i=0;i<300;i++)GwxCfg.prototype["$gwx"+i]=GwxCfg.prototype.$gwx;
	let runList={},pureData={},result={},actualPure={},importCnt={},frameName="",onlyTest=true,blockCss=[];//custom block css file which won't be imported by others.(no extension name)
	function cssRebuild(data){//need to bind this as {cssFile:__name__} before call
		let cssFile;
		function statistic(data){
			function addStat(id){
				if(!importCnt[id])importCnt[id]=1,statistic(pureData[id]);
				else ++importCnt[id];
			}
			if(typeof data==="number")return addStat(data);
			for(let content of data)if(typeof content==="object"&&content[0]==2)addStat(content[1]);
		}
		function makeup(data){
			var isPure=typeof data==="number";
			if(onlyTest){
				statistic(data);
				if(!isPure){
					if(data.length==1&&data[0][0]==2)data=data[0][1];
					else return "";
				}
				if(!actualPure[data]&&!blockCss.includes(wu.changeExt(wu.toDir(cssFile,frameName),""))){
					console.log("Regard "+cssFile+" as pure import file.");
					actualPure[data]=cssFile;
				}
				return "";
			}
			let res=[],attach="";
			if(isPure&&actualPure[data]!=cssFile){
				if(actualPure[data])return '@import "'+wu.changeExt(wu.toDir(actualPure[data],cssFile),".wxss")+'";\n';
				else{
					res.push("/*! Import by _C["+data+"], whose real path we cannot found. */");
					attach="/*! Import end */";
				}
			}
			let exactData=isPure?pureData[data]:data;
			for(let content of exactData)
				if(typeof content==="object"){
					switch(content[0]){
					case 0://rpx
						res.push(content[1]+"rpx");
						break;
					case 1://add suffix, ignore it for restoring correct!
						break;
					case 2://import
						res.push(makeup(content[1]));
						break;
					}
				}else res.push(content);
			return res.join("")+attach;
		}
		return ()=>{
			cssFile=this.cssFile;
			if(!result[cssFile])result[cssFile]="";
			result[cssFile]+=makeup(data);
		};
	}
A
aistri 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

function runVM(name, code) {
      // let wxAppCode = {}, handle = {cssFile: name};
      // let vm = new VM({
      //    sandbox: Object.assign(new GwxCfg(), {
      //       __wxAppCode__: wxAppCode,
      //       setCssToHead: cssRebuild.bind(handle)
      //    })
      // });
      // vm.run(code);
      // for (let name in wxAppCode) if (name.endsWith(".wxss")) {
      //    handle.cssFile = path.resolve(frameName, "..", name);
      //    wxAppCode[name]();
      // }
 
      let wxAppCode = {};
      let handle = {cssFile: name};
      let gg = new GwxCfg();
      let tsandbox = {
         $gwx: GwxCfg.prototype["$gwx"],
         __mainPageFrameReady__: GwxCfg.prototype["$gwx"],   //解决 $gwx is not defined
         __vd_version_info__: GwxCfg.prototype["$gwx"],  //解决 __vd_version_info__ is not defined
         __wxAppCode__: wxAppCode,
         setCssToHead: cssRebuild.bind(handle)
      }
 
      let vm = new VM({sandbox: tsandbox});
      vm.run(code);
      for (let name in wxAppCode) {
         if (name.endsWith(".wxss")) {
            handle.cssFile = path.resolve(frameName, "..", name);
            wxAppCode[name]();
         }
      }
   }
C
Cherrison 已提交
101 102 103 104 105 106 107 108 109 110
	function preRun(dir,frameFile,mainCode,files,cb){
		wu.addIO(cb);
		runList[path.resolve(dir,"./app.wxss")]=mainCode;
		for(let name of files)if(name!=frameFile){
			wu.get(name,code=>{
				code=code.slice(0,code.indexOf("\n"));
				if(code.indexOf("setCssToHead")>-1)runList[name]=code.slice(code.indexOf("setCssToHead"));
			});
		}
	}
A
aistri 已提交
111 112 113 114 115
 function runOnce() {
		for (let name in runList) {
			// console.log(name, runList[name]);
			runVM(name, runList[name]);
		}
C
Cherrison 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
	}
	function transformCss(style){
		let ast=csstree.parse(style);
		csstree.walk(ast,function(node){
			if(node.type=="Comment"){//Change the comment because the limit of css-tree
				node.type="Raw";
				node.value="\n/*"+node.value+"*/\n";
			}
			if(node.type=="TypeSelector"){
				if(node.name.startsWith("wx-"))node.name=node.name.slice(3);
				else if(node.name=="body")node.name="page";
			}
			if(node.children){
				const removeType=["webkit","moz","ms","o"];
				let list={};
				node.children.each((son,item)=>{
					if(son.type=="Declaration"){
						if(list[son.property]){
							let a=item,b=list[son.property],x=son,y=b.data,ans=null;
							if(x.value.type=='Raw'&&x.value.value.startsWith("progid:DXImageTransform")){
								node.children.remove(a);
								ans=b;
							}else if(y.value.type=='Raw'&&y.value.value.startsWith("progid:DXImageTransform")){
								node.children.remove(b);
								ans=a;
							}else{
								let xValue=x.value.children&&x.value.children.head&&x.value.children.head.data.name,yValue=y.value.children&&y.value.children.head&&y.value.children.head.data.name;
								if(xValue&&yValue)for(let type of removeType)if(xValue==`-${type}-${yValue}`){
									node.children.remove(a);
									ans=b;
									break;
								}else if(yValue==`-${type}-${xValue}`){
									node.children.remove(b);
									ans=a;
									break;
								}else{
									let mValue=`-${type}-`;
									if(xValue.startsWith(mValue))xValue=xValue.slice(mValue.length);
									if(yValue.startsWith(mValue))yValue=yValue.slice(mValue.length);
								}
								if(ans===null)ans=b;
							}
							list[son.property]=ans;
						}else list[son.property]=item;
					}
				});
				for(let name in list)if(!name.startsWith('-'))
					for(let type of removeType){
						let fullName=`-${type}-${name}`;
						if(list[fullName]){
							node.children.remove(list[fullName]);
							delete list[fullName];
						}
					}
			}
		});
		return cssbeautify(csstree.generate(ast),{indent:'    ',autosemicolon:true});
	}
	wu.scanDirByExt(dir,".html",files=>{
		let frameFile="";
		if(fs.existsSync(path.resolve(dir,"page-frame.html")))
			frameFile=path.resolve(dir,"page-frame.html");
		else if(fs.existsSync(path.resolve(dir,"app-wxss.js")))
			frameFile=path.resolve(dir,"app-wxss.js");
		else if(fs.existsSync(path.resolve(dir,"page-frame.js")))
			frameFile=path.resolve(dir,"page-frame.js");
		else throw Error("page-frame-like file is not found in the package by auto.");
		wu.get(frameFile,code=>{
			code=code.slice(code.indexOf('var setCssToHead = function(file, _xcInvalid'));
			code=code.slice(code.indexOf('\nvar _C= ')+1);
			let oriCode=code;
			code=code.slice(0,code.indexOf('\n'));
			let vm=new VM({sandbox:{}});
			pureData=vm.run(code+"\n_C");
			let mainCode=oriCode.slice(oriCode.indexOf("setCssToHead"),oriCode.lastIndexOf(";var __pageFrameEndTime__"));
			console.log("Guess wxss(first turn)...");
			preRun(dir,frameFile,mainCode,files,()=>{
				frameName=frameFile;
				onlyTest=true;
				runOnce();
				onlyTest=false;
				console.log("Import count info: %j",importCnt);
				for(let id in pureData)if(!actualPure[id]){
					if(!importCnt[id])importCnt[id]=0;
					if(importCnt[id]<=1){
						console.log("Cannot find pure import for _C["+id+"] which is only imported "+importCnt[id]+" times. Let importing become copying.");
					}else{
						let newFile=path.resolve(dir,"__wuBaseWxss__/"+id+".wxss");
						console.log("Cannot find pure import for _C["+id+"], force to save it in ("+newFile+").");
						id=Number.parseInt(id);
						actualPure[id]=newFile;
						cssRebuild.call({cssFile:newFile},id)();
					}
				}
				console.log("Guess wxss(first turn) done.\nGenerate wxss(second turn)...");
				runOnce()
				console.log("Generate wxss(second turn) done.\nSave wxss...");
				for(let name in result)wu.save(wu.changeExt(name,".wxss"),transformCss(result[name]));
				let delFiles={};
				for(let name of files)delFiles[name]=8;
				delFiles[frameFile]=4;
				cb(delFiles);
			});
		});
	});
}
module.exports={doWxss:doWxss};
if(require.main===module){
    wu.commandExecute(doWxss,"Restore wxss files.\n\n<dirs...>\n\n<dirs...> restore wxss file from a unpacked directory(Have page-frame.html (or app-wxss.js) and other html file).");
}