UNPKG

react-native-integrate

Version:

Automate integration of additional code into React Native projects

327 lines (326 loc) 16.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.integrate = integrate; const picocolors_1 = __importDefault(require("picocolors")); const preload_1 = __importDefault(require("semver/preload")); const options_1 = require("./options"); const progress_1 = require("./progress"); const prompter_1 = require("./prompter"); const analyzePackages_1 = require("./utils/analyzePackages"); const checkCondition_1 = require("./utils/checkCondition"); const checkForUpdate_1 = require("./utils/checkForUpdate"); const getErrMessage_1 = require("./utils/getErrMessage"); const getIntegrateConfig_1 = require("./utils/getIntegrateConfig"); const getPackageConfig_1 = require("./utils/getPackageConfig"); const logInfoNote_1 = require("./utils/logInfoNote"); const parseConfig_1 = require("./utils/parseConfig"); const runTask_1 = require("./utils/runTask"); const setState_1 = require("./utils/setState"); const taskManager_1 = require("./utils/taskManager"); const topologicalSort_1 = require("./utils/topologicalSort"); const updateIntegrationStatus_1 = require("./utils/updateIntegrationStatus"); const variables_1 = require("./variables"); async function integrate(packageName) { progress_1.progress.setOptions({ stage: 'checking for updates', }); await (0, checkForUpdate_1.checkForUpdate)(); let stage = 1; progress_1.progress.setOptions({ step: stage++, stage: 'analyzing packages', }); (0, prompter_1.startSpinner)('analyzing packages'); const analyzedPackages = (0, analyzePackages_1.analyzePackages)(packageName); const { deletedPackages, installedPackages, integratedPackages } = analyzedPackages; let { newPackages } = analyzedPackages; const shouldBreak = checkIfJustCreatedLockFile(analyzedPackages); let msg = `analyzed ${installedPackages.length} packages`; if (packageName) { // check if package is installed newPackages = newPackages.filter(([newPackageName]) => newPackageName == packageName); if (installedPackages.every(([installedPackageName]) => installedPackageName != packageName) || !newPackages.length) { (0, prompter_1.stopSpinner)(msg); (0, prompter_1.logWarning)(`${picocolors_1.default.bold(packageName)} is not installed - please install it first and try again`); return; } } else { if (shouldBreak) return; // get packages that need to be implemented if (newPackages.length || deletedPackages.length) { if (newPackages.length > 0) { msg += picocolors_1.default.green(` | ${newPackages.length} new package(s)`); } if (deletedPackages.length > 0) { msg += picocolors_1.default.gray(` | ${deletedPackages.length} deleted package(s)`); } } else { msg += ' | no changes'; } } (0, prompter_1.stopSpinner)(msg); const packageLockUpdates = []; let packagesToIntegrate = []; if (newPackages.length) { const globalInfo = []; progress_1.progress.setOptions({ step: stage++, stage: 'checking package configuration', }); (0, prompter_1.startSpinner)('checking package configuration'); for (let i = 0; i < newPackages.length; i++) { const [packageName, version] = newPackages[i]; const configPath = await (0, getPackageConfig_1.getPackageConfig)(packageName, { index: i, count: newPackages.length, }); if (!configPath) packageLockUpdates.push({ packageName, lockProjectData: { version, integrated: false, }, }); else { let config; try { config = (0, parseConfig_1.parseConfig)(configPath); } catch (e) { (0, prompter_1.logError)(picocolors_1.default.bold(picocolors_1.default.bgRed(' error ')) + picocolors_1.default.bold(picocolors_1.default.blue(` ${packageName} `)) + picocolors_1.default.red('could not parse package configuration\n') + picocolors_1.default.gray((0, getErrMessage_1.getErrMessage)(e, 'validation')), true); continue; } const rnVersionEntry = installedPackages.find(entry => entry[0] === 'react-native'); if (!rnVersionEntry) { (0, prompter_1.stopSpinner)('checked package configuration'); (0, prompter_1.logWarning)('React Native not installed!?'); return; } const rnVersion = rnVersionEntry[1]; const semRnVersion = preload_1.default.coerce(rnVersion); if (!semRnVersion) { (0, prompter_1.stopSpinner)('checked package configuration'); (0, prompter_1.logWarning)(`React Native version (${rnVersion}) is invalid!?`); return; } variables_1.variables.setPredefined('RN_VERSION', { major: semRnVersion.major, minor: semRnVersion.minor, patch: semRnVersion.patch, }); if (config.minRNVersion) { if (preload_1.default.lt(semRnVersion, preload_1.default.coerce(config.minRNVersion) || '0.0.0')) { (0, prompter_1.stopSpinner)('checked package configuration'); (0, prompter_1.logWarning)(`${picocolors_1.default.bold(picocolors_1.default.blue(packageName))} requires React Native version ${picocolors_1.default.bold(picocolors_1.default.blue(config.minRNVersion))}`); return; } } if (config.minVersion) { if (preload_1.default.lt(preload_1.default.coerce(version) || '0.0.0', preload_1.default.coerce(config.minVersion) || '0.0.0')) { (0, prompter_1.stopSpinner)('checked package configuration'); (0, prompter_1.logWarning)(`${picocolors_1.default.bold(picocolors_1.default.blue(packageName))} requires version ${picocolors_1.default.bold(picocolors_1.default.blue(config.minVersion))} - please update it first and try again`); return; } } if (config.dependencies?.length) { let warn = null; const packageInfo = []; for (const dependentPackageName of config.dependencies) { // check if dependency is not integrated and not already in new package list const isInNewPackages = newPackages.every(([packageName]) => packageName != dependentPackageName); const isNotIntegrated = integratedPackages.every(([packageName]) => packageName != dependentPackageName); if (isInNewPackages && isNotIntegrated) { //check if dependent is installed const installedPackage = installedPackages.find(([packageName]) => packageName == dependentPackageName); if (!installedPackage) { warn = `${picocolors_1.default.bold(picocolors_1.default.blue(dependentPackageName))} is not installed - please install it first and try again`; break; } else { // installed but not new, force add as new newPackages.push(installedPackage); packageInfo.push(`${picocolors_1.default.bold(picocolors_1.default.blue(dependentPackageName))}`); } } } if (warn) { (0, prompter_1.stopSpinner)('checked package configuration'); (0, prompter_1.logWarning)(`${picocolors_1.default.bold(picocolors_1.default.blue(packageName))} has dependencies that require integration: \n${warn}`); return; } else if (packageInfo.length) { globalInfo.push(`${picocolors_1.default.bold(picocolors_1.default.blue(packageName))} has dependencies that require integration: ${getInnerLogList(packageInfo)}`); } } packagesToIntegrate.push({ packageName, version, configPath, config, }); } } let msg = 'checked package configuration'; if (packageName) { if (packagesToIntegrate.length == 0) { (0, prompter_1.stopSpinner)(msg); (0, prompter_1.logWarning)(`${picocolors_1.default.bold(packageName)} has no configuration specified`); return; } } else { if (packagesToIntegrate.length > 0) { msg += picocolors_1.default.green(` | ${packagesToIntegrate.length} package can be integrated`); } else { msg += ' | no configuration specified'; } } (0, prompter_1.stopSpinner)(msg); if (globalInfo.length) globalInfo.forEach(prompter_1.logInfo); } if (packagesToIntegrate.length) { packagesToIntegrate = (0, topologicalSort_1.topologicalSort)(packagesToIntegrate); const integrateConfig = (0, getIntegrateConfig_1.getIntegrateConfig)(); for (let i = 0; i < packagesToIntegrate.length; i++) { const { packageName, version, configPath, config } = packagesToIntegrate[i]; progress_1.progress.setOptions({ step: i + 1, total: packagesToIntegrate.length, stage: `integrating ${picocolors_1.default.blue(packageName)}`, }); (0, prompter_1.logSuccess)(picocolors_1.default.bold(picocolors_1.default.bgBlue(' integration ')) + picocolors_1.default.bold(picocolors_1.default.blue(` ${packageName} `))); if (!options_1.options.get().interactive || (await (0, prompter_1.confirm)('would you like to integrate this package?'))) { variables_1.variables.clear(); // reset variables if (config.env) { Object.entries(config.env).forEach(([name, value]) => variables_1.variables.set(name, (0, variables_1.transformTextInObject)(value))); } if (integrateConfig) { const integratePackageconfig = (0, getIntegrateConfig_1.getIntegratePackageConfig)(integrateConfig, packageName); if (integratePackageconfig) variables_1.variables.set('config', integratePackageconfig); } let failedTaskCount = 0, completedTaskCount = 0; await (0, logInfoNote_1.logInfoNote)(config.preInfo); for (const task of config.steps) { if (task.when && !(0, checkCondition_1.checkCondition)(task.when)) { (0, setState_1.setState)(task.name, { state: 'skipped', }); continue; } (0, setState_1.setState)(task.name, { state: 'progress', }); const isNonSystemTask = !taskManager_1.taskManager.isSystemTask(task.task); if (isNonSystemTask) { if (task.label) task.label = (0, variables_1.getText)(task.label); else task.label = taskManager_1.taskManager.task[task.task].summary; (0, prompter_1.logInfo)(picocolors_1.default.bold(picocolors_1.default.inverse(picocolors_1.default.cyan(' task '))) + picocolors_1.default.bold(picocolors_1.default.cyan(` ${task.label} `))); } await (0, logInfoNote_1.logInfoNote)(task.preInfo); try { await (0, runTask_1.runTask)({ configPath, packageName, task, }); completedTaskCount++; (0, setState_1.setState)(task.name, { state: 'done', }); await (0, logInfoNote_1.logInfoNote)(task.postInfo); } catch (e) { failedTaskCount++; const errMessage = (0, getErrMessage_1.getErrMessage)(e); (0, prompter_1.logError)(errMessage); (0, setState_1.setState)(task.name, { state: 'error', reason: errMessage, }); } } await (0, logInfoNote_1.logInfoNote)(config.postInfo); if (failedTaskCount) { (0, prompter_1.logWarning)(picocolors_1.default.inverse(picocolors_1.default.bold(picocolors_1.default.yellow(' done with errors '))) + picocolors_1.default.bold(picocolors_1.default.blue(` ${packageName} `)) + picocolors_1.default.yellow(`failed to complete ${failedTaskCount} task(s) - please complete this integration manually`), true); } else { (0, prompter_1.logSuccess)(picocolors_1.default.inverse(picocolors_1.default.bold(picocolors_1.default.green(' done '))) + picocolors_1.default.green(` completed ${completedTaskCount} task(s) successfully`)); } packageLockUpdates.push({ packageName, lockProjectData: { version, integrated: true, }, }); } else { packageLockUpdates.push({ packageName, lockProjectData: { version, integrated: false, }, }); (0, prompter_1.log)(picocolors_1.default.gray(picocolors_1.default.italic('skipped package integration'))); } } } for (let i = 0; i < deletedPackages.length; i++) { const [packageName, lockProjectData] = deletedPackages[i]; lockProjectData.deleted = true; packageLockUpdates.push({ packageName, lockProjectData, }); } (0, updateIntegrationStatus_1.updateIntegrationStatus)(packageLockUpdates); } function checkIfJustCreatedLockFile(analyzedPackages) { const { newPackages, justCreatedLockFile } = analyzedPackages; if (justCreatedLockFile) { if (!analyzedPackages.forceIntegratePackageName) (0, prompter_1.stopSpinner)(picocolors_1.default.gray(picocolors_1.default.italic('first run, skipped integration checks'))); const packageLockUpdates = []; for (let i = 0; i < newPackages.length; i++) { const [packageName, version] = newPackages[i]; packageLockUpdates.push({ packageName, lockProjectData: { version, integrated: false, }, }); } (0, updateIntegrationStatus_1.updateIntegrationStatus)(packageLockUpdates); return true; } return false; } function getInnerLogList(strings) { return strings.reduce((o, s, index) => { return o + picocolors_1.default.gray(index == strings.length - 1 ? '\n└ ' : '\n├ ') + s; }, ''); }