From 00045bf81bdad4849c342619a59d2be047c49cf6 Mon Sep 17 00:00:00 2001 From: system-cpu <2315673456@qq.com> Date: Wed, 10 Jun 2020 11:46:00 +0800 Subject: [PATCH] no message --- ISSUE_TEMPLATE.md | 25 -- README.md | 62 ++-- bingo.bat | 48 +++ bingo.sh | 41 +++ package.json | 20 +- wuConfig.js | 269 ++++++++++------ wuJs.js | 91 +++--- wuLib.js | 347 +++++++++++--------- wuRestoreZ.js | 439 +++++++++++++------------ wuWxapkg.js | 304 +++++++++++------- wuWxml.js | 802 ++++++++++++++++++++++++---------------------- wuWxss.js | 404 +++++++++++++---------- 12 files changed, 1635 insertions(+), 1217 deletions(-) create mode 100644 bingo.bat create mode 100644 bingo.sh diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index cebaa5c..e69de29 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,25 +0,0 @@ -发表 Issue 前请仔细阅读以下内容: - -1. 如果你是要反馈 bug, 请按以下`模板`书写 Issue; -2. 如果你遇到的是 Node.js 使用问题, 请尽可能依赖搜索引擎解决问题; -3. 遇到包依赖问题,请联系对应项目; -4. 任何对某类小程序包的适配问题都应提供 wxapkg 程序包,否则直接 Close 处理; -5. 提交前请确认 wxapkg 程序包版本不小于 v0.6vv_20180111_fbi (直接用文本编辑器打开 wxapkg包搜索 v0.6vv 或 v0.5vv 即可查到,注意版本大小主要比较的是日期), 旧版本不提供支持, 相关 Issue 直接 Close 处理; -6. 直接分包和直接处理含插件的包两个功能暂不支持, 请勿重复发表 Issue, 新样例可在已存在的 Issue 下提出; -7. 请不要在其他 Issue 下发表与该 Issue 无关的回复, 否则将有可能被删除。 - -模板内容如下: - -程序执行命令(可选): - -程序执行错误信息(如果反馈是抛出异常的错误,必填): - -``` -复制到这里 -``` - -程序结果错误信息(如果反馈不是抛出异常的错误, 必填, 请尽可能详细描述): - -程序包(你所要解压的程序包地址, 可为网盘链接, 也可直接上传[上传前请先打包]. 必填): - -其他附加内容: diff --git a/README.md b/README.md index a1ae6e5..37a15ae 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # wxappUnpacker ![版本 0.3](https://img.shields.io/badge/版本-0.3-red.svg) ![支持的微信版本 >20180111](https://img.shields.io/badge/%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC-%3E=20180111-brightgreen.svg) ![高级特性支持度 0](https://img.shields.io/badge/%E6%94%AF%E6%8C%81-0%25-yellow.svg) @@ -8,33 +9,16 @@ ### wxapkg 包的获取 -Android 手机最近使用过的微信小程序所对应的 wxapkg 包文件都存储在特定文件夹下,可通过以下命令查看: + Android 手机最近使用过的微信小程序所对应的 wxapkg 包文件都存储在特定文件夹下,可通过以下命令查看: adb pull /data/data/com.tencent.mm/MicroMsg/{User}/appbrand/pkg + + 其中`{User}` 为当前用户的用户名,类似于 `2bc**************b65`。 -其中`{User}` 为当前用户的用户名,类似于 `2bc**************b65`。 - -### 使用 - - node wuWxapkg.js .wxapkg 的文件路径 // 例子 D:/node/wxappUnpacker-master._1123949441_321.wxapkg - - -### 另注 - -所有命令上都可以使用`-f`指令来提高一定的并行度,但输出信息会混乱。 - -如果发现包内文件“缺失”,请先检查解包时是否出现提示`NOTICE: SubPackages exist in this package.`。如存在,请在寻找好分包后,按上文提示操作。(小程序需要访问特定页面;小游戏需要触发特定函数,然后分包才会被下载。) - -### 局限(包括但可能不限于以下内容) - -- 实现中很多功能基于特定的版本(`wcc-v0.6vv_20180111_fbi`, 且不考虑面向低版本适配)和字符串搜索,所以不能很好的适应各种特殊情况。 -- wxml 文件拥有不同于 xml 和 html 文件的字符转义规则,且尚未公开(并非"没有"),因此未能很好的还原相关内容。 -- js 文件被压缩后会丢失原始变量名等信息内容无法还原;wxss 文件压缩后的注释也会丢失。 -- wxs 文件会将所有的变量如 Math 改为 nv_Math ,这里仅通过字符串替换去除。 -- 一些被引用 wxss 文件本身的源文件丢失,因此无法恢复原始目录。 -- 有些项目开启了难以复原的`es6转es5`选项,检验本项目结果是否正确时需要关闭项目中的`es6转es5`选项。 -- wxml 中一些无法找到相对应 的正向语句的内容无法还原。 -- json 中`components`项丢失,仅会标注被其他包引用的自定义组件。 +# 安装 +``` +npm install +``` ## 依赖 @@ -53,7 +37,31 @@ Android 手机最近使用过的微信小程序所对应的 wxapkg 包文件都 此外,这些 node.js 程序之间也有一定的依赖关系,比如他们都依赖于 wuLib.js 。 +### 使用 + + node wuWxapkg.js .wxapkg 的文件路径 // 例子 D:/node/wxappUnpacker-master._1123949441_321.wxapkg -## 技术支持 - Star 一下可以加微信 - 微信: li1664771111 //备注:反编译 +# 分包功能 + +当检测到 wxapkg 为子包时, 添加-s 参数指定主包源码路径即可自动将子包的 wxss,wxml,js 解析到主包的对应位置下. 完整流程大致如下: +1. 获取主包和若干子包 +2. 解包主包 `./bingo.sh testpkg/master-xxx.wxapkg` +3. 解包子包 `./bingo.sh testpkg/sub-1-xxx.wxapkg -s=../master-xxx` + +TIP +> -s 参数可为相对路径或绝对路径, 推荐使用绝对路径, 因为相对路径的起点不是当前目录 而是子包解包后的目录 + +``` +├── testpkg +│   ├── sub-1-xxx.wxapkg #被解析子包 +│   └── sub-1-xxx #相对路径的起点 +│   ├── app-service.js +│   ├── master-xxx.wxapkg +│   └── master-xxx # ../master-xxx 就是这个目录 +│   ├── app.json +``` + +# 支持 + ``` + Star 一个吧 +``` \ No newline at end of file diff --git a/bingo.bat b/bingo.bat new file mode 100644 index 0000000..b7f07df --- /dev/null +++ b/bingo.bat @@ -0,0 +1,48 @@ +# WXAPPUNPACKER_PATH 项目路径 +set WXAPPUNPACKER_PATH=%~dp0 + +set FILE_FORMAT=wxapkg + +:wxappUnpacker_pkg + +echo "node %WXAPPUNPACKER_PATH%/wuWxapkg.js %fname%" + +node %WXAPPUNPACKER_PATH%/wuWxapkg.js %2 %1 + +goto:eof + +:wxappUnpacker + +set de_dir=%1 + + if "%de_dir%" == "" + + set de_dir=%WXAPPUNPACKER_PATH% + +echo %de_dir% + +echo "for wxapkg in `find %de_dir% "*.${FILE_FORMAT}"`" + +for %%fname in `/f %de_dir% -name "*.%FILE_FORMAT%"` + + do + + (call :wxappUnpacker_pkg %fname% %2) + +goto:eof + +:de_pkg + + if "-d" == "%1" + + (call :wxappUnpacker %1 %2) + + else + + (call :wxappUnpacker_pkg %1 %2) + +goto:eof + +# $1: pkg file or pkg dir; $2: order + +call :de_pkg %1 %2 \ No newline at end of file diff --git a/bingo.sh b/bingo.sh new file mode 100644 index 0000000..110f7a3 --- /dev/null +++ b/bingo.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# MyWxappUnpacker 项目路径 +WXAPPUNPACKER_PATH=`pwd` + +FILE_FORMAT=wxapkg + +wxappUnpacker_pkg() { + echo "node ${WXAPPUNPACKER_PATH}/wuWxapkg.js ${fname}" + node ${WXAPPUNPACKER_PATH}/wuWxapkg.js $2 $1 + return 0; +} + +wxappUnpacker() { + de_dir=$1 + if [ -z "$1" ] + then + de_dir=`pwd` + fi + echo "${de_dir}" + echo "for wxapkg in `find ${de_dir} -name "*.${FILE_FORMAT}"`" + for fname in `find ${de_dir} -name "*.${FILE_FORMAT}"` + do + wxappUnpacker_pkg ${fname} $2 + done + return 0; +} + +de_pkg() { + if [ "-d" == "$1" ] + then + wxappUnpacker $1 $2 + else + wxappUnpacker_pkg $1 $2 + fi + return 0; +} +# $1: pkg file or pkg dir; $2: order +de_pkg $1 $2 + + diff --git a/package.json b/package.json index 33db075..ead8ce4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wxapp-unpacker", - "version": "0.3", + "version": "1.0.1", "description": "Wechat App(微信小程序, .wxapkg)解包及相关文件(.wxss, .json, .wxs, .wxml)还原工具", "main": "wuWxapkg.js", "repository": { @@ -12,14 +12,22 @@ "bugs": { "url": "https://github.com/qwerty472123/wxappUnpacker/issues" }, + "scripts": { + "pkg": "node wuWxapkg.js", + "css": "node wuWxss.js", + "xml": "node wuWxml.js", + "js": "node wuJs.js", + "cfg": "node wuConfig.js" + }, "homepage": "https://github.com/qwerty472123/wxappUnpacker#readme", "dependencies": { - "css-tree": "^1.0.0-alpha.37", + "cheerio": "^1.0.0-rc.3", + "css-tree": "^1.0.0-alpha.28", "cssbeautify": "^0.3.1", - "escodegen": "^1.12.0", - "esprima": "^4.0.1", - "js-beautify": "^1.10.2", + "escodegen": "^1.11.0", + "esprima": "^4.0.0", + "js-beautify": "^1.7.5", "uglify-es": "^3.3.9", - "vm2": "^3.8.4" + "vm2": "^3.6.0" } } diff --git a/wuConfig.js b/wuConfig.js index f8ea27c..80125f6 100644 --- a/wuConfig.js +++ b/wuConfig.js @@ -1,106 +1,169 @@ -const wu=require("./wuLib.js"); -const fs=require("fs"); -const path=require("path"); -const crypto=require("crypto"); -const {VM}=require('vm2'); -function getWorkerPath(name){ - let code=fs.readFileSync(name,{encoding:'utf8'}); - let commPath=false; - let vm=new VM({sandbox:{ - require(){}, - define(name){ - name=path.dirname(name)+'/'; - if(commPath===false)commPath=name; - commPath=wu.commonDir(commPath,name); - } - }}); - vm.run(code.slice(code.indexOf("define("))); - if(commPath.length>0)commPath=commPath.slice(0,-1); - console.log("Worker path: \""+commPath+"\""); - return commPath; +const wu = require("./wuLib.js"); +const fs = require("fs"); +const path = require("path"); +const crypto = require("crypto"); +const {VM} = require('vm2'); + +function getWorkerPath(name) { + let code = fs.readFileSync(name, {encoding: 'utf8'}); + let commPath = false; + let vm = new VM({ + sandbox: { + require() { + }, + define(name) { + name = path.dirname(name) + '/'; + if (commPath === false) commPath = name; + commPath = wu.commonDir(commPath, name); + } + } + }); + vm.run(code.slice(code.indexOf("define("))); + if (commPath.length > 0) commPath = commPath.slice(0, -1); + console.log("Worker path: \"" + commPath + "\""); + return commPath; } -function doConfig(configFile,cb){ - let dir=path.dirname(configFile); - wu.get(configFile,content=>{ - let e=JSON.parse(content); - let k=e.pages; - k.splice(k.indexOf(wu.changeExt(e.entryPagePath)),1); - k.unshift(wu.changeExt(e.entryPagePath)); - let app={pages:k,window:e.global&&e.global.window,tabBar:e.tabBar,networkTimeout:e.networkTimeout}; - if(e.subPackages){ - app.subPackages=e.subPackages; - console.log("=======================================================\nNOTICE: SubPackages exist in this package.\nDetails: ",app.subPackages,"\n======================================================="); - } - if(e.navigateToMiniProgramAppIdList)app.navigateToMiniProgramAppIdList=e.navigateToMiniProgramAppIdList; - if(fs.existsSync(path.resolve(dir,"workers.js")))app.workers=getWorkerPath(path.resolve(dir,"workers.js")); - if(e.extAppid) - wu.save(path.resolve(dir,'ext.json'),JSON.stringify({extEnable:true,extAppid:e.extAppid,ext:e.ext},null,4)); - if(typeof e.debug!="undefined")app.debug=e.debug; - let cur=path.resolve("./file"); - for(let a in e.page)if(e.page[a].window.usingComponents) - for(let name in e.page[a].window.usingComponents){ - let componentPath=e.page[a].window.usingComponents[name]+".html"; - let file=componentPath.startsWith('/')?componentPath.slice(1):wu.toDir(path.resolve(path.dirname(a),componentPath),cur); - if(!e.page[file])e.page[file]={}; - if(!e.page[file].window)e.page[file].window={}; - e.page[file].window.component=true; - } - if(fs.existsSync(path.resolve(dir,"app-service.js"))){ - let matches=fs.readFileSync(path.resolve(dir,"app-service.js"),{encoding:'utf8'}).match(/\_\_wxAppCode\_\_\['[^\.]+\.json[^;]+\;/g); - if(matches){ - let attachInfo={}; - (new VM({sandbox:{ - __wxAppCode__:attachInfo - }})).run(matches.join("")); - for(let name in attachInfo)e.page[wu.changeExt(name,".html")]={window:attachInfo[name]}; - } - } - let delWeight=8; - for(let a in e.page){ - let fileName=path.resolve(dir,wu.changeExt(a,".json")); - wu.save(fileName,JSON.stringify(e.page[a].window,null,4)); - if(configFile==fileName)delWeight=0; - } - if(app.tabBar&&app.tabBar.list) wu.scanDirByExt(dir,"",li=>{//search all files - let digests=[],digestsEvent=new wu.CntEvent,rdir=path.resolve(dir); - function fixDir(dir){return dir.startsWith(rdir)?dir.slice(rdir.length+1):dir;} - digestsEvent.add(()=>{ - for(let e of app.tabBar.list){ - e.pagePath=wu.changeExt(e.pagePath); - if(e.iconData){ - let hash=crypto.createHash("MD5").update(e.iconData,'base64').digest(); - for(let [buf,name] of digests)if(hash.equals(buf)){ - delete e.iconData; - e.iconPath=fixDir(name).replace(/\\/g,'/'); - break; - } - } - if(e.selectedIconData){ - let hash=crypto.createHash("MD5").update(e.selectedIconData,'base64').digest(); - for(let [buf,name] of digests)if(hash.equals(buf)){ - delete e.selectedIconData; - e.selectedIconPath=fixDir(name).replace(/\\/g,'/'); - break; - } - } - } - wu.save(path.resolve(dir,'app.json'),JSON.stringify(app,null,4)); - cb({[configFile]:delWeight}); - }); - for(let name of li){ - digestsEvent.encount(); - wu.get(name,data=>{ - digests.push([crypto.createHash("MD5").update(data).digest(),name]); - digestsEvent.decount(); - },{}); - } - });else{ - wu.save(path.resolve(dir,'app.json'),JSON.stringify(app,null,4)); - cb({[configFile]:delWeight}); - } - }); + +function doConfig(configFile, cb) { + let dir = path.dirname(configFile); + wu.get(configFile, content => { + let e = JSON.parse(content); + let k = e.pages; + k.splice(k.indexOf(wu.changeExt(e.entryPagePath)), 1); + k.unshift(wu.changeExt(e.entryPagePath)); + let app = {pages: k, window: e.global && e.global.window, tabBar: e.tabBar, networkTimeout: e.networkTimeout}; + if (e.subPackages) { + let subPackages = []; + let pages = app.pages; + for (let subPackage of e.subPackages) { + let root = subPackage.root; + let lastChar = root.substr(root.length - 1, 1); + if (lastChar !== '/') { + root = root + '/'; + } + let firstChar = root.substr(0, 1); + if (firstChar === '/') { + root = root.substring(1); + } + let newPages = []; + for (let page of subPackage.pages) { + let items = page.replace(root, ''); + newPages.push(items); + let subIndex = pages.indexOf(root + items); + if (subIndex !== -1) { + pages.splice(subIndex, 1); + } + } + subPackage.root = root; + subPackage.pages = newPages; + subPackages.push(subPackage); + } + app.subPackages = subPackages; + app.pages = pages; + console.log("=======================================================\n这个小程序采用了分包\n子包个数为: ", app.subPackages.length, "\n======================================================="); + } + if (e.navigateToMiniProgramAppIdList) app.navigateToMiniProgramAppIdList = e.navigateToMiniProgramAppIdList; + if (fs.existsSync(path.resolve(dir, "workers.js"))) app.workers = getWorkerPath(path.resolve(dir, "workers.js")); + if (e.extAppid) + wu.save(path.resolve(dir, 'ext.json'), JSON.stringify({ + extEnable: true, + extAppid: e.extAppid, + ext: e.ext + }, null, 4)); + if (typeof e.debug != "undefined") app.debug = e.debug; + let cur = path.resolve("./file"); + for (let a in e.page) if (e.page[a].window.usingComponents) + for (let name in e.page[a].window.usingComponents) { + let componentPath = e.page[a].window.usingComponents[name] + ".html"; + let file = componentPath.startsWith('/') ? componentPath.slice(1) : wu.toDir(path.resolve(path.dirname(a), componentPath), cur); + if (!e.page[file]) e.page[file] = {}; + if (!e.page[file].window) e.page[file].window = {}; + e.page[file].window.component = true; + } + if (fs.existsSync(path.resolve(dir, "app-service.js"))) { + let matches = fs.readFileSync(path.resolve(dir, "app-service.js"), {encoding: 'utf8'}).match(/\_\_wxAppCode\_\_\['[^\.]+\.json[^;]+\;/g); + if (matches) { + let attachInfo = {}; + (new VM({ + sandbox: { + __wxAppCode__: attachInfo + } + })).run(matches.join("")); + for (let name in attachInfo) e.page[wu.changeExt(name, ".html")] = {window: attachInfo[name]}; + } + } + let delWeight = 8; + for (let a in e.page) { + let fileName = path.resolve(dir, wu.changeExt(a, ".json")); + wu.save(fileName, JSON.stringify(e.page[a].window, null, 4)); + if (configFile == fileName) delWeight = 0; + } + if (app.subPackages) { + for (let subPackage of app.subPackages) { + if (subPackage.pages) { + for (let item of subPackage.pages) { + let a = subPackage.root + item + '.xx'; + //添加默认的 wxs, wxml, wxss + let jsName = wu.changeExt(a, ".js"); + let fileNameOfWxs = path.resolve(dir, jsName); + wu.save(fileNameOfWxs, "// " + jsName + "\nPage({data: {}})"); + let wxmlName = wu.changeExt(a, ".wxml"); + let fileNameOfWxml = path.resolve(dir, wxmlName); + wu.save(fileNameOfWxml, "" + wxmlName + ""); + let cssName = wu.changeExt(a, ".wxss"); + let fileNameOfWxss = path.resolve(dir, cssName); + wu.save(fileNameOfWxss, "/* " + cssName + " */"); + } + } + } + } + + + if (app.tabBar && app.tabBar.list) wu.scanDirByExt(dir, "", li => {//search all files + let digests = [], digestsEvent = new wu.CntEvent, rdir = path.resolve(dir); + + function fixDir(dir) { + return dir.startsWith(rdir) ? dir.slice(rdir.length + 1) : dir; + } + + digestsEvent.add(() => { + for (let e of app.tabBar.list) { + e.pagePath = wu.changeExt(e.pagePath); + if (e.iconData) { + let hash = crypto.createHash("MD5").update(e.iconData, 'base64').digest(); + for (let [buf, name] of digests) if (hash.equals(buf)) { + delete e.iconData; + e.iconPath = fixDir(name).replace(/\\/g, '/'); + break; + } + } + if (e.selectedIconData) { + let hash = crypto.createHash("MD5").update(e.selectedIconData, 'base64').digest(); + for (let [buf, name] of digests) if (hash.equals(buf)) { + delete e.selectedIconData; + e.selectedIconPath = fixDir(name).replace(/\\/g, '/'); + break; + } + } + } + wu.save(path.resolve(dir, 'app.json'), JSON.stringify(app, null, 4)); + cb({[configFile]: delWeight}); + }); + for (let name of li) { + digestsEvent.encount(); + wu.get(name, data => { + digests.push([crypto.createHash("MD5").update(data).digest(), name]); + digestsEvent.decount(); + }, {}); + } + }); else { + wu.save(path.resolve(dir, 'app.json'), JSON.stringify(app, null, 4)); + cb({[configFile]: delWeight}); + } + }); } -module.exports={doConfig:doConfig}; -if(require.main===module){ - wu.commandExecute(doConfig,"Split and make up weapp app-config.json file.\n\n\n\n app-config.json files to split and make up."); + +module.exports = {doConfig: doConfig}; +if (require.main === module) { + wu.commandExecute(doConfig, "Split and make up weapp app-config.json file.\n\n\n\n app-config.json files to split and make up."); } diff --git a/wuJs.js b/wuJs.js index b9db608..bba7ad4 100644 --- a/wuJs.js +++ b/wuJs.js @@ -1,39 +1,58 @@ -const wu=require("./wuLib.js"); -const path=require("path"); -const UglifyJS=require("uglify-es"); -const {js_beautify}=require("js-beautify"); -const {VM}=require('vm2'); -function jsBeautify(code){ - return UglifyJS.minify(code,{mangle:false,compress:false,output:{beautify:true,comments:true}}).code; +const wu = require("./wuLib.js"); +const path = require("path"); +const UglifyJS = require("uglify-es"); +const {js_beautify} = require("js-beautify"); +const {VM} = require('vm2'); + +function jsBeautify(code) { + return UglifyJS.minify(code, {mangle: false, compress: false, output: {beautify: true, comments: true}}).code; } -function splitJs(name,cb){ - let dir=path.dirname(name); - wu.get(name,code=>{ - let needDelList={}; - let vm=new VM({sandbox:{ - require(){}, - define(name,func){ - let code=func.toString(); - code=code.slice(code.indexOf("{")+1,code.lastIndexOf("}")-1).trim(); - let bcode=code; - if(code.startsWith('"use strict";')||code.startsWith("'use strict';"))code=code.slice(13); - else if((code.startsWith('(function(){"use strict";')||code.startsWith("(function(){'use strict';"))&&code.endsWith("})();"))code=code.slice(25,-5); - let res=jsBeautify(code); - if(typeof res=="undefined"){ - console.log("Fail to delete 'use strict' in \""+name+"\"."); - res=jsBeautify(bcode); - } - needDelList[path.resolve(dir,name)]=-8; - wu.save(path.resolve(dir,name),jsBeautify(res)); - } - }}); - vm.run(code.slice(code.indexOf("define("))); - console.log("Splitting \""+name+"\" done."); - if(!needDelList[name])needDelList[name]=8; - cb(needDelList); - }); + +function splitJs(name, cb, mainDir) { + let isSubPkg = mainDir && mainDir.length > 0; + let dir = path.dirname(name); + if (isSubPkg) { + dir = mainDir; + } + wu.get(name, code => { + let needDelList = {}; + let vm = new VM({ + sandbox: { + require() { + }, + define(name, func) { + let code = func.toString(); + code = code.slice(code.indexOf("{") + 1, code.lastIndexOf("}") - 1).trim(); + let bcode = code; + if (code.startsWith('"use strict";') || code.startsWith("'use strict';")) code = code.slice(13); + else if ((code.startsWith('(function(){"use strict";') || code.startsWith("(function(){'use strict';")) && code.endsWith("})();")) code = code.slice(25, -5); + let res = jsBeautify(code); + if (typeof res == "undefined") { + console.log("Fail to delete 'use strict' in \"" + name + "\"."); + res = jsBeautify(bcode); + } + console.log(dir, name); + needDelList[path.resolve(dir, name)] = -8; + wu.save(path.resolve(dir, name), jsBeautify(res)); + }, + definePlugin() { + }, + requirePlugin() { + } + } + }); + if (isSubPkg) { + code = code.slice(code.indexOf("define(")); + } + console.log('splitJs: ' + name); + vm.run(code); + console.log("Splitting \"" + name + "\" done."); + if (!needDelList[name]) needDelList[name] = 8; + cb(needDelList); + }); } -module.exports={jsBeautify:jsBeautify,wxsBeautify:js_beautify,splitJs:splitJs}; -if(require.main===module){ - wu.commandExecute(splitJs,"Split and beautify weapp js file.\n\n\n\n js files to split and beautify."); + +module.exports = {jsBeautify: jsBeautify, wxsBeautify: js_beautify, splitJs: splitJs}; +if (require.main === module) { + wu.commandExecute(splitJs, "Split and beautify weapp js file.\n\n\n\n js files to split and beautify."); } diff --git a/wuLib.js b/wuLib.js index 8850d51..cbefad7 100644 --- a/wuLib.js +++ b/wuLib.js @@ -1,165 +1,204 @@ -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); - } +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)); - } + +class LimitedRunner { + constructor(limit) { + this.limit = limit; + this.cnt = 0; + this.funcs = []; + } + + run(func) { + if (this.cnt < this.limit) { + this.cnt++; + setTimeout(func, 0); + } else { + this.funcs.push(func); + } + } + + done() { + if (this.cnt > 0) 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(); - }); + +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 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 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 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 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 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(); + +function commandExecute(cb, helper) { + console.time("Total use"); + + function endTime() { + ioEvent.check(() => console.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}; + +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 +}; diff --git a/wuRestoreZ.js b/wuRestoreZ.js index 8f63690..d508d25 100644 --- a/wuRestoreZ.js +++ b/wuRestoreZ.js @@ -1,245 +1,282 @@ -const wu=require("./wuLib.js"); -const {VM}=require('vm2'); -function catchZGroup(code,groupPreStr,cb){ - const debugPre="(function(z){var a=11;function Z(ops,debugLine){"; - let zArr={}; - for(let preStr of groupPreStr){ - let content=code.slice(code.indexOf(preStr)),z=[]; - content=content.slice(content.indexOf("(function(z){var a=11;")); - content=content.slice(0,content.indexOf("})(__WXML_GLOBAL__.ops_cached.$gwx"))+"})(z);"; - let vm=new VM({sandbox:{z:z,debugInfo:[]}}); +const wu = require("./wuLib.js"); +const {VM} = require('vm2'); + +function catchZGroup(code, groupPreStr, cb) { + const debugPre = "(function(z){var a=11;function Z(ops,debugLine){"; + let zArr = {}; + for (let preStr of groupPreStr) { + let content = code.slice(code.indexOf(preStr)), z = []; + content = content.slice(content.indexOf("(function(z){var a=11;")); + content = content.slice(0, content.indexOf("})(__WXML_GLOBAL__.ops_cached.$gwx")) + "})(z);"; + let vm = new VM({sandbox: {z: z, debugInfo: []}}); vm.run(content); - if(content.startsWith(debugPre))for(let i=0;i=":11,"<=":11,">":11,"<":11,"<<":12,">>":12, - "-":len==3?13:16 - }; - return priorList[op]?priorList[op]:0; - } - function getOp(i){ - let ret=restoreNext(ops[i],true); - if(ops[i] instanceof Object&&typeof ops[i][0]=="object"&&ops[i][0][0]==2){ - //Add brackets if we need - if(getPrior(op[1],ops.length)>getPrior(ops[i][0][1],ops[i].length))ret=enBrace(ret,'(');; + } else { + let ans = ""; + switch (op[0]) {//vop + case 2://arithmetic operator + { + function getPrior(op, len) { + const priorList = { + "?:": 4, + "&&": 6, + "||": 5, + "+": 13, + "*": 14, + "/": 14, + "%": 14, + "|": 7, + "^": 8, + "&": 9, + "!": 16, + "~": 16, + "===": 10, + "==": 10, + "!=": 10, + "!==": 10, + ">=": 11, + "<=": 11, + ">": 11, + "<": 11, + "<<": 12, + ">>": 12, + "-": len == 3 ? 13 : 16 + }; + return priorList[op] ? priorList[op] : 0; + } + + function getOp(i) { + let ret = restoreNext(ops[i], true); + if (ops[i] instanceof Object && typeof ops[i][0] == "object" && ops[i][0][0] == 2) { + //Add brackets if we need + if (getPrior(op[1], ops.length) > getPrior(ops[i][0][1], ops[i].length)) ret = enBrace(ret, '('); + ; + } + return ret; + } + + switch (op[1]) { + case"?:": + ans = getOp(1) + "?" + getOp(2) + ":" + getOp(3); + break; + case "!": + case "~": + ans = op[1] + getOp(1); + break; + case"-": + if (ops.length != 3) { + ans = op[1] + getOp(1); + break; + }//shoud not add more in there![fall through] + default: + ans = getOp(1) + op[1] + getOp(2); } - return ret; - } - switch(op[1]){ - case"?:": - ans=getOp(1)+"?"+getOp(2)+":"+getOp(3); - break; - case "!": - case "~": - ans=op[1]+getOp(1); break; - case"-": - if(ops.length!=3){ - ans=op[1]+getOp(1); - break; - }//shoud not add more in there![fall through] - default: - ans=getOp(1)+op[1]+getOp(2); } - break; - } - case 4://unkown-arrayStart? - ans=restoreNext(ops[1],true); - break; - case 5://merge-array - { - switch (ops.length) { - case 2: - ans=enBrace(restoreNext(ops[1],true),'['); - break; - case 1: - ans='[]'; + case 4://unkown-arrayStart? + ans = restoreNext(ops[1], true); break; - default: + case 5://merge-array { - let a=restoreNext(ops[1],true); - //console.log(a,a.startsWith('[')&&a.endsWith(']')); - if(a.startsWith('[')&&a.endsWith(']')){ - if(a!='[]'){ - ans=enBrace(a.slice(1,-1).trim()+','+restoreNext(ops[2],true),'['); - //console.log('-',a); - }else{ - ans=enBrace(restoreNext(ops[2],true),'['); + switch (ops.length) { + case 2: + ans = enBrace(restoreNext(ops[1], true), '['); + break; + case 1: + ans = '[]'; + break; + default: { + let a = restoreNext(ops[1], true); + //console.log(a,a.startsWith('[')&&a.endsWith(']')); + if (a.startsWith('[') && a.endsWith(']')) { + if (a != '[]') { + ans = enBrace(a.slice(1, -1).trim() + ',' + restoreNext(ops[2], true), '['); + //console.log('-',a); + } else { + ans = enBrace(restoreNext(ops[2], true), '['); + } + } else { + ans = enBrace('...' + a + ',' + restoreNext(ops[2], true), '[');//may/must not support in fact + } } - }else{ - ans=enBrace('...'+a+','+restoreNext(ops[2],true),'[');//may/must not support in fact } + break; } + case 6://get value of an object + { + let sonName = restoreNext(ops[2], true); + if (sonName._type === "var") + ans = restoreNext(ops[1], true) + enBrace(sonName, '['); + else { + let attach = ""; + if (/^[A-Za-z\_][A-Za-z\d\_]*$/.test(sonName)/*is a qualified id*/) + attach = '.' + sonName; + else attach = enBrace(sonName, '['); + ans = restoreNext(ops[1], true) + attach; + } + break; } - break; - } - case 6://get value of an object - { - let sonName=restoreNext(ops[2],true); - if(sonName._type==="var") - ans=restoreNext(ops[1],true)+enBrace(sonName,'['); - else{ - let attach=""; - if(/^[A-Za-z\_][A-Za-z\d\_]*$/.test(sonName)/*is a qualified id*/) - attach='.'+sonName; - else attach=enBrace(sonName,'['); - ans=restoreNext(ops[1],true)+attach; + case 7://get value of str + { + switch (ops[1][0]) { + case 11: + ans = enBrace("__unTestedGetValue:" + enBrace(jsoToWxon(ops), '['), '{'); + break; + case 3: + ans = new String(ops[1][1]); + ans._type = "var"; + break; + default: + throw Error("Unknown type to get value"); + } + break; } - break; - } - case 7://get value of str - { - switch(ops[1][0]){ - case 11: - ans=enBrace("__unTestedGetValue:"+enBrace(jsoToWxon(ops),'['),'{'); + case 8://first object + ans = enBrace(ops[1] + ':' + restoreNext(ops[2], true), '{');//ops[1] have only this way to define break; - case 3: - ans=new String(ops[1][1]); - ans._type="var"; + case 9://object + { + function type(x) { + if (x.startsWith('...')) return 1; + if (x.startsWith('{') && x.endsWith('}')) return 0; + return 2; + } + + let a = restoreNext(ops[1], true); + let b = restoreNext(ops[2], true); + let xa = type(a), xb = type(b); + if (xa == 2 || xb == 2) ans = enBrace("__unkownMerge:" + enBrace(a + "," + b, '['), '{'); + else { + if (!xa) a = a.slice(1, -1).trim(); + if (!xb) b = b.slice(1, -1).trim(); + //console.log(l,r); + ans = enBrace(a + ',' + b, '{'); + } break; - default: - throw Error("Unknown type to get value"); } - break; - } - case 8://first object - ans=enBrace(ops[1]+':'+restoreNext(ops[2],true),'{');//ops[1] have only this way to define - break; - case 9://object - { - function type(x){ - if(x.startsWith('...'))return 1; - if(x.startsWith('{')&&x.endsWith('}'))return 0; - return 2; - } - let a=restoreNext(ops[1],true); - let b=restoreNext(ops[2],true); - let xa=type(a),xb=type(b); - if(xa==2||xb==2)ans=enBrace("__unkownMerge:"+enBrace(a+","+b,'['),'{'); - else{ - if(!xa)a=a.slice(1,-1).trim(); - if(!xb)b=b.slice(1,-1).trim(); - //console.log(l,r); - ans=enBrace(a+','+b,'{'); + case 10://...object + ans = '...' + restoreNext(ops[1], true); + break; + case 12: { + let arr = restoreNext(ops[2], true); + if (arr.startsWith('[') && arr.endsWith(']')) + ans = restoreNext(ops[1], true) + enBrace(arr.slice(1, -1).trim(), '('); + else ans = restoreNext(ops[1], true) + '.apply' + enBrace('null,' + arr, '('); + break; } - break; - } - case 10://...object - ans='...'+restoreNext(ops[1],true); - break; - case 12: - { - let arr=restoreNext(ops[2],true); - if(arr.startsWith('[')&&arr.endsWith(']')) - ans=restoreNext(ops[1],true)+enBrace(arr.slice(1,-1).trim(),'('); - else ans=restoreNext(ops[1],true)+'.apply'+enBrace('null,'+arr,'('); - break; - } - default: - ans=enBrace("__unkownSpecific:"+jsoToWxon(ops),'{'); + default: + ans = enBrace("__unkownSpecific:" + jsoToWxon(ops), '{'); } return scope(ans); } } -function restoreGroup(z){ - let ans=[]; - for(let g in z.mul){ - let singleAns=[]; - for(let e of z.mul[g])singleAns.push(restoreSingle(e,false)); - ans[g]=singleAns; + +function restoreGroup(z) { + let ans = []; + for (let g in z.mul) { + let singleAns = []; + for (let e of z.mul[g]) singleAns.push(restoreSingle(e, false)); + ans[g] = singleAns; } - let ret=[];//Keep a null array for remaining global Z array. - ret.mul=ans; + let ret = [];//Keep a null array for remaining global Z array. + ret.mul = ans; return ret; } -function restoreAll(z){ - if(z.mul)return restoreGroup(z); - let ans=[]; - for(let e of z)ans.push(restoreSingle(e,false)); + +function restoreAll(z) { + if (z.mul) return restoreGroup(z); + let ans = []; + for (let e of z) ans.push(restoreSingle(e, false)); return ans; } -module.exports={getZ(code,cb){ - catchZ(code,z=>cb(restoreAll(z))); -}}; + +module.exports = { + getZ(code, cb) { + catchZ(code, z => cb(restoreAll(z))); + } +}; diff --git a/wuWxapkg.js b/wuWxapkg.js index b4a07da..3221253 100644 --- a/wuWxapkg.js +++ b/wuWxapkg.js @@ -1,120 +1,196 @@ -const wu=require("./wuLib.js"); -const wuJs=require("./wuJs.js"); -const wuCfg=require("./wuConfig.js"); -const wuMl=require("./wuWxml.js"); -const wuSs=require("./wuWxss.js"); -const path=require("path"); -const fs=require("fs"); -function header(buf){ - console.log("\nHeader info:"); - let firstMark=buf.readUInt8(0); - console.log(" firstMark: 0x%s",firstMark.toString(16)); - let unknownInfo=buf.readUInt32BE(1); - console.log(" unknownInfo: ",unknownInfo); - let infoListLength=buf.readUInt32BE(5); - console.log(" infoListLength: ",infoListLength); - let dataLength=buf.readUInt32BE(9); - console.log(" dataLength: ",dataLength); - let lastMark=buf.readUInt8(13); - console.log(" lastMark: 0x%s",lastMark.toString(16)); - if(firstMark!=0xbe||lastMark!=0xed)throw Error("Magic number is not correct!"); - return [infoListLength,dataLength]; +const wu = require("./wuLib.js"); +const wuJs = require("./wuJs.js"); +const wuCfg = require("./wuConfig.js"); +const wuMl = require("./wuWxml.js"); +const wuSs = require("./wuWxss.js"); +const path = require("path"); +const fs = require("fs"); + +function header(buf) { + console.log("\nHeader info:"); + let firstMark = buf.readUInt8(0); + console.log(" firstMark: 0x%s", firstMark.toString(16)); + let unknownInfo = buf.readUInt32BE(1); + console.log(" unknownInfo: ", unknownInfo); + let infoListLength = buf.readUInt32BE(5); + console.log(" infoListLength: ", infoListLength); + let dataLength = buf.readUInt32BE(9); + console.log(" dataLength: ", dataLength); + let lastMark = buf.readUInt8(13); + console.log(" lastMark: 0x%s", lastMark.toString(16)); + if (firstMark != 0xbe || lastMark != 0xed) throw Error("Magic number is not correct!"); + return [infoListLength, dataLength]; } -function genList(buf){ - console.log("\nFile list info:"); - let fileCount=buf.readUInt32BE(0); - console.log(" fileCount: ",fileCount); - let fileInfo=[],off=4; - for(let i=0;i{ - wu.addIO(()=>{ - console.log("Split and make up done."); - if(!order.includes("d")){ - console.log("Delete files..."); - wu.addIO(()=>console.log("Deleted.\n\nFile done.")); - for(let name in needDelete)if(needDelete[name]>=8)wu.del(name); - } - cb(); - }); - }); - function doBack(deletable){ - for(let key in deletable){ - if(!needDelete[key])needDelete[key]=0; - needDelete[key]+=deletable[key];//all file have score bigger than 8 will be delete. - } - weappEvent.decount(); - } - //This will be the only func running this time, so async is needless. - if(fs.existsSync(path.resolve(dir,"app-service.js"))){//weapp - console.log("Split app-service.js and make up configs & wxss & wxml & wxs..."); - wuCfg.doConfig(path.resolve(dir,"app-config.json"),doBack); - wuJs.splitJs(path.resolve(dir,"app-service.js"),doBack); - if(fs.existsSync(path.resolve(dir,"workers.js"))) - wuJs.splitJs(path.resolve(dir,"workers.js"),doBack); - if(fs.existsSync(path.resolve(dir,"page-frame.html"))) - wuMl.doFrame(path.resolve(dir,"page-frame.html"),doBack,order); - else if(fs.existsSync(path.resolve(dir,"app-wxss.js"))) { - wuMl.doFrame(path.resolve(dir,"app-wxss.js"),doBack,order); - if(!needDelete[path.resolve(dir,"page-frame.js")])needDelete[path.resolve(dir,"page-frame.js")]=8; - } else throw Error("page-frame-like file is not found in the package by auto."); - wuSs.doWxss(dir,doBack);//Force it run at last, becuase lots of error occured in this part - }else if(fs.existsSync(path.resolve(dir,"game.js"))){//wegame - console.log("Split game.js and rewrite game.json..."); - let gameCfg=path.resolve(dir,"app-config.json"); - wu.get(gameCfg,cfgPlain=>{ - let cfg=JSON.parse(cfgPlain); - if(cfg.subContext){ - console.log("Found subContext, splitting it...") - delete cfg.subContext; - let contextPath=path.resolve(dir,"subContext.js"); - wuJs.splitJs(contextPath,()=>wu.del(contextPath)); - } - wu.save(path.resolve(dir,"game.json"),JSON.stringify(cfg,null,4)); - wu.del(gameCfg); - }); - wuJs.splitJs(path.resolve(dir,"game.js"),()=>{ - wu.addIO(()=>{ - console.log("Split and rewrite done."); - cb(); - }); - }); - }else throw Error("This package is unrecognizable.\nMay be this package is a subPackage which should be unpacked with -s=.\nOtherwise, please decrypted every type of file by hand.") + +function packDone(dir, cb, order) { + console.log("Unpack done."); + let weappEvent = new wu.CntEvent, needDelete = {}; + weappEvent.encount(4); + weappEvent.add(() => { + wu.addIO(() => { + console.log("Split and make up done."); + if (!order.includes("d")) { + console.log("Delete files..."); + wu.addIO(() => console.log("Deleted.\n\nFile done.")); + for (let name in needDelete) if (needDelete[name] >= 8) wu.del(name); + } + cb(); + }); + }); + + function doBack(deletable) { + for (let key in deletable) { + if (!needDelete[key]) needDelete[key] = 0; + needDelete[key] += deletable[key];//all file have score bigger than 8 will be delete. + } + weappEvent.decount(); + } + + function dealThreeThings(dir, mainDir, nowDir) { + console.log("Split app-service.js and make up configs & wxss & wxml & wxs..."); + + //deal config + if (fs.existsSync(path.resolve(dir, "app-config.json"))) { + wuCfg.doConfig(path.resolve(dir, "app-config.json"), doBack); + console.log('deal config ok'); + } + //deal js + if (fs.existsSync(path.resolve(dir, "app-service.js"))) { + wuJs.splitJs(path.resolve(dir, "app-service.js"), doBack, mainDir); + console.log('deal js ok'); + } + if (fs.existsSync(path.resolve(dir, "workers.js"))) { + wuJs.splitJs(path.resolve(dir, "workers.js"), doBack, mainDir); + console.log('deal js2 ok'); + } + //deal html + if (mainDir) { + if (fs.existsSync(path.resolve(dir, "page-frame.js"))) { + wuMl.doFrame(path.resolve(dir, "page-frame.js"), doBack, order, mainDir); + console.log('deal sub html ok'); + } + wuSs.doWxss(dir, doBack, mainDir, nowDir); + } else { + if (fs.existsSync(path.resolve(dir, "page-frame.html"))) { + wuMl.doFrame(path.resolve(dir, "page-frame.html"), doBack, order, mainDir); + console.log('deal html ok'); + } else if (fs.existsSync(path.resolve(dir, "app-wxss.js"))) { + wuMl.doFrame(path.resolve(dir, "app-wxss.js"), doBack, order, mainDir); + if (!needDelete[path.resolve(dir, "page-frame.js")]) { + needDelete[path.resolve(dir, "page-frame.js")] = 8; + } + console.log('deal wxss.js ok'); + } else { + throw Error("page-frame-like file is not found in the package by auto."); + } + //Force it run at last, becuase lots of error occured in this part + wuSs.doWxss(dir, doBack); + + console.log('deal css ok'); + } + + } + +//This will be the only func running this time, so async is needless. + if (fs.existsSync(path.resolve(dir, "app-service.js"))) { + //weapp + dealThreeThings(dir); + } else if (fs.existsSync(path.resolve(dir, "game.js"))) { + //wegame + console.log("Split game.js and rewrite game.json..."); + let gameCfg = path.resolve(dir, "app-config.json"); + wu.get(gameCfg, cfgPlain => { + let cfg = JSON.parse(cfgPlain); + if (cfg.subContext) { + console.log("Found subContext, splitting it...") + delete cfg.subContext; + let contextPath = path.resolve(dir, "subContext.js"); + wuJs.splitJs(contextPath, () => wu.del(contextPath)); + } + wu.save(path.resolve(dir, "game.json"), JSON.stringify(cfg, null, 4)); + wu.del(gameCfg); + }); + wuJs.splitJs(path.resolve(dir, "game.js"), () => { + wu.addIO(() => { + console.log("Split and rewrite done."); + cb(); + }); + }); + } else {//分包 + let doSubPkg = false; + for (const orderElement of order) { + if (orderElement.indexOf('s=') !== -1) { + let mainDir = orderElement.substring(2, orderElement.length); + console.log("now dir: " + dir); + console.log("param of mainDir: " + mainDir); + + let findDir = function (dir, oldDir) { + let files = fs.readdirSync(dir); + for (const file of files) { + let workDir = path.join(dir, file); + if (fs.existsSync(path.resolve(workDir, "app-service.js"))) { + console.log("sub package word dir: " + workDir); + mainDir = path.resolve(oldDir, mainDir); + console.log("real mainDir: " + mainDir); + dealThreeThings(workDir, mainDir, oldDir); + doSubPkg = true; + return true; + } else { + findDir(workDir, oldDir); + } + } + + }; + + findDir(dir, dir); + + } + } + if (!doSubPkg) { + throw new Error("检测到此包是分包后的子包, 请通过 -s 参数指定存放路径后重试, 如 node wuWxapkg.js -s=/xxx/xxx ./testpkg/test-pkg-sub.wxapkg"); + } + } } -function doFile(name,cb,order){ - for(let ord of order)if(ord.startsWith("s="))global.subPack=ord.slice(3); - console.log("Unpack file "+name+"..."); - let dir=path.resolve(name,"..",path.basename(name,".wxapkg")); - wu.get(name,buf=>{ - let [infoListLength,dataLength]=header(buf.slice(0,14)); - if(order.includes("o"))wu.addIO(console.log.bind(console),"Unpack done."); - else wu.addIO(packDone,dir,cb,order); - saveFile(dir,buf,genList(buf.slice(14,infoListLength+14))); - },{}); + +function doFile(name, cb, order) { + for (let ord of order) if (ord.startsWith("s=")) global.subPack = ord.slice(3); + console.log("Unpack file " + name + "..."); + let dir = path.resolve(name, "..", path.basename(name, ".wxapkg")); + wu.get(name, buf => { + let [infoListLength, dataLength] = header(buf.slice(0, 14)); + if (order.includes("o")) wu.addIO(console.log.bind(console), "Unpack done."); + else wu.addIO(packDone, dir, cb, order); + saveFile(dir, buf, genList(buf.slice(14, infoListLength + 14))); + }, {}); } -module.exports={doFile:doFile}; -if(require.main===module){ - wu.commandExecute(doFile,"Unpack a wxapkg file.\n\n[-o] [-d] [-s=
] \n\n-d Do not delete transformed unpacked files.\n-o Do not execute any operation after unpack.\n-s=
Regard all packages provided as subPackages and\n regard
as the directory of sources of the main package.\n wxapkg files to unpack"); + +module.exports = {doFile: doFile}; +if (require.main === module) { + wu.commandExecute(doFile, "Unpack a wxapkg file.\n\n[-o] [-d] [-s=
] \n\n-d Do not delete transformed unpacked files.\n-o Do not execute any operation after unpack.\n-s=
Regard all packages provided as subPackages and\n regard
as the directory of sources of the main package.\n wxapkg files to unpack"); } diff --git a/wuWxml.js b/wuWxml.js index 50a442f..b8e7f93 100644 --- a/wuWxml.js +++ b/wuWxml.js @@ -1,392 +1,426 @@ -const wu=require("./wuLib.js"); -const {getZ}=require("./wuRestoreZ.js"); -const {wxsBeautify}=require("./wuJs.js"); -const fs=require('fs'); -const path=require("path"); -const esprima=require('esprima'); -const {VM}=require('vm2'); -const escodegen=require('escodegen'); -function analyze(core,z,namePool,xPool,fakePool={},zMulName="0"){ - function anaRecursion(core,fakePool={}){ - return analyze(core,z,namePool,xPool,fakePool,zMulName); - } - function push(name,elem){ - namePool[name]=elem; - } - function pushSon(pname,son){ - if(fakePool[pname])fakePool[pname].son.push(son); - else namePool[pname].son.push(son); - } - for(let ei=0;ei0) - throw Error("Noticable generics content: "+dec.init.arguments[2].toString()); - let mv={}; - let name=null,base=0; - for(let x of dec.init.arguments[1].elements){ - let v=x.value; - if(!v&&typeof v!="number"){ - if(x.type=="UnaryExpression"&&x.operator=="-")v=-x.argument.value; - else throw Error("Unknown type of object in _m attrs array: "+x.type); - } - if(name===null){ - name=v; - }else{ - if(base+v<0)mv[name]=null;else{ - mv[name]=z[base+v]; - if(base==0)base=v; - } - name=null; - } - } - push(dec.id.name,{tag:dec.init.arguments[0].value,son:[],v:mv}); - } - break; - case "_mz": - { - if(dec.init.arguments[3].elements.length>0) - throw Error("Noticable generics content: "+dec.init.arguments[3].toString()); - let mv={}; - let name=null,base=0; - for(let x of dec.init.arguments[2].elements){ - let v=x.value; - if(!v&&typeof v!="number"){ - if(x.type=="UnaryExpression"&&x.operator=="-")v=-x.argument.value; - else throw Error("Unknown type of object in _mz attrs array: "+x.type); - } - if(name===null){ - name=v; - }else{ - if(base+v<0)mv[name]=null;else{ - mv[name]=z.mul[zMulName][base+v]; - if(base==0)base=v; - } - name=null; - } - } - push(dec.id.name,{tag:dec.init.arguments[1].value,son:[],v:mv}); - } - break; - case "_gd"://template use/is - { - let is=namePool[dec.init.arguments[1].name].content; - let data=null,obj=null; - ei++; - for(let e of core[ei].consequent.body){ - if(e.type=="VariableDeclaration"){ - for(let f of e.declarations){ - if(f.init.type=="LogicalExpression"&&f.init.left.type=="CallExpression"){ - if(f.init.left.callee.name=="_1")data=z[f.init.left.arguments[0].value]; - else if(f.init.left.callee.name=="_1z")data=z.mul[zMulName][f.init.left.arguments[1].value]; - } - } - }else if(e.type=="ExpressionStatement"){ - let f=e.expression; - if(f.type=="AssignmentExpression"&&f.operator=="="&&f.left.property&&f.left.property.name=="wxXCkey"){ - obj=f.left.object.name; - } - } - } - namePool[obj].tag="template"; - Object.assign(namePool[obj].v,{is:is,data:data}); - } - break; - default: - { - let funName=dec.init.callee.name; - if(funName.startsWith("gz$gwx")){ - zMulName=funName.slice(6); - }else throw Error("Unknown init callee "+funName); - } - } - }else if(dec.init.type=="FunctionExpression"){ - push(dec.id.name,{tag:"gen",func:dec.init}); - }else if(dec.init.type=="MemberExpression"){ - if(dec.init.object.type=="MemberExpression"&&dec.init.object.object.name=="e_"&&dec.init.object.property.type=="MemberExpression"&&dec.init.object.property.object.name=="x"){ - if(dec.init.property.name=="j"){//include - //do nothing - }else if(dec.init.property.name=="i"){//import - //do nothing - }else throw Error("Unknown member expression declaration."); - }else throw Error("Unknown member expression declaration."); - }else throw Error("Unknown declaration init type " + dec.init.type); - } - break; - case "IfStatement": - if(e.test.callee.name.startsWith("_o")){ - function parse_OFun(e){ - if(e.test.callee.name=="_o")return z[e.test.arguments[0].value]; - else if(e.test.callee.name=="_oz")return z.mul[zMulName][e.test.arguments[1].value]; - else throw Error("Unknown if statement test callee name:"+e.test.callee.name); - } - let vname=e.consequent.body[0].expression.left.object.name; - let nif={tag:"block",v:{"wx:if":parse_OFun(e)},son:[]}; - anaRecursion(e.consequent.body,{[vname]:nif}); - pushSon(vname,nif); - if(e.alternate){ - while(e.alternate&&e.alternate.type=="IfStatement"){ - e=e.alternate; - nif={tag:"block",v:{"wx:elif":parse_OFun(e)},son:[]}; - anaRecursion(e.consequent.body,{[vname]:nif}); - pushSon(vname,nif); - } - if(e.alternate&&e.alternate.type=="BlockStatement"){ - e=e.alternate; - nif={tag:"block",v:{"wx:else":null},son:[]}; - anaRecursion(e.body,{[vname]:nif}); - pushSon(vname,nif); - } - } - }else throw Error("Unknown if statement."); - break; - default: - throw Error("Unknown type "+e.type); - } - } +const wu = require("./wuLib.js"); +const {getZ} = require("./wuRestoreZ.js"); +const {wxsBeautify} = require("./wuJs.js"); +const fs = require('fs'); +const path = require("path"); +const esprima = require('esprima'); +const {VM} = require('vm2'); +const escodegen = require('escodegen'); + +function analyze(core, z, namePool, xPool, fakePool = {}, zMulName = "0") { + function anaRecursion(core, fakePool = {}) { + return analyze(core, z, namePool, xPool, fakePool, zMulName); + } + + function push(name, elem) { + namePool[name] = elem; + } + + function pushSon(pname, son) { + if (fakePool[pname]) fakePool[pname].son.push(son); + else namePool[pname].son.push(son); + } + + for (let ei = 0; ei < core.length; ei++) { + let e = core[ei]; + switch (e.type) { + case "ExpressionStatement": { + let f = e.expression; + if (f.callee) { + if (f.callee.type == "Identifier") { + switch (f.callee.name) { + case "_r": + namePool[f.arguments[0].name].v[f.arguments[1].value] = z[f.arguments[2].value]; + break; + case "_rz": + namePool[f.arguments[1].name].v[f.arguments[2].value] = z.mul[zMulName][f.arguments[3].value]; + break; + case "_": + pushSon(f.arguments[0].name, namePool[f.arguments[1].name]); + break; + case "_2": { + let item = f.arguments[6].value;//def:item + let index = f.arguments[7].value;//def:index + let data = z[f.arguments[0].value]; + let key = escodegen.generate(f.arguments[8]).slice(1, -1);//f.arguments[8].value;//def:"" + let obj = namePool[f.arguments[5].name]; + let gen = namePool[f.arguments[1].name]; + if (gen.tag == "gen") { + let ret = gen.func.body.body.pop().argument.name; + anaRecursion(gen.func.body.body, {[ret]: obj}); + } + obj.v["wx:for"] = data; + if (index != "index") obj.v["wx:for-index"] = index; + if (item != "item") obj.v["wx:for-item"] = item; + if (key != "") obj.v["wx:key"] = key; + } + break; + case "_2z": { + let item = f.arguments[7].value;//def:item + let index = f.arguments[8].value;//def:index + let data = z.mul[zMulName][f.arguments[1].value]; + let key = escodegen.generate(f.arguments[9]).slice(1, -1);//f.arguments[9].value;//def:"" + let obj = namePool[f.arguments[6].name]; + let gen = namePool[f.arguments[2].name]; + if (gen.tag == "gen") { + let ret = gen.func.body.body.pop().argument.name; + anaRecursion(gen.func.body.body, {[ret]: obj}); + } + obj.v["wx:for"] = data; + if (index != "index") obj.v["wx:for-index"] = index; + if (item != "item") obj.v["wx:for-item"] = item; + if (key != "") obj.v["wx:key"] = key; + } + break; + case "_ic": + pushSon(f.arguments[5].name, { + tag: "include", + son: [], + v: {src: xPool[f.arguments[0].property.value]} + }); + break; + case "_ai": {//template import + let to = Object.keys(fakePool)[0]; + if (to) pushSon(to, { + tag: "import", + son: [], + v: {src: xPool[f.arguments[1].property.value]} + }); + else throw Error("Unexpected fake pool"); + } + break; + case "_af": + //ignore _af + break; + default: + throw Error("Unknown expression callee name " + f.callee.name); + } + } else if (f.callee.type == "MemberExpression") { + if (f.callee.object.name == "cs" || f.callee.property.name == "pop") break; + throw Error("Unknown member expression"); + } else throw Error("Unknown callee type " + f.callee.type); + } else if (f.type == "AssignmentExpression" && f.operator == "=") { + //no special use + } else throw Error("Unknown expression statement."); + break; + } + case "VariableDeclaration": + for (let dec of e.declarations) { + if (dec.init.type == "CallExpression") { + switch (dec.init.callee.name) { + case "_n": + push(dec.id.name, {tag: dec.init.arguments[0].value, son: [], v: {}}); + break; + case "_v": + push(dec.id.name, {tag: "block", son: [], v: {}}); + break; + case "_o": + push(dec.id.name, { + tag: "__textNode__", + textNode: true, + content: z[dec.init.arguments[0].value] + }); + break; + case "_oz": + push(dec.id.name, { + tag: "__textNode__", + textNode: true, + content: z.mul[zMulName][dec.init.arguments[1].value] + }); + break; + case "_m": { + if (dec.init.arguments[2].elements.length > 0) + throw Error("Noticable generics content: " + dec.init.arguments[2].toString()); + let mv = {}; + let name = null, base = 0; + for (let x of dec.init.arguments[1].elements) { + let v = x.value; + if (!v && typeof v != "number") { + if (x.type == "UnaryExpression" && x.operator == "-") v = -x.argument.value; + else throw Error("Unknown type of object in _m attrs array: " + x.type); + } + if (name === null) { + name = v; + } else { + if (base + v < 0) mv[name] = null; else { + mv[name] = z[base + v]; + if (base == 0) base = v; + } + name = null; + } + } + push(dec.id.name, {tag: dec.init.arguments[0].value, son: [], v: mv}); + } + break; + case "_mz": { + if (dec.init.arguments[3].elements.length > 0) + throw Error("Noticable generics content: " + dec.init.arguments[3].toString()); + let mv = {}; + let name = null, base = 0; + for (let x of dec.init.arguments[2].elements) { + let v = x.value; + if (!v && typeof v != "number") { + if (x.type == "UnaryExpression" && x.operator == "-") v = -x.argument.value; + else throw Error("Unknown type of object in _mz attrs array: " + x.type); + } + if (name === null) { + name = v; + } else { + if (base + v < 0) mv[name] = null; else { + mv[name] = z.mul[zMulName][base + v]; + if (base == 0) base = v; + } + name = null; + } + } + push(dec.id.name, {tag: dec.init.arguments[1].value, son: [], v: mv}); + } + break; + case "_gd"://template use/is + { + let is = namePool[dec.init.arguments[1].name].content; + let data = null, obj = null; + ei++; + for (let e of core[ei].consequent.body) { + if (e.type == "VariableDeclaration") { + for (let f of e.declarations) { + if (f.init.type == "LogicalExpression" && f.init.left.type == "CallExpression") { + if (f.init.left.callee.name == "_1") data = z[f.init.left.arguments[0].value]; + else if (f.init.left.callee.name == "_1z") data = z.mul[zMulName][f.init.left.arguments[1].value]; + } + } + } else if (e.type == "ExpressionStatement") { + let f = e.expression; + if (f.type == "AssignmentExpression" && f.operator == "=" && f.left.property && f.left.property.name == "wxXCkey") { + obj = f.left.object.name; + } + } + } + namePool[obj].tag = "template"; + Object.assign(namePool[obj].v, {is: is, data: data}); + } + break; + default: { + let funName = dec.init.callee.name; + if (funName.startsWith("gz$gwx")) { + zMulName = funName.slice(6); + } else throw Error("Unknown init callee " + funName); + } + } + } else if (dec.init.type == "FunctionExpression") { + push(dec.id.name, {tag: "gen", func: dec.init}); + } else if (dec.init.type == "MemberExpression") { + if (dec.init.object.type == "MemberExpression" && dec.init.object.object.name == "e_" && dec.init.object.property.type == "MemberExpression" && dec.init.object.property.object.name == "x") { + if (dec.init.property.name == "j") {//include + //do nothing + } else if (dec.init.property.name == "i") {//import + //do nothing + } else throw Error("Unknown member expression declaration."); + } else throw Error("Unknown member expression declaration."); + } else throw Error("Unknown declaration init type " + dec.init.type); + } + break; + case "IfStatement": + if (e.test.callee.name.startsWith("_o")) { + function parse_OFun(e) { + if (e.test.callee.name == "_o") return z[e.test.arguments[0].value]; + else if (e.test.callee.name == "_oz") return z.mul[zMulName][e.test.arguments[1].value]; + else throw Error("Unknown if statement test callee name:" + e.test.callee.name); + } + + let vname = e.consequent.body[0].expression.left.object.name; + let nif = {tag: "block", v: {"wx:if": parse_OFun(e)}, son: []}; + anaRecursion(e.consequent.body, {[vname]: nif}); + pushSon(vname, nif); + if (e.alternate) { + while (e.alternate && e.alternate.type == "IfStatement") { + e = e.alternate; + nif = {tag: "block", v: {"wx:elif": parse_OFun(e)}, son: []}; + anaRecursion(e.consequent.body, {[vname]: nif}); + pushSon(vname, nif); + } + if (e.alternate && e.alternate.type == "BlockStatement") { + e = e.alternate; + nif = {tag: "block", v: {"wx:else": null}, son: []}; + anaRecursion(e.body, {[vname]: nif}); + pushSon(vname, nif); + } + } + } else throw Error("Unknown if statement."); + break; + default: + throw Error("Unknown type " + e.type); + } + } } -function wxmlify(str,isText){ - if(typeof str=="undefined"||str===null)return "Empty";//throw Error("Empty str in "+(isText?"text":"prop")); - if(isText)return str;//may have some bugs in some specific case(undocumented by tx) - else return str.replace(/"/g, '\\"'); + +function wxmlify(str, isText) { + if (typeof str == "undefined" || str === null) return "Empty";//throw Error("Empty str in "+(isText?"text":"prop")); + if (isText) return str;//may have some bugs in some specific case(undocumented by tx) + else return str.replace(/"/g, '\\"'); } -function elemToString(elem,dep,moreInfo=false){ - const longerList=[];//put tag name which can't be style. - const indent=' '.repeat(4); - function isTextTag(elem){ - return elem.tag=="__textNode__"&&elem.textNode; - } - function elemRecursion(elem,dep){ - return elemToString(elem,dep,moreInfo); - } - function trimMerge(rets){ - let needTrimLeft=false,ans=""; - for(let ret of rets){ - if(ret.textNode==1){ - if(!needTrimLeft){ - needTrimLeft=true; - ans=ans.trimRight(); - } - }else if(needTrimLeft){ - needTrimLeft=false; - ret=ret.trimLeft(); - } - ans+=ret; - } - return ans; - } - if(isTextTag(elem)){ - //In comment, you can use typify text node, which beautify its code, but may destroy ui. - //So, we use a "hack" way to solve this problem by letting typify program stop when face textNode - let str=new String(wxmlify(elem.content,true)); - str.textNode=1; - return wxmlify(str,true);//indent.repeat(dep)+wxmlify(elem.content.trim(),true)+"\n"; - } - if(elem.tag=="block"&&!moreInfo){ - if(elem.son.length==1&&!isTextTag(elem.son[0])){ - let ok=true,s=elem.son[0]; - for(let x in elem.v)if(x in s.v){ - ok=false; - break; - } - if(ok&&!(("wx:for" in s.v||"wx:if" in s.v)&&("wx:if" in elem.v||"wx:else" in elem.v||"wx:elif" in elem.v))){//if for and if in one tag, the default result is an if in for. And we should block if nested in elif/else been combined. - Object.assign(s.v,elem.v); - return elemRecursion(s,dep); - } - }else if(Object.keys(elem.v).length==0){ - let ret=[]; - for(let s of elem.son)ret.push(elemRecursion(s,dep)); - return trimMerge(ret); - } - } - let ret=indent.repeat(dep)+"<"+elem.tag; - for(let v in elem.v)ret+=" "+v+(elem.v[v]!==null?"=\""+wxmlify(elem.v[v])+"\"":""); - if(elem.son.length==0){ - if(longerList.includes(elem.tag))return ret+" />\n"; - else return ret+">\n"; - } - ret+=">\n"; - let rets=[ret]; - for(let s of elem.son)rets.push(elemRecursion(s,dep+1)); - rets.push(indent.repeat(dep)+"\n"); - return trimMerge(rets); + +function elemToString(elem, dep, moreInfo = false) { + const longerList = [];//put tag name which can't be style. + const indent = ' '.repeat(4); + + function isTextTag(elem) { + return elem.tag == "__textNode__" && elem.textNode; + } + + function elemRecursion(elem, dep) { + return elemToString(elem, dep, moreInfo); + } + + function trimMerge(rets) { + let needTrimLeft = false, ans = ""; + for (let ret of rets) { + if (ret.textNode == 1) { + if (!needTrimLeft) { + needTrimLeft = true; + ans = ans.trimRight(); + } + } else if (needTrimLeft) { + needTrimLeft = false; + ret = ret.trimLeft(); + } + ans += ret; + } + return ans; + } + + if (isTextTag(elem)) { + //In comment, you can use typify text node, which beautify its code, but may destroy ui. + //So, we use a "hack" way to solve this problem by letting typify program stop when face textNode + let str = new String(wxmlify(elem.content, true)); + str.textNode = 1; + return wxmlify(str, true);//indent.repeat(dep)+wxmlify(elem.content.trim(),true)+"\n"; + } + if (elem.tag == "block" && !moreInfo) { + if (elem.son.length == 1 && !isTextTag(elem.son[0])) { + let ok = true, s = elem.son[0]; + for (let x in elem.v) if (x in s.v) { + ok = false; + break; + } + if (ok && !(("wx:for" in s.v || "wx:if" in s.v) && ("wx:if" in elem.v || "wx:else" in elem.v || "wx:elif" in elem.v))) {//if for and if in one tag, the default result is an if in for. And we should block if nested in elif/else been combined. + Object.assign(s.v, elem.v); + return elemRecursion(s, dep); + } + } else if (Object.keys(elem.v).length == 0) { + let ret = []; + for (let s of elem.son) ret.push(elemRecursion(s, dep)); + return trimMerge(ret); + } + } + let ret = indent.repeat(dep) + "<" + elem.tag; + for (let v in elem.v) ret += " " + v + (elem.v[v] !== null ? "=\"" + wxmlify(elem.v[v]) + "\"" : ""); + if (elem.son.length == 0) { + if (longerList.includes(elem.tag)) return ret + " />\n"; + else return ret + ">\n"; + } + ret += ">\n"; + let rets = [ret]; + for (let s of elem.son) rets.push(elemRecursion(s, dep + 1)); + rets.push(indent.repeat(dep) + "\n"); + return trimMerge(rets); } -function doWxml(state,dir,name,code,z,xPool,rDs,wxsList,moreInfo){ - let rname=code.slice(code.lastIndexOf("return")+6).replace(/[\;\}]/g,"").trim(); - code=code.slice(code.indexOf("\n"),code.lastIndexOf("return")).trim(); - let r={son:[]}; - analyze(esprima.parseScript(code).body,z,{[rname]:r},xPool,{[rname]:r}); - let ans=[]; - for(let elem of r.son)ans.push(elemToString(elem,0,moreInfo)); - let result=[ans.join("")]; - for(let v in rDs){ - state[0]=v; - let oriCode=rDs[v].toString(); - let rname=oriCode.slice(oriCode.lastIndexOf("return")+6).replace(/[\;\}]/g,"").trim(); - let tryPtr=oriCode.indexOf("\ntry{"); - let zPtr=oriCode.indexOf("var z=gz$gwx"); - let code=oriCode.slice(tryPtr+5,oriCode.lastIndexOf("\n}catch(")).trim(); - if(zPtr!=-1&&tryPtr>zPtr){ - let attach=oriCode.slice(zPtr); - attach=attach.slice(0,attach.indexOf("()"))+"()\n"; - code=attach+code; - } - let r={tag:"template",v:{name:v},son:[]}; - analyze(esprima.parseScript(code).body,z,{[rname]:r},xPool,{[rname]:r}); - result.unshift(elemToString(r,0,moreInfo)); - } - name=path.resolve(dir,name); - if(wxsList[name])result.push(wxsList[name]); - wu.save(name,result.join("")); + +function doWxml(state, dir, name, code, z, xPool, rDs, wxsList, moreInfo) { + let rname = code.slice(code.lastIndexOf("return") + 6).replace(/[\;\}]/g, "").trim(); + code = code.slice(code.indexOf("\n"), code.lastIndexOf("return")).trim(); + let r = {son: []}; + analyze(esprima.parseScript(code).body, z, {[rname]: r}, xPool, {[rname]: r}); + let ans = []; + for (let elem of r.son) ans.push(elemToString(elem, 0, moreInfo)); + let result = [ans.join("")]; + for (let v in rDs) { + state[0] = v; + let oriCode = rDs[v].toString(); + let rname = oriCode.slice(oriCode.lastIndexOf("return") + 6).replace(/[\;\}]/g, "").trim(); + let tryPtr = oriCode.indexOf("\ntry{"); + let zPtr = oriCode.indexOf("var z=gz$gwx"); + let code = oriCode.slice(tryPtr + 5, oriCode.lastIndexOf("\n}catch(")).trim(); + if (zPtr != -1 && tryPtr > zPtr) { + let attach = oriCode.slice(zPtr); + attach = attach.slice(0, attach.indexOf("()")) + "()\n"; + code = attach + code; + } + let r = {tag: "template", v: {name: v}, son: []}; + analyze(esprima.parseScript(code).body, z, {[rname]: r}, xPool, {[rname]: r}); + result.unshift(elemToString(r, 0, moreInfo)); + } + name = path.resolve(dir, name); + if (wxsList[name]) result.push(wxsList[name]); + wu.save(name, result.join("")); } -function tryWxml(dir,name,code,z,xPool,rDs,...args){ - console.log("Decompile "+name+"..."); - let state=[null]; - try{ - doWxml(state,dir,name,code,z,xPool,rDs,...args); - console.log("Decompile success!"); - }catch(e){ - console.log("error on "+name+"("+(state[0]===null?"Main":"Template-"+state[0])+")\nerr: ",e); - if(state[0]===null)wu.save(path.resolve(dir,name+".ori.js"),code); - else wu.save(path.resolve(dir,name+".tem-"+state[0]+".ori.js"),rDs[state[0]].toString()); - } + +function tryWxml(dir, name, code, z, xPool, rDs, ...args) { + console.log("Decompile " + name + "..."); + let state = [null]; + try { + doWxml(state, dir, name, code, z, xPool, rDs, ...args); + console.log("Decompile success!"); + } catch (e) { + console.log("error on " + name + "(" + (state[0] === null ? "Main" : "Template-" + state[0]) + ")\nerr: ", e); + if (state[0] === null) wu.save(path.resolve(dir, name + ".ori.js"), code); + else wu.save(path.resolve(dir, name + ".tem-" + state[0] + ".ori.js"), rDs[state[0]].toString()); + } } -function doWxs(code){ - const before='nv_module={nv_exports:{}};'; - return wxsBeautify(code.slice(code.indexOf(before)+before.length,code.lastIndexOf('return nv_module.nv_exports;}')).replace(/nv\_/g,'')); + +function doWxs(code, name) { + name = name || ''; + name = name.substring(0, name.lastIndexOf('/') + 1); + const before = 'nv_module={nv_exports:{}};'; + return wxsBeautify(code.slice(code.indexOf(before) + before.length, code.lastIndexOf('return nv_module.nv_exports;}')).replace(eval('/' + ('p_' + name).replace(/\//g, '\\/') + '/g'), '').replace(/nv\_/g, '').replace(/(require\(.*?\))\(\)/g,'$1')); } -function doFrame(name,cb,order){ - let moreInfo=order.includes("m"); - wxsList={}; - wu.get(name,code=>{ - getZ(code,z=>{ - const before="\nvar nv_require=function(){var nnm="; - code=code.slice(code.indexOf(before)+before.length,code.lastIndexOf("if(path&&e_[path]){")); - json=code.slice(0,code.indexOf("};")+1); - let endOfRequire=code.indexOf("()\r\n")+4; - if(endOfRequire==4-1)endOfRequire=code.indexOf("()\n")+3; - code=code.slice(endOfRequire); - let rD={},rE={},rF={},requireInfo,x,vm=new VM({sandbox:{d_:rD,e_:rE,f_:rF,_vmRev_(data){ - [x,requireInfo]=data; - },nv_require(path){ - return ()=>path; - }}}); - vm.run(code+"\n_vmRev_([x,"+json+"])"); - let dir=path.dirname(name),pF=[]; - for(let info in rF)if(typeof rF[info]=="function"){ - let name=path.resolve(dir,(info[0]=='/'?'.':'')+info),ref=rF[info](); - pF[ref]=info; - wu.save(name,doWxs(requireInfo[ref].toString())); - } - for(let info in rF)if(typeof rF[info]=="object"){ - let name=path.resolve(dir,(info[0]=='/'?'.':'')+info); - let res=[],now=rF[info]; - for(let deps in now){ - let ref=now[deps](); - if(ref.includes(":"))res.push("\n"+doWxs(requireInfo[ref].toString())+"\n"); - else if(pF[ref])res.push(""); - else res.push(""); - wxsList[name]=res.join("\n"); - } - } - for(let name in rE)tryWxml(dir,name,rE[name].f.toString(),z,x,rD[name],wxsList,moreInfo); - cb({[name]:4}); - }); - }); + +function doFrame(name, cb, order, mainDir) { + let moreInfo = order.includes("m"); + wxsList = {}; + wu.get(name, code => { + getZ(code, z => { + const before = "\nvar nv_require=function(){var nnm="; + code = code.slice(code.lastIndexOf(before) + before.length, code.lastIndexOf("if(path&&e_[path]){")); + json = code.slice(0, code.indexOf("};") + 1); + let endOfRequire = code.indexOf("()\r\n") + 4; + if (endOfRequire == 4 - 1) endOfRequire = code.indexOf("()\n") + 3; + code = code.slice(endOfRequire); + let rD = {}, rE = {}, rF = {}, requireInfo = {}, x, vm = new VM({ + sandbox: { + d_: rD, e_: rE, f_: rF, _vmRev_(data) { + [x, requireInfo] = data; + }, nv_require(path) { + return () => path; + } + } + }); + let vmCode = code + "\n_vmRev_([x," + json + "])"; + vm.run(vmCode); + let dir = mainDir || path.dirname(name), pF = []; + for (let info in rF) if (typeof rF[info] == "function") { + let name = path.resolve(dir, (info[0] == '/' ? '.' : '') + info), ref = rF[info](); + pF[ref] = info; + wu.save(name, doWxs(requireInfo[ref].toString(), info)); + } + for (let info in rF) if (typeof rF[info] == "object") { + let name = path.resolve(dir, (info[0] == '/' ? '.' : '') + info); + let res = [], now = rF[info]; + for (let deps in now) { + let ref = now[deps](); + if (ref.includes(":")) res.push("\n" + doWxs(requireInfo[ref].toString()) + "\n"); + else if (pF[ref]) res.push(""); + else res.push(""); + wxsList[name] = res.join("\n"); + } + } + for (let name in rE) tryWxml(dir, name, rE[name].f.toString(), z, x, rD[name], wxsList, moreInfo); + cb({[name]: 4}); + }); + }); } -module.exports={doFrame:doFrame}; -if(require.main===module){ - wu.commandExecute(doFrame,"Restore wxml files.\n\n\n\n restore wxml file from page-frame.html or app-wxss.js."); + +module.exports = {doFrame: doFrame}; +if (require.main === module) { + wu.commandExecute(doFrame, "Restore wxml files.\n\n\n\n restore wxml file from page-frame.html or app-wxss.js."); } diff --git a/wuWxss.js b/wuWxss.js index 7322178..2586a5a 100644 --- a/wuWxss.js +++ b/wuWxss.js @@ -1,215 +1,285 @@ -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 +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'); +const cheerio = require('cheerio'); + +function doWxss(dir, cb, mainDir, nowDir) { + let saveDir = dir; + let isSubPkg = mainDir && mainDir.length > 0; + if (isSubPkg) { + saveDir = mainDir + } + + 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]); + + 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){ + + 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]; + 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; + 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 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; + 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); + } else res.push(content); + return res.join("") + attach; + } + + return () => { + cssFile = this.cssFile; + if (!result[cssFile]) result[cssFile] = ""; + result[cssFile] += makeup(data); }; } - 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}); + + function runVM(name, code) { + let wxAppCode = {}, handle = {cssFile: name}; + let vm = new VM({ + sandbox: Object.assign(new GwxCfg(), { + __wxAppCode__: wxAppCode, + setCssToHead: cssRebuild.bind(handle), + $gwx(path, global) { + + } + }) + }); + + // console.log('do css runVm: ' + name); vm.run(code); - for (let name in wxAppCode) { - if (name.endsWith(".wxss")) { - handle.cssFile = path.resolve(frameName, "..", name); - wxAppCode[name](); - } - } - } - function preRun(dir,frameFile,mainCode,files,cb){ + for (let name in wxAppCode) { + handle.cssFile = path.resolve(saveDir, name); + if (name.endsWith(".wxss")) { + wxAppCode[name](); + } + } + } + + 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")); - }); - } - } - function runOnce(){ - for(let name in runList)runVM(name,runList[name]); - } - 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"; + runList[path.resolve(dir, "./app.wxss")] = mainCode; + + for (let name of files) { + if (name != frameFile) { + wu.get(name, code => { + code = code.replace(/display:-webkit-box;display:-webkit-flex;/gm, ''); + code = code.slice(0, code.indexOf("\n")); + if (code.indexOf("setCssToHead(") > -1) { + let lastName = name; + let dirSplit = name.split(nowDir + '/'); + if (dirSplit.length > 1) { + lastName = path.resolve(saveDir, dirSplit[1]); + } + runList[lastName] = code.slice(code.indexOf("setCssToHead(")); + } + }); + } + } + } + + function runOnce() { + for (let name in runList) runVM(name, runList[name]); + } + + 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.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")){ + 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")){ + 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}`){ + 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; + ans = b; break; - }else if(yValue==`-${type}-${xValue}`){ + } else if (yValue == `-${type}-${xValue}`) { node.children.remove(b); - ans=a; + 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); + } 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; + if (ans === null) ans = b; } - list[son.property]=ans; - }else list[son.property]=item; + 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]){ + 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"); + 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__")); + wu.get(frameFile, code => { + code = code.replace(/display:-webkit-box;display:-webkit-flex;/gm, ''); + let scriptCode = code; + //extract script content from html + if (frameFile.endsWith(".html")) { + try { + const $ = cheerio.load(code); + scriptCode = [].join.apply($('html').find('script').map(function (item) { + return $(this).html(); + }, "\n")); + } catch (e) { + //ignore + } + } + + let window = { + screen: { + width: 720, + height: 1028, + orientation: { + type: 'vertical' + } + } + }; + let navigator = { + userAgent: "iPhone" + }; + + scriptCode = scriptCode.slice(scriptCode.lastIndexOf('window.__wcc_version__')); + let mainCode = 'window= ' + JSON.stringify(window) + + ';\nnavigator=' + JSON.stringify(navigator) + + ';\nvar __mainPageFrameReady__ = window.__mainPageFrameReady__ || function(){};var __WXML_GLOBAL__={entrys:{},defines:{},modules:{},ops:[],wxs_nf_init:undefined,total_ops:0};var __vd_version_info__=__vd_version_info__||{}' + + ";\n" + scriptCode; + + //remove setCssToHead function + mainCode = mainCode.replace('var setCssToHead = function', 'var setCssToHead2 = function'); + + code = code.slice(code.lastIndexOf('var setCssToHead = function(file, _xcInvalid')); + code = code.slice(code.lastIndexOf('\nvar _C= ') + 1); + + code = code.slice(0, code.indexOf('\n')); + let vm = new VM({sandbox: {}}); + pureData = vm.run(code + "\n_C"); + console.log("Guess wxss(first turn)..."); - preRun(dir,frameFile,mainCode,files,()=>{ - frameName=frameFile; - onlyTest=true; + 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)(); + 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(saveDir, "__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; + + console.log('saveDir: ' + saveDir); + for (let name in result) { + let pathFile = path.resolve(saveDir, wu.changeExt(name, ".wxss")); + wu.save(pathFile, 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\n\n restore wxss file from a unpacked directory(Have page-frame.html (or app-wxss.js) and other html file)."); + +module.exports = {doWxss: doWxss}; +if (require.main === module) { + wu.commandExecute(doWxss, "Restore wxss files.\n\n\n\n restore wxss file from a unpacked directory(Have page-frame.html (or app-wxss.js) and other html file)."); }