UNPKG

@angular/cli

Version:
196 lines • 8.72 kB
"use strict"; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.coerceVersionNumber = coerceVersionNumber; exports.checkCLIVersion = checkCLIVersion; exports.getCLIUpdateRunnerVersion = getCLIUpdateRunnerVersion; exports.runTempBinary = runTempBinary; exports.shouldForcePackageManager = shouldForcePackageManager; const node_child_process_1 = require("node:child_process"); const node_fs_1 = require("node:fs"); const node_path_1 = require("node:path"); const semver = __importStar(require("semver")); const version_1 = require("../../../utilities/version"); const constants_1 = require("./constants"); /** * Coerces a string into a valid semantic version number. * @param version The version string to coerce. * @returns A valid semantic version string, or undefined if coercion fails. */ function coerceVersionNumber(version) { if (!version) { return undefined; } if (!/^\d{1,30}\.\d{1,30}\.\d{1,30}/.test(version)) { const match = version.match(/^\d{1,30}(\.\d{1,30})*/); if (!match) { return undefined; } if (!match[1]) { version = version.substring(0, match[0].length) + '.0.0' + version.substring(match[0].length); } else if (!match[2]) { version = version.substring(0, match[0].length) + '.0' + version.substring(match[0].length); } else { return undefined; } } return semver.valid(version) ?? undefined; } /** * Checks if the installed CLI version is compatible with the packages being updated. * @param packagesToUpdate The list of packages being updated. * @param logger The logger instance. * @param packageManager The package manager instance. * @param verbose Whether to log verbose output. * @param next Whether to check for the next version. * @returns The version of the CLI to install, or null if the current version is compatible. */ async function checkCLIVersion(packagesToUpdate, logger, packageManager, next = false) { const runnerVersion = getCLIUpdateRunnerVersion(packagesToUpdate, next); const manifest = await packageManager.getManifest(`@angular/cli@${runnerVersion}`); if (!manifest) { logger.warn(`Could not find @angular/cli version '${runnerVersion}'.`); return null; } const version = manifest.version; return version_1.VERSION.full === version ? null : version; } /** * Determines the version of the CLI to use for the update process. * @param packagesToUpdate The list of packages being updated. * @param next Whether to use the next version. * @returns The version or tag to use for the CLI update runner. */ function getCLIUpdateRunnerVersion(packagesToUpdate, next) { if (next) { return 'next'; } const updatingAngularPackage = packagesToUpdate?.find((r) => constants_1.ANGULAR_PACKAGES_REGEXP.test(r)); if (updatingAngularPackage) { // If we are updating any Angular package we can update the CLI to the target version because // migrations for @angular/core@13 can be executed using Angular/cli@13. // This is same behaviour as `npx @angular/cli@13 update @angular/core@13`. // `@angular/cli@13` -> ['', 'angular/cli', '13'] // `@angular/cli` -> ['', 'angular/cli'] const tempVersion = coerceVersionNumber(updatingAngularPackage.split('@')[2]); return semver.parse(tempVersion)?.major ?? 'latest'; } // When not updating an Angular package we cannot determine which schematic runtime the migration should to be executed in. // Typically, we can assume that the `@angular/cli` was updated previously. // Example: Angular official packages are typically updated prior to NGRX etc... // Therefore, we only update to the latest patch version of the installed major version of the Angular CLI. // This is important because we might end up in a scenario where locally Angular v12 is installed, updating NGRX from 11 to 12. // We end up using Angular ClI v13 to run the migrations if we run the migrations using the CLI installed major version + 1 logic. return version_1.VERSION.major; } /** * Runs a binary from a temporary package installation. * @param packageName The name of the package to install and run. * @param packageManager The package manager instance. * @param args The arguments to pass to the binary. * @returns The exit code of the binary. */ async function runTempBinary(packageName, packageManager, args = []) { const { workingDirectory, cleanup } = await packageManager.acquireTempPackage(packageName); try { // Remove version/tag etc... from package name // Ex: @angular/cli@latest -> @angular/cli const packageNameNoVersion = packageName.substring(0, packageName.lastIndexOf('@')); const pkgLocation = (0, node_path_1.join)(workingDirectory, 'node_modules', packageNameNoVersion); const packageJsonPath = (0, node_path_1.join)(pkgLocation, 'package.json'); // Get a binary location for this package let binPath; if ((0, node_fs_1.existsSync)(packageJsonPath)) { const content = await node_fs_1.promises.readFile(packageJsonPath, 'utf-8'); if (content) { const { bin = {} } = JSON.parse(content); const binKeys = Object.keys(bin); if (binKeys.length) { binPath = (0, node_path_1.resolve)(pkgLocation, bin[binKeys[0]]); } } } if (!binPath) { throw new Error(`Cannot locate bin for temporary package: ${packageNameNoVersion}.`); } const { status, error } = (0, node_child_process_1.spawnSync)(process.execPath, [binPath, ...args], { stdio: 'inherit', env: { ...process.env, NG_DISABLE_VERSION_CHECK: 'true', NG_CLI_ANALYTICS: 'false', }, }); if (status === null && error) { throw error; } return status ?? 0; } finally { await cleanup(); } } /** * Determines whether to force the package manager to ignore peer dependency warnings. * @param packageManager The package manager instance. * @param logger The logger instance. * @param verbose Whether to log verbose output. * @returns True if the package manager should be forced, false otherwise. */ async function shouldForcePackageManager(packageManager, logger, verbose) { // npm 7+ can fail due to it incorrectly resolving peer dependencies that have valid SemVer // ranges during an update. Update will set correct versions of dependencies within the // package.json file. The force option is set to workaround these errors. if (packageManager.name === 'npm') { const version = await packageManager.getVersion(); if (semver.gte(version, '7.0.0')) { if (verbose) { logger.info('NPM 7+ detected -- enabling force option for package installation'); } return true; } } return false; } //# sourceMappingURL=cli-version.js.map