Skip to content

Commit

Permalink
feat(schematics): add v9 migration rules for carousel and inject toke…
Browse files Browse the repository at this point in the history
…ns (#4469)
  • Loading branch information
hsuanxyz authored Apr 14, 2020
1 parent 6fba78d commit 704cb9b
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 1 deletion.
6 changes: 5 additions & 1 deletion schematics/ng-update/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -22,7 +24,9 @@ export function updateToV9(): Rule {
DropdownTemplateRule,
DropdownClassRule,
IconTemplateRule,
CalendarTemplateRule
CalendarTemplateRule,
CarouselTemplateRule,
InjectionTokenRule
],
ruleUpgradeData,
postUpdate
Expand Down
116 changes: 116 additions & 0 deletions schematics/ng-update/test-cases/v9/deprecated-injection-tokens.spec.ts
Original file line number Diff line number Diff line change
@@ -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<any> {
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);
});

});

});
Original file line number Diff line number Diff line change
@@ -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<any> {
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: \`
<nz-carousel [nzVertical]="true"></nz-carousel>
<nz-carousel nzVertical></nz-carousel>
\`
})
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.');
});

});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { findInputsOnElementWithTag, MigrationRule, ResolvedResource, TargetVersion } from '@angular/cdk/schematics';

export class CarouselTemplateRule extends MigrationRule<null> {

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.`
});
});

}
}
40 changes: 40 additions & 0 deletions schematics/ng-update/upgrade-rules/checks/injection-token-rule.ts
Original file line number Diff line number Diff line change
@@ -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<null> {

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.`);
}
});
}
}
17 changes: 17 additions & 0 deletions schematics/utils/ng-update/module-specifiers.ts
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 704cb9b

Please sign in to comment.