UNPKG

@plurid/joiner

Version:
1,309 lines (1,261 loc) 65.9 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var commander = require('commander'); var os = require('os'); var path = require('path'); var child_process = require('child_process'); var fetch = require('cross-fetch'); var fs = require('fs'); var Deon = require('@plurid/deon'); require('crypto'); var yaml = require('js-yaml'); var worker_threads = require('worker_threads'); var checkUpdates = require('npm-check-updates'); var alphaVersioning = require('alpha-versioning'); var http = require('http'); var ncp = require('ncp'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var os__default = /*#__PURE__*/_interopDefaultLegacy(os); var path__default = /*#__PURE__*/_interopDefaultLegacy(path); var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); var Deon__default = /*#__PURE__*/_interopDefaultLegacy(Deon); var yaml__default = /*#__PURE__*/_interopDefaultLegacy(yaml); var checkUpdates__default = /*#__PURE__*/_interopDefaultLegacy(checkUpdates); var http__default = /*#__PURE__*/_interopDefaultLegacy(http); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __awaiter(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()); }); } // #region imports // #endregion libraries // #endregion imports // #region module const homeDirectory = os__default["default"].homedir(); const JOINER_CONFIGURATION_FILE = '.joiner.config.deon'; const joinerConfigurationPath = path__default["default"].join(homeDirectory, JOINER_CONFIGURATION_FILE); const JOINER_CLI_VERSION = "0.0.0-6"; const MANUAL_JOINER = 'https://manual.plurid.com/joiner'; // #endregion module // #endregion libraries // #endregion imports // #region module const fileExists = (path) => __awaiter(void 0, void 0, void 0, function* () { return !!(yield fs.promises.stat(path).catch(e => false)); }); /** * Source: https://stackoverflow.com/a/57335271 * * @param callback Function to be called. * @param wait Debounce time. */ function debouncedCallback(callback, wait) { // track args & timeout handle between calls let argsRef; let timeout; function cleanup() { if (timeout) { clearTimeout(timeout); } } return function debouncedCallback(...args) { // capture latest args argsRef = args; // clear debounce timer cleanup(); // start waiting again timeout = setTimeout(() => { if (argsRef) { callback(...argsRef); } }, wait); }; } const resolveAbsolutePath = (value) => { const resolvedPath = path__default["default"].isAbsolute(value) ? value : path__default["default"].join(process.cwd(), value); return resolvedPath; }; // #endregion module // #endregion external // #endregion imports // #region module const updateConfigurationFile = (data) => __awaiter(void 0, void 0, void 0, function* () { try { const deon = new Deon__default["default"](); const exists = yield fileExists(joinerConfigurationPath); if (!exists) { yield fs.promises.writeFile(joinerConfigurationPath, ''); } const dataInFile = yield fs.promises.readFile(joinerConfigurationPath, 'utf-8'); const deonDataInFile = yield deon.parse(dataInFile); const newData = Object.assign(Object.assign({}, deonDataInFile), data); const newDataString = deon.stringify(newData); yield fs.promises.writeFile(joinerConfigurationPath, newDataString); return true; } catch (error) { console.log('error', error); return false; } }); const readConfigurationFile = () => __awaiter(void 0, void 0, void 0, function* () { const exists = yield fileExists(joinerConfigurationPath); if (!exists) { yield fs.promises.writeFile(joinerConfigurationPath, ''); return {}; } const data = yield fs.promises.readFile(joinerConfigurationPath, 'utf-8'); const deon = new Deon__default["default"](); const ownerData = yield deon.parse(data); return Deon.typer(ownerData); }); // #endregion exports // #endregion libraries // #endregion imports // #region module const serverStart = () => __awaiter(void 0, void 0, void 0, function* () { const out = fs__default["default"].openSync('./out.log', 'a'); const error = fs__default["default"].openSync('./out.log', 'a'); /** * Start the server from the package root. */ const spawnedChild = child_process.spawn('node', [ './distribution/dashboard/index.js', ], { cwd: path__default["default"].dirname(__dirname), stdio: [ 'ignore', out, error, ], detached: true, }); const { pid, } = spawnedChild; const port = yield new Promise((resolve, _) => { setTimeout(() => __awaiter(void 0, void 0, void 0, function* () { const outFile = yield fs.promises.readFile('./out.log', 'utf-8'); fs.promises.unlink('./out.log'); const re = /http:\/\/localhost:(\d+)/; const match = outFile.match(re); if (match) { resolve(match[1]); return; } resolve(''); }), 2000); }); spawnedChild.unref(); const parsedPort = parseInt(port); if (!parsedPort) { return; } return { pid, port: parsedPort, }; }); // #endregion exports // #endregion internal // #endregion imports // #region module const verifyDashboard = (address) => __awaiter(void 0, void 0, void 0, function* () { try { const response = yield fetch__default["default"](address); if (response.status !== 200) { return false; } return true; } catch (error) { return false; } }); const dashboardStatus = () => __awaiter(void 0, void 0, void 0, function* () { const configurationFile = yield readConfigurationFile(); const { dashboard, } = configurationFile; if (!(dashboard === null || dashboard === void 0 ? void 0 : dashboard.port) || !(dashboard === null || dashboard === void 0 ? void 0 : dashboard.pid)) { console.log(`\n\tJoiner dashboard not started.\n`); return; } const dashboardAdress = `http://localhost:${dashboard.port}`; const dashboardActive = yield verifyDashboard(dashboardAdress); if (!dashboardActive) { // Clean dashboard metadata since process is no longer active. const updatedConfigurationFile = { dashboard: undefined, }; yield updateConfigurationFile(updatedConfigurationFile); console.log(`\n\tJoiner dashboard not started.\n`); return; } console.log(`\n\tJoiner dashboard started on ${dashboardAdress}\n`); }); const dashboardStart = () => __awaiter(void 0, void 0, void 0, function* () { const configurationFile = yield readConfigurationFile(); if (configurationFile === null || configurationFile === void 0 ? void 0 : configurationFile.dashboard) { const dashboardAdress = `http://localhost:${configurationFile.dashboard.port}`; const dashboardActive = yield verifyDashboard(dashboardAdress); if (dashboardActive) { console.log(`\n\tJoiner dashboard already started on ${dashboardAdress}\n`); return; } else { // Clean dashboard metadata since process is no longer active. const updatedConfigurationFile = { dashboard: undefined, }; yield updateConfigurationFile(updatedConfigurationFile); } } const data = yield serverStart(); if (!data) { return; } const { pid, port, } = data; const updatedConfigurationFile = { dashboard: { pid, port, }, }; yield updateConfigurationFile(updatedConfigurationFile); console.log(`\n\tJoiner dashboard started on http://localhost:${port}\n`); }); const dashboardStop = () => __awaiter(void 0, void 0, void 0, function* () { try { const configurationFile = yield readConfigurationFile(); const { dashboard, } = configurationFile; if (!dashboard) { console.log(`\n\tJoiner dashboard not started.\n`); return; } try { const killCommand = `kill -9 ${dashboard.pid}`; child_process.execSync(killCommand); } catch (error) { // continue } const updatedConfigurationFile = { dashboard: undefined, }; yield updateConfigurationFile(updatedConfigurationFile); console.log(`\n\tJoiner dashboard stopped on port ${dashboard.port}.\n`); } catch (error) { console.log(`\n\tSomething went wrong.\n`); } }); const dashboardRegister = (options) => __awaiter(void 0, void 0, void 0, function* () { try { const configurationFile = yield readConfigurationFile(); const pathValue = resolveAbsolutePath(options.path); const paths = [ ...(configurationFile.paths || []), pathValue, ]; yield updateConfigurationFile({ paths, }); console.log(`\n\t${options.path} registered.\n`); } catch (error) { console.log(`\n\tSomething went wrong.\n`); } }); const dashboardDeregister = (options) => __awaiter(void 0, void 0, void 0, function* () { try { const configurationFile = yield readConfigurationFile(); const paths = [ ...(configurationFile.paths || []), ]; const pathValue = resolveAbsolutePath(options.path); const updatedPaths = paths.filter(path => path !== pathValue); yield updateConfigurationFile({ paths: updatedPaths, }); console.log(`\n\t${options.path} deregistered.\n`); } catch (error) { console.log(`\n\tSomething went wrong.\n`); } }); // #endregion exports // #endregion external // #endregion imports // #region module const resolveCommand = (value) => { if (!value) { return 'start'; } const cleanValue = value.toLowerCase().trim(); if (cleanValue === 'status' || cleanValue === 'start' || cleanValue === 'stop' || cleanValue === 'register' || cleanValue === 'deregister') { return cleanValue; } return; }; const dashboardCommand = (value, options) => __awaiter(void 0, void 0, void 0, function* () { const command = resolveCommand(value); if (!command) { console.log(`Dashboard command '${value}' is not adequate.`); return; } switch (command) { case 'status': yield dashboardStatus(); break; case 'start': yield dashboardStart(); break; case 'stop': yield dashboardStop(); break; case 'register': yield dashboardRegister(options); break; case 'deregister': yield dashboardDeregister(options); break; } }); // #endregion exports // #endregion external // #endregion imports // #region module const deonDefaultConfiguration = `// uncomment and add paths to packages { packages [ // /path/to/package // /path/to/multiple-packages/* ] package { manager yarn publisher npm ignore [] } yarnWorkspace false commit { engine git combine false root /path/to/root fullFolder false divider ' > ' message setup: package } runFrom '' development { watchPackages all serverPort 55000 watchDirectories [ build distribution dist ] externalPackages [] } } `; const yamlDefaultConfiguration = `--- # uncomment and add paths to packages packages: # - /path/to/package # - /path/to/multiple-packages/* package: manager: yarn publisher: npm ignore: [] yarnWorkspace: false commit: engine: git combine: false root: '/path/to/root' fullFolder: false divider: ' > ' message: 'setup: package' runFrom: '' development: watchPackages: all serverPort: 55000 watchDirectories: ['build', 'distribution', 'dist'] externalPackages: [] `; const initializeCommand = (type) => __awaiter(void 0, void 0, void 0, function* () { const filename = type === 'deon' ? 'joiner.deon' : 'joiner.yaml'; const joinerPath = path__default["default"].join(process.cwd(), filename); const joinerContent = type === 'deon' ? deonDefaultConfiguration : yamlDefaultConfiguration; if (!(yield fileExists(joinerPath))) { yield fs.promises.writeFile(joinerPath, joinerContent); console.log(`\n\tJoiner initialized in root path:\n\n\t${process.cwd()}\n`); } else { console.log(`\n\tJoiner already initialized. File '${filename}' exists in path:\n\n\t${process.cwd()}\n`); } }); // #endregion exports // #endregion external // #endregion imports // #region module const resolvePackage = (packageName, configurationData) => { const { packages, } = configurationData; const safePackageName = packageName.toLowerCase(); if (safePackageName === 'all' || safePackageName === '*') { return packages; } if (safePackageName === 'self') { // The joiner file resolves to only one package. const codePackage = packages[0]; if (!codePackage) { console.log(`\n\tPackage ${packageName} could not be resolved.\n`); return; } return [ packages[0], ]; } if (safePackageName.startsWith('%')) { // The package is a numeric value, e.g. '%0', or '%12'. const value = parseInt(safePackageName.replace('%', '')) || 0; const codePackage = packages[value]; if (!codePackage) { console.log(`\n\tPackage ${packageName} could not be resolved.\n`); return; } return [ codePackage, ]; } for (const codePackage of packages) { if (codePackage.name.toLowerCase() === safePackageName || codePackage.alias.toLowerCase() === safePackageName) { return [ codePackage, ]; } } console.log(`\n\tPackage ${packageName} could not be resolved.\n`); return; }; const locatePackages = (packages, yarnWorkspace, runFrom, packageIgnore) => __awaiter(void 0, void 0, void 0, function* () { if (!packages && !yarnWorkspace) { return []; } const packagesPaths = yield resolvePackagesPaths(packages, yarnWorkspace, runFrom); const locatedPackages = []; for (const packagePath of packagesPaths) { if (!packagePath.includes('/*')) { const packageAbsolutePath = path__default["default"].join(runFrom, packagePath); const locatedPackage = yield readPackageFile(packageAbsolutePath, packageIgnore); if (locatedPackage) { locatedPackages.push(locatedPackage); } } else { const packagesRoot = packagePath.replace('/*', ''); const packagesRootPath = path__default["default"].join(runFrom, packagesRoot); try { const rootFiles = yield fs.promises.readdir(packagesRootPath); for (const rootFile of rootFiles) { const packagePath = path__default["default"].join(packagesRootPath, rootFile); const statistics = yield fs.promises.stat(packagePath); if (statistics.isDirectory()) { const locatedPackage = yield readPackageFile(packagePath, packageIgnore); if (locatedPackage) { locatedPackages.push(locatedPackage); } } } } catch (error) { console.log(`\n\tPackages root ${packagesRootPath} could not be resolved.\n`); } } } const filteredPackagesByName = locatedPackages.filter(locatedPackage => !packageIgnore.includes(locatedPackage.name)); const filteredPackagesByPath = filteredPackagesByName.filter((filterablePackage) => { for (const packageIgnored of packageIgnore) { if (filterablePackage.path.includes(packageIgnored)) { return false; } } return true; }); return filteredPackagesByPath; }); const resolvePackagesPaths = (packages, yarnWorkspace, runFrom) => __awaiter(void 0, void 0, void 0, function* () { if (!yarnWorkspace) { return packages; } try { const packageJSONPath = path__default["default"].join(runFrom, 'package.json'); const packageRawData = yield fs.promises.readFile(packageJSONPath, 'utf-8'); const packageData = JSON.parse(packageRawData); const workspaces = packageData.workspaces || []; return workspaces; } catch (error) { console.log(`\n\tCould not read the workspaces in the package.json from:\n\t${process.cwd()}\n`); return []; } }); const readPackageFile = (packagePath, packageIgnore) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c, _d; try { const packageJSONPath = path__default["default"].join(packagePath, 'package.json'); const packageRawData = yield fs.promises.readFile(packageJSONPath, 'utf-8'); const packageData = JSON.parse(packageRawData); const packageName = (_a = packageData.name) !== null && _a !== void 0 ? _a : ''; const packageAlias = computePackageAlias(packageName); const packageVersion = (_b = packageData.version) !== null && _b !== void 0 ? _b : '0.0.0'; const packagePrivate = (_c = packageData.private) !== null && _c !== void 0 ? _c : false; const locatedPackage = { path: packagePath, name: packageName, alias: packageAlias, version: packageVersion, private: packagePrivate, joinerpackage: false, }; return locatedPackage; } catch (error) { try { const packageJoinerPath = path__default["default"].join(packagePath, 'joiner.package.yaml'); const packageRawData = yield fs.promises.readFile(packageJoinerPath, 'utf-8'); const packageData = yaml__default["default"].load(packageRawData); const packageName = (_d = packageData === null || packageData === void 0 ? void 0 : packageData.name) !== null && _d !== void 0 ? _d : ''; const packageAlias = computePackageAlias(packageName); const locatedPackage = { path: packagePath, name: packageName, alias: packageAlias, version: '0.0.0', private: true, joinerpackage: true, }; return locatedPackage; } catch (error) { let ignored = false; for (const packageIgnored of packageIgnore) { if (packagePath.includes(packageIgnored)) { ignored = true; } } if (!ignored) { console.log(`\n\tCould not read the package from:\n\t${packagePath}\n`); } return; } } }); /** * Extract from the package `name` the package `alias`. * * e.g. * * `@scope/one.two.three` -> `three` * * `one-two` -> `one-two` * * @param name */ const computePackageAlias = (name) => { const noScope = name.replace(/@\w+\//, ''); const split = noScope.split('.'); const lastWord = split[split.length - 1]; return lastWord; }; const resolveWatchedPackages = (packages, watchPackages) => { const allPackages = packages.map(workPackage => workPackage.name); if (!watchPackages) { return [ ...allPackages, ]; } if (typeof watchPackages === 'string') { if (watchPackages.toLowerCase() === 'all') { return [ ...allPackages, ]; } const watchPackage = packages.find(workPackage => workPackage.name === watchPackages); if (!watchPackage) { return []; } return [watchPackage.name]; } const resolvedWatchPackages = []; for (const watchPackage of watchPackages) { for (const workPackage of packages) { if (watchPackage === workPackage.name) { resolvedWatchPackages.push(watchPackage); break; } } } return resolvedWatchPackages; }; // #endregion module // #endregion external // #endregion imports // #region module const parseConfigurationFile = (configurationFile) => __awaiter(void 0, void 0, void 0, function* () { try { const configurationFilepath = configurationFile.startsWith('/') ? configurationFile : path__default["default"].join(process.cwd(), configurationFile); const configurationFileData = yield fs.promises.readFile(configurationFilepath, 'utf-8'); const extension = path__default["default"].extname(configurationFile); if (extension === Deon.DEON_FILENAME_EXTENSION) { const deon = new Deon__default["default"](); const data = yield deon.parse(configurationFileData, { filebase: path__default["default"].dirname(configurationFilepath), }); return yield handleParsedConfigurationFile(data, configurationFilepath); } const parsedData = yaml__default["default"].load(configurationFileData); return yield handleParsedConfigurationFile(parsedData, configurationFilepath); } catch (error) { console.log(`\n\tConfiguration file required.\n\n\tCheck the file '${configurationFile}' exists on the rootpath:\n\t${process.cwd()}\n`); return; } }); const handleParsedConfigurationFile = (parsedData, configurationFilepath) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3; const packageName = parsedData.name || ''; const packageManager = (_b = (_a = parsedData.package) === null || _a === void 0 ? void 0 : _a.manager) !== null && _b !== void 0 ? _b : 'yarn'; const packagePublisher = (_d = (_c = parsedData.package) === null || _c === void 0 ? void 0 : _c.publisher) !== null && _d !== void 0 ? _d : 'npm'; const packageIgnore = (_f = (_e = parsedData.package) === null || _e === void 0 ? void 0 : _e.ignore) !== null && _f !== void 0 ? _f : []; const yarnWorkspace = typeof parsedData.yarnWorkspace === 'boolean' ? parsedData.yarnWorkspace : parsedData.yarnWorkspace === 'true'; const commitEngine = (_h = (_g = parsedData.commit) === null || _g === void 0 ? void 0 : _g.engine) !== null && _h !== void 0 ? _h : 'git'; const commitCombine = typeof ((_j = parsedData.commit) === null || _j === void 0 ? void 0 : _j.combine) === 'boolean' ? (_k = parsedData.commit) === null || _k === void 0 ? void 0 : _k.combine : ((_l = parsedData.commit) === null || _l === void 0 ? void 0 : _l.combine) === 'true'; const commitRoot = (_o = (_m = parsedData.commit) === null || _m === void 0 ? void 0 : _m.root) !== null && _o !== void 0 ? _o : ''; const commitFullFolder = typeof ((_p = parsedData.commit) === null || _p === void 0 ? void 0 : _p.fullFolder) === 'boolean' ? (_q = parsedData.commit) === null || _q === void 0 ? void 0 : _q.fullFolder : ((_r = parsedData.commit) === null || _r === void 0 ? void 0 : _r.fullFolder) === 'true'; const commitDivider = (_t = (_s = parsedData.commit) === null || _s === void 0 ? void 0 : _s.divider) !== null && _t !== void 0 ? _t : ' > '; const commitMessage = (_v = (_u = parsedData.commit) === null || _u === void 0 ? void 0 : _u.message) !== null && _v !== void 0 ? _v : 'setup: package'; const runFromData = (_w = parsedData.runFrom) !== null && _w !== void 0 ? _w : ''; const configurationFileDirectory = path__default["default"].dirname(configurationFilepath); const runFrom = runFromData ? path__default["default"].resolve(configurationFileDirectory, runFromData) : process.cwd(); const commands = parsedData.commands || {}; const packages = yield locatePackages(parsedData.packages, yarnWorkspace, runFrom, packageIgnore); const developmentExternalPackages = (_y = (_x = parsedData.development) === null || _x === void 0 ? void 0 : _x.externalPackages) !== null && _y !== void 0 ? _y : []; const developmentWatchPackages = resolveWatchedPackages(packages, (_z = parsedData.development) === null || _z === void 0 ? void 0 : _z.watchPackages); const developmentWatchDirectories = (_1 = (_0 = parsedData.development) === null || _0 === void 0 ? void 0 : _0.watchDirectories) !== null && _1 !== void 0 ? _1 : ['build', 'distribution', 'dist']; const developmentServerPort = (_3 = (_2 = parsedData.development) === null || _2 === void 0 ? void 0 : _2.serverPort) !== null && _3 !== void 0 ? _3 : 55000; if (packages.length === 0 && !yarnWorkspace) { console.log(`\n\tPackages required to be specified in the 'joiner' configuration file.\n`); return; } const configurationFile = { name: packageName, packages, package: { manager: packageManager, publisher: packagePublisher, ignore: packageIgnore, }, yarnWorkspace, commit: { engine: commitEngine, combine: commitCombine, root: commitRoot, fullFolder: commitFullFolder, divider: commitDivider, message: commitMessage, }, development: { externalPackages: developmentExternalPackages, watchPackages: developmentWatchPackages, watchDirectories: developmentWatchDirectories, serverPort: developmentServerPort, }, runFrom, commands, }; return configurationFile; }); const getDefaultConfigurationFilepath = () => __awaiter(void 0, void 0, void 0, function* () { const filepaths = [ 'joiner.deon', 'joiner.yaml', 'scripts/joiner.deon', 'scripts/joiner.yaml', 'scripts/joiner.packages.deon', 'scripts/joiner.packages.yaml', ]; let pathFound = ''; for (const filepath of filepaths) { try { const possiblePath = path__default["default"].join(process.cwd(), filepath); const exists = yield fs.promises.stat(possiblePath); if (exists) { pathFound = filepath; break; } } catch (error) { continue; } } return pathFound; }); // #endregion module // #endregion external // #endregion imports // #region module const listCommand = (configurationFile) => __awaiter(void 0, void 0, void 0, function* () { const configurationData = yield parseConfigurationFile(configurationFile); if (!configurationData) { return; } const { packages, } = configurationData; if (packages.length > 0) { console.log(`\n\tJoiner commandable packages:\n`); for (const [index, configPackage] of packages.entries()) { console.log(`\t\t${index} · ${configPackage.name}`); console.log(`\t\talias: ${configPackage.alias}`); console.log(`\t\tpath: ${configPackage.path}\n`); } } else { console.log(`\n\tNo joiner commandable packages.\n`); } }); // #endregion exports // #endregion external // #endregion imports // #region module const runExecution = (configPackage, command) => __awaiter(void 0, void 0, void 0, function* () { const executableCommand = command.join(' '); console.log(`\n\tRunning command '${executableCommand}' in:\n\t${configPackage.path}\n`); const startTime = Date.now(); child_process.execSync(executableCommand, { cwd: configPackage.path, stdio: 'inherit', }); const endTime = Date.now(); const commandTime = (endTime - startTime) / 1000; console.log(`\n\tCommand\n\n\t\t${executableCommand}\n\n\tran in ${commandTime} seconds.\n`); }); // #endregion exports // #endregion external // #endregion imports // #region module const generateBatches = (packages, batch) => { const batchesCount = Math.ceil(packages.length / batch); const batches = []; for (let i = 0; i < batchesCount; i++) { const batchValues = packages.slice(i * batch, (i + 1) * batch); batches.push(batchValues); } return batches; }; // #endregion exports // #region imports // #endregion libraries // #endregion imports // #region module const runWorker = (name, data) => { return new Promise((resolve, reject) => { const worker = new worker_threads.Worker(path__default["default"].join(__dirname, `../distribution/worker-${name}.js`), { workerData: data, }); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) { reject(new Error(`Worker stopped with exit code ${code}`)); } resolve(true); }); }); }; // #endregion exports // #endregion external // #endregion imports // #region module class Batcher { constructor(packages, batch, workerName, workerData) { this.packages = packages; this.batch = batch; this.workerName = workerName; this.workerData = workerData; } run() { return __awaiter(this, void 0, void 0, function* () { const batches = generateBatches(this.packages, this.batch); for (const batchPackages of batches) { const promises = []; for (const configPackage of batchPackages) { const resolving = runWorker(this.workerName, Object.assign({ configPackage }, this.workerData)); promises.push(resolving); } yield Promise.all(promises); } }); } } // #endregion exports // #endregion external // #endregion imports // #region module const runCommand = (packageName, command, options) => __awaiter(void 0, void 0, void 0, function* () { const { batch, parallel, configuration, } = options; const configurationData = yield parseConfigurationFile(configuration); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } if (parallel) { const batcher = new Batcher(resolvedPackage, batch, 'run', { command, }); yield batcher.run(); return; } for (const configPackage of resolvedPackage) { yield runExecution(configPackage, command); } }); // #endregion exports // #endregion external // #endregion imports // #region module const commandExecution = (configPackage, commandNames, configurationData) => __awaiter(void 0, void 0, void 0, function* () { for (const commandName of commandNames) { const executableCommandData = configurationData.commands[commandName]; const executableCommand = executableCommandData.join(' '); console.log(`\n\tRunning command '${executableCommand}' in:\n\t${configPackage.path}\n`); const startTime = Date.now(); child_process.execSync(executableCommand, { cwd: configPackage.path, stdio: 'inherit', }); const endTime = Date.now(); const commandTime = (endTime - startTime) / 1000; console.log(`\n\tCommand\n\n\t\t${executableCommand}\n\n\tran in ${commandTime} seconds.\n`); } }); // #endregion exports // #endregion external // #endregion imports // #region module const commandCommand = (packageName, commandNames, options) => __awaiter(void 0, void 0, void 0, function* () { const { batch, parallel, configuration, } = options; const configurationData = yield parseConfigurationFile(configuration); if (!configurationData) { console.log(`\n\tNo configuration data in the configuration file ${configuration}.\n`); return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { console.log(`\n\tNo package ${packageName}.\n`); return; } const registeredCommands = Object.keys(configurationData.commands); for (const commandName of commandNames) { if (!registeredCommands.includes(commandName)) { console.log(`\n\tNo command ${commandName}.\n`); return; } } if (parallel) { const batcher = new Batcher(resolvedPackage, batch, 'command', { commandNames, configurationData, }); yield batcher.run(); return; } for (const configPackage of resolvedPackage) { yield commandExecution(configPackage, commandNames, configurationData); } }); // #endregion exports // #endregion external // #endregion imports // #region module const updateExecution = (configPackage, configurationFile) => __awaiter(void 0, void 0, void 0, function* () { const inThePackage = `in the package '${configPackage.name}'`; console.log(`\n\tChecking for updates ${inThePackage}...`); try { const updatedPackages = yield checkUpdates__default["default"]({ packageFile: path__default["default"].join(configPackage.path, 'package.json'), silent: true, jsonUpgraded: true, upgrade: true, dep: 'prod,dev', cache: true, }); if (!updatedPackages) { console.log(`\n\tCould not find updates ${inThePackage}...`); return; } if (Object.keys(updatedPackages).length > 0) { console.log(`\n\t'${configPackage.name}' dependencies updated:\n`); for (const [key, value] of Object.entries(updatedPackages)) { console.log(`\t\t${key}: ${value}`); } console.log(`\n\tInstalling the updates ${inThePackage}...`); installCommand(configPackage, configurationFile); console.log(`\tUpdates installed ${inThePackage}.\n`); } else { console.log(`\n\tNo dependencies updates ${inThePackage}.\n`); console.log(`\n\tInstalling the dependencies ${inThePackage}...`); installCommand(configPackage, configurationFile); console.log(`\tDependencies installed ${inThePackage}.\n`); } } catch (error) { console.log(`\n\tSomething went wrong.\n`); } }); const installCommand = (configPackage, configurationFile) => { const install = `${configurationFile.package.manager} install`; child_process.execSync(install, { cwd: configPackage.path, stdio: 'ignore', }); }; // #endregion exports // #endregion external // #endregion imports // #region module const updateCommand = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { const { batch, parallel, configuration, } = options; const configurationData = yield parseConfigurationFile(configuration); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } if (parallel) { const batcher = new Batcher(resolvedPackage, batch, 'update', { configurationFile: configurationData, }); yield batcher.run(); return; } for (const configPackage of resolvedPackage) { yield updateExecution(configPackage, configurationData); } }); // #endregion exports // #endregion external // #endregion imports // #region module const patchCommand = (packageName, configurationFile, versionType) => __awaiter(void 0, void 0, void 0, function* () { if (packageName === '.') { const packageData = { alias: '', joinerpackage: false, name: 'in the current directory', path: process.cwd(), private: false, version: '0.0.0-0', }; yield patchLogic(packageData, versionType); return; } const configurationData = yield parseConfigurationFile(configurationFile); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } for (const configPackage of resolvedPackage) { yield patchLogic(configPackage, versionType); } }); const patchLogic = (configPackage, versionType) => __awaiter(void 0, void 0, void 0, function* () { try { console.log(`\n\tPatching version for package ${configPackage.name}...`); const packageJSONPath = path__default["default"].join(configPackage.path, 'package.json'); const packageJSONRawData = yield fs.promises.readFile(packageJSONPath, 'utf-8'); const packageJSONData = JSON.parse(packageJSONRawData); const { version, } = packageJSONData; const isAlpha = alphaVersioning.isAlphaVersion(version); if (!isAlpha) { const versionTypeCommand = resolveVersionType(versionType); const patchCommand = `npm version ${versionTypeCommand} --no-git-tag-version`; child_process.execSync(patchCommand, { cwd: configPackage.path, stdio: 'ignore', }); const packageJSONPath = path__default["default"].join(configPackage.path, 'package.json'); const packageJSONRawData = yield fs.promises.readFile(packageJSONPath, 'utf-8'); const packageJSONData = JSON.parse(packageJSONRawData); const { name, version, } = packageJSONData; console.log(`\t${name} version patched to version ${version}.\n`); return; } const alphaUpdatedVersion = alphaVersioning.updateAlphaVersion(version); const updatedPackageData = Object.assign({}, packageJSONData); updatedPackageData.version = alphaUpdatedVersion; yield fs.promises.writeFile(packageJSONPath, JSON.stringify(updatedPackageData, null, 4)); } catch (error) { console.log(`\n\tSomething went wrong. Check the version field for '${configPackage.name}'.\n`); } }); const resolveVersionType = (versionType) => { const versionTypeCommand = (versionType === 'major' || versionType === 'minor' || versionType === 'patch') ? versionType : 'patch'; return versionTypeCommand; }; // #endregion exports // #endregion external // #endregion imports // #region module const commitCommand = (packageName, configurationFile, message) => __awaiter(void 0, void 0, void 0, function* () { const configurationData = yield parseConfigurationFile(configurationFile); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } for (const configPackage of resolvedPackage) { yield commitLogic(configPackage, configurationData, message); } }); const commitLogic = (configPackage, configurationData, message) => __awaiter(void 0, void 0, void 0, function* () { try { console.log(`\n\tCommiting the package '${configPackage.name}'...`); const addCommand = 'git add .'; child_process.execSync(addCommand, { cwd: configPackage.path, stdio: 'ignore', }); const { combine, root, fullFolder, divider, message: configMessage, } = configurationData.commit; const packageFolder = path__default["default"].relative(process.cwd(), configPackage.path); const packageFolderSplit = packageFolder.split('/'); const packageFolderName = packageFolderSplit[packageFolderSplit.length - 1]; const packageName = fullFolder ? packageFolder : packageFolderName; const commitMessage = message || configMessage; const commitCommandMessage = combine ? root + packageName + divider + commitMessage : commitMessage; const commitCommand = `git commit -m '${commitCommandMessage}'`; child_process.execSync(commitCommand, { cwd: configPackage.path, stdio: 'ignore', }); console.log(`\t'${configPackage.name}' changes commited.\n`); } catch (error) { console.log(`\n\tSomething went wrong.\n`); } }); // #endregion exports // #endregion external // #endregion imports // #region module const publishExecution = (configPackage) => __awaiter(void 0, void 0, void 0, function* () { try { if (configPackage.private) { console.log(`\n\tPackage '${configPackage.name} is private. Did not publish.'`); return; } console.log(`\n\tPublishing the package '${configPackage.name}'...`); const publishCommand = 'npm publish'; child_process.execSync(publishCommand, { cwd: configPackage.path, stdio: 'ignore', }); console.log(`\t'${configPackage.name}' published.\n`); } catch (error) { console.log(`\n\tSomething went wrong.\n`); } }); // #endregion exports // #endregion external // #endregion imports // #region module const publishCommand = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { const { batch, parallel, configuration, } = options; const configurationData = yield parseConfigurationFile(configuration); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } if (parallel) { const batcher = new Batcher(resolvedPackage, batch, 'publish', {}); yield batcher.run(); return; } for (const configPackage of resolvedPackage) { yield publishExecution(configPackage); } }); // #endregion exports // #endregion external // #endregion imports // #region module const ucomExecution = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { yield updateCommand(packageName, options); yield commitCommand(packageName, options.configuration); }); // #endregion exports // #endregion external // #endregion imports // #region module const ucomCommand = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { const { batch, parallel, configuration, } = options; if (parallel) { const configurationData = yield parseConfigurationFile(configuration); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } const batcher = new Batcher(resolvedPackage, batch, 'ucom', {}); yield batcher.run(); return; } console.log(`\n\t---------------`); console.log(`\tUcomishing ${packageName}...`); yield ucomExecution(packageName, options); console.log(`\n\tUcomished ${packageName}.`); console.log(`\t---------------\n`); }); // #endregion exports // #endregion external // #endregion imports // #region module const upcomExecution = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { yield updateCommand(packageName, options); yield patchCommand(packageName, options.configuration, 'patch'); yield commitCommand(packageName, options.configuration); }); // #endregion exports // #endregion external // #endregion imports // #region module const upcomCommand = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { const { batch, parallel, configuration, } = options; if (parallel) { const configurationData = yield parseConfigurationFile(configuration); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } const batcher = new Batcher(resolvedPackage, batch, 'upcom', {}); yield batcher.run(); return; } console.log(`\n\t---------------`); console.log(`\tUpcomishing ${packageName}...`); yield upcomExecution(packageName, options); console.log(`\n\tUpcomished ${packageName}.`); console.log(`\t---------------\n`); }); // #endregion exports // #endregion external // #endregion imports // #region module const upcomlishExecution = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { yield updateCommand(packageName, options); yield patchCommand(packageName, options.configuration, 'patch'); yield commitCommand(packageName, options.configuration); yield publishCommand(packageName, options); }); // #endregion exports // #endregion external // #endregion imports // #region module const upcomlishCommand = (packageName, options) => __awaiter(void 0, void 0, void 0, function* () { const { batch, parallel, configuration, } = options; if (parallel) { const configurationData = yield parseConfigurationFile(configuration); if (!configurationData) { return; } const resolvedPackage = resolvePackage(packageName, configurationData); if (!resolvedPackage) { return; } const batcher = new Batcher(resolvedPackage, batch, 'upcomlish', {}); yield batcher.run(); return; } console.log(`\n\t---------------`); console.log(`\tUpcomlishishing ${packageName}...`); yield upcomlishExecution(packageName, options); console.log(`\n\tUpcomlishished ${packageName}.`); console.log(`\t---------------\n`); }); // #endregion exports // #endregion external // #endregion imports // #region module const developmentPackageUpdateDirectoryLogic = (workPackage, updatePackage, watchDirectory) => __awaiter(void 0, void 0, void 0, function* () { const watchDirectoryPath = path__default["default"].join(workPackage.path, watchDirectory); const updatePackageDependencyPath = path__default["default"].join(updatePackage.path, 'node_modules', workPackage.name); // console.log('updatePackageDependencyPath', updatePackageDependencyPath); const updatePackageDependencyBuildPath = path__default["default"].join(updatePackageDependencyPath, watchDirectory); // console.log('updatePackageDependencyBuildPath', updatePackageDependencyBuildPath); if (fs__default["default"].existsSync(watchDirectoryPath)) { // check that the updatePackage is actually dependent on the workPackage if (!fs__default["default"].existsSync(updatePackageDependencyPath)) { return; } // check that if there is alre