UNPKG

@oblique/cli

Version:

Command Line Interface to manage Oblique projects

191 lines (189 loc) 8.2 kB
/** * @file Oblique, The front-end framework for your Swiss branded UI. * @copyright 2020 - 2026 Federal Office of Information Technology, Systems and Telecommunication FOITT {@link https://www.bit.admin.ch} * @version 15.4.1 (released on 2026-07-09, supported at least until 2027-02-28) * @author Oblique team, FOITT, BS-BSC-EN4 <oblique@bit.admin.ch> * @license MIT {@link https://github.com/oblique-bit/oblique/blob/master/LICENSE} * @see https://oblique.bit.admin.ch */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createObUpdateCommand = createObUpdateCommand; exports.initializeCommand = initializeCommand; exports.handleObUpdateActions = handleObUpdateActions; exports.checkNeededDependencies = checkNeededDependencies; exports.addSchematicsAngular = addSchematicsAngular; exports.runUpdateDependencies = runUpdateDependencies; exports.outputOutdatedDependencies = outputOutdatedDependencies; exports.isDependencyInPackage = isDependencyInPackage; exports.findPackage = findPackage; const tslib_1 = require("tslib"); const extra_typings_1 = require("@commander-js/extra-typings"); const path = tslib_1.__importStar(require("node:path")); const node_fs_1 = tslib_1.__importDefault(require("node:fs")); const cli_utils_1 = require("../utils/cli-utils"); const ob_update_model_1 = require("./ob-update.model"); const chalk_1 = tslib_1.__importDefault(require("chalk")); const child_process_1 = require("child_process"); const ob_configure_command_1 = require("../utils/ob-configure-command"); function createObUpdateCommand() { const command = new extra_typings_1.Command(); const initializedCommand = initializeCommand(command); return configureCommandOptions(initializedCommand); } function initializeCommand(command) { command .name('update') .helpOption('-h, --help', (0, cli_utils_1.getHelpText)('ob update')) .usage((0, cli_utils_1.commandUsageText)('update', ' ')) .summary(ob_update_model_1.updateDescriptions.summaryText) .action(() => handleAction({ command })) .showSuggestionAfterError(true) .showHelpAfterError(true); return command; } function handleAction(options) { (0, cli_utils_1.startObCommand)(handleObUpdateActions, 'Oblique CLI ob update completed in', options); } function handleObUpdateActions(options) { const cmdOptions = options.command.opts(); try { checkNeededDependencies(); addSchematicsAngular(); runUpdateDependencies(cmdOptions); runUpdateSave(); runNpmDedupe(); runNpmPrune(); } catch (error) { console.error(chalk_1.default.red('Update failed: '), error); process.exit(1); } // this have to be done at the end, because npm outdated exits with a non-zero exit code (status: 1 in the output) which causes execSync to throw and catch an error. outputOutdatedDependencies(); } function checkNeededDependencies() { if (!isDependencyInPackage('@oblique/oblique')) { console.error(chalk_1.default.red(`Package @oblique/oblique not found. Please install Oblique with '${cli_utils_1.ngAddOblique.command}' to ${cli_utils_1.ngAddOblique.description}.`)); process.exit(1); } } function addSchematicsAngular() { // This is temporary until a better solution is found // The problem is that @schematics/angular, which is a dependency of Oblique, needs to be updated at the same time as the other packages, // otherwise @angular-devkit/core won't be installed as a root dependency, but as a nested one. This can be solved with npm dedupe, // but there's no way to execute this function in the middle of the update command. // The solution is then to ensure that @schematics/angular is listed as a devDependency so that the update command also updates it if (!isDependencyInPackage('@schematics/angular')) { const pkg = findPackage(); if (pkg.dependencies) { const groups = /[^~](?<major>\d+)\.\d+\.\d+"/u.exec(pkg.dependencies['@angular/core'])?.groups ?? { major: '18' }; (0, child_process_1.execSync)(`npm i @schematics/angular@${groups['major']} --save-dev`, { stdio: 'inherit' }); } } } function runUpdateDependencies(cmdOptions) { try { const dependencies = Object.entries(cli_utils_1.currentVersions) .map(([dependency]) => dependency) .filter(dependency => isDependencyInPackage(dependency)); const angularDependencies = getAngularDependenciesFromPackage().filter(dependency => !skipDependencyUpdate(dependency)); const validatedOptions = returnTruthyOptions(cmdOptions); // commanderjs changes the key any kebab case option which turns it invalid as an angular param if (validatedOptions['allowDirty']) { validatedOptions['allow-dirty'] = validatedOptions['allowDirty']; delete validatedOptions['allowDirty']; } (0, cli_utils_1.execute)({ name: 'ngUpdate', dependencies, angularDependencies, options: validatedOptions, }); } catch (error) { console.error(error); } } function runUpdateSave() { console.info(chalk_1.default.blue('[Info]: Runs npm update')); try { (0, cli_utils_1.execute)({ name: 'npmUpdate' }); } catch (error) { console.info(error); } } function runNpmDedupe() { console.info(chalk_1.default.blue('[Info]: Runs npm dedupe')); try { (0, cli_utils_1.execute)({ name: 'npmDedupe' }); } catch (error) { console.info(error); } } function runNpmPrune() { console.info(chalk_1.default.blue('[Info]: Runs npm prune')); try { (0, cli_utils_1.execute)({ name: 'npmPrune' }); } catch (error) { console.info(error); } } function outputOutdatedDependencies() { console.info(chalk_1.default.blue('[Info]: Following dependencies should also be manually updated.\n')); try { (0, cli_utils_1.execute)({ name: 'npmOutdated' }); } catch { // npm outdated always fails, but no error management is needed since the execute function will already print its output. // the try..catch block only serves to avoid the error being thrown } } function isDependencyInPackage(dependency) { try { const packageJson = findPackage(); const dependencies = packageJson.dependencies ?? {}; const devDependencies = packageJson.devDependencies ?? {}; return dependency in dependencies || dependency in devDependencies; } catch (error) { console.error(chalk_1.default.red(`[Error]: This command is not available when running the Oblique CLI outside a workspace`), error); process.exit(1); } return false; } function findPackage() { const packageJsonPath = path.resolve(process.cwd(), 'package.json'); if (packageJsonPath) { return JSON.parse(node_fs_1.default.readFileSync(packageJsonPath, 'utf-8')); } throw new Error(`Cant find the package.json at path: ${[process.cwd(), 'package.json'].join('/')}. Please navigate to the level of your package.json and try "ob update" again.`); } function getAngularDependenciesFromPackage() { const pkg = findPackage(); const dependencies = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}), }; return Object.keys(dependencies).filter(dependency => dependency.startsWith('@angular/')); } function skipDependencyUpdate(dependency) { return cli_utils_1.nonUpdatableDependencies.includes(dependency); } function configureCommandOptions(updateCommand) { return (0, ob_configure_command_1.addObUpdateCommandOptions)(ob_update_model_1.schema, updateCommand); } //to avoid adding invalid options like --no-force to the ng update command function returnTruthyOptions(cmdOptions) { const trueValues = new Set([true, 'true']); const validatedOptions = {}; Object.entries(cmdOptions) .filter(([, value]) => trueValues.has(value)) .forEach(([key, value]) => { validatedOptions[key] = value; }); return validatedOptions; }