@eui/core 22.0.0-alpha.38 → 22.0.0-alpha.39

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.
@@ -3147,12 +3147,12 @@
3147
3147
  },
3148
3148
  {
3149
3149
  "name": "Schema",
3150
- "id": "interface-Schema-817c4b549cc3eab9fcf4936acab2e71182d90a4480369f5c003cbbda10792efa587ad99d65acf049f64e7030e32589e4fabc4a6d7a5621e4fe54725ef91dc9e8-21",
3151
- "file": "packages/core/schematics/migrate-to-standalone/index.ts",
3150
+ "id": "interface-Schema-cac2ac952d8245647e8a48b450e8f127a36bcffb394cf2cd81fe9c0810ed02c19e5e1629dbf29a68a5c6f675aed99570e9ac04ae470e13315e20c92cc0c6c453-21",
3151
+ "file": "packages/core/schematics/migrate-to-signals/index.ts",
3152
3152
  "deprecated": false,
3153
3153
  "deprecationMessage": "",
3154
3154
  "type": "interface",
3155
- "sourceCode": "import { parseTemplate, TmplAstElement, TmplAstNode } from '@angular/compiler';\nimport { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\n\ninterface ModuleMapping {\n importPath: string;\n selectors: Record<string, string>;\n}\n\nconst MODULE_MAPPINGS: Record<string, ModuleMapping> = {\n EuiAccordionModule: {\n importPath: '@eui/components/eui-accordion',\n selectors: {\n 'eui-accordion': 'EuiAccordionComponent',\n 'eui-accordion-item': 'EuiAccordionItemComponent',\n euiAccordionItemHeader: 'EuiAccordionItemHeaderDirective',\n },\n },\n EuiAlertModule: {\n importPath: '@eui/components/eui-alert',\n selectors: {\n 'eui-alert': 'EuiAlertComponent',\n euiAlert: 'EuiAlertComponent',\n 'eui-alert-title': 'EuiAlertTitleComponent',\n },\n },\n EuiAutocompleteModule: {\n importPath: '@eui/components/eui-autocomplete',\n selectors: {\n 'eui-autocomplete': 'EuiAutocompleteComponent',\n euiAutocomplete: 'EuiAutocompleteComponent',\n 'eui-autocomplete-option': 'EuiAutocompleteOptionComponent',\n 'eui-autocomplete-option-group': 'EuiAutocompleteOptionGroupComponent',\n 'eui-autocomplete-panel': 'EuiAutocompletePanelComponent',\n },\n },\n EuiAvatarModule: {\n importPath: '@eui/components/eui-avatar',\n selectors: {\n 'eui-avatar': 'EuiAvatarComponent',\n euiAvatar: 'EuiAvatarComponent',\n },\n },\n EuiBadgeModule: {\n importPath: '@eui/components/eui-badge',\n selectors: {\n 'eui-badge': 'EuiBadgeComponent',\n euiBadge: 'EuiBadgeComponent',\n },\n },\n EuiBlockContentModule: {\n importPath: '@eui/components/eui-block-content',\n selectors: {\n 'eui-block-content': 'EuiBlockContentComponent',\n },\n },\n EuiBreadcrumbModule: {\n importPath: '@eui/components/eui-breadcrumb',\n selectors: {\n 'eui-breadcrumb': 'EuiBreadcrumbComponent',\n },\n },\n EuiButtonModule: {\n importPath: '@eui/components/eui-button',\n selectors: {\n euiButton: 'EuiButtonComponent',\n },\n },\n EuiButtonGroupModule: {\n importPath: '@eui/components/eui-button-group',\n selectors: {\n 'eui-button-group': 'EuiButtonGroupComponent',\n },\n },\n EuiCardModule: {\n importPath: '@eui/components/eui-card',\n selectors: {\n 'eui-card': 'EuiCardComponent',\n 'eui-card-header': 'EuiCardHeaderComponent',\n 'eui-card-header-title': 'EuiCardHeaderTitleComponent',\n 'eui-card-content': 'EuiCardContentComponent',\n 'eui-card-footer': 'EuiCardFooterComponent',\n 'eui-card-media': 'EuiCardMediaComponent',\n },\n },\n EuiChipModule: {\n importPath: '@eui/components/eui-chip',\n selectors: {\n 'eui-chip': 'EuiChipComponent',\n euiChip: 'EuiChipComponent',\n },\n },\n EuiChipListModule: {\n importPath: '@eui/components/eui-chip-list',\n selectors: {\n 'eui-chip-list': 'EuiChipListComponent',\n },\n },\n EuiChipGroupModule: {\n importPath: '@eui/components/eui-chip-group',\n selectors: {\n 'eui-chip-group': 'EuiChipGroupComponent',\n },\n },\n EuiDashboardCardModule: {\n importPath: '@eui/components/eui-dashboard-card',\n selectors: {\n 'eui-dashboard-card': 'EuiDashboardCardComponent',\n 'eui-dashboard-card-content': 'EuiDashboardCardContentComponent',\n 'eui-dashboard-card-content-header': 'EuiDashboardCardContentHeaderComponent',\n 'eui-dashboard-card-content-body': 'EuiDashboardCardContentBodyComponent',\n 'eui-dashboard-card-content-footer': 'EuiDashboardCardContentFooterComponent',\n },\n },\n EuiDashboardButtonModule: {\n importPath: '@eui/components/eui-dashboard-card',\n selectors: {\n 'eui-dashboard-card': 'EuiDashboardCardComponent',\n 'eui-dashboard-card-content': 'EuiDashboardCardContentComponent',\n 'eui-dashboard-card-content-header': 'EuiDashboardCardContentHeaderComponent',\n 'eui-dashboard-card-content-body': 'EuiDashboardCardContentBodyComponent',\n 'eui-dashboard-card-content-footer': 'EuiDashboardCardContentFooterComponent',\n },\n },\n EuiDatepickerModule: {\n importPath: '@eui/components/eui-datepicker',\n selectors: {\n 'eui-datepicker': 'EuiDatepickerComponent',\n },\n },\n EuiDateRangeSelectorModule: {\n importPath: '@eui/components/eui-date-range-selector',\n selectors: {\n 'eui-date-range-selector': 'EuiDateRangeSelectorComponent',\n },\n },\n EuiDialogModule: {\n importPath: '@eui/components/eui-dialog',\n selectors: {\n 'eui-dialog': 'EuiDialogComponent',\n 'eui-dialog-header': 'EuiDialogHeaderDirective',\n 'eui-dialog-footer': 'EuiDialogFooterDirective',\n 'eui-dialog-container': 'EuiDialogContainerComponent',\n },\n },\n EuiDisableContentModule: {\n importPath: '@eui/components/eui-disable-content',\n selectors: {\n 'eui-disable-content': 'EuiDisableContentComponent',\n },\n },\n EuiDiscussionThreadModule: {\n importPath: '@eui/components/eui-discussion-thread',\n selectors: {\n 'eui-discussion-thread': 'EuiDiscussionThreadComponent',\n 'eui-discussion-thread-item': 'EuiDiscussionThreadItemComponent',\n },\n },\n EuiDropdownModule: {\n importPath: '@eui/components/eui-dropdown',\n selectors: {\n 'eui-dropdown': 'EuiDropdownComponent',\n },\n },\n EuiFeedbackMessageModule: {\n importPath: '@eui/components/eui-feedback-message',\n selectors: {\n 'eui-feedback-message': 'EuiFeedbackMessageComponent',\n },\n },\n EuiFieldsetModule: {\n importPath: '@eui/components/eui-fieldset',\n selectors: {\n 'eui-fieldset': 'EuiFieldsetComponent',\n euiFieldsetLabelRightContent: 'EuiFieldsetLabelRightContentTagDirective',\n euiFieldsetLabelExtraContent: 'EuiFieldsetLabelExtraContentTagDirective',\n },\n },\n EuiFileUploadModule: {\n importPath: '@eui/components/eui-file-upload',\n selectors: {\n 'eui-file-upload': 'EuiFileUploadComponent',\n },\n },\n EuiGrowlModule: {\n importPath: '@eui/components/eui-growl',\n selectors: {\n 'eui-growl': 'EuiGrowlComponent',\n },\n },\n EuiIconModule: {\n importPath: '@eui/components/eui-icon',\n selectors: {\n 'eui-icon-svg': 'EuiIconSvgComponent',\n euiIconSvg: 'EuiIconSvgComponent',\n },\n },\n EuiIconButtonModule: {\n importPath: '@eui/components/eui-icon-button',\n selectors: {\n 'eui-icon-button': 'EuiIconButtonComponent',\n },\n },\n EuiIconToggleModule: {\n importPath: '@eui/components/eui-icon-toggle',\n selectors: {\n 'eui-icon-toggle': 'EuiIconToggleComponent',\n },\n },\n EuiInputCheckboxModule: {\n importPath: '@eui/components/eui-input-checkbox',\n selectors: {\n euiInputCheckBox: 'EuiInputCheckboxComponent',\n },\n },\n EuiInputGroupModule: {\n importPath: '@eui/components/eui-input-group',\n selectors: {\n euiInputGroup: 'EuiInputGroupComponent',\n 'eui-input-group-addon': 'EuiInputGroupAddOnComponent',\n euiInputGroupAddOn: 'EuiInputGroupAddOnComponent',\n 'eui-input-group-addon-item': 'EuiInputGroupAddOnItemComponent',\n euiInputGroupAddOnItem: 'EuiInputGroupAddOnItemComponent',\n },\n },\n EuiInputNumberModule: {\n importPath: '@eui/components/eui-input-number',\n selectors: {\n euiInputNumber: 'EuiInputNumberComponent',\n },\n },\n EuiInputRadioModule: {\n importPath: '@eui/components/eui-input-radio',\n selectors: {\n euiInputRadio: 'EuiInputRadioComponent',\n },\n },\n EuiInputTextModule: {\n importPath: '@eui/components/eui-input-text',\n selectors: {\n euiInputText: 'EuiInputTextComponent',\n },\n },\n EuiLabelModule: {\n importPath: '@eui/components/eui-label',\n selectors: {\n 'eui-label': 'EuiLabelComponent',\n euiLabel: 'EuiLabelComponent',\n },\n },\n EuiListModule: {\n importPath: '@eui/components/eui-list',\n selectors: {\n 'eui-list': 'EuiListComponent',\n euiList: 'EuiListComponent',\n 'eui-list-item': 'EuiListItemComponent',\n euiListItem: 'EuiListItemComponent',\n },\n },\n EuiMenuModule: {\n importPath: '@eui/components/eui-menu',\n selectors: {\n 'eui-menu': 'EuiMenuComponent',\n 'eui-menu-item': 'EuiMenuItemComponent',\n },\n },\n EuiMessageBoxModule: {\n importPath: '@eui/components/eui-message-box',\n selectors: {\n 'eui-message-box': 'EuiMessageBoxComponent',\n 'eui-message-box-footer': 'EuiMessageBoxFooterDirective',\n },\n },\n EuiOverlayModule: {\n importPath: '@eui/components/eui-overlay',\n selectors: {\n 'eui-overlay': 'EuiOverlayComponent',\n },\n },\n EuiPageModule: {\n importPath: '@eui/components/eui-page',\n selectors: {\n 'eui-page': 'EuiPageComponent',\n },\n },\n EuiPaginatorModule: {\n importPath: '@eui/components/eui-paginator',\n selectors: {\n 'eui-paginator': 'EuiPaginatorComponent',\n },\n },\n EuiPopoverModule: {\n importPath: '@eui/components/eui-popover',\n selectors: {\n 'eui-popover': 'EuiPopoverComponent',\n },\n },\n EuiProgressBarModule: {\n importPath: '@eui/components/eui-progress-bar',\n selectors: {\n 'eui-progress-bar': 'EuiProgressBarComponent',\n },\n },\n EuiProgressCircleModule: {\n importPath: '@eui/components/eui-progress-circle',\n selectors: {\n 'eui-progress-circle': 'EuiProgressCircleComponent',\n },\n },\n EuiSelectModule: {\n importPath: '@eui/components/eui-select',\n selectors: {\n euiSelect: 'EuiSelectComponent',\n },\n },\n EuiSidebarMenuModule: {\n importPath: '@eui/components/eui-sidebar-menu',\n selectors: {\n 'eui-sidebar-menu': 'EuiSidebarMenuComponent',\n },\n },\n EuiSkeletonModule: {\n importPath: '@eui/components/eui-skeleton',\n selectors: {\n 'eui-skeleton': 'EuiSkeletonComponent',\n },\n },\n EuiSlideToggleModule: {\n importPath: '@eui/components/eui-slide-toggle',\n selectors: {\n 'eui-slide-toggle': 'EuiSlideToggleComponent',\n },\n },\n EuiTableModule: {\n importPath: '@eui/components/eui-table',\n selectors: {\n 'eui-table': 'EuiTableComponent',\n euiTable: 'EuiTableComponent',\n 'eui-table-filter': 'EuiTableFilterComponent',\n isSortable: 'EuiTableSortableColComponent',\n isStickyCol: 'EuiTableStickyColDirective',\n isHeaderSelectable: 'EuiTableSelectableHeaderComponent',\n isDataSelectable: 'EuiTableSelectableRowComponent',\n isExpandableRow: 'EuiTableExpandableRowDirective',\n },\n },\n EuiTableV2Module: {\n importPath: '@eui/components/eui-table',\n selectors: {\n 'eui-table': 'EuiTableComponent',\n euiTable: 'EuiTableComponent',\n 'eui-table-filter': 'EuiTableFilterComponent',\n isSortable: 'EuiTableSortableColComponent',\n isStickyCol: 'EuiTableStickyColDirective',\n isHeaderSelectable: 'EuiTableSelectableHeaderComponent',\n isDataSelectable: 'EuiTableSelectableRowComponent',\n isExpandableRow: 'EuiTableExpandableRowDirective',\n },\n },\n EuiTabsModule: {\n importPath: '@eui/components/eui-tabs',\n selectors: {\n 'eui-tabs': 'EuiTabsComponent',\n 'eui-tab': 'EuiTabComponent',\n 'eui-tab-header': 'EuiTabHeaderComponent',\n 'eui-tab-body': 'EuiTabBodyComponent',\n },\n },\n EuiTextAreaModule: {\n importPath: '@eui/components/eui-textarea',\n selectors: {\n euiTextArea: 'EuiTextareaComponent',\n },\n },\n EuiTimelineModule: {\n importPath: '@eui/components/eui-timeline',\n selectors: {\n 'eui-timeline': 'EuiTimelineComponent',\n 'eui-timeline-item': 'EuiTimelineItemComponent',\n },\n },\n EuiTimepickerModule: {\n importPath: '@eui/components/eui-timepicker',\n selectors: {\n 'eui-timepicker': 'EuiTimepickerComponent',\n },\n },\n EuiTreeModule: {\n importPath: '@eui/components/eui-tree',\n selectors: {\n 'eui-tree': 'EuiTreeComponent',\n },\n },\n EuiTreeListModule: {\n importPath: '@eui/components/eui-tree-list',\n selectors: {\n 'eui-tree-list': 'EuiTreeListComponent',\n 'eui-tree-list-item': 'EuiTreeListItemComponent',\n },\n },\n EuiUserProfileModule: {\n importPath: '@eui/components/eui-user-profile',\n selectors: {\n 'eui-user-profile': 'EuiUserProfileComponent',\n },\n },\n EuiWizardModule: {\n importPath: '@eui/components/eui-wizard',\n selectors: {\n 'eui-wizard': 'EuiWizardComponent',\n 'eui-wizard-step': 'EuiWizardStepComponent',\n },\n },\n EuiTooltipDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiTooltip: 'EuiTooltipDirective',\n },\n },\n EuiTemplateDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiTemplate: 'EuiTemplateDirective',\n },\n },\n EuiResizableDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiResizable: 'EuiResizableDirective',\n 'eui-resizable': 'EuiResizableComponent',\n },\n },\n EuiMaxLengthDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiEditorMaxlength: 'EuiMaxLengthDirective',\n },\n },\n EuiTruncatePipeModule: {\n importPath: '@eui/components/pipes',\n selectors: {\n euiTruncate: 'EuiTruncatePipe',\n },\n },\n EuiLayoutModule: {\n importPath: '@eui/components/layout',\n selectors: {\n 'eui-app': 'EuiAppComponent',\n 'eui-header': 'EuiHeaderComponent',\n 'eui-footer': 'EuiFooterComponent',\n 'eui-toolbar': 'EuiToolbarComponent',\n 'eui-sidebar-toggle': 'EuiSidebarToggleComponent',\n },\n },\n};\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nexport function migrateToStandalone(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n const allModuleNames = Object.keys(MODULE_MAPPINGS);\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const source = buffer.toString('utf-8');\n if (!allModuleNames.some((m) => source.includes(m))) return;\n\n const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\n const componentDecorators = findComponentDecorators(sourceFile);\n\n for (const decorator of componentDecorators) {\n const importsNode = findImportsArrayNode(decorator);\n if (!importsNode) continue;\n\n const currentSource = tree.read(path)!.toString('utf-8');\n const modulesInArray = allModuleNames.filter((m) => hasModuleInArray(importsNode, m, source));\n if (modulesInArray.length === 0) continue;\n\n const templateSelectors = getTemplateSelectors(tree, path, decorator, source);\n const replacements = buildReplacements(modulesInArray, templateSelectors);\n if (replacements.size === 0) continue;\n\n const result = applyReplacements(currentSource, path, replacements);\n if (options.dryRun) {\n logDryRun(context, `Would replace module imports with standalone imports in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n }\n });\n\n context.logger.info('Migration to standalone imports complete.');\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction visitDir(dir: DirEntry, callback: (path: string) => void): void {\n for (const file of dir.subfiles) {\n if (file.endsWith('.d.ts')) continue;\n if (!file.endsWith('.ts')) continue;\n callback(`${dir.path}/${file}`);\n }\n for (const sub of dir.subdirs) {\n if (sub === 'node_modules' || sub === 'dist') continue;\n visitDir(dir.dir(sub), callback);\n }\n}\n\nfunction buildReplacements(moduleNames: string[], templateSelectors: Set<string>): Map<string, { components: string[]; importPath: string }> {\n const map = new Map<string, { components: string[]; importPath: string }>();\n\n for (const moduleName of moduleNames) {\n const mapping = MODULE_MAPPINGS[moduleName];\n const components: string[] = [];\n\n for (const [selector, component] of Object.entries(mapping.selectors)) {\n if (templateSelectors.has(selector)) {\n components.push(component);\n }\n }\n\n if (components.length > 0) {\n map.set(moduleName, { components: [...new Set(components)].sort(), importPath: mapping.importPath });\n }\n }\n\n return map;\n}\n\nfunction findComponentDecorators(sourceFile: ts.SourceFile): ts.Decorator[] {\n const decorators: ts.Decorator[] = [];\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node)) {\n const decs = ts.getDecorators(node);\n if (decs) {\n for (const dec of decs) {\n if (ts.isCallExpression(dec.expression) && ts.isIdentifier(dec.expression.expression) && dec.expression.expression.text === 'Component') {\n decorators.push(dec);\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n return decorators;\n}\n\nfunction findImportsArrayNode(decorator: ts.Decorator): ts.ArrayLiteralExpression | undefined {\n const call = decorator.expression as ts.CallExpression;\n const metadata = call.arguments[0];\n if (!ts.isObjectLiteralExpression(metadata)) return undefined;\n\n for (const prop of metadata.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'imports') {\n if (ts.isArrayLiteralExpression(prop.initializer)) {\n return prop.initializer;\n }\n }\n }\n return undefined;\n}\n\nfunction hasModuleInArray(array: ts.ArrayLiteralExpression, moduleName: string, source: string): boolean {\n return array.elements.some((el) => source.slice(el.getStart(), el.getEnd()).trim() === moduleName);\n}\n\nfunction getTemplateSelectors(tree: Tree, tsPath: string, decorator: ts.Decorator, source: string): Set<string> {\n const call = decorator.expression as ts.CallExpression;\n const metadata = call.arguments[0] as ts.ObjectLiteralExpression;\n const allSelectors = Object.values(MODULE_MAPPINGS).flatMap((m) => Object.keys(m.selectors));\n\n for (const prop of metadata.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'template') {\n const init = prop.initializer;\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n return findSelectorsInTemplate(init.text, allSelectors);\n }\n }\n }\n\n for (const prop of metadata.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'templateUrl') {\n if (ts.isStringLiteral(prop.initializer)) {\n const dir = tsPath.substring(0, tsPath.lastIndexOf('/'));\n const templateBuffer = tree.read(`${dir}/${prop.initializer.text}`);\n if (templateBuffer) {\n return findSelectorsInTemplate(templateBuffer.toString('utf-8'), allSelectors);\n }\n }\n }\n }\n\n return new Set();\n}\n\nfunction findSelectorsInTemplate(html: string, knownSelectors: string[]): Set<string> {\n const selectors = new Set<string>();\n const parsed = parseTemplate(html, '', { preserveWhitespaces: true });\n\n const visit = (nodes: TmplAstNode[]): void => {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (knownSelectors.includes(node.name)) selectors.add(node.name);\n for (const attr of node.attributes) {\n if (knownSelectors.includes(attr.name)) selectors.add(attr.name);\n }\n visit(node.children);\n }\n }\n };\n visit(parsed.nodes);\n return selectors;\n}\n\nfunction applyReplacements(source: string, filePath: string, replacements: Map<string, { components: string[]; importPath: string }>): string {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n let result = replaceInImportsArray(source, sourceFile, replacements);\n result = updateEsImports(result, filePath, replacements);\n return result;\n}\n\nfunction replaceInImportsArray(source: string, sourceFile: ts.SourceFile, replacements: Map<string, { components: string[]; importPath: string }>): string {\n let result = source;\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node)) {\n const decs = ts.getDecorators(node);\n if (!decs) return;\n for (const dec of decs) {\n if (!ts.isCallExpression(dec.expression) || !ts.isIdentifier(dec.expression.expression) || dec.expression.expression.text !== 'Component') continue;\n const metadata = dec.expression.arguments[0];\n if (!ts.isObjectLiteralExpression(metadata)) continue;\n for (const prop of metadata.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name) || prop.name.text !== 'imports') continue;\n if (!ts.isArrayLiteralExpression(prop.initializer)) continue;\n const newElements = prop.initializer.elements\n .map((el) => {\n const text = result.slice(el.getStart(sourceFile), el.getEnd()).trim();\n const replacement = replacements.get(text);\n return replacement ? replacement.components.join(', ') : text;\n })\n .join(', ');\n result = result.slice(0, prop.initializer.getStart(sourceFile) + 1) + newElements + result.slice(prop.initializer.getEnd() - 1);\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n return result;\n}\n\nfunction updateEsImports(source: string, filePath: string, replacements: Map<string, { components: string[]; importPath: string }>): string {\n let result = source;\n\n for (const [moduleName, { components, importPath }] of replacements) {\n const sf = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n\n for (const stmt of sf.statements) {\n if (!ts.isImportDeclaration(stmt) || !stmt.importClause?.namedBindings || !ts.isNamedImports(stmt.importClause.namedBindings)) continue;\n const namedBindings = stmt.importClause.namedBindings;\n const importNames = namedBindings.elements.map((el) => el.name.text);\n if (!importNames.includes(moduleName)) continue;\n\n const moduleSpecifier = (stmt.moduleSpecifier as ts.StringLiteral).text;\n const remaining = importNames.filter((n) => n !== moduleName);\n const toAdd = components.filter((c) => !importNames.includes(c));\n\n if (moduleSpecifier === importPath) {\n const newNames = [...remaining, ...toAdd].sort();\n const newClause = `{ ${newNames.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n } else {\n if (remaining.length > 0) {\n const newClause = `{ ${remaining.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n } else {\n result = result.slice(0, stmt.getStart(sf)) + result.slice(stmt.getEnd()).replace(/^\\r?\\n/, '');\n }\n\n if (toAdd.length > 0) {\n const updatedSf = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n const existing = updatedSf.statements.find(\n (s) => ts.isImportDeclaration(s) && ts.isStringLiteral(s.moduleSpecifier) && s.moduleSpecifier.text === importPath,\n ) as ts.ImportDeclaration | undefined;\n\n if (existing?.importClause?.namedBindings && ts.isNamedImports(existing.importClause.namedBindings)) {\n const existingNames = existing.importClause.namedBindings.elements.map((el) => el.name.text);\n const allNames = [...new Set([...existingNames, ...toAdd])].sort();\n const newClause = `{ ${allNames.join(', ')} }`;\n result = result.slice(0, existing.importClause.namedBindings.getStart(updatedSf)) + newClause + result.slice(existing.importClause.namedBindings.getEnd());\n } else {\n const newImport = `import { ${toAdd.join(', ')} } from '${importPath}';\\n`;\n result = newImport + result;\n }\n }\n }\n break;\n }\n }\n\n return result;\n}\n",
3155
+ "sourceCode": "import { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport { parseTemplate, TmplAstElement, TmplAstNode } from '@angular/compiler';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\nimport { EUI_SIGNAL_MAP, EUI_SELECTOR_TO_CLASS } from './signal-map';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\n/**\n * Migrates consumer code that accesses EUI component instances programmatically.\n *\n * When EUI migrated @Input() → input(), @ViewChild() → viewChild(), and\n * @ContentChild() → contentChild(), properties that were plain class fields\n * became signal getters. Consumers who access them via @ViewChild need to\n * change `comp.prop` to `comp.prop()`.\n *\n * This schematic:\n * 1. Finds @ViewChild / @ContentChild fields typed as EUI component classes\n * 2. Resolves untyped @ViewChild('refName') by reading the component template\n * and matching #refName to an EUI element tag/selector\n * 3. Tracks which local variable names hold EUI component references (incl. aliases)\n * 4. Rewrites property accesses on those references: `ref.prop` → `ref.prop()`\n * (only for properties listed in the signal map)\n * 5. Does NOT touch template bindings — those are unaffected by signal migrations\n */\nexport function migrateToSignals(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let fileCount = 0;\n let propCount = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts')) return;\n // Skip spec files — test code may use different patterns\n if (path.endsWith('.spec.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n\n // Fast bail: file must mention at least one EUI class name or have\n // ViewChild/ContentChild with string refs (which might reference EUI elements)\n if (!hasEuiReference(original) && !hasStringRefQuery(original)) return;\n\n const result = migrateTypeScript(original, path, tree, context); if (result.source !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate ${result.editCount} signal property access(es) in ${path}`);\n } else {\n tree.overwrite(path, result.source);\n }\n fileCount++;\n propCount += result.editCount;\n }\n });\n\n context.logger.info(`Migrated ${propCount} property access(es) to signal getters in ${fileCount} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\n/** Quick check: does the file reference any EUI class name from the signal map? */\nfunction hasEuiReference(source: string): boolean {\n for (const className of Object.keys(EUI_SIGNAL_MAP)) {\n if (source.includes(className)) return true;\n }\n return false;\n}\n\n/** Quick check: does the file have @ViewChild('...') or @ContentChild('...') with string refs? */\nfunction hasStringRefQuery(source: string): boolean {\n return /(@ViewChild|@ContentChild|@ViewChildren|@ContentChildren)\\s*\\(\\s*['\"]/.test(source);\n}\n\ninterface MigrateResult {\n source: string;\n editCount: number;\n}\n\nfunction migrateTypeScript(source: string, filePath: string, tree: Tree, context: SchematicContext): MigrateResult {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Phase 0: Build template ref map (#refName → EUI class name) from the component's template\n const templateRefMap = buildTemplateRefMap(sourceFile, source, filePath, tree);\n\n // Phase 1: Collect all variables/properties typed as EUI classes\n const euiRefs = collectEuiReferences(sourceFile, source, templateRefMap);\n\n if (euiRefs.size === 0) {\n return { source, editCount: 0 };\n }\n\n // Phase 2: Find property accesses on those references and rewrite signal props\n const visitNode = (node: ts.Node): void => {\n // Match: ref.prop (PropertyAccessExpression)\n if (ts.isPropertyAccessExpression(node)) {\n const rewrite = tryRewritePropertyAccess(node, euiRefs, sourceFile, source);\n if (rewrite) {\n edits.push(rewrite);\n }\n }\n ts.forEachChild(node, visitNode);\n };\n\n ts.forEachChild(sourceFile, visitNode);\n\n if (edits.length === 0) {\n return { source, editCount: 0 };\n }\n\n return {\n source: applyEdits(source, edits),\n editCount: edits.length,\n };\n}\n\n/**\n * Scans the source file for class properties or variables typed as EUI component classes.\n * Returns a map: localName → Set of signal property names.\n *\n * Handles:\n * @ViewChild(EuiXxxComponent) name: EuiXxxComponent;\n * @ViewChild(EuiXxxComponent) name!: EuiXxxComponent;\n * @ViewChild('ref') name: EuiXxxComponent;\n * @ContentChild(EuiXxxComponent) name: EuiXxxComponent;\n * @ViewChild('ref') name: ElementRef; (resolved via template #ref → EUI selector)\n * someVar: EuiXxxComponent; (typed class field, even without decorator)\n * const alias = this.viewChildRef; (alias tracking)\n */\nfunction collectEuiReferences(\n sourceFile: ts.SourceFile,\n source: string,\n templateRefMap: Map<string, string>,\n): Map<string, ReadonlySet<string>> {\n const refs = new Map<string, ReadonlySet<string>>();\n\n // Pass 1: collect directly-typed references\n const visitDirect = (node: ts.Node): void => {\n // Class property declarations\n if (ts.isPropertyDeclaration(node) && node.name && ts.isIdentifier(node.name)) {\n const euiClass = resolveEuiClassName(node, sourceFile, templateRefMap);\n if (euiClass && EUI_SIGNAL_MAP[euiClass]) {\n refs.set(node.name.text, EUI_SIGNAL_MAP[euiClass]);\n }\n }\n\n // Variable declarations (const x: EuiXxxComponent = ...)\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {\n const typeName = getTypeAnnotationName(node.type);\n if (typeName && EUI_SIGNAL_MAP[typeName]) {\n refs.set(node.name.text, EUI_SIGNAL_MAP[typeName]);\n }\n }\n\n // Parameter declarations (method(ref: EuiXxxComponent))\n if (ts.isParameter(node) && ts.isIdentifier(node.name)) {\n const typeName = getTypeAnnotationName(node.type);\n if (typeName && EUI_SIGNAL_MAP[typeName]) {\n refs.set(node.name.text, EUI_SIGNAL_MAP[typeName]);\n }\n }\n\n ts.forEachChild(node, visitDirect);\n };\n\n ts.forEachChild(sourceFile, visitDirect);\n\n // Pass 2: track aliases — variables assigned from already-tracked references\n // e.g. const alias = this.viewChildRef; or const alias = someParam;\n const visitAlias = (node: ts.Node): void => {\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {\n // Skip if already tracked (has explicit type annotation)\n if (refs.has(node.name.text)) {\n ts.forEachChild(node, visitAlias);\n return;\n }\n\n const aliasedRef = resolveRefName(node.initializer);\n if (aliasedRef && refs.has(aliasedRef)) {\n refs.set(node.name.text, refs.get(aliasedRef)!);\n }\n }\n\n ts.forEachChild(node, visitAlias);\n };\n\n ts.forEachChild(sourceFile, visitAlias);\n return refs;\n}\n\n/**\n * Resolves the EUI class name from a property declaration.\n * Checks: type annotation → decorator class argument → template ref map.\n */\nfunction resolveEuiClassName(\n node: ts.PropertyDeclaration,\n sourceFile: ts.SourceFile,\n templateRefMap: Map<string, string>,\n): string | null {\n // Check type annotation first\n const typeName = getTypeAnnotationName(node.type);\n if (typeName && EUI_SIGNAL_MAP[typeName]) {\n return typeName;\n }\n\n // Check generic type argument: ElementRef<EuiXxxComponent>\n if (node.type && ts.isTypeReferenceNode(node.type) && node.type.typeArguments?.length) {\n const genericArg = getTypeAnnotationName(node.type.typeArguments[0]);\n if (genericArg && EUI_SIGNAL_MAP[genericArg]) {\n return genericArg;\n }\n }\n\n // Check decorator arguments: @ViewChild(EuiXxxComponent) or @ViewChild('refName')\n if (node.modifiers) {\n for (const modifier of node.modifiers) {\n if (!ts.isDecorator(modifier)) continue;\n if (!ts.isCallExpression(modifier.expression)) continue;\n\n const decoratorName = getDecoratorName(modifier.expression);\n if (!decoratorName) continue;\n if (!['ViewChild', 'ViewChildren', 'ContentChild', 'ContentChildren'].includes(decoratorName)) continue;\n\n const args = modifier.expression.arguments;\n if (args.length > 0) {\n const firstArg = args[0];\n\n // @ViewChild(EuiXxxComponent) — class reference\n if (ts.isIdentifier(firstArg) && EUI_SIGNAL_MAP[firstArg.text]) {\n return firstArg.text;\n }\n\n // @ViewChild('refName') — string template ref, resolve via template\n if (ts.isStringLiteralLike(firstArg)) {\n const refName = firstArg.text;\n const euiClass = templateRefMap.get(refName);\n if (euiClass && EUI_SIGNAL_MAP[euiClass]) {\n return euiClass;\n }\n }\n }\n }\n }\n\n return null;\n}\n\nfunction getDecoratorName(callExpr: ts.CallExpression): string | null {\n if (ts.isIdentifier(callExpr.expression)) {\n return callExpr.expression.text;\n }\n return null;\n}\n\nfunction getTypeAnnotationName(typeNode: ts.TypeNode | undefined): string | null {\n if (!typeNode) return null;\n if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {\n return typeNode.typeName.text;\n }\n return null;\n}\n\n/**\n * Checks if a property access `ref.prop` should be rewritten to `ref.prop()`.\n *\n * We rewrite if:\n * - `ref` is tracked in euiRefs\n * - `prop` is in the signal set for that EUI class\n * - The access is NOT already a call expression (not `ref.prop()` or `ref.prop(args)`)\n * - The access is NOT a write target (not `ref.prop = value`)\n * - The access is NOT a template binding argument (those are unaffected)\n */\nfunction tryRewritePropertyAccess(\n node: ts.PropertyAccessExpression,\n euiRefs: Map<string, ReadonlySet<string>>,\n sourceFile: ts.SourceFile,\n source: string,\n): Edit | null {\n const propName = node.name.text;\n\n // Resolve the reference name — handle `this.ref.prop` and `ref.prop`\n const refName = resolveRefName(node.expression);\n if (!refName) return null;\n\n const signalProps = euiRefs.get(refName);\n if (!signalProps || !signalProps.has(propName)) return null;\n\n // Skip if parent is already a call expression on this property: ref.prop(...)\n if (ts.isCallExpression(node.parent) && node.parent.expression === node) {\n return null;\n }\n\n // Skip if this is the left side of an assignment: ref.prop = value\n if (ts.isBinaryExpression(node.parent) &&\n node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&\n node.parent.left === node) {\n return null;\n }\n\n // Skip if this is a compound assignment: ref.prop += value, ref.prop &&= value, etc.\n if (ts.isBinaryExpression(node.parent) && isAssignmentOperator(node.parent.operatorToken.kind) && node.parent.left === node) {\n return null;\n }\n\n // Skip if this is used with delete: delete ref.prop\n if (ts.isDeleteExpression(node.parent) && node.parent.expression === node) {\n return null;\n }\n\n // Skip if inside a typeof: typeof ref.prop\n if (ts.isTypeOfExpression(node.parent) && node.parent.expression === node) {\n return null;\n }\n\n // Skip property access chains that go deeper: ref.prop.something → ref.prop().something\n // This IS correct — we still want to add ()\n\n // Rewrite: insert () after the property name\n const end = node.name.getEnd();\n return {\n start: end,\n end: end,\n replacement: '()',\n };\n}\n\nfunction isAssignmentOperator(kind: ts.SyntaxKind): boolean {\n return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;\n}\n\n/**\n * Resolves a reference name from an expression.\n * Handles: `ref`, `this.ref`, `this._ref`\n */\nfunction resolveRefName(expr: ts.Expression): string | null {\n // Direct identifier: ref.prop\n if (ts.isIdentifier(expr)) {\n return expr.text;\n }\n\n // this.ref.prop\n if (ts.isPropertyAccessExpression(expr) && expr.expression.kind === ts.SyntaxKind.ThisKeyword) {\n return expr.name.text;\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Template ref resolution\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a map of template reference variable names (#ref) to EUI class names.\n *\n * Parses the component's template (inline or external) and finds elements like:\n * <eui-alert #myAlert> → myAlert → EuiAlertComponent\n * <input euiAutocomplete #ac> → ac → EuiAutocompleteComponent\n *\n * Returns Map<refName, euiClassName>.\n */\nfunction buildTemplateRefMap(\n sourceFile: ts.SourceFile,\n source: string,\n filePath: string,\n tree: Tree,\n): Map<string, string> {\n const refMap = new Map<string, string>();\n\n // Find @Component decorator\n const componentMeta = findComponentMetadata(sourceFile, source);\n if (!componentMeta) return refMap;\n\n let templateSource: string | null = null;\n\n if (componentMeta.inlineTemplate !== null) {\n templateSource = componentMeta.inlineTemplate;\n } else if (componentMeta.templateUrl) {\n // Resolve templateUrl relative to the TS file\n const dir = filePath.substring(0, filePath.lastIndexOf('/'));\n const templatePath = `${dir}/${componentMeta.templateUrl}`;\n const buffer = tree.read(templatePath);\n if (buffer) {\n templateSource = buffer.toString('utf-8');\n }\n }\n\n if (!templateSource) return refMap;\n\n // Parse the template and collect #refs\n try {\n const parsed = parseTemplate(templateSource, '', { preserveWhitespaces: true });\n collectTemplateRefs(parsed.nodes, refMap);\n } catch {\n // Template parse failure — silently skip (might be malformed or use third-party syntax)\n }\n\n return refMap;\n}\n\n/**\n * Extracts @Component metadata: templateUrl or inline template content.\n */\nfunction findComponentMetadata(\n sourceFile: ts.SourceFile,\n source: string,\n): { templateUrl: string | null; inlineTemplate: string | null } | null {\n let result: { templateUrl: string | null; inlineTemplate: string | null } | null = null;\n\n const visit = (node: ts.Node): void => {\n if (result) return;\n\n if (ts.isDecorator(node) && ts.isCallExpression(node.expression)) {\n const name = getDecoratorName(node.expression);\n if (name !== 'Component') {\n ts.forEachChild(node, visit);\n return;\n }\n\n const args = node.expression.arguments;\n if (args.length === 0 || !ts.isObjectLiteralExpression(args[0])) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const meta: { templateUrl: string | null; inlineTemplate: string | null } = {\n templateUrl: null,\n inlineTemplate: null,\n };\n\n for (const prop of args[0].properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n\n if (prop.name.text === 'templateUrl') {\n const init = unwrapExpression(prop.initializer);\n if (ts.isStringLiteralLike(init)) {\n meta.templateUrl = init.text;\n }\n }\n\n if (prop.name.text === 'template') {\n const init = unwrapExpression(prop.initializer);\n if (ts.isStringLiteralLike(init)) {\n meta.inlineTemplate = init.text;\n } else if (ts.isNoSubstitutionTemplateLiteral(init)) {\n meta.inlineTemplate = init.text;\n }\n }\n }\n\n result = meta;\n return;\n }\n\n ts.forEachChild(node, visit);\n };\n\n ts.forEachChild(sourceFile, visit);\n return result;\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) current = current.expression;\n return current;\n}\n\n/**\n * Recursively walks template AST nodes, collecting #refName → EUI class name mappings.\n *\n * For each element with a template reference (#ref), we try to resolve its EUI class:\n * 1. Match element tag name against EUI_SELECTOR_TO_CLASS (e.g. 'eui-alert' → EuiAlertComponent)\n * 2. Match element attributes against attribute selectors (e.g. [euiAutocomplete] → EuiAutocompleteComponent)\n */\nfunction collectTemplateRefs(nodes: TmplAstNode[], refMap: Map<string, string>): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.references && node.references.length > 0) {\n const euiClass = resolveElementToEuiClass(node);\n if (euiClass) {\n for (const ref of node.references) {\n refMap.set(ref.name, euiClass);\n }\n }\n }\n collectTemplateRefs(node.children, refMap);\n }\n }\n}\n\n/**\n * Given a template element, resolves it to an EUI class name by checking:\n * 1. Tag name: <eui-alert> → look up 'eui-alert' in EUI_SELECTOR_TO_CLASS\n * 2. Attribute selectors: <input euiAutocomplete> → look up 'input[euiAutocomplete]' or '[euiAutocomplete]'\n */\nfunction resolveElementToEuiClass(element: TmplAstElement): string | null {\n const tag = element.name;\n\n // Direct tag match: eui-alert, eui-dialog, etc.\n if (EUI_SELECTOR_TO_CLASS[tag]) {\n return EUI_SELECTOR_TO_CLASS[tag];\n }\n\n // Attribute selector match: check all attributes against known patterns\n const allAttrNames = [\n ...element.attributes.map((a) => a.name),\n ...element.inputs.map((i) => i.name),\n ];\n\n for (const attrName of allAttrNames) {\n // Try tag[attr] pattern first (e.g. 'button[euiButton]', 'input[euiAutocomplete]')\n const tagAttrSelector = `${tag}[${attrName}]`;\n if (EUI_SELECTOR_TO_CLASS[tagAttrSelector]) {\n return EUI_SELECTOR_TO_CLASS[tagAttrSelector];\n }\n\n // Try [attr] pattern (e.g. '[euiTooltip]', '[euiLoading]')\n const attrSelector = `[${attrName}]`;\n if (EUI_SELECTOR_TO_CLASS[attrSelector]) {\n return EUI_SELECTOR_TO_CLASS[attrSelector];\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Edit helpers\n// ---------------------------------------------------------------------------\n\nfunction applyEdits(source: string, edits: Edit[]): string {\n const unique = deduplicateEdits(edits);\n let result = source;\n for (const edit of unique.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, edit.start) + edit.replacement + result.slice(edit.end);\n }\n return result;\n}\n\nfunction deduplicateEdits(edits: Edit[]): Edit[] {\n const seen = new Map<string, Edit>();\n for (const edit of edits) {\n const key = `${edit.start}:${edit.end}`;\n seen.set(key, edit);\n }\n return Array.from(seen.values());\n}\n\nfunction visitDir(dir: DirEntry, callback: (path: string) => void): void {\n for (const file of dir.subfiles) {\n if (file.endsWith('.d.ts')) continue;\n if (!file.endsWith('.ts')) continue;\n callback(`${dir.path}/${file}`);\n }\n for (const sub of dir.subdirs) {\n if (sub === 'node_modules' || sub === 'dist') continue;\n visitDir(dir.dir(sub), callback);\n }\n}\n",
3156
3156
  "displayName": "Schema",
3157
3157
  "properties": [
3158
3158
  {
@@ -3164,7 +3164,7 @@
3164
3164
  "indexKey": "",
3165
3165
  "optional": true,
3166
3166
  "description": "",
3167
- "line": 460,
3167
+ "line": 9,
3168
3168
  "rawdescription": "\n"
3169
3169
  },
3170
3170
  {
@@ -3176,7 +3176,7 @@
3176
3176
  "indexKey": "",
3177
3177
  "optional": true,
3178
3178
  "description": "",
3179
- "line": 459,
3179
+ "line": 8,
3180
3180
  "rawdescription": "\n"
3181
3181
  }
3182
3182
  ],
@@ -3194,12 +3194,12 @@
3194
3194
  },
