Skip to content

Commit 06b7378

Browse files
devversionmmalerba
authored andcommitted
fix(ng-add): do not overwrite version range specified in ng add (#18365)
* fix(ng-add): do not overwrite version range specified in `ng add` The CLI inserts requested dependencies into the `package.json` before `ng add` schematics run. This means that we usually do not need to insert the dependency into `package.json` files. Alternatively, it could happen that the `ng add` schematics run outside of the CLI `ng add` command, or the requested dependency is dev only. In those cases we insert a version based on the current version placeholder. * fixup! fix(ng-add): do not overwrite version range specified in `ng add` Address feedback
1 parent c687172 commit 06b7378

File tree

6 files changed

+87
-39
lines changed

6 files changed

+87
-39
lines changed

src/cdk/schematics/ng-add/index.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Tree} from '@angular-devkit/schematics';
22
import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
33
import {createTestApp, getFileContent} from '../testing';
4+
import {addPackageToPackageJson} from './package-config';
45

56
describe('CDK ng-add', () => {
67
let runner: SchematicTestRunner;
@@ -22,4 +23,18 @@ describe('CDK ng-add', () => {
2223
Object.keys(dependencies).sort(),
2324
'Expected the modified "dependencies" to be sorted alphabetically.');
2425
});
26+
27+
it('should respect version range from CLI ng-add command', async () => {
28+
// Simulates the behavior of the CLI `ng add` command. The command inserts the
29+
// requested package version into the `package.json` before the actual schematic runs.
30+
addPackageToPackageJson(appTree, '@angular/cdk', '^9.0.0');
31+
32+
const tree = await runner.runSchematicAsync('ng-add', {}, appTree).toPromise();
33+
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
34+
const dependencies = packageJson.dependencies;
35+
36+
expect(dependencies['@angular/cdk']).toBe('^9.0.0');
37+
expect(runner.tasks.some(task => task.name === 'node-package')).toBe(false,
38+
'Expected the package manager to not run since the CDK version was already inserted.');
39+
});
2540
});

src/cdk/schematics/ng-add/index.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

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

