Skip to content

fix(ng-add): do not overwrite version range specified in ng add #18365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/cdk/schematics/ng-add/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Tree} from '@angular-devkit/schematics';
import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
import {createTestApp, getFileContent} from '../testing';
import {addPackageToPackageJson} from './package-config';

describe('CDK ng-add', () => {
let runner: SchematicTestRunner;
Expand All @@ -24,4 +25,18 @@ describe('CDK ng-add', () => {
expect(runner.tasks.some(task => task.name === 'node-package')).toBe(true,
'Expected the package manager to be scheduled in order to update lock files.');
});

it('should respect version range from CLI ng-add command', async () => {
// Simulates the behavior of the CLI `ng add` command. The command inserts the
// requested package version into the `package.json` before the actual schematic runs.
addPackageToPackageJson(appTree, '@angular/cdk', '^9.0.0');

const tree = await runner.runSchematicAsync('ng-add', {}, appTree).toPromise();
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
const dependencies = packageJson.dependencies;

expect(dependencies['@angular/cdk']).toBe('^9.0.0');
expect(runner.tasks.some(task => task.name === 'node-package')).toBe(false,
'Expected the package manager to not run since the CDK version was already inserted.');
});
});
23 changes: 15 additions & 8 deletions src/cdk/schematics/ng-add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks';
import {addPackageToPackageJson} from './package-config';
import {addPackageToPackageJson, getPackageVersionFromPackageJson} from './package-config';

/**
* Schematic factory entry-point for the `ng-add` schematic. The ng-add schematic will be
Expand All @@ -20,13 +20,20 @@ import {addPackageToPackageJson} from './package-config';
*/
export default function(): Rule {
return (host: Tree, context: SchematicContext) => {
// In order to align the CDK version with other Angular dependencies that are setup
// by "@schematics/angular", we use tilde instead of caret. This is default for Angular
// dependencies in new CLI projects.
addPackageToPackageJson(host, '@angular/cdk', `~0.0.0-PLACEHOLDER`);
// The CLI inserts `@angular/cdk` into the `package.json` before this schematic runs. This
// means that we do not need to insert the CDK into `package.json` files again. In some cases
// though, it could happen that this schematic runs outside of the CLI `ng add` command, or
// the CDK is only listed as a dev dependency. If that is the case, we insert a version based
// on the current build version (substituted version placeholder).
if (getPackageVersionFromPackageJson(host, '@angular/cdk') === null) {
// In order to align the CDK version with other Angular dependencies that are setup by
// `@schematics/angular`, we use tilde instead of caret. This is default for Angular
// dependencies in new CLI projects.
addPackageToPackageJson(host, '@angular/cdk', `~0.0.0-PLACEHOLDER`);

// Add a task to run the package manager. This is necessary because we updated the
// workspace "package.json" file and we want lock files to reflect the new version range.
context.addTask(new NodePackageInstallTask());
// Add a task to run the package manager. This is necessary because we updated the
// workspace "package.json" file and we want lock files to reflect the new version range.
context.addTask(new NodePackageInstallTask());
}
};
}
15 changes: 15 additions & 0 deletions src/cdk/schematics/ng-add/package-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,18 @@ export function addPackageToPackageJson(host: Tree, pkg: string, version: string

return host;
}

/** Gets the version of the specified package by looking at the package.json in the given tree. */
export function getPackageVersionFromPackageJson(tree: Tree, name: string): string | null {
if (!tree.exists('package.json')) {
return null;
}

const packageJson = JSON.parse(tree.read('package.json')!.toString('utf8'));

if (packageJson.dependencies && packageJson.dependencies[name]) {
return packageJson.dependencies[name];
}

return null;
}
14 changes: 14 additions & 0 deletions src/material/schematics/ng-add/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from '@angular/cdk/schematics';
import {createTestApp, getFileContent} from '@angular/cdk/schematics/testing';
import {getWorkspace} from '@schematics/angular/utility/config';
import {addPackageToPackageJson} from './package-config';

describe('ng-add schematic', () => {
let runner: SchematicTestRunner;
Expand Down Expand Up @@ -79,6 +80,19 @@ describe('ng-add schematic', () => {
'Expected the setup-project schematic to be scheduled.');
});

it('should respect version range from CLI ng-add command', async () => {
// Simulates the behavior of the CLI `ng add` command. The command inserts the
// requested package version into the `package.json` before the actual schematic runs.
addPackageToPackageJson(appTree, '@angular/material', '^9.0.0');

const tree = await runner.runSchematicAsync('ng-add', {}, appTree).toPromise();
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
const dependencies = packageJson.dependencies;

expect(dependencies['@angular/material']).toBe('^9.0.0');
expect(dependencies['@angular/cdk']).toBe('^9.0.0');
});

it('should add default theme', async () => {
const tree = await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();

Expand Down
31 changes: 24 additions & 7 deletions src/material/schematics/ng-add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,17 @@ import {Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {NodePackageInstallTask, RunSchematicTask} from '@angular-devkit/schematics/tasks';
import {addPackageToPackageJson, getPackageVersionFromPackageJson} from './package-config';
import {Schema} from './schema';
import {materialVersion, requiredAngularVersionRange} from './version-names';

/**
* Version range that will be used for the Angular CDK and Angular Material if this
* schematic has been run outside of the CLI `ng add` command. In those cases, there
* can be no dependency on `@angular/material` in the `package.json` file, and we need
* to manually insert the dependency based on the build version placeholder.
*
* Note that the fallback version range does not use caret, but tilde because that is
* the default for Angular framework dependencies in CLI projects.
*/
const fallbackMaterialVersionRange = `~0.0.0-PLACEHOLDER`;

/**
* Schematic factory entry-point for the `ng-add` schematic. The ng-add schematic will be
Expand All @@ -25,13 +35,20 @@ export default function(options: Schema): Rule {
// of the CLI project. This tag should be preferred because all Angular dependencies should
// have the same version tag if possible.
const ngCoreVersionTag = getPackageVersionFromPackageJson(host, '@angular/core');
const angularDependencyVersion = ngCoreVersionTag || requiredAngularVersionRange;
const materialVersionRange = getPackageVersionFromPackageJson(host, '@angular/material');
const angularDependencyVersion = ngCoreVersionTag || `0.0.0-NG`;

// The CLI inserts `@angular/material` into the `package.json` before this schematic runs.
// This means that we do not need to insert Angular Material into `package.json` files again.
// In some cases though, it could happen that this schematic runs outside of the CLI `ng add`
// command, or Material is only listed a dev dependency. If that is the case, we insert a
// version based on the current build version (substituted version placeholder).
if (materialVersionRange === null) {
addPackageToPackageJson(host, '@angular/material', fallbackMaterialVersionRange);
}

// In order to align the Material and CDK version with other Angular dependencies that
// are setup by "@schematics/angular", we use tilde instead of caret. This is default for
// Angular dependencies in new CLI projects.
addPackageToPackageJson(host, '@angular/cdk', `~${materialVersion}`);
addPackageToPackageJson(host, '@angular/material', `~${materialVersion}`);
addPackageToPackageJson(
host, '@angular/cdk', materialVersionRange || fallbackMaterialVersionRange);
addPackageToPackageJson(host, '@angular/forms', angularDependencyVersion);
addPackageToPackageJson(host, '@angular/animations', angularDependencyVersion);

Expand Down
16 changes: 0 additions & 16 deletions src/material/schematics/ng-add/version-names.ts

This file was deleted.