Skip to content

Commit 214a00d

Browse files
hsuanxyzvthinkxie
authored andcommitted
fix(schematic:ng-add): duplicate add bugs (#1623)
* fix(schematic:ng-add): duplicate add bugs * fix(schematic:ng-add): theme exists
1 parent feffeb8 commit 214a00d

3 files changed

Lines changed: 93 additions & 12 deletions

File tree

schematics/ng-add/index.ts

Lines changed: 89 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@ import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
33
import * as ts from 'typescript';
44
import { addModuleImportToRootModule, getSourceFile } from '../utils/ast';
55
import { createCustomTheme } from '../utils/custom-theme';
6-
import { addSymbolToNgModuleMetadata, findNodes, insertAfterLastOccurrence } from '../utils/devkit-utils/ast-utils';
7-
import { InsertChange } from '../utils/devkit-utils/change';
6+
import {
7+
addSymbolToNgModuleMetadata,
8+
findNodes,
9+
getDecoratorMetadata,
10+
insertAfterLastOccurrence
11+
} from '../utils/devkit-utils/ast-utils';
12+
import { Change, InsertChange, ReplaceChange } from '../utils/devkit-utils/change';
813
import { getProjectFromWorkspace, getWorkspace, Project, Workspace } from '../utils/devkit-utils/config';
914
import { getAppModulePath } from '../utils/devkit-utils/ng-ast-utils';
1015
import { insertImport } from '../utils/devkit-utils/route-utils';
@@ -42,29 +47,96 @@ function addI18n(options: Schema): (host: Tree) => Tree {
4247
throw new SchematicsException(`Invalid locale-symbol`);
4348
}
4449

45-
const allImports = findNodes(moduleSource, ts.SyntaxKind.ImportDeclaration);
46-
4750
const changes = [
4851
insertImport(moduleSource, modulePath, 'NZ_I18N', 'ng-zorro-antd'),
4952
insertImport(moduleSource, modulePath, locale, 'ng-zorro-antd'),
5053
insertImport(moduleSource, modulePath, 'registerLocaleData', '@angular/common'),
5154
insertImport(moduleSource, modulePath, localePrefix, `@angular/common/locales/${localePrefix}`, true),
52-
...addSymbolToNgModuleMetadata(moduleSource, modulePath, 'providers', `{ provide: NZ_I18N, useValue: ${locale} }`, null),
53-
insertAfterLastOccurrence(allImports, `\n\nregisterLocaleData(${localePrefix});`, modulePath, 0)
55+
registerLocaleData(moduleSource, modulePath, localePrefix),
56+
...insertI18nTokenProvide(moduleSource, modulePath, locale)
5457
];
5558

5659
const recorder = host.beginUpdate(modulePath);
5760
changes.forEach((change) => {
5861
if (change instanceof InsertChange) {
5962
recorder.insertLeft(change.pos, change.toAdd);
6063
}
64+
65+
if (change instanceof ReplaceChange) {
66+
recorder.remove(change.pos, change.oldText.length);
67+
recorder.insertLeft(change.pos, change.newText);
68+
}
69+
6170
});
6271

6372
host.commitUpdate(recorder);
6473
return host;
6574
};
6675
}
6776

