devextreme-schematics 1.2.19 → 1.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/package.json +2 -2
  2. package/src/add-app-template/index.ts +30 -0
  3. package/src/add-app-template/index_spec.ts +73 -0
  4. package/src/add-layout/files/e2e/src/app.e2e-spec.ts +14 -14
  5. package/src/add-layout/files/e2e/src/app.po.ts +11 -11
  6. package/src/add-layout/files/src/app/app-navigation.ts +1 -1
  7. package/src/add-layout/files/src/app/layouts/index.ts +3 -3
  8. package/src/add-layout/files/src/app/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.component.ts +1 -1
  9. package/src/add-layout/files/src/app/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.component.ts +1 -1
  10. package/src/add-layout/files/src/app/shared/components/change-password-form/change-password-form.component.html +8 -6
  11. package/src/add-layout/files/src/app/shared/components/create-account-form/create-account-form.component.html +9 -7
  12. package/src/add-layout/files/src/app/shared/components/footer/footer.component.ts +19 -19
  13. package/src/add-layout/files/src/app/shared/components/login-form/login-form.component.html +8 -6
  14. package/src/add-layout/files/src/app/shared/components/reset-password-form/reset-password-form.component.html +8 -6
  15. package/src/add-layout/index.ts +386 -0
  16. package/src/add-layout/index_spec.ts +340 -0
  17. package/src/add-sample-views/files/pages/home/home.component.ts +10 -10
  18. package/src/add-sample-views/files/pages/profile/profile.component.ts +33 -33
  19. package/src/add-sample-views/index.ts +141 -0
  20. package/src/add-sample-views/index_spec.ts +74 -0
  21. package/src/add-view/index.ts +165 -0
  22. package/src/add-view/index_spec.ts +155 -0
  23. package/src/install/index.ts +86 -0
  24. package/src/install/index_spec.ts +106 -0
  25. package/src/install/schema.json +1 -1
  26. package/src/utility/array.ts +3 -0
  27. package/src/utility/change.js +1 -1
  28. package/src/utility/change.ts +66 -0
  29. package/src/utility/latest-versions.js +2 -2
  30. package/src/utility/latest-versions.ts +6 -0
  31. package/src/utility/modify-json-file.ts +13 -0
  32. package/src/utility/project.ts +25 -0
  33. package/src/utility/routing.js +4 -4
  34. package/src/utility/routing.ts +44 -0
  35. package/src/utility/source.ts +16 -0
  36. package/src/utility/string.ts +5 -0
  37. package/src/utility/styles.ts +33 -0
