Skip to content

Commit b219cbc

Browse files
authored
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 3af0d8a commit b219cbc

File tree

6 files changed

+83
-31
lines changed

6 files changed

+83
-31
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;
@@ -24,4 +25,18 @@ describe('CDK ng-add', () => {
2425
expect(runner.tasks.some(task => task.name === 'node-package')).toBe(true,
2526
'Expected the package manager to be scheduled in order to update lock files.');
2627
});
28+
29+
it('should respect version range from CLI ng-add command', async () => {
30+
// Simulates the behavior of the CLI `ng add` command. The command inserts the
31+
// requested package version into the `package.json` before the actual schematic runs.
32+
addPackageToPackageJson(appTree, '@angular/cdk', '^9.0.0');
33+
34+
const tree = await runner.runSchematicAsync('ng-add', {}, appTree).toPromise();
35+
const packageJson = JSON.parse(getFileContent(tree, '/package.json'));
36+
const dependencies = packageJson.dependencies;
37+
38+
expect(dependencies['@angular/cdk']).toBe('^9.0.0');
39+
expect(runner.tasks.some(task => task.name === 'node-package')).toBe(false,
40+
'Expected the package manager to not run since the CDK version was already inserted.');
41+
});
2742
});

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

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

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

28-
// Add a task to run the package manager. This is necessary because we updated the
29-
// workspace "package.json" file and we want lock files to reflect the new version range.
30-
context.addTask(new NodePackageInstallTask());
34+
// Add a task to run the package manager. This is necessary because we updated the
35+
// workspace "package.json" file and we want lock files to reflect the new version range.
36+
context.addTask(new NodePackageInstallTask());
37+
}
3138
};
3239
}

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;
@@ -79,6 +80,19 @@ describe('ng-add schematic', () => {
7980
'Expected the setup-project schematic to be scheduled.');
8081
});
8182

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

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

Lines changed: 24 additions & 7 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,13 +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 other Angular dependencies that
31-
// are setup by "@schematics/angular", we use tilde instead of caret. This is default for
32-
// Angular dependencies in new CLI projects.
33-
addPackageToPackageJson(host, '@angular/cdk', `~${materialVersion}`);
34-
addPackageToPackageJson(host, '@angular/material', `~${materialVersion}`);
50+
addPackageToPackageJson(
51+
host, '@angular/cdk', materialVersionRange || fallbackMaterialVersionRange);
3552
addPackageToPackageJson(host, '@angular/forms', angularDependencyVersion);
3653
addPackageToPackageJson(host, '@angular/animations', angularDependencyVersion);
3754

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

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

0 commit comments

Comments
 (0)