diff --git a/README.md b/README.md index de4f562..3783b96 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,61 @@ The WBC file is a specially designed binary file that contains pre-compiled Java npm install @openwebf/wbc --save ``` -## Usage +## Cli Usage + +**Install** +``` +npm install @openwebf/wbc -g +``` + +**Convert JavaScript Into WBC file** + +``` +wbc -s /tmp/index.js -d /tmp +``` + +**Transform Inline Scripts in HTML** + +``` +wbc -s ./demo.html -d ./demo_wbc.html --convert-html +``` + +## Node Usage + +**Convert JavaScript Into WBC buffer** + +```javascript +const { compileJavaScriptToWbc } = require('@openwebf/wbc'); + +compileJavaScriptToWbc('function hello() { return 1 + 1};'); // the WBC bytes +``` + +**Transform Inline JavaScript Codes into WBC** ```javascript -const WBC = require('@openwebf/wbc'); -const wbc = new WBC(); +const { transformInlineScriptToWbc } = require('@openwebf/wbc'); + +const transformedHtml = transformInlineScriptToWbc(` + + + + + + +`); + +console.log(transformedHtml); /* + + + + + +*/ -// Dump bytecode from javascript source; -wbc.compile('function hello() { return 1 + 1};'); // ``` ## Contribute diff --git a/bin/wbc.js b/bin/wbc.js index 30c5a58..f39fd31 100755 --- a/bin/wbc.js +++ b/bin/wbc.js @@ -1,10 +1,9 @@ #!/usr/bin/env node -const Wbc = require('./wbc_lib').Wbc; const path = require('path'); const fs = require('fs'); const { program } = require('commander'); const packageConfig = require('../package.json'); -const Qjsc = require('../index'); +const { compileJavaScriptToWbc, transformInlineScriptToWbc, legacyCompileJavaScriptToKBC } = require('../index'); program .version(packageConfig.version) @@ -12,6 +11,7 @@ program .requiredOption('-s, --source ', 'the Javascript source file path') .requiredOption('-d, --dist ', 'the generated bytecode file path') .option('--legacy_kbc1', 'generate legacy kbc1 file, (compact with openkraken project)') + .option('--convert-html', 'Given an HTML string as input, convert all inline JavaScript code to WBC format.') .parse(process.argv); let options = program.opts(); @@ -30,21 +30,21 @@ if (!path.isAbsolute(dist)) { dist = path.join(process.cwd(), dist); } -const qjsc = new Qjsc(); - const sourceFileName = source.split('/').slice(-1)[0].split('.')[0]; -const sourceCode = fs.readFileSync(source, {encoding: 'utf-8'}); - -let buffer = qjsc.compile(sourceCode); - -if (type == 'kbc1') { - let distPath = path.join(dist, sourceFileName + '.kbc1'); - fs.writeFileSync(distPath, buffer); - console.log('Quickjs bytecode generated kbc1 at: \n' + distPath); -} else if (type == 'wbc') { - const wbc = new Wbc(); - let wbcBytecode = wbc.generateWbcBytecode(buffer); - let distPath = path.join(dist, sourceFileName + '.wbc1'); - fs.writeFileSync(distPath, wbcBytecode); - console.log('Quickjs bytecode generated wbc1 at: \n' + distPath); +const sourceCode = fs.readFileSync(source, { encoding: 'utf-8' }); + +if (options.convertHtml) { + const output = transformInlineScriptToWbc(sourceCode); + fs.writeFileSync(dist, output); + console.log('Quickjs bytecode generated wbc1 at: \n' + dist); +} else { + if (type == 'kbc1') { + let distPath = path.join(dist, sourceFileName + '.kbc1'); + fs.writeFileSync(distPath, legacyCompileJavaScriptToKBC(sourceCode)); + console.log('Quickjs bytecode generated kbc1 at: \n' + distPath); + } else if (type == 'wbc') { + let distPath = path.join(dist, sourceFileName + '.wbc1'); + fs.writeFileSync(distPath, compileJavaScriptToWbc(sourceCode)); + console.log('Quickjs bytecode generated wbc1 at: \n' + distPath); + } } diff --git a/demo.html b/demo.html new file mode 100644 index 0000000..b2a9e19 --- /dev/null +++ b/demo.html @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/html_converter.js b/html_converter.js new file mode 100644 index 0000000..cd3ed46 --- /dev/null +++ b/html_converter.js @@ -0,0 +1,25 @@ +const jsdom = require("jsdom"); +const { JSDOM } = jsdom; +const Qjsc = require('./qjsc'); +const { Wbc } = require('./wbc'); + +function parseAndConvertHTML(html, version = '1') { + let dom = new JSDOM(html); + const scripts = dom.window.document.querySelectorAll('script'); + + [].slice.call(scripts).forEach(script => { + const textContent = script.textContent; + if (textContent.length == 0) return; + const qjsc = new Qjsc(); + const wbc = new Wbc(); + const buffer = qjsc.compile(textContent); + let wbcBytecode = wbc.generateWbcBytecode(buffer); + let code = wbcBytecode.toString('binary'); + script.textContent = code; + }) + + return dom.window.document.documentElement.outerHTML; +} + + +module.exports = parseAndConvertHTML; \ No newline at end of file diff --git a/index.js b/index.js index 9f1ae72..fced9a2 100644 --- a/index.js +++ b/index.js @@ -1,33 +1,24 @@ -const supportedVersions = ['1']; +const { Wbc } = require('./wbc'); +const Qjsc = require('./qjsc'); +const parseAndConvertHTML = require('./html_converter'); -class Qjsc { - constructor(options = {}) { - let version = options.version || '1'; - if (supportedVersions.indexOf(version) === -1) { - throw new Error('Unsupported WBC version: ' + version); - } - this._bindings = require('node-gyp-build')(__dirname); - } - help() { - console.log('Supported WBC versions: ' + supportedVersions.join(', ')); - } - - getSupportedVersions() { - return supportedVersions; - } - - compile(code, options = {}) { - let sourceURL = options.sourceURL || 'internal://'; - return this._bindings.dumpByteCode(code, sourceURL); - } +function compileJavaScriptToWbc(code, version = '1') { + const qjsc = new Qjsc({version: version}); + const wbc = new Wbc(); + const quickjsBuffer = qjsc.compile(code); + let wbcBytecode = wbc.generateWbcBytecode(quickjsBuffer); + return wbcBytecode; +} - get version() { - return this._bindings.version; - } +function legacyCompileJavaScriptToKBC(code) { + const qjsc = new Qjsc(); + return qjsc.compile(code); +} - _evalByteCode(buffer) { - return this._bindings.evalByteCode(buffer); - } +function transformInlineScriptToWbc(html, version = '1') { + return parseAndConvertHTML(html, version); } -module.exports = Qjsc; +exports.compileJavaScriptToWbc = compileJavaScriptToWbc; +exports.transformInlineScriptToWbc = transformInlineScriptToWbc; +exports.legacyCompileJavaScriptToKBC = legacyCompileJavaScriptToKBC; \ No newline at end of file diff --git a/package.json b/package.json index 3405eaa..3e3ee04 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "bindings": "^1.5.0", "commander": "^8.2.0", "crc32": "^0.2.2", + "jsdom": "^24.0.0", "lz4": "^0.6.5", "nan": "^2.15.0", "node-addon-api": "^4.1.0", diff --git a/qjsc.js b/qjsc.js new file mode 100644 index 0000000..9f1ae72 --- /dev/null +++ b/qjsc.js @@ -0,0 +1,33 @@ +const supportedVersions = ['1']; + +class Qjsc { + constructor(options = {}) { + let version = options.version || '1'; + if (supportedVersions.indexOf(version) === -1) { + throw new Error('Unsupported WBC version: ' + version); + } + this._bindings = require('node-gyp-build')(__dirname); + } + help() { + console.log('Supported WBC versions: ' + supportedVersions.join(', ')); + } + + getSupportedVersions() { + return supportedVersions; + } + + compile(code, options = {}) { + let sourceURL = options.sourceURL || 'internal://'; + return this._bindings.dumpByteCode(code, sourceURL); + } + + get version() { + return this._bindings.version; + } + + _evalByteCode(buffer) { + return this._bindings.evalByteCode(buffer); + } +} + +module.exports = Qjsc; diff --git a/bin/wbc_lib.js b/wbc.js similarity index 98% rename from bin/wbc_lib.js rename to wbc.js index 248bb4e..8b6aadb 100644 --- a/bin/wbc_lib.js +++ b/wbc.js @@ -31,7 +31,7 @@ const HEADER_FIELDS = [ class Wbc { constructor(options = {}) { - const rootDir = path.resolve(__dirname, '..'); + const rootDir = path.resolve(__dirname, '.'); this._bindings = require('node-gyp-build')(rootDir); }