77+
function insertI18nTokenProvide(moduleSource: ts.SourceFile, modulePath: string, locale: string): Change[] {
78+
const metadataField = 'providers';
79+
const nodes = getDecoratorMetadata(moduleSource, 'NgModule', '@angular/core');
80+
const addProvide = addSymbolToNgModuleMetadata(moduleSource, modulePath, 'providers', `{ provide: NZ_I18N, useValue: ${locale} }`, null);
81+
let node: any = nodes[0]; // tslint:disable-line:no-any
82+
83+
if (!node) {
84+
return [];
85+
}
86+
87+
const matchingProperties: ts.ObjectLiteralElement[] =
88+
(node as ts.ObjectLiteralExpression).properties
89+
.filter(prop => prop.kind === ts.SyntaxKind.PropertyAssignment)
90+
.filter((prop: ts.PropertyAssignment) => {
91+
const name = prop.name;
92+
switch (name.kind) {
93+
case ts.SyntaxKind.Identifier:
94+
return (name as ts.Identifier).getText(moduleSource) === metadataField;
95+
case ts.SyntaxKind.StringLiteral:
96+
return (name as ts.StringLiteral).text === metadataField;
97+
}
98+
99+
return false;
100+
});
101+
102+
if (!matchingProperties) {
103+
return [];
104+
}
105+
106+
if (matchingProperties.length) {
107+
const assignment = matchingProperties[0] as ts.PropertyAssignment;
108+
if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
109+
return [];
110+
}
111+
const arrLiteral = assignment.initializer as ts.ArrayLiteralExpression;
112+
if (arrLiteral.elements.length === 0) {
113+
return addProvide;
114+
} else {
115+
node = arrLiteral.elements.filter(e => e.getText && e.getText().includes('NZ_I18N'));
116+
if (node.length === 0) {
117+
return addProvide;
118+
}
119+
return node.map(e => new ReplaceChange(modulePath, e.getStart(), e.getText(), `{ provide: NZ_I18N, useValue: ${locale} }`));
120+
}
121+
} else {
122+
return addProvide;
123+
}
124+
125+
}
126+
127+
/** 注册 ng 国际化 */
128+
function registerLocaleData(moduleSource: ts.SourceFile, modulePath: string, locale: string): Change {
129+
const allImports = findNodes(moduleSource, ts.SyntaxKind.ImportDeclaration);
130+
const allFun = findNodes(moduleSource, ts.SyntaxKind.ExpressionStatement);
131+
const registerLocaleDataFun = allFun.filter(node => {
132+
const fun = node.getChildren();
133+
return fun[0].getChildren()[0] && fun[0].getChildren()[0].getText() === 'registerLocaleData';
134+
});
135+
return registerLocaleDataFun.length === 0
136+
? insertAfterLastOccurrence(allImports, `\n\nregisterLocaleData(${locale});`, modulePath, 0)
137+
: new ReplaceChange(modulePath, registerLocaleDataFun[0].getStart(), registerLocaleDataFun[0].getText(), `registerLocaleData(${locale});`);
138+
}
139+
68140
/** 降级 less */
69141
function downgradeLess(): (host: Tree) => Tree {
70142
return (host: Tree) => {
@@ -90,7 +162,7 @@ function addModulesToAppModule(options: Schema): (host: Tree) => Tree {
90162
addModuleImportToRootModule(host, 'BrowserAnimationsModule', '@angular/platform-browser/animations', project);
91163
addModuleImportToRootModule(host, 'FormsModule', '@angular/forms', project);
92164
addModuleImportToRootModule(host, 'HttpClientModule', '@angular/common/http', project);
93-
addModuleImportToRootModule(host, 'NgZorroAntdModule.forRoot()', 'ng-zorro-antd', project);
165+
addModuleImportToRootModule(host, 'NgZorroAntdModule', 'ng-zorro-antd', project);
94166

95167
return host;
96168
};
@@ -113,7 +185,16 @@ export function addThemeToAppStyles(options: Schema): (host: Tree) => Tree {
113185
/** 将预设样式写入 theme.less,并添加到 angular.json */
114186
function insertCustomTheme(project: Project, host: Tree, workspace: Workspace): void {
115187
const themePath = 'src/theme.less';
116-
host.create(themePath, createCustomTheme());
188+
const customTheme = createCustomTheme();
189+
if (host.exists(themePath)) {
190+
const beforeContent = host.read(themePath).toString('utf8');
191+
if (beforeContent.indexOf(customTheme) === -1) {
192+
host.overwrite(themePath, `${customTheme}\n${beforeContent}`);
193+
}
194+
} else {
195+
host.create(themePath, createCustomTheme());
196+
}
197+
117198
if (project.architect) {
118199
addStyleToTarget(project.architect.build, host, themePath, workspace);
119200
addStyleToTarget(project.architect.test, host, themePath, workspace);

schematics/utils/devkit-utils/ast-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ export function addSymbolToNgModuleMetadata(
364364

365365
let toInsert: string;
366366
let position = node.getEnd();
367-
if (node.kind == ts.SyntaxKind.ObjectLiteralExpression) {
367+
if (node.kind == ts.SyntaxKind.ObjectLiteralExpression && node === arrLiteral) {
368368
// We haven't found the field in the metadata declaration. Insert a new
369369
// field.
370370
const expr = node as ts.ObjectLiteralExpression;

schematics/utils/devkit-utils/change.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export class RemoveChange implements Change {
7575
order: number;
7676
description: string;
7777

78-
constructor(public path: string, private pos: number, private toRemove: string) {
78+
constructor(public path: string, public pos: number, public toRemove: string) {
7979
if (pos < 0) {
8080
throw new Error('Negative positions are invalid');
8181
}
@@ -101,8 +101,8 @@ export class ReplaceChange implements Change {
101101
order: number;
102102
description: string;
103103

104-
constructor(public path: string, private pos: number, private oldText: string,
105-
private newText: string) {
104+
constructor(public path: string, public pos: number, public oldText: string,
105+
public newText: string) {
106106
if (pos < 0) {
107107
throw new Error('Negative positions are invalid');
108108
}

0 commit comments

Comments
 (0)