UNPKG

@gluestack-v2/framework-cli

Version:

Gluestack V2 Framework CLI

519 lines (518 loc) 24 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "events", "../writer", "../watcher", "prettier", "../file", "fs", "../getStorePath", "../meta/plugin-instances", "./factory/plugin/GluePluginStoreFactory", "../commander", "../../commands", "path", "../../constants/gluestack.v2", "../execute"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = __importDefault(require("events")); const writer_1 = __importDefault(require("../writer")); const watcher_1 = __importDefault(require("../watcher")); const prettier_1 = __importDefault(require("prettier")); const file_1 = require("../file"); const fs_1 = __importDefault(require("fs")); const getStorePath_1 = require("../getStorePath"); const plugin_instances_1 = require("../meta/plugin-instances"); const GluePluginStoreFactory_1 = __importDefault(require("./factory/plugin/GluePluginStoreFactory")); const commander_1 = __importDefault(require("../commander")); const commands_1 = __importDefault(require("../../commands")); const path_1 = require("path"); const gluestack_v2_1 = require("../../constants/gluestack.v2"); const execute_1 = require("../execute"); const sourceMap = require('source-map'); class AppCLI { constructor() { // @API: addCommand this.addCommand = (runner) => { this.commander.addCommand(this, runner); }; this.plugins = []; this.commander = commander_1.default; this.eventEmitter = new events_1.default.EventEmitter(); this.gluePluginStoreFactory = new GluePluginStoreFactory_1.default(); } populatePlugins(localPlugins) { return __awaiter(this, void 0, void 0, function* () { const plugins = yield (0, plugin_instances_1.getTopToBottomPluginInstanceTree)(this, process.cwd()); // boot plugins in npm let bootedPlugins = plugins.map(({ plugin }) => plugin); // boot plugins in local let bootedLocalPlugins = localPlugins.map((PluginClass) => { const that = this; const loadPlugins = (PluginClass) => { const p = new PluginClass(that); return new PluginClass(that, (0, getStorePath_1.injectPluginStore)(this, p.getName())); }; // @ts-ignore return loadPlugins(PluginClass); }); let mergedPlugins = bootedPlugins.concat(bootedLocalPlugins); // unique installed and local plugins mergedPlugins = [ ...new Map(mergedPlugins.map((item) => [item.getName(), item])).values(), ]; this.plugins = mergedPlugins; }); } initPlugins(localPlugins) { return __awaiter(this, void 0, void 0, function* () { yield this.populatePlugins(localPlugins); for (const plugin of this.plugins) { yield plugin.init(); } yield this.initPluginInstances(); }); } destroyPlugins() { return __awaiter(this, void 0, void 0, function* () { yield this.destroyPluginInstances(); for (const plugin of this.plugins) { yield plugin.destroy(); } }); } initPluginInstances() { return __awaiter(this, void 0, void 0, function* () { for (const plugin of this.plugins) { for (const instance of plugin.getInstances()) { yield instance.init(); } } }); } destroyPluginInstances() { return __awaiter(this, void 0, void 0, function* () { for (const plugin of this.plugins) { for (const instance of plugin.getInstances()) { yield instance.destroy(); } } }); } // @API: doctor doctor() { return __awaiter(this, void 0, void 0, function* () { // }); } prepare() { return __awaiter(this, void 0, void 0, function* () { (0, execute_1.executeSync)('sh', ['-c', `cd ${process.cwd()} && npm install --legacy-peer-deps`], { stdio: 'inherit', }); }); } // @API: dispatchEvent dispatchEvent(eventName, ...args) { this.eventEmitter.emit(eventName, ...args); } // @API: addEventListener addEventListener(eventName, callback = (...args) => { }) { this.eventEmitter.on(eventName, callback); } // @API: createPluginInstance createPluginInstance(plugin, instance, src, target) { return __awaiter(this, void 0, void 0, function* () { if (src && target) { yield (0, file_1.copyFolder)(src, target); } return (0, plugin_instances_1.attachPluginInstance)(this, plugin, instance, target ? target : ''); }); } // @API: getPluginByName getPluginByName(pluginName) { for (const plugin of this.plugins) { if (plugin.getName() === pluginName) { return plugin; } } return null; } // @API: getPlugins getPlugins() { return this.plugins; } // @API: getContainerTypePluginInstances getContainerTypePluginInstances(bottomToTop = false) { const instances = []; for (const plugin of this.plugins) { for (const instance of plugin.getInstances()) { if (!instance.isOfTypeInstance) { instances.push(instance); } } } if (bottomToTop) { return instances.reverse(); } return instances; } // @API: watch listen(cwd, pattern, callback) { watcher_1.default.watch(cwd, pattern, callback); } generateSourceMap(sourcePath, destinationPath) { const filePathExtension = (0, path_1.extname)(sourcePath); if (!['.ts', '.js'].includes(filePathExtension)) { return; } const generator = new sourceMap.SourceMapGenerator({ file: sourcePath, sourceRoot: '', }); // Add mapping const source = fs_1.default.readFileSync(sourcePath, 'utf8'); const lines = source.split('\n'); for (let i = 0; i < lines.length; i++) { const columns = lines[i].split(''); for (let j = 0; j < columns.length; j++) { generator.addMapping({ source: sourcePath, original: { line: i + 1, column: j }, generated: { line: i + 1, column: j }, }); } } const sourceMapString = generator.toString(); fs_1.default.writeFileSync(destinationPath + '.map', sourceMapString); fs_1.default.appendFileSync(destinationPath, `\n//# sourceMappingURL=${destinationPath}.map`); } removeSourceMap(destinationPath) { fs_1.default.rmSync(destinationPath + '.map'); } extractImports(jsString) { const importRegex = /import\s+([\w{},\s*]+)\s+from\s+['"](.+?)['"]/g; // Array to store the matched imports const imports = []; let match; while ((match = importRegex.exec(jsString)) !== null) { const importedNames = match[1] .split(',') .map((name) => name.trim()); const fromModule = match[2]; imports.push({ importedNames, fromModule }); } return imports; } updateConfigFile(instanceName, configType = 'index') { const configPath = (0, path_1.join)(process.cwd(), 'config', `${configType}.ts`); const importName = `${instanceName}${configType.charAt(0).toUpperCase() + configType.slice(1)}`; const data = fs_1.default.readFileSync(configPath, 'utf-8'); const newImport = `import ${importName} from '@project/${instanceName}-${configType}-sdk';\n`; const newProviderEntry = ` ${instanceName}: ${importName},`; const providers = this.getProvidersFromConfig(data); const existingImports = this.extractImports(data); let finalImports = ``; existingImports.map((val) => { if (!finalImports.includes(`import ${val.importedNames} from '${val.fromModule}';`)) finalImports += `import ${val.importedNames} from '${val.fromModule}';\n`; }); if (!finalImports.includes(newImport)) { finalImports += newImport; } // const modifiedContent = data.replace( // 'export const config = {', // `${newImport}\n$&` // ); // this.addProviderEntry( // modifiedContent, // newProviderEntry, // configPath // ); // ${providers?.map((provider) => { // return `${provider}\n`; // })}, // ${newProviderEntry} // console.log(data); if (!data.includes(newProviderEntry)) { let content = ` ${finalImports} export const config = { providers:{${providers === null || providers === void 0 ? void 0 : providers.map((provider) => { if (!provider.includes(newProviderEntry)) { return `${provider}\n`; } })} ${providers.length > 0 ? ',' : ''}${newProviderEntry}} };`; fs_1.default.writeFileSync(configPath, prettier_1.default.format(content, { parser: 'babel-ts', }), 'utf8'); } // Step 3: Write the modified content back to the file // fs.writeFileSync( // configPath, // prettier.format(content, { // parser: 'babel-ts', // }), // 'utf8' // ); // if (!data.includes(newProviderEntry)) { // this.addProviderEntry(data, newProviderEntry, configPath); // } else { // console.error('Provider entry already exists'); // } // if (!data.includes(newImport)) { // const modifiedContent = data.replace( // 'export const config = {', // `${newImport}\n$&` // ); // this.addProviderEntry( // modifiedContent, // newProviderEntry, // configPath // ); // } else { // console.error('Import already exists'); // } } getProvidersFromConfig(config) { // Regular expression to match the providers object content const providersRegex = /providers:\s*{([\s\S]*?)},/; // Find the providers content using regex const match = config.match(providersRegex); if (match) { const providersContent = match[1]; // Function to parse providersContent into a JavaScript object const parseProvidersObject = (str) => { const keyValuePairsRegex = /\s*([\w$]+)\s*:\s*([\w$]+)\s*,?/g; const providersObject = {}; let kvMatch; let providersArr = []; while ((kvMatch = keyValuePairsRegex.exec(str))) { providersArr.push(kvMatch[0]); const key = kvMatch[1]; const value = kvMatch[2]; // Check if the line is commented const commentRegex = new RegExp(`\\s*//.*${key}\\s*:`); if (commentRegex.test(str.substring(0, kvMatch.index))) { continue; // Ignore commented lines } providersObject[key] = value; } let finalArr = []; providersArr.map((val) => { if (typeof val === 'string' && val.length > 0 && val.includes(',')) { finalArr.push(val.replace(',', '')); } }); return finalArr; }; // Convert providersContent into a JavaScript object const providersObject = parseProvidersObject(providersContent); return providersObject; } else { console.error('Providers object not found in the given string.'); } } getGeneratedPackagePath(packageName) { return (0, path_1.join)(process.cwd(), gluestack_v2_1.GLUE_GENERATED_PACKAGES_PATH, packageName); } watch(source, destination, callback) { this.listen(source, ['./'], (event, path) => { const sourcePath = (0, path_1.join)(source, path); const destinationPath = (0, path_1.join)(destination, path); if (destination) { switch (event) { case 'add': fs_1.default.copyFileSync(sourcePath, destinationPath); this.generateSourceMap(sourcePath, destinationPath); break; case 'addDir': fs_1.default.mkdirSync(destinationPath, { recursive: true }); break; case 'change': fs_1.default.copyFileSync(sourcePath, destinationPath); this.generateSourceMap(sourcePath, destinationPath); break; case 'unlinkDir': fs_1.default.rmSync(destinationPath, { recursive: true }); break; case 'unlink': fs_1.default.rmSync(destinationPath); this.removeSourceMap(destinationPath); break; } } callback(event, path); }); } // @API: writer write(source, destination) { return __awaiter(this, void 0, void 0, function* () { yield writer_1.default.write(source, destination); }); } // @API: destroy destroy() { return __awaiter(this, void 0, void 0, function* () { // destroy all plugins yield this.destroyPlugins(); // close commander this.commander.destroy(); // save changes made into all stores this.gluePluginStoreFactory.saveAllStores(); }); } // @API: init init(localPlugins) { return __awaiter(this, void 0, void 0, function* () { // initialise the commander this.commander.init(); // initialise the local commands yield this.initLocalCommands(); // initialise all plugins yield this.initPlugins(localPlugins); }); } initLocalCommands() { return __awaiter(this, void 0, void 0, function* () { for (const command of (0, commands_1.default)()) { this.addCommand(command); } }); } updateServices(instanceWorkspacePath = '') { var _a, e_1, _b, _c; return __awaiter(this, void 0, void 0, function* () { const packagesPath = (0, path_1.join)(process.cwd(), gluestack_v2_1.GLUE_GENERATED_PACKAGES_PATH); const updatePackageInService = (servicePath) => __awaiter(this, void 0, void 0, function* () { if (yield (0, file_1.fileExists)(servicePath)) { (0, file_1.rm)((0, path_1.join)(servicePath, 'packages')); yield (0, file_1.copyFolder)(packagesPath, servicePath + '/packages'); } }); const servicesPath = this.getAllServicePaths(); if (instanceWorkspacePath) { yield updatePackageInService(instanceWorkspacePath); } else if (servicesPath.length > 0) { try { for (var _d = true, servicesPath_1 = __asyncValues(servicesPath), servicesPath_1_1; servicesPath_1_1 = yield servicesPath_1.next(), _a = servicesPath_1_1.done, !_a; _d = true) { _c = servicesPath_1_1.value; _d = false; const path = _c; let servicePath = (0, path_1.join)(path, '/src'); yield updatePackageInService(servicePath); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_d && !_a && (_b = servicesPath_1.return)) yield _b.call(servicesPath_1); } finally { if (e_1) throw e_1.error; } } } else { // console.log('No services found'); } }); } replaceTemplateValues(filePath, template, value) { return __awaiter(this, void 0, void 0, function* () { let data = fs_1.default.readFileSync(filePath, { encoding: 'utf-8' }); data = data.replace(template, value); fs_1.default.writeFileSync(filePath, data); }); } getAllServicePaths() { const servicesPath = (0, path_1.join)(process.cwd(), gluestack_v2_1.GLUE_GENERATED_SERVICES_PATH); if (!fs_1.default.existsSync(servicesPath)) { return []; } return fs_1.default .readdirSync(servicesPath, { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) .map((dirent) => (0, path_1.join)(servicesPath, dirent.name)); } getAllPackagePaths() { const packagesPath = (0, path_1.join)(process.cwd(), gluestack_v2_1.GLUE_GENERATED_PACKAGES_PATH); if (!fs_1.default.existsSync(packagesPath)) { return []; } return fs_1.default .readdirSync(packagesPath, { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) .map((dirent) => (0, path_1.join)(packagesPath, dirent.name)); } getAllServiceInstances() { let plugins = this.getPlugins(); let allInstances = []; for (const plugin of plugins) { allInstances.push(...plugin.getInstances()); } return allInstances.filter((instance) => instance._instanceType === 'service'); } updateNameInPackageJSON(packagePath, packageName) { return __awaiter(this, void 0, void 0, function* () { const packageJSONPath = (0, path_1.join)(packagePath, 'package.json'); yield (0, file_1.rewriteFile)(packageJSONPath, packageName, 'INSTANCENAME'); }); } // async updateDestinationPackageJSON() { // // update package.json'S name index with the new instance name // const pluginPackage = `${this._destinationPath}/package.json`; // await rewriteFile(pluginPackage, this.getName(), 'INSTANCENAME'); // } // async updateRootPackageJSONWithSourcePath() { // // update root package.json's workspaces with the new instance name // const rootPackage: string = `${process.cwd()}/package.json`; // await Workspaces.append( // rootPackage, // relative(process.cwd(), this._sourcePath) // ); // } // async updateRootPackageJSONWithDestinationPath() { // const rootPackage: string = `${process.cwd()}/package.json`; // await Workspaces.append( // rootPackage, // relative(process.cwd(), this._destinationPath) // ); // } createPackage(packageName, packageSourcePath) { return __awaiter(this, void 0, void 0, function* () { const packagePath = (0, path_1.join)(process.cwd(), gluestack_v2_1.GLUE_GENERATED_PACKAGES_PATH, packageName); if (packageSourcePath) { yield this.write(packageSourcePath, packagePath); } else { // FIX: Remove this path const packageTemplatePath = (0, path_1.join)(process.cwd(), 'node_modules', '@gluestack-v2/framework-cli', 'src', 'helpers', 'templates', 'package'); yield this.write(packageTemplatePath, packagePath); } yield this.updateNameInPackageJSON(packagePath, packageName); return packagePath; }); } } exports.default = AppCLI; });