@gluestack-v2/framework-cli
Version:
Gluestack V2 Framework CLI
519 lines (518 loc) • 24 kB
JavaScript
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;
});