3195
3195
  {
3196
3196
  "name": "Schema",
3197
- "id": "interface-Schema-cac2ac952d8245647e8a48b450e8f127a36bcffb394cf2cd81fe9c0810ed02c19e5e1629dbf29a68a5c6f675aed99570e9ac04ae470e13315e20c92cc0c6c453-22",
3198
- "file": "packages/core/schematics/migrate-to-signals/index.ts",
3197
+ "id": "interface-Schema-817c4b549cc3eab9fcf4936acab2e71182d90a4480369f5c003cbbda10792efa587ad99d65acf049f64e7030e32589e4fabc4a6d7a5621e4fe54725ef91dc9e8-22",
3198
+ "file": "packages/core/schematics/migrate-to-standalone/index.ts",
3199
3199
  "deprecated": false,
3200
3200
  "deprecationMessage": "",
3201
3201
  "type": "interface",
3202
- "sourceCode": "import { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport { parseTemplate, TmplAstElement, TmplAstNode } from '@angular/compiler';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\nimport { EUI_SIGNAL_MAP, EUI_SELECTOR_TO_CLASS } from './signal-map';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\n/**\n * Migrates consumer code that accesses EUI component instances programmatically.\n *\n * When EUI migrated @Input() → input(), @ViewChild() → viewChild(), and\n * @ContentChild() → contentChild(), properties that were plain class fields\n * became signal getters. Consumers who access them via @ViewChild need to\n * change `comp.prop` to `comp.prop()`.\n *\n * This schematic:\n * 1. Finds @ViewChild / @ContentChild fields typed as EUI component classes\n * 2. Resolves untyped @ViewChild('refName') by reading the component template\n * and matching #refName to an EUI element tag/selector\n * 3. Tracks which local variable names hold EUI component references (incl. aliases)\n * 4. Rewrites property accesses on those references: `ref.prop` → `ref.prop()`\n * (only for properties listed in the signal map)\n * 5. Does NOT touch template bindings — those are unaffected by signal migrations\n */\nexport function migrateToSignals(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let fileCount = 0;\n let propCount = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts')) return;\n // Skip spec files — test code may use different patterns\n if (path.endsWith('.spec.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n\n // Fast bail: file must mention at least one EUI class name or have\n // ViewChild/ContentChild with string refs (which might reference EUI elements)\n if (!hasEuiReference(original) && !hasStringRefQuery(original)) return;\n\n const result = migrateTypeScript(original, path, tree, context); if (result.source !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate ${result.editCount} signal property access(es) in ${path}`);\n } else {\n tree.overwrite(path, result.source);\n }\n fileCount++;\n propCount += result.editCount;\n }\n });\n\n context.logger.info(`Migrated ${propCount} property access(es) to signal getters in ${fileCount} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\n/** Quick check: does the file reference any EUI class name from the signal map? */\nfunction hasEuiReference(source: string): boolean {\n for (const className of Object.keys(EUI_SIGNAL_MAP)) {\n if (source.includes(className)) return true;\n }\n return false;\n}\n\n/** Quick check: does the file have @ViewChild('...') or @ContentChild('...') with string refs? */\nfunction hasStringRefQuery(source: string): boolean {\n return /(@ViewChild|@ContentChild|@ViewChildren|@ContentChildren)\\s*\\(\\s*['\"]/.test(source);\n}\n\ninterface MigrateResult {\n source: string;\n editCount: number;\n}\n\nfunction migrateTypeScript(source: string, filePath: string, tree: Tree, context: SchematicContext): MigrateResult {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Phase 0: Build template ref map (#refName → EUI class name) from the component's template\n const templateRefMap = buildTemplateRefMap(sourceFile, source, filePath, tree);\n\n // Phase 1: Collect all variables/properties typed as EUI classes\n const euiRefs = collectEuiReferences(sourceFile, source, templateRefMap);\n\n if (euiRefs.size === 0) {\n return { source, editCount: 0 };\n }\n\n // Phase 2: Find property accesses on those references and rewrite signal props\n const visitNode = (node: ts.Node): void => {\n // Match: ref.prop (PropertyAccessExpression)\n if (ts.isPropertyAccessExpression(node)) {\n const rewrite = tryRewritePropertyAccess(node, euiRefs, sourceFile, source);\n if (rewrite) {\n edits.push(rewrite);\n }\n }\n ts.forEachChild(node, visitNode);\n };\n\n ts.forEachChild(sourceFile, visitNode);\n\n if (edits.length === 0) {\n return { source, editCount: 0 };\n }\n\n return {\n source: applyEdits(source, edits),\n editCount: edits.length,\n };\n}\n\n/**\n * Scans the source file for class properties or variables typed as EUI component classes.\n * Returns a map: localName → Set of signal property names.\n *\n * Handles:\n * @ViewChild(EuiXxxComponent) name: EuiXxxComponent;\n * @ViewChild(EuiXxxComponent) name!: EuiXxxComponent;\n * @ViewChild('ref') name: EuiXxxComponent;\n * @ContentChild(EuiXxxComponent) name: EuiXxxComponent;\n * @ViewChild('ref') name: ElementRef; (resolved via template #ref → EUI selector)\n * someVar: EuiXxxComponent; (typed class field, even without decorator)\n * const alias = this.viewChildRef; (alias tracking)\n */\nfunction collectEuiReferences(\n sourceFile: ts.SourceFile,\n source: string,\n templateRefMap: Map<string, string>,\n): Map<string, ReadonlySet<string>> {\n const refs = new Map<string, ReadonlySet<string>>();\n\n // Pass 1: collect directly-typed references\n const visitDirect = (node: ts.Node): void => {\n // Class property declarations\n if (ts.isPropertyDeclaration(node) && node.name && ts.isIdentifier(node.name)) {\n const euiClass = resolveEuiClassName(node, sourceFile, templateRefMap);\n if (euiClass && EUI_SIGNAL_MAP[euiClass]) {\n refs.set(node.name.text, EUI_SIGNAL_MAP[euiClass]);\n }\n }\n\n // Variable declarations (const x: EuiXxxComponent = ...)\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {\n const typeName = getTypeAnnotationName(node.type);\n if (typeName && EUI_SIGNAL_MAP[typeName]) {\n refs.set(node.name.text, EUI_SIGNAL_MAP[typeName]);\n }\n }\n\n // Parameter declarations (method(ref: EuiXxxComponent))\n if (ts.isParameter(node) && ts.isIdentifier(node.name)) {\n const typeName = getTypeAnnotationName(node.type);\n if (typeName && EUI_SIGNAL_MAP[typeName]) {\n refs.set(node.name.text, EUI_SIGNAL_MAP[typeName]);\n }\n }\n\n ts.forEachChild(node, visitDirect);\n };\n\n ts.forEachChild(sourceFile, visitDirect);\n\n // Pass 2: track aliases — variables assigned from already-tracked references\n // e.g. const alias = this.viewChildRef; or const alias = someParam;\n const visitAlias = (node: ts.Node): void => {\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {\n // Skip if already tracked (has explicit type annotation)\n if (refs.has(node.name.text)) {\n ts.forEachChild(node, visitAlias);\n return;\n }\n\n const aliasedRef = resolveRefName(node.initializer);\n if (aliasedRef && refs.has(aliasedRef)) {\n refs.set(node.name.text, refs.get(aliasedRef)!);\n }\n }\n\n ts.forEachChild(node, visitAlias);\n };\n\n ts.forEachChild(sourceFile, visitAlias);\n return refs;\n}\n\n/**\n * Resolves the EUI class name from a property declaration.\n * Checks: type annotation → decorator class argument → template ref map.\n */\nfunction resolveEuiClassName(\n node: ts.PropertyDeclaration,\n sourceFile: ts.SourceFile,\n templateRefMap: Map<string, string>,\n): string | null {\n // Check type annotation first\n const typeName = getTypeAnnotationName(node.type);\n if (typeName && EUI_SIGNAL_MAP[typeName]) {\n return typeName;\n }\n\n // Check generic type argument: ElementRef<EuiXxxComponent>\n if (node.type && ts.isTypeReferenceNode(node.type) && node.type.typeArguments?.length) {\n const genericArg = getTypeAnnotationName(node.type.typeArguments[0]);\n if (genericArg && EUI_SIGNAL_MAP[genericArg]) {\n return genericArg;\n }\n }\n\n // Check decorator arguments: @ViewChild(EuiXxxComponent) or @ViewChild('refName')\n if (node.modifiers) {\n for (const modifier of node.modifiers) {\n if (!ts.isDecorator(modifier)) continue;\n if (!ts.isCallExpression(modifier.expression)) continue;\n\n const decoratorName = getDecoratorName(modifier.expression);\n if (!decoratorName) continue;\n if (!['ViewChild', 'ViewChildren', 'ContentChild', 'ContentChildren'].includes(decoratorName)) continue;\n\n const args = modifier.expression.arguments;\n if (args.length > 0) {\n const firstArg = args[0];\n\n // @ViewChild(EuiXxxComponent) — class reference\n if (ts.isIdentifier(firstArg) && EUI_SIGNAL_MAP[firstArg.text]) {\n return firstArg.text;\n }\n\n // @ViewChild('refName') — string template ref, resolve via template\n if (ts.isStringLiteralLike(firstArg)) {\n const refName = firstArg.text;\n const euiClass = templateRefMap.get(refName);\n if (euiClass && EUI_SIGNAL_MAP[euiClass]) {\n return euiClass;\n }\n }\n }\n }\n }\n\n return null;\n}\n\nfunction getDecoratorName(callExpr: ts.CallExpression): string | null {\n if (ts.isIdentifier(callExpr.expression)) {\n return callExpr.expression.text;\n }\n return null;\n}\n\nfunction getTypeAnnotationName(typeNode: ts.TypeNode | undefined): string | null {\n if (!typeNode) return null;\n if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {\n return typeNode.typeName.text;\n }\n return null;\n}\n\n/**\n * Checks if a property access `ref.prop` should be rewritten to `ref.prop()`.\n *\n * We rewrite if:\n * - `ref` is tracked in euiRefs\n * - `prop` is in the signal set for that EUI class\n * - The access is NOT already a call expression (not `ref.prop()` or `ref.prop(args)`)\n * - The access is NOT a write target (not `ref.prop = value`)\n * - The access is NOT a template binding argument (those are unaffected)\n */\nfunction tryRewritePropertyAccess(\n node: ts.PropertyAccessExpression,\n euiRefs: Map<string, ReadonlySet<string>>,\n sourceFile: ts.SourceFile,\n source: string,\n): Edit | null {\n const propName = node.name.text;\n\n // Resolve the reference name — handle `this.ref.prop` and `ref.prop`\n const refName = resolveRefName(node.expression);\n if (!refName) return null;\n\n const signalProps = euiRefs.get(refName);\n if (!signalProps || !signalProps.has(propName)) return null;\n\n // Skip if parent is already a call expression on this property: ref.prop(...)\n if (ts.isCallExpression(node.parent) && node.parent.expression === node) {\n return null;\n }\n\n // Skip if this is the left side of an assignment: ref.prop = value\n if (ts.isBinaryExpression(node.parent) &&\n node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&\n node.parent.left === node) {\n return null;\n }\n\n // Skip if this is a compound assignment: ref.prop += value, ref.prop &&= value, etc.\n if (ts.isBinaryExpression(node.parent) && isAssignmentOperator(node.parent.operatorToken.kind) && node.parent.left === node) {\n return null;\n }\n\n // Skip if this is used with delete: delete ref.prop\n if (ts.isDeleteExpression(node.parent) && node.parent.expression === node) {\n return null;\n }\n\n // Skip if inside a typeof: typeof ref.prop\n if (ts.isTypeOfExpression(node.parent) && node.parent.expression === node) {\n return null;\n }\n\n // Skip property access chains that go deeper: ref.prop.something → ref.prop().something\n // This IS correct — we still want to add ()\n\n // Rewrite: insert () after the property name\n const end = node.name.getEnd();\n return {\n start: end,\n end: end,\n replacement: '()',\n };\n}\n\nfunction isAssignmentOperator(kind: ts.SyntaxKind): boolean {\n return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;\n}\n\n/**\n * Resolves a reference name from an expression.\n * Handles: `ref`, `this.ref`, `this._ref`\n */\nfunction resolveRefName(expr: ts.Expression): string | null {\n // Direct identifier: ref.prop\n if (ts.isIdentifier(expr)) {\n return expr.text;\n }\n\n // this.ref.prop\n if (ts.isPropertyAccessExpression(expr) && expr.expression.kind === ts.SyntaxKind.ThisKeyword) {\n return expr.name.text;\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Template ref resolution\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a map of template reference variable names (#ref) to EUI class names.\n *\n * Parses the component's template (inline or external) and finds elements like:\n * <eui-alert #myAlert> → myAlert → EuiAlertComponent\n * <input euiAutocomplete #ac> → ac → EuiAutocompleteComponent\n *\n * Returns Map<refName, euiClassName>.\n */\nfunction buildTemplateRefMap(\n sourceFile: ts.SourceFile,\n source: string,\n filePath: string,\n tree: Tree,\n): Map<string, string> {\n const refMap = new Map<string, string>();\n\n // Find @Component decorator\n const componentMeta = findComponentMetadata(sourceFile, source);\n if (!componentMeta) return refMap;\n\n let templateSource: string | null = null;\n\n if (componentMeta.inlineTemplate !== null) {\n templateSource = componentMeta.inlineTemplate;\n } else if (componentMeta.templateUrl) {\n // Resolve templateUrl relative to the TS file\n const dir = filePath.substring(0, filePath.lastIndexOf('/'));\n const templatePath = `${dir}/${componentMeta.templateUrl}`;\n const buffer = tree.read(templatePath);\n if (buffer) {\n templateSource = buffer.toString('utf-8');\n }\n }\n\n if (!templateSource) return refMap;\n\n // Parse the template and collect #refs\n try {\n const parsed = parseTemplate(templateSource, '', { preserveWhitespaces: true });\n collectTemplateRefs(parsed.nodes, refMap);\n } catch {\n // Template parse failure — silently skip (might be malformed or use third-party syntax)\n }\n\n return refMap;\n}\n\n/**\n * Extracts @Component metadata: templateUrl or inline template content.\n */\nfunction findComponentMetadata(\n sourceFile: ts.SourceFile,\n source: string,\n): { templateUrl: string | null; inlineTemplate: string | null } | null {\n let result: { templateUrl: string | null; inlineTemplate: string | null } | null = null;\n\n const visit = (node: ts.Node): void => {\n if (result) return;\n\n if (ts.isDecorator(node) && ts.isCallExpression(node.expression)) {\n const name = getDecoratorName(node.expression);\n if (name !== 'Component') {\n ts.forEachChild(node, visit);\n return;\n }\n\n const args = node.expression.arguments;\n if (args.length === 0 || !ts.isObjectLiteralExpression(args[0])) {\n ts.forEachChild(node, visit);\n return;\n }\n\n const meta: { templateUrl: string | null; inlineTemplate: string | null } = {\n templateUrl: null,\n inlineTemplate: null,\n };\n\n for (const prop of args[0].properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n\n if (prop.name.text === 'templateUrl') {\n const init = unwrapExpression(prop.initializer);\n if (ts.isStringLiteralLike(init)) {\n meta.templateUrl = init.text;\n }\n }\n\n if (prop.name.text === 'template') {\n const init = unwrapExpression(prop.initializer);\n if (ts.isStringLiteralLike(init)) {\n meta.inlineTemplate = init.text;\n } else if (ts.isNoSubstitutionTemplateLiteral(init)) {\n meta.inlineTemplate = init.text;\n }\n }\n }\n\n result = meta;\n return;\n }\n\n ts.forEachChild(node, visit);\n };\n\n ts.forEachChild(sourceFile, visit);\n return result;\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) current = current.expression;\n return current;\n}\n\n/**\n * Recursively walks template AST nodes, collecting #refName → EUI class name mappings.\n *\n * For each element with a template reference (#ref), we try to resolve its EUI class:\n * 1. Match element tag name against EUI_SELECTOR_TO_CLASS (e.g. 'eui-alert' → EuiAlertComponent)\n * 2. Match element attributes against attribute selectors (e.g. [euiAutocomplete] → EuiAutocompleteComponent)\n */\nfunction collectTemplateRefs(nodes: TmplAstNode[], refMap: Map<string, string>): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.references && node.references.length > 0) {\n const euiClass = resolveElementToEuiClass(node);\n if (euiClass) {\n for (const ref of node.references) {\n refMap.set(ref.name, euiClass);\n }\n }\n }\n collectTemplateRefs(node.children, refMap);\n }\n }\n}\n\n/**\n * Given a template element, resolves it to an EUI class name by checking:\n * 1. Tag name: <eui-alert> → look up 'eui-alert' in EUI_SELECTOR_TO_CLASS\n * 2. Attribute selectors: <input euiAutocomplete> → look up 'input[euiAutocomplete]' or '[euiAutocomplete]'\n */\nfunction resolveElementToEuiClass(element: TmplAstElement): string | null {\n const tag = element.name;\n\n // Direct tag match: eui-alert, eui-dialog, etc.\n if (EUI_SELECTOR_TO_CLASS[tag]) {\n return EUI_SELECTOR_TO_CLASS[tag];\n }\n\n // Attribute selector match: check all attributes against known patterns\n const allAttrNames = [\n ...element.attributes.map((a) => a.name),\n ...element.inputs.map((i) => i.name),\n ];\n\n for (const attrName of allAttrNames) {\n // Try tag[attr] pattern first (e.g. 'button[euiButton]', 'input[euiAutocomplete]')\n const tagAttrSelector = `${tag}[${attrName}]`;\n if (EUI_SELECTOR_TO_CLASS[tagAttrSelector]) {\n return EUI_SELECTOR_TO_CLASS[tagAttrSelector];\n }\n\n // Try [attr] pattern (e.g. '[euiTooltip]', '[euiLoading]')\n const attrSelector = `[${attrName}]`;\n if (EUI_SELECTOR_TO_CLASS[attrSelector]) {\n return EUI_SELECTOR_TO_CLASS[attrSelector];\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Edit helpers\n// ---------------------------------------------------------------------------\n\nfunction applyEdits(source: string, edits: Edit[]): string {\n const unique = deduplicateEdits(edits);\n let result = source;\n for (const edit of unique.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, edit.start) + edit.replacement + result.slice(edit.end);\n }\n return result;\n}\n\nfunction deduplicateEdits(edits: Edit[]): Edit[] {\n const seen = new Map<string, Edit>();\n for (const edit of edits) {\n const key = `${edit.start}:${edit.end}`;\n seen.set(key, edit);\n }\n return Array.from(seen.values());\n}\n\nfunction visitDir(dir: DirEntry, callback: (path: string) => void): void {\n for (const file of dir.subfiles) {\n if (file.endsWith('.d.ts')) continue;\n if (!file.endsWith('.ts')) continue;\n callback(`${dir.path}/${file}`);\n }\n for (const sub of dir.subdirs) {\n if (sub === 'node_modules' || sub === 'dist') continue;\n visitDir(dir.dir(sub), callback);\n }\n}\n",
3202
+ "sourceCode": "import { parseTemplate, TmplAstElement, TmplAstNode } from '@angular/compiler';\nimport { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\n\ninterface ModuleMapping {\n importPath: string;\n selectors: Record<string, string>;\n}\n\nconst MODULE_MAPPINGS: Record<string, ModuleMapping> = {\n EuiAccordionModule: {\n importPath: '@eui/components/eui-accordion',\n selectors: {\n 'eui-accordion': 'EuiAccordionComponent',\n 'eui-accordion-item': 'EuiAccordionItemComponent',\n euiAccordionItemHeader: 'EuiAccordionItemHeaderDirective',\n },\n },\n EuiAlertModule: {\n importPath: '@eui/components/eui-alert',\n selectors: {\n 'eui-alert': 'EuiAlertComponent',\n euiAlert: 'EuiAlertComponent',\n 'eui-alert-title': 'EuiAlertTitleComponent',\n },\n },\n EuiAutocompleteModule: {\n importPath: '@eui/components/eui-autocomplete',\n selectors: {\n 'eui-autocomplete': 'EuiAutocompleteComponent',\n euiAutocomplete: 'EuiAutocompleteComponent',\n 'eui-autocomplete-option': 'EuiAutocompleteOptionComponent',\n 'eui-autocomplete-option-group': 'EuiAutocompleteOptionGroupComponent',\n 'eui-autocomplete-panel': 'EuiAutocompletePanelComponent',\n },\n },\n EuiAvatarModule: {\n importPath: '@eui/components/eui-avatar',\n selectors: {\n 'eui-avatar': 'EuiAvatarComponent',\n euiAvatar: 'EuiAvatarComponent',\n },\n },\n EuiBadgeModule: {\n importPath: '@eui/components/eui-badge',\n selectors: {\n 'eui-badge': 'EuiBadgeComponent',\n euiBadge: 'EuiBadgeComponent',\n },\n },\n EuiBlockContentModule: {\n importPath: '@eui/components/eui-block-content',\n selectors: {\n 'eui-block-content': 'EuiBlockContentComponent',\n },\n },\n EuiBreadcrumbModule: {\n importPath: '@eui/components/eui-breadcrumb',\n selectors: {\n 'eui-breadcrumb': 'EuiBreadcrumbComponent',\n },\n },\n EuiButtonModule: {\n importPath: '@eui/components/eui-button',\n selectors: {\n euiButton: 'EuiButtonComponent',\n },\n },\n EuiButtonGroupModule: {\n importPath: '@eui/components/eui-button-group',\n selectors: {\n 'eui-button-group': 'EuiButtonGroupComponent',\n },\n },\n EuiCardModule: {\n importPath: '@eui/components/eui-card',\n selectors: {\n 'eui-card': 'EuiCardComponent',\n 'eui-card-header': 'EuiCardHeaderComponent',\n 'eui-card-header-title': 'EuiCardHeaderTitleComponent',\n 'eui-card-content': 'EuiCardContentComponent',\n 'eui-card-footer': 'EuiCardFooterComponent',\n 'eui-card-media': 'EuiCardMediaComponent',\n },\n },\n EuiChipModule: {\n importPath: '@eui/components/eui-chip',\n selectors: {\n 'eui-chip': 'EuiChipComponent',\n euiChip: 'EuiChipComponent',\n },\n },\n EuiChipListModule: {\n importPath: '@eui/components/eui-chip-list',\n selectors: {\n 'eui-chip-list': 'EuiChipListComponent',\n },\n },\n EuiChipGroupModule: {\n importPath: '@eui/components/eui-chip-group',\n selectors: {\n 'eui-chip-group': 'EuiChipGroupComponent',\n },\n },\n EuiDashboardCardModule: {\n importPath: '@eui/components/eui-dashboard-card',\n selectors: {\n 'eui-dashboard-card': 'EuiDashboardCardComponent',\n 'eui-dashboard-card-content': 'EuiDashboardCardContentComponent',\n 'eui-dashboard-card-content-header': 'EuiDashboardCardContentHeaderComponent',\n 'eui-dashboard-card-content-body': 'EuiDashboardCardContentBodyComponent',\n 'eui-dashboard-card-content-footer': 'EuiDashboardCardContentFooterComponent',\n },\n },\n EuiDashboardButtonModule: {\n importPath: '@eui/components/eui-dashboard-card',\n selectors: {\n 'eui-dashboard-card': 'EuiDashboardCardComponent',\n 'eui-dashboard-card-content': 'EuiDashboardCardContentComponent',\n 'eui-dashboard-card-content-header': 'EuiDashboardCardContentHeaderComponent',\n 'eui-dashboard-card-content-body': 'EuiDashboardCardContentBodyComponent',\n 'eui-dashboard-card-content-footer': 'EuiDashboardCardContentFooterComponent',\n },\n },\n EuiDatepickerModule: {\n importPath: '@eui/components/eui-datepicker',\n selectors: {\n 'eui-datepicker': 'EuiDatepickerComponent',\n },\n },\n EuiDateRangeSelectorModule: {\n importPath: '@eui/components/eui-date-range-selector',\n selectors: {\n 'eui-date-range-selector': 'EuiDateRangeSelectorComponent',\n },\n },\n EuiDialogModule: {\n importPath: '@eui/components/eui-dialog',\n selectors: {\n 'eui-dialog': 'EuiDialogComponent',\n 'eui-dialog-header': 'EuiDialogHeaderDirective',\n 'eui-dialog-footer': 'EuiDialogFooterDirective',\n 'eui-dialog-container': 'EuiDialogContainerComponent',\n },\n },\n EuiDisableContentModule: {\n importPath: '@eui/components/eui-disable-content',\n selectors: {\n 'eui-disable-content': 'EuiDisableContentComponent',\n },\n },\n EuiDiscussionThreadModule: {\n importPath: '@eui/components/eui-discussion-thread',\n selectors: {\n 'eui-discussion-thread': 'EuiDiscussionThreadComponent',\n 'eui-discussion-thread-item': 'EuiDiscussionThreadItemComponent',\n },\n },\n EuiDropdownModule: {\n importPath: '@eui/components/eui-dropdown',\n selectors: {\n 'eui-dropdown': 'EuiDropdownComponent',\n },\n },\n EuiFeedbackMessageModule: {\n importPath: '@eui/components/eui-feedback-message',\n selectors: {\n 'eui-feedback-message': 'EuiFeedbackMessageComponent',\n },\n },\n EuiFieldsetModule: {\n importPath: '@eui/components/eui-fieldset',\n selectors: {\n 'eui-fieldset': 'EuiFieldsetComponent',\n euiFieldsetLabelRightContent: 'EuiFieldsetLabelRightContentTagDirective',\n euiFieldsetLabelExtraContent: 'EuiFieldsetLabelExtraContentTagDirective',\n },\n },\n EuiFileUploadModule: {\n importPath: '@eui/components/eui-file-upload',\n selectors: {\n 'eui-file-upload': 'EuiFileUploadComponent',\n },\n },\n EuiGrowlModule: {\n importPath: '@eui/components/eui-growl',\n selectors: {\n 'eui-growl': 'EuiGrowlComponent',\n },\n },\n EuiIconModule: {\n importPath: '@eui/components/eui-icon',\n selectors: {\n 'eui-icon-svg': 'EuiIconSvgComponent',\n euiIconSvg: 'EuiIconSvgComponent',\n },\n },\n EuiIconButtonModule: {\n importPath: '@eui/components/eui-icon-button',\n selectors: {\n 'eui-icon-button': 'EuiIconButtonComponent',\n },\n },\n EuiIconToggleModule: {\n importPath: '@eui/components/eui-icon-toggle',\n selectors: {\n 'eui-icon-toggle': 'EuiIconToggleComponent',\n },\n },\n EuiInputCheckboxModule: {\n importPath: '@eui/components/eui-input-checkbox',\n selectors: {\n euiInputCheckBox: 'EuiInputCheckboxComponent',\n },\n },\n EuiInputGroupModule: {\n importPath: '@eui/components/eui-input-group',\n selectors: {\n euiInputGroup: 'EuiInputGroupComponent',\n 'eui-input-group-addon': 'EuiInputGroupAddOnComponent',\n euiInputGroupAddOn: 'EuiInputGroupAddOnComponent',\n 'eui-input-group-addon-item': 'EuiInputGroupAddOnItemComponent',\n euiInputGroupAddOnItem: 'EuiInputGroupAddOnItemComponent',\n },\n },\n EuiInputNumberModule: {\n importPath: '@eui/components/eui-input-number',\n selectors: {\n euiInputNumber: 'EuiInputNumberComponent',\n },\n },\n EuiInputRadioModule: {\n importPath: '@eui/components/eui-input-radio',\n selectors: {\n euiInputRadio: 'EuiInputRadioComponent',\n },\n },\n EuiInputTextModule: {\n importPath: '@eui/components/eui-input-text',\n selectors: {\n euiInputText: 'EuiInputTextComponent',\n },\n },\n EuiLabelModule: {\n importPath: '@eui/components/eui-label',\n selectors: {\n 'eui-label': 'EuiLabelComponent',\n euiLabel: 'EuiLabelComponent',\n },\n },\n EuiListModule: {\n importPath: '@eui/components/eui-list',\n selectors: {\n 'eui-list': 'EuiListComponent',\n euiList: 'EuiListComponent',\n 'eui-list-item': 'EuiListItemComponent',\n euiListItem: 'EuiListItemComponent',\n },\n },\n EuiMenuModule: {\n importPath: '@eui/components/eui-menu',\n selectors: {\n 'eui-menu': 'EuiMenuComponent',\n 'eui-menu-item': 'EuiMenuItemComponent',\n },\n },\n EuiMessageBoxModule: {\n importPath: '@eui/components/eui-message-box',\n selectors: {\n 'eui-message-box': 'EuiMessageBoxComponent',\n 'eui-message-box-footer': 'EuiMessageBoxFooterDirective',\n },\n },\n EuiOverlayModule: {\n importPath: '@eui/components/eui-overlay',\n selectors: {\n 'eui-overlay': 'EuiOverlayComponent',\n },\n },\n EuiPageModule: {\n importPath: '@eui/components/eui-page',\n selectors: {\n 'eui-page': 'EuiPageComponent',\n },\n },\n EuiPaginatorModule: {\n importPath: '@eui/components/eui-paginator',\n selectors: {\n 'eui-paginator': 'EuiPaginatorComponent',\n },\n },\n EuiPopoverModule: {\n importPath: '@eui/components/eui-popover',\n selectors: {\n 'eui-popover': 'EuiPopoverComponent',\n },\n },\n EuiProgressBarModule: {\n importPath: '@eui/components/eui-progress-bar',\n selectors: {\n 'eui-progress-bar': 'EuiProgressBarComponent',\n },\n },\n EuiProgressCircleModule: {\n importPath: '@eui/components/eui-progress-circle',\n selectors: {\n 'eui-progress-circle': 'EuiProgressCircleComponent',\n },\n },\n EuiSelectModule: {\n importPath: '@eui/components/eui-select',\n selectors: {\n euiSelect: 'EuiSelectComponent',\n },\n },\n EuiSidebarMenuModule: {\n importPath: '@eui/components/eui-sidebar-menu',\n selectors: {\n 'eui-sidebar-menu': 'EuiSidebarMenuComponent',\n },\n },\n EuiSkeletonModule: {\n importPath: '@eui/components/eui-skeleton',\n selectors: {\n 'eui-skeleton': 'EuiSkeletonComponent',\n },\n },\n EuiSlideToggleModule: {\n importPath: '@eui/components/eui-slide-toggle',\n selectors: {\n 'eui-slide-toggle': 'EuiSlideToggleComponent',\n },\n },\n EuiTableModule: {\n importPath: '@eui/components/eui-table',\n selectors: {\n 'eui-table': 'EuiTableComponent',\n euiTable: 'EuiTableComponent',\n 'eui-table-filter': 'EuiTableFilterComponent',\n isSortable: 'EuiTableSortableColComponent',\n isStickyCol: 'EuiTableStickyColDirective',\n isHeaderSelectable: 'EuiTableSelectableHeaderComponent',\n isDataSelectable: 'EuiTableSelectableRowComponent',\n isExpandableRow: 'EuiTableExpandableRowDirective',\n },\n },\n EuiTableV2Module: {\n importPath: '@eui/components/eui-table',\n selectors: {\n 'eui-table': 'EuiTableComponent',\n euiTable: 'EuiTableComponent',\n 'eui-table-filter': 'EuiTableFilterComponent',\n isSortable: 'EuiTableSortableColComponent',\n isStickyCol: 'EuiTableStickyColDirective',\n isHeaderSelectable: 'EuiTableSelectableHeaderComponent',\n isDataSelectable: 'EuiTableSelectableRowComponent',\n isExpandableRow: 'EuiTableExpandableRowDirective',\n },\n },\n EuiTabsModule: {\n importPath: '@eui/components/eui-tabs',\n selectors: {\n 'eui-tabs': 'EuiTabsComponent',\n 'eui-tab': 'EuiTabComponent',\n 'eui-tab-header': 'EuiTabHeaderComponent',\n 'eui-tab-body': 'EuiTabBodyComponent',\n },\n },\n EuiTextAreaModule: {\n importPath: '@eui/components/eui-textarea',\n selectors: {\n euiTextArea: 'EuiTextareaComponent',\n },\n },\n EuiTimelineModule: {\n importPath: '@eui/components/eui-timeline',\n selectors: {\n 'eui-timeline': 'EuiTimelineComponent',\n 'eui-timeline-item': 'EuiTimelineItemComponent',\n },\n },\n EuiTimepickerModule: {\n importPath: '@eui/components/eui-timepicker',\n selectors: {\n 'eui-timepicker': 'EuiTimepickerComponent',\n },\n },\n EuiTreeModule: {\n importPath: '@eui/components/eui-tree',\n selectors: {\n 'eui-tree': 'EuiTreeComponent',\n },\n },\n EuiTreeListModule: {\n importPath: '@eui/components/eui-tree-list',\n selectors: {\n 'eui-tree-list': 'EuiTreeListComponent',\n 'eui-tree-list-item': 'EuiTreeListItemComponent',\n },\n },\n EuiUserProfileModule: {\n importPath: '@eui/components/eui-user-profile',\n selectors: {\n 'eui-user-profile': 'EuiUserProfileComponent',\n },\n },\n EuiWizardModule: {\n importPath: '@eui/components/eui-wizard',\n selectors: {\n 'eui-wizard': 'EuiWizardComponent',\n 'eui-wizard-step': 'EuiWizardStepComponent',\n },\n },\n EuiTooltipDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiTooltip: 'EuiTooltipDirective',\n },\n },\n EuiTemplateDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiTemplate: 'EuiTemplateDirective',\n },\n },\n EuiResizableDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiResizable: 'EuiResizableDirective',\n 'eui-resizable': 'EuiResizableComponent',\n },\n },\n EuiMaxLengthDirectiveModule: {\n importPath: '@eui/components/directives',\n selectors: {\n euiEditorMaxlength: 'EuiMaxLengthDirective',\n },\n },\n EuiTruncatePipeModule: {\n importPath: '@eui/components/pipes',\n selectors: {\n euiTruncate: 'EuiTruncatePipe',\n },\n },\n EuiLayoutModule: {\n importPath: '@eui/components/layout',\n selectors: {\n 'eui-app': 'EuiAppComponent',\n 'eui-header': 'EuiHeaderComponent',\n 'eui-footer': 'EuiFooterComponent',\n 'eui-toolbar': 'EuiToolbarComponent',\n 'eui-sidebar-toggle': 'EuiSidebarToggleComponent',\n },\n },\n};\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nexport function migrateToStandalone(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n const allModuleNames = Object.keys(MODULE_MAPPINGS);\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const source = buffer.toString('utf-8');\n if (!allModuleNames.some((m) => source.includes(m))) return;\n\n const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\n const componentDecorators = findComponentDecorators(sourceFile);\n\n for (const decorator of componentDecorators) {\n const importsNode = findImportsArrayNode(decorator);\n if (!importsNode) continue;\n\n const currentSource = tree.read(path)!.toString('utf-8');\n const modulesInArray = allModuleNames.filter((m) => hasModuleInArray(importsNode, m, source));\n if (modulesInArray.length === 0) continue;\n\n const templateSelectors = getTemplateSelectors(tree, path, decorator, source);\n const replacements = buildReplacements(modulesInArray, templateSelectors);\n if (replacements.size === 0) continue;\n\n const result = applyReplacements(currentSource, path, replacements);\n if (options.dryRun) {\n logDryRun(context, `Would replace module imports with standalone imports in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n }\n });\n\n context.logger.info('Migration to standalone imports complete.');\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction visitDir(dir: DirEntry, callback: (path: string) => void): void {\n for (const file of dir.subfiles) {\n if (file.endsWith('.d.ts')) continue;\n if (!file.endsWith('.ts')) continue;\n callback(`${dir.path}/${file}`);\n }\n for (const sub of dir.subdirs) {\n if (sub === 'node_modules' || sub === 'dist') continue;\n visitDir(dir.dir(sub), callback);\n }\n}\n\nfunction buildReplacements(moduleNames: string[], templateSelectors: Set<string>): Map<string, { components: string[]; importPath: string }> {\n const map = new Map<string, { components: string[]; importPath: string }>();\n\n for (const moduleName of moduleNames) {\n const mapping = MODULE_MAPPINGS[moduleName];\n const components: string[] = [];\n\n for (const [selector, component] of Object.entries(mapping.selectors)) {\n if (templateSelectors.has(selector)) {\n components.push(component);\n }\n }\n\n if (components.length > 0) {\n map.set(moduleName, { components: [...new Set(components)].sort(), importPath: mapping.importPath });\n }\n }\n\n return map;\n}\n\nfunction findComponentDecorators(sourceFile: ts.SourceFile): ts.Decorator[] {\n const decorators: ts.Decorator[] = [];\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node)) {\n const decs = ts.getDecorators(node);\n if (decs) {\n for (const dec of decs) {\n if (ts.isCallExpression(dec.expression) && ts.isIdentifier(dec.expression.expression) && dec.expression.expression.text === 'Component') {\n decorators.push(dec);\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n return decorators;\n}\n\nfunction findImportsArrayNode(decorator: ts.Decorator): ts.ArrayLiteralExpression | undefined {\n const call = decorator.expression as ts.CallExpression;\n const metadata = call.arguments[0];\n if (!ts.isObjectLiteralExpression(metadata)) return undefined;\n\n for (const prop of metadata.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'imports') {\n if (ts.isArrayLiteralExpression(prop.initializer)) {\n return prop.initializer;\n }\n }\n }\n return undefined;\n}\n\nfunction hasModuleInArray(array: ts.ArrayLiteralExpression, moduleName: string, source: string): boolean {\n return array.elements.some((el) => source.slice(el.getStart(), el.getEnd()).trim() === moduleName);\n}\n\nfunction getTemplateSelectors(tree: Tree, tsPath: string, decorator: ts.Decorator, source: string): Set<string> {\n const call = decorator.expression as ts.CallExpression;\n const metadata = call.arguments[0] as ts.ObjectLiteralExpression;\n const allSelectors = Object.values(MODULE_MAPPINGS).flatMap((m) => Object.keys(m.selectors));\n\n for (const prop of metadata.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'template') {\n const init = prop.initializer;\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n return findSelectorsInTemplate(init.text, allSelectors);\n }\n }\n }\n\n for (const prop of metadata.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'templateUrl') {\n if (ts.isStringLiteral(prop.initializer)) {\n const dir = tsPath.substring(0, tsPath.lastIndexOf('/'));\n const templateBuffer = tree.read(`${dir}/${prop.initializer.text}`);\n if (templateBuffer) {\n return findSelectorsInTemplate(templateBuffer.toString('utf-8'), allSelectors);\n }\n }\n }\n }\n\n return new Set();\n}\n\nfunction findSelectorsInTemplate(html: string, knownSelectors: string[]): Set<string> {\n const selectors = new Set<string>();\n const parsed = parseTemplate(html, '', { preserveWhitespaces: true });\n\n const visit = (nodes: TmplAstNode[]): void => {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (knownSelectors.includes(node.name)) selectors.add(node.name);\n for (const attr of node.attributes) {\n if (knownSelectors.includes(attr.name)) selectors.add(attr.name);\n }\n visit(node.children);\n }\n }\n };\n visit(parsed.nodes);\n return selectors;\n}\n\nfunction applyReplacements(source: string, filePath: string, replacements: Map<string, { components: string[]; importPath: string }>): string {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n let result = replaceInImportsArray(source, sourceFile, replacements);\n result = updateEsImports(result, filePath, replacements);\n return result;\n}\n\nfunction replaceInImportsArray(source: string, sourceFile: ts.SourceFile, replacements: Map<string, { components: string[]; importPath: string }>): string {\n let result = source;\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node)) {\n const decs = ts.getDecorators(node);\n if (!decs) return;\n for (const dec of decs) {\n if (!ts.isCallExpression(dec.expression) || !ts.isIdentifier(dec.expression.expression) || dec.expression.expression.text !== 'Component') continue;\n const metadata = dec.expression.arguments[0];\n if (!ts.isObjectLiteralExpression(metadata)) continue;\n for (const prop of metadata.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name) || prop.name.text !== 'imports') continue;\n if (!ts.isArrayLiteralExpression(prop.initializer)) continue;\n const newElements = prop.initializer.elements\n .map((el) => {\n const text = result.slice(el.getStart(sourceFile), el.getEnd()).trim();\n const replacement = replacements.get(text);\n return replacement ? replacement.components.join(', ') : text;\n })\n .join(', ');\n result = result.slice(0, prop.initializer.getStart(sourceFile) + 1) + newElements + result.slice(prop.initializer.getEnd() - 1);\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n return result;\n}\n\nfunction updateEsImports(source: string, filePath: string, replacements: Map<string, { components: string[]; importPath: string }>): string {\n let result = source;\n\n for (const [moduleName, { components, importPath }] of replacements) {\n const sf = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n\n for (const stmt of sf.statements) {\n if (!ts.isImportDeclaration(stmt) || !stmt.importClause?.namedBindings || !ts.isNamedImports(stmt.importClause.namedBindings)) continue;\n const namedBindings = stmt.importClause.namedBindings;\n const importNames = namedBindings.elements.map((el) => el.name.text);\n if (!importNames.includes(moduleName)) continue;\n\n const moduleSpecifier = (stmt.moduleSpecifier as ts.StringLiteral).text;\n const remaining = importNames.filter((n) => n !== moduleName);\n const toAdd = components.filter((c) => !importNames.includes(c));\n\n if (moduleSpecifier === importPath) {\n const newNames = [...remaining, ...toAdd].sort();\n const newClause = `{ ${newNames.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n } else {\n if (remaining.length > 0) {\n const newClause = `{ ${remaining.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n } else {\n result = result.slice(0, stmt.getStart(sf)) + result.slice(stmt.getEnd()).replace(/^\\r?\\n/, '');\n }\n\n if (toAdd.length > 0) {\n const updatedSf = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n const existing = updatedSf.statements.find(\n (s) => ts.isImportDeclaration(s) && ts.isStringLiteral(s.moduleSpecifier) && s.moduleSpecifier.text === importPath,\n ) as ts.ImportDeclaration | undefined;\n\n if (existing?.importClause?.namedBindings && ts.isNamedImports(existing.importClause.namedBindings)) {\n const existingNames = existing.importClause.namedBindings.elements.map((el) => el.name.text);\n const allNames = [...new Set([...existingNames, ...toAdd])].sort();\n const newClause = `{ ${allNames.join(', ')} }`;\n result = result.slice(0, existing.importClause.namedBindings.getStart(updatedSf)) + newClause + result.slice(existing.importClause.namedBindings.getEnd());\n } else {\n const newImport = `import { ${toAdd.join(', ')} } from '${importPath}';\\n`;\n result = newImport + result;\n }\n }\n }\n break;\n }\n }\n\n return result;\n}\n",
3203
3203
  "displayName": "Schema",
3204
3204
  "properties": [
3205
3205
  {
@@ -3211,7 +3211,7 @@
3211
3211
  "indexKey": "",
3212
3212
  "optional": true,
3213
3213
  "description": "",
3214
- "line": 9,
3214
+ "line": 460,
3215
3215
  "rawdescription": "\n"
3216
3216
  },
3217
3217
  {
@@ -3223,7 +3223,7 @@
3223
3223
  "indexKey": "",
3224
3224
  "optional": true,
3225
3225
  "description": "",
3226
- "line": 8,
3226
+ "line": 459,
3227
3227
  "rawdescription": "\n"
3228
3228
  }
3229
3229
  ],
@@ -36709,7 +36709,7 @@
36709
36709
  },
