diff --git a/src/lib/schematics/BUILD.bazel b/src/lib/schematics/BUILD.bazel index f9cfa39202dc..76c5a52a6ee2 100644 --- a/src/lib/schematics/BUILD.bazel +++ b/src/lib/schematics/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_typescript//:defs.bzl", "ts_library") load("@build_bazel_rules_nodejs//:defs.bzl", "npm_package", "jasmine_node_test") +load("//:packages.bzl", "VERSION_PLACEHOLDER_REPLACEMENTS") filegroup( name = "schematics_assets", @@ -20,6 +21,7 @@ npm_package( name = "npm_package", srcs = [":schematics_assets"], deps = [":schematics"], + replacements = VERSION_PLACEHOLDER_REPLACEMENTS, ) ### Testing rules diff --git a/src/lib/schematics/install/index.spec.ts b/src/lib/schematics/install/index.spec.ts index 7369ff843f4f..1149cbd66321 100644 --- a/src/lib/schematics/install/index.spec.ts +++ b/src/lib/schematics/install/index.spec.ts @@ -3,7 +3,7 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import {getProjectFromWorkspace} from '../utils/get-project'; import {getFileContent} from '@schematics/angular/utility/test'; import {collectionPath, createTestApp} from '../utils/testing'; -import {getConfig, getAppFromConfig, getWorkspace} from '@schematics/angular/utility/config'; +import {getWorkspace} from '@schematics/angular/utility/config'; import {getIndexHtmlPath} from '../utils/ast'; import {normalize} from '@angular-devkit/core'; @@ -19,9 +19,12 @@ describe('material-install-schematic', () => { it('should update package.json', () => { const tree = runner.runSchematic('ng-add', {}, appTree); const packageJson = JSON.parse(getFileContent(tree, '/package.json')); + const angularCoreVersion = packageJson.dependencies['@angular/core']; expect(packageJson.dependencies['@angular/material']).toBeDefined(); expect(packageJson.dependencies['@angular/cdk']).toBeDefined(); + expect(packageJson.dependencies['@angular/animations']).toBe(angularCoreVersion, + 'Expected the @angular/animations package to have the same version as @angular/core.'); }); it('should add default theme', () => { diff --git a/src/lib/schematics/install/index.ts b/src/lib/schematics/install/index.ts index 2fbe6645dfba..50612b1ce4a9 100644 --- a/src/lib/schematics/install/index.ts +++ b/src/lib/schematics/install/index.ts @@ -15,13 +15,13 @@ import { Tree, } from '@angular-devkit/schematics'; import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks'; -import {addModuleImportToRootModule, getStylesPath} from '../utils/ast'; import {InsertChange} from '@schematics/angular/utility/change'; import {getWorkspace} from '@schematics/angular/utility/config'; +import {materialVersion, requiredAngularVersion} from './version-names'; +import {addModuleImportToRootModule, getStylesPath} from '../utils/ast'; import {getProjectFromWorkspace} from '../utils/get-project'; import {addHeadLink} from '../utils/html'; -import {angularVersion, materialVersion} from '../utils/lib-versions'; -import {addPackageToPackageJson} from '../utils/package'; +import {addPackageToPackageJson, getPackageVersionFromPackageJson} from '../utils/package'; import {Schema} from './schema'; import {addThemeToAppStyles} from './theming'; import * as parse5 from 'parse5'; @@ -30,7 +30,7 @@ import * as parse5 from 'parse5'; * Scaffolds the basics of a Angular Material application, this includes: * - Add Packages to package.json * - Adds pre-built themes to styles.ext - * - Adds Browser Animation to app.momdule + * - Adds Browser Animation to app.module */ export default function(options: Schema): Rule { if (!parse5) { @@ -47,13 +47,21 @@ export default function(options: Schema): Rule { ]); } -/** Add material, cdk, annimations to package.json if not already present. */ +/** Add material, cdk, animations to package.json if not already present. */ function addMaterialToPackageJson() { return (host: Tree, context: SchematicContext) => { + // Version tag of the `@angular/core` dependency that has been loaded from the `package.json` + // 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'); + addPackageToPackageJson(host, 'dependencies', '@angular/cdk', materialVersion); addPackageToPackageJson(host, 'dependencies', '@angular/material', materialVersion); - addPackageToPackageJson(host, 'dependencies', '@angular/animations', angularVersion); + addPackageToPackageJson(host, 'dependencies', '@angular/animations', + ngCoreVersionTag || requiredAngularVersion); + context.addTask(new NodePackageInstallTask()); + return host; }; } diff --git a/src/lib/schematics/install/version-names.ts b/src/lib/schematics/install/version-names.ts new file mode 100644 index 000000000000..94e18e762044 --- /dev/null +++ b/src/lib/schematics/install/version-names.ts @@ -0,0 +1,24 @@ +/** + * @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.io/license + */ + +/** Name of the Material version that is shipped together with the schematics. */ +export const materialVersion = + loadPackageVersionGracefully('@angular/cdk') || + loadPackageVersionGracefully('@angular/material'); + +/** Angular version that is needed for the Material version that comes with the schematics. */ +export const requiredAngularVersion = '0.0.0-NG'; + +/** Loads the full version from the given Angular package gracefully. */ +function loadPackageVersionGracefully(packageName: string): string | null { + try { + return require(packageName).VERSION.full; + } catch { + return null; + } +} diff --git a/src/lib/schematics/utils/lib-versions.ts b/src/lib/schematics/utils/lib-versions.ts deleted file mode 100644 index 959a2b087b4b..000000000000 --- a/src/lib/schematics/utils/lib-versions.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @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.io/license - */ - -export const materialVersion = '^6.2.0'; -export const angularVersion = '^6.0.0'; diff --git a/src/lib/schematics/utils/package.ts b/src/lib/schematics/utils/package.ts index a525028229b1..493718730456 100644 --- a/src/lib/schematics/utils/package.ts +++ b/src/lib/schematics/utils/package.ts @@ -8,11 +8,10 @@ import {Tree} from '@angular-devkit/schematics'; -/** - * Adds a package to the package.json - */ -export function addPackageToPackageJson( - host: Tree, type: string, pkg: string, version: string): Tree { +/** Adds a package to the package.json in the given host tree. */ +export function addPackageToPackageJson(host: Tree, type: string, pkg: string, + version: string): Tree { + if (host.exists('package.json')) { const sourceText = host.read('package.json')!.toString('utf-8'); const json = JSON.parse(sourceText); @@ -29,3 +28,18 @@ export function addPackageToPackageJson( 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; +} diff --git a/tools/gulp/tasks/material-release.ts b/tools/gulp/tasks/material-release.ts index d1483ed0d0f4..c9c0771451bc 100644 --- a/tools/gulp/tasks/material-release.ts +++ b/tools/gulp/tasks/material-release.ts @@ -64,12 +64,12 @@ task('material:prepare-release', sequenceTask( )); task('material:copy-schematics', () => { - src(schematicsGlobs).pipe(dest(join(releasePath, 'schematics'))); + return src(schematicsGlobs).pipe(dest(join(releasePath, 'schematics'))); }); /** Copies all prebuilt themes into the release package under `prebuilt-themes/` */ task('material:copy-prebuilt-themes', () => { - src(prebuiltThemeGlob) + return src(prebuiltThemeGlob) .pipe(gulpRename({dirname: ''})) .pipe(dest(join(releasePath, 'prebuilt-themes'))); });