diff --git a/src/cdk/schematics/BUILD.bazel b/src/cdk/schematics/BUILD.bazel index dddd754ef83a..b4aab85d043b 100644 --- a/src/cdk/schematics/BUILD.bazel +++ b/src/cdk/schematics/BUILD.bazel @@ -36,7 +36,6 @@ ts_library( "@npm//glob", "@npm//parse5", "@npm//typescript", - "@npm//chalk", ], ) diff --git a/src/cdk/schematics/ng-update/index.ts b/src/cdk/schematics/ng-update/index.ts index e0966aff1ea6..a8262d3aa118 100644 --- a/src/cdk/schematics/ng-update/index.ts +++ b/src/cdk/schematics/ng-update/index.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Rule} from '@angular-devkit/schematics'; -import chalk from 'chalk'; +import {Rule, SchematicContext} from '@angular-devkit/schematics'; import {TargetVersion} from '../update-tool/target-version'; import {cdkUpgradeData} from './upgrade-data'; import {createUpgradeRule} from './upgrade-rules'; @@ -33,14 +32,15 @@ export function updateToV9(): Rule { } /** Function that will be called when the migration completed. */ -function onMigrationComplete(targetVersion: TargetVersion, hasFailures: boolean) { - console.log(); - console.log(chalk.green(` ✓ Updated Angular CDK to ${targetVersion}`)); - console.log(); +function onMigrationComplete(context: SchematicContext, targetVersion: TargetVersion, + hasFailures: boolean) { + context.logger.info(''); + context.logger.info(` ✓ Updated Angular CDK to ${targetVersion}`); + context.logger.info(''); if (hasFailures) { - console.log(chalk.yellow( + context.logger.warn( ' ⚠ Some issues were detected but could not be fixed automatically. Please check the ' + - 'output above and fix these issues manually.')); + 'output above and fix these issues manually.'); } } diff --git a/src/cdk/schematics/ng-update/upgrade-rules/class-inheritance-rule.ts b/src/cdk/schematics/ng-update/upgrade-rules/class-inheritance-rule.ts index 54bf05958f66..9e67c532f262 100644 --- a/src/cdk/schematics/ng-update/upgrade-rules/class-inheritance-rule.ts +++ b/src/cdk/schematics/ng-update/upgrade-rules/class-inheritance-rule.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import chalk from 'chalk'; import * as ts from 'typescript'; import {MigrationRule} from '../../update-tool/migration-rule'; import {PropertyNameUpgradeData} from '../data/property-names'; @@ -54,9 +53,9 @@ export class ClassInheritanceRule extends MigrationRule { if (data) { this.createFailureAtNode( node, - `Found class "${chalk.bold(className)}" which extends class ` + - `"${chalk.bold(typeName)}". Please note that the base class property ` + - `"${chalk.red(data.replace)}" has changed to "${chalk.green(data.replaceWith)}". ` + + `Found class "${className}" which extends class ` + + `"${typeName}". Please note that the base class property ` + + `"${data.replace}" has changed to "${data.replaceWith}". ` + `You may need to update your class as well.`); } }); diff --git a/src/cdk/schematics/ng-update/upgrade-rules/index.ts b/src/cdk/schematics/ng-update/upgrade-rules/index.ts index d53d445435c6..3d9e17442917 100644 --- a/src/cdk/schematics/ng-update/upgrade-rules/index.ts +++ b/src/cdk/schematics/ng-update/upgrade-rules/index.ts @@ -44,13 +44,16 @@ export const cdkMigrationRules: MigrationRuleType[] = [ type NullableMigrationRule = MigrationRuleType; +type PostMigrationFn = (context: SchematicContext, targetVersion: TargetVersion, + hasFailure: boolean) => void; + /** * Creates a Angular schematic rule that runs the upgrade for the * specified target version. */ export function createUpgradeRule( targetVersion: TargetVersion, extraRules: NullableMigrationRule[], upgradeData: RuleUpgradeData, - onMigrationCompleteFn?: (targetVersion: TargetVersion, hasFailures: boolean) => void): Rule { + onMigrationCompleteFn?: PostMigrationFn): Rule { return async (tree: Tree, context: SchematicContext) => { const logger = context.logger; const {buildPaths, testPaths} = getProjectTsConfigPaths(tree); @@ -99,7 +102,7 @@ export function createUpgradeRule( } if (onMigrationCompleteFn) { - onMigrationCompleteFn(targetVersion, hasRuleFailures); + onMigrationCompleteFn(context, targetVersion, hasRuleFailures); } }; } diff --git a/src/material/schematics/BUILD.bazel b/src/material/schematics/BUILD.bazel index d1fcaee7b887..2655d84e1e27 100644 --- a/src/material/schematics/BUILD.bazel +++ b/src/material/schematics/BUILD.bazel @@ -34,7 +34,6 @@ ts_library( "@npm//@types/node", "@npm//tslint", "@npm//typescript", - "@npm//chalk", ], ) diff --git a/src/material/schematics/ng-add/index.spec.ts b/src/material/schematics/ng-add/index.spec.ts index aa8e36f1e0da..aaafcf89be33 100644 --- a/src/material/schematics/ng-add/index.spec.ts +++ b/src/material/schematics/ng-add/index.spec.ts @@ -14,10 +14,22 @@ import {getWorkspace} from '@schematics/angular/utility/config'; describe('ng-add schematic', () => { let runner: SchematicTestRunner; let appTree: Tree; + let errorOutput: string[]; + let warnOutput: string[]; beforeEach(async () => { runner = new SchematicTestRunner('schematics', require.resolve('../collection.json')); appTree = await createTestApp(runner); + + errorOutput = []; + warnOutput = []; + runner.logger.subscribe(e => { + if (e.level === 'error') { + errorOutput.push(e.message); + } else if (e.level === 'warn') { + warnOutput.push(e.message); + } + }); }); /** Expects the given file to be in the styles of the specified workspace project. */ @@ -164,12 +176,10 @@ describe('ng-add schematic', () => { addModuleImportToRootModule( appTree, 'NoopAnimationsModule', '@angular/platform-browser/animations', project); - spyOn(console, 'warn'); await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise(); - expect(console.warn) - .toHaveBeenCalledWith( - jasmine.stringMatching(/Could not set up "BrowserAnimationsModule"/)); + expect(errorOutput.length).toBe(1); + expect(errorOutput[0]).toMatch(/Could not set up "BrowserAnimationsModule"/); }); }); @@ -231,12 +241,12 @@ describe('ng-add schematic', () => { it('should warn if the "test" target has been changed', async () => { overwriteTargetBuilder(appTree, 'test', 'thirdparty-test-builder'); - spyOn(console, 'warn'); await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise(); - expect(console.warn) - .toHaveBeenCalledWith(jasmine.stringMatching( - /not using the default builders.*cannot add the configured theme/)); + expect(errorOutput.length).toBe(0); + expect(warnOutput.length).toBe(1); + expect(warnOutput[0]).toMatch( + /not using the default builders.*cannot add the configured theme/); }); }); @@ -276,7 +286,6 @@ describe('ng-add schematic', () => { }); it('should not replace existing custom theme files', async () => { - spyOn(console, 'warn'); writeStyleFileToWorkspace(appTree, './projects/material/custom-theme.scss'); const tree = await runner.runSchematicAsync('ng-add-setup-project', {}, appTree).toPromise(); @@ -286,8 +295,8 @@ describe('ng-add schematic', () => { expect(styles).not.toContain( defaultPrebuiltThemePath, 'Expected the default prebuilt theme to be not configured.'); - expect(console.warn) - .toHaveBeenCalledWith(jasmine.stringMatching(/Could not add the selected theme/)); + expect(errorOutput.length).toBe(1); + expect(errorOutput[0]).toMatch(/Could not add the selected theme/); }); it('should not add a theme file multiple times', async () => { diff --git a/src/material/schematics/ng-add/setup-project.ts b/src/material/schematics/ng-add/setup-project.ts index 19009f81cd34..a7fda9037720 100644 --- a/src/material/schematics/ng-add/setup-project.ts +++ b/src/material/schematics/ng-add/setup-project.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {chain, Rule, Tree} from '@angular-devkit/schematics'; +import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics'; import { addModuleImportToRootModule, getProjectFromWorkspace, @@ -14,7 +14,6 @@ import { getProjectStyleFile, hasNgModuleImport, } from '@angular/cdk/schematics'; -import chalk from 'chalk'; import {getWorkspace} from '@schematics/angular/utility/config'; import {getAppModulePath} from '@schematics/angular/utility/ng-ast-utils'; import {addFontsToIndex} from './fonts/material-fonts'; @@ -49,7 +48,7 @@ export default function(options: Schema): Rule { * components of Angular Material will throw an exception. */ function addAnimationsModule(options: Schema) { - return (host: Tree) => { + return (host: Tree, context: SchematicContext) => { const workspace = getWorkspace(host); const project = getProjectFromWorkspace(workspace, options.project); const appModulePath = getAppModulePath(host, getProjectMainFile(project)); @@ -60,10 +59,11 @@ function addAnimationsModule(options: Schema) { // animations. If we would add the BrowserAnimationsModule while the NoopAnimationsModule // is already configured, we would cause unexpected behavior and runtime exceptions. if (hasNgModuleImport(host, appModulePath, noopAnimationsModuleName)) { - return console.warn(chalk.red( - `Could not set up "${chalk.bold(browserAnimationsModuleName)}" ` + - `because "${chalk.bold(noopAnimationsModuleName)}" is already imported. Please ` + - `manually set up browser animations.`)); + context.logger.error( + `Could not set up "${browserAnimationsModuleName}" ` + + `because "${noopAnimationsModuleName}" is already imported.`); + context.logger.info(`Please manually set up browser animations.`); + return; } addModuleImportToRootModule(host, browserAnimationsModuleName, @@ -84,23 +84,24 @@ function addAnimationsModule(options: Schema) { * and reset the default browser body margin. */ function addMaterialAppStyles(options: Schema) { - return (host: Tree) => { + return (host: Tree, context: SchematicContext) => { const workspace = getWorkspace(host); const project = getProjectFromWorkspace(workspace, options.project); const styleFilePath = getProjectStyleFile(project); + const logger = context.logger; if (!styleFilePath) { - console.warn(chalk.red(`Could not find the default style file for this project.`)); - console.warn(chalk.red(`Please consider manually setting up the Roboto font in your CSS.`)); + logger.error(`Could not find the default style file for this project.`); + logger.info(`Please consider manually setting up the Roboto font in your CSS.`); return; } const buffer = host.read(styleFilePath); if (!buffer) { - console.warn(chalk.red(`Could not read the default style file within the project ` + - `(${chalk.italic(styleFilePath)})`)); - console.warn(chalk.red(`Please consider manually setting up the Robot font.`)); + logger.error(`Could not read the default style file within the project ` + + `(${styleFilePath})`); + logger.info(`Please consider manually setting up the Robot font.`); return; } diff --git a/src/material/schematics/ng-add/theming/theming.ts b/src/material/schematics/ng-add/theming/theming.ts index 60dd60d71db5..45968ca6f642 100644 --- a/src/material/schematics/ng-add/theming/theming.ts +++ b/src/material/schematics/ng-add/theming/theming.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {normalize} from '@angular-devkit/core'; +import {normalize, logging} from '@angular-devkit/core'; import {WorkspaceProject, WorkspaceSchema} from '@angular-devkit/core/src/experimental/workspace'; -import {SchematicsException, Tree} from '@angular-devkit/schematics'; +import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; import { addBodyClass, defaultTargetBuilders, @@ -19,7 +19,6 @@ import { } from '@angular/cdk/schematics'; import {InsertChange} from '@schematics/angular/utility/change'; import {getWorkspace} from '@schematics/angular/utility/config'; -import chalk from 'chalk'; import {join} from 'path'; import {Schema} from '../schema'; import {createCustomTheme} from './create-custom-theme'; @@ -31,16 +30,16 @@ const prebuiltThemePathSegment = '@angular/material/prebuilt-themes'; const defaultCustomThemeFilename = 'custom-theme.scss'; /** Add pre-built styles to the main project style file. */ -export function addThemeToAppStyles(options: Schema): (host: Tree) => Tree { - return function(host: Tree): Tree { +export function addThemeToAppStyles(options: Schema): Rule { + return function(host: Tree, context: SchematicContext): Tree { const workspace = getWorkspace(host); const project = getProjectFromWorkspace(workspace, options.project); const themeName = options.theme || 'indigo-pink'; if (themeName === 'custom') { - insertCustomTheme(project, options.project, host, workspace); + insertCustomTheme(project, options.project, host, workspace, context.logger); } else { - insertPrebuiltTheme(project, host, themeName, workspace); + insertPrebuiltTheme(project, host, themeName, workspace, context.logger); } return host; @@ -69,7 +68,7 @@ export function addTypographyClass(options: Schema): (host: Tree) => Tree { * Scss file for the custom theme will be created. */ function insertCustomTheme(project: WorkspaceProject, projectName: string, host: Tree, - workspace: WorkspaceSchema) { + workspace: WorkspaceSchema, logger: logging.LoggerApi) { const stylesPath = getProjectStyleFile(project, 'scss'); const themeContent = createCustomTheme(projectName); @@ -85,13 +84,13 @@ function insertCustomTheme(project: WorkspaceProject, projectName: string, host: const customThemePath = normalize(join(project.sourceRoot, defaultCustomThemeFilename)); if (host.exists(customThemePath)) { - console.warn(chalk.yellow(`Cannot create a custom Angular Material theme because - ${chalk.bold(customThemePath)} already exists. Skipping custom theme generation.`)); + logger.warn(`Cannot create a custom Angular Material theme because + ${customThemePath} already exists. Skipping custom theme generation.`); return; } host.create(customThemePath, themeContent); - addThemeStyleToTarget(project, 'build', host, customThemePath, workspace); + addThemeStyleToTarget(project, 'build', host, customThemePath, workspace, logger); return; } @@ -104,20 +103,21 @@ function insertCustomTheme(project: WorkspaceProject, projectName: string, host: /** Insert a pre-built theme into the angular.json file. */ function insertPrebuiltTheme(project: WorkspaceProject, host: Tree, theme: string, - workspace: WorkspaceSchema) { + workspace: WorkspaceSchema, logger: logging.LoggerApi) { // Path needs to be always relative to the `package.json` or workspace root. const themePath = `./node_modules/@angular/material/prebuilt-themes/${theme}.css`; - addThemeStyleToTarget(project, 'build', host, themePath, workspace); - addThemeStyleToTarget(project, 'test', host, themePath, workspace); + addThemeStyleToTarget(project, 'build', host, themePath, workspace, logger); + addThemeStyleToTarget(project, 'test', host, themePath, workspace, logger); } /** Adds a theming style entry to the given project target options. */ function addThemeStyleToTarget(project: WorkspaceProject, targetName: 'test' | 'build', host: Tree, - assetPath: string, workspace: WorkspaceSchema) { + assetPath: string, workspace: WorkspaceSchema, + logger: logging.LoggerApi) { // Do not update the builder options in case the target does not use the default CLI builder. - if (!validateDefaultTargetBuilder(project, targetName)) { + if (!validateDefaultTargetBuilder(project, targetName, logger)) { return; } @@ -139,11 +139,10 @@ function addThemeStyleToTarget(project: WorkspaceProject, targetName: 'test' | ' // theme because these files can contain custom styles, while prebuilt themes are // always packaged and considered replaceable. if (stylePath.includes(defaultCustomThemeFilename)) { - console.warn(chalk.red(`Could not add the selected theme to the CLI project ` + - `configuration because there is already a custom theme file referenced.`)); - console.warn(chalk.red( - `Please manually add the following style file to your configuration:`)); - console.warn(chalk.yellow(` ${chalk.bold(assetPath)}`)); + logger.error(`Could not add the selected theme to the CLI project ` + + `configuration because there is already a custom theme file referenced.`); + logger.info(`Please manually add the following style file to your configuration:`); + logger.info(` ${assetPath}`); return; } else if (stylePath.includes(prebuiltThemePathSegment)) { targetOptions.styles.splice(index, 1); @@ -161,7 +160,8 @@ function addThemeStyleToTarget(project: WorkspaceProject, targetName: 'test' | ' * provided by the Angular CLI. If the configured builder does not match the default builder, * this function can either throw or just show a warning. */ -function validateDefaultTargetBuilder(project: WorkspaceProject, targetName: 'build' | 'test') { +function validateDefaultTargetBuilder(project: WorkspaceProject, targetName: 'build' | 'test', + logger: logging.LoggerApi) { const defaultBuilder = defaultTargetBuilders[targetName]; const targetConfig = project.architect && project.architect[targetName] || project.targets && project.targets[targetName]; @@ -178,7 +178,9 @@ function validateDefaultTargetBuilder(project: WorkspaceProject, targetName: 'bu `"${targetName}". The Angular Material schematics cannot add a theme to the workspace ` + `configuration if the builder has been changed.`); } else if (!isDefaultBuilder) { - console.warn(`Your project is not using the default builders for "${targetName}". This ` + + // for non-build targets we gracefully report the error without actually aborting the + // setup schematic. This is because a theme is not mandatory for running tests. + logger.warn(`Your project is not using the default builders for "${targetName}". This ` + `means that we cannot add the configured theme to the "${targetName}" target.`); } diff --git a/src/material/schematics/ng-update/index.ts b/src/material/schematics/ng-update/index.ts index cf937a9d5d2c..b7097041753b 100644 --- a/src/material/schematics/ng-update/index.ts +++ b/src/material/schematics/ng-update/index.ts @@ -6,9 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Rule} from '@angular-devkit/schematics'; +import {Rule, SchematicContext} from '@angular-devkit/schematics'; import {createUpgradeRule, TargetVersion} from '@angular/cdk/schematics'; -import chalk from 'chalk'; import {materialUpgradeData} from './upgrade-data'; import {HammerGesturesRule} from './upgrade-rules/hammer-gestures-v9/hammer-gestures-rule'; @@ -58,14 +57,15 @@ export function updateToV9(): Rule { } /** Function that will be called when the migration completed. */ -function onMigrationComplete(targetVersion: TargetVersion, hasFailures: boolean) { - console.log(); - console.log(chalk.green(` ✓ Updated Angular Material to ${targetVersion}`)); - console.log(); +function onMigrationComplete(context: SchematicContext, targetVersion: TargetVersion, + hasFailures: boolean) { + context.logger.info(''); + context.logger.info(` ✓ Updated Angular Material to ${targetVersion}`); + context.logger.info(''); if (hasFailures) { - console.log(chalk.yellow( + context.logger.warn( ' ⚠ Some issues were detected but could not be fixed automatically. Please check the ' + - 'output above and fix these issues manually.')); + 'output above and fix these issues manually.'); } } diff --git a/src/material/schematics/ng-update/upgrade-rules/hammer-gestures-v9/hammer-gestures-rule.ts b/src/material/schematics/ng-update/upgrade-rules/hammer-gestures-v9/hammer-gestures-rule.ts index 5f76bad209f4..53d2f1599f64 100644 --- a/src/material/schematics/ng-update/upgrade-rules/hammer-gestures-v9/hammer-gestures-rule.ts +++ b/src/material/schematics/ng-update/upgrade-rules/hammer-gestures-v9/hammer-gestures-rule.ts @@ -31,7 +31,6 @@ import { import {InsertChange} from '@schematics/angular/utility/change'; import {getWorkspace} from '@schematics/angular/utility/config'; import {WorkspaceProject} from '@schematics/angular/utility/workspace-models'; -import chalk from 'chalk'; import {readFileSync} from 'fs'; import {dirname, join, relative} from 'path'; import * as ts from 'typescript'; @@ -851,10 +850,10 @@ export class HammerGesturesRule extends MigrationRule { */ static globalPostMigration(tree: Tree, context: SchematicContext): PostMigrationAction { // Always notify the developer that the Hammer v9 migration does not migrate tests. - context.logger.info(chalk.yellow( + context.logger.info( '\n⚠ General notice: The HammerJS v9 migration for Angular Components is not able to ' + 'migrate tests. Please manually clean up tests in your project if they rely on ' + - (this.globalUsesHammer ? 'the deprecated Angular Material gesture config.' : 'HammerJS.'))); + (this.globalUsesHammer ? 'the deprecated Angular Material gesture config.' : 'HammerJS.')); context.logger.info( 'Read more about migrating tests: https://git.io/ng-material-v9-hammer-migrate-tests');