@@ -0,0 +1,340 @@
1
+ import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
2
+ import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema';
3
+ import {
4
+ NodeDependencyType,
5
+ addPackageJsonDependency,
6
+ removePackageJsonDependency
7
+ } from '@schematics/angular/utility/dependencies';
8
+ import * as path from 'path';
9
+
10
+ import { modifyJSONFile } from '../utility/modify-json-file';
11
+
12
+ const collectionPath = path.join(__dirname, '../collection.json');
13
+
14
+ describe('layout', () => {
15
+ const appOptions: any = {
16
+ name: 'testApp',
17
+ projectRoot: '',
18
+ inlineStyle: false,
19
+ inlineTemplate: false,
20
+ routing: false,
21
+ style: 'scss',
22
+ skipTests: false,
23
+ skipPackageJson: false
24
+ };
25
+
26
+ const workspaceOptions: WorkspaceOptions = {
27
+ name: 'workspace',
28
+ version: '6.0.0'
29
+ };
30
+
31
+ const options: any = {
32
+ layout: 'side-nav-outer-toolbar',
33
+ resolveConflicts: 'override',
34
+ globalNgCliVersion: '^8.0.0'
35
+ };
36
+
37
+ const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
38
+ const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
39
+ let appTree: UnitTestTree;
40
+
41
+ beforeEach(async () => {
42
+ appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
43
+ appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
44
+ });
45
+
46
+ it('should add layout with override', async () => {
47
+ const runner = new SchematicTestRunner('schematics', collectionPath);
48
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
49
+
50
+ expect(tree.files)
51
+ .toContain('/devextreme.json');
52
+ expect(tree.files)
53
+ .toContain('/src/app/app-navigation.ts');
54
+ expect(tree.files)
55
+ .toContain('/src/app/shared/components/header/header.component.ts');
56
+ expect(tree.files)
57
+ .toContain('/src/app/shared/components/login-form/login-form.component.ts');
58
+ expect(tree.files)
59
+ .toContain('/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
60
+ expect(tree.files)
61
+ .toContain('/src/app/shared/services/app-info.service.ts');
62
+ expect(tree.files)
63
+ .toContain('/src/app/shared/services/auth.service.ts');
64
+ expect(tree.files)
65
+ .toContain('/src/app/shared/services/screen.service.ts');
66
+ expect(tree.files)
67
+ .toContain('/src/app/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.component.ts');
68
+ expect(tree.files)
69
+ .toContain('/src/app/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.component.ts');
70
+ expect(tree.files)
71
+ .toContain('/src/app/layouts/single-card/single-card.component.ts');
72
+ expect(tree.files)
73
+ .toContain('/src/themes/metadata.base.json');
74
+ expect(tree.files)
75
+ .toContain('/src/themes/metadata.additional.json');
76
+
77
+ const devextremeConfigContent = tree.readContent('/devextreme.json');
78
+ expect(devextremeConfigContent).toContain('"applicationEngine": "angular"');
79
+ expect(devextremeConfigContent).toContain('"inputFile": "src/themes/metadata.additional.json"');
80
+ expect(devextremeConfigContent).toMatch(/\n\s{2}\S/g);
81
+
82
+ const componentContent = tree.readContent('/src/app/app.component.html');
83
+ expect(componentContent).toContain('app-side-nav-outer-toolbar title="{{appInfo.title}}"');
84
+
85
+ const stylesContent = tree.readContent('/src/dx-styles.scss');
86
+ expect(stylesContent).toMatch(/html, body {/);
87
+
88
+ const indexContent = tree.readContent('/src/index.html');
89
+ expect(indexContent).toMatch(/<body class="dx-viewport">/);
90
+
91
+ const angularContent = JSON.parse(tree.readContent('/angular.json'));
92
+ const styles = angularContent.projects.testApp.architect.build.options.styles;
93
+
94
+ expect(styles[0]).toBe('node_modules/devextreme/dist/css/dx.common.css');
95
+ expect(styles[1]).toBe('src/themes/generated/theme.base.css');
96
+ expect(styles[2]).toBe('src/themes/generated/theme.additional.css');
97
+
98
+ const moduleContent = tree.readContent('/src/app/app.module.ts');
99
+ expect(moduleContent)
100
+ .toContain('import { SideNavOuterToolbarModule, SideNavInnerToolbarModule, SingleCardModule }');
101
+ expect(moduleContent)
102
+ .toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
103
+ expect(moduleContent).toContain('import { AppRoutingModule }');
104
+ expect(moduleContent)
105
+ .toContain('import { FooterModule, ' +
106
+ 'ResetPasswordFormModule, ' +
107
+ 'CreateAccountFormModule, ' +
108
+ 'ChangePasswordFormModule, ' +
109
+ 'LoginFormModule }');
110
+
111
+ const testContent = tree.readContent('/e2e/src/app.e2e-spec.ts');
112
+ expect(testContent).toMatch(/'Welcome to TestApp!'/);
113
+
114
+ const testUtilsContent = tree.readContent('/e2e/src/app.po.ts');
115
+ expect(testUtilsContent).toMatch(/'app-root .dx-drawer-content .dx-card p:nth-child\(2\)'/);
116
+
117
+ const appContent = tree.readContent('/src/app/app.component.ts');
118
+ expect(appContent).toContain('templateUrl: \'./app.component.html\',');
119
+ expect(appContent).toContain('styleUrls: [\'./app.component.scss\']');
120
+ expect(appContent).toContain('selector: \'app-root\',');
121
+ expect(appContent).toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
122
+
123
+ const navigationMenu = tree.readContent(
124
+ '/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
125
+ expect(navigationMenu).toContain('@ViewChild(DxTreeViewComponent, { static: true })');
126
+ });
127
+
128
+ it('should add npm scripts', async () => {
129
+ const runner = new SchematicTestRunner('schematics', collectionPath);
130
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
131
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
132
+ expect(packageConfig.scripts['build-themes']).toBe('devextreme build');
133
+ expect(packageConfig.scripts['postinstall']).toBe('npm run build-themes');
134
+ });
135
+
136
+ it('should set static flag', async () => {
137
+ removePackageJsonDependency(appTree, '@angular/core');
138
+ addPackageJsonDependency(appTree, {
139
+ type: NodeDependencyType.Default,
140
+ name: '@angular/core',
141
+ version: '7.0.0'
142
+ });
143
+
144
+ const runner = new SchematicTestRunner('schematics', collectionPath);
145
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
146
+ const navigationMenu = tree.readContent(
147
+ '/src/app/shared/components/side-navigation-menu/side-navigation-menu.component.ts');
148
+
149
+ expect(navigationMenu).toContain('@ViewChild(DxTreeViewComponent, { static: true })');
150
+ });
151
+
152
+ it('should add npm scripts safely', async () => {
153
+ modifyJSONFile(appTree, './package.json', config => {
154
+ const scripts = config['scripts'];
155
+
156
+ scripts['build-themes'] = 'prev value 1';
157
+ scripts['postinstall'] = 'prev value 2';
158
+
159
+ return config;
160
+ });
161
+
162
+ const runner = new SchematicTestRunner('schematics', collectionPath);
163
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
164
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
165
+ expect(packageConfig.scripts['origin-build-themes']).toBe('prev value 1');
166
+ expect(packageConfig.scripts['origin-postinstall']).toBe('prev value 2');
167
+ expect(packageConfig.scripts['build-themes']).toBe('npm run origin-build-themes && devextreme build');
168
+ expect(packageConfig.scripts['postinstall']).toBe('npm run origin-postinstall && npm run build-themes');
169
+ });
170
+
171
+ it('should add angular/cdk dependency', async () => {
172
+ const runner = new SchematicTestRunner('schematics', collectionPath);
173
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
174
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
175
+
176
+ expect(packageConfig.dependencies['@angular/cdk']).toBeDefined();
177
+ });
178
+
179
+ it('should choose angular/cdk version such as angular/cli', async () => {
180
+ const runner = new SchematicTestRunner('schematics', collectionPath);
181
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
182
+ const packageConfig = JSON.parse(tree.readContent('package.json'));
183
+
184
+ expect(packageConfig.dependencies['@angular/cdk']).toBe('^8.0.0');
185
+ });
186
+
187
+ it('should update budgets if updateBudgets option is true', async () => {
188
+ const runner = new SchematicTestRunner('schematics', collectionPath);
189
+ const tree = await runner.runSchematicAsync('add-layout', {
190
+ ...options,
191
+ updateBudgets: true
192
+ }, appTree).toPromise();
193
+
194
+ const angularContent = JSON.parse(tree.readContent('/angular.json'));
195
+ const budgets = angularContent.projects.testApp.architect.build.configurations.production.budgets;
196
+
197
+ expect(budgets.length).toBe(2);
198
+ expect(budgets[0]).toEqual({
199
+ type: 'initial',
200
+ maximumWarning: '4mb',
201
+ maximumError: '7mb'
202
+ });
203
+ });
204
+
205
+ it('should not update budgets if updateBudgets option is not defined or false', async () => {
206
+ const runner = new SchematicTestRunner('schematics', collectionPath);
207
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
208
+
209
+ const angularContent = JSON.parse(tree.readContent('/angular.json'));
210
+ const budgets = angularContent.projects.testApp.architect.build.configurations.production.budgets;
211
+ const defaultBudget = {
212
+ type: 'initial',
213
+ maximumWarning: '2mb',
214
+ maximumError: '5mb'
215
+ };
216
+
217
+ expect(budgets.length).toBe(2);
218
+ expect(budgets[0]).toEqual(defaultBudget);
219
+ });
220
+
221
+ it('should add layout without override', async () => {
222
+ const runner = new SchematicTestRunner('schematics', collectionPath);
223
+
224
+ options.resolveConflicts = 'createNew';
225
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
226
+
227
+ expect(tree.files).toContain('/src/app/app1.component.ts');
228
+
229
+ const componentContent = tree.readContent('/src/app/app1.component.html');
230
+ expect(componentContent).toContain('app-side-nav-outer-toolbar title="{{appInfo.title}}"');
231
+
232
+ const appContent = tree.readContent('/src/app/app.component.ts');
233
+ expect(appContent).toMatch(/templateUrl: '.\/app.component.html',/);
234
+ expect(appContent).toMatch(/styleUrls: \['.\/app.component.scss'\]/);
235
+
236
+ const newAppContent = tree.readContent('/src/app/app1.component.ts');
237
+ expect(newAppContent).toMatch(/templateUrl: '.\/app1.component.html',/);
238
+ expect(newAppContent).toMatch(/styleUrls: \['.\/app1.component.scss'\]/);
239
+ expect(newAppContent).toContain(`import { AuthService, ScreenService, AppInfoService } from './shared/services';`);
240
+
241
+ const appInfo = tree.readContent('/src/app/shared/services/app-info.service.ts');
242
+ expect(appInfo).toContain(`return 'TestApp';`);
243
+ });
244
+
245
+ it('should add routing to layout', async () => {
246
+ let newAppTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
247
+
248
+ appOptions.routing = false;
249
+ newAppTree = await schematicRunner.runSchematicAsync(
250
+ 'application', appOptions, newAppTree).toPromise();
251
+
252
+ const runner = new SchematicTestRunner('schematics', collectionPath);
253
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
254
+
255
+ expect(tree.files).toContain('/src/app/app-routing.module.ts');
256
+ const moduleContent = tree.readContent('/src/app/app-routing.module.ts');
257
+ expect(moduleContent)
258
+ .toMatch(/imports:\s\[RouterModule\.forRoot\(routes, { useHash: true }\)\],/);
259
+
260
+ expect(moduleContent)
261
+ .toContain(`{
262
+ path: 'login-form',
263
+ component: LoginFormComponent,
264
+ canActivate: [ AuthGuardService ]
265
+ }`);
266
+ });
267
+
268
+ it('should use selected layout', async () => {
269
+ const runner = new SchematicTestRunner('schematics', collectionPath);
270
+ options.layout = 'side-nav-inner-toolbar';
271
+ options.resolveConflicts = 'override';
272
+ const tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
273
+ const content = tree.readContent('/src/app/app.component.html');
274
+
275
+ expect(content).toContain('app-side-nav-inner-toolbar title="{{appInfo.title}}"');
276
+ });
277
+
278
+ it('should consider the `project` option', async () => {
279
+ appTree = await schematicRunner.runSchematicAsync('application', {
280
+ ...appOptions,
281
+ name: 'testApp2',
282
+ projectRoot: 'projects/testApp2'
283
+ }, appTree).toPromise();
284
+
285
+ const runner = new SchematicTestRunner('schematics', collectionPath);
286
+ const tree = await runner.runSchematicAsync('add-layout', {
287
+ ...options,
288
+ project: 'testApp2'
289
+ }, appTree).toPromise();
290
+
291
+ expect(tree.files)
292
+ .toContain('/devextreme.json');
293
+ expect(tree.files)
294
+ .toContain('/projects/testApp2/src/themes/metadata.base.json');
295
+ });
296
+
297
+ it('should merge build commands in devextreme.json file', async () => {
298
+ appTree = await schematicRunner.runSchematicAsync('application', {
299
+ ...appOptions,
300
+ name: 'testApp2',
301
+ prefix: 'app2',
302
+ projectRoot: 'projects/testApp2'
303
+ }, appTree).toPromise();
304
+
305
+ const runner = new SchematicTestRunner('schematics', collectionPath);
306
+ let tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
307
+ tree = await runner.runSchematicAsync('add-layout', {
308
+ ...options,
309
+ project: 'testApp2'
310
+ }, appTree).toPromise();
311
+
312
+ const appContent = tree.readContent('projects/testApp2/src/app/app.component.ts');
313
+ expect(appContent).toContain('selector: \'app2-root\',');
314
+
315
+ const content = tree.readContent('/devextreme.json');
316
+ expect(content).toContain('"inputFile": "src/themes/metadata.base.json",');
317
+ expect(content).toContain('"inputFile": "projects/testApp2/src/themes/metadata.base.json",');
318
+ });
319
+
320
+ it('should add e2e tests only for default project', async () => {
321
+ appTree = await schematicRunner.runSchematicAsync('application', {
322
+ ...appOptions,
323
+ name: 'testApp2',
324
+ projectRoot: 'projects/testApp2'
325
+ }, appTree).toPromise();
326
+
327
+ const runner = new SchematicTestRunner('schematics', collectionPath);
328
+ let tree = await runner.runSchematicAsync('add-layout', options, appTree).toPromise();
329
+ tree = await runner.runSchematicAsync('add-layout', {
330
+ ...options,
331
+ project: 'testApp2'
332
+ }, appTree).toPromise();
333
+
334
+ const testContent = tree.readContent('/e2e/src/app.e2e-spec.ts');
335
+ expect(testContent).toContain('Welcome to TestApp!');
336
+
337
+ const testUtilsContent = tree.readContent('/e2e/src/app.po.ts');
338
+ expect(testUtilsContent).toMatch(/'app-root .dx-drawer-content .dx-card p:nth-child\(2\)'/);
339
+ });
340
+ });
@@ -1,10 +1,10 @@
1
- import { Component } from '@angular/core';
2
-
3
- @Component({
4
- templateUrl: 'home.component.html',
5
- styleUrls: [ './home.component.scss' ]
6
- })
7
-
8
- export class HomeComponent {
9
- constructor() {}
10
- }
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ templateUrl: 'home.component.html',
5
+ styleUrls: [ './home.component.scss' ]
6
+ })
7
+
8
+ export class HomeComponent {
9
+ constructor() {}
10
+ }
@@ -1,33 +1,33 @@
1
- import { Component } from '@angular/core';
2
-
3
- @Component({
4
- templateUrl: 'profile.component.html',
5
- styleUrls: [ './profile.component.scss' ]
6
- })
7
-
8
- export class ProfileComponent {
9
- employee: any;
10
- colCountByScreen: object;
11
-
12
- constructor() {
13
- this.employee = {
14
- ID: 7,
15
- FirstName: 'Sandra',
16
- LastName: 'Johnson',
17
- Prefix: 'Mrs.',
18
- Position: 'Controller',
19
- Picture: 'images/employees/06.png',
20
- BirthDate: new Date('1974/11/15'),
21
- HireDate: new Date('2005/05/11'),
22
- /* tslint:disable-next-line:max-line-length */
23
- Notes: 'Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you`ve not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.',
24
- Address: '4600 N Virginia Rd.'
25
- };
26
- this.colCountByScreen = {
27
- xs: 1,
28
- sm: 2,
29
- md: 3,
30
- lg: 4
31
- };
32
- }
33
- }
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ templateUrl: 'profile.component.html',
5
+ styleUrls: [ './profile.component.scss' ]
6
+ })
7
+
8
+ export class ProfileComponent {
9
+ employee: any;
10
+ colCountByScreen: object;
11
+
12
+ constructor() {
13
+ this.employee = {
14
+ ID: 7,
15
+ FirstName: 'Sandra',
16
+ LastName: 'Johnson',
17
+ Prefix: 'Mrs.',
18
+ Position: 'Controller',
19
+ Picture: 'images/employees/06.png',
20
+ BirthDate: new Date('1974/11/5'),
21
+ HireDate: new Date('2005/05/11'),
22
+ /* tslint:disable-next-line:max-line-length */
23
+ Notes: 'Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you`ve not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.',
24
+ Address: '4600 N Virginia Rd.'
25
+ };
26
+ this.colCountByScreen = {
27
+ xs: 1,
28
+ sm: 2,
29
+ md: 3,
30
+ lg: 4
31
+ };
32
+ }
33
+ }
@@ -0,0 +1,141 @@
1
+ import {
2
+ Rule,
3
+ Tree,
4
+ chain,
5
+ apply,
6
+ template,
7
+ move,
8
+ url,
9
+ mergeWith
10
+ } from '@angular-devkit/schematics';
11
+
12
+ import {
13
+ addDeclarationToModule,
14
+ addImportToModule
15
+ } from '@schematics/angular/utility/ast-utils';
16
+
17
+ import { addViewToRouting } from '../add-view';
18
+
19
+ import {
20
+ getApplicationPath,
21
+ getProjectName
22
+ } from '../utility/project';
23
+
24
+ import { humanize } from '../utility/string';
25
+
26
+ import {
27
+ applyChanges,
28
+ insertItemToArray
29
+ } from '../utility/change';
30
+
31
+ import { getSourceFile } from '../utility/source';
32
+
33
+ const sampleViewOptions = [
34
+ {
35
+ name: 'home',
36
+ componentName: 'HomeComponent',
37
+ relativePath: './pages/home/home.component'
38
+ }, {
39
+ name: 'profile',
40
+ componentName: 'ProfileComponent',
41
+ relativePath: './pages/profile/profile.component'
42
+ }, {
43
+ name: 'tasks',
44
+ componentName: 'TasksComponent',
45
+ relativePath: './pages/tasks/tasks.component'
46
+ }];
47
+
48
+ const devextremeOptions = [
49
+ {
50
+ componentName: 'DxDataGridModule',
51
+ relativePath: 'devextreme-angular'
52
+ }, {
53
+ componentName: 'DxFormModule',
54
+ relativePath: 'devextreme-angular'
55
+ }];
56
+
57
+ const navigations = [
58
+ ` {
59
+ text: 'Home',
60
+ path: '/home',
61
+ icon: 'home'
62
+ }`,
63
+ ` {
64
+ text: 'Examples',
65
+ icon: 'folder',
66
+ items: [
67
+ {
68
+ text: 'Profile',
69
+ path: '/profile'
70
+ },
71
+ {
72
+ text: 'Tasks',
73
+ path: '/tasks'
74
+ }
75
+ ]
76
+ }`
77
+ ];
78
+
79
+ function addImportsToRoutingModule(isView: boolean, routingPath: string, options: any) {
80
+ return (host: Tree) => {
81
+ const source = getSourceFile(host, routingPath);
82
+
83
+ if (!source) {
84
+ return host;
85
+ }
86
+
87
+ let changes;
88
+
89
+ if (isView) {
90
+ changes = addDeclarationToModule(source, routingPath, options.componentName, options.relativePath);
91
+ } else {
92
+ changes = addImportToModule(source, routingPath, options.componentName, options.relativePath);
93
+ }
94
+
95
+ return applyChanges(host, changes, routingPath);
96
+ };
97
+ }
98
+
99
+ function addDefaultNavigation(rootPath: string) {
100
+ return (host: Tree) => {
101
+ const navigationPath = rootPath + 'app-navigation.ts';
102
+
103
+ navigations.forEach((navigation) => {
104
+ const navigationSource = getSourceFile(host, navigationPath)!;
105
+ insertItemToArray(host, navigationPath, navigationSource, navigation, { location: 'end' });
106
+ });
107
+
108
+ return host;
109
+ };
110
+ }
111
+
112
+ export default function(options: any): Rule {
113
+ return (host: Tree) => {
114
+ const project = getProjectName(host, options.project);
115
+ const rootPath = getApplicationPath(host, project);
116
+ const routingPath = rootPath + 'app-routing.module.ts';
117
+ const rules: any[] = [];
118
+
119
+ const templateSource = apply(url('./files'), [
120
+ template({
121
+ project: humanize(project)
122
+ }),
123
+ move(rootPath)
124
+ ]);
125
+
126
+ rules.push(mergeWith(templateSource));
127
+
128
+ sampleViewOptions.forEach((viewOptions) => {
129
+ rules.push(addViewToRouting({ name: viewOptions.name, project, module: 'app-routing' }));
130
+ rules.push(addImportsToRoutingModule(true, routingPath, viewOptions));
131
+ });
132
+
133
+ devextremeOptions.forEach((moduleOptions) => {
134
+ rules.push(addImportsToRoutingModule(false, routingPath, moduleOptions));
135
+ });
136
+
137
+ rules.push(addDefaultNavigation(rootPath));
138
+
139
+ return chain(rules);
140
+ };
141
+ }
@@ -0,0 +1,74 @@
1
+ import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
2
+ import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema';
3
+ import * as path from 'path';
4
+
5
+ const collectionPath = path.join(__dirname, '../collection.json');
6
+
7
+ describe('sample views', () => {
8
+ const appOptions: any = {
9
+ name: 'testApp',
10
+ projectRoot: '',
11
+ inlineStyle: false,
12
+ inlineTemplate: false,
13
+ routing: true,
14
+ style: 'css',
15
+ skipTests: false,
16
+ skipPackageJson: false
17
+ };
18
+
19
+ const workspaceOptions: WorkspaceOptions = {
20
+ name: 'workspace',
21
+ version: '6.0.0'
22
+ };
23
+
24
+ const sampleViewsOptions: any = {
25
+ project: 'testApp'
26
+ };
27
+
28
+ const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
29
+ const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
30
+ let appTree: UnitTestTree;
31
+
32
+ beforeEach(async () => {
33
+ appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
34
+ appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
35
+ });
36
+
37
+ it('should add sample views', async () => {
38
+ const runner = new SchematicTestRunner('schematics', collectionPath);
39
+ let tree = await runner.runSchematicAsync('add-layout', { layout: 'side-nav-outer-toolbar' }, appTree).toPromise();
40
+ tree = await runner.runSchematicAsync('add-sample-views', sampleViewsOptions, tree).toPromise();
41
+
42
+ const moduleContent = tree.readContent('/src/app/app-routing.module.ts');
43
+
44
+ expect(moduleContent).toMatch(/component: HomeComponent/);
45
+ expect(moduleContent).toMatch(/path: 'home'/);
46
+
47
+ expect(moduleContent).toMatch(/import { HomeComponent } from /);
48
+ expect(moduleContent).toMatch(/declarations: \[HomeComponent/);
49
+
50
+ const navigationContent = tree.readContent('/src/app/app-navigation.ts');
51
+ expect(navigationContent).toMatch(/text: 'Home'/);
52
+ expect(navigationContent).toContain(`export const navigation = [
53
+ {
54
+ text: 'Home',
55
+ path: '/home',
56
+ icon: 'home'
57
+ },
58
+ {
59
+ text: 'Examples',
60
+ icon: 'folder',
61
+ items: [
62
+ {
63
+ text: 'Profile',
64
+ path: '/profile'
65
+ },
66
+ {
67
+ text: 'Tasks',
68
+ path: '/tasks'
69
+ }
70
+ ]
71
+ }
72
+ ];`);
73
+ });
74
+ });