lowleveljs
Version:
1. 使用`@babel/parser`解析出js代码的语法树 2. 把所有的功能语句编译成最基础的操作指令列表 3. 编写解释器来运行这些基础操作指令
104 lines (99 loc) • 3.19 kB
JavaScript
// file参数支持三种类型:
// 1. content: Uint8Array/Buffer
// 2. Object{ content: Uint8Array/Buffer, filename: String }
// 3. filename: String
function run(maskstr, file, bindVars) {
let _bin, _filename
let isNode=typeof window==='undefined'
if(typeof file==='string' && isNode) {
_filename=file
_bin=require('fs').readFileSync(file)
}else if(file.constructor===Uint8Array || file.constructor===Array || (isNode && file.constructor===Buffer)) {
_bin=file
}else if(file.constructor===Object) {
const {content, filename}=file
_bin=content
_filename=filename
}
if(!_bin) {
throw new Error('no content input')
}
const top=isNode? (gg=>{
const path=require('path')
const workdir=process.cwd()
if(!_filename) {
_filename=path.resolve(workdir+'/index.js')
}
const _fn=path.resolve(_filename)
const _dir=path.parse(_fn).dir
const exports={}, module={exports}
return Object.assign(gg, {
__filename: _fn,
__dirname: _dir,
require: fn=>{
return require(require.resolve(fn, {
paths: [workdir, _dir],
}))
},
exports, module,
})
})(global): window
const runner=require(__dirname+'/libs/vm')
runner([_bin], bindVars, top, maskstr && (new TextEncoder).encode(maskstr))
return top
}
exports.run=run
exports.compile=(maskstr, code)=>{
const compile=require(__dirname+'/libs/compiler')
return compile(code, maskstr && (new TextEncoder).encode(maskstr))
}
exports.require_lljs=(...argv)=>{
return run(...argv).module.exports
}
// _compile(code, {repVars: 'T_', transform: 1, uglifyjs: 1, mask: 'xxx'})
exports._compile=(sourceCode, opts)=>{
let steps={}
if(opts.repVars) {
console.log('正在替换`'+opts.repVars+'`开头的变量..')
let T_vals={}, T_valsI=Date.now()%1e3
sourceCode=sourceCode.replace(new RegExp('\\b'+opts.repVars+'[a-z\\d_$]+\\b', 'ig'), a=>{
if(T_vals[a]) return T_vals[a]
T_valsI+=Math.random()*9+1|1
T_vals[a]=opts.repVars+T_valsI.toString(36)
return T_vals[a]
})
steps._afterRepVals=sourceCode
console.log(`替换结果:`)
console.log(T_vals)
}
if(opts.transform) {
console.log('正在转换为es5语法,并添加polyfill..')
const brc={
"plugins": [__dirname+"/node_modules/@babel/plugin-transform-async-to-generator"],
"presets": [
[
__dirname+"/node_modules/@babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": 2
}
]
]
}
sourceCode=require('@babel/core').transform(sourceCode, brc).code
steps._afterTransfrom=sourceCode
}
if(opts.uglifyjs) {
console.log('正在使用uglifyjs混淆代码..')
const UglifyJS=require("uglify-js")
sourceCode=UglifyJS.minify('(function() {\n'+sourceCode+'\n})()', {
output: {
beautify: opts.beautify? false: true,
},
}).code
steps._afterUglifyjs=sourceCode
}
const Ret=exports.compile(opts.mask, sourceCode)
Object.assign(Ret, steps)
return Ret
}