diff --git a/packages/devextreme-cli/index.js b/packages/devextreme-cli/index.js index 6852d8fe5..94d2a68a5 100644 --- a/packages/devextreme-cli/index.js +++ b/packages/devextreme-cli/index.js @@ -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); diff --git a/packages/devextreme-cli/src/application.js b/packages/devextreme-cli/src/application.js index a5a65228b..c931ad27e 100644 --- a/packages/devextreme-cli/src/application.js +++ b/packages/devextreme-cli/src/application.js @@ -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']); @@ -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'; @@ -104,5 +126,6 @@ const run = async(commands, options, devextremeConfig) => { module.exports = { isApplicationCommand, + isMigrationCommand, run }; diff --git a/packages/devextreme-cli/src/applications/application.angular.js b/packages/devextreme-cli/src/applications/application.angular.js index 0f3f72d46..3e01e7751 100644 --- a/packages/devextreme-cli/src/applications/application.angular.js +++ b/packages/devextreme-cli/src/applications/application.angular.js @@ -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() => { @@ -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 manually:'); + 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'); @@ -174,5 +249,6 @@ module.exports = { install, create, addTemplate, - addView + addView, + migrateConfigComponents }; diff --git a/packages/devextreme-cli/src/commands.json b/packages/devextreme-cli/src/commands.json index 51e291c3a..58e6519fe 100644 --- a/packages/devextreme-cli/src/commands.json +++ b/packages/devextreme-cli/src/commands.json @@ -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 [options]", + "arguments": [{ + "name": "angular-config-components", + "description": "Migrate to the latest DevExtreme configuration components.", + "options": [{ + "name": "--include", + "description": "Template file glob patterns 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\"])." + }, { + "name": "--script-include", + "description": "TypeScript/JavaScript file glob patterns to scan for inline templates (default: **/*.ts,**/*.js). You can pass multiple patterns as a comma-separated string or as an array. Pass an empty value ('' or []) to disable." + }, { + "name": "--dry", + "description": "Run in dry mode to preview changes without applying them (default: false)." + }] + }] }, { "name": "build-theme", "description": "Build a custom color scheme", diff --git a/packages/devextreme-schematics/README.md b/packages/devextreme-schematics/README.md index 851aaee14..2907f2b92 100644 --- a/packages/devextreme-schematics/README.md +++ b/packages/devextreme-schematics/README.md @@ -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. diff --git a/packages/devextreme-schematics/package-lock.json b/packages/devextreme-schematics/package-lock.json index 4b6bdc421..af900b312 100644 --- a/packages/devextreme-schematics/package-lock.json +++ b/packages/devextreme-schematics/package-lock.json @@ -11,11 +11,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", @@ -50,6 +53,18 @@ } } }, + "node_modules/@angular-devkit/core/node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@angular-devkit/core/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -233,6 +248,13 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", @@ -472,6 +494,18 @@ "node": ">=0.3.1" } }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -789,6 +823,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -811,9 +857,10 @@ "dev": true }, "node_modules/picomatch": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", - "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", "engines": { "node": ">=12" }, diff --git a/packages/devextreme-schematics/package.json b/packages/devextreme-schematics/package.json index 475047c81..ca91ca4bf 100644 --- a/packages/devextreme-schematics/package.json +++ b/packages/devextreme-schematics/package.json @@ -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", diff --git a/packages/devextreme-schematics/src/collection.json b/packages/devextreme-schematics/src/collection.json index 30f0bdcc5..10b4a2206 100644 --- a/packages/devextreme-schematics/src/collection.json +++ b/packages/devextreme-schematics/src/collection.json @@ -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 to the latest DevExtreme configuration components.", + "factory": "./migrate-config-components/index#migrateConfigComponents", + "schema": "./migrate-config-components/schema.json" } } } diff --git a/packages/devextreme-schematics/src/migrate-config-components/README.md b/packages/devextreme-schematics/src/migrate-config-components/README.md new file mode 100644 index 000000000..b6b9aee76 --- /dev/null +++ b/packages/devextreme-schematics/src/migrate-config-components/README.md @@ -0,0 +1,87 @@ +# migrate-config-components + +A schematic that migrates deprecated nested DevExtreme components to the new config-based structure. + +## Description + +This schematic automatically migrates your Angular application to use the latest DevExtreme component structure by replacing deprecated nested components (such as ``) with their new config-based equivalents (such as ``). The migration command is available as a top-level DevExtreme CLI command and can be run from any directory. + +## Usage + +### Via DevExtreme CLI (Recommended) + +The migration command can be run from any directory and will work both inside and outside Angular workspaces: + +```bash +devextreme migrate angular-config-components +``` + +### Options (All Optional) + +- `--include`: Glob patterns of template files to include (default: `**/*.html`). Separate multiple patterns with commas. +- `--script-include`: Glob patterns for TypeScript/JavaScript files to scan for inline `@Component({ template })` (default: `**/*.ts,**/*.js`). Set to empty to disable. +- `--dry`: Run in dry mode to preview changes without applying them (default: `false`) + +### Examples + +```bash +# Migrate all HTML templates and inline templates (using defaults) +devextreme migrate angular-config-components + +# Migrate only specific files +devextreme migrate angular-config-components --include="src/app/**/*.html,src/shared/**/*.html" + +# Preview changes without applying them +devextreme migrate angular-config-components --dry + +# Migrate only HTML templates, skip inline templates +devextreme migrate angular-config-components --script-include="" + +# Combine multiple options +devextreme migrate angular-config-components --include="*.html,*.ts" --dry +``` + +### Via Angular CLI + +Alternatively, you can run the schematic directly with Angular CLI: + +```bash +ng g devextreme-schematics:migrate-config-components +``` + +## What it does + +This schematic automatically updates your templates to replace deprecated nested components with the new config-based component structure. For example: + +**Before (deprecated nested):** +```html + + + + +``` + +**After (config-based):** +```html + + + + +``` + +### Why migrate? + +DevExtreme Angular components are moving from a nested structure (e.g., ``) to a config-based structure (e.g., ``) for improved clarity, maintainability, and future compatibility. This schematic automates the migration process to help you keep your codebase up to date with the latest DevExtreme standards. + +## Requirements + +- Node.js and npm/yarn installed +- Angular application with DevExtreme components (when running inside a workspace) +- DevExtreme Angular version that supports the new component structure + +## Notes + +- The command can be run from any directory, not just Angular workspaces +- When run outside an Angular workspace, the underlying Angular CLI will show appropriate error messages +- All options are optional and have sensible defaults +- The command uses the latest version of `devextreme-schematics` automatically diff --git a/packages/devextreme-schematics/src/migrate-config-components/index.ts b/packages/devextreme-schematics/src/migrate-config-components/index.ts new file mode 100644 index 000000000..a61430227 --- /dev/null +++ b/packages/devextreme-schematics/src/migrate-config-components/index.ts @@ -0,0 +1,80 @@ +import { Rule, Tree, SchematicContext } from '@angular-devkit/schematics'; +import type { HostRule } from './template-migrator'; +import { applyHostAwareTemplateMigrations, applyInlineComponentTemplateMigrations } from './template-migrator'; +import mapping from './mappings/deprecated-config-map.json'; + +export interface Options { + include?: string[]; + dry?: boolean; + scriptInclude?: string[]; +} + +export function migrateConfigComponents(options: Options = {}): Rule { + // Accept --include as array or comma-separated string + let include: string[] = ['**/*.html']; + const rawInclude = options.include; + if (Array.isArray(rawInclude) && rawInclude.length) { + include = rawInclude; + } else if (typeof rawInclude === 'string' && rawInclude) { + let str = (rawInclude as string).trim(); + if (str.startsWith('[') && str.endsWith(']')) { + str = str.slice(1, -1); + } + include = str.split(',').map((s: string) => s.trim()).filter((s: string) => !!s); + } + + // Coerce string 'true'/'false' to boolean for dry option + let dryFlag: boolean = false; + if (typeof options.dry === 'string') { + dryFlag = options.dry === 'true'; + } else { + dryFlag = !!options.dry; + } + + // Accept --script-include as array or comma-separated string + let scriptGlobs: string[] = ['**/*.ts', '**/*.js']; + const rawScriptInclude = options.scriptInclude; + if (Array.isArray(rawScriptInclude) && rawScriptInclude.length) { + scriptGlobs = rawScriptInclude; + } else if (typeof rawScriptInclude === 'string' && rawScriptInclude) { + let str = (rawScriptInclude as string).trim(); + if (str.startsWith('[') && str.endsWith(']')) { + str = str.slice(1, -1); + } + scriptGlobs = str.split(',').map((s: string) => s.trim()).filter((s: string) => !!s); + } + + return async (tree: Tree, ctx: SchematicContext): Promise => { + ctx.logger.info(`[config-migrator] Starting…`); + + type HostMap = Record>; + const hostMap = mapping as unknown as HostMap; + + const processedMapping = Object.entries(hostMap).map(([hostComponentName, map]) => { + const hostSelector = map._hostSelector ?? componentToSelectorGuess(hostComponentName); + const configMap: Record = Object.fromEntries( + Object.entries(map).filter(([k]) => k !== '_hostSelector') + ); + return { hostSelector, configMap }; + }) as HostRule[]; + + // External HTML templates + await applyHostAwareTemplateMigrations(tree, { + includeGlobs: include, + rules: processedMapping + }, { dryRun: dryFlag, logger: ctx.logger }); + + // Inline templates inside component decorators (ts/js) + await applyInlineComponentTemplateMigrations(tree, { + includeGlobs: [], rules: processedMapping + }, { dryRun: dryFlag, logger: ctx.logger }, scriptGlobs); + + ctx.logger.info(`[config-migrator] Done.`); + }; +} + +// Fallback if _hostSelector is missing: "DxFooBarComponent" -> "dx-foo-bar" +function componentToSelectorGuess(componentName: string): string { + const core = componentName.replace(/Component$/, '').replace(/^Dx/, 'dx-'); + return core.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); +} diff --git a/packages/devextreme-schematics/src/migrate-config-components/mappings/deprecated-config-map.json b/packages/devextreme-schematics/src/migrate-config-components/mappings/deprecated-config-map.json new file mode 100644 index 000000000..3532e4a5b --- /dev/null +++ b/packages/devextreme-schematics/src/migrate-config-components/mappings/deprecated-config-map.json @@ -0,0 +1,1088 @@ +{ + "_generated": true, + "_description": "Mapping: host component -> { _hostSelector?: string, generic config selector : component-specific selector }", + "_note": "Do not edit manually. Run scripts/generate-deprecated-config-map.mjs to generate a new map.", + "DxAccordionComponent": { + "_hostSelector": "dx-accordion", + "dxi-item": "dxi-accordion-item" + }, + "DxActionSheetComponent": { + "_hostSelector": "dx-action-sheet", + "dxi-item": "dxi-action-sheet-item" + }, + "DxAutocompleteComponent": { + "_hostSelector": "dx-autocomplete", + "dxi-button": "dxi-autocomplete-button", + "dxi-item": "dxi-autocomplete-item", + "dxi-toolbar-item": "dxi-autocomplete-toolbar-item", + "dxo-animation": "dxo-autocomplete-animation", + "dxo-at": "dxo-autocomplete-at", + "dxo-boundary-offset": "dxo-autocomplete-boundary-offset", + "dxo-collision": "dxo-autocomplete-collision", + "dxo-drop-down-options": "dxo-autocomplete-drop-down-options", + "dxo-from": "dxo-autocomplete-from", + "dxo-hide": "dxo-autocomplete-hide", + "dxo-my": "dxo-autocomplete-my", + "dxo-offset": "dxo-autocomplete-offset", + "dxo-options": "dxo-autocomplete-options", + "dxo-position": "dxo-autocomplete-position", + "dxo-show": "dxo-autocomplete-show", + "dxo-to": "dxo-autocomplete-to" + }, + "DxBarGaugeComponent": { + "_hostSelector": "dx-bar-gauge", + "dxo-animation": "dxo-bar-gauge-animation", + "dxo-border": "dxo-bar-gauge-border", + "dxo-export": "dxo-bar-gauge-export", + "dxo-font": "dxo-bar-gauge-font", + "dxo-format": "dxo-bar-gauge-format", + "dxo-geometry": "dxo-bar-gauge-geometry", + "dxo-item-text-format": "dxo-bar-gauge-item-text-format", + "dxo-label": "dxo-bar-gauge-label", + "dxo-legend": "dxo-bar-gauge-legend", + "dxo-loading-indicator": "dxo-bar-gauge-loading-indicator", + "dxo-margin": "dxo-bar-gauge-margin", + "dxo-shadow": "dxo-bar-gauge-shadow", + "dxo-size": "dxo-bar-gauge-size", + "dxo-subtitle": "dxo-bar-gauge-subtitle", + "dxo-title": "dxo-bar-gauge-title", + "dxo-tooltip": "dxo-bar-gauge-tooltip" + }, + "DxBoxComponent": { + "_hostSelector": "dx-box", + "dxi-item": "dxi-box-item" + }, + "DxBulletComponent": { + "_hostSelector": "dx-bullet", + "dxo-border": "dxo-bullet-border", + "dxo-font": "dxo-bullet-font", + "dxo-format": "dxo-bullet-format", + "dxo-margin": "dxo-bullet-margin", + "dxo-shadow": "dxo-bullet-shadow", + "dxo-size": "dxo-bullet-size", + "dxo-tooltip": "dxo-bullet-tooltip" + }, + "DxButtonGroupComponent": { + "_hostSelector": "dx-button-group", + "dxi-item": "dxi-button-group-item" + }, + "DxCardViewComponent": { + "_hostSelector": "dx-card-view", + "dxi-change": "dxi-card-view-change", + "dxi-column": "dxi-card-view-column", + "dxi-custom-operation": "dxi-card-view-custom-operation", + "dxi-field": "dxi-card-view-field", + "dxi-group-item": "dxi-card-view-group-item", + "dxi-item": "dxi-card-view-item", + "dxi-tab": "dxi-card-view-tab", + "dxi-toolbar-item": "dxi-card-view-toolbar-item", + "dxi-validation-rule": "dxi-card-view-validation-rule", + "dxo-animation": "dxo-card-view-animation", + "dxo-at": "dxo-card-view-at", + "dxo-boundary-offset": "dxo-card-view-boundary-offset", + "dxo-button-options": "dxo-card-view-button-options", + "dxo-col-count-by-screen": "dxo-card-view-col-count-by-screen", + "dxo-collision": "dxo-card-view-collision", + "dxo-column-chooser": "dxo-card-view-column-chooser", + "dxo-editing": "dxo-card-view-editing", + "dxo-filter-builder": "dxo-card-view-filter-builder", + "dxo-filter-operation-descriptions": "dxo-card-view-filter-operation-descriptions", + "dxo-filter-panel": "dxo-card-view-filter-panel", + "dxo-form": "dxo-card-view-form", + "dxo-form-item": "dxo-card-view-form-item", + "dxo-format": "dxo-card-view-format", + "dxo-from": "dxo-card-view-from", + "dxo-group-operation-descriptions": "dxo-card-view-group-operation-descriptions", + "dxo-header-filter": "dxo-card-view-header-filter", + "dxo-hide": "dxo-card-view-hide", + "dxo-label": "dxo-card-view-label", + "dxo-load-panel": "dxo-card-view-load-panel", + "dxo-lookup": "dxo-card-view-lookup", + "dxo-my": "dxo-card-view-my", + "dxo-offset": "dxo-card-view-offset", + "dxo-pager": "dxo-card-view-pager", + "dxo-paging": "dxo-card-view-paging", + "dxo-position": "dxo-card-view-position", + "dxo-remote-operations": "dxo-card-view-remote-operations", + "dxo-scrolling": "dxo-card-view-scrolling", + "dxo-search": "dxo-card-view-search", + "dxo-search-panel": "dxo-card-view-search-panel", + "dxo-selection": "dxo-card-view-selection", + "dxo-show": "dxo-card-view-show", + "dxo-sorting": "dxo-card-view-sorting", + "dxo-tab-panel-options": "dxo-card-view-tab-panel-options", + "dxo-texts": "dxo-card-view-texts", + "dxo-to": "dxo-card-view-to", + "dxo-toolbar": "dxo-card-view-toolbar" + }, + "DxChartComponent": { + "_hostSelector": "dx-chart", + "dxi-annotation": "dxi-chart-annotation", + "dxi-break": "dxi-chart-break", + "dxi-constant-line": "dxi-chart-constant-line", + "dxi-pane": "dxi-chart-pane", + "dxi-series": "dxi-chart-series", + "dxi-strip": "dxi-chart-strip", + "dxi-value-axis": "dxi-chart-value-axis", + "dxo-adaptive-layout": "dxo-chart-adaptive-layout", + "dxo-aggregation": "dxo-chart-aggregation", + "dxo-aggregation-interval": "dxo-chart-aggregation-interval", + "dxo-animation": "dxo-chart-animation", + "dxo-argument-axis": "dxo-chart-argument-axis", + "dxo-argument-format": "dxo-chart-argument-format", + "dxo-background-color": "dxo-chart-background-color", + "dxo-border": "dxo-chart-border", + "dxo-break-style": "dxo-chart-break-style", + "dxo-color": "dxo-chart-color", + "dxo-common-annotation-settings": "dxo-chart-common-annotation-settings", + "dxo-common-axis-settings": "dxo-chart-common-axis-settings", + "dxo-common-pane-settings": "dxo-chart-common-pane-settings", + "dxo-common-series-settings": "dxo-chart-common-series-settings", + "dxo-connector": "dxo-chart-connector", + "dxo-constant-line-style": "dxo-chart-constant-line-style", + "dxo-crosshair": "dxo-chart-crosshair", + "dxo-data-prepare-settings": "dxo-chart-data-prepare-settings", + "dxo-drag-box-style": "dxo-chart-drag-box-style", + "dxo-export": "dxo-chart-export", + "dxo-font": "dxo-chart-font", + "dxo-format": "dxo-chart-format", + "dxo-grid": "dxo-chart-grid", + "dxo-hatching": "dxo-chart-hatching", + "dxo-height": "dxo-chart-height", + "dxo-horizontal-line": "dxo-chart-horizontal-line", + "dxo-hover-style": "dxo-chart-hover-style", + "dxo-image": "dxo-chart-image", + "dxo-label": "dxo-chart-label", + "dxo-legend": "dxo-chart-legend", + "dxo-loading-indicator": "dxo-chart-loading-indicator", + "dxo-margin": "dxo-chart-margin", + "dxo-min-visual-range-length": "dxo-chart-min-visual-range-length", + "dxo-minor-grid": "dxo-chart-minor-grid", + "dxo-minor-tick": "dxo-chart-minor-tick", + "dxo-minor-tick-interval": "dxo-chart-minor-tick-interval", + "dxo-point": "dxo-chart-point", + "dxo-reduction": "dxo-chart-reduction", + "dxo-scroll-bar": "dxo-chart-scroll-bar", + "dxo-selection-style": "dxo-chart-selection-style", + "dxo-series-template": "dxo-chart-series-template", + "dxo-shadow": "dxo-chart-shadow", + "dxo-size": "dxo-chart-size", + "dxo-strip-style": "dxo-chart-strip-style", + "dxo-subtitle": "dxo-chart-subtitle", + "dxo-tick": "dxo-chart-tick", + "dxo-tick-interval": "dxo-chart-tick-interval", + "dxo-title": "dxo-chart-title", + "dxo-tooltip": "dxo-chart-tooltip", + "dxo-url": "dxo-chart-url", + "dxo-value-error-bar": "dxo-chart-value-error-bar", + "dxo-vertical-line": "dxo-chart-vertical-line", + "dxo-width": "dxo-chart-width", + "dxo-zoom-and-pan": "dxo-chart-zoom-and-pan" + }, + "DxChatComponent": { + "_hostSelector": "dx-chat", + "dxi-alert": "dxi-chat-alert", + "dxi-item": "dxi-chat-item", + "dxi-typing-user": "dxi-chat-typing-user", + "dxo-author": "dxo-chat-author", + "dxo-day-header-format": "dxo-chat-day-header-format", + "dxo-editing": "dxo-chat-editing", + "dxo-message-timestamp-format": "dxo-chat-message-timestamp-format", + "dxo-user": "dxo-chat-user" + }, + "DxCircularGaugeComponent": { + "_hostSelector": "dx-circular-gauge", + "dxi-range": "dxi-circular-gauge-range", + "dxo-animation": "dxo-circular-gauge-animation", + "dxo-background-color": "dxo-circular-gauge-background-color", + "dxo-border": "dxo-circular-gauge-border", + "dxo-color": "dxo-circular-gauge-color", + "dxo-export": "dxo-circular-gauge-export", + "dxo-font": "dxo-circular-gauge-font", + "dxo-format": "dxo-circular-gauge-format", + "dxo-geometry": "dxo-circular-gauge-geometry", + "dxo-label": "dxo-circular-gauge-label", + "dxo-loading-indicator": "dxo-circular-gauge-loading-indicator", + "dxo-margin": "dxo-circular-gauge-margin", + "dxo-minor-tick": "dxo-circular-gauge-minor-tick", + "dxo-range-container": "dxo-circular-gauge-range-container", + "dxo-scale": "dxo-circular-gauge-scale", + "dxo-shadow": "dxo-circular-gauge-shadow", + "dxo-size": "dxo-circular-gauge-size", + "dxo-subtitle": "dxo-circular-gauge-subtitle", + "dxo-subvalue-indicator": "dxo-circular-gauge-subvalue-indicator", + "dxo-text": "dxo-circular-gauge-text", + "dxo-tick": "dxo-circular-gauge-tick", + "dxo-title": "dxo-circular-gauge-title", + "dxo-tooltip": "dxo-circular-gauge-tooltip", + "dxo-value-indicator": "dxo-circular-gauge-value-indicator" + }, + "DxColorBoxComponent": { + "_hostSelector": "dx-color-box", + "dxi-button": "dxi-color-box-button", + "dxi-toolbar-item": "dxi-color-box-toolbar-item", + "dxo-animation": "dxo-color-box-animation", + "dxo-at": "dxo-color-box-at", + "dxo-boundary-offset": "dxo-color-box-boundary-offset", + "dxo-collision": "dxo-color-box-collision", + "dxo-drop-down-options": "dxo-color-box-drop-down-options", + "dxo-from": "dxo-color-box-from", + "dxo-hide": "dxo-color-box-hide", + "dxo-my": "dxo-color-box-my", + "dxo-offset": "dxo-color-box-offset", + "dxo-options": "dxo-color-box-options", + "dxo-position": "dxo-color-box-position", + "dxo-show": "dxo-color-box-show", + "dxo-to": "dxo-color-box-to" + }, + "DxContextMenuComponent": { + "_hostSelector": "dx-context-menu", + "dxi-item": "dxi-context-menu-item", + "dxo-animation": "dxo-context-menu-animation", + "dxo-at": "dxo-context-menu-at", + "dxo-boundary-offset": "dxo-context-menu-boundary-offset", + "dxo-collision": "dxo-context-menu-collision", + "dxo-delay": "dxo-context-menu-delay", + "dxo-from": "dxo-context-menu-from", + "dxo-hide": "dxo-context-menu-hide", + "dxo-my": "dxo-context-menu-my", + "dxo-offset": "dxo-context-menu-offset", + "dxo-position": "dxo-context-menu-position", + "dxo-show": "dxo-context-menu-show", + "dxo-show-event": "dxo-context-menu-show-event", + "dxo-show-submenu-mode": "dxo-context-menu-show-submenu-mode", + "dxo-to": "dxo-context-menu-to" + }, + "DxDataGridComponent": { + "_hostSelector": "dx-data-grid", + "dxi-button": "dxi-data-grid-button", + "dxi-change": "dxi-data-grid-change", + "dxi-column": "dxi-data-grid-column", + "dxi-custom-operation": "dxi-data-grid-custom-operation", + "dxi-field": "dxi-data-grid-field", + "dxi-group-item": "dxi-data-grid-group-item", + "dxi-item": "dxi-data-grid-item", + "dxi-sort-by-group-summary-info": "dxi-data-grid-sort-by-group-summary-info", + "dxi-toolbar-item": "dxi-data-grid-toolbar-item", + "dxi-total-item": "dxi-data-grid-total-item", + "dxi-validation-rule": "dxi-data-grid-validation-rule", + "dxo-animation": "dxo-data-grid-animation", + "dxo-at": "dxo-data-grid-at", + "dxo-boundary-offset": "dxo-data-grid-boundary-offset", + "dxo-col-count-by-screen": "dxo-data-grid-col-count-by-screen", + "dxo-collision": "dxo-data-grid-collision", + "dxo-column-chooser": "dxo-data-grid-column-chooser", + "dxo-column-fixing": "dxo-data-grid-column-fixing", + "dxo-cursor-offset": "dxo-data-grid-cursor-offset", + "dxo-editing": "dxo-data-grid-editing", + "dxo-export": "dxo-data-grid-export", + "dxo-filter-builder": "dxo-data-grid-filter-builder", + "dxo-filter-builder-popup": "dxo-data-grid-filter-builder-popup", + "dxo-filter-operation-descriptions": "dxo-data-grid-filter-operation-descriptions", + "dxo-filter-panel": "dxo-data-grid-filter-panel", + "dxo-filter-row": "dxo-data-grid-filter-row", + "dxo-form": "dxo-data-grid-form", + "dxo-form-item": "dxo-data-grid-form-item", + "dxo-format": "dxo-data-grid-format", + "dxo-from": "dxo-data-grid-from", + "dxo-group-operation-descriptions": "dxo-data-grid-group-operation-descriptions", + "dxo-group-panel": "dxo-data-grid-group-panel", + "dxo-grouping": "dxo-data-grid-grouping", + "dxo-header-filter": "dxo-data-grid-header-filter", + "dxo-hide": "dxo-data-grid-hide", + "dxo-icons": "dxo-data-grid-icons", + "dxo-keyboard-navigation": "dxo-data-grid-keyboard-navigation", + "dxo-label": "dxo-data-grid-label", + "dxo-load-panel": "dxo-data-grid-load-panel", + "dxo-lookup": "dxo-data-grid-lookup", + "dxo-master-detail": "dxo-data-grid-master-detail", + "dxo-my": "dxo-data-grid-my", + "dxo-offset": "dxo-data-grid-offset", + "dxo-operation-descriptions": "dxo-data-grid-operation-descriptions", + "dxo-pager": "dxo-data-grid-pager", + "dxo-paging": "dxo-data-grid-paging", + "dxo-popup": "dxo-data-grid-popup", + "dxo-position": "dxo-data-grid-position", + "dxo-remote-operations": "dxo-data-grid-remote-operations", + "dxo-row-dragging": "dxo-data-grid-row-dragging", + "dxo-scrolling": "dxo-data-grid-scrolling", + "dxo-search": "dxo-data-grid-search", + "dxo-search-panel": "dxo-data-grid-search-panel", + "dxo-selection": "dxo-data-grid-selection", + "dxo-show": "dxo-data-grid-show", + "dxo-sorting": "dxo-data-grid-sorting", + "dxo-state-storing": "dxo-data-grid-state-storing", + "dxo-summary": "dxo-data-grid-summary", + "dxo-texts": "dxo-data-grid-texts", + "dxo-to": "dxo-data-grid-to", + "dxo-toolbar": "dxo-data-grid-toolbar", + "dxo-value-format": "dxo-data-grid-value-format" + }, + "DxDateBoxComponent": { + "_hostSelector": "dx-date-box", + "dxi-button": "dxi-date-box-button", + "dxi-toolbar-item": "dxi-date-box-toolbar-item", + "dxo-animation": "dxo-date-box-animation", + "dxo-at": "dxo-date-box-at", + "dxo-boundary-offset": "dxo-date-box-boundary-offset", + "dxo-calendar-options": "dxo-date-box-calendar-options", + "dxo-collision": "dxo-date-box-collision", + "dxo-display-format": "dxo-date-box-display-format", + "dxo-drop-down-options": "dxo-date-box-drop-down-options", + "dxo-from": "dxo-date-box-from", + "dxo-hide": "dxo-date-box-hide", + "dxo-my": "dxo-date-box-my", + "dxo-offset": "dxo-date-box-offset", + "dxo-options": "dxo-date-box-options", + "dxo-position": "dxo-date-box-position", + "dxo-show": "dxo-date-box-show", + "dxo-to": "dxo-date-box-to" + }, + "DxDateRangeBoxComponent": { + "_hostSelector": "dx-date-range-box", + "dxi-button": "dxi-date-range-box-button", + "dxi-toolbar-item": "dxi-date-range-box-toolbar-item", + "dxo-animation": "dxo-date-range-box-animation", + "dxo-at": "dxo-date-range-box-at", + "dxo-boundary-offset": "dxo-date-range-box-boundary-offset", + "dxo-calendar-options": "dxo-date-range-box-calendar-options", + "dxo-collision": "dxo-date-range-box-collision", + "dxo-display-format": "dxo-date-range-box-display-format", + "dxo-drop-down-options": "dxo-date-range-box-drop-down-options", + "dxo-from": "dxo-date-range-box-from", + "dxo-hide": "dxo-date-range-box-hide", + "dxo-my": "dxo-date-range-box-my", + "dxo-offset": "dxo-date-range-box-offset", + "dxo-options": "dxo-date-range-box-options", + "dxo-position": "dxo-date-range-box-position", + "dxo-show": "dxo-date-range-box-show", + "dxo-to": "dxo-date-range-box-to" + }, + "DxDeferRenderingComponent": { + "_hostSelector": "dx-defer-rendering", + "dxo-animation": "dxo-defer-rendering-animation", + "dxo-at": "dxo-defer-rendering-at", + "dxo-boundary-offset": "dxo-defer-rendering-boundary-offset", + "dxo-collision": "dxo-defer-rendering-collision", + "dxo-from": "dxo-defer-rendering-from", + "dxo-my": "dxo-defer-rendering-my", + "dxo-offset": "dxo-defer-rendering-offset", + "dxo-position": "dxo-defer-rendering-position", + "dxo-to": "dxo-defer-rendering-to" + }, + "DxDiagramComponent": { + "_hostSelector": "dx-diagram", + "dxi-command": "dxi-diagram-command", + "dxi-connection-point": "dxi-diagram-connection-point", + "dxi-custom-shape": "dxi-diagram-custom-shape", + "dxi-group": "dxi-diagram-group", + "dxi-item": "dxi-diagram-item", + "dxi-tab": "dxi-diagram-tab", + "dxo-auto-layout": "dxo-diagram-auto-layout", + "dxo-context-menu": "dxo-diagram-context-menu", + "dxo-context-toolbox": "dxo-diagram-context-toolbox", + "dxo-default-item-properties": "dxo-diagram-default-item-properties", + "dxo-edges": "dxo-diagram-edges", + "dxo-editing": "dxo-diagram-editing", + "dxo-export": "dxo-diagram-export", + "dxo-grid-size": "dxo-diagram-grid-size", + "dxo-history-toolbar": "dxo-diagram-history-toolbar", + "dxo-main-toolbar": "dxo-diagram-main-toolbar", + "dxo-nodes": "dxo-diagram-nodes", + "dxo-page-size": "dxo-diagram-page-size", + "dxo-properties-panel": "dxo-diagram-properties-panel", + "dxo-toolbox": "dxo-diagram-toolbox", + "dxo-view-toolbar": "dxo-diagram-view-toolbar", + "dxo-zoom-level": "dxo-diagram-zoom-level" + }, + "DxDraggableComponent": { + "_hostSelector": "dx-draggable", + "dxo-cursor-offset": "dxo-draggable-cursor-offset" + }, + "DxDropDownBoxComponent": { + "_hostSelector": "dx-drop-down-box", + "dxi-button": "dxi-drop-down-box-button", + "dxi-toolbar-item": "dxi-drop-down-box-toolbar-item", + "dxo-animation": "dxo-drop-down-box-animation", + "dxo-at": "dxo-drop-down-box-at", + "dxo-boundary-offset": "dxo-drop-down-box-boundary-offset", + "dxo-collision": "dxo-drop-down-box-collision", + "dxo-drop-down-options": "dxo-drop-down-box-drop-down-options", + "dxo-from": "dxo-drop-down-box-from", + "dxo-hide": "dxo-drop-down-box-hide", + "dxo-my": "dxo-drop-down-box-my", + "dxo-offset": "dxo-drop-down-box-offset", + "dxo-options": "dxo-drop-down-box-options", + "dxo-position": "dxo-drop-down-box-position", + "dxo-show": "dxo-drop-down-box-show", + "dxo-to": "dxo-drop-down-box-to" + }, + "DxDropDownButtonComponent": { + "_hostSelector": "dx-drop-down-button", + "dxi-item": "dxi-drop-down-button-item", + "dxi-toolbar-item": "dxi-drop-down-button-toolbar-item", + "dxo-animation": "dxo-drop-down-button-animation", + "dxo-at": "dxo-drop-down-button-at", + "dxo-boundary-offset": "dxo-drop-down-button-boundary-offset", + "dxo-collision": "dxo-drop-down-button-collision", + "dxo-drop-down-options": "dxo-drop-down-button-drop-down-options", + "dxo-from": "dxo-drop-down-button-from", + "dxo-hide": "dxo-drop-down-button-hide", + "dxo-my": "dxo-drop-down-button-my", + "dxo-offset": "dxo-drop-down-button-offset", + "dxo-position": "dxo-drop-down-button-position", + "dxo-show": "dxo-drop-down-button-show", + "dxo-to": "dxo-drop-down-button-to" + }, + "DxFileManagerComponent": { + "_hostSelector": "dx-file-manager", + "dxi-column": "dxi-file-manager-column", + "dxi-file-selection-item": "dxi-file-manager-file-selection-item", + "dxi-item": "dxi-file-manager-item", + "dxi-toolbar-item": "dxi-file-manager-toolbar-item", + "dxo-context-menu": "dxo-file-manager-context-menu", + "dxo-details": "dxo-file-manager-details", + "dxo-item-view": "dxo-file-manager-item-view", + "dxo-notifications": "dxo-file-manager-notifications", + "dxo-permissions": "dxo-file-manager-permissions", + "dxo-toolbar": "dxo-file-manager-toolbar", + "dxo-upload": "dxo-file-manager-upload" + }, + "DxFilterBuilderComponent": { + "_hostSelector": "dx-filter-builder", + "dxi-custom-operation": "dxi-filter-builder-custom-operation", + "dxi-field": "dxi-filter-builder-field", + "dxo-filter-operation-descriptions": "dxo-filter-builder-filter-operation-descriptions", + "dxo-format": "dxo-filter-builder-format", + "dxo-group-operation-descriptions": "dxo-filter-builder-group-operation-descriptions", + "dxo-lookup": "dxo-filter-builder-lookup" + }, + "DxFormComponent": { + "_hostSelector": "dx-form", + "dxi-group-item": "dxi-form-group-item", + "dxi-item": "dxi-form-item", + "dxi-tab": "dxi-form-tab", + "dxi-validation-rule": "dxi-form-validation-rule", + "dxo-button-options": "dxo-form-button-options", + "dxo-col-count-by-screen": "dxo-form-col-count-by-screen", + "dxo-label": "dxo-form-label", + "dxo-tab-panel-options": "dxo-form-tab-panel-options" + }, + "DxFunnelComponent": { + "_hostSelector": "dx-funnel", + "dxo-adaptive-layout": "dxo-funnel-adaptive-layout", + "dxo-border": "dxo-funnel-border", + "dxo-connector": "dxo-funnel-connector", + "dxo-export": "dxo-funnel-export", + "dxo-font": "dxo-funnel-font", + "dxo-format": "dxo-funnel-format", + "dxo-hatching": "dxo-funnel-hatching", + "dxo-hover-style": "dxo-funnel-hover-style", + "dxo-item": "dxo-funnel-item", + "dxo-label": "dxo-funnel-label", + "dxo-legend": "dxo-funnel-legend", + "dxo-loading-indicator": "dxo-funnel-loading-indicator", + "dxo-margin": "dxo-funnel-margin", + "dxo-selection-style": "dxo-funnel-selection-style", + "dxo-shadow": "dxo-funnel-shadow", + "dxo-size": "dxo-funnel-size", + "dxo-subtitle": "dxo-funnel-subtitle", + "dxo-title": "dxo-funnel-title", + "dxo-tooltip": "dxo-funnel-tooltip" + }, + "DxGalleryComponent": { + "_hostSelector": "dx-gallery", + "dxi-item": "dxi-gallery-item" + }, + "DxGanttComponent": { + "_hostSelector": "dx-gantt", + "dxi-column": "dxi-gantt-column", + "dxi-item": "dxi-gantt-item", + "dxi-strip-line": "dxi-gantt-strip-line", + "dxi-toolbar-item": "dxi-gantt-toolbar-item", + "dxo-context-menu": "dxo-gantt-context-menu", + "dxo-dependencies": "dxo-gantt-dependencies", + "dxo-editing": "dxo-gantt-editing", + "dxo-filter-row": "dxo-gantt-filter-row", + "dxo-format": "dxo-gantt-format", + "dxo-header-filter": "dxo-gantt-header-filter", + "dxo-operation-descriptions": "dxo-gantt-operation-descriptions", + "dxo-resource-assignments": "dxo-gantt-resource-assignments", + "dxo-resources": "dxo-gantt-resources", + "dxo-scale-type-range": "dxo-gantt-scale-type-range", + "dxo-search": "dxo-gantt-search", + "dxo-sorting": "dxo-gantt-sorting", + "dxo-tasks": "dxo-gantt-tasks", + "dxo-texts": "dxo-gantt-texts", + "dxo-toolbar": "dxo-gantt-toolbar", + "dxo-validation": "dxo-gantt-validation" + }, + "DxHtmlEditorComponent": { + "_hostSelector": "dx-html-editor", + "dxi-command": "dxi-html-editor-command", + "dxi-item": "dxi-html-editor-item", + "dxi-mention": "dxi-html-editor-mention", + "dxi-tab": "dxi-html-editor-tab", + "dxi-toolbar-item": "dxi-html-editor-toolbar-item", + "dxo-converter": "dxo-html-editor-converter", + "dxo-file-uploader-options": "dxo-html-editor-file-uploader-options", + "dxo-image-upload": "dxo-html-editor-image-upload", + "dxo-media-resizing": "dxo-html-editor-media-resizing", + "dxo-table-context-menu": "dxo-html-editor-table-context-menu", + "dxo-table-resizing": "dxo-html-editor-table-resizing", + "dxo-toolbar": "dxo-html-editor-toolbar", + "dxo-variables": "dxo-html-editor-variables" + }, + "DxLinearGaugeComponent": { + "_hostSelector": "dx-linear-gauge", + "dxi-range": "dxi-linear-gauge-range", + "dxo-animation": "dxo-linear-gauge-animation", + "dxo-background-color": "dxo-linear-gauge-background-color", + "dxo-border": "dxo-linear-gauge-border", + "dxo-color": "dxo-linear-gauge-color", + "dxo-export": "dxo-linear-gauge-export", + "dxo-font": "dxo-linear-gauge-font", + "dxo-format": "dxo-linear-gauge-format", + "dxo-geometry": "dxo-linear-gauge-geometry", + "dxo-label": "dxo-linear-gauge-label", + "dxo-loading-indicator": "dxo-linear-gauge-loading-indicator", + "dxo-margin": "dxo-linear-gauge-margin", + "dxo-minor-tick": "dxo-linear-gauge-minor-tick", + "dxo-range-container": "dxo-linear-gauge-range-container", + "dxo-scale": "dxo-linear-gauge-scale", + "dxo-shadow": "dxo-linear-gauge-shadow", + "dxo-size": "dxo-linear-gauge-size", + "dxo-subtitle": "dxo-linear-gauge-subtitle", + "dxo-subvalue-indicator": "dxo-linear-gauge-subvalue-indicator", + "dxo-text": "dxo-linear-gauge-text", + "dxo-tick": "dxo-linear-gauge-tick", + "dxo-title": "dxo-linear-gauge-title", + "dxo-tooltip": "dxo-linear-gauge-tooltip", + "dxo-value-indicator": "dxo-linear-gauge-value-indicator", + "dxo-width": "dxo-linear-gauge-width" + }, + "DxListComponent": { + "_hostSelector": "dx-list", + "dxi-button": "dxi-list-button", + "dxi-item": "dxi-list-item", + "dxi-menu-item": "dxi-list-menu-item", + "dxo-cursor-offset": "dxo-list-cursor-offset", + "dxo-item-dragging": "dxo-list-item-dragging", + "dxo-options": "dxo-list-options", + "dxo-search-editor-options": "dxo-list-search-editor-options" + }, + "DxLoadPanelComponent": { + "_hostSelector": "dx-load-panel", + "dxo-animation": "dxo-load-panel-animation", + "dxo-at": "dxo-load-panel-at", + "dxo-boundary-offset": "dxo-load-panel-boundary-offset", + "dxo-collision": "dxo-load-panel-collision", + "dxo-from": "dxo-load-panel-from", + "dxo-hide": "dxo-load-panel-hide", + "dxo-my": "dxo-load-panel-my", + "dxo-offset": "dxo-load-panel-offset", + "dxo-position": "dxo-load-panel-position", + "dxo-show": "dxo-load-panel-show", + "dxo-to": "dxo-load-panel-to" + }, + "DxLookupComponent": { + "_hostSelector": "dx-lookup", + "dxi-item": "dxi-lookup-item", + "dxi-toolbar-item": "dxi-lookup-toolbar-item", + "dxo-animation": "dxo-lookup-animation", + "dxo-at": "dxo-lookup-at", + "dxo-boundary-offset": "dxo-lookup-boundary-offset", + "dxo-collision": "dxo-lookup-collision", + "dxo-drop-down-options": "dxo-lookup-drop-down-options", + "dxo-from": "dxo-lookup-from", + "dxo-hide": "dxo-lookup-hide", + "dxo-hide-event": "dxo-lookup-hide-event", + "dxo-my": "dxo-lookup-my", + "dxo-offset": "dxo-lookup-offset", + "dxo-position": "dxo-lookup-position", + "dxo-show": "dxo-lookup-show", + "dxo-show-event": "dxo-lookup-show-event", + "dxo-to": "dxo-lookup-to" + }, + "DxMapComponent": { + "_hostSelector": "dx-map", + "dxi-location": "dxi-map-location", + "dxi-marker": "dxi-map-marker", + "dxi-route": "dxi-map-route", + "dxo-api-key": "dxo-map-api-key", + "dxo-provider-config": "dxo-map-provider-config", + "dxo-tooltip": "dxo-map-tooltip" + }, + "DxMenuComponent": { + "_hostSelector": "dx-menu", + "dxi-item": "dxi-menu-item", + "dxo-animation": "dxo-menu-animation", + "dxo-at": "dxo-menu-at", + "dxo-boundary-offset": "dxo-menu-boundary-offset", + "dxo-collision": "dxo-menu-collision", + "dxo-delay": "dxo-menu-delay", + "dxo-from": "dxo-menu-from", + "dxo-hide": "dxo-menu-hide", + "dxo-my": "dxo-menu-my", + "dxo-offset": "dxo-menu-offset", + "dxo-position": "dxo-menu-position", + "dxo-show": "dxo-menu-show", + "dxo-show-first-submenu-mode": "dxo-menu-show-first-submenu-mode", + "dxo-show-submenu-mode": "dxo-menu-show-submenu-mode", + "dxo-to": "dxo-menu-to" + }, + "DxMultiViewComponent": { + "_hostSelector": "dx-multi-view", + "dxi-item": "dxi-multi-view-item" + }, + "DxNumberBoxComponent": { + "_hostSelector": "dx-number-box", + "dxi-button": "dxi-number-box-button", + "dxo-format": "dxo-number-box-format", + "dxo-options": "dxo-number-box-options" + }, + "DxPieChartComponent": { + "_hostSelector": "dx-pie-chart", + "dxi-annotation": "dxi-pie-chart-annotation", + "dxi-series": "dxi-pie-chart-series", + "dxo-adaptive-layout": "dxo-pie-chart-adaptive-layout", + "dxo-animation": "dxo-pie-chart-animation", + "dxo-argument-format": "dxo-pie-chart-argument-format", + "dxo-border": "dxo-pie-chart-border", + "dxo-color": "dxo-pie-chart-color", + "dxo-common-annotation-settings": "dxo-pie-chart-common-annotation-settings", + "dxo-common-series-settings": "dxo-pie-chart-common-series-settings", + "dxo-connector": "dxo-pie-chart-connector", + "dxo-export": "dxo-pie-chart-export", + "dxo-font": "dxo-pie-chart-font", + "dxo-format": "dxo-pie-chart-format", + "dxo-hatching": "dxo-pie-chart-hatching", + "dxo-hover-style": "dxo-pie-chart-hover-style", + "dxo-image": "dxo-pie-chart-image", + "dxo-label": "dxo-pie-chart-label", + "dxo-legend": "dxo-pie-chart-legend", + "dxo-loading-indicator": "dxo-pie-chart-loading-indicator", + "dxo-margin": "dxo-pie-chart-margin", + "dxo-selection-style": "dxo-pie-chart-selection-style", + "dxo-series-template": "dxo-pie-chart-series-template", + "dxo-shadow": "dxo-pie-chart-shadow", + "dxo-size": "dxo-pie-chart-size", + "dxo-small-values-grouping": "dxo-pie-chart-small-values-grouping", + "dxo-subtitle": "dxo-pie-chart-subtitle", + "dxo-title": "dxo-pie-chart-title", + "dxo-tooltip": "dxo-pie-chart-tooltip" + }, + "DxPivotGridComponent": { + "_hostSelector": "dx-pivot-grid", + "dxo-export": "dxo-pivot-grid-export", + "dxo-field-chooser": "dxo-pivot-grid-field-chooser", + "dxo-field-panel": "dxo-pivot-grid-field-panel", + "dxo-header-filter": "dxo-pivot-grid-header-filter", + "dxo-load-panel": "dxo-pivot-grid-load-panel", + "dxo-scrolling": "dxo-pivot-grid-scrolling", + "dxo-search": "dxo-pivot-grid-search", + "dxo-state-storing": "dxo-pivot-grid-state-storing", + "dxo-texts": "dxo-pivot-grid-texts" + }, + "DxPivotGridFieldChooserComponent": { + "_hostSelector": "dx-pivot-grid-field-chooser", + "dxo-header-filter": "dxo-pivot-grid-field-chooser-header-filter", + "dxo-search": "dxo-pivot-grid-field-chooser-search", + "dxo-texts": "dxo-pivot-grid-field-chooser-texts" + }, + "DxPolarChartComponent": { + "_hostSelector": "dx-polar-chart", + "dxi-annotation": "dxi-polar-chart-annotation", + "dxi-constant-line": "dxi-polar-chart-constant-line", + "dxi-series": "dxi-polar-chart-series", + "dxi-strip": "dxi-polar-chart-strip", + "dxo-adaptive-layout": "dxo-polar-chart-adaptive-layout", + "dxo-animation": "dxo-polar-chart-animation", + "dxo-argument-axis": "dxo-polar-chart-argument-axis", + "dxo-argument-format": "dxo-polar-chart-argument-format", + "dxo-border": "dxo-polar-chart-border", + "dxo-color": "dxo-polar-chart-color", + "dxo-common-annotation-settings": "dxo-polar-chart-common-annotation-settings", + "dxo-common-axis-settings": "dxo-polar-chart-common-axis-settings", + "dxo-common-series-settings": "dxo-polar-chart-common-series-settings", + "dxo-connector": "dxo-polar-chart-connector", + "dxo-constant-line-style": "dxo-polar-chart-constant-line-style", + "dxo-data-prepare-settings": "dxo-polar-chart-data-prepare-settings", + "dxo-export": "dxo-polar-chart-export", + "dxo-font": "dxo-polar-chart-font", + "dxo-format": "dxo-polar-chart-format", + "dxo-grid": "dxo-polar-chart-grid", + "dxo-hatching": "dxo-polar-chart-hatching", + "dxo-hover-style": "dxo-polar-chart-hover-style", + "dxo-image": "dxo-polar-chart-image", + "dxo-label": "dxo-polar-chart-label", + "dxo-legend": "dxo-polar-chart-legend", + "dxo-loading-indicator": "dxo-polar-chart-loading-indicator", + "dxo-margin": "dxo-polar-chart-margin", + "dxo-min-visual-range-length": "dxo-polar-chart-min-visual-range-length", + "dxo-minor-grid": "dxo-polar-chart-minor-grid", + "dxo-minor-tick": "dxo-polar-chart-minor-tick", + "dxo-minor-tick-interval": "dxo-polar-chart-minor-tick-interval", + "dxo-point": "dxo-polar-chart-point", + "dxo-selection-style": "dxo-polar-chart-selection-style", + "dxo-series-template": "dxo-polar-chart-series-template", + "dxo-shadow": "dxo-polar-chart-shadow", + "dxo-size": "dxo-polar-chart-size", + "dxo-strip-style": "dxo-polar-chart-strip-style", + "dxo-subtitle": "dxo-polar-chart-subtitle", + "dxo-tick": "dxo-polar-chart-tick", + "dxo-tick-interval": "dxo-polar-chart-tick-interval", + "dxo-title": "dxo-polar-chart-title", + "dxo-tooltip": "dxo-polar-chart-tooltip", + "dxo-value-axis": "dxo-polar-chart-value-axis", + "dxo-value-error-bar": "dxo-polar-chart-value-error-bar" + }, + "DxPopoverComponent": { + "_hostSelector": "dx-popover", + "dxi-toolbar-item": "dxi-popover-toolbar-item", + "dxo-animation": "dxo-popover-animation", + "dxo-at": "dxo-popover-at", + "dxo-boundary-offset": "dxo-popover-boundary-offset", + "dxo-collision": "dxo-popover-collision", + "dxo-from": "dxo-popover-from", + "dxo-hide": "dxo-popover-hide", + "dxo-hide-event": "dxo-popover-hide-event", + "dxo-my": "dxo-popover-my", + "dxo-offset": "dxo-popover-offset", + "dxo-position": "dxo-popover-position", + "dxo-show": "dxo-popover-show", + "dxo-show-event": "dxo-popover-show-event", + "dxo-to": "dxo-popover-to" + }, + "DxRadioGroupComponent": { + "_hostSelector": "dx-radio-group", + "dxi-item": "dxi-radio-group-item" + }, + "DxRangeSelectorComponent": { + "_hostSelector": "dx-range-selector", + "dxi-break": "dxi-range-selector-break", + "dxi-series": "dxi-range-selector-series", + "dxo-aggregation": "dxo-range-selector-aggregation", + "dxo-aggregation-interval": "dxo-range-selector-aggregation-interval", + "dxo-argument-format": "dxo-range-selector-argument-format", + "dxo-background": "dxo-range-selector-background", + "dxo-behavior": "dxo-range-selector-behavior", + "dxo-border": "dxo-range-selector-border", + "dxo-break-style": "dxo-range-selector-break-style", + "dxo-chart": "dxo-range-selector-chart", + "dxo-color": "dxo-range-selector-color", + "dxo-common-series-settings": "dxo-range-selector-common-series-settings", + "dxo-connector": "dxo-range-selector-connector", + "dxo-data-prepare-settings": "dxo-range-selector-data-prepare-settings", + "dxo-export": "dxo-range-selector-export", + "dxo-font": "dxo-range-selector-font", + "dxo-format": "dxo-range-selector-format", + "dxo-hatching": "dxo-range-selector-hatching", + "dxo-height": "dxo-range-selector-height", + "dxo-hover-style": "dxo-range-selector-hover-style", + "dxo-image": "dxo-range-selector-image", + "dxo-indent": "dxo-range-selector-indent", + "dxo-label": "dxo-range-selector-label", + "dxo-loading-indicator": "dxo-range-selector-loading-indicator", + "dxo-margin": "dxo-range-selector-margin", + "dxo-marker": "dxo-range-selector-marker", + "dxo-max-range": "dxo-range-selector-max-range", + "dxo-min-range": "dxo-range-selector-min-range", + "dxo-minor-tick": "dxo-range-selector-minor-tick", + "dxo-minor-tick-interval": "dxo-range-selector-minor-tick-interval", + "dxo-point": "dxo-range-selector-point", + "dxo-reduction": "dxo-range-selector-reduction", + "dxo-scale": "dxo-range-selector-scale", + "dxo-selection-style": "dxo-range-selector-selection-style", + "dxo-series-template": "dxo-range-selector-series-template", + "dxo-shutter": "dxo-range-selector-shutter", + "dxo-size": "dxo-range-selector-size", + "dxo-slider-handle": "dxo-range-selector-slider-handle", + "dxo-slider-marker": "dxo-range-selector-slider-marker", + "dxo-subtitle": "dxo-range-selector-subtitle", + "dxo-tick": "dxo-range-selector-tick", + "dxo-tick-interval": "dxo-range-selector-tick-interval", + "dxo-title": "dxo-range-selector-title", + "dxo-url": "dxo-range-selector-url", + "dxo-value-axis": "dxo-range-selector-value-axis", + "dxo-value-error-bar": "dxo-range-selector-value-error-bar", + "dxo-width": "dxo-range-selector-width" + }, + "DxRangeSliderComponent": { + "_hostSelector": "dx-range-slider", + "dxo-format": "dxo-range-slider-format", + "dxo-label": "dxo-range-slider-label", + "dxo-tooltip": "dxo-range-slider-tooltip" + }, + "DxResponsiveBoxComponent": { + "_hostSelector": "dx-responsive-box", + "dxi-col": "dxi-responsive-box-col", + "dxi-item": "dxi-responsive-box-item", + "dxi-location": "dxi-responsive-box-location", + "dxi-row": "dxi-responsive-box-row" + }, + "DxSankeyComponent": { + "_hostSelector": "dx-sankey", + "dxo-adaptive-layout": "dxo-sankey-adaptive-layout", + "dxo-border": "dxo-sankey-border", + "dxo-export": "dxo-sankey-export", + "dxo-font": "dxo-sankey-font", + "dxo-format": "dxo-sankey-format", + "dxo-hatching": "dxo-sankey-hatching", + "dxo-hover-style": "dxo-sankey-hover-style", + "dxo-label": "dxo-sankey-label", + "dxo-link": "dxo-sankey-link", + "dxo-loading-indicator": "dxo-sankey-loading-indicator", + "dxo-margin": "dxo-sankey-margin", + "dxo-node": "dxo-sankey-node", + "dxo-shadow": "dxo-sankey-shadow", + "dxo-size": "dxo-sankey-size", + "dxo-subtitle": "dxo-sankey-subtitle", + "dxo-title": "dxo-sankey-title", + "dxo-tooltip": "dxo-sankey-tooltip" + }, + "DxSchedulerComponent": { + "_hostSelector": "dx-scheduler", + "dxi-item": "dxi-scheduler-item", + "dxi-resource": "dxi-scheduler-resource", + "dxi-toolbar-item": "dxi-scheduler-toolbar-item", + "dxi-view": "dxi-scheduler-view", + "dxo-appointment-dragging": "dxo-scheduler-appointment-dragging", + "dxo-editing": "dxo-scheduler-editing", + "dxo-options": "dxo-scheduler-options", + "dxo-scrolling": "dxo-scheduler-scrolling", + "dxo-toolbar": "dxo-scheduler-toolbar" + }, + "DxSelectBoxComponent": { + "_hostSelector": "dx-select-box", + "dxi-button": "dxi-select-box-button", + "dxi-item": "dxi-select-box-item", + "dxi-toolbar-item": "dxi-select-box-toolbar-item", + "dxo-animation": "dxo-select-box-animation", + "dxo-at": "dxo-select-box-at", + "dxo-boundary-offset": "dxo-select-box-boundary-offset", + "dxo-collision": "dxo-select-box-collision", + "dxo-drop-down-options": "dxo-select-box-drop-down-options", + "dxo-from": "dxo-select-box-from", + "dxo-hide": "dxo-select-box-hide", + "dxo-my": "dxo-select-box-my", + "dxo-offset": "dxo-select-box-offset", + "dxo-options": "dxo-select-box-options", + "dxo-position": "dxo-select-box-position", + "dxo-show": "dxo-select-box-show", + "dxo-to": "dxo-select-box-to" + }, + "DxSliderComponent": { + "_hostSelector": "dx-slider", + "dxo-format": "dxo-slider-format", + "dxo-label": "dxo-slider-label", + "dxo-tooltip": "dxo-slider-tooltip" + }, + "DxSortableComponent": { + "_hostSelector": "dx-sortable", + "dxo-cursor-offset": "dxo-sortable-cursor-offset" + }, + "DxSparklineComponent": { + "_hostSelector": "dx-sparkline", + "dxo-border": "dxo-sparkline-border", + "dxo-font": "dxo-sparkline-font", + "dxo-format": "dxo-sparkline-format", + "dxo-margin": "dxo-sparkline-margin", + "dxo-shadow": "dxo-sparkline-shadow", + "dxo-size": "dxo-sparkline-size", + "dxo-tooltip": "dxo-sparkline-tooltip" + }, + "DxSplitterComponent": { + "_hostSelector": "dx-splitter", + "dxi-item": "dxi-splitter-item" + }, + "DxStepperComponent": { + "_hostSelector": "dx-stepper", + "dxi-item": "dxi-stepper-item" + }, + "DxTabPanelComponent": { + "_hostSelector": "dx-tab-panel", + "dxi-item": "dxi-tab-panel-item" + }, + "DxTabsComponent": { + "_hostSelector": "dx-tabs", + "dxi-item": "dxi-tabs-item" + }, + "DxTagBoxComponent": { + "_hostSelector": "dx-tag-box", + "dxi-button": "dxi-tag-box-button", + "dxi-item": "dxi-tag-box-item", + "dxi-toolbar-item": "dxi-tag-box-toolbar-item", + "dxo-animation": "dxo-tag-box-animation", + "dxo-at": "dxo-tag-box-at", + "dxo-boundary-offset": "dxo-tag-box-boundary-offset", + "dxo-collision": "dxo-tag-box-collision", + "dxo-drop-down-options": "dxo-tag-box-drop-down-options", + "dxo-from": "dxo-tag-box-from", + "dxo-hide": "dxo-tag-box-hide", + "dxo-my": "dxo-tag-box-my", + "dxo-offset": "dxo-tag-box-offset", + "dxo-options": "dxo-tag-box-options", + "dxo-position": "dxo-tag-box-position", + "dxo-show": "dxo-tag-box-show", + "dxo-to": "dxo-tag-box-to" + }, + "DxTextBoxComponent": { + "_hostSelector": "dx-text-box", + "dxi-button": "dxi-text-box-button", + "dxo-options": "dxo-text-box-options" + }, + "DxTileViewComponent": { + "_hostSelector": "dx-tile-view", + "dxi-item": "dxi-tile-view-item" + }, + "DxToastComponent": { + "_hostSelector": "dx-toast", + "dxo-animation": "dxo-toast-animation", + "dxo-at": "dxo-toast-at", + "dxo-boundary-offset": "dxo-toast-boundary-offset", + "dxo-collision": "dxo-toast-collision", + "dxo-from": "dxo-toast-from", + "dxo-hide": "dxo-toast-hide", + "dxo-my": "dxo-toast-my", + "dxo-offset": "dxo-toast-offset", + "dxo-position": "dxo-toast-position", + "dxo-show": "dxo-toast-show", + "dxo-to": "dxo-toast-to" + }, + "DxToolbarComponent": { + "_hostSelector": "dx-toolbar", + "dxi-item": "dxi-toolbar-item" + }, + "DxTooltipComponent": { + "_hostSelector": "dx-tooltip", + "dxo-animation": "dxo-tooltip-animation", + "dxo-at": "dxo-tooltip-at", + "dxo-boundary-offset": "dxo-tooltip-boundary-offset", + "dxo-collision": "dxo-tooltip-collision", + "dxo-from": "dxo-tooltip-from", + "dxo-hide": "dxo-tooltip-hide", + "dxo-hide-event": "dxo-tooltip-hide-event", + "dxo-my": "dxo-tooltip-my", + "dxo-offset": "dxo-tooltip-offset", + "dxo-position": "dxo-tooltip-position", + "dxo-show": "dxo-tooltip-show", + "dxo-show-event": "dxo-tooltip-show-event", + "dxo-to": "dxo-tooltip-to" + }, + "DxTreeListComponent": { + "_hostSelector": "dx-tree-list", + "dxi-button": "dxi-tree-list-button", + "dxi-change": "dxi-tree-list-change", + "dxi-column": "dxi-tree-list-column", + "dxi-custom-operation": "dxi-tree-list-custom-operation", + "dxi-field": "dxi-tree-list-field", + "dxi-item": "dxi-tree-list-item", + "dxi-toolbar-item": "dxi-tree-list-toolbar-item", + "dxi-validation-rule": "dxi-tree-list-validation-rule", + "dxo-animation": "dxo-tree-list-animation", + "dxo-at": "dxo-tree-list-at", + "dxo-boundary-offset": "dxo-tree-list-boundary-offset", + "dxo-col-count-by-screen": "dxo-tree-list-col-count-by-screen", + "dxo-collision": "dxo-tree-list-collision", + "dxo-column-chooser": "dxo-tree-list-column-chooser", + "dxo-column-fixing": "dxo-tree-list-column-fixing", + "dxo-cursor-offset": "dxo-tree-list-cursor-offset", + "dxo-editing": "dxo-tree-list-editing", + "dxo-filter-builder": "dxo-tree-list-filter-builder", + "dxo-filter-builder-popup": "dxo-tree-list-filter-builder-popup", + "dxo-filter-operation-descriptions": "dxo-tree-list-filter-operation-descriptions", + "dxo-filter-panel": "dxo-tree-list-filter-panel", + "dxo-filter-row": "dxo-tree-list-filter-row", + "dxo-form": "dxo-tree-list-form", + "dxo-form-item": "dxo-tree-list-form-item", + "dxo-format": "dxo-tree-list-format", + "dxo-from": "dxo-tree-list-from", + "dxo-group-operation-descriptions": "dxo-tree-list-group-operation-descriptions", + "dxo-header-filter": "dxo-tree-list-header-filter", + "dxo-hide": "dxo-tree-list-hide", + "dxo-icons": "dxo-tree-list-icons", + "dxo-keyboard-navigation": "dxo-tree-list-keyboard-navigation", + "dxo-label": "dxo-tree-list-label", + "dxo-load-panel": "dxo-tree-list-load-panel", + "dxo-lookup": "dxo-tree-list-lookup", + "dxo-my": "dxo-tree-list-my", + "dxo-offset": "dxo-tree-list-offset", + "dxo-operation-descriptions": "dxo-tree-list-operation-descriptions", + "dxo-pager": "dxo-tree-list-pager", + "dxo-paging": "dxo-tree-list-paging", + "dxo-popup": "dxo-tree-list-popup", + "dxo-position": "dxo-tree-list-position", + "dxo-remote-operations": "dxo-tree-list-remote-operations", + "dxo-row-dragging": "dxo-tree-list-row-dragging", + "dxo-scrolling": "dxo-tree-list-scrolling", + "dxo-search": "dxo-tree-list-search", + "dxo-search-panel": "dxo-tree-list-search-panel", + "dxo-selection": "dxo-tree-list-selection", + "dxo-show": "dxo-tree-list-show", + "dxo-sorting": "dxo-tree-list-sorting", + "dxo-state-storing": "dxo-tree-list-state-storing", + "dxo-texts": "dxo-tree-list-texts", + "dxo-to": "dxo-tree-list-to", + "dxo-toolbar": "dxo-tree-list-toolbar" + }, + "DxTreeMapComponent": { + "_hostSelector": "dx-tree-map", + "dxo-border": "dxo-tree-map-border", + "dxo-colorizer": "dxo-tree-map-colorizer", + "dxo-export": "dxo-tree-map-export", + "dxo-font": "dxo-tree-map-font", + "dxo-format": "dxo-tree-map-format", + "dxo-group": "dxo-tree-map-group", + "dxo-hover-style": "dxo-tree-map-hover-style", + "dxo-label": "dxo-tree-map-label", + "dxo-loading-indicator": "dxo-tree-map-loading-indicator", + "dxo-margin": "dxo-tree-map-margin", + "dxo-selection-style": "dxo-tree-map-selection-style", + "dxo-shadow": "dxo-tree-map-shadow", + "dxo-size": "dxo-tree-map-size", + "dxo-subtitle": "dxo-tree-map-subtitle", + "dxo-tile": "dxo-tree-map-tile", + "dxo-title": "dxo-tree-map-title", + "dxo-tooltip": "dxo-tree-map-tooltip" + }, + "DxTreeViewComponent": { + "_hostSelector": "dx-tree-view", + "dxi-button": "dxi-tree-view-button", + "dxi-item": "dxi-tree-view-item", + "dxo-options": "dxo-tree-view-options", + "dxo-search-editor-options": "dxo-tree-view-search-editor-options" + }, + "DxValidationSummaryComponent": { + "_hostSelector": "dx-validation-summary", + "dxi-item": "dxi-validation-summary-item" + }, + "DxValidatorComponent": { + "_hostSelector": "dx-validator", + "dxi-validation-rule": "dxi-validator-validation-rule", + "dxo-adapter": "dxo-validator-adapter" + }, + "DxVectorMapComponent": { + "_hostSelector": "dx-vector-map", + "dxi-annotation": "dxi-vector-map-annotation", + "dxi-layer": "dxi-vector-map-layer", + "dxi-legend": "dxi-vector-map-legend", + "dxo-background": "dxo-vector-map-background", + "dxo-border": "dxo-vector-map-border", + "dxo-common-annotation-settings": "dxo-vector-map-common-annotation-settings", + "dxo-control-bar": "dxo-vector-map-control-bar", + "dxo-export": "dxo-vector-map-export", + "dxo-font": "dxo-vector-map-font", + "dxo-image": "dxo-vector-map-image", + "dxo-label": "dxo-vector-map-label", + "dxo-loading-indicator": "dxo-vector-map-loading-indicator", + "dxo-margin": "dxo-vector-map-margin", + "dxo-projection": "dxo-vector-map-projection", + "dxo-shadow": "dxo-vector-map-shadow", + "dxo-size": "dxo-vector-map-size", + "dxo-source": "dxo-vector-map-source", + "dxo-subtitle": "dxo-vector-map-subtitle", + "dxo-title": "dxo-vector-map-title", + "dxo-tooltip": "dxo-vector-map-tooltip" + } +} diff --git a/packages/devextreme-schematics/src/migrate-config-components/schema.json b/packages/devextreme-schematics/src/migrate-config-components/schema.json new file mode 100644 index 000000000..66012f3ff --- /dev/null +++ b/packages/devextreme-schematics/src/migrate-config-components/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "SchematicsDevextremeMigrateConfigComponents", + "title": "Migrate to the latest DevExtreme configuration components.", + "type": "object", + "properties": { + "include": { + "oneOf": [ + { "type": "array", "items": { "type": "string" } }, + { "type": "string" } + ], + "description": "Glob(s) of template files to include (default: **/*.html)" + }, + "scriptInclude": { + "oneOf": [ + { "type": "array", "items": { "type": "string" } }, + { "type": "string" } + ], + "description": "Glob(s) of TS/JS files to scan for inline templates (default: ['**/*.ts','**/*.js']; set empty ('' or []) to disable)" + }, + "dry": { + "oneOf": [ + { "type": "boolean", "default": false }, + { "type": "string", "enum": ["true", "false"], "default": "false" } + ] + } + } +} \ No newline at end of file diff --git a/packages/devextreme-schematics/src/migrate-config-components/template-migrator.ts b/packages/devextreme-schematics/src/migrate-config-components/template-migrator.ts new file mode 100644 index 000000000..4ec4c0b53 --- /dev/null +++ b/packages/devextreme-schematics/src/migrate-config-components/template-migrator.ts @@ -0,0 +1,333 @@ +import { Tree } from '@angular-devkit/schematics'; +import * as parse5 from 'parse5'; +import * as path from 'path'; +import picomatch from 'picomatch'; + +// Dynamically require TypeScript if available; skip inline template migration if not. +let ts: any = null; +const tsResolutionErrors: string[] = []; +const tsResolutionPaths = [ + __dirname, + process.cwd(), + path.dirname(require.main?.filename || ''), +]; +for (const p of tsResolutionPaths) { + try { + // tslint:disable-next-line:no-var-requires + ts = require(require.resolve('typescript', { paths: [p] })); + break; + } catch (err) { + tsResolutionErrors.push(`Failed to import TypeScript from ${p}: ${err?.message || err}`); + } +} +if (!ts) { + try { + // tslint:disable-next-line:no-var-requires + ts = require('typescript'); + } catch (err) { + tsResolutionErrors.push(`Failed to import TypeScript: ${err?.message || err}`); + } +} + +// Minimal parse5 types for our usage +interface P5Node { [k: string]: any; } +interface P5Element extends P5Node { tagName?: string; } +interface P5Document extends P5Node { + documentElement?: P5Element; +} + +export interface HostRule { + hostSelector: string; + configMap: Record; +} + +export interface RunnerOptions { + includeGlobs: string[]; + rules: HostRule[]; +} + +export interface ExecOptions { + dryRun: boolean; + logger: { info: (s: string) => void; warn: (s: string) => void }; +} + +// Transform external HTML template files matched by includeGlobs. +export async function applyHostAwareTemplateMigrations( + tree: Tree, + runner: RunnerOptions, + exec: ExecOptions +): Promise { + const matcher = picomatch(runner.includeGlobs.length ? runner.includeGlobs : ['**/*.html']); + + tree.visit(filePath => { + if (!matcher(filePath)) { + return; + } + if (!filePath.endsWith('.html')) { + return; + } + + const buffer = tree.read(filePath); + if (!buffer) { + return; + } + + const source = buffer.toString('utf8'); + const { updated, changeCount } = transformTemplate(source, runner.rules); + if (changeCount === 0) { + return; + } + if (exec.dryRun) { + exec.logger.info(`[dry] ${filePath} → ${changeCount} changes`); + } else { + exec.logger.info(`${filePath} → ${changeCount} changes`); + tree.overwrite(filePath, updated); + } + }); +} + +// Apply migrations inside inline component templates found in TS/JS files. +export async function applyInlineComponentTemplateMigrations( + tree: Tree, + runner: RunnerOptions, + exec: ExecOptions, + scriptGlobs: string[] +): Promise { + if (!scriptGlobs.length) { + return; + } + if (!ts) { + exec.logger.warn( + '[config-migrator] Failed to import TypeScript. Skipping inline template migration.\n' + + 'Resolution attempts and errors:\n' + + tsResolutionErrors.map(e => ' - ' + e).join('\n') + '\n' + + 'To resolve this issue, perform one of the following steps:\n' + + ' 1. Install the "typescript" package in your project root: `npm install typescript --save-dev`\n' + + ' 2. Install the "typescript" package globally on your machine: `npm install -g typescript`\n' + + 'Refer to the README for further troubleshooting information.' + ); + return; + } + const matcher = picomatch(scriptGlobs); + tree.visit(filePath => { + if (!matcher(filePath)) { + return; + } + if (!(filePath.endsWith('.ts') || filePath.endsWith('.js'))) { + return; + } + + const buffer = tree.read(filePath); + if (!buffer) { + return; + } + const sourceText = buffer.toString('utf8'); + + const sf = ts.createSourceFile( + filePath, sourceText, ts.ScriptTarget.ES2022, true, + filePath.endsWith('.ts') ? ts.ScriptKind.TS : ts.ScriptKind.JS); + + interface TemplateEdit { start: number; end: number; text: string; changes: number; } + const edits: TemplateEdit[] = []; + + function visit(node: any) { + if (ts.isDecorator(node) && ts.isCallExpression(node.expression)) { + const call = node.expression; + if (ts.isIdentifier(call.expression) && call.expression.text === 'Component' && call.arguments.length) { + const arg = call.arguments[0]; + if (ts.isObjectLiteralExpression(arg)) { + for (const prop of arg.properties) { + if (!ts.isPropertyAssignment(prop)) { + continue; + } + const name = prop.name; + const propName = ts.isIdentifier(name) ? name.text : ts.isStringLiteral(name) ? name.text : undefined; + if (propName !== 'template') { + continue; + } + const init = prop.initializer; + if (ts.isStringLiteral(init)) { + const raw = init.text; + const { updated, changeCount } = transformTemplate(raw, runner.rules); + if (changeCount > 0) { + const quote = init.getText().startsWith("'") ? '"' : init.getText()[0]; + const newLiteral = quote + updated.replace(new RegExp(quote, 'g'), '\\' + quote) + quote; + edits.push({ start: init.getStart(), end: init.getEnd(), text: newLiteral, changes: changeCount }); + } + } else if (ts.isNoSubstitutionTemplateLiteral(init)) { + const raw = init.text; + const { updated, changeCount } = transformTemplate(raw, runner.rules); + if (changeCount > 0) { + const newLiteral = '`' + escapeBackticks(updated) + '`'; + edits.push({ start: init.getStart(), end: init.getEnd(), text: newLiteral, changes: changeCount }); + } + } else if (ts.isTemplateExpression(init)) { + const { placeholderContent, placeholders } = flattenTemplateExpression(init, sourceText); + const { updated, changeCount } = transformTemplate(placeholderContent, runner.rules); + if (changeCount > 0) { + let rebuilt = updated; + placeholders.forEach(placeholder => { + rebuilt = rebuilt.replace(new RegExp(placeholder.token, 'g'), placeholder.fullText); + }); + const newLiteral = '`' + escapeBackticks(rebuilt) + '`'; + edits.push({ start: init.getStart(), end: init.getEnd(), text: newLiteral, changes: changeCount }); + } + } + } + } + } + } + ts.forEachChild(node, visit); + } + visit(sf); + + if (!edits.length) { + return; + } + edits.sort((a, b) => b.start - a.start); // edits from last to first + let updatedFile = sourceText; + for (const edit of edits) { + updatedFile = updatedFile.slice(0, edit.start) + edit.text + updatedFile.slice(edit.end); + } + const totalChanges = edits.reduce((acc, edit) => acc + edit.changes, 0); + if (exec.dryRun) { + exec.logger.info( + `[dry] ${filePath} (inline templates) → ${totalChanges} changes in ${edits.length} template(s)`); + } else { + exec.logger.info( + `${filePath} (inline templates) → ${totalChanges} changes in ${edits.length} template(s)`); + tree.overwrite(filePath, updatedFile); + } + }); +} + +export function transformTemplate( + source: string, + rules: RunnerOptions['rules'] +): { updated: string; changeCount: number } { + const document = parse5.parse(source, { sourceCodeLocationInfo: true }) as unknown as P5Document; + const replacements: Array<{ start: number; end: number; text: string }> = []; + + const hostSelectorSet = new Set(rules.map(rule => rule.hostSelector)); + + const seenOpens = new Set(); + const seenCloses = new Set(); + + function walkHost(root: P5Element, visitFn: (node: P5Node) => void) { + function recursiveWalk(node: P5Node) { + visitFn(node); + const childNodes = (node as any).childNodes as P5Node[] | undefined; + if (!childNodes) { + return; + } + for (const childNode of childNodes) { + if (isElement(childNode) && hostSelectorSet.has((childNode as any).tagName) && childNode !== root) { + continue; + } + recursiveWalk(childNode); + } + } + recursiveWalk(root); + } + + for (const rule of rules) { + const hosts = findElementsByTag(document, rule.hostSelector); + for (const host of hosts) { + if (!(host as any).sourceCodeLocation) { + continue; + } + walkHost(host, (node) => { + if (!isElement(node)) { + return; + } + const oldName: string | undefined = (node as any).tagName; + if (!oldName) { + return; + } + const newName = rule.configMap[oldName]; + if (!newName) { + return; + } + const loc: any = (node as any).sourceCodeLocation; + if (!loc) { + return; + } + if (loc.startTag) { + const openStart = loc.startTag.startOffset + 1; + const openEnd = openStart + oldName.length; + if (!seenOpens.has(openStart)) { + seenOpens.add(openStart); + replacements.push({ start: openStart, end: openEnd, text: newName }); + } + } + if (loc.endTag) { + const endStart = loc.endTag.startOffset + 2; + const endEnd = endStart + oldName.length; + if (!seenCloses.has(endStart)) { + seenCloses.add(endStart); + replacements.push({ start: endStart, end: endEnd, text: newName }); + } + } + }); + } + } + + if (!replacements.length) { + return { updated: source, changeCount: 0 }; + } + replacements.sort((a, b) => b.start - a.start); + let updated = source; + for (const replacement of replacements) { + updated = updated.slice(0, replacement.start) + replacement.text + updated.slice(replacement.end); + } + return { updated, changeCount: replacements.length }; +} + +// Helpers + +function flattenTemplateExpression( + node: any, + source: string +): { placeholderContent: string; placeholders: Array<{ token: string; fullText: string }> } { + const placeholders: Array<{ token: string; fullText: string }> = []; + let content = node.head.text; + node.templateSpans.forEach((span: any, i: number) => { + const token = `__NG_EXPR_PLACEHOLDER_${i}__`; + const fullText = '${' + source.slice(span.expression.getStart(), span.expression.getEnd()) + '}'; + placeholders.push({ token, fullText }); + content += token + span.literal.text; + }); + return { placeholderContent: content, placeholders }; +} + +function escapeBackticks(text: string): string { + // First escape backslashes, then escape backticks + return text.replace(/\\/g, '\\\\').replace(/`/g, '\\`'); +} + +// Utilities + +function isElement(n: P5Node): n is P5Element { + return (n as any).tagName !== undefined; +} + +function walk(node: P5Node, visit: (n: P5Node) => void) { + visit(node); + const childNodes = (node as any).childNodes as P5Node[] | undefined; + if (!childNodes) { + return; + } + for (const childNode of childNodes) { + walk(childNode, visit); + } +} + +function findElementsByTag(doc: P5Document | P5Element, tag: string): P5Element[] { + const result: P5Element[] = []; + walk(doc as unknown as P5Node, (node) => { + if (isElement(node) && node.tagName === tag) { + result.push(node); + } + }); + return result; +} diff --git a/packages/devextreme-schematics/tsconfig.json b/packages/devextreme-schematics/tsconfig.json index 0b296985d..a458abe18 100644 --- a/packages/devextreme-schematics/tsconfig.json +++ b/packages/devextreme-schematics/tsconfig.json @@ -8,6 +8,8 @@ "declaration": true, "module": "commonjs", "moduleResolution": "node", + "esModuleInterop": true, + "resolveJsonModule": true, "noEmitOnError": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": true,