| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- /**
- * @license
- * Copyright Google Inc. 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.io/license
- */
- const core_1 = require("@angular-devkit/core");
- const tools_1 = require("@angular-devkit/schematics/tools");
- const path_1 = require("path");
- const semver_1 = require("semver");
- const analytics_1 = require("../models/analytics");
- const schematic_command_1 = require("../models/schematic-command");
- const install_package_1 = require("../tasks/install-package");
- const color_1 = require("../utilities/color");
- const package_manager_1 = require("../utilities/package-manager");
- const package_metadata_1 = require("../utilities/package-metadata");
- const npa = require('npm-package-arg');
- class AddCommand extends schematic_command_1.SchematicCommand {
- constructor() {
- super(...arguments);
- this.allowPrivateSchematics = true;
- this.allowAdditionalArgs = true;
- this.packageManager = package_manager_1.getPackageManager(this.workspace.root);
- }
- async run(options) {
- if (!options.collection) {
- this.logger.fatal(`The "ng add" command requires a name argument to be specified eg. ` +
- `${color_1.colors.yellow('ng add [name] ')}. For more details, use "ng help".`);
- return 1;
- }
- let packageIdentifier;
- try {
- packageIdentifier = npa(options.collection);
- }
- catch (e) {
- this.logger.error(e.message);
- return 1;
- }
- if (packageIdentifier.registry && this.isPackageInstalled(packageIdentifier.name)) {
- // Already installed so just run schematic
- this.logger.info('Skipping installation: Package already installed');
- return this.executeSchematic(packageIdentifier.name, options['--']);
- }
- const usingYarn = this.packageManager === 'yarn';
- if (packageIdentifier.type === 'tag' && !packageIdentifier.rawSpec) {
- // only package name provided; search for viable version
- // plus special cases for packages that did not have peer deps setup
- let packageMetadata;
- try {
- packageMetadata = await package_metadata_1.fetchPackageMetadata(packageIdentifier.name, this.logger, {
- registry: options.registry,
- usingYarn,
- verbose: options.verbose,
- });
- }
- catch (e) {
- this.logger.error('Unable to fetch package metadata: ' + e.message);
- return 1;
- }
- const latestManifest = packageMetadata.tags['latest'];
- if (latestManifest && Object.keys(latestManifest.peerDependencies).length === 0) {
- if (latestManifest.name === '@angular/pwa') {
- const version = await this.findProjectVersion('@angular/cli');
- // tslint:disable-next-line:no-any
- const semverOptions = { includePrerelease: true };
- if (version &&
- ((semver_1.validRange(version) && semver_1.intersects(version, '7', semverOptions)) ||
- (semver_1.valid(version) && semver_1.satisfies(version, '7', semverOptions)))) {
- packageIdentifier = npa.resolve('@angular/pwa', '0.12');
- }
- }
- }
- else if (!latestManifest || (await this.hasMismatchedPeer(latestManifest))) {
- // 'latest' is invalid so search for most recent matching package
- const versionManifests = Object.values(packageMetadata.versions).filter(value => !semver_1.prerelease(value.version));
- versionManifests.sort((a, b) => semver_1.rcompare(a.version, b.version, true));
- let newIdentifier;
- for (const versionManifest of versionManifests) {
- if (!(await this.hasMismatchedPeer(versionManifest))) {
- newIdentifier = npa.resolve(packageIdentifier.name, versionManifest.version);
- break;
- }
- }
- if (!newIdentifier) {
- this.logger.warn("Unable to find compatible package. Using 'latest'.");
- }
- else {
- packageIdentifier = newIdentifier;
- }
- }
- }
- let collectionName = packageIdentifier.name;
- if (!packageIdentifier.registry) {
- try {
- const manifest = await package_metadata_1.fetchPackageManifest(packageIdentifier, this.logger, {
- registry: options.registry,
- verbose: options.verbose,
- usingYarn,
- });
- collectionName = manifest.name;
- if (await this.hasMismatchedPeer(manifest)) {
- this.logger.warn('Package has unmet peer dependencies. Adding the package may not succeed.');
- }
- }
- catch (e) {
- this.logger.error('Unable to fetch package manifest: ' + e.message);
- return 1;
- }
- }
- install_package_1.installPackage(packageIdentifier.raw, this.logger, this.packageManager);
- return this.executeSchematic(collectionName, options['--']);
- }
- async reportAnalytics(paths, options, dimensions = [], metrics = []) {
- const collection = options.collection;
- // Add the collection if it's safe listed.
- if (collection && analytics_1.isPackageNameSafeForAnalytics(collection)) {
- dimensions[core_1.analytics.NgCliAnalyticsDimensions.NgAddCollection] = collection;
- }
- else {
- delete dimensions[core_1.analytics.NgCliAnalyticsDimensions.NgAddCollection];
- }
- return super.reportAnalytics(paths, options, dimensions, metrics);
- }
- isPackageInstalled(name) {
- try {
- require.resolve(path_1.join(name, 'package.json'), { paths: [this.workspace.root] });
- return true;
- }
- catch (e) {
- if (e.code !== 'MODULE_NOT_FOUND') {
- throw e;
- }
- }
- return false;
- }
- async executeSchematic(collectionName, options = []) {
- const runOptions = {
- schematicOptions: options,
- collectionName,
- schematicName: 'ng-add',
- dryRun: false,
- force: false,
- };
- try {
- return await this.runSchematic(runOptions);
- }
- catch (e) {
- if (e instanceof tools_1.NodePackageDoesNotSupportSchematics) {
- this.logger.error(core_1.tags.oneLine `
- The package that you are trying to add does not support schematics. You can try using
- a different version of the package or contact the package author to add ng-add support.
- `);
- return 1;
- }
- throw e;
- }
- }
- async findProjectVersion(name) {
- let installedPackage;
- try {
- installedPackage = require.resolve(path_1.join(name, 'package.json'), {
- paths: [this.workspace.root],
- });
- }
- catch (_a) { }
- if (installedPackage) {
- try {
- const installed = await package_metadata_1.fetchPackageManifest(path_1.dirname(installedPackage), this.logger);
- return installed.version;
- }
- catch (_b) { }
- }
- let projectManifest;
- try {
- projectManifest = await package_metadata_1.fetchPackageManifest(this.workspace.root, this.logger);
- }
- catch (_c) { }
- if (projectManifest) {
- const version = projectManifest.dependencies[name] || projectManifest.devDependencies[name];
- if (version) {
- return version;
- }
- }
- return null;
- }
- async hasMismatchedPeer(manifest) {
- for (const peer in manifest.peerDependencies) {
- let peerIdentifier;
- try {
- peerIdentifier = npa.resolve(peer, manifest.peerDependencies[peer]);
- }
- catch (_a) {
- this.logger.warn(`Invalid peer dependency ${peer} found in package.`);
- continue;
- }
- if (peerIdentifier.type === 'version' || peerIdentifier.type === 'range') {
- try {
- const version = await this.findProjectVersion(peer);
- if (!version) {
- continue;
- }
- // tslint:disable-next-line:no-any
- const options = { includePrerelease: true };
- if (!semver_1.intersects(version, peerIdentifier.rawSpec, options) &&
- !semver_1.satisfies(version, peerIdentifier.rawSpec, options)) {
- return true;
- }
- }
- catch (_b) {
- // Not found or invalid so ignore
- continue;
- }
- }
- else {
- // type === 'tag' | 'file' | 'directory' | 'remote' | 'git'
- // Cannot accurately compare these as the tag/location may have changed since install
- }
- }
- return false;
- }
- }
- exports.AddCommand = AddCommand;
|