1213
/** Name of the Angular CDK version that is shipped together with the schematics. */
1314
export const cdkVersion = loadPackageVersionGracefully('@angular/cdk');
@@ -21,10 +22,22 @@ export const cdkVersion = loadPackageVersionGracefully('@angular/cdk');
2122
* this ensures that there will be no error that says that the CDK does not support `ng add`.
2223
*/
2324
export default function(): Rule {
24-
return (host: Tree) => {
25-
// In order to align the CDK version with the other Angular dependencies, we use tilde
26-
// instead of caret. This is default for Angular dependencies in new CLI projects.
27-
addPackageToPackageJson(host, '@angular/cdk', `~${cdkVersion}`);
25+
return (host: Tree, context: SchematicContext) => {
26+
// The CLI inserts `@angular/cdk` into the `package.json` before this schematic runs. This
27+
// means that we do not need to insert the CDK into `package.json` files again. In some cases
28+
// though, it could happen that this schematic runs outside of the CLI `ng add` command, or
29+
// the CDK is only listed as a dev dependency. If that is the case, we insert a version based
30+
// on the current build version (substituted version placeholder).
31+
if (getPackageVersionFromPackageJson(host, '@angular/cdk') === null) {
32+
// In order to align the CDK version with other Angular dependencies that are setup by
33+
// `@schematics/angular`, we use tilde instead of caret. This is default for Angular
34+
// dependencies in new CLI projects.
35+
addPackageToPackageJson(host, '@angular/cdk', `~0.0.0-PLACEHOLDER`);
36+
37+
// Add a task to run the package manager. This is necessary because we updated the
38+
// workspace "package.json" file and we want lock files to reflect the new version range.
39+
context.addTask(new NodePackageInstallTask());
40+
}
2841
};
2942
}
3043

src/cdk/schematics/ng-add/package-config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,18 @@ export function addPackageToPackageJson(host: Tree, pkg: string, version: string
3737

3838
return host;
3939
}
40+
41+
/** Gets the version of the specified package by looking at the package.json in the given tree. */
42+
export function getPackageVersionFromPackageJson(tree: Tree, name: string): string | null {
43+
if (!tree.exists('package.json')) {
44+
return null;
45+
}
46+
47+
const packageJson = JSON.parse(tree.read('package.json')!.toString('utf8'));
48+
49+
if (packageJson.dependencies && packageJson.dependencies[name]) {
50+
return packageJson.dependencies[name];
51+
}
52+
53+
return null;
54+
}

src/material/schematics/ng-add/index.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from '@angular/cdk/schematics';
1111
import {createTestApp, getFileContent} from '@angular/cdk/schematics/testing';
1212
import {getWorkspace} from '@schematics/angular/utility/config';
13+
import {addPackageToPackageJson} from './package-config';
1314

1415
describe('ng-add schematic', () => {
1516
let runner: SchematicTestRunner;
@@ -76,6 +77,19 @@ describe('ng-add schematic', () => {
7677
expect(runner.tasks.some(task => task.name === 'run-schematic')).toBe(true);
7778
});
7879

80+
it('should respect version range from CLI ng-add command', async () => {
81+
// Simulates the behavior of the CLI `ng add` command. The command inserts the
82+
// requested package version into the `package.json` before the actual schematic runs.
83+
addPackageToPackageJson(appTree, '@angular/material', '^9.0.0');
84+
85+
const tree = await runner.runSchematicAsync('ng-add', {}, appTree).toPromise();
86+
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
87+
const dependencies = packageJson.dependencies;
88+
89+
expect(dependencies['@angular/material']).toBe('^9.0.0');
90+
expect(dependencies['@angular/cdk']).toBe('^9.0.0');
91+
});
92+
7993
it('should add default theme', async () => {
8094
const tree = await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise();
8195

src/material/schematics/ng-add/index.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,17 @@ import {Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
1010
import {NodePackageInstallTask, RunSchematicTask} from '@angular-devkit/schematics/tasks';
1111
import {addPackageToPackageJson, getPackageVersionFromPackageJson} from './package-config';
1212
import {Schema} from './schema';
13-
import {materialVersion, requiredAngularVersionRange} from './version-names';
13+
14+
/**
15+
* Version range that will be used for the Angular CDK and Angular Material if this
16+
* schematic has been run outside of the CLI `ng add` command. In those cases, there
17+
* can be no dependency on `@angular/material` in the `package.json` file, and we need
18+
* to manually insert the dependency based on the build version placeholder.
19+
*
20+
* Note that the fallback version range does not use caret, but tilde because that is
21+
* the default for Angular framework dependencies in CLI projects.
22+
*/
23+
const fallbackMaterialVersionRange = `~0.0.0-PLACEHOLDER`;
1424

1525
/**
1626
* Schematic factory entry-point for the `ng-add` schematic. The ng-add schematic will be
@@ -25,12 +35,20 @@ export default function(options: Schema): Rule {
2535
// of the CLI project. This tag should be preferred because all Angular dependencies should
2636
// have the same version tag if possible.
2737
const ngCoreVersionTag = getPackageVersionFromPackageJson(host, '@angular/core');
28-
const angularDependencyVersion = ngCoreVersionTag || requiredAngularVersionRange;
38+
const materialVersionRange = getPackageVersionFromPackageJson(host, '@angular/material');
39+
const angularDependencyVersion = ngCoreVersionTag || `0.0.0-NG`;
40+
41+
// The CLI inserts `@angular/material` into the `package.json` before this schematic runs.
42+
// This means that we do not need to insert Angular Material into `package.json` files again.
43+
// In some cases though, it could happen that this schematic runs outside of the CLI `ng add`
44+
// command, or Material is only listed a dev dependency. If that is the case, we insert a
45+
// version based on the current build version (substituted version placeholder).
46+
if (materialVersionRange === null) {
47+
addPackageToPackageJson(host, '@angular/material', fallbackMaterialVersionRange);
48+
}
2949

30-
// In order to align the Material and CDK version with the other Angular dependencies,
31-
// we use tilde instead of caret. This is default for Angular dependencies in new CLI projects.
32-
addPackageToPackageJson(host, '@angular/cdk', `~${materialVersion}`);
33-
addPackageToPackageJson(host, '@angular/material', `~${materialVersion}`);
50+
addPackageToPackageJson(
51+
host, '@angular/cdk', materialVersionRange || fallbackMaterialVersionRange);
3452
addPackageToPackageJson(host, '@angular/forms', angularDependencyVersion);
3553
addPackageToPackageJson(host, '@angular/animations', angularDependencyVersion);
3654

src/material/schematics/ng-add/version-names.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)