devextreme-schematics 1.15.0 → 1.16.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devextreme-schematics",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "DevExtreme schematics",
5
5
  "author": "Developer Express Inc.",
6
6
  "license": "MIT",
@@ -17,16 +17,16 @@
17
17
  ],
18
18
  "schematics": "./src/collection.json",
19
19
  "dependencies": {
20
- "@angular-devkit/core": "^19.2.25",
21
- "@angular-devkit/schematics": "^19.2.25",
22
- "@schematics/angular": "^19.2.25",
20
+ "@angular-devkit/core": "^19.2.27",
21
+ "@angular-devkit/schematics": "^19.2.27",
22
+ "@schematics/angular": "^19.2.27",
23
23
  "parse5": "^7.3.0",
24
24
  "picomatch": "^4.0.4",
25
- "semver": "^7.8.0"
25
+ "semver": "^7.8.5"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/jasmine": "~3.10.19",
29
- "@types/node": "20.19.40",
29
+ "@types/node": "20.19.43",
30
30
  "@types/picomatch": "^4.0.3",
31
31
  "@types/semver": "^7.7.1",
32
32
  "jasmine": "^2.99.0",
@@ -39,7 +39,7 @@
39
39
  "dxversion": {
40
40
  "type": "string",
41
41
  "description": "The DevExtreme version",
42
- "default": "25.2.7"
42
+ "default": "26.1.3"
43
43
  },
44
44
  "globalNgCliVersion": {
45
45
  "type":"string",
@@ -7,7 +7,7 @@
7
7
  "dxversion": {
8
8
  "type": "string",
9
9
  "description": "The DevExtreme version",
10
- "default": "25.2.7"
10
+ "default": "26.1.3"
11
11
  },
12
12
  "project": {
13
13
  "type": "string",
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.latestVersions = void 0;
4
4
  // TODO: implement
5
5
  exports.latestVersions = {
6
- 'devextreme': '25.2.7',
7
- 'devextreme-angular': '25.2.7',
6
+ 'devextreme': '26.1.3',
7
+ 'devextreme-angular': '26.1.3',
8
8
  'devextreme-cli': 'latest',
9
9
  'sass-embedded': '1.66.0'
10
10
  };
@@ -1,56 +0,0 @@
1
- import {
2
- Rule,
3
- chain,
4
- schematic,
5
- Tree,
6
- } from '@angular-devkit/schematics';
7
-
8
- import { existsSync } from 'fs';
9
- import { resolve, join } from 'path';
10
-
11
- import { spawnSync } from 'child_process';
12
-
13
- export default function(options: any): Rule {
14
- const rules = [
15
- schematic('install', {
16
- dxversion: options.dxversion,
17
- project: options.project
18
- }),
19
- schematic('add-layout', {
20
- layout: options.layout,
21
- resolveConflicts: options.resolveConflicts,
22
- project: options.project,
23
- skipInstall: true,
24
- updateBudgets: options.updateBudgets,
25
- globalNgCliVersion: options.globalNgCliVersion
26
- }),
27
- // schematics installed packages with flag --ignore-scripts
28
- // @angular/cli@14 add option allowScript to NodePackageInstallTask
29
- (host: Tree) => {
30
- postinstallScripts();
31
- return host;
32
- }
33
- ];
34
-
35
- if (!options.empty) {
36
- rules.push(schematic('add-sample-views', {
37
- project: options.project
38
- }));
39
- }
40
-
41
- return chain(rules);
42
- }
43
-
44
- const postinstallScripts = () => {
45
- const isWin = /^win/.test(process.platform);
46
-
47
- const sassEmbeddedPath = resolve('node_modules', 'sass-embedded');
48
- const sassVendorPath = join(sassEmbeddedPath, 'dist', 'lib', 'src', 'vendor', 'dart-sass-embedded');
49
- if (!existsSync(sassVendorPath)) {
50
- spawnSync('npm', ['run', 'postinstall'], {
51
- cwd: resolve(join('node_modules', 'sass-embedded')),
52
- windowsVerbatimArguments: true,
53
- shell: isWin ? false : true
54
- });
55
- }
56
- };
@@ -1,73 +0,0 @@
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
- const appOptions: any = {
8
- name: 'testApp',
9
- projectRoot: '',
10
- inlineStyle: false,
11
- inlineTemplate: false,
12
- routing: true,
13
- style: 'css',
14
- skipTests: false,
15
- skipPackageJson: false
16
- };
17
-
18
- const workspaceOptions: WorkspaceOptions = {
19
- name: 'workspace',
20
- version: '6.0.0'
21
- };
22
-
23
- const angularSchematicsCollection = require.resolve('../../node_modules/@schematics/angular/collection.json');
24
- const schematicRunner = new SchematicTestRunner('@schematics/angular', angularSchematicsCollection);
25
- let appTree: UnitTestTree;
26
-
27
- beforeEach(async () => {
28
- appTree = await schematicRunner.runSchematic('workspace', workspaceOptions);
29
- appTree = await schematicRunner.runSchematic('application', appOptions, appTree);
30
- });
31
-
32
- describe('add-app-template', () => {
33
- it('should add DevExtreme', async () => {
34
- const runner = new SchematicTestRunner('schematics', collectionPath);
35
- const tree = await runner.runSchematic('add-app-template', { }, appTree);
36
- const packageConfig = JSON.parse(tree.readContent('package.json'));
37
-
38
- expect('devextreme' in packageConfig.dependencies).toBe(true);
39
- });
40
-
41
- it('should consider the `project` option', async () => {
42
- appTree = await schematicRunner.runSchematic('application', {
43
- name: 'testApp2',
44
- inlineStyle: false,
45
- inlineTemplate: false,
46
- routing: true,
47
- style: 'scss',
48
- projectRoot: 'projects/testApp2'
49
- }, appTree);
50
-
51
- const runner = new SchematicTestRunner('schematics', collectionPath);
52
- const tree = await runner.runSchematic('add-app-template', {
53
- project: 'testApp2'
54
- }, appTree);
55
-
56
- expect(tree.files)
57
- .toContain('/devextreme.json');
58
- expect(tree.files)
59
- .toContain('/projects/testApp2/src/themes/metadata.base.json');
60
- expect(tree.files)
61
- .toContain('/projects/testApp2/src/app/pages/home/home.component.ts');
62
- });
63
-
64
- it('should consider the `updateBudgets` option', async () => {
65
- const runner = new SchematicTestRunner('schematics', collectionPath);
66
- const tree = await runner.runSchematic('add-app-template', { updateBudgets: true }, appTree);
67
-
68
- const angularContent = JSON.parse(tree.readContent('/angular.json'));
69
- const budgets = angularContent.projects.testApp.architect.build.configurations.production.budgets;
70
-
71
- expect(budgets[0].maximumWarning).toEqual('4mb');
72
- });
73
- });
@@ -1,447 +0,0 @@
1
- import {
2
- Rule,
3
- SchematicContext,
4
- Tree,
5
- apply,
6
- url,
7
- move,
8
- chain,
9
- filter,
10
- forEach,
11
- mergeWith,
12
- callRule,
13
- FileEntry,
14
- template
15
- } from '@angular-devkit/schematics';
16
-
17
- import {
18
- SourceFile
19
- } from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript';
20
-
21
- import { strings } from '@angular-devkit/core';
22
-
23
- import { join, basename } from 'path';
24
-
25
- import { SemVer } from 'semver';
26
-
27
- import {
28
- getApplicationPath,
29
- getSourceRootPath,
30
- getProjectName
31
- } from '../utility/project';
32
-
33
- import {
34
- humanize
35
- } from '../utility/string';
36
-
37
- import {
38
- addStylesToApp
39
- } from '../utility/styles';
40
-
41
- import {
42
- modifyJSONFile,
43
- } from '../utility/modify-json-file';
44
-
45
- import {
46
- NodeDependencyType,
47
- addPackageJsonDependency,
48
- getPackageJsonDependency,
49
- } from '@schematics/angular/utility/dependencies';
50
-
51
- import { getSourceFile } from '../utility/source';
52
-
53
- import {
54
- applyChanges,
55
- insertItemToArray
56
- } from '../utility/change';
57
-
58
- import {
59
- hasComponentInRoutes,
60
- getRoute,
61
- findRoutesInSource
62
- } from '../utility/routing';
63
-
64
- import { insertImport } from '@schematics/angular/utility/ast-utils';
65
-
66
- import { getWorkspace } from '@schematics/angular/utility/workspace';
67
- import { Change } from '@schematics/angular/utility/change';
68
-
69
- import { PatchNodePackageInstallTask } from '../utility/patch';
70
- import { isAngularVersionHigherThan } from '../utility/angular-version';
71
-
72
- const routes = [
73
- {
74
- name: 'AuthGuardService',
75
- type: 'service',
76
- location: './shared/services'
77
- },
78
- {
79
- name: 'LoginFormComponent',
80
- path: 'login-form',
81
- type: 'component',
82
- location: './shared/components'
83
- },
84
- {
85
- name: 'ResetPasswordFormComponent',
86
- path: 'reset-password',
87
- type: 'component',
88
- location: './shared/components'
89
- },
90
- {
91
- name: 'CreateAccountFormComponent',
92
- path: 'create-account',
93
- type: 'component',
94
- location: './shared/components'
95
- },
96
- {
97
- name: 'ChangePasswordFormComponent',
98
- path: 'change-password/:recoveryCode',
99
- type: 'component',
100
- location: './shared/components'
101
- }
102
- ];
103
-
104
- const projectFilesSource = './files/src';
105
- const workspaceFilesSource = './files';
106
-
107
- function addScriptSafe(scripts: any, name: string, value: string) {
108
- const currentValue = scripts[name];
109
-
110
- if (!currentValue) {
111
- scripts[name] = value;
112
- return;
113
- }
114
-
115
- const alterName = `origin-${name}`;
116
- const safeValue = `npm run ${alterName} && ${value}`;
117
-
118
- if (currentValue === value || currentValue === safeValue) {
119
- return;
120
- }
121
-
122
- scripts[alterName] = currentValue;
123
- scripts[name] = safeValue;
124
- }
125
-
126
- function addBuildThemeScript() {
127
- return (host: Tree) => {
128
- modifyJSONFile(host, './package.json', config => {
129
- const scripts = config['scripts'];
130
-
131
- addScriptSafe(scripts, 'build-themes', 'devextreme build');
132
- addScriptSafe(scripts, 'postinstall', 'npm run build-themes');
133
-
134
- return config;
135
- });
136
-
137
- return host;
138
- };
139
- }
140
-
141
- async function addCustomThemeStyles(host: Tree, options: any, sourcePath: string = '') {
142
- const projectName = await getProjectName(host, options.project);
143
- modifyJSONFile(host, './angular.json', config => {
144
- const stylesList = [
145
- `${sourcePath}/variables.scss`,
146
- `${sourcePath}/dx-styles.scss`,
147
- `${sourcePath}/themes/generated/theme.additional.css`,
148
- `${sourcePath}/themes/generated/theme.additional.dark.css`,
149
- `${sourcePath}/themes/generated/theme.base.css`,
150
- `${sourcePath}/themes/generated/theme.base.dark.css`,
151
- 'node_modules/devextreme/dist/css/dx.common.css'
152
- ];
153
-
154
- return addStylesToApp(projectName, config, stylesList);
155
- });
156
-
157
- return host;
158
- }
159
-
160
- async function updateBudgets(host: Tree, options: any) {
161
- const projectName = await getProjectName(host, options.project);
162
- modifyJSONFile(host, './angular.json', config => {
163
- const budgets: any[] = config.projects[projectName].architect.build.configurations.production.budgets;
164
-
165
- const budget = budgets.find((item) => item.type === 'initial');
166
- if (budget) {
167
- budget.maximumWarning = '4mb';
168
- budget.maximumError = '7mb';
169
- }
170
-
171
- return config;
172
- });
173
-
174
- return host;
175
- }
176
-
177
- async function addPolyfills(host: Tree, project: string, polyfills: string[]) {
178
- const projectName = await getProjectName(host, project);
179
-
180
- modifyJSONFile(host, './angular.json', config => {
181
- const buildOptions: Record<string, any> = config.projects[projectName]['architect']['build']['options'];
182
-
183
- if (!buildOptions.polyfills) {
184
- buildOptions.polyfills = [];
185
- }
186
-
187
- polyfills.forEach((polyfill) => {
188
- if (!buildOptions.polyfills.includes(polyfill)) {
189
- buildOptions.polyfills.push(polyfill);
190
- }
191
- });
192
-
193
- return config;
194
- });
195
-
196
- return host;
197
- }
198
-
199
- function addViewportToBody(sourcePath: string = '') {
200
- return (host: Tree) => {
201
- const indexPath = join(sourcePath, 'index.html');
202
- let indexContent = host.read(indexPath)!.toString();
203
-
204
- indexContent = indexContent.replace(/<body>/, '<body class="dx-viewport">');
205
- host.overwrite(indexPath, indexContent);
206
-
207
- return host;
208
- };
209
- }
210
-
211
- function modifyFileRule(path: string, callback: (source: SourceFile) => Change[]) {
212
- return (host: Tree) => {
213
- const source = getSourceFile(host, path);
214
-
215
- if (!source) {
216
- return host;
217
- }
218
-
219
- const changes = callback(source);
220
-
221
- return applyChanges(host, changes, path);
222
- };
223
- }
224
-
225
- function updateAppComponent(sourcePath: string, templateOptions: any = {}) {
226
- const appMComponentPath = sourcePath + templateOptions.name + '.ts';
227
-
228
- const importSetter = (importName: string, path: string, alias: string) => {
229
- return (source: SourceFile) => {
230
- return [insertImport(source, appMComponentPath, importName, path, false, alias)];
231
- };
232
- };
233
-
234
- const rules = [
235
- modifyFileRule(appMComponentPath, importSetter(
236
- templateOptions.layout === 'side-nav-outer-toolbar'
237
- ? 'SideNavOuterToolbarComponent'
238
- : 'SideNavInnerToolbarComponent',
239
- './layouts',
240
- 'SideNavToolbarComponent',
241
- )),
242
- ];
243
-
244
- return chain(rules);
245
- }
246
-
247
- function getComponentName(host: Tree, sourcePath: string) {
248
- let name = '';
249
- let index = 0;
250
-
251
- if (!host.exists(sourcePath + 'app.component.ts') && !host.exists(sourcePath + 'app.ts')) {
252
- name = 'app';
253
- }
254
-
255
- while (!name) {
256
- index++;
257
- const componentName = `app${index}`;
258
-
259
- if (
260
- !host.exists(`${sourcePath}${componentName}.component.ts`)
261
- && !host.exists(`${sourcePath}${componentName}.ts`)
262
- ) {
263
- name = componentName;
264
- }
265
- }
266
-
267
- return name;
268
- }
269
-
270
- function hasRouting(host: Tree, sourcePath: string) {
271
- return host.exists(sourcePath + 'app.routes.ts');
272
- }
273
-
274
- function addPackagesToDependency(globalNgCliVersion: string) {
275
- const version = new SemVer(globalNgCliVersion.replace(/\^|\~/g, ''));
276
-
277
- return (host: Tree) => {
278
- const zonejs = getPackageJsonDependency(host, 'zone.js');
279
-
280
- addPackageJsonDependency(host, {
281
- type: NodeDependencyType.Default,
282
- name: '@angular/cdk',
283
- version: version.raw.includes('next') || version.raw.includes('-rc')
284
- ? 'next' : `^${version.major}.0.0`
285
- });
286
-
287
- if (!zonejs) {
288
- addPackageJsonDependency(host, {
289
- type: NodeDependencyType.Default,
290
- name: 'zone.js',
291
- version: version.major > 18 ? '~0.15.0' : '~0.14.0'
292
- });
293
- }
294
-
295
- return host;
296
- };
297
- }
298
-
299
- function modifyContentByTemplate(
300
- sourcePath: string = '',
301
- templateSourcePath: string,
302
- filePath: string | null,
303
- templateOptions: any = {},
304
- modifyContent?: (templateContent: string, currentContent: string, filePath: string ) => string)
305
- : Rule {
306
- return (host: Tree, context: SchematicContext) => {
307
- const modifyIfExists = (fileEntry: FileEntry) => {
308
- const fileEntryPath = join(sourcePath, fileEntry.path.toString());
309
- if (!host.exists(fileEntryPath)) {
310
- return fileEntry;
311
- }
312
-
313
- const templateContent = fileEntry.content!.toString();
314
- let modifiedContent = templateContent;
315
-
316
- const currentContent = host.read(fileEntryPath)!.toString();
317
- if (modifyContent) {
318
- modifiedContent = modifyContent(templateContent, currentContent, fileEntryPath);
319
- }
320
-
321
- // NOTE: Workaround for https://github.com/angular/angular-cli/issues/11337
322
- if (modifiedContent !== currentContent) {
323
- host.overwrite(fileEntryPath, modifiedContent);
324
- }
325
- return null;
326
- };
327
-
328
- const rules = [
329
- filter(path => {
330
- return !filePath || join('./', path) === join('./', filePath);
331
- }),
332
- template(templateOptions),
333
- forEach(modifyIfExists),
334
- move(sourcePath)
335
- ];
336
-
337
- const modifiedSource = apply(url(templateSourcePath), rules);
338
- const resultRule = mergeWith(modifiedSource);
339
-
340
- return callRule(resultRule, host, context);
341
- };
342
- }
343
-
344
- function updateDevextremeConfig(sourcePath: string = '') {
345
- const devextremeConfigPath = '/devextreme.json';
346
- const templateOptions = {
347
- sourcePath
348
- };
349
-
350
- const modifyConfig = (templateContent: string, currentContent: string) => {
351
- const oldConfig = JSON.parse(currentContent);
352
- const newConfig = JSON.parse(templateContent);
353
-
354
- [].push.apply(oldConfig.build.commands, newConfig.build.commands);
355
-
356
- return JSON.stringify(oldConfig, null, ' ');
357
- };
358
-
359
- return modifyContentByTemplate('./', workspaceFilesSource, devextremeConfigPath, templateOptions, modifyConfig);
360
- }
361
-
362
- const modifyRouting = (host: Tree, routingFilePath: string) => {
363
- // TODO: Try to use the isolated host to generate the result string
364
- let source = getSourceFile(host, routingFilePath)!;
365
- const importChanges = [];
366
- for (const route of routes) {
367
- importChanges.push(insertImport(source, routingFilePath, route.name, route.location));
368
- }
369
-
370
- applyChanges(host, importChanges, routingFilePath);
371
- for (const route of routes) {
372
- if (route.type === 'component' && route.path) {
373
- source = getSourceFile(host, routingFilePath)!;
374
- const routeInSource = findRoutesInSource(source)!;
375
- if (!hasComponentInRoutes(routeInSource, route.path)) {
376
- const routeToAdd = getRoute(route.name, route.name, route.path);
377
- insertItemToArray(host, routingFilePath, routeInSource, routeToAdd);
378
- }
379
- }
380
- }
381
-
382
- };
383
-
384
- function setPostfix(host: Tree, name: string) {
385
- return name + (isAngularVersionHigherThan(host, 20) ? '' : '.component');
386
- }
387
-
388
- export default function(options: any): Rule {
389
- return async (host: Tree) => {
390
- const project = await getProjectName(host, options.project);
391
- const workspace = await getWorkspace(host);
392
- const ngProject = workspace.projects.get(project);
393
- const prefix = ngProject?.prefix;
394
- const title = humanize(project);
395
- const appPath = await getApplicationPath(host, project);
396
- const sourcePath = await getSourceRootPath(host, project);
397
- const layout = options.layout;
398
- const override = options.resolveConflicts === 'override';
399
- const componentName = override ? 'app' : getComponentName(host, appPath);
400
- const pathToCss = sourcePath?.replace(/\/?(\w)+\/?/g, '../');
401
-
402
- const templateOptions = {
403
- name: setPostfix(host, componentName),
404
- layout,
405
- title,
406
- strings,
407
- path: pathToCss,
408
- prefix
409
- };
410
-
411
- const modifyContent = (templateContent: string, currentContent: string, filePath: string) => {
412
- if (basename(filePath) === 'styles.scss') {
413
- return `${currentContent}\n${templateContent}`;
414
- }
415
-
416
- if (basename(filePath) === 'app.routes.ts' && hasRouting(host, appPath)) {
417
- modifyRouting(host, filePath);
418
- return currentContent;
419
- }
420
-
421
- return templateContent;
422
- };
423
-
424
- const rules = [
425
- modifyContentByTemplate(sourcePath, projectFilesSource, null, templateOptions, modifyContent),
426
- updateDevextremeConfig(sourcePath),
427
- updateAppComponent(appPath, templateOptions),
428
- addBuildThemeScript(),
429
- () => addCustomThemeStyles(host, options, sourcePath) as any,
430
- addViewportToBody(sourcePath),
431
- addPackagesToDependency(options.globalNgCliVersion),
432
- () => addPolyfills(host, options.project, ['zone.js'])
433
- ];
434
-
435
- if (options.updateBudgets) {
436
- rules.push(() => updateBudgets(host, options) as any);
437
- }
438
-
439
- if (!options.skipInstall) {
440
- rules.push((_: Tree, context: SchematicContext) => {
441
- context.addTask(new PatchNodePackageInstallTask());
442
- });
443
- }
444
-
445
- return chain(rules);
446
- };
447
- }