Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/devextreme-cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ if(args.help) {
const run = async(commands, options) => {
if(application.isApplicationCommand(commands[0])) {
await application.run(commands, options, devextremeConfig.read());
} else if(application.isMigrationCommand(commands[0])) {
if(!commands[1]) {
console.error('Please specify a change name for migration.');
printHelp('migrate');
return;
}
await application.run(['migrate', commands[1], ...commands.slice(2)], options, { applicationEngine: 'angular' });
return;
} else if(themeBuilder.isThemeBuilderCommand(commands[0])) {
options.command = commands[0];
themeBuilder.run(options);
Expand Down
23 changes: 23 additions & 0 deletions packages/devextreme-cli/src/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@ const isApplicationCommand = (command) => {
return [ 'new', 'add' ].includes(command);
};

const isMigrationCommand = (command) => {
return [ 'migrate' ].includes(command);
};

const handleWrongAppType = (appType, command) => {
console.error(`The '${appType}' application type is not valid`);
printHelp(command);
};

const handleWrongChangeName = (changeName, command) => {
console.error(`The '${changeName}' change name is not valid`);
printHelp(command);
};

const createReact = async(appName, options, command) => {
const reactAppType = await getReactAppType(options['app-type']);

Expand All @@ -30,12 +39,25 @@ const createReact = async(appName, options, command) => {
};

const run = async(commands, options, devextremeConfig) => {

if(!commands[1]) {
console.error('Command is incomplete. Please specify parameters.');
printHelp(commands[0]);
return;
}

if(commands[0] === 'migrate') {
const changeName = commands[1];
switch(changeName) {
case 'angular-config-components':
await angularApplication.migrateConfigComponents(options);
return;
default:
handleWrongChangeName(changeName, commands[0]);
return;
}
}

if(commands[0] === 'new') {
const app = commands[1];
const appName = commands[2] || 'my-app';
Expand Down Expand Up @@ -104,5 +126,6 @@ const run = async(commands, options, devextremeConfig) => {

module.exports = {
isApplicationCommand,
isMigrationCommand,
run
};
86 changes: 81 additions & 5 deletions packages/devextreme-cli/src/applications/application.angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,24 @@ async function runNgCommand(commandArguments, commandOptions, commandConfig) {
}

function localPackageExists(packageName) {
// Check local node_modules first
const nodeModulesPath = path.join(process.cwd(), 'node_modules');
if(!fs.existsSync(nodeModulesPath)) {
return;
if(fs.existsSync(nodeModulesPath)) {
const packageJsonPath = path.join(nodeModulesPath, packageName, 'package.json');
if(fs.existsSync(packageJsonPath)) {
return true;
}
}

const packageJsonPath = path.join(nodeModulesPath, packageName, 'package.json');
return fs.existsSync(packageJsonPath);
// Check if globally installed by trying to resolve the package
try {
require.resolve(`${packageName}/package.json`);
return true;
} catch(e) {
// Package not found globally
}

return false;
}

const hasSutableNgCli = async() => {
Expand Down Expand Up @@ -152,6 +163,70 @@ const addView = (viewName, options) => {
runSchematicCommand('add-view', schematicOptions);
};

const migrateConfigComponents = async(options = {}) => {
const collectionName = 'devextreme-schematics';

// Check if devextreme-schematics is installed
if(!localPackageExists(collectionName)) {
const prompts = require('prompts');

console.log(`\nThe '${collectionName}' package is required to run this command.`);

const response = await prompts({
type: 'confirm',
name: 'install',
message: `Would you like to install '${collectionName}' now?`,
initial: true
});

if(!response.install) {
console.log('Migration cancelled. Please install devextreme-schematics manually:');
console.log(`npm install -g ${collectionName}@${schematicsVersion}`);
process.exit(1);
}

console.log(`Installing ${collectionName}@${schematicsVersion}...`);
try {
await runCommand('npm', ['install', '-g', `${collectionName}@${schematicsVersion}`], { stdio: 'inherit' });
console.log('Installation completed successfully.');
} catch(error) {
console.error('Failed to install devextreme-schematics. Please install it manually:');
Comment thread
ajivanyandev marked this conversation as resolved.
Outdated
console.error(`npm install -g ${collectionName}@${schematicsVersion}`);
process.exit(1);
}
}

const schematicOptions = {
...options
};

if(schematicOptions.include && typeof schematicOptions.include === 'string') {
schematicOptions.include = schematicOptions.include.split(',').map(s => s.trim());
}
if(schematicOptions.scriptInclude && typeof schematicOptions.scriptInclude === 'string') {
schematicOptions.scriptInclude = schematicOptions.scriptInclude.split(',').map(s => s.trim());
}

const commandArguments = ['schematics', `${collectionName}:migrate-config-components`];

const { [depsVersionTagOptionName]: _, ...optionsToArguments } = schematicOptions; // eslint-disable-line no-unused-vars
for(let option in optionsToArguments) {
const value = optionsToArguments[option];
if(value !== undefined && value !== null && value !== '') {
if(Array.isArray(value)) {
if(value.length > 0) {
commandArguments.push(`--${dasherize(option)}=${value.join(',')}`);
}
} else {
commandArguments.push(`--${dasherize(option)}=${value}`);
}
}
}

// Use runCommand directly with npx to work outside Angular workspace
return runCommand('npx', commandArguments, { stdio: 'inherit' });
};

const changeMainTs = (appPath) => {
const filePath = path.join(appPath, 'src', 'main.ts');

Expand All @@ -174,5 +249,6 @@ module.exports = {
install,
create,
addTemplate,
addView
addView,
migrateConfigComponents
};
18 changes: 18 additions & 0 deletions packages/devextreme-cli/src/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@
"name": "devextreme-angular",
"description": "Add DevExtreme to an Angular application"
}]
}, {
"name": "migrate",
"description": "Migration commands for DevExtreme applications",
"usage": "devextreme migrate <change name> [options]",
"arguments": [{
"name": "angular-config-components",
"description": "Migrate DevExtreme configuration components to the latest version.",
Comment thread
ajivanyandev marked this conversation as resolved.
Outdated
"options": [{
"name": "--include",
"description": "Glob patterns of template files to include (default: **/*.html). You can pass multiple patterns as a comma-separated string (e.g. \"**/a.html,**/b.html\") or as an array (e.g. [\"**/a.html\",\"**/b.html\"])."
Comment thread
ajivanyandev marked this conversation as resolved.
Outdated
}, {
"name": "--script-include",
"description": "Glob patterns for TypeScript/JavaScript files to scan for inline @Component({ template }) (default: **/*.ts,**/*.js). You can pass multiple patterns as a comma-separated string or as an array. Set to empty to disable."
Comment thread
ajivanyandev marked this conversation as resolved.
Outdated
}, {
"name": "--dry",
"description": "Run in dry mode to preview changes without applying them (default: false)"
Comment thread
ajivanyandev marked this conversation as resolved.
Outdated
}]
}]
}, {
"name": "build-theme",
"description": "Build a custom color scheme",
Expand Down
27 changes: 27 additions & 0 deletions packages/devextreme-schematics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,30 @@ This package includes the following schematics:

- [add-view](src/add-view)
Adds a view to a DevExtreme Angular application

## TypeScript Dependency & Global CLI Usage

Some DevExtreme migration schematics require TypeScript to process inline Angular templates. The CLI attempts to resolve TypeScript from multiple locations:

- The CLI's own node_modules
- Your project's node_modules
- The global node_modules

If TypeScript is not found, inline template migration will be skipped and a warning will be shown with resolution attempts and errors.

### How to Fix TypeScript Not Available

1. **Local Project:** Install TypeScript in your project root:
```sh
npm install typescript --save-dev
```
2. **Global CLI:** If you use the CLI globally, also install TypeScript globally:
```sh
npm install -g typescript
```
3. **npx Usage:** If you use npx, ensure TypeScript is available in your workspace or globally.
4. **Troubleshooting:**
- Some npm global installs may not link dependencies as expected. If you see repeated TypeScript resolution errors, try running the CLI from a project where TypeScript is installed locally.
- You can also manually link TypeScript to your global node_modules if needed.

If you continue to see errors, review the warning output for resolution attempts and check your npm/node installation paths.
55 changes: 51 additions & 4 deletions packages/devextreme-schematics/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/devextreme-schematics/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
"dependencies": {
"@angular-devkit/core": "^17.3.17",
"@angular-devkit/schematics": "^17.3.17",
"@schematics/angular": "^17.3.17"
"@schematics/angular": "^17.3.17",
"parse5": "^7.1.2",
"picomatch": "^4.0.2"
},
"devDependencies": {
"@types/jasmine": "~3.10.18",
"@types/node": "ts5.2",
"@types/picomatch": "^4.0.2",
"@types/semver": "^7.7.1",
"jasmine": "^2.99.0",
"rxjs": "^6.6.7",
Expand Down
5 changes: 5 additions & 0 deletions packages/devextreme-schematics/src/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
"description": "Add a new view to app-template.",
"factory": "./add-view/index",
"schema": "./add-view/schema.json"
},
"migrate-config-components": {
"description": "Migrate DevExtreme configuration components to the latest version.",
Comment thread
ajivanyandev marked this conversation as resolved.
Outdated
"factory": "./migrate-config-components/index#migrateConfigComponents",
"schema": "./migrate-config-components/schema.json"
}
}
}
Loading
Loading