UNPKG

@bernhste/obfuscator-io-metro-plugin

Version:

A metro plugin to use javascript-obfuscator library with react-native

132 lines (124 loc) 3.65 kB
const readline = require('readline'); const {Command} = require('commander'); const {Readable} = require('stream'); const { EXTS, END_ANNOTATION, BEG_ANNOTATION, BUNDLE_OUTPUT_CLI_ARG, BUNDLE_SOURCEMAP_OUTPUT_CLI_ARG, BUNDLE_DEV_CLI_ARG, BUNDLE_CMD } = require('./constants'); /** * Only 'bundle' command triggers obfuscation. * Development bundles will be ignored (--dev true). Use JSO_METRO_DEV to override this behaviour. * @returns {string} skip reason. If falsy value dont skip obfuscation */ function skipObfuscation({ runInDev }) { let isBundleCmd = false; const command = new Command(); command .command(BUNDLE_CMD) .allowUnknownOption() .action(() => (isBundleCmd = true)); command.option(`${BUNDLE_DEV_CLI_ARG} <boolean>`).parse(process.argv); if (!isBundleCmd) { return 'Not a *bundle* command'; } if (command.dev === 'true') { return ( !runInDev && 'Development mode. Override with JSO_METRO_DEV=true environment variable' ); } return null; } /** * Get bundle path based CLI arguments * @returns {{bundlePath: string, bundleSourceMapPath: string}} * @throws {Error} when bundle output was not found */ function getBundlePath() { const command = new Command(); command .option(`${BUNDLE_OUTPUT_CLI_ARG} <string>`) .option(`${BUNDLE_SOURCEMAP_OUTPUT_CLI_ARG} <string>`) .parse(process.argv); if (command.bundleOutput) { return { bundlePath: command.bundleOutput, bundleSourceMapPath: command.sourcemapOutput }; } console.error('Bundle output path not found.'); return process.exit(-1); } /** * Strip all tags from code * @param {string} code * @returns {string} */ function stripTags(code) { return code.replace(new RegExp(BEG_ANNOTATION, 'g'), '') .replace(new RegExp(END_ANNOTATION, 'g'), '') } /** * When next character is a new line (\n or \r\n), * we should increment startIndex to avoid user code starting with a new line. * @param {string} startIndex * @param {string} code * @returns {number} * @example * __d(function(g,r,i,a,m,e,d){(detect new line here and start below) * // user code * ... * } */ function shiftStartIndexOnNewLine(startIndex, code) { switch (code[startIndex + 1]) { case '\r': startIndex++; return shiftStartIndexOnNewLine(startIndex, code); case '\n': startIndex++; break; } return startIndex; } /** * Wrap user code with TAGS {BEG_ANNOTATION and END_ANNOTATION} * @param {{code: string}} data */ function wrapCodeWithTags(data) { let startIndex = data.code.indexOf('{'); const endIndex = data.code.lastIndexOf('}'); startIndex = shiftStartIndexOnNewLine(startIndex, data.code); const init = data.code.substring(0, startIndex + 1); const clientCode = data.code.substring(startIndex + 1, endIndex); const end = data.code.substr(endIndex, data.code.length); data.code = init + BEG_ANNOTATION + clientCode + END_ANNOTATION + end; } /** * @param {string} path * @param {string} projectRoot * @returns {string} undefined if path is empty or invalid * * @example * <project_root>/react-native0.59-grocery-list/App/index.js -> App/index.js * <project_root>/react-native0.59-grocery-list/App/index.ts -> App/index.js */ function buildNormalizePath(path, projectRoot) { if (typeof path !== 'string' || path.trim().length === 0) { return; } const relativePath = path.replace(projectRoot, ''); return relativePath.replace(EXTS, '.js').substring(1 /* remove '/' */); } module.exports = { skipObfuscation, getBundlePath, stripTags, wrapCodeWithTags, buildNormalizePath }