/* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const fs = require('fs'); const path = require('path'); const readline = require('readline'); const babel = require('@babel/core'); /** * Babel configuration */ const babelConfig = { android: { comments: false, compact: false, }, ios: { presets: [ [ '@babel/env', { targets: { safari: '8', }, }, ], ], comments: false, compact: false, }, }; /** * Code header and content */ const CodePieces = { header() { return `/* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-${new Date().getFullYear()} THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "core/vm/native_source_code.h" #include "core/base/macros.h" // clang-format off namespace {`; }, android: { piece1: ` } // namespace namespace hippy { static const std::unordered_map global_base_js_source_map{ {"bootstrap.js", {k_bootstrap, arraysize(k_bootstrap) - 1}}, // NOLINT {"hippy.js", {k_hippy, arraysize(k_hippy) - 1}}, // NOLINT`, piece2: ` }; const NativeSourceCode GetNativeSourceCode(const std::string& filename) { const auto it = global_base_js_source_map.find(filename); return it != global_base_js_source_map.cend() ? it->second : NativeSourceCode{}; } } // namespace hippy `, }, ios: { piece1: ` } // namespace namespace hippy { const NativeSourceCode GetNativeSourceCode(const std::string& filename) { const std::unordered_map global_base_js_source_map{ {"bootstrap.js", {k_bootstrap, arraysize(k_bootstrap) - 1}}, // NOLINT {"hippy.js", {k_hippy, arraysize(k_hippy) - 1}}, // NOLINT`, piece2: ` }; const auto it = global_base_js_source_map.find(filename); return it != global_base_js_source_map.cend() ? it->second : NativeSourceCode{}; } } // namespace hippy `, }, }; /** * Initial the code git st buffer header and footer. */ const wrapperBeginBuffer = Buffer.from('(function(exports, require, internalBinding) {'); const wraperBeginByteArr = []; for (let i = 0; i < wrapperBeginBuffer.length; i += 1) { wraperBeginByteArr.push(wrapperBeginBuffer[i]); } const wrapperEndBuffer = Buffer.from('});'); const wraperEndByteArr = []; for (let i = 0; i < wrapperEndBuffer.length; i += 1) { wraperEndByteArr.push(wrapperEndBuffer[i]); } /** * Get the absolute full path * @param {string} relativePath - relative path */ function getAbsolutePath(relativePath) { return path.resolve(__dirname, relativePath); } /** * Get the core js files list for specific platform. * * @param {android|ios} platform - specific platform. */ function getAllRequiredFiles(platform) { return new Promise((resole) => { const rl = readline.createInterface({ input: fs.createReadStream(getAbsolutePath(`../core/js/entry/${platform}/hippy.js`)), }); const filePaths = [ getAbsolutePath('../core/js/bootstrap.js'), getAbsolutePath(`../core/js/entry/${platform}/hippy.js`), getAbsolutePath('../core/js/modules/ExceptionHandle.js'), ]; rl.on('line', (line) => { const lineSlice = line.split('//')[0]; if (lineSlice.indexOf('require(\'') > -1 || lineSlice.indexOf('require("') > -1) { const entry = line.split('(\'')[1].split('\')')[0]; filePaths.push(getAbsolutePath(`../core/js/entry/${platform}/${entry}`)); } }); rl.on('close', () => { resole(filePaths); }); }); } /** * Read the file content to be a buffer. * * @param {android|ios} platform - specific platform. * @param {string} filePath - the file path will read. */ function readFileToBuffer(platform, filePath) { switch (platform) { case 'ios': case 'android': { const code = fs.readFileSync(filePath).toString(); const compiled = babel.transform(code, babelConfig[platform]); return Buffer.from(compiled.code); } default: return null; } } /** * Read the js files and generate the core cpp files. * * @param {android|ios} platform - specific platform. * @param {string} buildDirPath - output directory. */ function generateCpp(platform, buildDirPath) { let code = CodePieces.header(platform); getAllRequiredFiles(platform).then((filesArr) => { filesArr.forEach((filePath) => { const fileName = path.basename(filePath, '.js'); const fileBuffer = readFileToBuffer(platform, filePath); const byteArr = []; for (let i = 0; i < fileBuffer.length; i += 1) { byteArr.push(fileBuffer[i]); } if (fileName === 'bootstrap' || fileName === 'ExceptionHandle') { code += ` const uint8_t k_${fileName}[] = { ${byteArr.join(',')},0 }; // NOLINT`; } else { code += ` const uint8_t k_${fileName}[] = { ${wraperBeginByteArr.join(',')},${byteArr.join(',')},${wraperEndByteArr.join(',')},0 }; // NOLINT`; } }); code += CodePieces[platform].piece1; for (let i = 2; i < filesArr.length; i += 1) { const fileName = path.basename(filesArr[i], '.js'); code += ` {"${fileName}.js", {k_${fileName}, arraysize(k_${fileName}) - 1}}, // NOLINT`; } code += CodePieces[platform].piece2; const targetPath = `${buildDirPath}/native_source_code_${platform}.cc`; fs.writeFile(targetPath, code, (err) => { if (err) { /* eslint-disable-next-line no-console */ console.log('[writeFile error] : ', err); return; } /* eslint-disable-next-line no-console */ console.log(`${platform} convert success, output ${targetPath}`); }); }); } // Start to work generateCpp('ios', getAbsolutePath('../core/src/vm/jsc/')); generateCpp('android', getAbsolutePath('../core/src/vm/v8/'));