devextreme-schematics 1.2.20 → 1.2.24
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +2 -2
- package/src/add-app-template/index.ts +30 -0
- package/src/add-app-template/index_spec.ts +73 -0
- package/src/add-layout/files/e2e/src/app.e2e-spec.ts +14 -14
- package/src/add-layout/files/e2e/src/app.po.ts +11 -11
- package/src/add-layout/files/src/app/app-navigation.ts +1 -1
- package/src/add-layout/files/src/app/layouts/index.ts +3 -3
- package/src/add-layout/files/src/app/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.component.ts +1 -1
- package/src/add-layout/files/src/app/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.component.ts +1 -1
- package/src/add-layout/files/src/app/shared/components/change-password-form/change-password-form.component.html +8 -6
- package/src/add-layout/files/src/app/shared/components/create-account-form/create-account-form.component.html +9 -7
- package/src/add-layout/files/src/app/shared/components/footer/footer.component.ts +19 -19
- package/src/add-layout/files/src/app/shared/components/login-form/login-form.component.html +8 -6
- package/src/add-layout/files/src/app/shared/components/reset-password-form/reset-password-form.component.html +8 -6
- package/src/add-layout/files/src/dx-styles.scss +4 -0
- package/src/add-layout/index.ts +386 -0
- package/src/add-layout/index_spec.ts +340 -0
- package/src/add-sample-views/files/pages/home/home.component.ts +10 -10
- package/src/add-sample-views/files/pages/profile/profile.component.ts +33 -33
- package/src/add-sample-views/index.ts +141 -0
- package/src/add-sample-views/index_spec.ts +74 -0
- package/src/add-view/index.ts +165 -0
- package/src/add-view/index_spec.ts +155 -0
- package/src/install/index.ts +86 -0
- package/src/install/index_spec.ts +106 -0
- package/src/install/schema.json +1 -1
- package/src/utility/array.ts +3 -0
- package/src/utility/change.js +1 -1
- package/src/utility/change.ts +66 -0
- package/src/utility/latest-versions.js +2 -2
- package/src/utility/latest-versions.ts +6 -0
- package/src/utility/modify-json-file.ts +13 -0
- package/src/utility/project.ts +25 -0
- package/src/utility/routing.js +4 -4
- package/src/utility/routing.ts +44 -0
- package/src/utility/source.ts +16 -0
- package/src/utility/string.ts +5 -0
- package/src/utility/styles.ts +33 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
import {
|
2
|
+
Rule,
|
3
|
+
chain,
|
4
|
+
Tree,
|
5
|
+
SchematicsException,
|
6
|
+
externalSchematic
|
7
|
+
} from '@angular-devkit/schematics';
|
8
|
+
|
9
|
+
import {
|
10
|
+
findModuleFromOptions
|
11
|
+
} from '@schematics/angular/utility/find-module';
|
12
|
+
|
13
|
+
import {
|
14
|
+
insertItemToArray
|
15
|
+
} from '../utility/change';
|
16
|
+
|
17
|
+
import {
|
18
|
+
hasComponentInRoutes,
|
19
|
+
getRoute,
|
20
|
+
findRoutesInSource
|
21
|
+
} from '../utility/routing';
|
22
|
+
|
23
|
+
import { getSourceFile } from '../utility/source';
|
24
|
+
|
25
|
+
import { strings, basename, normalize, dirname } from '@angular-devkit/core';
|
26
|
+
|
27
|
+
import {
|
28
|
+
getProjectName,
|
29
|
+
getApplicationPath
|
30
|
+
} from '../utility/project';
|
31
|
+
import { humanize } from '../utility/string';
|
32
|
+
|
33
|
+
function getPathToFile(host: Tree, projectName: string, moduleName: string) {
|
34
|
+
const rootPath = getApplicationPath(host, projectName);
|
35
|
+
|
36
|
+
try {
|
37
|
+
return findModuleFromOptions(host, { name: moduleName, path: rootPath, module: moduleName });
|
38
|
+
} catch (error) {
|
39
|
+
return;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
function addViewToNavigation(options: any) {
|
44
|
+
return (host: Tree) => {
|
45
|
+
const navigationName = 'app-navigation';
|
46
|
+
const navigationFilePath = getPathToFile(host, options.project, navigationName);
|
47
|
+
|
48
|
+
if (!navigationFilePath) {
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
|
52
|
+
const source = getSourceFile(host, navigationFilePath)!;
|
53
|
+
const pagePath = strings.dasherize(options.name);
|
54
|
+
const name = strings.dasherize(basename(normalize(options.name)));
|
55
|
+
const title = humanize(name);
|
56
|
+
const navigationItem = ` {
|
57
|
+
text: '${title}',
|
58
|
+
path: '/${pagePath}',
|
59
|
+
icon: '${options.icon}'
|
60
|
+
}`;
|
61
|
+
|
62
|
+
insertItemToArray(host, navigationFilePath, source, navigationItem, { location: 'end' });
|
63
|
+
|
64
|
+
return host;
|
65
|
+
};
|
66
|
+
}
|
67
|
+
|
68
|
+
function addRedirectRoute(host: Tree, routingModulePath: string, page: string) {
|
69
|
+
const source = getSourceFile(host, routingModulePath)!;
|
70
|
+
const content = source.getText();
|
71
|
+
if (content.match(/path:\s*'\*\*'/g)) {
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
|
75
|
+
const routes = findRoutesInSource(source)!;
|
76
|
+
const redirectRoute = ` {
|
77
|
+
path: '**',
|
78
|
+
redirectTo: '${strings.dasherize(page)}'
|
79
|
+
}`;
|
80
|
+
|
81
|
+
insertItemToArray(host, routingModulePath, routes, redirectRoute, { location: 'end' });
|
82
|
+
}
|
83
|
+
|
84
|
+
export function addViewToRouting(options: any) {
|
85
|
+
return (host: Tree) => {
|
86
|
+
const routingModulePath = getPathToFile(host, options.project, options.module);
|
87
|
+
|
88
|
+
if (!routingModulePath) {
|
89
|
+
throw new SchematicsException('Specified module does not exist.');
|
90
|
+
}
|
91
|
+
|
92
|
+
addRedirectRoute(host, routingModulePath, options.name);
|
93
|
+
|
94
|
+
const source = getSourceFile(host, routingModulePath)!;
|
95
|
+
const routes = findRoutesInSource(source);
|
96
|
+
|
97
|
+
if (!routes) {
|
98
|
+
throw new SchematicsException('No routes found.');
|
99
|
+
}
|
100
|
+
|
101
|
+
if (!hasComponentInRoutes(routes, options.name)) {
|
102
|
+
const route = getRoute(options.name);
|
103
|
+
insertItemToArray(host, routingModulePath, routes, route);
|
104
|
+
}
|
105
|
+
return host;
|
106
|
+
};
|
107
|
+
}
|
108
|
+
|
109
|
+
function getPathForView(name: string) {
|
110
|
+
if (name.includes('/')) {
|
111
|
+
return name;
|
112
|
+
}
|
113
|
+
return 'pages/' + name;
|
114
|
+
}
|
115
|
+
|
116
|
+
function getModuleName(addRoute: boolean, moduleName: string) {
|
117
|
+
if (!moduleName && addRoute) {
|
118
|
+
return 'app-routing';
|
119
|
+
}
|
120
|
+
return moduleName;
|
121
|
+
}
|
122
|
+
|
123
|
+
function addContentToView(options: any) {
|
124
|
+
return (host: Tree) => {
|
125
|
+
const name = strings.dasherize(basename(normalize(options.name)));
|
126
|
+
const path = `${dirname(options.name)}/${name}`;
|
127
|
+
const title = humanize(name);
|
128
|
+
const componentPath = `/${getApplicationPath(host, options.project)}${path}/${name}.component.html`;
|
129
|
+
if (host.exists(componentPath)) {
|
130
|
+
host.overwrite(
|
131
|
+
componentPath,
|
132
|
+
`<h2 class="content-block">${title}</h2>
|
133
|
+
<div class="content-block">
|
134
|
+
<div class="dx-card responsive-paddings">Put your content here</div>
|
135
|
+
</div>
|
136
|
+
`);
|
137
|
+
}
|
138
|
+
return host;
|
139
|
+
};
|
140
|
+
}
|
141
|
+
|
142
|
+
export default function(options: any): Rule {
|
143
|
+
return (host: Tree) => {
|
144
|
+
const addRoute = options.addRoute;
|
145
|
+
const project = getProjectName(host, options);
|
146
|
+
const module = getModuleName(addRoute, options.module);
|
147
|
+
const name = getPathForView(options.name);
|
148
|
+
const rules = [externalSchematic('@schematics/angular', 'component', {
|
149
|
+
name,
|
150
|
+
project,
|
151
|
+
module,
|
152
|
+
skipTests: options.skipTests,
|
153
|
+
inlineStyle: options.inlineStyle,
|
154
|
+
prefix: options.prefix
|
155
|
+
}),
|
156
|
+
addContentToView({ name, project })
|
157
|
+
];
|
158
|
+
|
159
|
+
if (addRoute) {
|
160
|
+
rules.push(addViewToRouting({ name, project, module }));
|
161
|
+
rules.push(addViewToNavigation({ name, icon: options.icon, project }));
|
162
|
+
}
|
163
|
+
return chain(rules);
|
164
|
+
};
|
165
|
+
}
|
@@ -0,0 +1,155 @@
|
|
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('view', () => {
|
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 componentOptions: any = {
|
25
|
+
name: 'test',
|
26
|
+
inlineStyle: false,
|
27
|
+
inlineTemplate: false,
|
28
|
+
changeDetection: 'Default',
|
29
|
+
styleext: 'css',
|
30
|
+
skipImport: true,
|
31
|
+
module: undefined,
|
32
|
+
export: false,
|
33
|
+
project: 'testApp'
|
34
|
+
};
|
35
|
+
|
36
|
+
const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
|
37
|
+
const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
|
38
|
+
let appTree: UnitTestTree;
|
39
|
+
|
40
|
+
beforeEach(async () => {
|
41
|
+
appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
|
42
|
+
appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
|
43
|
+
});
|
44
|
+
|
45
|
+
it('should create new view', async () => {
|
46
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
47
|
+
let tree = await runner.runSchematicAsync('add-layout', { layout: 'side-nav-outer-toolbar' }, appTree).toPromise();
|
48
|
+
tree = await runner.runSchematicAsync('add-view', componentOptions, appTree).toPromise();
|
49
|
+
|
50
|
+
expect(tree.files).toContain('/src/app/pages/test/test.component.ts');
|
51
|
+
expect(tree.files).toContain('/src/app/pages/test/test.component.html');
|
52
|
+
|
53
|
+
const content = tree.readContent('/src/app/pages/test/test.component.html');
|
54
|
+
|
55
|
+
expect(content).toMatch(/<h2 class="content-block">Test<\/h2>/);
|
56
|
+
});
|
57
|
+
|
58
|
+
it('should add view to default routing module', async () => {
|
59
|
+
const options = { ...componentOptions, addRoute: true };
|
60
|
+
|
61
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
62
|
+
let tree = await runner.runSchematicAsync('add-layout', { layout: 'side-nav-outer-toolbar' }, appTree).toPromise();
|
63
|
+
tree = await runner.runSchematicAsync('add-view', options, tree).toPromise();
|
64
|
+
tree = await runner.runSchematicAsync('add-view', { ...options, name: 'test2' }, tree).toPromise();
|
65
|
+
const moduleContent = tree.readContent('/src/app/app-routing.module.ts');
|
66
|
+
|
67
|
+
expect(moduleContent).toContain(`const routes: Routes = [
|
68
|
+
{
|
69
|
+
path: 'pages/test2',
|
70
|
+
component: Test2Component,
|
71
|
+
canActivate: [ AuthGuardService ]
|
72
|
+
},
|
73
|
+
{
|
74
|
+
path: 'pages/test',
|
75
|
+
component: TestComponent,
|
76
|
+
canActivate: [ AuthGuardService ]
|
77
|
+
},
|
78
|
+
{
|
79
|
+
path: 'login-form',
|
80
|
+
component: LoginFormComponent,
|
81
|
+
canActivate: [ AuthGuardService ]
|
82
|
+
},
|
83
|
+
{
|
84
|
+
path: '**',
|
85
|
+
redirectTo: 'pages/test'
|
86
|
+
}
|
87
|
+
];`);
|
88
|
+
});
|
89
|
+
|
90
|
+
it('should add view to other routing module', async () => {
|
91
|
+
const options = { ...componentOptions, addRoute: true, module: 'test/test-routing' };
|
92
|
+
|
93
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
94
|
+
let tree = await runner.runExternalSchematicAsync('@schematics/angular', 'module', {
|
95
|
+
name: 'test',
|
96
|
+
routing: true,
|
97
|
+
project: 'testApp'
|
98
|
+
}, appTree).toPromise();
|
99
|
+
|
100
|
+
tree = await runner.runSchematicAsync('add-layout', {
|
101
|
+
layout: 'side-nav-outer-toolbar',
|
102
|
+
project: 'testApp',
|
103
|
+
name: 'test'
|
104
|
+
}, tree).toPromise();
|
105
|
+
tree = await runner.runSchematicAsync('add-view', options, tree).toPromise();
|
106
|
+
|
107
|
+
const moduleContent = tree.readContent('/src/app/test/test-routing.module.ts');
|
108
|
+
|
109
|
+
expect(moduleContent).toMatch(/component: TestComponent/);
|
110
|
+
expect(moduleContent).toMatch(/path: 'pages\/test'/);
|
111
|
+
expect(moduleContent).toContain('canActivate: [ AuthGuardService ]');
|
112
|
+
});
|
113
|
+
|
114
|
+
it('should add view to navigation', async () => {
|
115
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
116
|
+
let tree = await runner.runSchematicAsync('add-layout', { layout: 'side-nav-outer-toolbar' }, appTree).toPromise();
|
117
|
+
tree = await runner.runSchematicAsync('add-view', componentOptions, tree).toPromise();
|
118
|
+
|
119
|
+
componentOptions.name = 'some test';
|
120
|
+
componentOptions.icon = 'home';
|
121
|
+
tree = await runner.runSchematicAsync('add-view', componentOptions, tree).toPromise();
|
122
|
+
|
123
|
+
const moduleContent = tree.readContent('/src/app/app-navigation.ts');
|
124
|
+
|
125
|
+
expect(moduleContent).toMatch(/text: 'Some Test'/);
|
126
|
+
expect(moduleContent).toMatch(/icon: 'home'/);
|
127
|
+
expect(moduleContent).toMatch(/text: 'Test'/);
|
128
|
+
expect(moduleContent).toMatch(/icon: 'folder'/);
|
129
|
+
|
130
|
+
expect(moduleContent).toContain(`navigation = [
|
131
|
+
{
|
132
|
+
text: 'Test',
|
133
|
+
path: '/pages/test',
|
134
|
+
icon: 'folder'
|
135
|
+
},
|
136
|
+
{
|
137
|
+
text: 'Some Test',
|
138
|
+
path: '/pages/some-test',
|
139
|
+
icon: 'home'
|
140
|
+
}
|
141
|
+
];`);
|
142
|
+
const pageContent = tree.readContent('/src/app/pages/some-test/some-test.component.html');
|
143
|
+
expect(pageContent).toMatch(/<h2 class="content-block">Some Test<\/h2>/);
|
144
|
+
});
|
145
|
+
|
146
|
+
it('should create new view with path', async () => {
|
147
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
148
|
+
componentOptions.name = 'folder/test';
|
149
|
+
let tree = await runner.runSchematicAsync('add-layout', { layout: 'side-nav-outer-toolbar' }, appTree).toPromise();
|
150
|
+
tree = await runner.runSchematicAsync('add-view', componentOptions, appTree).toPromise();
|
151
|
+
|
152
|
+
expect(tree.files).toContain('/src/app/folder/test/test.component.ts');
|
153
|
+
expect(tree.files).toContain('/src/app/folder/test/test.component.html');
|
154
|
+
});
|
155
|
+
});
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import {
|
2
|
+
Rule,
|
3
|
+
Tree,
|
4
|
+
SchematicContext,
|
5
|
+
chain
|
6
|
+
} from '@angular-devkit/schematics';
|
7
|
+
|
8
|
+
import { addStylesToApp } from '../utility/styles';
|
9
|
+
|
10
|
+
import {
|
11
|
+
NodeDependencyType,
|
12
|
+
addPackageJsonDependency
|
13
|
+
} from '@schematics/angular/utility/dependencies';
|
14
|
+
|
15
|
+
import {
|
16
|
+
NodePackageInstallTask
|
17
|
+
} from '@angular-devkit/schematics/tasks';
|
18
|
+
|
19
|
+
import { latestVersions } from '../utility/latest-versions';
|
20
|
+
import { modifyJSONFile } from '../utility/modify-json-file';
|
21
|
+
|
22
|
+
export default function(options: any): Rule {
|
23
|
+
return chain([
|
24
|
+
(host: Tree) => addDevExtremeDependency(host, { dxversion: options.dxversion }),
|
25
|
+
(host: Tree) => addDevExtremeCSS(host, { project: options.project }),
|
26
|
+
(host: Tree) => reqisterJSZip(host),
|
27
|
+
(_, context: SchematicContext) => {
|
28
|
+
context.addTask(new NodePackageInstallTask());
|
29
|
+
}
|
30
|
+
]);
|
31
|
+
}
|
32
|
+
|
33
|
+
function addDevExtremeDependency(host: Tree, options: any) {
|
34
|
+
addPackageJsonDependency(host, {
|
35
|
+
type: NodeDependencyType.Default,
|
36
|
+
name: 'devextreme',
|
37
|
+
version: options.dxversion || latestVersions['devextreme']
|
38
|
+
});
|
39
|
+
addPackageJsonDependency(host, {
|
40
|
+
type: NodeDependencyType.Default,
|
41
|
+
name: 'devextreme-angular',
|
42
|
+
version: options.dxversion || latestVersions['devextreme-angular']
|
43
|
+
});
|
44
|
+
addPackageJsonDependency(host, {
|
45
|
+
type: NodeDependencyType.Dev,
|
46
|
+
name: 'devextreme-cli',
|
47
|
+
version: latestVersions['devextreme-cli']
|
48
|
+
});
|
49
|
+
addPackageJsonDependency(host, {
|
50
|
+
type: NodeDependencyType.Dev,
|
51
|
+
name: 'devextreme-themebuilder',
|
52
|
+
version: options.dxversion || latestVersions['devextreme']
|
53
|
+
});
|
54
|
+
|
55
|
+
return host;
|
56
|
+
}
|
57
|
+
|
58
|
+
function addDevExtremeCSS(host: Tree, options: any) {
|
59
|
+
modifyJSONFile(host, './angular.json', config => {
|
60
|
+
|
61
|
+
return addStylesToApp(host, options.project, config);
|
62
|
+
});
|
63
|
+
|
64
|
+
return host;
|
65
|
+
}
|
66
|
+
|
67
|
+
function reqisterJSZip(host: Tree) {
|
68
|
+
modifyJSONFile(host, './tsconfig.app.json', config => {
|
69
|
+
const compilerOptions = config['compilerOptions'];
|
70
|
+
let paths = compilerOptions['paths'];
|
71
|
+
|
72
|
+
if (!paths) {
|
73
|
+
paths = {};
|
74
|
+
}
|
75
|
+
|
76
|
+
if (!paths['jszip']) {
|
77
|
+
paths['jszip'] = ['node_modules/jszip/dist/jszip.min.js'];
|
78
|
+
}
|
79
|
+
|
80
|
+
compilerOptions['paths'] = paths;
|
81
|
+
|
82
|
+
return config;
|
83
|
+
});
|
84
|
+
|
85
|
+
return host;
|
86
|
+
}
|
@@ -0,0 +1,106 @@
|
|
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
|
+
import { latestVersions } from '../utility/latest-versions';
|
5
|
+
|
6
|
+
const collectionPath = path.join(__dirname, '../collection.json');
|
7
|
+
|
8
|
+
describe('install', () => {
|
9
|
+
// TODO: Extract workspase preparing somewhere
|
10
|
+
const appOptions: any = {
|
11
|
+
name: 'testApp',
|
12
|
+
projectRoot: '',
|
13
|
+
inlineStyle: false,
|
14
|
+
inlineTemplate: false,
|
15
|
+
routing: true,
|
16
|
+
style: 'css',
|
17
|
+
skipTests: false,
|
18
|
+
skipPackageJson: false
|
19
|
+
};
|
20
|
+
|
21
|
+
const workspaceOptions: WorkspaceOptions = {
|
22
|
+
name: 'workspace',
|
23
|
+
// TODO: use angular latest-versions module
|
24
|
+
version: '6.0.0'
|
25
|
+
};
|
26
|
+
|
27
|
+
const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
|
28
|
+
const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
|
29
|
+
let appTree: UnitTestTree;
|
30
|
+
|
31
|
+
beforeEach(async () => {
|
32
|
+
appTree = await schematicRunner.runSchematicAsync('workspace', workspaceOptions).toPromise();
|
33
|
+
appTree = await schematicRunner.runSchematicAsync('application', appOptions, appTree).toPromise();
|
34
|
+
});
|
35
|
+
|
36
|
+
it('should add devextreme dependency (default)', async () => {
|
37
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
38
|
+
const tree = await runner.runSchematicAsync('install', {}, appTree).toPromise();
|
39
|
+
const packageConfig = JSON.parse(tree.readContent('package.json'));
|
40
|
+
|
41
|
+
expect(packageConfig.dependencies['devextreme']).toBe(latestVersions['devextreme']);
|
42
|
+
expect(packageConfig.dependencies['devextreme-angular']).toBe(latestVersions['devextreme-angular']);
|
43
|
+
expect(packageConfig.devDependencies['devextreme-themebuilder']).toBe(latestVersions['devextreme']);
|
44
|
+
});
|
45
|
+
|
46
|
+
it('should add devextreme dependency (custom)', async () => {
|
47
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
48
|
+
const tree = await runner.runSchematicAsync('install', { dxversion: '18.2.5' }, appTree).toPromise();
|
49
|
+
const packageConfig = JSON.parse(tree.readContent('package.json'));
|
50
|
+
|
51
|
+
expect(packageConfig.dependencies.devextreme).toBe('18.2.5');
|
52
|
+
expect(packageConfig.devDependencies['devextreme-themebuilder']).toBe('18.2.5');
|
53
|
+
});
|
54
|
+
|
55
|
+
it('should add devextreme cli devDependency', async () => {
|
56
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
57
|
+
const tree = await runner.runSchematicAsync('install', { dxversion: '18.2.5' }, appTree).toPromise();
|
58
|
+
const packageConfig = JSON.parse(tree.readContent('package.json'));
|
59
|
+
|
60
|
+
expect(packageConfig.devDependencies['devextreme-cli']).toBeDefined();
|
61
|
+
});
|
62
|
+
|
63
|
+
it('should add devextreme styles', async () => {
|
64
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
65
|
+
const tree = await runner.runSchematicAsync('install', {}, appTree).toPromise();
|
66
|
+
const angularConfig = JSON.parse(tree.readContent('angular.json'));
|
67
|
+
const styles = angularConfig['projects']['testApp']['architect']['build']['options']['styles'];
|
68
|
+
|
69
|
+
expect(styles[0]).toBe('node_modules/devextreme/dist/css/dx.common.css');
|
70
|
+
expect(styles[1]).toBe('node_modules/devextreme/dist/css/dx.light.css');
|
71
|
+
});
|
72
|
+
|
73
|
+
it('should register jszip', async () => {
|
74
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
75
|
+
const tree = await runner.runSchematicAsync('install', {}, appTree).toPromise();
|
76
|
+
const tsconfig = JSON.parse(tree.readContent('tsconfig.app.json'));
|
77
|
+
const jszip = tsconfig['compilerOptions']['paths']['jszip'];
|
78
|
+
|
79
|
+
expect(jszip[0]).toBe('node_modules/jszip/dist/jszip.min.js');
|
80
|
+
});
|
81
|
+
|
82
|
+
it('should add devextreme styles to the specified project', async () => {
|
83
|
+
const secondAppOptions: any = {
|
84
|
+
name: 'testApp2',
|
85
|
+
inlineStyle: false,
|
86
|
+
inlineTemplate: false,
|
87
|
+
projectRoot: 'src2',
|
88
|
+
routing: true,
|
89
|
+
style: 'css',
|
90
|
+
skipTests: false,
|
91
|
+
skipPackageJson: false
|
92
|
+
};
|
93
|
+
|
94
|
+
appTree = await schematicRunner.runSchematicAsync('application', secondAppOptions, appTree).toPromise();
|
95
|
+
|
96
|
+
const runner = new SchematicTestRunner('schematics', collectionPath);
|
97
|
+
const tree = await runner.runSchematicAsync('install', { project: 'testApp2' }, appTree).toPromise();
|
98
|
+
const angularConfig = JSON.parse(tree.readContent('angular.json'));
|
99
|
+
const styles = angularConfig['projects']['testApp2']['architect']['build']['options']['styles'];
|
100
|
+
|
101
|
+
expect(styles[0]).toBe('node_modules/devextreme/dist/css/dx.common.css');
|
102
|
+
expect(styles[1]).toBe('node_modules/devextreme/dist/css/dx.light.css');
|
103
|
+
|
104
|
+
expect(angularConfig['projects']['testApp']['architect']['build']['options']['styles'].length).toBe(1);
|
105
|
+
});
|
106
|
+
});
|
package/src/install/schema.json
CHANGED
package/src/utility/change.js
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
import { Tree } from '@angular-devkit/schematics';
|
2
|
+
import { InsertChange, Change } from '@schematics/angular/utility/change';
|
3
|
+
|
4
|
+
import {
|
5
|
+
Node
|
6
|
+
} from 'typescript';
|
7
|
+
|
8
|
+
const newLine = `
|
9
|
+
`;
|
10
|
+
|
11
|
+
export function applyChanges(host: Tree, changes: Change[], filePath: string) {
|
12
|
+
const recorder = host.beginUpdate(filePath);
|
13
|
+
|
14
|
+
changes.forEach((change: InsertChange) => {
|
15
|
+
recorder.insertLeft(change.pos, change.toAdd);
|
16
|
+
});
|
17
|
+
|
18
|
+
host.commitUpdate(recorder);
|
19
|
+
|
20
|
+
return host;
|
21
|
+
}
|
22
|
+
|
23
|
+
// TODO: implement options.index
|
24
|
+
// TODO: implement spaces shift calculation
|
25
|
+
export function insertItemToArray(
|
26
|
+
host: Tree,
|
27
|
+
filePath: string,
|
28
|
+
node: Node,
|
29
|
+
item: string,
|
30
|
+
options: { location: 'start' | 'end' } = { location: 'start' }
|
31
|
+
) {
|
32
|
+
const isItemValid = /^\s*\{[\s\S]*\}\s*$/m.test(item);
|
33
|
+
if (!isItemValid) {
|
34
|
+
return host;
|
35
|
+
}
|
36
|
+
|
37
|
+
const nodeContent = node.getText();
|
38
|
+
const nodePosition = node.getStart();
|
39
|
+
const leftBracketPosition = nodePosition + nodeContent.indexOf('[');
|
40
|
+
const rightBracketPosition = nodePosition + nodeContent.lastIndexOf(']');
|
41
|
+
let itemPosition = leftBracketPosition + 1;
|
42
|
+
let fileRecorder = host.beginUpdate(filePath);
|
43
|
+
|
44
|
+
item = newLine + item;
|
45
|
+
|
46
|
+
const isNodeEmpty = !/\[[\s\S]*\S+[\s\S]*\]/m.test(nodeContent);
|
47
|
+
if (isNodeEmpty) {
|
48
|
+
const formattedArray = `[${newLine}]`;
|
49
|
+
fileRecorder.remove(leftBracketPosition, rightBracketPosition - leftBracketPosition + 1);
|
50
|
+
fileRecorder.insertLeft(leftBracketPosition, formattedArray);
|
51
|
+
host.commitUpdate(fileRecorder);
|
52
|
+
fileRecorder = host.beginUpdate(filePath);
|
53
|
+
} else {
|
54
|
+
if (options.location === 'end') {
|
55
|
+
itemPosition = nodePosition + nodeContent.lastIndexOf('}') + 1;
|
56
|
+
item = ',' + item;
|
57
|
+
} else {
|
58
|
+
item = item + ',';
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
fileRecorder.insertLeft(itemPosition, item);
|
63
|
+
host.commitUpdate(fileRecorder);
|
64
|
+
|
65
|
+
return host;
|
66
|
+
}
|
@@ -2,8 +2,8 @@
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
// TODO: implement
|
4
4
|
exports.latestVersions = {
|
5
|
-
'devextreme': '^21.
|
6
|
-
'devextreme-angular': '^21.
|
5
|
+
'devextreme': '^21.2.4',
|
6
|
+
'devextreme-angular': '^21.2.4',
|
7
7
|
'devextreme-cli': 'latest'
|
8
8
|
};
|
9
9
|
//# sourceMappingURL=latest-versions.js.map
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Tree } from '@angular-devkit/schematics';
|
2
|
+
|
3
|
+
export function modifyJSONFile(host: Tree, path: string, callback: (obj: any) => any) {
|
4
|
+
let serializedConfig = host.read(path)!.toString();
|
5
|
+
serializedConfig = serializedConfig.replace(/\/\*[\S\s]+?\*\/\r?\n/g, '');
|
6
|
+
let obj = JSON.parse(serializedConfig);
|
7
|
+
|
8
|
+
obj = callback(obj);
|
9
|
+
|
10
|
+
host.overwrite(path, `${JSON.stringify(obj, null, 2)}\n`);
|
11
|
+
|
12
|
+
return host;
|
13
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { Tree } from '@angular-devkit/schematics';
|
2
|
+
import { getWorkspace } from '@schematics/angular/utility/config';
|
3
|
+
|
4
|
+
export function getProjectName(host: Tree, project: any) {
|
5
|
+
const projectName = project;
|
6
|
+
const workspace = getWorkspace(host);
|
7
|
+
const projects = Object.keys(workspace.projects);
|
8
|
+
|
9
|
+
return projectName && projects.indexOf(projectName) > -1 ? projectName : workspace.defaultProject;
|
10
|
+
}
|
11
|
+
|
12
|
+
export function getApplicationPath(host: Tree, projectName: string) {
|
13
|
+
const sourcePath = getSourceRootPath(host, projectName);
|
14
|
+
return sourcePath ? `${sourcePath}/app/` : 'src/app/';
|
15
|
+
}
|
16
|
+
|
17
|
+
export function getSourceRootPath(host: Tree, projectName: string) {
|
18
|
+
const project = getWorkspace(host).projects[projectName];
|
19
|
+
return project.sourceRoot || project.root;
|
20
|
+
}
|
21
|
+
|
22
|
+
export function getRootPath(host: Tree, projectName: string) {
|
23
|
+
const project = getWorkspace(host).projects[projectName];
|
24
|
+
return project.root;
|
25
|
+
}
|
package/src/utility/routing.js
CHANGED
@@ -12,10 +12,10 @@ function hasComponentInRoutes(routes, name) {
|
|
12
12
|
}
|
13
13
|
exports.hasComponentInRoutes = hasComponentInRoutes;
|
14
14
|
function getRoute(name) {
|
15
|
-
return ` {
|
16
|
-
path: '${core_1.strings.dasherize(name)}',
|
17
|
-
component: ${getRouteComponentName(name)},
|
18
|
-
canActivate: [ AuthGuardService ]
|
15
|
+
return ` {
|
16
|
+
path: '${core_1.strings.dasherize(name)}',
|
17
|
+
component: ${getRouteComponentName(name)},
|
18
|
+
canActivate: [ AuthGuardService ]
|
19
19
|
}`;
|
20
20
|
}
|
21
21
|
exports.getRoute = getRoute;
|