diff --git a/schematics/ng-update/index.ts b/schematics/ng-update/index.ts index c9b255481ec..3e8a4cc521a 100644 --- a/schematics/ng-update/index.ts +++ b/schematics/ng-update/index.ts @@ -3,9 +3,11 @@ import { createUpgradeRule, TargetVersion } from '@angular/cdk/schematics'; import chalk from 'chalk'; import { ruleUpgradeData } from './upgrade-data'; import { CalendarTemplateRule } from './upgrade-rules/checks/calendar-input-rule'; +import { CarouselTemplateRule } from "./upgrade-rules/checks/carousel-like-template-rule"; import { DropdownClassRule } from './upgrade-rules/checks/dropdown-class-rule'; import { DropdownTemplateRule } from './upgrade-rules/checks/dropdown-template-rule'; import { IconTemplateRule } from './upgrade-rules/checks/icon-template-rule'; +import { InjectionTokenRule } from "./upgrade-rules/checks/injection-token-rule"; import { TooltipLikeTemplateRule } from './upgrade-rules/checks/tooltip-like-template-rule'; /** Entry point for the migration schematics with target of NG-ZORRO v7 */ @@ -22,7 +24,9 @@ export function updateToV9(): Rule { DropdownTemplateRule, DropdownClassRule, IconTemplateRule, - CalendarTemplateRule + CalendarTemplateRule, + CarouselTemplateRule, + InjectionTokenRule ], ruleUpgradeData, postUpdate diff --git a/schematics/ng-update/test-cases/v9/deprecated-injection-tokens.spec.ts b/schematics/ng-update/test-cases/v9/deprecated-injection-tokens.spec.ts new file mode 100644 index 00000000000..521d00b45fd --- /dev/null +++ b/schematics/ng-update/test-cases/v9/deprecated-injection-tokens.spec.ts @@ -0,0 +1,116 @@ +import { getSystemPath, normalize, virtualFs } from '@angular-devkit/core'; +import { TempScopedNodeJsSyncHost } from '@angular-devkit/core/node/testing'; +import { HostTree } from '@angular-devkit/schematics'; +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import * as shx from 'shelljs'; +import { SchematicsTestNGConfig, SchematicsTestTsConfig } from '../config'; + +describe('injection tokens migration', () => { + let runner: SchematicTestRunner; + let host: TempScopedNodeJsSyncHost; + let tree: UnitTestTree; + let tmpDirPath: string; + let previousWorkingDir: string; + let warnOutput: string[]; + + beforeEach(() => { + runner = new SchematicTestRunner('test', require.resolve('../../../migration.json')); + host = new TempScopedNodeJsSyncHost(); + tree = new UnitTestTree(new HostTree(host)); + + writeFile('/tsconfig.json', JSON.stringify(SchematicsTestTsConfig)); + writeFile('/angular.json', JSON.stringify(SchematicsTestNGConfig)); + + warnOutput = []; + runner.logger.subscribe(logEntry => { + if (logEntry.level === 'warn') { + warnOutput.push(logEntry.message); + } + }); + + previousWorkingDir = shx.pwd(); + tmpDirPath = getSystemPath(host.root); + + shx.cd(tmpDirPath); + + writeFakeAngular(); + }); + + afterEach(() => { + shx.cd(previousWorkingDir); + shx.rm('-r', tmpDirPath); + }); + + function writeFakeAngular(): void { writeFile('/node_modules/@angular/core/index.d.ts', ``); } + + function writeFile(filePath: string, contents: string): void { + host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); + } + + // tslint:disable-next-line:no-any + async function runMigration(): Promise { + await runner.runSchematicAsync('migration-v9', {}, tree).toPromise(); + } + + describe('Injection Tokens', () => { + + it('should properly report invalid deprecated injection tokens', async() => { + writeFile('/index.ts', ` + import { NZ_NOTIFICATION_CONFIG, NZ_MESSAGE_CONFIG, NZ_DEFAULT_EMPTY_CONTENT } from 'ng-zorro-antd'; + + `); + await runMigration(); + + const tokensWarn = [ + 'index.ts@2:16 - Found deprecated symbol "NZ_NOTIFICATION_CONFIG" which has been removed. Use "NZ_CONFIG" to ' + + 'instead please.', + 'index.ts@2:40 - Found deprecated symbol "NZ_MESSAGE_CONFIG" which has been removed. Use "NZ_CONFIG" to ' + + 'instead please.', + 'index.ts@2:59 - Found deprecated symbol "NZ_DEFAULT_EMPTY_CONTENT" which has been removed. Use "NZ_CONFIG" ' + + 'to instead please.' + ]; + + tokensWarn.forEach(warn => { + expect(warnOutput).toContain(warn); + }); + }); + + it('should properly report invalid deprecated injection tokens whit secondary entry', async() => { + writeFile('/index.ts', ` + import { NZ_NOTIFICATION_CONFIG} from 'ng-zorro-antd/notification'; + import { NZ_DEFAULT_EMPTY_CONTENT } from 'ng-zorro-antd/empty'; + import { NZ_MESSAGE_CONFIG } from 'ng-zorro-antd/message'; + + `); + await runMigration(); + + const tokensWarn = [ + 'index.ts@2:16 - Found deprecated symbol "NZ_NOTIFICATION_CONFIG" which has been removed. Use "NZ_CONFIG" ' + + 'to instead please.', + 'index.ts@3:16 - Found deprecated symbol "NZ_DEFAULT_EMPTY_CONTENT" which has been removed. Use "NZ_CONFIG" ' + + 'to instead please.', + 'index.ts@4:16 - Found deprecated symbol "NZ_MESSAGE_CONFIG" which has been removed. Use "NZ_CONFIG" to ' + + 'instead please.' + ]; + + tokensWarn.forEach(warn => { + expect(warnOutput).toContain(warn); + }); + }); + + it('should not report invalid deprecated injection tokens in other package', async() => { + writeFile('/index.ts', ` + import { NZ_NOTIFICATION_CONFIG} from 'other/notification'; + import { NZ_DEFAULT_EMPTY_CONTENT } from 'other/empty'; + import { NZ_MESSAGE_CONFIG } from 'other/message'; + import { NZ_NOTIFICATION_CONFIG, NZ_MESSAGE_CONFIG, NZ_DEFAULT_EMPTY_CONTENT } from 'other'; + + `); + await runMigration(); + + expect(warnOutput.length).toBe(0); + }); + + }); + +}); diff --git a/schematics/ng-update/test-cases/v9/deprecated-inputs-carousel.spec.ts b/schematics/ng-update/test-cases/v9/deprecated-inputs-carousel.spec.ts new file mode 100644 index 00000000000..f738694a702 --- /dev/null +++ b/schematics/ng-update/test-cases/v9/deprecated-inputs-carousel.spec.ts @@ -0,0 +1,78 @@ +import { getSystemPath, normalize, virtualFs } from '@angular-devkit/core'; +import { TempScopedNodeJsSyncHost } from '@angular-devkit/core/node/testing'; +import { HostTree } from '@angular-devkit/schematics'; +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import * as shx from 'shelljs'; +import { SchematicsTestNGConfig, SchematicsTestTsConfig } from '../config'; + +describe('carousel migration', () => { + let runner: SchematicTestRunner; + let host: TempScopedNodeJsSyncHost; + let tree: UnitTestTree; + let tmpDirPath: string; + let previousWorkingDir: string; + let warnOutput: string[]; + + beforeEach(() => { + runner = new SchematicTestRunner('test', require.resolve('../../../migration.json')); + host = new TempScopedNodeJsSyncHost(); + tree = new UnitTestTree(new HostTree(host)); + + writeFile('/tsconfig.json', JSON.stringify(SchematicsTestTsConfig)); + writeFile('/angular.json', JSON.stringify(SchematicsTestNGConfig)); + + warnOutput = []; + runner.logger.subscribe(logEntry => { + if (logEntry.level === 'warn') { + warnOutput.push(logEntry.message); + } + }); + + previousWorkingDir = shx.pwd(); + tmpDirPath = getSystemPath(host.root); + + shx.cd(tmpDirPath); + + writeFakeAngular(); + }); + + afterEach(() => { + shx.cd(previousWorkingDir); + shx.rm('-r', tmpDirPath); + }); + + function writeFakeAngular(): void { writeFile('/node_modules/@angular/core/index.d.ts', ``); } + + function writeFile(filePath: string, contents: string): void { + host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); + } + + // tslint:disable-next-line:no-any + async function runMigration(): Promise { + await runner.runSchematicAsync('migration-v9', {}, tree).toPromise(); + } + + describe('Carousel', () => { + + it('should properly report invalid deprecated input', async() => { + writeFile('/index.ts', `; + import {Component} from '@angular/core' + @Component({ + template: \` + + + \` + }) + export class MyComp { + }`); + await runMigration(); + + expect(warnOutput).toContain('index.ts@6:24 - Found deprecated "[nzVertical]" input. Use "[nzDotPosition]" to ' + + 'instead please.'); + expect(warnOutput).toContain('index.ts@5:25 - Found deprecated "[nzVertical]" input. Use "[nzDotPosition]" to ' + + 'instead please.'); + }); + + }); + +}); diff --git a/schematics/ng-update/upgrade-rules/checks/carousel-like-template-rule.ts b/schematics/ng-update/upgrade-rules/checks/carousel-like-template-rule.ts new file mode 100644 index 00000000000..ac7d9abb777 --- /dev/null +++ b/schematics/ng-update/upgrade-rules/checks/carousel-like-template-rule.ts @@ -0,0 +1,19 @@ +import { findInputsOnElementWithTag, MigrationRule, ResolvedResource, TargetVersion } from '@angular/cdk/schematics'; + +export class CarouselTemplateRule extends MigrationRule { + + ruleEnabled = this.targetVersion === TargetVersion.V9; + + visitTemplate(template: ResolvedResource): void { + + findInputsOnElementWithTag(template.content, 'nzVertical', ['nz-carousel']) + .forEach(offset => { + this.failures.push({ + filePath: template.filePath, + position: template.getCharacterAndLineOfPosition(offset), + message: `Found deprecated "[nzVertical]" input. Use "[nzDotPosition]" to instead please.` + }); + }); + + } +} diff --git a/schematics/ng-update/upgrade-rules/checks/injection-token-rule.ts b/schematics/ng-update/upgrade-rules/checks/injection-token-rule.ts new file mode 100644 index 00000000000..7357c567ea1 --- /dev/null +++ b/schematics/ng-update/upgrade-rules/checks/injection-token-rule.ts @@ -0,0 +1,40 @@ +import { MigrationRule, TargetVersion } from '@angular/cdk/schematics'; +import * as ts from 'typescript'; +import { isNgZorroImportDeclaration } from "../../../utils/ng-update/module-specifiers"; + +export class InjectionTokenRule extends MigrationRule { + + ruleEnabled = this.targetVersion === TargetVersion.V9; + + visitNode(node: ts.Node): void { + if (ts.isImportDeclaration(node)) { + this._visitImportDeclaration(node); + } + } + + private _visitImportDeclaration(node: ts.ImportDeclaration): void { + if (!isNgZorroImportDeclaration(node) || !node.importClause || + !node.importClause.namedBindings) { + return; + } + + const namedBindings = node.importClause.namedBindings; + + if (ts.isNamedImports(namedBindings)) { + this._checkInjectionToken(namedBindings); + } + } + + private _checkInjectionToken(namedImports: ts.NamedImports): void { + namedImports.elements.filter(element => ts.isIdentifier(element.name)).forEach(element => { + const importName = element.name.text; + + const deprecatedTokens = ['NZ_MESSAGE_CONFIG', 'NZ_NOTIFICATION_CONFIG', 'NZ_DEFAULT_EMPTY_CONTENT']; + + if (deprecatedTokens.indexOf(importName) !== -1) { + this.createFailureAtNode( + element, `Found deprecated symbol "${importName}" which has been removed. Use "NZ_CONFIG" to instead please.`); + } + }); + } +} diff --git a/schematics/utils/ng-update/module-specifiers.ts b/schematics/utils/ng-update/module-specifiers.ts new file mode 100644 index 00000000000..5022a487bdf --- /dev/null +++ b/schematics/utils/ng-update/module-specifiers.ts @@ -0,0 +1,17 @@ +import { getImportDeclaration } from '@angular/cdk/schematics'; +import * as ts from 'typescript'; + +export const materialModuleSpecifier = 'ng-zorro-antd'; + +export function isNgZorroImportDeclaration(node: ts.Node): boolean { + return isNgZorroDeclaration(getImportDeclaration(node)); +} + +function isNgZorroDeclaration(declaration: ts.ImportDeclaration|ts.ExportDeclaration): boolean { + if (!declaration.moduleSpecifier) { + return false; + } + + const moduleSpecifier = declaration.moduleSpecifier.getText(); + return moduleSpecifier.indexOf(materialModuleSpecifier) !== -1 +}