36710
36710
  {
36711
36711
  "name": "visitDir",
36712
- "file": "packages/core/schematics/migrate-to-standalone/index.ts",
36712
+ "file": "packages/core/schematics/migrate-to-signals/index.ts",
36713
36713
  "ctype": "miscellaneous",
36714
36714
  "subtype": "function",
36715
36715
  "coverageIgnore": false,
@@ -36754,7 +36754,7 @@
36754
36754
  },
36755
36755
  {
36756
36756
  "name": "visitDir",
36757
- "file": "packages/core/schematics/migrate-to-signals/index.ts",
36757
+ "file": "packages/core/schematics/migrate-to-standalone/index.ts",
36758
36758
  "ctype": "miscellaneous",
36759
36759
  "subtype": "function",
36760
36760
  "coverageIgnore": false,
package/docs/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # eui documentation
2
2
 
3
- > Generated by compodoc 2.0.0 at 2026-10-01T18:33:59.642Z, llm-md export.
3
+ > Generated by compodoc 2.0.0 at 2026-10-02T08:04:06.131Z, llm-md export.
4
4
 
5
5
  ## Modules
6
6
 
@@ -1122,7 +1122,7 @@ Properties:
1122
1122
 
1123
1123
  ### Schema
1124
1124
 
1125
- File: `packages/core/schematics/migrate-eui-avatar/index.ts`
1125
+ File: `packages/core/schematics/migrate-eui-alert/index.ts`
1126
1126
 
1127
1127
  Properties:
1128
1128
  - `dryRun?: boolean`
@@ -1130,7 +1130,7 @@ Properties:
1130
1130
 
1131
1131
  ### Schema
1132
1132
 
1133
- File: `packages/core/schematics/migrate-eui-alert/index.ts`
1133
+ File: `packages/core/schematics/migrate-eui-avatar/index.ts`
1134
1134
 
1135
1135
  Properties:
1136
1136
  - `dryRun?: boolean`
@@ -1418,10 +1418,10 @@ Properties:
1418
1418
  Defined in `packages/core/schematics/migrate-eui-table/index.ts`
1419
1419
  - `collectPipeRenames(nodes, source: string, edits): void`
1420
1420
  Defined in `packages/core/schematics/migrate-eui-table/index.ts`
1421
- - `collectRemovals(element: TmplAstElement, removals): void`
1422
- Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1423
1421
  - `collectRemovals(element: TmplAstElement, removals): void`
1424
1422
  Defined in `packages/core/schematics/migrate-eui-alert/index.ts`
1423
+ - `collectRemovals(element: TmplAstElement, removals): void`
1424
+ Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1425
1425
  - `collectRemovals(element: TmplAstElement, removals): void`
1426
1426
  Defined in `packages/core/schematics/migrate-eui-chip/index.ts`
1427
1427
  - `collectRemovals(element: TmplAstElement, source: string, removals): void`
@@ -1520,10 +1520,10 @@ Properties:
1520
1520
  Defined in `packages/core/schematics/fix-no-multiple-empty-lines/index.ts`
1521
1521
  - `formatInnerLines(source: string, indent: string): string[]`
1522
1522
  Defined in `packages/core/schematics/migrate-eui-tabs/index.ts`
1523
- - `getAttributeSpan(attr): { start: number; end: number }`
1524
- Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1525
1523
  - `getAttributeSpan(attr): { start: number; end: number }`
1526
1524
  Defined in `packages/core/schematics/migrate-eui-alert/index.ts`
1525
+ - `getAttributeSpan(attr): { start: number; end: number }`
1526
+ Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1527
1527
  - `getAttributeSpan(attr): { start: number; end: number }`
1528
1528
  Defined in `packages/core/schematics/migrate-eui-chip/index.ts`
1529
1529
  - `getAttributeSpan(attr): { start: number; end: number }`
@@ -1730,10 +1730,10 @@ Properties:
1730
1730
  Defined in `packages/core/schematics/migrate-eui-toolbar-menu/index.ts`
1731
1731
  - `migrateInlineTemplates(source: string): string`
1732
1732
  Defined in `packages/core/schematics/migrate-eui-accent/index.ts`
1733
- - `migrateInlineTemplates(source: string): string`
1734
- Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1735
1733
  - `migrateInlineTemplates(source: string): string`
1736
1734
  Defined in `packages/core/schematics/migrate-eui-alert/index.ts`
1735
+ - `migrateInlineTemplates(source: string): string`
1736
+ Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1737
1737
  - `migrateInlineTemplates(source: string): string`
1738
1738
  Defined in `packages/core/schematics/migrate-eui-button/index.ts`
1739
1739
  - `migrateInlineTemplates(source: string): string`
@@ -1760,10 +1760,10 @@ Properties:
1760
1760
  Defined in `packages/core/schematics/migrate-eui-toolbar-menu/index.ts`
1761
1761
  - `migrateTemplate(source: string): string`
1762
1762
  Defined in `packages/core/schematics/migrate-eui-accent/index.ts`
1763
- - `migrateTemplate(source: string): string`
1764
- Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1765
1763
  - `migrateTemplate(source: string): string`
1766
1764
  Defined in `packages/core/schematics/migrate-eui-alert/index.ts`
1765
+ - `migrateTemplate(source: string): string`
1766
+ Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1767
1767
  - `migrateTemplate(source: string): string`
1768
1768
  Defined in `packages/core/schematics/migrate-eui-button/index.ts`
1769
1769
  - `migrateTemplate(source: string): string`
@@ -1906,10 +1906,10 @@ Properties:
1906
1906
  Defined in `packages/core/schematics/fix-no-multiple-empty-lines/index.ts`
1907
1907
  - `visitDir(dir: DirEntry, callback): void`
1908
1908
  Defined in `packages/core/schematics/migrate-eui-accent/index.ts`
1909
- - `visitDir(dir: DirEntry, callback): void`
1910
- Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1911
1909
  - `visitDir(dir: DirEntry, callback): void`
1912
1910
  Defined in `packages/core/schematics/migrate-eui-alert/index.ts`
1911
+ - `visitDir(dir: DirEntry, callback): void`
1912
+ Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1913
1913
  - `visitDir(dir: DirEntry, callback): void`
1914
1914
  Defined in `packages/core/schematics/migrate-eui-button/index.ts`
1915
1915
  - `visitDir(dir: DirEntry, callback): void`
@@ -1946,10 +1946,10 @@ Properties:
1946
1946
  Defined in `packages/core/schematics/migrate-eui-table/index.ts`
1947
1947
  - `visitNodes(nodes, edits): void`
1948
1948
  Defined in `packages/core/schematics/migrate-eui-accent/index.ts`
1949
- - `visitNodes(nodes, removals): void`
1950
- Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1951
1949
  - `visitNodes(nodes, removals): void`
1952
1950
  Defined in `packages/core/schematics/migrate-eui-alert/index.ts`
1951
+ - `visitNodes(nodes, removals): void`
1952
+ Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
1953
1953
  - `visitNodes(nodes, edits): void`
1954
1954
  Defined in `packages/core/schematics/migrate-eui-button/index.ts`
1955
1955
  - `visitNodes(nodes, removals): void`
@@ -2309,10 +2309,10 @@ Properties:
2309
2309
  Defined in `packages/core/schematics/migrate-eui-chip-list/index.ts`
2310
2310
  - `removeApiQueueItem: unknown = (state: AppState, action: RemoveApiQueueItemAction): AppState => { // remove the specified id from the list of item ids and recreate the apiQueue from the remai…`
2311
2311
  Defined in `packages/core/src/lib/services/store/reducers/app.reducers.ts`
2312
- - `REMOVED_INPUTS: unknown = new Set(['isFlat'])`
2313
- Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
2314
2312
  - `REMOVED_INPUTS: unknown = new Set(['alertIconType', 'alertIconFillColor', 'isMuted', 'isBordered'])`
2315
2313
  Defined in `packages/core/schematics/migrate-eui-alert/index.ts`
2314
+ - `REMOVED_INPUTS: unknown = new Set(['isFlat'])`
2315
+ Defined in `packages/core/schematics/migrate-eui-avatar/index.ts`
2316
2316
  - `REMOVED_INPUTS: unknown = new Set(['isSquared'])`
2317
2317
  Defined in `packages/core/schematics/migrate-eui-chip/index.ts`
2318
2318
  - `REMOVED_INPUTS: unknown = new Set(['maxVisibleChipsCount', 'isMaxVisibleChipsOpened', 'toggleLinkMoreLabel', 'toggleLinkLessLabel', 'isChipsSorted', 'chipsSortOrder'])`