@eui/core 22.0.0-alpha.24 → 22.0.0-alpha.26

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.
@@ -2139,12 +2139,12 @@
2139
2139
  },
2140
2140
  {
2141
2141
  "name": "Schema",
2142
- "id": "interface-Schema-9c5e016857e1416ac7bbb881973e644c0f578a53bd432bb951c1676ac3f2a6631bfe3344860346a081b841217278723e0bb0bf2fa35fb869de67cb0cc8d99849",
2143
- "file": "packages/core/schematics/add-eui-imports/index.ts",
2142
+ "id": "interface-Schema-4fe31ff3e9f1d34845a6b865d605e215f33552094b88c3d0eab0b180187fe64ce4d68d687516cb3d62c57d2678a103969b2dacbb18a49b26060f78096678fcce",
2143
+ "file": "packages/core/schematics/fix-no-multiple-empty-lines/index.ts",
2144
2144
  "deprecated": false,
2145
2145
  "deprecationMessage": "",
2146
2146
  "type": "interface",
2147
- "sourceCode": "import { parseTemplate, TmplAstElement, TmplAstNode, TmplAstTemplate } from '@angular/compiler';\nimport { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\nimport { SELECTOR_MAP, SelectorEntry, getClassNamesForArray } from './selector-map';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n useClassArray?: boolean;\n}\n\ninterface ImportToAdd {\n /** The symbol to add to imports array (class name or array name for spread) */\n symbol: string;\n /** Whether this should be spread (...EUI_BUTTON) */\n isSpread: boolean;\n /** ES import path */\n importPath: string;\n}\n\nexport function addEuiImports(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n const useClassArray = options.useClassArray ?? false;\n let filesUpdated = 0;\n\n // Index NgModules for standalone:false support\n const ngModuleIndex = buildNgModuleIndex(tree, tree.getDir(scanPath || '/'));\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts') || path.endsWith('.spec.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n const source = buffer.toString('utf-8');\n\n const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\n const components = findComponentDecorators(sourceFile);\n if (components.length === 0) return;\n\n let modified = false;\n\n for (const { decorator, className: componentClassName, isNonStandalone } of components) {\n const templateHtml = getTemplateContent(tree, path, decorator, source);\n if (!templateHtml) continue;\n\n const matched = matchSelectorsInTemplate(templateHtml);\n if (matched.length === 0) continue;\n\n const importsToAdd = resolveImports(matched, useClassArray);\n if (importsToAdd.length === 0) continue;\n\n if (isNonStandalone) {\n // Find the NgModule that declares this component and add imports there\n const moduleInfo = findDeclaringModule(ngModuleIndex, componentClassName);\n if (!moduleInfo) {\n context.logger.warn(`⚠ Could not find declaring NgModule for ${componentClassName} in ${path}`);\n continue;\n }\n const moduleBuffer = tree.read(moduleInfo.path);\n if (!moduleBuffer) continue;\n const moduleSource = moduleBuffer.toString('utf-8');\n const result = addImportsToFile(moduleSource, moduleInfo.path, moduleInfo.decoratorPos, importsToAdd, useClassArray);\n if (result !== moduleSource) {\n if (options.dryRun) {\n logDryRun(context, `Would add EUI imports to NgModule in ${moduleInfo.path} for component ${componentClassName}`);\n } else {\n tree.overwrite(moduleInfo.path, result);\n }\n modified = true;\n }\n } else {\n // Standalone component — add imports directly\n const currentSource = tree.read(path)!.toString('utf-8');\n const result = addImportsToFile(currentSource, path, decorator.getStart(), importsToAdd, useClassArray);\n if (result !== currentSource) {\n if (options.dryRun) {\n logDryRun(context, `Would add EUI imports to ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n modified = true;\n }\n }\n }\n\n if (modified) filesUpdated++;\n });\n\n context.logger.info(`add-eui-imports: ${filesUpdated} file(s) updated.`);\n if (options.dryRun) logDryRunNote(context);\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('.html') && !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\n// --- Selector Matching ---\n\nfunction matchSelectorsInTemplate(html: string): SelectorEntry[] {\n const parsed = parseTemplate(html, '', { preserveWhitespaces: true });\n if (parsed.errors?.length) return [];\n\n const matched: SelectorEntry[] = [];\n visitTemplateNodes(parsed.nodes, matched);\n return matched;\n}\n\nfunction visitTemplateNodes(nodes: TmplAstNode[], matched: SelectorEntry[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n matchElement(node, matched);\n visitTemplateNodes(node.children, matched);\n } else if (node instanceof TmplAstTemplate) {\n visitTemplateNodes(node.children, matched);\n }\n }\n}\n\nfunction matchElement(element: TmplAstElement, matched: SelectorEntry[]): void {\n const tagName = element.name;\n const attrNames = new Set([\n ...element.attributes.map(a => a.name),\n ...element.inputs.map(i => i.name),\n ]);\n\n for (const entry of SELECTOR_MAP) {\n if (entry.element && entry.element !== tagName) continue;\n if (!entry.element && entry.attributes.length === 0) continue;\n if (!entry.attributes.every(attr => attrNames.has(attr))) continue;\n // If no element specified, at least one attribute must match on this element\n if (!entry.element && entry.attributes.length > 0 && !entry.attributes.some(attr => attrNames.has(attr))) continue;\n matched.push(entry);\n }\n}\n\n// --- Import Resolution ---\n\nfunction resolveImports(matched: SelectorEntry[], useClassArray: boolean): ImportToAdd[] {\n const seen = new Set<string>();\n const result: ImportToAdd[] = [];\n\n for (const entry of matched) {\n if (useClassArray && entry.classArray) {\n if (seen.has(entry.classArray)) continue;\n seen.add(entry.classArray);\n result.push({ symbol: entry.classArray, isSpread: true, importPath: entry.importPath });\n } else {\n if (seen.has(entry.className)) continue;\n seen.add(entry.className);\n result.push({ symbol: entry.className, isSpread: false, importPath: entry.importPath });\n }\n }\n\n return result;\n}\n\n// --- Template Extraction ---\n\nfunction getTemplateContent(tree: Tree, tsPath: string, decorator: ts.Decorator, source: string): string | null {\n const call = decorator.expression as ts.CallExpression;\n if (!call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) return null;\n const metadata = call.arguments[0];\n\n for (const prop of metadata.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n if (prop.name.text === 'template') {\n const init = prop.initializer;\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n return init.text;\n }\n }\n if (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) return templateBuffer.toString('utf-8');\n }\n }\n }\n return null;\n}\n\n// --- Component Decorator Detection ---\n\ninterface ComponentInfo {\n decorator: ts.Decorator;\n className: string;\n isNonStandalone: boolean;\n}\n\nfunction findComponentDecorators(sourceFile: ts.SourceFile): ComponentInfo[] {\n const results: ComponentInfo[] = [];\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node) && node.name) {\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 const isNonStandalone = hasStandaloneFalse(dec);\n results.push({ decorator: dec, className: node.name.text, isNonStandalone });\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n return results;\n}\n\nfunction hasStandaloneFalse(decorator: ts.Decorator): boolean {\n const call = decorator.expression as ts.CallExpression;\n if (!call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) return false;\n for (const prop of call.arguments[0].properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'standalone') {\n return prop.initializer.kind === ts.SyntaxKind.FalseKeyword;\n }\n }\n return false;\n}\n\n// --- NgModule Index ---\n\ninterface NgModuleInfo {\n path: string;\n declarations: string[];\n decoratorPos: number;\n}\n\nfunction buildNgModuleIndex(tree: Tree, dir: DirEntry): NgModuleInfo[] {\n const modules: NgModuleInfo[] = [];\n\n visitDir(dir, (path) => {\n if (!path.endsWith('.ts') || path.endsWith('.spec.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n const source = buffer.toString('utf-8');\n if (!source.includes('NgModule')) return;\n\n const sf = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\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 === 'NgModule') {\n const declarations = extractArrayProperty(dec, 'declarations', source);\n modules.push({ path, declarations, decoratorPos: dec.getStart() });\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n });\n\n return modules;\n}\n\nfunction extractArrayProperty(decorator: ts.Decorator, propName: string, source: string): string[] {\n const call = decorator.expression as ts.CallExpression;\n if (!call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) return [];\n for (const prop of call.arguments[0].properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === propName) {\n if (ts.isArrayLiteralExpression(prop.initializer)) {\n return prop.initializer.elements\n .filter(ts.isIdentifier)\n .map(id => id.text);\n }\n }\n }\n return [];\n}\n\nfunction findDeclaringModule(modules: NgModuleInfo[], componentClassName: string): NgModuleInfo | undefined {\n return modules.find(m => m.declarations.includes(componentClassName));\n}\n\n// --- Import Addition ---\n\nfunction addImportsToFile(source: string, filePath: string, decoratorStartHint: number, imports: ImportToAdd[], useClassArray: boolean): string {\n const sf = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n\n // Find the imports array in the decorator closest to decoratorStartHint\n const importsArrayInfo = findDecoratorImportsArray(sf, source, decoratorStartHint);\n if (!importsArrayInfo) return source;\n\n const { arrayNode, decoratorType } = importsArrayInfo;\n\n // Determine what's already in the imports array\n const existingSymbols = new Set<string>();\n const existingSpreads = new Set<string>();\n for (const el of arrayNode.elements) {\n if (ts.isSpreadElement(el) && ts.isIdentifier(el.expression)) {\n existingSpreads.add(el.expression.text);\n } else if (ts.isIdentifier(el)) {\n existingSymbols.add(el.text);\n }\n }\n\n // Filter out already-present imports and compute what to add/remove\n const toAdd: ImportToAdd[] = [];\n const toRemoveFromArray: string[] = []; // individual class names to consolidate\n\n for (const imp of imports) {\n if (imp.isSpread) {\n if (existingSpreads.has(imp.symbol)) continue; // Already has ...EUI_X\n toAdd.push(imp);\n // Consolidate: remove individual class names covered by this array\n if (useClassArray) {\n const coveredClasses = getClassNamesForArray(imp.symbol);\n for (const cls of coveredClasses) {\n if (existingSymbols.has(cls)) toRemoveFromArray.push(cls);\n }\n }\n } else {\n if (existingSymbols.has(imp.symbol)) continue;\n // Also skip if a spread already covers this class\n const coveringArray = imports.find(i => i.isSpread && getClassNamesForArray(i.symbol).includes(imp.symbol));\n if (coveringArray && (existingSpreads.has(coveringArray.symbol) || toAdd.some(a => a.symbol === coveringArray.symbol))) continue;\n toAdd.push(imp);\n }\n }\n\n if (toAdd.length === 0 && toRemoveFromArray.length === 0) return source;\n\n // Build new array content\n let result = source;\n result = updateDecoratorImportsArray(result, filePath, arrayNode, toAdd, toRemoveFromArray);\n\n // Add ES imports\n result = addEsImports(result, filePath, toAdd);\n\n // Remove consolidated class names from ES imports\n if (toRemoveFromArray.length > 0) {\n result = removeFromEsImports(result, filePath, toRemoveFromArray);\n }\n\n return result;\n}\n\ninterface ImportsArrayInfo {\n arrayNode: ts.ArrayLiteralExpression;\n decoratorType: 'Component' | 'NgModule';\n}\n\nfunction findDecoratorImportsArray(sf: ts.SourceFile, source: string, decoratorStartHint: number): ImportsArrayInfo | null {\n let found: ImportsArrayInfo | null = null;\n\n const visit = (node: ts.Node): void => {\n if (found) return;\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)) continue;\n if (!ts.isIdentifier(dec.expression.expression)) continue;\n const decName = dec.expression.expression.text;\n if (decName !== 'Component' && decName !== 'NgModule') continue;\n if (Math.abs(dec.getStart() - decoratorStartHint) > 5) continue; // Match by position\n\n const metadata = dec.expression.arguments[0];\n if (!ts.isObjectLiteralExpression(metadata)) continue;\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 found = { arrayNode: prop.initializer, decoratorType: decName as 'Component' | 'NgModule' };\n return;\n }\n }\n }\n\n // No imports array found — create one\n if (!found && decName === 'Component') {\n // We need to add `imports: []` to the decorator\n // Insert after the last property\n const lastProp = metadata.properties[metadata.properties.length - 1];\n if (lastProp) {\n const insertPos = lastProp.getEnd();\n const indent = detectIndent(source, metadata.getStart());\n const insertion = `,\\n${indent} imports: []`;\n const newSource = source.slice(0, insertPos) + insertion + source.slice(insertPos);\n // Re-parse to get the array node\n const newSf = ts.createSourceFile('', newSource, ts.ScriptTarget.Latest, true);\n const newArray = findImportsArrayInSource(newSf);\n if (newArray) {\n // We can't return a node from a different source file in the general case.\n // Instead, we'll handle the \"no imports array\" case by adding it inline.\n found = null; // Will be handled separately\n }\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return found;\n}\n\nfunction findImportsArrayInSource(sf: ts.SourceFile): ts.ArrayLiteralExpression | null {\n let found: ts.ArrayLiteralExpression | null = null;\n const visit = (node: ts.Node): void => {\n if (found) return;\n if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === 'imports' && ts.isArrayLiteralExpression(node.initializer)) {\n found = node.initializer;\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return found;\n}\n\nfunction updateDecoratorImportsArray(source: string, filePath: string, arrayNode: ts.ArrayLiteralExpression, toAdd: ImportToAdd[], toRemove: string[]): string {\n const sf = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n\n // Rebuild the array content\n const existingElements: string[] = [];\n for (const el of arrayNode.elements) {\n const text = source.slice(el.getStart(sf), el.getEnd()).trim();\n // Check if this element should be removed (consolidation)\n if (ts.isIdentifier(el) && toRemove.includes(el.text)) continue;\n existingElements.push(text);\n }\n\n // Add new entries\n for (const imp of toAdd) {\n const entry = imp.isSpread ? `...${imp.symbol}` : imp.symbol;\n if (!existingElements.includes(entry)) {\n existingElements.push(entry);\n }\n }\n\n // Determine formatting\n const arrayStart = arrayNode.getStart(sf);\n const arrayEnd = arrayNode.getEnd();\n const originalText = source.slice(arrayStart, arrayEnd);\n const isMultiline = originalText.includes('\\n');\n\n let newArrayText: string;\n if (isMultiline || existingElements.length > 3) {\n const indent = detectIndent(source, arrayStart);\n const itemIndent = indent + ' ';\n newArrayText = `[\\n${existingElements.map(e => `${itemIndent}${e},`).join('\\n')}\\n${indent}]`;\n } else {\n newArrayText = `[${existingElements.join(', ')}]`;\n }\n\n return source.slice(0, arrayStart) + newArrayText + source.slice(arrayEnd);\n}\n\nfunction addEsImports(source: string, filePath: string, imports: ImportToAdd[]): string {\n let result = source;\n\n // Group by import path\n const byPath = new Map<string, string[]>();\n for (const imp of imports) {\n const existing = byPath.get(imp.importPath) || [];\n existing.push(imp.symbol);\n byPath.set(imp.importPath, existing);\n }\n\n for (const [importPath, symbols] of byPath) {\n const sf = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n\n // Check if there's already an import from this path\n const existingImport = sf.statements.find(\n (s): s is ts.ImportDeclaration =>\n ts.isImportDeclaration(s) && ts.isStringLiteral(s.moduleSpecifier) && s.moduleSpecifier.text === importPath,\n );\n\n if (existingImport?.importClause?.namedBindings && ts.isNamedImports(existingImport.importClause.namedBindings)) {\n // Extend existing import\n const namedBindings = existingImport.importClause.namedBindings;\n const existingNames = namedBindings.elements.map(el => el.name.text);\n const newNames = symbols.filter(s => !existingNames.includes(s));\n if (newNames.length === 0) continue;\n\n const allNames = [...existingNames, ...newNames].sort();\n const newClause = `{ ${allNames.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n } else {\n // Add new import statement\n const sortedSymbols = [...symbols].sort();\n const newImport = `import { ${sortedSymbols.join(', ')} } from '${importPath}';\\n`;\n\n // Insert after the last existing import\n const lastImport = [...sf.statements].reverse().find(ts.isImportDeclaration);\n if (lastImport) {\n const pos = lastImport.getEnd();\n result = result.slice(0, pos) + '\\n' + newImport.trimEnd() + result.slice(pos);\n } else {\n result = newImport + result;\n }\n }\n }\n\n return result;\n}\n\nfunction detectIndent(source: string, pos: number): string {\n const lineStart = source.lastIndexOf('\\n', pos - 1) + 1;\n const match = source.slice(lineStart, pos).match(/^(\\s*)/);\n return match ? match[1] : '';\n}\n\nfunction removeFromEsImports(source: string, filePath: string, symbolsToRemove: string[]): string {\n let result = source;\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 existingNames = namedBindings.elements.map(el => el.name.text);\n const remaining = existingNames.filter(n => !symbolsToRemove.includes(n));\n\n if (remaining.length === existingNames.length) continue; // Nothing to remove from this import\n\n if (remaining.length === 0) {\n // Remove the entire import statement\n result = result.slice(0, stmt.getStart(sf)) + result.slice(stmt.getEnd()).replace(/^\\r?\\n/, '');\n } else {\n const newClause = `{ ${remaining.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n }\n break; // Only process the first matching import for the consolidated symbols\n }\n\n return result;\n}\n",
2147
+ "sourceCode": "import { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst MULTIPLE_EMPTY_LINES = /\\n{3,}/g;\n\nexport function fixNoMultipleEmptyLines(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (filePath) => {\n const buffer = tree.read(filePath);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n const result = original.replace(MULTIPLE_EMPTY_LINES, '\\n\\n');\n\n if (result !== original) {\n if (filePath.endsWith('.ts')) {\n const sourceFile = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if ((sourceFile as any).parseDiagnostics?.length) {\n context.logger.warn(`Skipping ${filePath}: file would not parse after transformation.`);\n return;\n }\n }\n if (options.dryRun) {\n logDryRun(context, `Would collapse multiple empty lines in ${filePath}`);\n } else {\n tree.overwrite(filePath, result);\n }\n count++;\n }\n });\n\n context.logger.info(`Fixed multiple empty lines in ${count} file(s).`);\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') && !file.endsWith('.html') && !file.endsWith('.scss') && !file.endsWith('.css')) 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",
2148
2148
  "displayName": "Schema",
2149
2149
  "properties": [
2150
2150
  {
@@ -2156,7 +2156,7 @@
2156
2156
  "indexKey": "",
2157
2157
  "optional": true,
2158
2158
  "description": "",
2159
- "line": 9,
2159
+ "line": 7,
2160
2160
  "rawdescription": "\n"
2161
2161
  },
2162
2162
  {
@@ -2168,19 +2168,7 @@
2168
2168
  "indexKey": "",
2169
2169
  "optional": true,
2170
2170
  "description": "",
2171
- "line": 8,
2172
- "rawdescription": "\n"
2173
- },
2174
- {
2175
- "name": "useClassArray",
2176
- "coverageIgnore": false,
2177
- "deprecated": false,
2178
- "deprecationMessage": "",
2179
- "type": "boolean",
2180
- "indexKey": "",
2181
- "optional": true,
2182
- "description": "",
2183
- "line": 10,
2171
+ "line": 6,
2184
2172
  "rawdescription": "\n"
2185
2173
  }
2186
2174
  ],
@@ -2195,12 +2183,12 @@
2195
2183
  },
2196
2184
  {
2197
2185
  "name": "Schema",
2198
- "id": "interface-Schema-4fe31ff3e9f1d34845a6b865d605e215f33552094b88c3d0eab0b180187fe64ce4d68d687516cb3d62c57d2678a103969b2dacbb18a49b26060f78096678fcce-1",
2199
- "file": "packages/core/schematics/fix-no-multiple-empty-lines/index.ts",
2186
+ "id": "interface-Schema-5cd6db1920bd5b70a44c0b8a7f7e30f600bfd16a9950f218e6d451a1755ced95b462ef9a62ee87e39bcb8c392981b8d2597895bf0a272fd8aea71f03429ed976-1",
2187
+ "file": "packages/core/schematics/icon-migrate/schema.ts",
2200
2188
  "deprecated": false,
2201
2189
  "deprecationMessage": "",
2202
2190
  "type": "interface",
2203
- "sourceCode": "import { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst MULTIPLE_EMPTY_LINES = /\\n{3,}/g;\n\nexport function fixNoMultipleEmptyLines(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (filePath) => {\n const buffer = tree.read(filePath);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n const result = original.replace(MULTIPLE_EMPTY_LINES, '\\n\\n');\n\n if (result !== original) {\n if (filePath.endsWith('.ts')) {\n const sourceFile = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if ((sourceFile as any).parseDiagnostics?.length) {\n context.logger.warn(`Skipping ${filePath}: file would not parse after transformation.`);\n return;\n }\n }\n if (options.dryRun) {\n logDryRun(context, `Would collapse multiple empty lines in ${filePath}`);\n } else {\n tree.overwrite(filePath, result);\n }\n count++;\n }\n });\n\n context.logger.info(`Fixed multiple empty lines in ${count} file(s).`);\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') && !file.endsWith('.html') && !file.endsWith('.scss') && !file.endsWith('.css')) 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",
2191
+ "sourceCode": "export interface Schema {\n /** The path to scan for files to migrate */\n path?: string;\n /** Whether to perform a dry run without making changes */\n dryRun?: boolean;\n}\n",
2204
2192
  "displayName": "Schema",
2205
2193
  "properties": [
2206
2194
  {
@@ -2211,9 +2199,9 @@
2211
2199
  "type": "boolean",
2212
2200
  "indexKey": "",
2213
2201
  "optional": true,
2214
- "description": "",
2215
- "line": 7,
2216
- "rawdescription": "\n"
2202
+ "description": "<p>Whether to perform a dry run without making changes</p>\n",
2203
+ "line": 5,
2204
+ "rawdescription": "\nWhether to perform a dry run without making changes"
2217
2205
  },
2218
2206
  {
2219
2207
  "name": "path",
@@ -2223,9 +2211,9 @@
2223
2211
  "type": "string",
2224
2212
  "indexKey": "",
2225
2213
  "optional": true,
2226
- "description": "",
2227
- "line": 6,
2228
- "rawdescription": "\n"
2214
+ "description": "<p>The path to scan for files to migrate</p>\n",
2215
+ "line": 3,
2216
+ "rawdescription": "\nThe path to scan for files to migrate"
2229
2217
  }
2230
2218
  ],
2231
2219
  "indexSignatures": [],
@@ -2242,12 +2230,12 @@
2242
2230
  },
2243
2231
  {
2244
2232
  "name": "Schema",
2245
- "id": "interface-Schema-5cd6db1920bd5b70a44c0b8a7f7e30f600bfd16a9950f218e6d451a1755ced95b462ef9a62ee87e39bcb8c392981b8d2597895bf0a272fd8aea71f03429ed976-2",
2246
- "file": "packages/core/schematics/icon-migrate/schema.ts",
2233
+ "id": "interface-Schema-56b9fe60701ca349dc90e152829b0a18bb7a8a9bb303c4bac05f9764cd2e933cce0879775ca17168b4c881e202d0258af3668a2a3a1b940e561f7e4b2349b5cc-2",
2234
+ "file": "packages/core/schematics/migrate/schema.ts",
2247
2235
  "deprecated": false,
2248
2236
  "deprecationMessage": "",
2249
2237
  "type": "interface",
2250
- "sourceCode": "export interface Schema {\n /** The path to scan for files to migrate */\n path?: string;\n /** Whether to perform a dry run without making changes */\n dryRun?: boolean;\n}\n",
2238
+ "sourceCode": "export interface Schema {\n /** The path to scan for files to migrate */\n path?: string;\n /** Whether to apply MyWorkplace-specific replacements */\n mwp?: boolean;\n /** Whether to perform a dry run without making changes */\n dryRun?: boolean;\n}\n",
2251
2239
  "displayName": "Schema",
2252
2240
  "properties": [
2253
2241
  {
@@ -2259,9 +2247,21 @@
2259
2247
  "indexKey": "",
2260
2248
  "optional": true,
2261
2249
  "description": "<p>Whether to perform a dry run without making changes</p>\n",
2262
- "line": 5,
2250
+ "line": 7,
2263
2251
  "rawdescription": "\nWhether to perform a dry run without making changes"
2264
2252
  },
2253
+ {
2254
+ "name": "mwp",
2255
+ "coverageIgnore": false,
2256
+ "deprecated": false,
2257
+ "deprecationMessage": "",
2258
+ "type": "boolean",
2259
+ "indexKey": "",
2260
+ "optional": true,
2261
+ "description": "<p>Whether to apply MyWorkplace-specific replacements</p>\n",
2262
+ "line": 5,
2263
+ "rawdescription": "\nWhether to apply MyWorkplace-specific replacements"
2264
+ },
2265
2265
  {
2266
2266
  "name": "path",
2267
2267
  "coverageIgnore": false,
@@ -2289,12 +2289,12 @@
2289
2289
  },
2290
2290
  {
2291
2291
  "name": "Schema",
2292
- "id": "interface-Schema-56b9fe60701ca349dc90e152829b0a18bb7a8a9bb303c4bac05f9764cd2e933cce0879775ca17168b4c881e202d0258af3668a2a3a1b940e561f7e4b2349b5cc-3",
2293
- "file": "packages/core/schematics/migrate/schema.ts",
2292
+ "id": "interface-Schema-9c5e016857e1416ac7bbb881973e644c0f578a53bd432bb951c1676ac3f2a6631bfe3344860346a081b841217278723e0bb0bf2fa35fb869de67cb0cc8d99849-3",
2293
+ "file": "packages/core/schematics/add-eui-imports/index.ts",
2294
2294
  "deprecated": false,
2295
2295
  "deprecationMessage": "",
2296
2296
  "type": "interface",
2297
- "sourceCode": "export interface Schema {\n /** The path to scan for files to migrate */\n path?: string;\n /** Whether to apply MyWorkplace-specific replacements */\n mwp?: boolean;\n /** Whether to perform a dry run without making changes */\n dryRun?: boolean;\n}\n",
2297
+ "sourceCode": "import { parseTemplate, TmplAstElement, TmplAstNode, TmplAstTemplate } from '@angular/compiler';\nimport { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\nimport { SELECTOR_MAP, SelectorEntry, getClassNamesForArray } from './selector-map';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n useClassArray?: boolean;\n}\n\ninterface ImportToAdd {\n /** The symbol to add to imports array (class name or array name for spread) */\n symbol: string;\n /** Whether this should be spread (...EUI_BUTTON) */\n isSpread: boolean;\n /** ES import path */\n importPath: string;\n}\n\nexport function addEuiImports(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n const useClassArray = options.useClassArray ?? false;\n let filesUpdated = 0;\n\n // Index NgModules for standalone:false support\n const ngModuleIndex = buildNgModuleIndex(tree, tree.getDir(scanPath || '/'));\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts') || path.endsWith('.spec.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n const source = buffer.toString('utf-8');\n\n const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\n const components = findComponentDecorators(sourceFile);\n if (components.length === 0) return;\n\n let modified = false;\n\n for (const { decorator, className: componentClassName, isNonStandalone } of components) {\n const templateHtml = getTemplateContent(tree, path, decorator, source);\n if (!templateHtml) continue;\n\n const matched = matchSelectorsInTemplate(templateHtml);\n if (matched.length === 0) continue;\n\n const importsToAdd = resolveImports(matched, useClassArray);\n if (importsToAdd.length === 0) continue;\n\n if (isNonStandalone) {\n // Find the NgModule that declares this component and add imports there\n const moduleInfo = findDeclaringModule(ngModuleIndex, componentClassName);\n if (!moduleInfo) {\n context.logger.warn(`⚠ Could not find declaring NgModule for ${componentClassName} in ${path}`);\n continue;\n }\n const moduleBuffer = tree.read(moduleInfo.path);\n if (!moduleBuffer) continue;\n const moduleSource = moduleBuffer.toString('utf-8');\n const result = addImportsToFile(moduleSource, moduleInfo.path, moduleInfo.decoratorPos, importsToAdd, useClassArray);\n if (result !== moduleSource) {\n if (options.dryRun) {\n logDryRun(context, `Would add EUI imports to NgModule in ${moduleInfo.path} for component ${componentClassName}`);\n } else {\n tree.overwrite(moduleInfo.path, result);\n }\n modified = true;\n }\n } else {\n // Standalone component — add imports directly\n const currentSource = tree.read(path)!.toString('utf-8');\n const result = addImportsToFile(currentSource, path, decorator.getStart(), importsToAdd, useClassArray);\n if (result !== currentSource) {\n if (options.dryRun) {\n logDryRun(context, `Would add EUI imports to ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n modified = true;\n }\n }\n }\n\n if (modified) filesUpdated++;\n });\n\n context.logger.info(`add-eui-imports: ${filesUpdated} file(s) updated.`);\n if (options.dryRun) logDryRunNote(context);\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('.html') && !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\n// --- Selector Matching ---\n\nfunction matchSelectorsInTemplate(html: string): SelectorEntry[] {\n const parsed = parseTemplate(html, '', { preserveWhitespaces: true });\n if (parsed.errors?.length) return [];\n\n const matched: SelectorEntry[] = [];\n visitTemplateNodes(parsed.nodes, matched);\n return matched;\n}\n\nfunction visitTemplateNodes(nodes: TmplAstNode[], matched: SelectorEntry[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n matchElement(node, matched);\n visitTemplateNodes(node.children, matched);\n } else if (node instanceof TmplAstTemplate) {\n visitTemplateNodes(node.children, matched);\n }\n }\n}\n\nfunction matchElement(element: TmplAstElement, matched: SelectorEntry[]): void {\n const tagName = element.name;\n const attrNames = new Set([\n ...element.attributes.map(a => a.name),\n ...element.inputs.map(i => i.name),\n ]);\n\n for (const entry of SELECTOR_MAP) {\n if (entry.element && entry.element !== tagName) continue;\n if (!entry.element && entry.attributes.length === 0) continue;\n if (!entry.attributes.every(attr => attrNames.has(attr))) continue;\n // If no element specified, at least one attribute must match on this element\n if (!entry.element && entry.attributes.length > 0 && !entry.attributes.some(attr => attrNames.has(attr))) continue;\n matched.push(entry);\n }\n}\n\n// --- Import Resolution ---\n\nfunction resolveImports(matched: SelectorEntry[], useClassArray: boolean): ImportToAdd[] {\n const seen = new Set<string>();\n const result: ImportToAdd[] = [];\n\n for (const entry of matched) {\n if (useClassArray && entry.classArray) {\n if (seen.has(entry.classArray)) continue;\n seen.add(entry.classArray);\n result.push({ symbol: entry.classArray, isSpread: true, importPath: entry.importPath });\n } else {\n if (seen.has(entry.className)) continue;\n seen.add(entry.className);\n result.push({ symbol: entry.className, isSpread: false, importPath: entry.importPath });\n }\n }\n\n return result;\n}\n\n// --- Template Extraction ---\n\nfunction getTemplateContent(tree: Tree, tsPath: string, decorator: ts.Decorator, source: string): string | null {\n const call = decorator.expression as ts.CallExpression;\n if (!call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) return null;\n const metadata = call.arguments[0];\n\n for (const prop of metadata.properties) {\n if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;\n if (prop.name.text === 'template') {\n const init = prop.initializer;\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n return init.text;\n }\n }\n if (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) return templateBuffer.toString('utf-8');\n }\n }\n }\n return null;\n}\n\n// --- Component Decorator Detection ---\n\ninterface ComponentInfo {\n decorator: ts.Decorator;\n className: string;\n isNonStandalone: boolean;\n}\n\nfunction findComponentDecorators(sourceFile: ts.SourceFile): ComponentInfo[] {\n const results: ComponentInfo[] = [];\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node) && node.name) {\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 const isNonStandalone = hasStandaloneFalse(dec);\n results.push({ decorator: dec, className: node.name.text, isNonStandalone });\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n return results;\n}\n\nfunction hasStandaloneFalse(decorator: ts.Decorator): boolean {\n const call = decorator.expression as ts.CallExpression;\n if (!call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) return false;\n for (const prop of call.arguments[0].properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === 'standalone') {\n return prop.initializer.kind === ts.SyntaxKind.FalseKeyword;\n }\n }\n return false;\n}\n\n// --- NgModule Index ---\n\ninterface NgModuleInfo {\n path: string;\n declarations: string[];\n decoratorPos: number;\n}\n\nfunction buildNgModuleIndex(tree: Tree, dir: DirEntry): NgModuleInfo[] {\n const modules: NgModuleInfo[] = [];\n\n visitDir(dir, (path) => {\n if (!path.endsWith('.ts') || path.endsWith('.spec.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n const source = buffer.toString('utf-8');\n if (!source.includes('NgModule')) return;\n\n const sf = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\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 === 'NgModule') {\n const declarations = extractArrayProperty(dec, 'declarations', source);\n modules.push({ path, declarations, decoratorPos: dec.getStart() });\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n });\n\n return modules;\n}\n\nfunction extractArrayProperty(decorator: ts.Decorator, propName: string, source: string): string[] {\n const call = decorator.expression as ts.CallExpression;\n if (!call.arguments[0] || !ts.isObjectLiteralExpression(call.arguments[0])) return [];\n for (const prop of call.arguments[0].properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === propName) {\n if (ts.isArrayLiteralExpression(prop.initializer)) {\n return prop.initializer.elements\n .filter(ts.isIdentifier)\n .map(id => id.text);\n }\n }\n }\n return [];\n}\n\nfunction findDeclaringModule(modules: NgModuleInfo[], componentClassName: string): NgModuleInfo | undefined {\n return modules.find(m => m.declarations.includes(componentClassName));\n}\n\n// --- Import Addition ---\n\nfunction addImportsToFile(source: string, filePath: string, decoratorStartHint: number, imports: ImportToAdd[], useClassArray: boolean): string {\n const sf = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n\n // Find the imports array in the decorator closest to decoratorStartHint\n const importsArrayInfo = findDecoratorImportsArray(sf, source, decoratorStartHint);\n if (!importsArrayInfo) return source;\n\n const { arrayNode, decoratorType } = importsArrayInfo;\n\n // Determine what's already in the imports array\n const existingSymbols = new Set<string>();\n const existingSpreads = new Set<string>();\n for (const el of arrayNode.elements) {\n if (ts.isSpreadElement(el) && ts.isIdentifier(el.expression)) {\n existingSpreads.add(el.expression.text);\n } else if (ts.isIdentifier(el)) {\n existingSymbols.add(el.text);\n }\n }\n\n // Filter out already-present imports and compute what to add/remove\n const toAdd: ImportToAdd[] = [];\n const toRemoveFromArray: string[] = []; // individual class names to consolidate\n\n for (const imp of imports) {\n if (imp.isSpread) {\n if (existingSpreads.has(imp.symbol)) continue; // Already has ...EUI_X\n toAdd.push(imp);\n // Consolidate: remove individual class names covered by this array\n if (useClassArray) {\n const coveredClasses = getClassNamesForArray(imp.symbol);\n for (const cls of coveredClasses) {\n if (existingSymbols.has(cls)) toRemoveFromArray.push(cls);\n }\n }\n } else {\n if (existingSymbols.has(imp.symbol)) continue;\n // Also skip if a spread already covers this class\n const coveringArray = imports.find(i => i.isSpread && getClassNamesForArray(i.symbol).includes(imp.symbol));\n if (coveringArray && (existingSpreads.has(coveringArray.symbol) || toAdd.some(a => a.symbol === coveringArray.symbol))) continue;\n toAdd.push(imp);\n }\n }\n\n if (toAdd.length === 0 && toRemoveFromArray.length === 0) return source;\n\n // Build new array content\n let result = source;\n result = updateDecoratorImportsArray(result, filePath, arrayNode, toAdd, toRemoveFromArray);\n\n // Add ES imports\n result = addEsImports(result, filePath, toAdd);\n\n // Remove consolidated class names from ES imports\n if (toRemoveFromArray.length > 0) {\n result = removeFromEsImports(result, filePath, toRemoveFromArray);\n }\n\n return result;\n}\n\ninterface ImportsArrayInfo {\n arrayNode: ts.ArrayLiteralExpression;\n decoratorType: 'Component' | 'NgModule';\n}\n\nfunction findDecoratorImportsArray(sf: ts.SourceFile, source: string, decoratorStartHint: number): ImportsArrayInfo | null {\n let found: ImportsArrayInfo | null = null;\n\n const visit = (node: ts.Node): void => {\n if (found) return;\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)) continue;\n if (!ts.isIdentifier(dec.expression.expression)) continue;\n const decName = dec.expression.expression.text;\n if (decName !== 'Component' && decName !== 'NgModule') continue;\n if (Math.abs(dec.getStart() - decoratorStartHint) > 5) continue; // Match by position\n\n const metadata = dec.expression.arguments[0];\n if (!ts.isObjectLiteralExpression(metadata)) continue;\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 found = { arrayNode: prop.initializer, decoratorType: decName as 'Component' | 'NgModule' };\n return;\n }\n }\n }\n\n // No imports array found — create one\n if (!found && decName === 'Component') {\n // We need to add `imports: []` to the decorator\n // Insert after the last property\n const lastProp = metadata.properties[metadata.properties.length - 1];\n if (lastProp) {\n const insertPos = lastProp.getEnd();\n const indent = detectIndent(source, metadata.getStart());\n const insertion = `,\\n${indent} imports: []`;\n const newSource = source.slice(0, insertPos) + insertion + source.slice(insertPos);\n // Re-parse to get the array node\n const newSf = ts.createSourceFile('', newSource, ts.ScriptTarget.Latest, true);\n const newArray = findImportsArrayInSource(newSf);\n if (newArray) {\n // We can't return a node from a different source file in the general case.\n // Instead, we'll handle the \"no imports array\" case by adding it inline.\n found = null; // Will be handled separately\n }\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return found;\n}\n\nfunction findImportsArrayInSource(sf: ts.SourceFile): ts.ArrayLiteralExpression | null {\n let found: ts.ArrayLiteralExpression | null = null;\n const visit = (node: ts.Node): void => {\n if (found) return;\n if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === 'imports' && ts.isArrayLiteralExpression(node.initializer)) {\n found = node.initializer;\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n return found;\n}\n\nfunction updateDecoratorImportsArray(source: string, filePath: string, arrayNode: ts.ArrayLiteralExpression, toAdd: ImportToAdd[], toRemove: string[]): string {\n const sf = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n\n // Rebuild the array content\n const existingElements: string[] = [];\n for (const el of arrayNode.elements) {\n const text = source.slice(el.getStart(sf), el.getEnd()).trim();\n // Check if this element should be removed (consolidation)\n if (ts.isIdentifier(el) && toRemove.includes(el.text)) continue;\n existingElements.push(text);\n }\n\n // Add new entries\n for (const imp of toAdd) {\n const entry = imp.isSpread ? `...${imp.symbol}` : imp.symbol;\n if (!existingElements.includes(entry)) {\n existingElements.push(entry);\n }\n }\n\n // Determine formatting\n const arrayStart = arrayNode.getStart(sf);\n const arrayEnd = arrayNode.getEnd();\n const originalText = source.slice(arrayStart, arrayEnd);\n const isMultiline = originalText.includes('\\n');\n\n let newArrayText: string;\n if (isMultiline || existingElements.length > 3) {\n const indent = detectIndent(source, arrayStart);\n const itemIndent = indent + ' ';\n newArrayText = `[\\n${existingElements.map(e => `${itemIndent}${e},`).join('\\n')}\\n${indent}]`;\n } else {\n newArrayText = `[${existingElements.join(', ')}]`;\n }\n\n return source.slice(0, arrayStart) + newArrayText + source.slice(arrayEnd);\n}\n\nfunction addEsImports(source: string, filePath: string, imports: ImportToAdd[]): string {\n let result = source;\n\n // Group by import path\n const byPath = new Map<string, string[]>();\n for (const imp of imports) {\n const existing = byPath.get(imp.importPath) || [];\n existing.push(imp.symbol);\n byPath.set(imp.importPath, existing);\n }\n\n for (const [importPath, symbols] of byPath) {\n const sf = ts.createSourceFile(filePath, result, ts.ScriptTarget.Latest, true);\n\n // Check if there's already an import from this path\n const existingImport = sf.statements.find(\n (s): s is ts.ImportDeclaration =>\n ts.isImportDeclaration(s) && ts.isStringLiteral(s.moduleSpecifier) && s.moduleSpecifier.text === importPath,\n );\n\n if (existingImport?.importClause?.namedBindings && ts.isNamedImports(existingImport.importClause.namedBindings)) {\n // Extend existing import\n const namedBindings = existingImport.importClause.namedBindings;\n const existingNames = namedBindings.elements.map(el => el.name.text);\n const newNames = symbols.filter(s => !existingNames.includes(s));\n if (newNames.length === 0) continue;\n\n const allNames = [...existingNames, ...newNames].sort();\n const newClause = `{ ${allNames.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n } else {\n // Add new import statement\n const sortedSymbols = [...symbols].sort();\n const newImport = `import { ${sortedSymbols.join(', ')} } from '${importPath}';\\n`;\n\n // Insert after the last existing import\n const lastImport = [...sf.statements].reverse().find(ts.isImportDeclaration);\n if (lastImport) {\n const pos = lastImport.getEnd();\n result = result.slice(0, pos) + '\\n' + newImport.trimEnd() + result.slice(pos);\n } else {\n result = newImport + result;\n }\n }\n }\n\n return result;\n}\n\nfunction detectIndent(source: string, pos: number): string {\n const lineStart = source.lastIndexOf('\\n', pos - 1) + 1;\n const match = source.slice(lineStart, pos).match(/^(\\s*)/);\n return match ? match[1] : '';\n}\n\nfunction removeFromEsImports(source: string, filePath: string, symbolsToRemove: string[]): string {\n let result = source;\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 existingNames = namedBindings.elements.map(el => el.name.text);\n const remaining = existingNames.filter(n => !symbolsToRemove.includes(n));\n\n if (remaining.length === existingNames.length) continue; // Nothing to remove from this import\n\n if (remaining.length === 0) {\n // Remove the entire import statement\n result = result.slice(0, stmt.getStart(sf)) + result.slice(stmt.getEnd()).replace(/^\\r?\\n/, '');\n } else {\n const newClause = `{ ${remaining.join(', ')} }`;\n result = result.slice(0, namedBindings.getStart(sf)) + newClause + result.slice(namedBindings.getEnd());\n }\n break; // Only process the first matching import for the consolidated symbols\n }\n\n return result;\n}\n",
2298
2298
  "displayName": "Schema",
2299
2299
  "properties": [
2300
2300
  {
@@ -2305,33 +2305,33 @@
2305
2305
  "type": "boolean",
2306
2306
  "indexKey": "",
2307
2307
  "optional": true,
2308
- "description": "<p>Whether to perform a dry run without making changes</p>\n",
2309
- "line": 7,
2310
- "rawdescription": "\nWhether to perform a dry run without making changes"
2308
+ "description": "",
2309
+ "line": 9,
2310
+ "rawdescription": "\n"
2311
2311
  },
2312
2312
  {
2313
- "name": "mwp",
2313
+ "name": "path",
2314
2314
  "coverageIgnore": false,
2315
2315
  "deprecated": false,
2316
2316
  "deprecationMessage": "",
2317
- "type": "boolean",
2317
+ "type": "string",
2318
2318
  "indexKey": "",
2319
2319
  "optional": true,
2320
- "description": "<p>Whether to apply MyWorkplace-specific replacements</p>\n",
2321
- "line": 5,
2322
- "rawdescription": "\nWhether to apply MyWorkplace-specific replacements"
2320
+ "description": "",
2321
+ "line": 8,
2322
+ "rawdescription": "\n"
2323
2323
  },
2324
2324
  {
2325
- "name": "path",
2325
+ "name": "useClassArray",
2326
2326
  "coverageIgnore": false,
2327
2327
  "deprecated": false,
2328
2328
  "deprecationMessage": "",
2329
- "type": "string",
2329
+ "type": "boolean",
2330
2330
  "indexKey": "",
2331
2331
  "optional": true,
2332
- "description": "<p>The path to scan for files to migrate</p>\n",
2333
- "line": 3,
2334
- "rawdescription": "\nThe path to scan for files to migrate"
2332
+ "description": "",
2333
+ "line": 10,
2334
+ "rawdescription": "\n"
2335
2335
  }
2336
2336
  ],
2337
2337
  "indexSignatures": [],
@@ -2489,12 +2489,12 @@
2489
2489
  },
2490
2490
  {
2491
2491
  "name": "Schema",
2492
- "id": "interface-Schema-c0c08f5e83da9afa13ce8375f982fb280b9bde854e00c914f41b04d44deecd531496c2cee264b50314e92a6260c26cebe35741a2cf5ec068d8b6da5c5267539e-7",
2493
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
2492
+ "id": "interface-Schema-311bef7d5e4b40b356b0fdb5e35dd89e48a5c5beec29eeb865c22c2ca1c4c4fb1fd0bb4391ed0b33825a6d1d744bc3a2e9822b347fbc686a537e15b170c279dd-7",
2493
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
2494
2494
  "deprecated": false,
2495
2495
  "deprecationMessage": "",
2496
2496
  "type": "interface",
2497
- "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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst OLD_NAME = 'euiButtonCall';\nconst NEW_NAME = 'euiCTAButton';\n\nexport function migrateEuiButton(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(OLD_NAME)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS property access usages\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {\n if (!original.includes(OLD_NAME)) return;\n\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"${OLD_NAME}\" has been renamed to \"${NEW_NAME}\". Update this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Renamed '${OLD_NAME}' → '${NEW_NAME}' on elements with euiButton in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(OLD_NAME)) {\n ts.forEachChild(node, visit); return; \n}\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, text: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction hasEuiButtonAttribute(element: TmplAstElement): boolean {\n return element.attributes.some((a) => a.name === 'euiButton') ||\n element.inputs.some((i) => i.name === 'euiButton');\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (hasEuiButtonAttribute(node)) collectRenames(node, edits);\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n if (attr.name === OLD_NAME) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n for (const input of element.inputs) {\n if (input.name === OLD_NAME) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2497
+ "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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\nconst CHIP_LIST_TAG = 'eui-chip-list';\nconst CHIP_LIST_ATTR = 'euiChipList';\nconst CHIP_TAG = 'eui-chip';\nconst CHIP_ATTR = 'euiChip';\n\nconst PROPAGATED_INPUTS = new Set([\n 'euiPrimary', 'euiSecondary', 'euiSuccess', 'euiInfo', 'euiWarning',\n 'euiDanger', 'euiAccent', 'euiVariant', 'euiSizeS', 'euiSizeVariant',\n 'euiOutline', 'euiDisabled',\n]);\n\nconst WARN_PROPERTIES = new Set([...PROPAGATED_INPUTS, 'chipRemove', 'isChipsRemovable', 'chipsLabelTruncateCount',\n 'maxVisibleChipsCount', 'isMaxVisibleChipsOpened', 'toggleLinkMoreLabel', 'toggleLinkLessLabel',\n 'isChipsSorted', 'chipsSortOrder']);\n\nconst REMOVED_INPUTS = new Set(['maxVisibleChipsCount', 'isMaxVisibleChipsOpened', 'toggleLinkMoreLabel', 'toggleLinkLessLabel', 'isChipsSorted', 'chipsSortOrder']);\n\nconst TRUNCATE_PIPE_IMPORT = 'EuiTruncatePipe';\nconst TRUNCATE_PIPE_PATH = '@eui/components/pipes';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\nexport function migrateEuiChipList(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n const filesNeedingTruncateImport = new Set<string>();\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(CHIP_LIST_TAG) && !original.includes(CHIP_LIST_ATTR)) return;\n\n let result: string;\n let addedTruncate = false;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n if (result !== original && result.includes('euiTruncate') && !original.includes('euiTruncate')) {\n // Find the associated .ts file\n const tsPath = path.replace(/\\.html$/, '.ts');\n if (tree.exists(tsPath)) {\n filesNeedingTruncateImport.add(tsPath);\n } else {\n // Try component naming convention\n const componentTsPath = path.replace(/\\.html$/, '.component.ts');\n if (tree.exists(componentTsPath)) {\n filesNeedingTruncateImport.add(componentTsPath);\n }\n }\n }\n } else {\n result = migrateInlineTemplates(original);\n if (result !== original && result.includes('euiTruncate') && !original.includes('euiTruncate')) {\n addedTruncate = true;\n }\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would move variant/size/outline inputs to child eui-chip in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n if (addedTruncate) {\n filesNeedingTruncateImport.add(path);\n }\n\n // Warn about TS usages of removed properties\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {\n if ([...WARN_PROPERTIES].some((p) => original.includes(p))) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && WARN_PROPERTIES.has(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${path}:${line + 1} - \"${node.name.text}\" has been removed from eui-chip-list. Move it to individual eui-chip elements.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n }\n });\n\n // Add EuiTruncatePipe import to component files that need it\n for (const tsPath of filesNeedingTruncateImport) {\n const buffer = tree.read(tsPath);\n if (!buffer) continue;\n const source = buffer.toString('utf-8');\n if (source.includes(TRUNCATE_PIPE_IMPORT)) continue;\n const result = addTruncatePipeImport(source, tsPath);\n if (result !== source) {\n if (!options.dryRun) {\n tree.overwrite(tsPath, result);\n }\n }\n }\n\n context.logger.info(`Migrated eui-chip-list inputs/outputs to child eui-chip in ${count} file(s).`);\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('.html') && !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 addTruncatePipeImport(source: string, filePath: string): string {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n const edits: Edit[] = [];\n\n // 1. Add ES import statement for EuiTruncatePipe\n let hasEsImport = false;\n let lastImportEnd = 0;\n\n for (const stmt of sourceFile.statements) {\n if (ts.isImportDeclaration(stmt)) {\n lastImportEnd = stmt.getEnd();\n const moduleSpec = (stmt.moduleSpecifier as ts.StringLiteral).text;\n if (moduleSpec === TRUNCATE_PIPE_PATH) {\n const namedBindings = stmt.importClause?.namedBindings;\n if (namedBindings && ts.isNamedImports(namedBindings)) {\n if (namedBindings.elements.some((el) => el.name.text === TRUNCATE_PIPE_IMPORT)) {\n hasEsImport = true;\n } else {\n // Add to existing import from same path\n const lastEl = namedBindings.elements[namedBindings.elements.length - 1];\n edits.push({ start: lastEl.getEnd(), end: lastEl.getEnd(), replacement: `, ${TRUNCATE_PIPE_IMPORT}` });\n hasEsImport = true;\n }\n }\n }\n }\n }\n\n if (!hasEsImport) {\n const importStatement = `\\nimport { ${TRUNCATE_PIPE_IMPORT} } from '${TRUNCATE_PIPE_PATH}';`;\n edits.push({ start: lastImportEnd, end: lastImportEnd, replacement: importStatement });\n }\n\n // 2. Add EuiTruncatePipe to @Component imports array\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 arr = prop.initializer;\n const arrText = source.slice(arr.getStart(sourceFile), arr.getEnd());\n if (arrText.includes(TRUNCATE_PIPE_IMPORT)) continue;\n if (arr.elements.length > 0) {\n const lastElement = arr.elements[arr.elements.length - 1];\n edits.push({ start: lastElement.getEnd(), end: lastElement.getEnd(), replacement: `,\\n ${TRUNCATE_PIPE_IMPORT}` });\n } else {\n edits.push({ start: arr.getStart(sourceFile) + 1, end: arr.getEnd() - 1, replacement: TRUNCATE_PIPE_IMPORT });\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: Edit[] = [];\n\n visitNodes(parsed.nodes, source, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(CHIP_LIST_TAG) && !rawTemplate.includes(CHIP_LIST_ATTR)) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, replacement: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, changes);\n}\n\nfunction visitNodes(nodes: TmplAstNode[], source: string, edits: Edit[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (isChipListElement(node)) {\n migrateChipListElement(node, source, edits);\n }\n visitNodes(node.children, source, edits);\n }\n }\n}\n\nfunction isChipListElement(element: TmplAstElement): boolean {\n if (element.name === CHIP_LIST_TAG) return true;\n return element.attributes.some((a) => a.name === CHIP_LIST_ATTR);\n}\n\nfunction isChipElement(element: TmplAstElement): boolean {\n if (element.name === CHIP_TAG) return true;\n return element.attributes.some((a) => a.name === CHIP_ATTR);\n}\n\nfunction findChildChips(nodes: TmplAstNode[]): TmplAstElement[] {\n const chips: TmplAstElement[] = [];\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (isChipElement(node)) {\n chips.push(node);\n } else {\n chips.push(...findChildChips(node.children));\n }\n }\n }\n return chips;\n}\n\nfunction migrateChipListElement(element: TmplAstElement, source: string, edits: Edit[]): void {\n const childChips = findChildChips(element.children);\n const insertions: string[] = [];\n let truncateValue: string | null = null;\n\n // Collect and remove propagated static attributes\n for (const attr of element.attributes) {\n if (PROPAGATED_INPUTS.has(attr.name)) {\n edits.push(removalEdit(attr, source));\n insertions.push(attr.value ? `${attr.name}=\"${attr.value}\"` : attr.name);\n }\n if (attr.name === 'isChipsRemovable') {\n edits.push(removalEdit(attr, source));\n insertions.push('isChipRemovable');\n }\n if (attr.name === 'chipsLabelTruncateCount') {\n edits.push(removalEdit(attr, source));\n truncateValue = attr.value || null;\n }\n if (REMOVED_INPUTS.has(attr.name)) {\n edits.push(removalEdit(attr, source));\n }\n }\n\n // Collect and remove propagated bound inputs\n for (const input of element.inputs) {\n if (PROPAGATED_INPUTS.has(input.name)) {\n edits.push(removalEdit(input, source));\n const raw = source.slice(input.sourceSpan.start.offset, input.sourceSpan.end.offset);\n insertions.push(raw);\n }\n if (input.name === 'isChipsRemovable') {\n edits.push(removalEdit(input, source));\n const valueText = extractBindingValue(input, source);\n insertions.push(`[isChipRemovable]=\"${valueText}\"`);\n }\n if (input.name === 'chipsLabelTruncateCount') {\n edits.push(removalEdit(input, source));\n truncateValue = extractBindingValue(input, source);\n }\n if (REMOVED_INPUTS.has(input.name)) {\n edits.push(removalEdit(input, source));\n }\n }\n\n // Collect and remove (chipRemove) output\n let chipRemoveHandler: string | null = null;\n for (const output of element.outputs) {\n if (output.name === 'chipRemove') {\n edits.push(removalEdit(output, source));\n chipRemoveHandler = extractHandlerExpression(output, source);\n }\n }\n\n if (chipRemoveHandler) {\n insertions.push(`(remove)=\"${chipRemoveHandler}\"`);\n }\n\n // Add collected attributes to each child eui-chip\n if (insertions.length > 0) {\n for (const chip of childChips) {\n const existingNames = getExistingAttrNames(chip);\n const toInsert = insertions.filter((ins) => {\n const name = extractAttrName(ins);\n return !existingNames.has(name);\n });\n if (toInsert.length > 0) {\n const insertPos = chip.startSourceSpan.end.offset - 1;\n edits.push({ start: insertPos, end: insertPos, replacement: ' ' + toInsert.join(' ') });\n }\n }\n }\n\n // Add euiTruncate pipe to chip label content\n if (truncateValue) {\n for (const chip of childChips) {\n const labelEdit = buildTruncatePipeEdit(chip, source, truncateValue);\n if (labelEdit) edits.push(labelEdit);\n }\n }\n}\n\nfunction buildTruncatePipeEdit(chip: TmplAstElement, source: string, truncateValue: string): Edit | null {\n // Find <span euiLabel>...</span> inside the chip\n const labelEl = findLabelElement(chip.children);\n if (labelEl && labelEl.endSourceSpan) {\n const contentStart = labelEl.startSourceSpan.end.offset;\n const contentEnd = labelEl.endSourceSpan.start.offset;\n const content = source.slice(contentStart, contentEnd);\n if (content && !content.includes('euiTruncate')) {\n const trimmed = content.trim();\n const interpMatch = trimmed.match(/^\\{\\{\\s*(.+?)\\s*\\}\\}$/);\n if (interpMatch) {\n return { start: contentStart, end: contentEnd, replacement: `{{ ${interpMatch[1]} | euiTruncate: ${truncateValue} }}` };\n }\n return { start: contentStart, end: contentEnd, replacement: `{{ '${trimmed}' | euiTruncate: ${truncateValue} }}` };\n }\n }\n\n // Check direct text content inside chip (no label element)\n if (chip.endSourceSpan) {\n const chipContentStart = chip.startSourceSpan.end.offset;\n const chipContentEnd = chip.endSourceSpan.start.offset;\n const chipContent = source.slice(chipContentStart, chipContentEnd);\n const trimmed = chipContent.trim();\n const interpMatch = trimmed.match(/^\\{\\{\\s*(.+?)\\s*\\}\\}$/);\n if (interpMatch && !chipContent.includes('euiTruncate')) {\n return { start: chipContentStart, end: chipContentEnd, replacement: `{{ ${interpMatch[1]} | euiTruncate: ${truncateValue} }}` };\n }\n }\n return null;\n}\n\nfunction findLabelElement(nodes: TmplAstNode[]): TmplAstElement | null {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.attributes.some((a) => a.name === 'euiLabel')) return node;\n const nested = findLabelElement(node.children);\n if (nested) return nested;\n }\n }\n return null;\n}\n\nfunction getExistingAttrNames(element: TmplAstElement): Set<string> {\n const names = new Set<string>();\n for (const attr of element.attributes) names.add(attr.name);\n for (const input of element.inputs) names.add(input.name);\n for (const output of element.outputs) names.add(output.name);\n return names;\n}\n\nfunction extractAttrName(insertion: string): string {\n const outputMatch = insertion.match(/^\\(([^)]+)\\)/);\n if (outputMatch) return outputMatch[1];\n const inputMatch = insertion.match(/^\\[([^\\]]+)\\]/);\n if (inputMatch) return inputMatch[1];\n return insertion.split('=')[0];\n}\n\nfunction removalEdit(node: TmplAstTextAttribute | TmplAstBoundAttribute | TmplAstBoundEvent, source: string): Edit {\n let start = node.sourceSpan.start.offset;\n while (start > 0 && (source[start - 1] === ' ' || source[start - 1] === '\\t')) {\n start--;\n }\n return { start, end: node.sourceSpan.end.offset, replacement: '' };\n}\n\nfunction extractBindingValue(input: TmplAstBoundAttribute, source: string): string {\n const raw = source.slice(input.sourceSpan.start.offset, input.sourceSpan.end.offset);\n const match = raw.match(/=[\"']([^\"']*)[\"']/);\n return match ? match[1] : 'true';\n}\n\nfunction extractHandlerExpression(output: TmplAstBoundEvent, source: string): string {\n const raw = source.slice(output.sourceSpan.start.offset, output.sourceSpan.end.offset);\n const match = raw.match(/=[\"']([^\"']*)[\"']/);\n return match ? match[1] : '';\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\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 seen.set(`${edit.start}:${edit.end}`, edit);\n }\n return Array.from(seen.values());\n}\n",
2498
2498
  "displayName": "Schema",
2499
2499
  "properties": [
2500
2500
  {
@@ -2506,7 +2506,7 @@
2506
2506
  "indexKey": "",
2507
2507
  "optional": true,
2508
2508
  "description": "",
2509
- "line": 8,
2509
+ "line": 28,
2510
2510
  "rawdescription": "\n"
2511
2511
  },
2512
2512
  {
@@ -2518,7 +2518,7 @@
2518
2518
  "indexKey": "",
2519
2519
  "optional": true,
2520
2520
  "description": "",
2521
- "line": 7,
2521
+ "line": 27,
2522
2522
  "rawdescription": "\n"
2523
2523
  }
2524
2524
  ],
@@ -2536,12 +2536,12 @@
2536
2536
  },
2537
2537
  {
2538
2538
  "name": "Schema",
2539
- "id": "interface-Schema-39d3d52e788050bebc4e0b99ed0756f7e9727556cb090ae8796bd4261a56463fe1f479c322b23028cd4134d71e4d1dc44cd248ac62a9a148b5fc46a665466f7c-8",
2540
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
2539
+ "id": "interface-Schema-869dfc324e9111966817cbebb3553eabfe200acfe33bb77efa71a6c46e1cba0ff5852de7b9ade3060f87264035b99591361331a9e0622daaac22b8d59146c761-8",
2540
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
2541
2541
  "deprecated": false,
2542
2542
  "deprecationMessage": "",
2543
2543
  "type": "interface",
2544
- "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst REMOVED_INPUTS = new Set(['isSquared']);\n\nexport function migrateEuiChip(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes('eui-chip') && !original.includes('euiChip')) return;\n\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would remove 'isSquared' input in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS usages inline\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && original.includes('isSquared')) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === 'isSquared') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"isSquared\" is no longer a valid input on eui-chip. Remove this assignment.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Removed deprecated eui-chip 'isSquared' input from ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const removals: { start: number; end: number }[] = [];\n\n visitNodes(parsed.nodes, removals);\n\n let result = source;\n for (const { start, end } of removals.sort((a, b) => b.start - a.start)) {\n let adjustedStart = start;\n while (adjustedStart > 0 && (result[adjustedStart - 1] === ' ' || result[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n result = result.slice(0, adjustedStart) + result.slice(end);\n }\n\n return result;\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const templateRegex = /template\\s*:\\s*`([^`]*)`/gs;\n return source.replace(templateRegex, (match, templateContent: string) => {\n if (!templateContent.includes('eui-chip') && !templateContent.includes('euiChip')) return match;\n const migrated = migrateTemplate(templateContent);\n if (migrated === templateContent) return match;\n return match.replace(templateContent, migrated);\n });\n}\n\nfunction isChipElement(element: TmplAstElement): boolean {\n if (element.name === 'eui-chip') return true;\n return element.attributes.some((a) => a.name === 'euiChip');\n}\n\nfunction visitNodes(nodes: TmplAstNode[], removals: { start: number; end: number }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (isChipElement(node)) collectRemovals(node, removals);\n visitNodes(node.children, removals);\n }\n }\n}\n\nfunction collectRemovals(element: TmplAstElement, removals: { start: number; end: number }[]): void {\n for (const attr of element.attributes) {\n if (REMOVED_INPUTS.has(attr.name)) {\n removals.push(getAttributeSpan(attr));\n }\n }\n for (const input of element.inputs) {\n if (REMOVED_INPUTS.has(input.name)) {\n removals.push(getAttributeSpan(input));\n }\n }\n}\n\nfunction getAttributeSpan(attr: TmplAstTextAttribute | TmplAstBoundAttribute): { start: number; end: number } {\n return { start: attr.sourceSpan.start.offset, end: attr.sourceSpan.end.offset };\n}\n",
2544
+ "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst COMPONENT_TAG = 'eui-discussion-thread';\n\nexport function migrateEuiDiscussionThread(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would remove [trackBy] binding in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS usages inline\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && original.includes('trackByFn')) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === 'trackByFn') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"trackByFn\" has been removed from ${COMPONENT_TAG}. Remove this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Removed trackByFn-based [trackBy] bindings from ${COMPONENT_TAG} in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const removals: { start: number; end: number }[] = [];\n\n visitNodes(parsed.nodes, source, removals);\n\n let result = source;\n for (const { start, end } of removals.sort((a, b) => b.start - a.start)) {\n let adjustedStart = start;\n while (adjustedStart > 0 && (result[adjustedStart - 1] === ' ' || result[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n result = result.slice(0, adjustedStart) + result.slice(end);\n }\n\n return result;\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const templateRegex = /template\\s*:\\s*`([^`]*)`/gs;\n return source.replace(templateRegex, (match, templateContent: string) => {\n if (!templateContent.includes(COMPONENT_TAG)) return match;\n const migrated = migrateTemplate(templateContent);\n if (migrated === templateContent) return match;\n return match.replace(templateContent, migrated);\n });\n}\n\nfunction visitNodes(nodes: TmplAstNode[], source: string, removals: { start: number; end: number }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) collectRemovals(node, source, removals);\n visitNodes(node.children, source, removals);\n }\n }\n}\n\nfunction collectRemovals(element: TmplAstElement, source: string, removals: { start: number; end: number }[]): void {\n for (const input of element.inputs) {\n if (input.name === 'trackBy') {\n const valueSource = source.slice(input.sourceSpan.start.offset, input.sourceSpan.end.offset);\n if (valueSource.includes('trackByFn')) {\n removals.push({ start: input.sourceSpan.start.offset, end: input.sourceSpan.end.offset });\n }\n }\n }\n}\n",
2545
2545
  "displayName": "Schema",
2546
2546
  "properties": [
2547
2547
  {
@@ -2583,12 +2583,12 @@
2583
2583
  },
2584
2584
  {
2585
2585
  "name": "Schema",
2586
- "id": "interface-Schema-311bef7d5e4b40b356b0fdb5e35dd89e48a5c5beec29eeb865c22c2ca1c4c4fb1fd0bb4391ed0b33825a6d1d744bc3a2e9822b347fbc686a537e15b170c279dd-9",
2587
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
2586
+ "id": "interface-Schema-375dc0924084a2acbafe4a6a32577d59f631c9a386d151180d8fb1c89e7e7cd23da9fd459e597592ed823692adb6ad2633c50baf16621f003246e8c9bb1c6ce0-9",
2587
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
2588
2588
  "deprecated": false,
2589
2589
  "deprecationMessage": "",
2590
2590
  "type": "interface",
2591
- "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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\nconst CHIP_LIST_TAG = 'eui-chip-list';\nconst CHIP_LIST_ATTR = 'euiChipList';\nconst CHIP_TAG = 'eui-chip';\nconst CHIP_ATTR = 'euiChip';\n\nconst PROPAGATED_INPUTS = new Set([\n 'euiPrimary', 'euiSecondary', 'euiSuccess', 'euiInfo', 'euiWarning',\n 'euiDanger', 'euiAccent', 'euiVariant', 'euiSizeS', 'euiSizeVariant',\n 'euiOutline', 'euiDisabled',\n]);\n\nconst WARN_PROPERTIES = new Set([...PROPAGATED_INPUTS, 'chipRemove', 'isChipsRemovable', 'chipsLabelTruncateCount',\n 'maxVisibleChipsCount', 'isMaxVisibleChipsOpened', 'toggleLinkMoreLabel', 'toggleLinkLessLabel',\n 'isChipsSorted', 'chipsSortOrder']);\n\nconst REMOVED_INPUTS = new Set(['maxVisibleChipsCount', 'isMaxVisibleChipsOpened', 'toggleLinkMoreLabel', 'toggleLinkLessLabel', 'isChipsSorted', 'chipsSortOrder']);\n\nconst TRUNCATE_PIPE_IMPORT = 'EuiTruncatePipe';\nconst TRUNCATE_PIPE_PATH = '@eui/components/pipes';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\nexport function migrateEuiChipList(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n const filesNeedingTruncateImport = new Set<string>();\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(CHIP_LIST_TAG) && !original.includes(CHIP_LIST_ATTR)) return;\n\n let result: string;\n let addedTruncate = false;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n if (result !== original && result.includes('euiTruncate') && !original.includes('euiTruncate')) {\n // Find the associated .ts file\n const tsPath = path.replace(/\\.html$/, '.ts');\n if (tree.exists(tsPath)) {\n filesNeedingTruncateImport.add(tsPath);\n } else {\n // Try component naming convention\n const componentTsPath = path.replace(/\\.html$/, '.component.ts');\n if (tree.exists(componentTsPath)) {\n filesNeedingTruncateImport.add(componentTsPath);\n }\n }\n }\n } else {\n result = migrateInlineTemplates(original);\n if (result !== original && result.includes('euiTruncate') && !original.includes('euiTruncate')) {\n addedTruncate = true;\n }\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would move variant/size/outline inputs to child eui-chip in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n if (addedTruncate) {\n filesNeedingTruncateImport.add(path);\n }\n\n // Warn about TS usages of removed properties\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {\n if ([...WARN_PROPERTIES].some((p) => original.includes(p))) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && WARN_PROPERTIES.has(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${path}:${line + 1} - \"${node.name.text}\" has been removed from eui-chip-list. Move it to individual eui-chip elements.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n }\n });\n\n // Add EuiTruncatePipe import to component files that need it\n for (const tsPath of filesNeedingTruncateImport) {\n const buffer = tree.read(tsPath);\n if (!buffer) continue;\n const source = buffer.toString('utf-8');\n if (source.includes(TRUNCATE_PIPE_IMPORT)) continue;\n const result = addTruncatePipeImport(source, tsPath);\n if (result !== source) {\n if (!options.dryRun) {\n tree.overwrite(tsPath, result);\n }\n }\n }\n\n context.logger.info(`Migrated eui-chip-list inputs/outputs to child eui-chip in ${count} file(s).`);\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('.html') && !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 addTruncatePipeImport(source: string, filePath: string): string {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n const edits: Edit[] = [];\n\n // 1. Add ES import statement for EuiTruncatePipe\n let hasEsImport = false;\n let lastImportEnd = 0;\n\n for (const stmt of sourceFile.statements) {\n if (ts.isImportDeclaration(stmt)) {\n lastImportEnd = stmt.getEnd();\n const moduleSpec = (stmt.moduleSpecifier as ts.StringLiteral).text;\n if (moduleSpec === TRUNCATE_PIPE_PATH) {\n const namedBindings = stmt.importClause?.namedBindings;\n if (namedBindings && ts.isNamedImports(namedBindings)) {\n if (namedBindings.elements.some((el) => el.name.text === TRUNCATE_PIPE_IMPORT)) {\n hasEsImport = true;\n } else {\n // Add to existing import from same path\n const lastEl = namedBindings.elements[namedBindings.elements.length - 1];\n edits.push({ start: lastEl.getEnd(), end: lastEl.getEnd(), replacement: `, ${TRUNCATE_PIPE_IMPORT}` });\n hasEsImport = true;\n }\n }\n }\n }\n }\n\n if (!hasEsImport) {\n const importStatement = `\\nimport { ${TRUNCATE_PIPE_IMPORT} } from '${TRUNCATE_PIPE_PATH}';`;\n edits.push({ start: lastImportEnd, end: lastImportEnd, replacement: importStatement });\n }\n\n // 2. Add EuiTruncatePipe to @Component imports array\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 arr = prop.initializer;\n const arrText = source.slice(arr.getStart(sourceFile), arr.getEnd());\n if (arrText.includes(TRUNCATE_PIPE_IMPORT)) continue;\n if (arr.elements.length > 0) {\n const lastElement = arr.elements[arr.elements.length - 1];\n edits.push({ start: lastElement.getEnd(), end: lastElement.getEnd(), replacement: `,\\n ${TRUNCATE_PIPE_IMPORT}` });\n } else {\n edits.push({ start: arr.getStart(sourceFile) + 1, end: arr.getEnd() - 1, replacement: TRUNCATE_PIPE_IMPORT });\n }\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: Edit[] = [];\n\n visitNodes(parsed.nodes, source, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(CHIP_LIST_TAG) && !rawTemplate.includes(CHIP_LIST_ATTR)) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, replacement: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, changes);\n}\n\nfunction visitNodes(nodes: TmplAstNode[], source: string, edits: Edit[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (isChipListElement(node)) {\n migrateChipListElement(node, source, edits);\n }\n visitNodes(node.children, source, edits);\n }\n }\n}\n\nfunction isChipListElement(element: TmplAstElement): boolean {\n if (element.name === CHIP_LIST_TAG) return true;\n return element.attributes.some((a) => a.name === CHIP_LIST_ATTR);\n}\n\nfunction isChipElement(element: TmplAstElement): boolean {\n if (element.name === CHIP_TAG) return true;\n return element.attributes.some((a) => a.name === CHIP_ATTR);\n}\n\nfunction findChildChips(nodes: TmplAstNode[]): TmplAstElement[] {\n const chips: TmplAstElement[] = [];\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (isChipElement(node)) {\n chips.push(node);\n } else {\n chips.push(...findChildChips(node.children));\n }\n }\n }\n return chips;\n}\n\nfunction migrateChipListElement(element: TmplAstElement, source: string, edits: Edit[]): void {\n const childChips = findChildChips(element.children);\n const insertions: string[] = [];\n let truncateValue: string | null = null;\n\n // Collect and remove propagated static attributes\n for (const attr of element.attributes) {\n if (PROPAGATED_INPUTS.has(attr.name)) {\n edits.push(removalEdit(attr, source));\n insertions.push(attr.value ? `${attr.name}=\"${attr.value}\"` : attr.name);\n }\n if (attr.name === 'isChipsRemovable') {\n edits.push(removalEdit(attr, source));\n insertions.push('isChipRemovable');\n }\n if (attr.name === 'chipsLabelTruncateCount') {\n edits.push(removalEdit(attr, source));\n truncateValue = attr.value || null;\n }\n if (REMOVED_INPUTS.has(attr.name)) {\n edits.push(removalEdit(attr, source));\n }\n }\n\n // Collect and remove propagated bound inputs\n for (const input of element.inputs) {\n if (PROPAGATED_INPUTS.has(input.name)) {\n edits.push(removalEdit(input, source));\n const raw = source.slice(input.sourceSpan.start.offset, input.sourceSpan.end.offset);\n insertions.push(raw);\n }\n if (input.name === 'isChipsRemovable') {\n edits.push(removalEdit(input, source));\n const valueText = extractBindingValue(input, source);\n insertions.push(`[isChipRemovable]=\"${valueText}\"`);\n }\n if (input.name === 'chipsLabelTruncateCount') {\n edits.push(removalEdit(input, source));\n truncateValue = extractBindingValue(input, source);\n }\n if (REMOVED_INPUTS.has(input.name)) {\n edits.push(removalEdit(input, source));\n }\n }\n\n // Collect and remove (chipRemove) output\n let chipRemoveHandler: string | null = null;\n for (const output of element.outputs) {\n if (output.name === 'chipRemove') {\n edits.push(removalEdit(output, source));\n chipRemoveHandler = extractHandlerExpression(output, source);\n }\n }\n\n if (chipRemoveHandler) {\n insertions.push(`(remove)=\"${chipRemoveHandler}\"`);\n }\n\n // Add collected attributes to each child eui-chip\n if (insertions.length > 0) {\n for (const chip of childChips) {\n const existingNames = getExistingAttrNames(chip);\n const toInsert = insertions.filter((ins) => {\n const name = extractAttrName(ins);\n return !existingNames.has(name);\n });\n if (toInsert.length > 0) {\n const insertPos = chip.startSourceSpan.end.offset - 1;\n edits.push({ start: insertPos, end: insertPos, replacement: ' ' + toInsert.join(' ') });\n }\n }\n }\n\n // Add euiTruncate pipe to chip label content\n if (truncateValue) {\n for (const chip of childChips) {\n const labelEdit = buildTruncatePipeEdit(chip, source, truncateValue);\n if (labelEdit) edits.push(labelEdit);\n }\n }\n}\n\nfunction buildTruncatePipeEdit(chip: TmplAstElement, source: string, truncateValue: string): Edit | null {\n // Find <span euiLabel>...</span> inside the chip\n const labelEl = findLabelElement(chip.children);\n if (labelEl && labelEl.endSourceSpan) {\n const contentStart = labelEl.startSourceSpan.end.offset;\n const contentEnd = labelEl.endSourceSpan.start.offset;\n const content = source.slice(contentStart, contentEnd);\n if (content && !content.includes('euiTruncate')) {\n const trimmed = content.trim();\n const interpMatch = trimmed.match(/^\\{\\{\\s*(.+?)\\s*\\}\\}$/);\n if (interpMatch) {\n return { start: contentStart, end: contentEnd, replacement: `{{ ${interpMatch[1]} | euiTruncate: ${truncateValue} }}` };\n }\n return { start: contentStart, end: contentEnd, replacement: `{{ '${trimmed}' | euiTruncate: ${truncateValue} }}` };\n }\n }\n\n // Check direct text content inside chip (no label element)\n if (chip.endSourceSpan) {\n const chipContentStart = chip.startSourceSpan.end.offset;\n const chipContentEnd = chip.endSourceSpan.start.offset;\n const chipContent = source.slice(chipContentStart, chipContentEnd);\n const trimmed = chipContent.trim();\n const interpMatch = trimmed.match(/^\\{\\{\\s*(.+?)\\s*\\}\\}$/);\n if (interpMatch && !chipContent.includes('euiTruncate')) {\n return { start: chipContentStart, end: chipContentEnd, replacement: `{{ ${interpMatch[1]} | euiTruncate: ${truncateValue} }}` };\n }\n }\n return null;\n}\n\nfunction findLabelElement(nodes: TmplAstNode[]): TmplAstElement | null {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.attributes.some((a) => a.name === 'euiLabel')) return node;\n const nested = findLabelElement(node.children);\n if (nested) return nested;\n }\n }\n return null;\n}\n\nfunction getExistingAttrNames(element: TmplAstElement): Set<string> {\n const names = new Set<string>();\n for (const attr of element.attributes) names.add(attr.name);\n for (const input of element.inputs) names.add(input.name);\n for (const output of element.outputs) names.add(output.name);\n return names;\n}\n\nfunction extractAttrName(insertion: string): string {\n const outputMatch = insertion.match(/^\\(([^)]+)\\)/);\n if (outputMatch) return outputMatch[1];\n const inputMatch = insertion.match(/^\\[([^\\]]+)\\]/);\n if (inputMatch) return inputMatch[1];\n return insertion.split('=')[0];\n}\n\nfunction removalEdit(node: TmplAstTextAttribute | TmplAstBoundAttribute | TmplAstBoundEvent, source: string): Edit {\n let start = node.sourceSpan.start.offset;\n while (start > 0 && (source[start - 1] === ' ' || source[start - 1] === '\\t')) {\n start--;\n }\n return { start, end: node.sourceSpan.end.offset, replacement: '' };\n}\n\nfunction extractBindingValue(input: TmplAstBoundAttribute, source: string): string {\n const raw = source.slice(input.sourceSpan.start.offset, input.sourceSpan.end.offset);\n const match = raw.match(/=[\"']([^\"']*)[\"']/);\n return match ? match[1] : 'true';\n}\n\nfunction extractHandlerExpression(output: TmplAstBoundEvent, source: string): string {\n const raw = source.slice(output.sourceSpan.start.offset, output.sourceSpan.end.offset);\n const match = raw.match(/=[\"']([^\"']*)[\"']/);\n return match ? match[1] : '';\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\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 seen.set(`${edit.start}:${edit.end}`, edit);\n }\n return Array.from(seen.values());\n}\n",
2591
+ "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\nconst COMPONENT_TAG = 'eui-editor';\nconst OLD_NAME = 'onEditorChanged';\nconst NEW_NAME = 'contentChange';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nexport function migrateEuiEditor(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n\n if (path.endsWith('.html')) {\n if (!original.includes(COMPONENT_TAG)) return;\n const result = migrateTemplate(original);\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n return;\n }\n\n // .ts file — handle both migration and warnings in one pass\n const hasTag = original.includes(COMPONENT_TAG);\n const hasOldName = original.includes(OLD_NAME);\n if (!hasTag && !hasOldName) return;\n\n if (hasTag) {\n const result = migrateInlineTemplates(original);\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n }\n\n // Warn about TS property access usages (skip spec files)\n if (hasOldName && !path.endsWith('.spec.ts')) {\n warnPropertyAccesses(path, original, context);\n }\n });\n\n context.logger.info(`Renamed '(${OLD_NAME})' → '(${NEW_NAME})' on ${COMPONENT_TAG} in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit); return;\n}\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, text: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction warnPropertyAccesses(path: string, source: string, context: SchematicContext): void {\n const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"${OLD_NAME}\" has been renamed to \"${NEW_NAME}\" on ${COMPONENT_TAG}. Update this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) collectRenames(node, edits);\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const output of element.outputs) {\n if (output.name === OLD_NAME) {\n edits.push({ start: output.keySpan!.start.offset, end: output.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2592
2592
  "displayName": "Schema",
2593
2593
  "properties": [
2594
2594
  {
@@ -2600,7 +2600,7 @@
2600
2600
  "indexKey": "",
2601
2601
  "optional": true,
2602
2602
  "description": "",
2603
- "line": 28,
2603
+ "line": 12,
2604
2604
  "rawdescription": "\n"
2605
2605
  },
2606
2606
  {
@@ -2612,7 +2612,7 @@
2612
2612
  "indexKey": "",
2613
2613
  "optional": true,
2614
2614
  "description": "",
2615
- "line": 27,
2615
+ "line": 11,
2616
2616
  "rawdescription": "\n"
2617
2617
  }
2618
2618
  ],
@@ -2630,12 +2630,12 @@
2630
2630
  },
2631
2631
  {
2632
2632
  "name": "Schema",
2633
- "id": "interface-Schema-869dfc324e9111966817cbebb3553eabfe200acfe33bb77efa71a6c46e1cba0ff5852de7b9ade3060f87264035b99591361331a9e0622daaac22b8d59146c761-10",
2634
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
2633
+ "id": "interface-Schema-0ee574e11dd651dd971057cb66220845e5b87b2949c69c623c8ddf7355af92a396c58c237a52a05f18c22a5332a2695b717bcfeb8ea840c4e7df8d0084c2b49c-10",
2634
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
2635
2635
  "deprecated": false,
2636
2636
  "deprecationMessage": "",
2637
2637
  "type": "interface",
2638
- "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst COMPONENT_TAG = 'eui-discussion-thread';\n\nexport function migrateEuiDiscussionThread(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would remove [trackBy] binding in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS usages inline\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && original.includes('trackByFn')) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === 'trackByFn') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"trackByFn\" has been removed from ${COMPONENT_TAG}. Remove this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Removed trackByFn-based [trackBy] bindings from ${COMPONENT_TAG} in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const removals: { start: number; end: number }[] = [];\n\n visitNodes(parsed.nodes, source, removals);\n\n let result = source;\n for (const { start, end } of removals.sort((a, b) => b.start - a.start)) {\n let adjustedStart = start;\n while (adjustedStart > 0 && (result[adjustedStart - 1] === ' ' || result[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n result = result.slice(0, adjustedStart) + result.slice(end);\n }\n\n return result;\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const templateRegex = /template\\s*:\\s*`([^`]*)`/gs;\n return source.replace(templateRegex, (match, templateContent: string) => {\n if (!templateContent.includes(COMPONENT_TAG)) return match;\n const migrated = migrateTemplate(templateContent);\n if (migrated === templateContent) return match;\n return match.replace(templateContent, migrated);\n });\n}\n\nfunction visitNodes(nodes: TmplAstNode[], source: string, removals: { start: number; end: number }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) collectRemovals(node, source, removals);\n visitNodes(node.children, source, removals);\n }\n }\n}\n\nfunction collectRemovals(element: TmplAstElement, source: string, removals: { start: number; end: number }[]): void {\n for (const input of element.inputs) {\n if (input.name === 'trackBy') {\n const valueSource = source.slice(input.sourceSpan.start.offset, input.sourceSpan.end.offset);\n if (valueSource.includes('trackByFn')) {\n removals.push({ start: input.sourceSpan.start.offset, end: input.sourceSpan.end.offset });\n }\n }\n }\n}\n",
2638
+ "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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst COMPONENT_TAG = 'eui-fieldset';\nconst OLD_NAME = 'iconSvgType';\nconst NEW_NAME = 'iconSvgName';\n\nexport function migrateEuiFieldset(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS property access usages (merged from warnTsUsages)\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && original.includes(OLD_NAME)) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"${OLD_NAME}\" has been renamed to \"${NEW_NAME}\" on ${COMPONENT_TAG}. Update this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Renamed '${OLD_NAME}' → '${NEW_NAME}' on ${COMPONENT_TAG} in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit); return; \n}\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, text: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) collectRenames(node, edits);\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n if (attr.name === OLD_NAME) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n for (const input of element.inputs) {\n if (input.name === OLD_NAME) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2639
2639
  "displayName": "Schema",
2640
2640
  "properties": [
2641
2641
  {
@@ -2677,12 +2677,12 @@
2677
2677
  },
2678
2678
  {
2679
2679
  "name": "Schema",
2680
- "id": "interface-Schema-375dc0924084a2acbafe4a6a32577d59f631c9a386d151180d8fb1c89e7e7cd23da9fd459e597592ed823692adb6ad2633c50baf16621f003246e8c9bb1c6ce0-11",
2681
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
2680
+ "id": "interface-Schema-b3ff4600c4a5ca1888c45e5baf3600fa6dc6477f1e473e5241ff6682e2929dc8950a5dfa8b1048a348dba7ad1f0ce8cc3681471933911b689e04713334ef4811-11",
2681
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
2682
2682
  "deprecated": false,
2683
2683
  "deprecationMessage": "",
2684
2684
  "type": "interface",
2685
- "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\nconst COMPONENT_TAG = 'eui-editor';\nconst OLD_NAME = 'onEditorChanged';\nconst NEW_NAME = 'contentChange';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nexport function migrateEuiEditor(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n\n if (path.endsWith('.html')) {\n if (!original.includes(COMPONENT_TAG)) return;\n const result = migrateTemplate(original);\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n return;\n }\n\n // .ts file — handle both migration and warnings in one pass\n const hasTag = original.includes(COMPONENT_TAG);\n const hasOldName = original.includes(OLD_NAME);\n if (!hasTag && !hasOldName) return;\n\n if (hasTag) {\n const result = migrateInlineTemplates(original);\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n }\n\n // Warn about TS property access usages (skip spec files)\n if (hasOldName && !path.endsWith('.spec.ts')) {\n warnPropertyAccesses(path, original, context);\n }\n });\n\n context.logger.info(`Renamed '(${OLD_NAME})' → '(${NEW_NAME})' on ${COMPONENT_TAG} in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit); return;\n}\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, text: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction warnPropertyAccesses(path: string, source: string, context: SchematicContext): void {\n const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"${OLD_NAME}\" has been renamed to \"${NEW_NAME}\" on ${COMPONENT_TAG}. Update this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) collectRenames(node, edits);\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const output of element.outputs) {\n if (output.name === OLD_NAME) {\n edits.push({ start: output.keySpan!.start.offset, end: output.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2685
+ "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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst COMPONENT_TAG = 'eui-icon-svg';\n\nconst INPUT_RENAMES = new Map([\n ['variant', 'fillColor'],\n ['aria-label', 'ariaLabel'],\n]);\n\nconst TS_PROPERTY_RENAMES = new Map([\n ['variant', 'fillColor'],\n]);\n\nexport function migrateEuiIconSvg(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n result = renameTsPropertyAccesses(result);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename deprecated inputs in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n });\n\n context.logger.info(`Migrated eui-icon-svg inputs in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) {\n changes.push({ start, end, text: migrated });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction renameTsPropertyAccesses(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && TS_PROPERTY_RENAMES.has(node.name.text)) {\n edits.push({ start: node.name.getStart(sourceFile), end: node.name.getEnd(), replacement: TS_PROPERTY_RENAMES.get(node.name.text)! });\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) {\n collectRenames(node, edits);\n }\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n const newName = INPUT_RENAMES.get(attr.name);\n if (newName) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n }\n for (const input of element.inputs) {\n const newName = INPUT_RENAMES.get(input.name);\n if (newName) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2686
2686
  "displayName": "Schema",
2687
2687
  "properties": [
2688
2688
  {
@@ -2694,7 +2694,7 @@
2694
2694
  "indexKey": "",
2695
2695
  "optional": true,
2696
2696
  "description": "",
2697
- "line": 12,
2697
+ "line": 8,
2698
2698
  "rawdescription": "\n"
2699
2699
  },
2700
2700
  {
@@ -2706,7 +2706,7 @@
2706
2706
  "indexKey": "",
2707
2707
  "optional": true,
2708
2708
  "description": "",
2709
- "line": 11,
2709
+ "line": 7,
2710
2710
  "rawdescription": "\n"
2711
2711
  }
2712
2712
  ],
@@ -2724,12 +2724,12 @@
2724
2724
  },
2725
2725
  {
2726
2726
  "name": "Schema",
2727
- "id": "interface-Schema-0ee574e11dd651dd971057cb66220845e5b87b2949c69c623c8ddf7355af92a396c58c237a52a05f18c22a5332a2695b717bcfeb8ea840c4e7df8d0084c2b49c-12",
2728
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
2727
+ "id": "interface-Schema-21147930d3fbc38fbb3052a2ed9e7aa2b7505e6ed8c88c28796ce7101bd2ad914726eb230dda5826647036190edec6dae7e7e1d172387cd3803aa00bcdf790be-12",
2728
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
2729
2729
  "deprecated": false,
2730
2730
  "deprecationMessage": "",
2731
2731
  "type": "interface",
2732
- "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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst COMPONENT_TAG = 'eui-fieldset';\nconst OLD_NAME = 'iconSvgType';\nconst NEW_NAME = 'iconSvgName';\n\nexport function migrateEuiFieldset(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS property access usages (merged from warnTsUsages)\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && original.includes(OLD_NAME)) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"${OLD_NAME}\" has been renamed to \"${NEW_NAME}\" on ${COMPONENT_TAG}. Update this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Renamed '${OLD_NAME}' → '${NEW_NAME}' on ${COMPONENT_TAG} in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit); return; \n}\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, text: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) collectRenames(node, edits);\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n if (attr.name === OLD_NAME) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n for (const input of element.inputs) {\n if (input.name === OLD_NAME) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2732
+ "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst OLD_NAME = 'iconSet';\nconst NEW_NAME = 'iconSvgName';\nconst COMPONENT_TAG = 'eui-icon-toggle';\n\nexport function migrateEuiIconToggle(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let templateCount = 0;\n let tsCount = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n result = renameTsPropertyAccesses(result);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n if (path.endsWith('.html')) templateCount++;\n else tsCount++;\n }\n });\n\n context.logger.info(`Renamed '${OLD_NAME}' → '${NEW_NAME}' on ${COMPONENT_TAG} in ${templateCount + tsCount} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) {\n changes.push({ start, end, text: migrated });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction renameTsPropertyAccesses(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n edits.push({ start: node.name.getStart(sourceFile), end: node.name.getEnd(), replacement: NEW_NAME });\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) {\n collectRenames(node, edits);\n }\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n if (attr.name === OLD_NAME) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n for (const input of element.inputs) {\n if (input.name === OLD_NAME) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2733
2733
  "displayName": "Schema",
2734
2734
  "properties": [
2735
2735
  {
@@ -2771,12 +2771,12 @@
2771
2771
  },
2772
2772
  {
2773
2773
  "name": "Schema",
2774
- "id": "interface-Schema-b3ff4600c4a5ca1888c45e5baf3600fa6dc6477f1e473e5241ff6682e2929dc8950a5dfa8b1048a348dba7ad1f0ce8cc3681471933911b689e04713334ef4811-13",
2775
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
2774
+ "id": "interface-Schema-a806c1769fb526271565003a6a3ef9ab4c67e421d93ee0cb54e1f6de223807afc1f16ad294656ef614a77a91a38cc914ce41ac97ed3a8a4195a1e74a729c0c08-13",
2775
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
2776
2776
  "deprecated": false,
2777
2777
  "deprecationMessage": "",
2778
2778
  "type": "interface",
2779
- "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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst COMPONENT_TAG = 'eui-icon-svg';\n\nconst INPUT_RENAMES = new Map([\n ['variant', 'fillColor'],\n ['aria-label', 'ariaLabel'],\n]);\n\nconst TS_PROPERTY_RENAMES = new Map([\n ['variant', 'fillColor'],\n]);\n\nexport function migrateEuiIconSvg(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n result = renameTsPropertyAccesses(result);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename deprecated inputs in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n });\n\n context.logger.info(`Migrated eui-icon-svg inputs in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) {\n changes.push({ start, end, text: migrated });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction renameTsPropertyAccesses(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && TS_PROPERTY_RENAMES.has(node.name.text)) {\n edits.push({ start: node.name.getStart(sourceFile), end: node.name.getEnd(), replacement: TS_PROPERTY_RENAMES.get(node.name.text)! });\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) {\n collectRenames(node, edits);\n }\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n const newName = INPUT_RENAMES.get(attr.name);\n if (newName) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n }\n for (const input of element.inputs) {\n const newName = INPUT_RENAMES.get(input.name);\n if (newName) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2779
+ "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst REMOVED_INPUTS = new Set(['type']);\n\nexport function migrateEuiPopover(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes('eui-popover')) return;\n\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would remove 'type' input in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS usages inline\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && (original.includes('eui-popover') || original.includes('euiPopover') || original.includes('EuiPopover'))) {\n if (original.includes('type')) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === 'type') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${path}:${line + 1} - Manual action needed: \"type\" is no longer a valid input on eui-popover. Remove this assignment.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n }\n });\n\n context.logger.info(`Removed deprecated eui-popover 'type' input from ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const removals: { start: number; end: number }[] = [];\n\n visitNodes(parsed.nodes, removals);\n\n let result = source;\n for (const { start, end } of removals.sort((a, b) => b.start - a.start)) {\n // Extend start backwards to consume leading whitespace\n let adjustedStart = start;\n while (adjustedStart > 0 && (result[adjustedStart - 1] === ' ' || result[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n result = result.slice(0, adjustedStart) + result.slice(end);\n }\n\n return result;\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const templateRegex = /template\\s*:\\s*`([^`]*)`/gs;\n return source.replace(templateRegex, (match, templateContent: string) => {\n if (!templateContent.includes('eui-popover')) return match;\n const migrated = migrateTemplate(templateContent);\n if (migrated === templateContent) return match;\n return match.replace(templateContent, migrated);\n });\n}\n\nfunction visitNodes(nodes: TmplAstNode[], removals: { start: number; end: number }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === 'eui-popover') {\n collectRemovals(node, removals);\n }\n visitNodes(node.children, removals);\n }\n }\n}\n\nfunction collectRemovals(element: TmplAstElement, removals: { start: number; end: number }[]): void {\n for (const attr of element.attributes) {\n if (REMOVED_INPUTS.has(attr.name)) {\n removals.push(getAttributeSpan(attr));\n }\n }\n for (const input of element.inputs) {\n if (REMOVED_INPUTS.has(input.name)) {\n removals.push(getAttributeSpan(input));\n }\n }\n}\n\nfunction getAttributeSpan(attr: TmplAstTextAttribute | TmplAstBoundAttribute): { start: number; end: number } {\n return { start: attr.sourceSpan.start.offset, end: attr.sourceSpan.end.offset };\n}\n",
2780
2780
  "displayName": "Schema",
2781
2781
  "properties": [
2782
2782
  {
@@ -2818,12 +2818,12 @@
2818
2818
  },
2819
2819
  {
2820
2820
  "name": "Schema",
2821
- "id": "interface-Schema-21147930d3fbc38fbb3052a2ed9e7aa2b7505e6ed8c88c28796ce7101bd2ad914726eb230dda5826647036190edec6dae7e7e1d172387cd3803aa00bcdf790be-14",
2822
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
2821
+ "id": "interface-Schema-90e62c16ce9ada881e8d434336bb633dae9745236106ddf60964afbd11de6aa579255a13d6036b384281860eb6ed2ee329194b519c51fdaf20f79bc511d0f64f-14",
2822
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
2823
2823
  "deprecated": false,
2824
2824
  "deprecationMessage": "",
2825
2825
  "type": "interface",
2826
- "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst OLD_NAME = 'iconSet';\nconst NEW_NAME = 'iconSvgName';\nconst COMPONENT_TAG = 'eui-icon-toggle';\n\nexport function migrateEuiIconToggle(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let templateCount = 0;\n let tsCount = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(COMPONENT_TAG)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n result = renameTsPropertyAccesses(result);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n if (path.endsWith('.html')) templateCount++;\n else tsCount++;\n }\n });\n\n context.logger.info(`Renamed '${OLD_NAME}' → '${NEW_NAME}' on ${COMPONENT_TAG} in ${templateCount + tsCount} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(COMPONENT_TAG)) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) {\n changes.push({ start, end, text: migrated });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction renameTsPropertyAccesses(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n edits.push({ start: node.name.getStart(sourceFile), end: node.name.getEnd(), replacement: NEW_NAME });\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === COMPONENT_TAG) {\n collectRenames(node, edits);\n }\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n if (attr.name === OLD_NAME) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n for (const input of element.inputs) {\n if (input.name === OLD_NAME) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2826
+ "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst INPUT_RENAMES = new Map([\n ['iconLabelClass', 'icon'],\n ['iconLabelStyleClass', 'fillColor'],\n]);\n\nexport function migrateEuiProgressCircle(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n const oldNames = [...INPUT_RENAMES.keys()];\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n\n if (original.includes('eui-progress-circle')) {\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename deprecated inputs in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n }\n\n // Warn about TS property access usages (merged from warnTsUsages)\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {\n if (oldNames.some((name) => original.includes(name))) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && INPUT_RENAMES.has(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const newName = INPUT_RENAMES.get(node.name.text);\n context.logger.warn(\n `${path}:${line + 1} - \"${node.name.text}\" has been renamed to \"${newName}\" on eui-progress-circle. Update this reference manually.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n }\n });\n\n context.logger.info(`Renamed deprecated eui-progress-circle inputs in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes('eui-progress-circle')) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) {\n changes.push({ start, end, text: migrated });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === 'eui-progress-circle') {\n collectRenames(node, edits);\n }\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n const newName = INPUT_RENAMES.get(attr.name);\n if (newName) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n }\n for (const input of element.inputs) {\n const newName = INPUT_RENAMES.get(input.name);\n if (newName) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2827
2827
  "displayName": "Schema",
2828
2828
  "properties": [
2829
2829
  {
@@ -2865,12 +2865,12 @@
2865
2865
  },
2866
2866
  {
2867
2867
  "name": "Schema",
2868
- "id": "interface-Schema-a806c1769fb526271565003a6a3ef9ab4c67e421d93ee0cb54e1f6de223807afc1f16ad294656ef614a77a91a38cc914ce41ac97ed3a8a4195a1e74a729c0c08-15",
2869
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
2868
+ "id": "interface-Schema-91c9f900bf3ebb82488fb65644938ef486ceaa447cff8bfd9d710df9595d82acb267b26f3c252173bc684353f362473120226426ed7ee5d98b33e30011dd9383-15",
2869
+ "file": "packages/core/schematics/migrate-eui-table/index.ts",
2870
2870
  "deprecated": false,
2871
2871
  "deprecationMessage": "",
2872
2872
  "type": "interface",
2873
- "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst REMOVED_INPUTS = new Set(['type']);\n\nexport function migrateEuiPopover(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes('eui-popover')) return;\n\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would remove 'type' input in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS usages inline\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && (original.includes('eui-popover') || original.includes('euiPopover') || original.includes('EuiPopover'))) {\n if (original.includes('type')) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === 'type') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${path}:${line + 1} - Manual action needed: \"type\" is no longer a valid input on eui-popover. Remove this assignment.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n }\n });\n\n context.logger.info(`Removed deprecated eui-popover 'type' input from ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const removals: { start: number; end: number }[] = [];\n\n visitNodes(parsed.nodes, removals);\n\n let result = source;\n for (const { start, end } of removals.sort((a, b) => b.start - a.start)) {\n // Extend start backwards to consume leading whitespace\n let adjustedStart = start;\n while (adjustedStart > 0 && (result[adjustedStart - 1] === ' ' || result[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n result = result.slice(0, adjustedStart) + result.slice(end);\n }\n\n return result;\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const templateRegex = /template\\s*:\\s*`([^`]*)`/gs;\n return source.replace(templateRegex, (match, templateContent: string) => {\n if (!templateContent.includes('eui-popover')) return match;\n const migrated = migrateTemplate(templateContent);\n if (migrated === templateContent) return match;\n return match.replace(templateContent, migrated);\n });\n}\n\nfunction visitNodes(nodes: TmplAstNode[], removals: { start: number; end: number }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === 'eui-popover') {\n collectRemovals(node, removals);\n }\n visitNodes(node.children, removals);\n }\n }\n}\n\nfunction collectRemovals(element: TmplAstElement, removals: { start: number; end: number }[]): void {\n for (const attr of element.attributes) {\n if (REMOVED_INPUTS.has(attr.name)) {\n removals.push(getAttributeSpan(attr));\n }\n }\n for (const input of element.inputs) {\n if (REMOVED_INPUTS.has(input.name)) {\n removals.push(getAttributeSpan(input));\n }\n }\n}\n\nfunction getAttributeSpan(attr: TmplAstTextAttribute | TmplAstBoundAttribute): { start: number; end: number } {\n return { start: attr.sourceSpan.start.offset, end: attr.sourceSpan.end.offset };\n}\n",
2873
+ "sourceCode": "import { BindingPipe, parseTemplate, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstTemplate, TmplAstTextAttribute, AST, ASTWithSource, Interpolation } 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 Edit { start: number; end: number; replacement: string; }\n\n// --- Table-level input renames (on elements with euiTable attribute) ---\nconst TABLE_INPUT_RENAMES = new Map([\n ['rows', 'data'],\n ['loading', 'isLoading'],\n ['asyncTable', 'isAsync'],\n ['euiTableResponsive', 'isTableResponsive'],\n ['euiTableFixedLayout', 'isTableFixedLayout'],\n ['euiTableCompact', 'isTableCompact'],\n ['hasStickyColumns', 'hasStickyCols'],\n]);\n\n// --- Child element input renames (scoped to euiTable context) ---\nconst TH_TD_INPUT_RENAMES = new Map([\n ['isStickyColumn', 'isStickyCol'],\n ['sortable', 'isSortable'],\n]);\n\nconst TR_INPUT_RENAMES = new Map([\n ['isSelectableHeader', 'isHeaderSelectable'],\n ['isSelectable', 'isDataSelectable'],\n]);\n\n// --- Removed inputs ---\nconst REMOVED_INPUTS = new Set(['euiTableBordered', 'isHoverable', 'defaultMultiOrder', 'paginable']);\n\n// --- Output renames/removals ---\nconst OUTPUT_RENAMES = new Map([['selectedRows', 'rowsSelect']]);\nconst REMOVED_OUTPUTS = new Set(['multiSortChange']);\n\n// --- Pipe rename ---\nconst OLD_PIPE = 'euiTableHighlightFilter';\nconst NEW_PIPE = 'euiTableHighlight';\n\n// --- TS property renames ---\nconst TS_PROPERTY_RENAMES = new Map([['filteredRows', 'getFilteredData']]);\n\nconst PAGINATOR_IMPORT_PATH = '@eui/components/eui-paginator';\nconst PAGINATOR_COMPONENT = 'EuiPaginatorComponent';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nexport function migrateEuiTable(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n const paginatorHtmlFiles = new Set<string>();\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes('euiTable') && !original.includes(OLD_PIPE) && !original.includes('filteredRows') && !original.includes('setSort')) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n const { output, hasPaginator } = migrateTemplateWithPaginator(original, path, context);\n result = output;\n if (hasPaginator) paginatorHtmlFiles.add(path);\n } else {\n const { output, hasPaginator } = migrateTypeScript(original, path, context);\n result = output;\n if (hasPaginator) {\n result = addPaginatorImport(result, path);\n }\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate eui-table breaking changes in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n });\n\n // Handle paginator imports for external templates\n if (paginatorHtmlFiles.size > 0) {\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const source = buffer.toString('utf-8');\n if (!source.includes('templateUrl')) return;\n\n for (const htmlFile of paginatorHtmlFiles) {\n const htmlFileName = htmlFile.split('/').pop()!;\n if (source.includes(htmlFileName)) {\n const updated = addPaginatorImport(source, path);\n if (updated !== source) {\n if (options.dryRun) {\n logDryRun(context, `Would add paginator import in ${path}`);\n } else {\n tree.overwrite(path, updated);\n }\n count++;\n }\n break;\n }\n }\n });\n }\n\n context.logger.info(`Migrated eui-table in ${count} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction migrateTemplateWithPaginator(source: string, filePath: string, context: SchematicContext): { output: string; hasPaginator: boolean } {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: Edit[] = [];\n let hasPaginator = false;\n\n const paginatorResult = visitNodesForTable(parsed.nodes, source, edits, false, filePath, context);\n if (paginatorResult) hasPaginator = true;\n\n collectPipeRenames(parsed.nodes, source, edits);\n\n return { output: applyEdits(source, edits), hasPaginator };\n}\n\nfunction migrateTemplate(source: string, filePath: string, context: SchematicContext): string {\n return migrateTemplateWithPaginator(source, filePath, context).output;\n}\n\nfunction migrateTypeScript(source: string, filePath: string, context: SchematicContext): { output: string; hasPaginator: boolean } {\n let result = source;\n let hasPaginator = false;\n\n // Migrate inline templates\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = result.slice(start, end);\n if (!rawTemplate.includes('euiTable') && !rawTemplate.includes(OLD_PIPE)) {\n ts.forEachChild(node, visit); return;\n}\n const { output: migrated, hasPaginator: pag } = migrateTemplateWithPaginator(rawTemplate, filePath, context);\n if (pag) hasPaginator = true;\n if (migrated !== rawTemplate) changes.push({ start, end, replacement: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n result = applyEdits(result, changes);\n\n // Rename TS property accesses\n result = renameTsProperties(result);\n\n // Warn about setSort\n warnSetSort(result, filePath, context);\n\n return { output: result, hasPaginator };\n}\n\nfunction renameTsProperties(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && TS_PROPERTY_RENAMES.has(node.name.text)) {\n edits.push({ start: node.name.getStart(sourceFile), end: node.name.getEnd(), replacement: TS_PROPERTY_RENAMES.get(node.name.text)! });\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return applyEdits(source, edits);\n}\n\nfunction warnSetSort(source: string, filePath: string, context: SchematicContext): void {\n if (!source.includes('setSort')) return;\n\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) &&\n ts.isIdentifier(node.expression.name) && node.expression.name.text === 'setSort') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${filePath}:${line + 1} - \"setSort\" signature changed from setSort(sort: string, order: \"asc\" | \"desc\") to setSort(Sort[]). Update manually.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n}\n\n// --- Template AST visitors ---\n\nfunction visitNodesForTable(\n nodes: TmplAstNode[], source: string, edits: Edit[], insideEuiTable: boolean, filePath: string, context: SchematicContext,\n): boolean {\n let hasPaginator = false;\n\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n const isEuiTable = hasEuiTableAttribute(node);\n\n if (isEuiTable) {\n collectTableInputRenames(node, edits);\n collectInputRemovals(node, source, edits, filePath, context);\n collectOutputChanges(node, source, edits, filePath, context);\n if (collectPaginatorMigration(node, source, edits)) hasPaginator = true;\n }\n\n if (isEuiTable || insideEuiTable) {\n collectChildElementRenames(node, edits);\n collectChildInputRemovals(node, source, edits, filePath, context);\n collectEmptyMessageRename(node, edits);\n }\n\n const childResult = visitNodesForTable(node.children, source, edits, isEuiTable || insideEuiTable, filePath, context);\n if (childResult) hasPaginator = true;\n }\n\n if (node instanceof TmplAstTemplate) {\n if (insideEuiTable) {\n collectTemplateEmptyMessageRename(node, edits);\n }\n const childResult = visitNodesForTable(node.children, source, edits, insideEuiTable, filePath, context);\n if (childResult) hasPaginator = true;\n }\n }\n\n return hasPaginator;\n}\n\nfunction hasEuiTableAttribute(element: TmplAstElement): boolean {\n return element.attributes.some((a) => a.name === 'euiTable') ||\n element.inputs.some((i) => i.name === 'euiTable');\n}\n\nfunction collectTableInputRenames(element: TmplAstElement, edits: Edit[]): void {\n for (const attr of element.attributes) {\n const newName = TABLE_INPUT_RENAMES.get(attr.name);\n if (newName) edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n for (const input of element.inputs) {\n const newName = TABLE_INPUT_RENAMES.get(input.name);\n if (newName) edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n}\n\nfunction collectChildElementRenames(element: TmplAstElement, edits: Edit[]): void {\n const renames = (element.name === 'th' || element.name === 'td') ? TH_TD_INPUT_RENAMES\n : element.name === 'tr' ? TR_INPUT_RENAMES : null;\n if (!renames) return;\n\n for (const attr of element.attributes) {\n const newName = renames.get(attr.name);\n if (newName) edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n for (const input of element.inputs) {\n const newName = renames.get(input.name);\n if (newName) edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n}\n\nfunction collectChildInputRemovals(element: TmplAstElement, source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n const childRemovedInputs = new Set(['defaultMultiOrder']);\n\n for (const attr of element.attributes) {\n if (childRemovedInputs.has(attr.name)) {\n removeAttribute(attr.sourceSpan.start.offset, attr.sourceSpan.end.offset, source, edits);\n logRemovalWarning(attr.name, filePath, element, context);\n }\n }\n for (const input of element.inputs) {\n if (childRemovedInputs.has(input.name)) {\n removeAttribute(input.sourceSpan.start.offset, input.sourceSpan.end.offset, source, edits);\n logRemovalWarning(input.name, filePath, element, context);\n }\n }\n}\n\nfunction collectInputRemovals(element: TmplAstElement, source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n for (const attr of element.attributes) {\n if (REMOVED_INPUTS.has(attr.name) && attr.name !== 'paginable') {\n removeAttribute(attr.sourceSpan.start.offset, attr.sourceSpan.end.offset, source, edits);\n logRemovalWarning(attr.name, filePath, element, context);\n }\n }\n for (const input of element.inputs) {\n if (REMOVED_INPUTS.has(input.name) && input.name !== 'paginable') {\n removeAttribute(input.sourceSpan.start.offset, input.sourceSpan.end.offset, source, edits);\n logRemovalWarning(input.name, filePath, element, context);\n }\n }\n}\n\nfunction collectOutputChanges(element: TmplAstElement, source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n for (const output of element.outputs) {\n const newName = OUTPUT_RENAMES.get(output.name);\n if (newName) {\n edits.push({ start: output.keySpan!.start.offset, end: output.keySpan!.end.offset, replacement: newName });\n }\n if (REMOVED_OUTPUTS.has(output.name)) {\n removeAttribute(output.sourceSpan.start.offset, output.sourceSpan.end.offset, source, edits);\n const { line } = element.startSourceSpan.start;\n context.logger.warn(\n `${filePath}:${line + 1} - \"(${output.name})\" removed. Multi-sort is now supported by (sortChange) output.`,\n );\n }\n }\n}\n\nfunction collectPaginatorMigration(element: TmplAstElement, source: string, edits: Edit[]): boolean {\n let found = false;\n\n for (const attr of element.attributes) {\n if (attr.name === 'paginable') {\n removeAttribute(attr.sourceSpan.start.offset, attr.sourceSpan.end.offset, source, edits);\n found = true;\n }\n }\n for (const input of element.inputs) {\n if (input.name === 'paginable') {\n removeAttribute(input.sourceSpan.start.offset, input.sourceSpan.end.offset, source, edits);\n found = true;\n }\n }\n\n if (found) {\n // Add [paginator]=\"paginator\" before closing > of opening tag\n const insertPos = element.startSourceSpan.end.offset - 1;\n edits.push({ start: insertPos, end: insertPos, replacement: ' [paginator]=\"paginator\"' });\n\n // Add eui-paginator after </table>\n if (element.endSourceSpan) {\n const afterTable = element.endSourceSpan.end.offset;\n edits.push({\n start: afterTable,\n end: afterTable,\n replacement: '\\n<!-- TODO: Configure paginator and implement onPageChange handler -->\\n<eui-paginator #paginator [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\" />',\n });\n }\n }\n\n return found;\n}\n\nfunction collectEmptyMessageRename(element: TmplAstElement, edits: Edit[]): void {\n // Handle direct attribute on elements (unlikely but handle)\n for (const attr of element.attributes) {\n if (attr.name === 'euiTemplate' && attr.value === 'emptyMessage' && attr.valueSpan) {\n edits.push({ start: attr.valueSpan.start.offset, end: attr.valueSpan.end.offset, replacement: 'footer' });\n }\n }\n}\n\nfunction collectTemplateEmptyMessageRename(template: TmplAstTemplate, edits: Edit[]): void {\n for (const attr of template.templateAttrs) {\n if (attr instanceof TmplAstTextAttribute && attr.name === 'euiTemplate' && attr.value === 'emptyMessage' && attr.valueSpan) {\n edits.push({ start: attr.valueSpan.start.offset, end: attr.valueSpan.end.offset, replacement: 'footer' });\n }\n }\n for (const attr of template.attributes) {\n if (attr.name === 'euiTemplate' && attr.value === 'emptyMessage' && attr.valueSpan) {\n edits.push({ start: attr.valueSpan.start.offset, end: attr.valueSpan.end.offset, replacement: 'footer' });\n }\n }\n}\n\n// --- Pipe rename via AST ---\n\nfunction collectPipeRenames(nodes: TmplAstNode[], source: string, edits: Edit[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n for (const input of node.inputs) {\n visitExpressionForPipes(input.value, edits);\n }\n for (const output of node.outputs) {\n if (output.handler) visitExpressionForPipes(output.handler, edits);\n }\n collectPipeRenames(node.children, source, edits);\n }\n if (node instanceof TmplAstTemplate) {\n for (const input of node.inputs) {\n visitExpressionForPipes(input.value, edits);\n }\n collectPipeRenames(node.children, source, edits);\n }\n if (node instanceof TmplAstBoundText) {\n visitExpressionForPipes(node.value, edits);\n }\n }\n}\n\nfunction visitExpressionForPipes(expr: AST, edits: Edit[]): void {\n if (expr instanceof ASTWithSource && expr.ast) {\n visitAstForPipes(expr.ast, edits);\n } else {\n visitAstForPipes(expr, edits);\n }\n}\n\nfunction visitAstForPipes(ast: AST, edits: Edit[]): void {\n if (ast instanceof BindingPipe) {\n if (ast.name === OLD_PIPE && ast.nameSpan) {\n edits.push({ start: ast.nameSpan.start, end: ast.nameSpan.end, replacement: NEW_PIPE });\n }\n visitAstForPipes(ast.exp, edits);\n for (const arg of ast.args) {\n visitAstForPipes(arg, edits);\n }\n return;\n }\n\n if (ast instanceof Interpolation) {\n for (const expr of ast.expressions) {\n visitAstForPipes(expr, edits);\n }\n return;\n }\n\n // Recursively visit all properties that could contain AST nodes\n for (const key of Object.keys(ast)) {\n // eslint-disable-next-line\n const val = (ast as any)[key];\n if (val instanceof AST) {\n visitAstForPipes(val, edits);\n } else if (Array.isArray(val)) {\n for (const item of val) {\n if (item instanceof AST) visitAstForPipes(item, edits);\n }\n }\n }\n}\n\n// --- Import handling for paginator ---\n\nfunction addPaginatorImport(source: string, filePath: string): string {\n if (source.includes(PAGINATOR_COMPONENT)) return source;\n\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Add import statement after last import\n let lastImportEnd = 0;\n for (const stmt of sourceFile.statements) {\n if (ts.isImportDeclaration(stmt)) {\n lastImportEnd = stmt.getEnd();\n }\n }\n\n if (lastImportEnd > 0) {\n edits.push({\n start: lastImportEnd,\n end: lastImportEnd,\n replacement: `\\nimport { ${PAGINATOR_COMPONENT} } from '${PAGINATOR_IMPORT_PATH}';`,\n });\n }\n\n // Add to component imports array\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === 'imports' && isComponentMetadataProperty(node)) {\n if (ts.isArrayLiteralExpression(node.initializer)) {\n const arr = node.initializer;\n const elements = arr.elements;\n if (elements.length > 0) {\n const lastElement = elements[elements.length - 1];\n edits.push({\n start: lastElement.getEnd(),\n end: lastElement.getEnd(),\n replacement: `, ${PAGINATOR_COMPONENT}`,\n });\n } else {\n const insertPos = arr.getStart(sourceFile) + 1;\n edits.push({ start: insertPos, end: insertPos, replacement: PAGINATOR_COMPONENT });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\n// --- Helpers ---\n\nfunction removeAttribute(start: number, end: number, source: string, edits: Edit[]): void {\n let adjustedStart = start;\n while (adjustedStart > 0 && (source[adjustedStart - 1] === ' ' || source[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n edits.push({ start: adjustedStart, end, replacement: '' });\n}\n\nfunction logRemovalWarning(name: string, filePath: string, element: TmplAstElement, context: SchematicContext): void {\n const { line } = element.startSourceSpan.start;\n if (name === 'defaultMultiOrder') {\n context.logger.warn(`${filePath}:${line + 1} - \"[${name}]\" removed. Use setSort(Sort[]) to initialize sorting.`);\n } else {\n context.logger.warn(`${filePath}:${line + 1} - \"[${name}]\" removed to align to Design System.`);\n }\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction applyEdits(source: string, edits: Edit[]): string {\n const unique = new Map<string, Edit>();\n for (const edit of edits) {\n const key = `${edit.start}:${edit.end}`;\n unique.set(key, edit);\n }\n let result = source;\n for (const edit of [...unique.values()].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 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('.html') && !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",
2874
2874
  "displayName": "Schema",
2875
2875
  "properties": [
2876
2876
  {
@@ -2882,7 +2882,7 @@
2882
2882
  "indexKey": "",
2883
2883
  "optional": true,
2884
2884
  "description": "",
2885
- "line": 8,
2885
+ "line": 49,
2886
2886
  "rawdescription": "\n"
2887
2887
  },
2888
2888
  {
@@ -2894,7 +2894,7 @@
2894
2894
  "indexKey": "",
2895
2895
  "optional": true,
2896
2896
  "description": "",
2897
- "line": 7,
2897
+ "line": 48,
2898
2898
  "rawdescription": "\n"
2899
2899
  }
2900
2900
  ],
@@ -2912,12 +2912,12 @@
2912
2912
  },
2913
2913
  {
2914
2914
  "name": "Schema",
2915
- "id": "interface-Schema-90e62c16ce9ada881e8d434336bb633dae9745236106ddf60964afbd11de6aa579255a13d6036b384281860eb6ed2ee329194b519c51fdaf20f79bc511d0f64f-16",
2916
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
2915
+ "id": "interface-Schema-c0c08f5e83da9afa13ce8375f982fb280b9bde854e00c914f41b04d44deecd531496c2cee264b50314e92a6260c26cebe35741a2cf5ec068d8b6da5c5267539e-16",
2916
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
2917
2917
  "deprecated": false,
2918
2918
  "deprecationMessage": "",
2919
2919
  "type": "interface",
2920
- "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst INPUT_RENAMES = new Map([\n ['iconLabelClass', 'icon'],\n ['iconLabelStyleClass', 'fillColor'],\n]);\n\nexport function migrateEuiProgressCircle(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n const oldNames = [...INPUT_RENAMES.keys()];\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n\n if (original.includes('eui-progress-circle')) {\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename deprecated inputs in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n }\n\n // Warn about TS property access usages (merged from warnTsUsages)\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {\n if (oldNames.some((name) => original.includes(name))) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && INPUT_RENAMES.has(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const newName = INPUT_RENAMES.get(node.name.text);\n context.logger.warn(\n `${path}:${line + 1} - \"${node.name.text}\" has been renamed to \"${newName}\" on eui-progress-circle. Update this reference manually.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n }\n });\n\n context.logger.info(`Renamed deprecated eui-progress-circle inputs in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes('eui-progress-circle')) {\n ts.forEachChild(node, visit);\n return;\n }\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) {\n changes.push({ start, end, text: migrated });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n return current;\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === 'eui-progress-circle') {\n collectRenames(node, edits);\n }\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n const newName = INPUT_RENAMES.get(attr.name);\n if (newName) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n }\n for (const input of element.inputs) {\n const newName = INPUT_RENAMES.get(input.name);\n if (newName) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2920
+ "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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst OLD_NAME = 'euiButtonCall';\nconst NEW_NAME = 'euiCTAButton';\n\nexport function migrateEuiButton(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(OLD_NAME)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original);\n } else {\n result = migrateInlineTemplates(original);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would rename '${OLD_NAME}' → '${NEW_NAME}' in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS property access usages\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {\n if (!original.includes(OLD_NAME)) return;\n\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === OLD_NAME) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"${OLD_NAME}\" has been renamed to \"${NEW_NAME}\". Update this reference manually.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Renamed '${OLD_NAME}' → '${NEW_NAME}' on elements with euiButton in ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: { start: number; end: number; replacement: string }[] = [];\n\n visitNodes(parsed.nodes, edits);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: { start: number; end: number; text: string }[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(OLD_NAME)) {\n ts.forEachChild(node, visit); return; \n}\n const migrated = migrateTemplate(rawTemplate);\n if (migrated !== rawTemplate) changes.push({ start, end, text: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n let result = source;\n for (const change of changes.sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n return result;\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction hasEuiButtonAttribute(element: TmplAstElement): boolean {\n return element.attributes.some((a) => a.name === 'euiButton') ||\n element.inputs.some((i) => i.name === 'euiButton');\n}\n\nfunction visitNodes(nodes: TmplAstNode[], edits: { start: number; end: number; replacement: string }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (hasEuiButtonAttribute(node)) collectRenames(node, edits);\n visitNodes(node.children, edits);\n }\n }\n}\n\nfunction collectRenames(element: TmplAstElement, edits: { start: number; end: number; replacement: string }[]): void {\n for (const attr of element.attributes) {\n if (attr.name === OLD_NAME) {\n edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n for (const input of element.inputs) {\n if (input.name === OLD_NAME) {\n edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: NEW_NAME });\n }\n }\n}\n\nfunction applyEdits(source: string, edits: { start: number; end: number; replacement: string }[]): string {\n let result = source;\n for (const edit of edits.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",
2921
2921
  "displayName": "Schema",
2922
2922
  "properties": [
2923
2923
  {
@@ -2959,12 +2959,12 @@
2959
2959
  },
2960
2960
  {
2961
2961
  "name": "Schema",
2962
- "id": "interface-Schema-91c9f900bf3ebb82488fb65644938ef486ceaa447cff8bfd9d710df9595d82acb267b26f3c252173bc684353f362473120226426ed7ee5d98b33e30011dd9383-17",
2963
- "file": "packages/core/schematics/migrate-eui-table/index.ts",
2962
+ "id": "interface-Schema-760dec88d3f709d5b38226e55f7cbfb1e5fabcea6c004fd46e611be1dd563b8b247e9e6c77667e5582fe7b443374ba2c4facd2b2db2985edb46c9a4a37a8a876-17",
2963
+ "file": "packages/core/schematics/migrate-eui-tabs/index.ts",
2964
2964
  "deprecated": false,
2965
2965
  "deprecationMessage": "",
2966
2966
  "type": "interface",
2967
- "sourceCode": "import { BindingPipe, parseTemplate, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstTemplate, TmplAstTextAttribute, AST, ASTWithSource, Interpolation } 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 Edit { start: number; end: number; replacement: string; }\n\n// --- Table-level input renames (on elements with euiTable attribute) ---\nconst TABLE_INPUT_RENAMES = new Map([\n ['rows', 'data'],\n ['loading', 'isLoading'],\n ['asyncTable', 'isAsync'],\n ['euiTableResponsive', 'isTableResponsive'],\n ['euiTableFixedLayout', 'isTableFixedLayout'],\n ['euiTableCompact', 'isTableCompact'],\n ['hasStickyColumns', 'hasStickyCols'],\n]);\n\n// --- Child element input renames (scoped to euiTable context) ---\nconst TH_TD_INPUT_RENAMES = new Map([\n ['isStickyColumn', 'isStickyCol'],\n ['sortable', 'isSortable'],\n]);\n\nconst TR_INPUT_RENAMES = new Map([\n ['isSelectableHeader', 'isHeaderSelectable'],\n ['isSelectable', 'isDataSelectable'],\n]);\n\n// --- Removed inputs ---\nconst REMOVED_INPUTS = new Set(['euiTableBordered', 'isHoverable', 'defaultMultiOrder', 'paginable']);\n\n// --- Output renames/removals ---\nconst OUTPUT_RENAMES = new Map([['selectedRows', 'rowsSelect']]);\nconst REMOVED_OUTPUTS = new Set(['multiSortChange']);\n\n// --- Pipe rename ---\nconst OLD_PIPE = 'euiTableHighlightFilter';\nconst NEW_PIPE = 'euiTableHighlight';\n\n// --- TS property renames ---\nconst TS_PROPERTY_RENAMES = new Map([['filteredRows', 'getFilteredData']]);\n\nconst PAGINATOR_IMPORT_PATH = '@eui/components/eui-paginator';\nconst PAGINATOR_COMPONENT = 'EuiPaginatorComponent';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nexport function migrateEuiTable(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n const paginatorHtmlFiles = new Set<string>();\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes('euiTable') && !original.includes(OLD_PIPE) && !original.includes('filteredRows') && !original.includes('setSort')) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n const { output, hasPaginator } = migrateTemplateWithPaginator(original, path, context);\n result = output;\n if (hasPaginator) paginatorHtmlFiles.add(path);\n } else {\n const { output, hasPaginator } = migrateTypeScript(original, path, context);\n result = output;\n if (hasPaginator) {\n result = addPaginatorImport(result, path);\n }\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate eui-table breaking changes in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n });\n\n // Handle paginator imports for external templates\n if (paginatorHtmlFiles.size > 0) {\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const source = buffer.toString('utf-8');\n if (!source.includes('templateUrl')) return;\n\n for (const htmlFile of paginatorHtmlFiles) {\n const htmlFileName = htmlFile.split('/').pop()!;\n if (source.includes(htmlFileName)) {\n const updated = addPaginatorImport(source, path);\n if (updated !== source) {\n if (options.dryRun) {\n logDryRun(context, `Would add paginator import in ${path}`);\n } else {\n tree.overwrite(path, updated);\n }\n count++;\n }\n break;\n }\n }\n });\n }\n\n context.logger.info(`Migrated eui-table in ${count} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction migrateTemplateWithPaginator(source: string, filePath: string, context: SchematicContext): { output: string; hasPaginator: boolean } {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: Edit[] = [];\n let hasPaginator = false;\n\n const paginatorResult = visitNodesForTable(parsed.nodes, source, edits, false, filePath, context);\n if (paginatorResult) hasPaginator = true;\n\n collectPipeRenames(parsed.nodes, source, edits);\n\n return { output: applyEdits(source, edits), hasPaginator };\n}\n\nfunction migrateTemplate(source: string, filePath: string, context: SchematicContext): string {\n return migrateTemplateWithPaginator(source, filePath, context).output;\n}\n\nfunction migrateTypeScript(source: string, filePath: string, context: SchematicContext): { output: string; hasPaginator: boolean } {\n let result = source;\n let hasPaginator = false;\n\n // Migrate inline templates\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = result.slice(start, end);\n if (!rawTemplate.includes('euiTable') && !rawTemplate.includes(OLD_PIPE)) {\n ts.forEachChild(node, visit); return;\n}\n const { output: migrated, hasPaginator: pag } = migrateTemplateWithPaginator(rawTemplate, filePath, context);\n if (pag) hasPaginator = true;\n if (migrated !== rawTemplate) changes.push({ start, end, replacement: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n result = applyEdits(result, changes);\n\n // Rename TS property accesses\n result = renameTsProperties(result);\n\n // Warn about setSort\n warnSetSort(result, filePath, context);\n\n return { output: result, hasPaginator };\n}\n\nfunction renameTsProperties(source: string): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && TS_PROPERTY_RENAMES.has(node.name.text)) {\n edits.push({ start: node.name.getStart(sourceFile), end: node.name.getEnd(), replacement: TS_PROPERTY_RENAMES.get(node.name.text)! });\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return applyEdits(source, edits);\n}\n\nfunction warnSetSort(source: string, filePath: string, context: SchematicContext): void {\n if (!source.includes('setSort')) return;\n\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) &&\n ts.isIdentifier(node.expression.name) && node.expression.name.text === 'setSort') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${filePath}:${line + 1} - \"setSort\" signature changed from setSort(sort: string, order: \"asc\" | \"desc\") to setSort(Sort[]). Update manually.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n}\n\n// --- Template AST visitors ---\n\nfunction visitNodesForTable(\n nodes: TmplAstNode[], source: string, edits: Edit[], insideEuiTable: boolean, filePath: string, context: SchematicContext,\n): boolean {\n let hasPaginator = false;\n\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n const isEuiTable = hasEuiTableAttribute(node);\n\n if (isEuiTable) {\n collectTableInputRenames(node, edits);\n collectInputRemovals(node, source, edits, filePath, context);\n collectOutputChanges(node, source, edits, filePath, context);\n if (collectPaginatorMigration(node, source, edits)) hasPaginator = true;\n }\n\n if (isEuiTable || insideEuiTable) {\n collectChildElementRenames(node, edits);\n collectChildInputRemovals(node, source, edits, filePath, context);\n collectEmptyMessageRename(node, edits);\n }\n\n const childResult = visitNodesForTable(node.children, source, edits, isEuiTable || insideEuiTable, filePath, context);\n if (childResult) hasPaginator = true;\n }\n\n if (node instanceof TmplAstTemplate) {\n if (insideEuiTable) {\n collectTemplateEmptyMessageRename(node, edits);\n }\n const childResult = visitNodesForTable(node.children, source, edits, insideEuiTable, filePath, context);\n if (childResult) hasPaginator = true;\n }\n }\n\n return hasPaginator;\n}\n\nfunction hasEuiTableAttribute(element: TmplAstElement): boolean {\n return element.attributes.some((a) => a.name === 'euiTable') ||\n element.inputs.some((i) => i.name === 'euiTable');\n}\n\nfunction collectTableInputRenames(element: TmplAstElement, edits: Edit[]): void {\n for (const attr of element.attributes) {\n const newName = TABLE_INPUT_RENAMES.get(attr.name);\n if (newName) edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n for (const input of element.inputs) {\n const newName = TABLE_INPUT_RENAMES.get(input.name);\n if (newName) edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n}\n\nfunction collectChildElementRenames(element: TmplAstElement, edits: Edit[]): void {\n const renames = (element.name === 'th' || element.name === 'td') ? TH_TD_INPUT_RENAMES\n : element.name === 'tr' ? TR_INPUT_RENAMES : null;\n if (!renames) return;\n\n for (const attr of element.attributes) {\n const newName = renames.get(attr.name);\n if (newName) edits.push({ start: attr.keySpan!.start.offset, end: attr.keySpan!.end.offset, replacement: newName });\n }\n for (const input of element.inputs) {\n const newName = renames.get(input.name);\n if (newName) edits.push({ start: input.keySpan!.start.offset, end: input.keySpan!.end.offset, replacement: newName });\n }\n}\n\nfunction collectChildInputRemovals(element: TmplAstElement, source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n const childRemovedInputs = new Set(['defaultMultiOrder']);\n\n for (const attr of element.attributes) {\n if (childRemovedInputs.has(attr.name)) {\n removeAttribute(attr.sourceSpan.start.offset, attr.sourceSpan.end.offset, source, edits);\n logRemovalWarning(attr.name, filePath, element, context);\n }\n }\n for (const input of element.inputs) {\n if (childRemovedInputs.has(input.name)) {\n removeAttribute(input.sourceSpan.start.offset, input.sourceSpan.end.offset, source, edits);\n logRemovalWarning(input.name, filePath, element, context);\n }\n }\n}\n\nfunction collectInputRemovals(element: TmplAstElement, source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n for (const attr of element.attributes) {\n if (REMOVED_INPUTS.has(attr.name) && attr.name !== 'paginable') {\n removeAttribute(attr.sourceSpan.start.offset, attr.sourceSpan.end.offset, source, edits);\n logRemovalWarning(attr.name, filePath, element, context);\n }\n }\n for (const input of element.inputs) {\n if (REMOVED_INPUTS.has(input.name) && input.name !== 'paginable') {\n removeAttribute(input.sourceSpan.start.offset, input.sourceSpan.end.offset, source, edits);\n logRemovalWarning(input.name, filePath, element, context);\n }\n }\n}\n\nfunction collectOutputChanges(element: TmplAstElement, source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n for (const output of element.outputs) {\n const newName = OUTPUT_RENAMES.get(output.name);\n if (newName) {\n edits.push({ start: output.keySpan!.start.offset, end: output.keySpan!.end.offset, replacement: newName });\n }\n if (REMOVED_OUTPUTS.has(output.name)) {\n removeAttribute(output.sourceSpan.start.offset, output.sourceSpan.end.offset, source, edits);\n const { line } = element.startSourceSpan.start;\n context.logger.warn(\n `${filePath}:${line + 1} - \"(${output.name})\" removed. Multi-sort is now supported by (sortChange) output.`,\n );\n }\n }\n}\n\nfunction collectPaginatorMigration(element: TmplAstElement, source: string, edits: Edit[]): boolean {\n let found = false;\n\n for (const attr of element.attributes) {\n if (attr.name === 'paginable') {\n removeAttribute(attr.sourceSpan.start.offset, attr.sourceSpan.end.offset, source, edits);\n found = true;\n }\n }\n for (const input of element.inputs) {\n if (input.name === 'paginable') {\n removeAttribute(input.sourceSpan.start.offset, input.sourceSpan.end.offset, source, edits);\n found = true;\n }\n }\n\n if (found) {\n // Add [paginator]=\"paginator\" before closing > of opening tag\n const insertPos = element.startSourceSpan.end.offset - 1;\n edits.push({ start: insertPos, end: insertPos, replacement: ' [paginator]=\"paginator\"' });\n\n // Add eui-paginator after </table>\n if (element.endSourceSpan) {\n const afterTable = element.endSourceSpan.end.offset;\n edits.push({\n start: afterTable,\n end: afterTable,\n replacement: '\\n<!-- TODO: Configure paginator and implement onPageChange handler -->\\n<eui-paginator #paginator [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\" />',\n });\n }\n }\n\n return found;\n}\n\nfunction collectEmptyMessageRename(element: TmplAstElement, edits: Edit[]): void {\n // Handle direct attribute on elements (unlikely but handle)\n for (const attr of element.attributes) {\n if (attr.name === 'euiTemplate' && attr.value === 'emptyMessage' && attr.valueSpan) {\n edits.push({ start: attr.valueSpan.start.offset, end: attr.valueSpan.end.offset, replacement: 'footer' });\n }\n }\n}\n\nfunction collectTemplateEmptyMessageRename(template: TmplAstTemplate, edits: Edit[]): void {\n for (const attr of template.templateAttrs) {\n if (attr instanceof TmplAstTextAttribute && attr.name === 'euiTemplate' && attr.value === 'emptyMessage' && attr.valueSpan) {\n edits.push({ start: attr.valueSpan.start.offset, end: attr.valueSpan.end.offset, replacement: 'footer' });\n }\n }\n for (const attr of template.attributes) {\n if (attr.name === 'euiTemplate' && attr.value === 'emptyMessage' && attr.valueSpan) {\n edits.push({ start: attr.valueSpan.start.offset, end: attr.valueSpan.end.offset, replacement: 'footer' });\n }\n }\n}\n\n// --- Pipe rename via AST ---\n\nfunction collectPipeRenames(nodes: TmplAstNode[], source: string, edits: Edit[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n for (const input of node.inputs) {\n visitExpressionForPipes(input.value, edits);\n }\n for (const output of node.outputs) {\n if (output.handler) visitExpressionForPipes(output.handler, edits);\n }\n collectPipeRenames(node.children, source, edits);\n }\n if (node instanceof TmplAstTemplate) {\n for (const input of node.inputs) {\n visitExpressionForPipes(input.value, edits);\n }\n collectPipeRenames(node.children, source, edits);\n }\n if (node instanceof TmplAstBoundText) {\n visitExpressionForPipes(node.value, edits);\n }\n }\n}\n\nfunction visitExpressionForPipes(expr: AST, edits: Edit[]): void {\n if (expr instanceof ASTWithSource && expr.ast) {\n visitAstForPipes(expr.ast, edits);\n } else {\n visitAstForPipes(expr, edits);\n }\n}\n\nfunction visitAstForPipes(ast: AST, edits: Edit[]): void {\n if (ast instanceof BindingPipe) {\n if (ast.name === OLD_PIPE && ast.nameSpan) {\n edits.push({ start: ast.nameSpan.start, end: ast.nameSpan.end, replacement: NEW_PIPE });\n }\n visitAstForPipes(ast.exp, edits);\n for (const arg of ast.args) {\n visitAstForPipes(arg, edits);\n }\n return;\n }\n\n if (ast instanceof Interpolation) {\n for (const expr of ast.expressions) {\n visitAstForPipes(expr, edits);\n }\n return;\n }\n\n // Recursively visit all properties that could contain AST nodes\n for (const key of Object.keys(ast)) {\n // eslint-disable-next-line\n const val = (ast as any)[key];\n if (val instanceof AST) {\n visitAstForPipes(val, edits);\n } else if (Array.isArray(val)) {\n for (const item of val) {\n if (item instanceof AST) visitAstForPipes(item, edits);\n }\n }\n }\n}\n\n// --- Import handling for paginator ---\n\nfunction addPaginatorImport(source: string, filePath: string): string {\n if (source.includes(PAGINATOR_COMPONENT)) return source;\n\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Add import statement after last import\n let lastImportEnd = 0;\n for (const stmt of sourceFile.statements) {\n if (ts.isImportDeclaration(stmt)) {\n lastImportEnd = stmt.getEnd();\n }\n }\n\n if (lastImportEnd > 0) {\n edits.push({\n start: lastImportEnd,\n end: lastImportEnd,\n replacement: `\\nimport { ${PAGINATOR_COMPONENT} } from '${PAGINATOR_IMPORT_PATH}';`,\n });\n }\n\n // Add to component imports array\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === 'imports' && isComponentMetadataProperty(node)) {\n if (ts.isArrayLiteralExpression(node.initializer)) {\n const arr = node.initializer;\n const elements = arr.elements;\n if (elements.length > 0) {\n const lastElement = elements[elements.length - 1];\n edits.push({\n start: lastElement.getEnd(),\n end: lastElement.getEnd(),\n replacement: `, ${PAGINATOR_COMPONENT}`,\n });\n } else {\n const insertPos = arr.getStart(sourceFile) + 1;\n edits.push({ start: insertPos, end: insertPos, replacement: PAGINATOR_COMPONENT });\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return applyEdits(source, edits);\n}\n\n// --- Helpers ---\n\nfunction removeAttribute(start: number, end: number, source: string, edits: Edit[]): void {\n let adjustedStart = start;\n while (adjustedStart > 0 && (source[adjustedStart - 1] === ' ' || source[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n edits.push({ start: adjustedStart, end, replacement: '' });\n}\n\nfunction logRemovalWarning(name: string, filePath: string, element: TmplAstElement, context: SchematicContext): void {\n const { line } = element.startSourceSpan.start;\n if (name === 'defaultMultiOrder') {\n context.logger.warn(`${filePath}:${line + 1} - \"[${name}]\" removed. Use setSort(Sort[]) to initialize sorting.`);\n } else {\n context.logger.warn(`${filePath}:${line + 1} - \"[${name}]\" removed to align to Design System.`);\n }\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction applyEdits(source: string, edits: Edit[]): string {\n const unique = new Map<string, Edit>();\n for (const edit of edits) {\n const key = `${edit.start}:${edit.end}`;\n unique.set(key, edit);\n }\n let result = source;\n for (const edit of [...unique.values()].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 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('.html') && !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",
2967
+ "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 TextChange {\n start: number;\n end: number;\n text: string;\n}\n\ninterface MigrationResult {\n content: string;\n migrated: number;\n skipped: number;\n}\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst OLD_LABEL = 'eui-tab-label';\nconst OLD_SUB_LABEL = 'euiTabSubLabel';\nconst OLD_CONTENT = 'eui-tab-content';\nconst NEW_HEADER = 'eui-tab-header';\nconst NEW_HEADER_LABEL = 'eui-tab-header-label';\nconst NEW_HEADER_SUB_LABEL = 'eui-tab-header-sub-label';\nconst NEW_BODY = 'eui-tab-body';\n\nexport function migrateEuiTabs(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let migrated = 0;\n let skipped = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) {\n return;\n }\n\n const original = buffer.toString('utf-8');\n const result = path.endsWith('.html')\n ? migrateTemplate(original, path, context)\n : migrateInlineTemplates(original, path, context);\n\n migrated += result.migrated;\n skipped += result.skipped;\n\n if (result.content !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate ${result.migrated} tab block(s) in ${path}`);\n } else {\n tree.overwrite(path, result.content);\n }\n }\n });\n\n context.logger.info(`Migrated ${migrated} EUI tab template block(s).`);\n if (skipped > 0) {\n context.logger.warn(`Skipped ${skipped} malformed EUI tab template block(s).`);\n }\n if (options.dryRun) {\n logDryRunNote(context);\n }\n\n return tree;\n };\n}\n\nfunction migrateInlineTemplates(source: string, filePath: string, context: SchematicContext): MigrationResult {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: TextChange[] = [];\n let migrated = 0;\n let skipped = 0;\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const initializer = unwrapExpression(node.initializer);\n\n if (ts.isStringLiteral(initializer) || ts.isNoSubstitutionTemplateLiteral(initializer)) {\n const start = initializer.getStart(sourceFile) + 1;\n const end = initializer.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n const result = migrateTemplate(rawTemplate, `${filePath}@inline-template`, context);\n\n migrated += result.migrated;\n skipped += result.skipped;\n\n if (result.content !== rawTemplate) {\n changes.push({ start, end, text: result.content });\n }\n } else if (ts.isTemplateExpression(initializer)) {\n context.logger.warn(`Skipping interpolated inline template in ${filePath}.`);\n skipped++;\n }\n }\n\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return {\n content: applyChanges(source, changes),\n migrated,\n skipped,\n };\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (\n (ts.isIdentifier(name) && name.text === 'template') ||\n (ts.isStringLiteral(name) && name.text === 'template')\n );\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n\n return current;\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) {\n return false;\n }\n\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) {\n return false;\n }\n\n return (\n ts.isDecorator(callExpression.parent) &&\n ts.isIdentifier(callExpression.expression) &&\n callExpression.expression.text === 'Component'\n );\n}\n\nfunction migrateTemplate(source: string, filePath: string, context: SchematicContext): MigrationResult {\n const parsed = parseTemplate(source, filePath, { preserveWhitespaces: true });\n const changes: TextChange[] = [];\n let migrated = 0;\n let skipped = 0;\n\n for (const error of parsed.errors ?? []) {\n context.logger.warn(`Template parse warning in ${filePath}: ${error.msg}`);\n }\n\n for (const tab of findElements(parsed.nodes, 'eui-tab')) {\n const label = findDirectChild(tab, OLD_LABEL);\n const content = findDirectChild(tab, OLD_CONTENT);\n const hasOldMarkup = Boolean(label || content);\n const hasNewMarkup = Boolean(findDirectChild(tab, NEW_HEADER) || findDirectChild(tab, NEW_BODY));\n\n if (!hasOldMarkup || hasNewMarkup) {\n continue;\n }\n\n if (!label || !content) {\n context.logger.warn(`Skipping malformed <eui-tab> in ${filePath}.`);\n skipped++;\n continue;\n }\n\n changes.push({\n start: label.sourceSpan.start.offset,\n end: label.sourceSpan.end.offset,\n text: buildHeaderReplacement(source, label),\n });\n changes.push({\n start: content.sourceSpan.start.offset,\n end: content.sourceSpan.end.offset,\n text: buildBodyReplacement(source, content),\n });\n migrated++;\n }\n\n return {\n content: applyChanges(source, withoutOverlaps(changes)),\n migrated,\n skipped,\n };\n}\n\nfunction findElements(nodes: readonly TmplAstNode[], name: string): TmplAstElement[] {\n const matches: TmplAstElement[] = [];\n\n for (const node of nodes) {\n if (isElement(node)) {\n if (node.name === name) {\n matches.push(node);\n }\n matches.push(...findElements(node.children, name));\n }\n }\n\n return matches;\n}\n\nfunction findDirectChild(element: TmplAstElement, name: string): TmplAstElement | undefined {\n return element.children.find((child): child is TmplAstElement => isElement(child) && child.name === name);\n}\n\nfunction isElement(node: TmplAstNode): node is TmplAstElement {\n return node instanceof TmplAstElement;\n}\n\nfunction buildHeaderReplacement(source: string, label: TmplAstElement): string {\n const indent = getIndent(source, label.sourceSpan.start.offset);\n const labelAttributes = getAttributeText(source, label, OLD_LABEL);\n const subLabels = findElements(label.children, OLD_SUB_LABEL);\n const mainLabelContent = removeElementRanges(getInnerText(source, label), label, subLabels);\n const lines = [\n `<${NEW_HEADER}>`,\n `${indent} <${NEW_HEADER_LABEL}${labelAttributes}>`,\n ...formatInnerLines(mainLabelContent, `${indent} `),\n `${indent} </${NEW_HEADER_LABEL}>`,\n ];\n\n for (const subLabel of subLabels) {\n const subLabelAttributes = getAttributeText(source, subLabel, OLD_SUB_LABEL);\n lines.push(\n `${indent} <${NEW_HEADER_SUB_LABEL}${subLabelAttributes}>`,\n ...formatInnerLines(getInnerText(source, subLabel), `${indent} `),\n `${indent} </${NEW_HEADER_SUB_LABEL}>`,\n );\n }\n\n lines.push(`${indent}</${NEW_HEADER}>`);\n\n return lines.join('\\n');\n}\n\nfunction buildBodyReplacement(source: string, content: TmplAstElement): string {\n const indent = getIndent(source, content.sourceSpan.start.offset);\n const attributes = getAttributeText(source, content, OLD_CONTENT);\n const innerText = getInnerText(source, content);\n const trimmed = innerText.trim();\n\n if (trimmed && !trimmed.includes('\\n')) {\n return `<${NEW_BODY}${attributes}>${trimmed}</${NEW_BODY}>`;\n }\n\n return [\n `<${NEW_BODY}${attributes}>`,\n ...formatInnerLines(innerText, `${indent} `),\n `${indent}</${NEW_BODY}>`,\n ].join('\\n');\n}\n\nfunction getInnerText(source: string, element: TmplAstElement): string {\n if (!element.endSourceSpan) {\n return '';\n }\n\n return source.slice(element.startSourceSpan.end.offset, element.endSourceSpan.start.offset);\n}\n\nfunction removeElementRanges(source: string, parent: TmplAstElement, elements: readonly TmplAstElement[]): string {\n const parentContentStart = parent.startSourceSpan.end.offset;\n let result = source;\n\n for (const element of [...elements].sort((a, b) => b.sourceSpan.start.offset - a.sourceSpan.start.offset)) {\n const start = element.sourceSpan.start.offset - parentContentStart;\n const end = element.sourceSpan.end.offset - parentContentStart;\n result = result.slice(0, start) + result.slice(end);\n }\n\n return result;\n}\n\nfunction getAttributeText(source: string, element: TmplAstElement, tagName: string): string {\n const startTag = source.slice(element.startSourceSpan.start.offset, element.startSourceSpan.end.offset);\n const tagStart = startTag.indexOf(tagName);\n\n if (tagStart === -1) {\n return '';\n }\n\n const contentEnd = startTag.endsWith('/>') ? startTag.length - 2 : startTag.length - 1;\n return startTag.slice(tagStart + tagName.length, contentEnd).trimEnd();\n}\n\nfunction getIndent(source: string, offset: number): string {\n const lineStart = source.lastIndexOf('\\n', offset - 1) + 1;\n const prefix = source.slice(lineStart, offset);\n return prefix.match(/^\\s*/)?.[0] ?? '';\n}\n\nfunction formatInnerLines(source: string, indent: string): string[] {\n const trimmed = source.trim();\n\n if (!trimmed) {\n return [];\n }\n\n return trimmed.split(/\\r?\\n/).map((line) => `${indent}${line.trim()}`);\n}\n\nfunction withoutOverlaps(changes: TextChange[]): TextChange[] {\n const accepted: TextChange[] = [];\n\n for (const change of [...changes].sort((a, b) => a.start - b.start || b.end - a.end)) {\n if (!accepted.some((current) => change.start < current.end && current.start < change.end)) {\n accepted.push(change);\n }\n }\n\n return accepted;\n}\n\nfunction applyChanges(source: string, changes: readonly TextChange[]): string {\n let result = source;\n\n for (const change of [...changes].sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n\n return result;\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('.html') && !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",
2968
2968
  "displayName": "Schema",
2969
2969
  "properties": [
2970
2970
  {
@@ -2976,7 +2976,7 @@
2976
2976
  "indexKey": "",
2977
2977
  "optional": true,
2978
2978
  "description": "",
2979
- "line": 49,
2979
+ "line": 20,
2980
2980
  "rawdescription": "\n"
2981
2981
  },
2982
2982
  {
@@ -2988,7 +2988,7 @@
2988
2988
  "indexKey": "",
2989
2989
  "optional": true,
2990
2990
  "description": "",
2991
- "line": 48,
2991
+ "line": 19,
2992
2992
  "rawdescription": "\n"
2993
2993
  }
2994
2994
  ],
@@ -3006,12 +3006,12 @@
3006
3006
  },
3007
3007
  {
3008
3008
  "name": "Schema",
3009
- "id": "interface-Schema-760dec88d3f709d5b38226e55f7cbfb1e5fabcea6c004fd46e611be1dd563b8b247e9e6c77667e5582fe7b443374ba2c4facd2b2db2985edb46c9a4a37a8a876-18",
3010
- "file": "packages/core/schematics/migrate-eui-tabs/index.ts",
3009
+ "id": "interface-Schema-e1cd02924eb82a618c71a0b26c081bdd020519d2699aa0e2dc98640c4e0f347c3649b967c5fc87543e41bbbfabd1304835850ccc38f40684d6521c242b2030ed-18",
3010
+ "file": "packages/core/schematics/migrate-eui-toolbar-menu/index.ts",
3011
3011
  "deprecated": false,
3012
3012
  "deprecationMessage": "",
3013
3013
  "type": "interface",
3014
- "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 TextChange {\n start: number;\n end: number;\n text: string;\n}\n\ninterface MigrationResult {\n content: string;\n migrated: number;\n skipped: number;\n}\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst OLD_LABEL = 'eui-tab-label';\nconst OLD_SUB_LABEL = 'euiTabSubLabel';\nconst OLD_CONTENT = 'eui-tab-content';\nconst NEW_HEADER = 'eui-tab-header';\nconst NEW_HEADER_LABEL = 'eui-tab-header-label';\nconst NEW_HEADER_SUB_LABEL = 'eui-tab-header-sub-label';\nconst NEW_BODY = 'eui-tab-body';\n\nexport function migrateEuiTabs(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let migrated = 0;\n let skipped = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) {\n return;\n }\n\n const original = buffer.toString('utf-8');\n const result = path.endsWith('.html')\n ? migrateTemplate(original, path, context)\n : migrateInlineTemplates(original, path, context);\n\n migrated += result.migrated;\n skipped += result.skipped;\n\n if (result.content !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate ${result.migrated} tab block(s) in ${path}`);\n } else {\n tree.overwrite(path, result.content);\n }\n }\n });\n\n context.logger.info(`Migrated ${migrated} EUI tab template block(s).`);\n if (skipped > 0) {\n context.logger.warn(`Skipped ${skipped} malformed EUI tab template block(s).`);\n }\n if (options.dryRun) {\n logDryRunNote(context);\n }\n\n return tree;\n };\n}\n\nfunction migrateInlineTemplates(source: string, filePath: string, context: SchematicContext): MigrationResult {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: TextChange[] = [];\n let migrated = 0;\n let skipped = 0;\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const initializer = unwrapExpression(node.initializer);\n\n if (ts.isStringLiteral(initializer) || ts.isNoSubstitutionTemplateLiteral(initializer)) {\n const start = initializer.getStart(sourceFile) + 1;\n const end = initializer.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n const result = migrateTemplate(rawTemplate, `${filePath}@inline-template`, context);\n\n migrated += result.migrated;\n skipped += result.skipped;\n\n if (result.content !== rawTemplate) {\n changes.push({ start, end, text: result.content });\n }\n } else if (ts.isTemplateExpression(initializer)) {\n context.logger.warn(`Skipping interpolated inline template in ${filePath}.`);\n skipped++;\n }\n }\n\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n return {\n content: applyChanges(source, changes),\n migrated,\n skipped,\n };\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (\n (ts.isIdentifier(name) && name.text === 'template') ||\n (ts.isStringLiteral(name) && name.text === 'template')\n );\n}\n\nfunction unwrapExpression(expression: ts.Expression): ts.Expression {\n let current = expression;\n\n while (ts.isParenthesizedExpression(current)) {\n current = current.expression;\n }\n\n return current;\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) {\n return false;\n }\n\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) {\n return false;\n }\n\n return (\n ts.isDecorator(callExpression.parent) &&\n ts.isIdentifier(callExpression.expression) &&\n callExpression.expression.text === 'Component'\n );\n}\n\nfunction migrateTemplate(source: string, filePath: string, context: SchematicContext): MigrationResult {\n const parsed = parseTemplate(source, filePath, { preserveWhitespaces: true });\n const changes: TextChange[] = [];\n let migrated = 0;\n let skipped = 0;\n\n for (const error of parsed.errors ?? []) {\n context.logger.warn(`Template parse warning in ${filePath}: ${error.msg}`);\n }\n\n for (const tab of findElements(parsed.nodes, 'eui-tab')) {\n const label = findDirectChild(tab, OLD_LABEL);\n const content = findDirectChild(tab, OLD_CONTENT);\n const hasOldMarkup = Boolean(label || content);\n const hasNewMarkup = Boolean(findDirectChild(tab, NEW_HEADER) || findDirectChild(tab, NEW_BODY));\n\n if (!hasOldMarkup || hasNewMarkup) {\n continue;\n }\n\n if (!label || !content) {\n context.logger.warn(`Skipping malformed <eui-tab> in ${filePath}.`);\n skipped++;\n continue;\n }\n\n changes.push({\n start: label.sourceSpan.start.offset,\n end: label.sourceSpan.end.offset,\n text: buildHeaderReplacement(source, label),\n });\n changes.push({\n start: content.sourceSpan.start.offset,\n end: content.sourceSpan.end.offset,\n text: buildBodyReplacement(source, content),\n });\n migrated++;\n }\n\n return {\n content: applyChanges(source, withoutOverlaps(changes)),\n migrated,\n skipped,\n };\n}\n\nfunction findElements(nodes: readonly TmplAstNode[], name: string): TmplAstElement[] {\n const matches: TmplAstElement[] = [];\n\n for (const node of nodes) {\n if (isElement(node)) {\n if (node.name === name) {\n matches.push(node);\n }\n matches.push(...findElements(node.children, name));\n }\n }\n\n return matches;\n}\n\nfunction findDirectChild(element: TmplAstElement, name: string): TmplAstElement | undefined {\n return element.children.find((child): child is TmplAstElement => isElement(child) && child.name === name);\n}\n\nfunction isElement(node: TmplAstNode): node is TmplAstElement {\n return node instanceof TmplAstElement;\n}\n\nfunction buildHeaderReplacement(source: string, label: TmplAstElement): string {\n const indent = getIndent(source, label.sourceSpan.start.offset);\n const labelAttributes = getAttributeText(source, label, OLD_LABEL);\n const subLabels = findElements(label.children, OLD_SUB_LABEL);\n const mainLabelContent = removeElementRanges(getInnerText(source, label), label, subLabels);\n const lines = [\n `<${NEW_HEADER}>`,\n `${indent} <${NEW_HEADER_LABEL}${labelAttributes}>`,\n ...formatInnerLines(mainLabelContent, `${indent} `),\n `${indent} </${NEW_HEADER_LABEL}>`,\n ];\n\n for (const subLabel of subLabels) {\n const subLabelAttributes = getAttributeText(source, subLabel, OLD_SUB_LABEL);\n lines.push(\n `${indent} <${NEW_HEADER_SUB_LABEL}${subLabelAttributes}>`,\n ...formatInnerLines(getInnerText(source, subLabel), `${indent} `),\n `${indent} </${NEW_HEADER_SUB_LABEL}>`,\n );\n }\n\n lines.push(`${indent}</${NEW_HEADER}>`);\n\n return lines.join('\\n');\n}\n\nfunction buildBodyReplacement(source: string, content: TmplAstElement): string {\n const indent = getIndent(source, content.sourceSpan.start.offset);\n const attributes = getAttributeText(source, content, OLD_CONTENT);\n const innerText = getInnerText(source, content);\n const trimmed = innerText.trim();\n\n if (trimmed && !trimmed.includes('\\n')) {\n return `<${NEW_BODY}${attributes}>${trimmed}</${NEW_BODY}>`;\n }\n\n return [\n `<${NEW_BODY}${attributes}>`,\n ...formatInnerLines(innerText, `${indent} `),\n `${indent}</${NEW_BODY}>`,\n ].join('\\n');\n}\n\nfunction getInnerText(source: string, element: TmplAstElement): string {\n if (!element.endSourceSpan) {\n return '';\n }\n\n return source.slice(element.startSourceSpan.end.offset, element.endSourceSpan.start.offset);\n}\n\nfunction removeElementRanges(source: string, parent: TmplAstElement, elements: readonly TmplAstElement[]): string {\n const parentContentStart = parent.startSourceSpan.end.offset;\n let result = source;\n\n for (const element of [...elements].sort((a, b) => b.sourceSpan.start.offset - a.sourceSpan.start.offset)) {\n const start = element.sourceSpan.start.offset - parentContentStart;\n const end = element.sourceSpan.end.offset - parentContentStart;\n result = result.slice(0, start) + result.slice(end);\n }\n\n return result;\n}\n\nfunction getAttributeText(source: string, element: TmplAstElement, tagName: string): string {\n const startTag = source.slice(element.startSourceSpan.start.offset, element.startSourceSpan.end.offset);\n const tagStart = startTag.indexOf(tagName);\n\n if (tagStart === -1) {\n return '';\n }\n\n const contentEnd = startTag.endsWith('/>') ? startTag.length - 2 : startTag.length - 1;\n return startTag.slice(tagStart + tagName.length, contentEnd).trimEnd();\n}\n\nfunction getIndent(source: string, offset: number): string {\n const lineStart = source.lastIndexOf('\\n', offset - 1) + 1;\n const prefix = source.slice(lineStart, offset);\n return prefix.match(/^\\s*/)?.[0] ?? '';\n}\n\nfunction formatInnerLines(source: string, indent: string): string[] {\n const trimmed = source.trim();\n\n if (!trimmed) {\n return [];\n }\n\n return trimmed.split(/\\r?\\n/).map((line) => `${indent}${line.trim()}`);\n}\n\nfunction withoutOverlaps(changes: TextChange[]): TextChange[] {\n const accepted: TextChange[] = [];\n\n for (const change of [...changes].sort((a, b) => a.start - b.start || b.end - a.end)) {\n if (!accepted.some((current) => change.start < current.end && current.start < change.end)) {\n accepted.push(change);\n }\n }\n\n return accepted;\n}\n\nfunction applyChanges(source: string, changes: readonly TextChange[]): string {\n let result = source;\n\n for (const change of [...changes].sort((a, b) => b.start - a.start)) {\n result = result.slice(0, change.start) + change.text + result.slice(change.end);\n }\n\n return result;\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('.html') && !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",
3014
+ "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\nconst OLD_TAG = 'eui-toolbar-menu';\nconst NEW_TAG = 'eui-toolbar-mega-menu';\nconst OLD_COMPONENT = 'EuiToolbarMenuComponent';\nconst NEW_COMPONENT = 'EuiToolbarMegaMenuComponent';\nconst OLD_INTERFACE = 'ToolbarItem';\nconst NEW_INTERFACE = 'EuiMenuItem';\nconst NEW_COMPONENT_PATH = '@eui/components/layout';\nconst NEW_INTERFACE_PATH = '@eui/core';\nconst REMOVED_OUTPUT = 'menuItemClick';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\nexport function migrateEuiToolbarMenu(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let fileCount = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(OLD_TAG) && !original.includes(OLD_COMPONENT) && !original.includes(OLD_INTERFACE)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original, path, context);\n } else {\n result = migrateTypeScript(original, path, context);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate eui-toolbar-menu → eui-toolbar-mega-menu in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n fileCount++;\n }\n });\n\n context.logger.info(`Migrated eui-toolbar-menu → eui-toolbar-mega-menu in ${fileCount} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction migrateTemplate(source: string, filePath: string, context: SchematicContext): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: Edit[] = [];\n\n visitNodes(parsed.nodes, source, edits, filePath, context);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateTypeScript(source: string, filePath: string, context: SchematicContext): string {\n let result = migrateInlineTemplates(source, filePath, context);\n result = migrateImportsAndTypes(result, filePath, context);\n return result;\n}\n\nfunction migrateInlineTemplates(source: string, filePath: string, context: SchematicContext): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(OLD_TAG)) {\n ts.forEachChild(node, visit); return; \n}\n const migrated = migrateTemplate(rawTemplate, filePath, context);\n if (migrated !== rawTemplate) changes.push({ start, end, replacement: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return applyEdits(source, changes);\n}\n\nfunction migrateImportsAndTypes(source: string, filePath: string, context: SchematicContext): string {\n if (!source.includes(OLD_COMPONENT) && !source.includes(OLD_INTERFACE)) return source;\n\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Track if EuiMenuItem is already imported from @eui/core\n let hasEuiMenuItemImport = false;\n\n // First pass: analyze imports\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const moduleSpec = (stmt.moduleSpecifier as ts.StringLiteral).text;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n for (const specifier of namedBindings.elements) {\n if (specifier.name.text === NEW_INTERFACE && moduleSpec === NEW_INTERFACE_PATH) {\n hasEuiMenuItemImport = true;\n }\n }\n }\n\n // Second pass: collect edits for import declarations\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n const moduleSpec = stmt.moduleSpecifier as ts.StringLiteral;\n const specifiers = namedBindings.elements;\n const hasComponent = specifiers.some((s) => s.name.text === OLD_COMPONENT);\n const hasInterface = specifiers.some((s) => s.name.text === OLD_INTERFACE);\n\n if (hasComponent && hasInterface) {\n // Both are in the same import → must split into two different paths\n const others = specifiers.filter((s) => s.name.text !== OLD_COMPONENT && s.name.text !== OLD_INTERFACE);\n const lines: string[] = [];\n lines.push(`import { ${NEW_COMPONENT} } from '${NEW_COMPONENT_PATH}';`);\n if (!hasEuiMenuItemImport) {\n lines.push(`import { ${NEW_INTERFACE} } from '${NEW_INTERFACE_PATH}';`);\n }\n if (others.length > 0) {\n const otherNames = others.map((s) => s.name.text).join(', ');\n lines.push(`import { ${otherNames} } from '${moduleSpec.text}';`);\n }\n edits.push({\n start: stmt.getStart(sourceFile),\n end: stmt.getEnd(),\n replacement: lines.join('\\n'),\n });\n } else if (hasComponent) {\n edits.push({\n start: moduleSpec.getStart(sourceFile) + 1,\n end: moduleSpec.getEnd() - 1,\n replacement: NEW_COMPONENT_PATH,\n });\n for (const specifier of specifiers) {\n if (specifier.name.text === OLD_COMPONENT) {\n edits.push({\n start: specifier.name.getStart(sourceFile),\n end: specifier.name.getEnd(),\n replacement: NEW_COMPONENT,\n });\n }\n }\n } else if (hasInterface) {\n if (hasEuiMenuItemImport) {\n removeImportSpecifier(namedBindings, specifiers.find((s) => s.name.text === OLD_INTERFACE)!, sourceFile, edits);\n } else {\n edits.push({\n start: moduleSpec.getStart(sourceFile) + 1,\n end: moduleSpec.getEnd() - 1,\n replacement: NEW_INTERFACE_PATH,\n });\n for (const specifier of specifiers) {\n if (specifier.name.text === OLD_INTERFACE) {\n edits.push({\n start: specifier.name.getStart(sourceFile),\n end: specifier.name.getEnd(),\n replacement: NEW_INTERFACE,\n });\n }\n }\n }\n }\n }\n\n // Third pass: rename identifier references in non-import positions\n const visitRefs = (node: ts.Node): void => {\n if (ts.isImportDeclaration(node)) return; // skip imports (already handled)\n if (ts.isIdentifier(node)) {\n if (node.text === OLD_COMPONENT) {\n edits.push({ start: node.getStart(sourceFile), end: node.getEnd(), replacement: NEW_COMPONENT });\n }\n if (node.text === OLD_INTERFACE) {\n edits.push({ start: node.getStart(sourceFile), end: node.getEnd(), replacement: NEW_INTERFACE });\n }\n }\n ts.forEachChild(node, visitRefs);\n };\n\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) {\n visitRefs(stmt);\n }\n }\n\n // Warn about ToolbarItem-specific properties\n warnRemovedProperties(sourceFile, filePath, context);\n\n return applyEdits(source, edits);\n}\n\nfunction removeImportSpecifier(\n namedImports: ts.NamedImports,\n specifier: ts.ImportSpecifier,\n sourceFile: ts.SourceFile,\n edits: Edit[],\n): void {\n const elements = namedImports.elements;\n if (elements.length === 1) {\n // Remove the entire import declaration\n const importDecl = namedImports.parent.parent;\n edits.push({\n start: importDecl.getStart(sourceFile),\n end: importDecl.getEnd(),\n replacement: '',\n });\n } else {\n // Remove just this specifier with surrounding comma/whitespace\n const idx = elements.indexOf(specifier);\n let start: number;\n let end: number;\n if (idx < elements.length - 1) {\n start = specifier.getStart(sourceFile);\n end = elements[idx + 1].getStart(sourceFile);\n } else {\n start = elements[idx - 1].getEnd();\n end = specifier.getEnd();\n }\n edits.push({ start, end, replacement: '' });\n }\n}\n\nfunction warnRemovedProperties(sourceFile: ts.SourceFile, filePath: string, context: SchematicContext): void {\n const deprecated = ['isHome', 'isSeparator'];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && deprecated.includes(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${filePath}:${line + 1} - \"${node.name.text}\" was part of ToolbarItem but does not exist on EuiMenuItem. Review manually.`,\n );\n }\n if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && deprecated.includes(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${filePath}:${line + 1} - \"${node.name.text}\" was part of ToolbarItem but does not exist on EuiMenuItem. Review manually.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n}\n\nfunction visitNodes(nodes: TmplAstNode[], source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === OLD_TAG) {\n collectTagRenames(node, source, edits);\n collectOutputRemovals(node, source, edits, filePath, context);\n }\n visitNodes(node.children, source, edits, filePath, context);\n }\n }\n}\n\nfunction collectTagRenames(element: TmplAstElement, source: string, edits: Edit[]): void {\n // Rename opening tag\n const openStart = element.startSourceSpan.start.offset + 1; // skip '<'\n edits.push({ start: openStart, end: openStart + OLD_TAG.length, replacement: NEW_TAG });\n\n // Rename closing tag\n if (element.endSourceSpan) {\n const closeStart = element.endSourceSpan.start.offset + 2; // skip '</'\n edits.push({ start: closeStart, end: closeStart + OLD_TAG.length, replacement: NEW_TAG });\n }\n}\n\nfunction collectOutputRemovals(\n element: TmplAstElement,\n source: string,\n edits: Edit[],\n filePath: string,\n context: SchematicContext,\n): void {\n for (const output of element.outputs) {\n if (output.name === REMOVED_OUTPUT) {\n let start = output.sourceSpan.start.offset;\n // Remove leading whitespace\n while (start > 0 && (source[start - 1] === ' ' || source[start - 1] === '\\t')) {\n start--;\n }\n edits.push({ start, end: output.sourceSpan.end.offset, replacement: '' });\n\n const { line } = element.startSourceSpan.start;\n context.logger.warn(\n `${filePath}:${line + 1} - \"(menuItemClick)\" has been removed. There is no equivalent on eui-toolbar-mega-menu.`,\n );\n }\n }\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction applyEdits(source: string, edits: Edit[]): string {\n // Deduplicate edits at same position (e.g. module path edits when both Component and ToolbarItem are from same source)\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 // Last wins for same range\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('.html') && !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",
3015
3015
  "displayName": "Schema",
3016
3016
  "properties": [
3017
3017
  {
@@ -3023,7 +3023,7 @@
3023
3023
  "indexKey": "",
3024
3024
  "optional": true,
3025
3025
  "description": "",
3026
- "line": 20,
3026
+ "line": 18,
3027
3027
  "rawdescription": "\n"
3028
3028
  },
3029
3029
  {
@@ -3035,7 +3035,7 @@
3035
3035
  "indexKey": "",
3036
3036
  "optional": true,
3037
3037
  "description": "",
3038
- "line": 19,
3038
+ "line": 17,
3039
3039
  "rawdescription": "\n"
3040
3040
  }
3041
3041
  ],
@@ -3053,12 +3053,12 @@
3053
3053
  },
3054
3054
  {
3055
3055
  "name": "Schema",
3056
- "id": "interface-Schema-e1cd02924eb82a618c71a0b26c081bdd020519d2699aa0e2dc98640c4e0f347c3649b967c5fc87543e41bbbfabd1304835850ccc38f40684d6521c242b2030ed-19",
3057
- "file": "packages/core/schematics/migrate-eui-toolbar-menu/index.ts",
3056
+ "id": "interface-Schema-d36032102ed30a7ada1e3d36bb9ca41b7234b855760cac9783a25818f7ffe2097e1ebd8e808b574ddec0760f827272f6cd561f45f3eb1578f87f39ee2633730a-19",
3057
+ "file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
3058
3058
  "deprecated": false,
3059
3059
  "deprecationMessage": "",
3060
3060
  "type": "interface",
3061
- "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\nconst OLD_TAG = 'eui-toolbar-menu';\nconst NEW_TAG = 'eui-toolbar-mega-menu';\nconst OLD_COMPONENT = 'EuiToolbarMenuComponent';\nconst NEW_COMPONENT = 'EuiToolbarMegaMenuComponent';\nconst OLD_INTERFACE = 'ToolbarItem';\nconst NEW_INTERFACE = 'EuiMenuItem';\nconst NEW_COMPONENT_PATH = '@eui/components/layout';\nconst NEW_INTERFACE_PATH = '@eui/core';\nconst REMOVED_OUTPUT = 'menuItemClick';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\nexport function migrateEuiToolbarMenu(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let fileCount = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(OLD_TAG) && !original.includes(OLD_COMPONENT) && !original.includes(OLD_INTERFACE)) return;\n\n let result: string;\n\n if (path.endsWith('.html')) {\n result = migrateTemplate(original, path, context);\n } else {\n result = migrateTypeScript(original, path, context);\n }\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate eui-toolbar-menu → eui-toolbar-mega-menu in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n fileCount++;\n }\n });\n\n context.logger.info(`Migrated eui-toolbar-menu → eui-toolbar-mega-menu in ${fileCount} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction migrateTemplate(source: string, filePath: string, context: SchematicContext): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const edits: Edit[] = [];\n\n visitNodes(parsed.nodes, source, edits, filePath, context);\n\n return applyEdits(source, edits);\n}\n\nfunction migrateTypeScript(source: string, filePath: string, context: SchematicContext): string {\n let result = migrateInlineTemplates(source, filePath, context);\n result = migrateImportsAndTypes(result, filePath, context);\n return result;\n}\n\nfunction migrateInlineTemplates(source: string, filePath: string, context: SchematicContext): string {\n const sourceFile = ts.createSourceFile('', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const changes: Edit[] = [];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAssignment(node) && isTemplateProperty(node) && isComponentMetadataProperty(node)) {\n const init = unwrapExpression(node.initializer);\n if (ts.isStringLiteral(init) || ts.isNoSubstitutionTemplateLiteral(init)) {\n const start = init.getStart(sourceFile) + 1;\n const end = init.getEnd() - 1;\n const rawTemplate = source.slice(start, end);\n if (!rawTemplate.includes(OLD_TAG)) {\n ts.forEachChild(node, visit); return; \n}\n const migrated = migrateTemplate(rawTemplate, filePath, context);\n if (migrated !== rawTemplate) changes.push({ start, end, replacement: migrated });\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return applyEdits(source, changes);\n}\n\nfunction migrateImportsAndTypes(source: string, filePath: string, context: SchematicContext): string {\n if (!source.includes(OLD_COMPONENT) && !source.includes(OLD_INTERFACE)) return source;\n\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Track if EuiMenuItem is already imported from @eui/core\n let hasEuiMenuItemImport = false;\n\n // First pass: analyze imports\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const moduleSpec = (stmt.moduleSpecifier as ts.StringLiteral).text;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n for (const specifier of namedBindings.elements) {\n if (specifier.name.text === NEW_INTERFACE && moduleSpec === NEW_INTERFACE_PATH) {\n hasEuiMenuItemImport = true;\n }\n }\n }\n\n // Second pass: collect edits for import declarations\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n const moduleSpec = stmt.moduleSpecifier as ts.StringLiteral;\n const specifiers = namedBindings.elements;\n const hasComponent = specifiers.some((s) => s.name.text === OLD_COMPONENT);\n const hasInterface = specifiers.some((s) => s.name.text === OLD_INTERFACE);\n\n if (hasComponent && hasInterface) {\n // Both are in the same import → must split into two different paths\n const others = specifiers.filter((s) => s.name.text !== OLD_COMPONENT && s.name.text !== OLD_INTERFACE);\n const lines: string[] = [];\n lines.push(`import { ${NEW_COMPONENT} } from '${NEW_COMPONENT_PATH}';`);\n if (!hasEuiMenuItemImport) {\n lines.push(`import { ${NEW_INTERFACE} } from '${NEW_INTERFACE_PATH}';`);\n }\n if (others.length > 0) {\n const otherNames = others.map((s) => s.name.text).join(', ');\n lines.push(`import { ${otherNames} } from '${moduleSpec.text}';`);\n }\n edits.push({\n start: stmt.getStart(sourceFile),\n end: stmt.getEnd(),\n replacement: lines.join('\\n'),\n });\n } else if (hasComponent) {\n edits.push({\n start: moduleSpec.getStart(sourceFile) + 1,\n end: moduleSpec.getEnd() - 1,\n replacement: NEW_COMPONENT_PATH,\n });\n for (const specifier of specifiers) {\n if (specifier.name.text === OLD_COMPONENT) {\n edits.push({\n start: specifier.name.getStart(sourceFile),\n end: specifier.name.getEnd(),\n replacement: NEW_COMPONENT,\n });\n }\n }\n } else if (hasInterface) {\n if (hasEuiMenuItemImport) {\n removeImportSpecifier(namedBindings, specifiers.find((s) => s.name.text === OLD_INTERFACE)!, sourceFile, edits);\n } else {\n edits.push({\n start: moduleSpec.getStart(sourceFile) + 1,\n end: moduleSpec.getEnd() - 1,\n replacement: NEW_INTERFACE_PATH,\n });\n for (const specifier of specifiers) {\n if (specifier.name.text === OLD_INTERFACE) {\n edits.push({\n start: specifier.name.getStart(sourceFile),\n end: specifier.name.getEnd(),\n replacement: NEW_INTERFACE,\n });\n }\n }\n }\n }\n }\n\n // Third pass: rename identifier references in non-import positions\n const visitRefs = (node: ts.Node): void => {\n if (ts.isImportDeclaration(node)) return; // skip imports (already handled)\n if (ts.isIdentifier(node)) {\n if (node.text === OLD_COMPONENT) {\n edits.push({ start: node.getStart(sourceFile), end: node.getEnd(), replacement: NEW_COMPONENT });\n }\n if (node.text === OLD_INTERFACE) {\n edits.push({ start: node.getStart(sourceFile), end: node.getEnd(), replacement: NEW_INTERFACE });\n }\n }\n ts.forEachChild(node, visitRefs);\n };\n\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) {\n visitRefs(stmt);\n }\n }\n\n // Warn about ToolbarItem-specific properties\n warnRemovedProperties(sourceFile, filePath, context);\n\n return applyEdits(source, edits);\n}\n\nfunction removeImportSpecifier(\n namedImports: ts.NamedImports,\n specifier: ts.ImportSpecifier,\n sourceFile: ts.SourceFile,\n edits: Edit[],\n): void {\n const elements = namedImports.elements;\n if (elements.length === 1) {\n // Remove the entire import declaration\n const importDecl = namedImports.parent.parent;\n edits.push({\n start: importDecl.getStart(sourceFile),\n end: importDecl.getEnd(),\n replacement: '',\n });\n } else {\n // Remove just this specifier with surrounding comma/whitespace\n const idx = elements.indexOf(specifier);\n let start: number;\n let end: number;\n if (idx < elements.length - 1) {\n start = specifier.getStart(sourceFile);\n end = elements[idx + 1].getStart(sourceFile);\n } else {\n start = elements[idx - 1].getEnd();\n end = specifier.getEnd();\n }\n edits.push({ start, end, replacement: '' });\n }\n}\n\nfunction warnRemovedProperties(sourceFile: ts.SourceFile, filePath: string, context: SchematicContext): void {\n const deprecated = ['isHome', 'isSeparator'];\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && deprecated.includes(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${filePath}:${line + 1} - \"${node.name.text}\" was part of ToolbarItem but does not exist on EuiMenuItem. Review manually.`,\n );\n }\n if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && deprecated.includes(node.name.text)) {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(\n `${filePath}:${line + 1} - \"${node.name.text}\" was part of ToolbarItem but does not exist on EuiMenuItem. Review manually.`,\n );\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n}\n\nfunction visitNodes(nodes: TmplAstNode[], source: string, edits: Edit[], filePath: string, context: SchematicContext): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (node.name === OLD_TAG) {\n collectTagRenames(node, source, edits);\n collectOutputRemovals(node, source, edits, filePath, context);\n }\n visitNodes(node.children, source, edits, filePath, context);\n }\n }\n}\n\nfunction collectTagRenames(element: TmplAstElement, source: string, edits: Edit[]): void {\n // Rename opening tag\n const openStart = element.startSourceSpan.start.offset + 1; // skip '<'\n edits.push({ start: openStart, end: openStart + OLD_TAG.length, replacement: NEW_TAG });\n\n // Rename closing tag\n if (element.endSourceSpan) {\n const closeStart = element.endSourceSpan.start.offset + 2; // skip '</'\n edits.push({ start: closeStart, end: closeStart + OLD_TAG.length, replacement: NEW_TAG });\n }\n}\n\nfunction collectOutputRemovals(\n element: TmplAstElement,\n source: string,\n edits: Edit[],\n filePath: string,\n context: SchematicContext,\n): void {\n for (const output of element.outputs) {\n if (output.name === REMOVED_OUTPUT) {\n let start = output.sourceSpan.start.offset;\n // Remove leading whitespace\n while (start > 0 && (source[start - 1] === ' ' || source[start - 1] === '\\t')) {\n start--;\n }\n edits.push({ start, end: output.sourceSpan.end.offset, replacement: '' });\n\n const { line } = element.startSourceSpan.start;\n context.logger.warn(\n `${filePath}:${line + 1} - \"(menuItemClick)\" has been removed. There is no equivalent on eui-toolbar-mega-menu.`,\n );\n }\n }\n}\n\nfunction isTemplateProperty(node: ts.PropertyAssignment): boolean {\n const name = node.name;\n return (ts.isIdentifier(name) && name.text === 'template') || (ts.isStringLiteral(name) && name.text === 'template');\n}\n\nfunction isComponentMetadataProperty(node: ts.PropertyAssignment): boolean {\n const objectLiteral = node.parent;\n if (!ts.isObjectLiteralExpression(objectLiteral)) return false;\n const callExpression = objectLiteral.parent;\n if (!ts.isCallExpression(callExpression) || callExpression.arguments[0] !== objectLiteral) return false;\n return ts.isDecorator(callExpression.parent) && ts.isIdentifier(callExpression.expression) && callExpression.expression.text === 'Component';\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\nfunction applyEdits(source: string, edits: Edit[]): string {\n // Deduplicate edits at same position (e.g. module path edits when both Component and ToolbarItem are from same source)\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 // Last wins for same range\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('.html') && !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",
3061
+ "sourceCode": "import { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\nconst OLD_CLASS = 'EuiTooltipConfig';\nconst NEW_INTERFACE = 'EuiTooltipInterface';\n\nexport function migrateEuiTooltip(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let fileCount = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(OLD_CLASS)) return;\n\n const result = migrateTypeScript(original, path, context);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate EuiTooltipConfig → EuiTooltipInterface in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n fileCount++;\n }\n });\n\n context.logger.info(`Migrated EuiTooltipConfig → EuiTooltipInterface in ${fileCount} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction migrateTypeScript(source: string, filePath: string, context: SchematicContext): string {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Track if EuiTooltipInterface is already imported\n let hasInterfaceImport = false;\n let classImportDecl: ts.ImportDeclaration | null = null;\n let classImportModuleSpecifier: string | null = null;\n\n // First pass: analyze imports\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n for (const specifier of namedBindings.elements) {\n if (specifier.name.text === NEW_INTERFACE) {\n hasInterfaceImport = true;\n }\n if (specifier.name.text === OLD_CLASS) {\n classImportDecl = stmt;\n classImportModuleSpecifier = (stmt.moduleSpecifier as ts.StringLiteral).text;\n }\n }\n }\n\n // Second pass: handle import declarations\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n const specifiers = namedBindings.elements;\n const classSpecifier = specifiers.find((s) => s.name.text === OLD_CLASS);\n if (!classSpecifier) continue;\n\n if (hasInterfaceImport) {\n // EuiTooltipInterface is already imported elsewhere → remove EuiTooltipConfig from this import\n removeImportSpecifier(namedBindings, classSpecifier, sourceFile, edits);\n } else {\n // Rename EuiTooltipConfig → EuiTooltipInterface in the import\n edits.push({\n start: classSpecifier.name.getStart(sourceFile),\n end: classSpecifier.name.getEnd(),\n replacement: NEW_INTERFACE,\n });\n hasInterfaceImport = true;\n }\n }\n\n // Third pass: replace `new EuiTooltipConfig(...)` → spread/cast to interface\n const visitNewExpressions = (node: ts.Node): void => {\n if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === OLD_CLASS) {\n const args = node.arguments;\n if (args && args.length === 1) {\n const arg = args[0];\n // `new EuiTooltipConfig({ ... })` → `{ ... } as EuiTooltipInterface`\n // But if the argument is just a variable, we keep it: `varName as EuiTooltipInterface`\n const argText = source.slice(arg.getStart(sourceFile), arg.getEnd());\n\n if (ts.isObjectLiteralExpression(arg)) {\n // Inline object: `new EuiTooltipConfig({ x: 1 })` → `{ x: 1 }`\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: argText,\n });\n } else {\n // Variable or expression: `new EuiTooltipConfig(opts)` → `opts`\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: argText,\n });\n }\n } else if (!args || args.length === 0) {\n // `new EuiTooltipConfig()` → `{} as EuiTooltipInterface`\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: `{} as ${NEW_INTERFACE}`,\n });\n }\n return; // don't recurse into children we've already replaced\n }\n ts.forEachChild(node, visitNewExpressions);\n };\n\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) {\n visitNewExpressions(stmt);\n }\n }\n\n // Fourth pass: rename all remaining identifier references (type annotations, etc.)\n const visitRefs = (node: ts.Node): void => {\n if (ts.isImportDeclaration(node)) return;\n // Skip nodes we already covered in new expressions\n if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === OLD_CLASS) return;\n\n if (ts.isIdentifier(node) && node.text === OLD_CLASS) {\n // Ensure this is not part of an import declaration\n if (!isPartOfImport(node)) {\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: NEW_INTERFACE,\n });\n }\n }\n ts.forEachChild(node, visitRefs);\n };\n\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) {\n visitRefs(stmt);\n }\n }\n\n return applyEdits(source, edits);\n}\n\nfunction isPartOfImport(node: ts.Node): boolean {\n let current: ts.Node | undefined = node.parent;\n while (current) {\n if (ts.isImportDeclaration(current)) return true;\n current = current.parent;\n }\n return false;\n}\n\nfunction removeImportSpecifier(\n namedImports: ts.NamedImports,\n specifier: ts.ImportSpecifier,\n sourceFile: ts.SourceFile,\n edits: Edit[],\n): void {\n const elements = namedImports.elements;\n if (elements.length === 1) {\n // Remove the entire import declaration\n const importDecl = namedImports.parent.parent;\n let end = importDecl.getEnd();\n // Also remove trailing newline if present\n const fullText = sourceFile.getFullText();\n if (fullText[end] === '\\n') end++;\n edits.push({\n start: importDecl.getStart(sourceFile),\n end,\n replacement: '',\n });\n } else {\n // Remove just this specifier with surrounding comma/whitespace\n const idx = elements.indexOf(specifier);\n let start: number;\n let end: number;\n if (idx < elements.length - 1) {\n // Not the last → remove from this specifier start to next specifier start\n start = specifier.getStart(sourceFile);\n end = elements[idx + 1].getStart(sourceFile);\n } else {\n // Last element → remove from previous element end to this end\n start = elements[idx - 1].getEnd();\n end = specifier.getEnd();\n }\n edits.push({ start, end, replacement: '' });\n }\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",
3062
3062
  "displayName": "Schema",
3063
3063
  "properties": [
3064
3064
  {
@@ -3070,7 +3070,7 @@
3070
3070
  "indexKey": "",
3071
3071
  "optional": true,
3072
3072
  "description": "",
3073
- "line": 18,
3073
+ "line": 7,
3074
3074
  "rawdescription": "\n"
3075
3075
  },
3076
3076
  {
@@ -3082,7 +3082,7 @@
3082
3082
  "indexKey": "",
3083
3083
  "optional": true,
3084
3084
  "description": "",
3085
- "line": 17,
3085
+ "line": 6,
3086
3086
  "rawdescription": "\n"
3087
3087
  }
3088
3088
  ],
@@ -3100,12 +3100,12 @@
3100
3100
  },
3101
3101
  {
3102
3102
  "name": "Schema",
3103
- "id": "interface-Schema-d36032102ed30a7ada1e3d36bb9ca41b7234b855760cac9783a25818f7ffe2097e1ebd8e808b574ddec0760f827272f6cd561f45f3eb1578f87f39ee2633730a-20",
3104
- "file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
3103
+ "id": "interface-Schema-cac2ac952d8245647e8a48b450e8f127a36bcffb394cf2cd81fe9c0810ed02c19e5e1629dbf29a68a5c6f675aed99570e9ac04ae470e13315e20c92cc0c6c453-20",
3104
+ "file": "packages/core/schematics/migrate-to-signals/index.ts",
3105
3105
  "deprecated": false,
3106
3106
  "deprecationMessage": "",
3107
3107
  "type": "interface",
3108
- "sourceCode": "import { DirEntry, Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\nimport * as ts from 'typescript';\nimport { logDryRun, logDryRunNote } from '../utils/dry-run';\n\ninterface Schema {\n path?: string;\n dryRun?: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n replacement: string;\n}\n\nconst OLD_CLASS = 'EuiTooltipConfig';\nconst NEW_INTERFACE = 'EuiTooltipInterface';\n\nexport function migrateEuiTooltip(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let fileCount = 0;\n\n visitDir(tree.getDir(scanPath || '/'), (path) => {\n if (!path.endsWith('.ts')) return;\n\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes(OLD_CLASS)) return;\n\n const result = migrateTypeScript(original, path, context);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would migrate EuiTooltipConfig → EuiTooltipInterface in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n fileCount++;\n }\n });\n\n context.logger.info(`Migrated EuiTooltipConfig → EuiTooltipInterface in ${fileCount} file(s).`);\n if (options.dryRun) {\n logDryRunNote(context);\n }\n return tree;\n };\n}\n\nfunction migrateTypeScript(source: string, filePath: string, context: SchematicContext): string {\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);\n const edits: Edit[] = [];\n\n // Track if EuiTooltipInterface is already imported\n let hasInterfaceImport = false;\n let classImportDecl: ts.ImportDeclaration | null = null;\n let classImportModuleSpecifier: string | null = null;\n\n // First pass: analyze imports\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n for (const specifier of namedBindings.elements) {\n if (specifier.name.text === NEW_INTERFACE) {\n hasInterfaceImport = true;\n }\n if (specifier.name.text === OLD_CLASS) {\n classImportDecl = stmt;\n classImportModuleSpecifier = (stmt.moduleSpecifier as ts.StringLiteral).text;\n }\n }\n }\n\n // Second pass: handle import declarations\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n const namedBindings = stmt.importClause?.namedBindings;\n if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;\n\n const specifiers = namedBindings.elements;\n const classSpecifier = specifiers.find((s) => s.name.text === OLD_CLASS);\n if (!classSpecifier) continue;\n\n if (hasInterfaceImport) {\n // EuiTooltipInterface is already imported elsewhere → remove EuiTooltipConfig from this import\n removeImportSpecifier(namedBindings, classSpecifier, sourceFile, edits);\n } else {\n // Rename EuiTooltipConfig → EuiTooltipInterface in the import\n edits.push({\n start: classSpecifier.name.getStart(sourceFile),\n end: classSpecifier.name.getEnd(),\n replacement: NEW_INTERFACE,\n });\n hasInterfaceImport = true;\n }\n }\n\n // Third pass: replace `new EuiTooltipConfig(...)` → spread/cast to interface\n const visitNewExpressions = (node: ts.Node): void => {\n if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === OLD_CLASS) {\n const args = node.arguments;\n if (args && args.length === 1) {\n const arg = args[0];\n // `new EuiTooltipConfig({ ... })` → `{ ... } as EuiTooltipInterface`\n // But if the argument is just a variable, we keep it: `varName as EuiTooltipInterface`\n const argText = source.slice(arg.getStart(sourceFile), arg.getEnd());\n\n if (ts.isObjectLiteralExpression(arg)) {\n // Inline object: `new EuiTooltipConfig({ x: 1 })` → `{ x: 1 }`\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: argText,\n });\n } else {\n // Variable or expression: `new EuiTooltipConfig(opts)` → `opts`\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: argText,\n });\n }\n } else if (!args || args.length === 0) {\n // `new EuiTooltipConfig()` → `{} as EuiTooltipInterface`\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: `{} as ${NEW_INTERFACE}`,\n });\n }\n return; // don't recurse into children we've already replaced\n }\n ts.forEachChild(node, visitNewExpressions);\n };\n\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) {\n visitNewExpressions(stmt);\n }\n }\n\n // Fourth pass: rename all remaining identifier references (type annotations, etc.)\n const visitRefs = (node: ts.Node): void => {\n if (ts.isImportDeclaration(node)) return;\n // Skip nodes we already covered in new expressions\n if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === OLD_CLASS) return;\n\n if (ts.isIdentifier(node) && node.text === OLD_CLASS) {\n // Ensure this is not part of an import declaration\n if (!isPartOfImport(node)) {\n edits.push({\n start: node.getStart(sourceFile),\n end: node.getEnd(),\n replacement: NEW_INTERFACE,\n });\n }\n }\n ts.forEachChild(node, visitRefs);\n };\n\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) {\n visitRefs(stmt);\n }\n }\n\n return applyEdits(source, edits);\n}\n\nfunction isPartOfImport(node: ts.Node): boolean {\n let current: ts.Node | undefined = node.parent;\n while (current) {\n if (ts.isImportDeclaration(current)) return true;\n current = current.parent;\n }\n return false;\n}\n\nfunction removeImportSpecifier(\n namedImports: ts.NamedImports,\n specifier: ts.ImportSpecifier,\n sourceFile: ts.SourceFile,\n edits: Edit[],\n): void {\n const elements = namedImports.elements;\n if (elements.length === 1) {\n // Remove the entire import declaration\n const importDecl = namedImports.parent.parent;\n let end = importDecl.getEnd();\n // Also remove trailing newline if present\n const fullText = sourceFile.getFullText();\n if (fullText[end] === '\\n') end++;\n edits.push({\n start: importDecl.getStart(sourceFile),\n end,\n replacement: '',\n });\n } else {\n // Remove just this specifier with surrounding comma/whitespace\n const idx = elements.indexOf(specifier);\n let start: number;\n let end: number;\n if (idx < elements.length - 1) {\n // Not the last → remove from this specifier start to next specifier start\n start = specifier.getStart(sourceFile);\n end = elements[idx + 1].getStart(sourceFile);\n } else {\n // Last element → remove from previous element end to this end\n start = elements[idx - 1].getEnd();\n end = specifier.getEnd();\n }\n edits.push({ start, end, replacement: '' });\n }\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",
3108
+ "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",
3109
3109
  "displayName": "Schema",
3110
3110
  "properties": [
3111
3111
  {
@@ -3117,7 +3117,7 @@
3117
3117
  "indexKey": "",
3118
3118
  "optional": true,
3119
3119
  "description": "",
3120
- "line": 7,
3120
+ "line": 9,
3121
3121
  "rawdescription": "\n"
3122
3122
  },
3123
3123
  {
@@ -3129,7 +3129,7 @@
3129
3129
  "indexKey": "",
3130
3130
  "optional": true,
3131
3131
  "description": "",
3132
- "line": 6,
3132
+ "line": 8,
3133
3133
  "rawdescription": "\n"
3134
3134
  }
3135
3135
  ],
@@ -3147,12 +3147,12 @@
3147
3147
  },
3148
3148
  {
3149
3149
  "name": "Schema",
3150
- "id": "interface-Schema-cac2ac952d8245647e8a48b450e8f127a36bcffb394cf2cd81fe9c0810ed02c19e5e1629dbf29a68a5c6f675aed99570e9ac04ae470e13315e20c92cc0c6c453-21",
3151
- "file": "packages/core/schematics/migrate-to-signals/index.ts",
3150
+ "id": "interface-Schema-817c4b549cc3eab9fcf4936acab2e71182d90a4480369f5c003cbbda10792efa587ad99d65acf049f64e7030e32589e4fabc4a6d7a5621e4fe54725ef91dc9e8-21",
3151
+ "file": "packages/core/schematics/migrate-to-standalone/index.ts",
3152
3152
  "deprecated": false,
3153
3153
  "deprecationMessage": "",
3154
3154
  "type": "interface",
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",
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",
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": 9,
3167
+ "line": 460,
3168
3168
  "rawdescription": "\n"
3169
3169
  },
3170
3170
  {
@@ -3176,7 +3176,7 @@
3176
3176
  "indexKey": "",
3177
3177
  "optional": true,
3178
3178
  "description": "",
3179
- "line": 8,
3179
+ "line": 459,
3180
3180
  "rawdescription": "\n"
3181
3181
  }
3182
3182
  ],
@@ -3194,12 +3194,12 @@
3194
3194
  },
3195
3195
  {
3196
3196
  "name": "Schema",
3197
- "id": "interface-Schema-817c4b549cc3eab9fcf4936acab2e71182d90a4480369f5c003cbbda10792efa587ad99d65acf049f64e7030e32589e4fabc4a6d7a5621e4fe54725ef91dc9e8-22",
3198
- "file": "packages/core/schematics/migrate-to-standalone/index.ts",
3197
+ "id": "interface-Schema-39d3d52e788050bebc4e0b99ed0756f7e9727556cb090ae8796bd4261a56463fe1f479c322b23028cd4134d71e4d1dc44cd248ac62a9a148b5fc46a665466f7c-22",
3198
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
3199
3199
  "deprecated": false,
3200
3200
  "deprecationMessage": "",
3201
3201
  "type": "interface",
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",
3202
+ "sourceCode": "import { parseTemplate, TmplAstBoundAttribute, TmplAstElement, TmplAstNode, TmplAstTextAttribute } 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 Schema {\n path?: string;\n dryRun?: boolean;\n}\n\nconst REMOVED_INPUTS = new Set(['isSquared']);\n\nexport function migrateEuiChip(options: Schema = {}): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const scanPath = options.path ? '/' + options.path.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n let count = 0;\n\n const dir = tree.getDir(scanPath || '/');\n visitDir(dir, (path) => {\n const buffer = tree.read(path);\n if (!buffer) return;\n\n const original = buffer.toString('utf-8');\n if (!original.includes('eui-chip') && !original.includes('euiChip')) return;\n\n const result = path.endsWith('.html')\n ? migrateTemplate(original)\n : migrateInlineTemplates(original);\n\n if (result !== original) {\n if (options.dryRun) {\n logDryRun(context, `Would remove 'isSquared' input in ${path}`);\n } else {\n tree.overwrite(path, result);\n }\n count++;\n }\n\n // Warn about TS usages inline\n if (path.endsWith('.ts') && !path.endsWith('.spec.ts') && original.includes('isSquared')) {\n const sourceFile = ts.createSourceFile(path, original, ts.ScriptTarget.Latest, true);\n\n const visit = (node: ts.Node): void => {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name) && node.name.text === 'isSquared') {\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n context.logger.warn(`${path}:${line + 1} - \"isSquared\" is no longer a valid input on eui-chip. Remove this assignment.`);\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n }\n });\n\n context.logger.info(`Removed deprecated eui-chip 'isSquared' input from ${count} file(s).`);\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('.html') && !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 migrateTemplate(source: string): string {\n const parsed = parseTemplate(source, '', { preserveWhitespaces: true });\n const removals: { start: number; end: number }[] = [];\n\n visitNodes(parsed.nodes, removals);\n\n let result = source;\n for (const { start, end } of removals.sort((a, b) => b.start - a.start)) {\n let adjustedStart = start;\n while (adjustedStart > 0 && (result[adjustedStart - 1] === ' ' || result[adjustedStart - 1] === '\\t')) {\n adjustedStart--;\n }\n result = result.slice(0, adjustedStart) + result.slice(end);\n }\n\n return result;\n}\n\nfunction migrateInlineTemplates(source: string): string {\n const templateRegex = /template\\s*:\\s*`([^`]*)`/gs;\n return source.replace(templateRegex, (match, templateContent: string) => {\n if (!templateContent.includes('eui-chip') && !templateContent.includes('euiChip')) return match;\n const migrated = migrateTemplate(templateContent);\n if (migrated === templateContent) return match;\n return match.replace(templateContent, migrated);\n });\n}\n\nfunction isChipElement(element: TmplAstElement): boolean {\n if (element.name === 'eui-chip') return true;\n return element.attributes.some((a) => a.name === 'euiChip');\n}\n\nfunction visitNodes(nodes: TmplAstNode[], removals: { start: number; end: number }[]): void {\n for (const node of nodes) {\n if (node instanceof TmplAstElement) {\n if (isChipElement(node)) collectRemovals(node, removals);\n visitNodes(node.children, removals);\n }\n }\n}\n\nfunction collectRemovals(element: TmplAstElement, removals: { start: number; end: number }[]): void {\n for (const attr of element.attributes) {\n if (REMOVED_INPUTS.has(attr.name)) {\n removals.push(getAttributeSpan(attr));\n }\n }\n for (const input of element.inputs) {\n if (REMOVED_INPUTS.has(input.name)) {\n removals.push(getAttributeSpan(input));\n }\n }\n}\n\nfunction getAttributeSpan(attr: TmplAstTextAttribute | TmplAstBoundAttribute): { start: number; end: number } {\n return { start: attr.sourceSpan.start.offset, end: attr.sourceSpan.end.offset };\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": 460,
3214
+ "line": 8,
3215
3215
  "rawdescription": "\n"
3216
3216
  },
3217
3217
  {
@@ -3223,7 +3223,7 @@
3223
3223
  "indexKey": "",
3224
3224
  "optional": true,
3225
3225
  "description": "",
3226
- "line": 459,
3226
+ "line": 7,
3227
3227
  "rawdescription": "\n"
3228
3228
  }
3229
3229
  ],
@@ -23257,29 +23257,29 @@
23257
23257
  "name": "NEW_NAME",
23258
23258
  "ctype": "miscellaneous",
23259
23259
  "subtype": "variable",
23260
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
23260
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
23261
23261
  "coverageIgnore": false,
23262
23262
  "deprecated": false,
23263
23263
  "deprecationMessage": "",
23264
23264
  "type": "string",
23265
- "defaultValue": "'euiCTAButton'"
23265
+ "defaultValue": "'contentChange'"
23266
23266
  },
23267
23267
  {
23268
23268
  "name": "NEW_NAME",
23269
23269
  "ctype": "miscellaneous",
23270
23270
  "subtype": "variable",
23271
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
23271
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
23272
23272
  "coverageIgnore": false,
23273
23273
  "deprecated": false,
23274
23274
  "deprecationMessage": "",
23275
23275
  "type": "string",
23276
- "defaultValue": "'contentChange'"
23276
+ "defaultValue": "'iconSvgName'"
23277
23277
  },
23278
23278
  {
23279
23279
  "name": "NEW_NAME",
23280
23280
  "ctype": "miscellaneous",
23281
23281
  "subtype": "variable",
23282
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
23282
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
23283
23283
  "coverageIgnore": false,
23284
23284
  "deprecated": false,
23285
23285
  "deprecationMessage": "",
@@ -23290,12 +23290,12 @@
23290
23290
  "name": "NEW_NAME",
23291
23291
  "ctype": "miscellaneous",
23292
23292
  "subtype": "variable",
23293
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
23293
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
23294
23294
  "coverageIgnore": false,
23295
23295
  "deprecated": false,
23296
23296
  "deprecationMessage": "",
23297
23297
  "type": "string",
23298
- "defaultValue": "'iconSvgName'"
23298
+ "defaultValue": "'euiCTAButton'"
23299
23299
  },
23300
23300
  {
23301
23301
  "name": "NEW_PIPE",
@@ -23402,45 +23402,45 @@
23402
23402
  "name": "OLD_NAME",
23403
23403
  "ctype": "miscellaneous",
23404
23404
  "subtype": "variable",
23405
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
23405
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
23406
23406
  "coverageIgnore": false,
23407
23407
  "deprecated": false,
23408
23408
  "deprecationMessage": "",
23409
23409
  "type": "string",
23410
- "defaultValue": "'euiButtonCall'"
23410
+ "defaultValue": "'onEditorChanged'"
23411
23411
  },
23412
23412
  {
23413
23413
  "name": "OLD_NAME",
23414
23414
  "ctype": "miscellaneous",
23415
23415
  "subtype": "variable",
23416
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
23416
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
23417
23417
  "coverageIgnore": false,
23418
23418
  "deprecated": false,
23419
23419
  "deprecationMessage": "",
23420
23420
  "type": "string",
23421
- "defaultValue": "'onEditorChanged'"
23421
+ "defaultValue": "'iconSvgType'"
23422
23422
  },
23423
23423
  {
23424
23424
  "name": "OLD_NAME",
23425
23425
  "ctype": "miscellaneous",
23426
23426
  "subtype": "variable",
23427
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
23427
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
23428
23428
  "coverageIgnore": false,
23429
23429
  "deprecated": false,
23430
23430
  "deprecationMessage": "",
23431
23431
  "type": "string",
23432
- "defaultValue": "'iconSvgType'"
23432
+ "defaultValue": "'iconSet'"
23433
23433
  },
23434
23434
  {
23435
23435
  "name": "OLD_NAME",
23436
23436
  "ctype": "miscellaneous",
23437
23437
  "subtype": "variable",
23438
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
23438
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
23439
23439
  "coverageIgnore": false,
23440
23440
  "deprecated": false,
23441
23441
  "deprecationMessage": "",
23442
23442
  "type": "string",
23443
- "defaultValue": "'iconSet'"
23443
+ "defaultValue": "'euiButtonCall'"
23444
23444
  },
23445
23445
  {
23446
23446
  "name": "OLD_PIPE",
@@ -23593,45 +23593,45 @@
23593
23593
  "name": "REMOVED_INPUTS",
23594
23594
  "ctype": "miscellaneous",
23595
23595
  "subtype": "variable",
23596
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
23596
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
23597
23597
  "coverageIgnore": false,
23598
23598
  "deprecated": false,
23599
23599
  "deprecationMessage": "",
23600
23600
  "type": "unknown",
23601
- "defaultValue": "new Set(['isSquared'])"
23601
+ "defaultValue": "new Set(['maxVisibleChipsCount', 'isMaxVisibleChipsOpened', 'toggleLinkMoreLabel', 'toggleLinkLessLabel', 'isChipsSorted', 'chipsSortOrder'])"
23602
23602
  },
23603
23603
  {
23604
23604
  "name": "REMOVED_INPUTS",
23605
23605
  "ctype": "miscellaneous",
23606
23606
  "subtype": "variable",
23607
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
23607
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
23608
23608
  "coverageIgnore": false,
23609
23609
  "deprecated": false,
23610
23610
  "deprecationMessage": "",
23611
23611
  "type": "unknown",
23612
- "defaultValue": "new Set(['maxVisibleChipsCount', 'isMaxVisibleChipsOpened', 'toggleLinkMoreLabel', 'toggleLinkLessLabel', 'isChipsSorted', 'chipsSortOrder'])"
23612
+ "defaultValue": "new Set(['type'])"
23613
23613
  },
23614
23614
  {
23615
23615
  "name": "REMOVED_INPUTS",
23616
23616
  "ctype": "miscellaneous",
23617
23617
  "subtype": "variable",
23618
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
23618
+ "file": "packages/core/schematics/migrate-eui-table/index.ts",
23619
23619
  "coverageIgnore": false,
23620
23620
  "deprecated": false,
23621
23621
  "deprecationMessage": "",
23622
23622
  "type": "unknown",
23623
- "defaultValue": "new Set(['type'])"
23623
+ "defaultValue": "new Set(['euiTableBordered', 'isHoverable', 'defaultMultiOrder', 'paginable'])"
23624
23624
  },
23625
23625
  {
23626
23626
  "name": "REMOVED_INPUTS",
23627
23627
  "ctype": "miscellaneous",
23628
23628
  "subtype": "variable",
23629
- "file": "packages/core/schematics/migrate-eui-table/index.ts",
23629
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
23630
23630
  "coverageIgnore": false,
23631
23631
  "deprecated": false,
23632
23632
  "deprecationMessage": "",
23633
23633
  "type": "unknown",
23634
- "defaultValue": "new Set(['euiTableBordered', 'isHoverable', 'defaultMultiOrder', 'paginable'])"
23634
+ "defaultValue": "new Set(['isSquared'])"
23635
23635
  },
23636
23636
  {
23637
23637
  "name": "REMOVED_OUTPUT",
@@ -24426,51 +24426,6 @@
24426
24426
  }
24427
24427
  ]
24428
24428
  },
24429
- {
24430
- "name": "applyEdits",
24431
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
24432
- "ctype": "miscellaneous",
24433
- "subtype": "function",
24434
- "coverageIgnore": false,
24435
- "deprecated": false,
24436
- "deprecationMessage": "",
24437
- "rawdescription": "",
24438
- "description": "",
24439
- "displayName": "applyEdits",
24440
- "args": [
24441
- {
24442
- "name": "source",
24443
- "type": "string",
24444
- "deprecated": false,
24445
- "deprecationMessage": ""
24446
- },
24447
- {
24448
- "name": "edits",
24449
- "deprecated": false,
24450
- "deprecationMessage": ""
24451
- }
24452
- ],
24453
- "returnType": "string",
24454
- "jsdoctags": [
24455
- {
24456
- "name": "source",
24457
- "type": "string",
24458
- "deprecated": false,
24459
- "deprecationMessage": "",
24460
- "tagName": {
24461
- "text": "param"
24462
- }
24463
- },
24464
- {
24465
- "name": "edits",
24466
- "deprecated": false,
24467
- "deprecationMessage": "",
24468
- "tagName": {
24469
- "text": "param"
24470
- }
24471
- }
24472
- ]
24473
- },
24474
24429
  {
24475
24430
  "name": "applyEdits",
24476
24431
  "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
@@ -24786,6 +24741,51 @@
24786
24741
  }
24787
24742
  ]
24788
24743
  },
24744
+ {
24745
+ "name": "applyEdits",
24746
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
24747
+ "ctype": "miscellaneous",
24748
+ "subtype": "function",
24749
+ "coverageIgnore": false,
24750
+ "deprecated": false,
24751
+ "deprecationMessage": "",
24752
+ "rawdescription": "",
24753
+ "description": "",
24754
+ "displayName": "applyEdits",
24755
+ "args": [
24756
+ {
24757
+ "name": "source",
24758
+ "type": "string",
24759
+ "deprecated": false,
24760
+ "deprecationMessage": ""
24761
+ },
24762
+ {
24763
+ "name": "edits",
24764
+ "deprecated": false,
24765
+ "deprecationMessage": ""
24766
+ }
24767
+ ],
24768
+ "returnType": "string",
24769
+ "jsdoctags": [
24770
+ {
24771
+ "name": "source",
24772
+ "type": "string",
24773
+ "deprecated": false,
24774
+ "deprecationMessage": "",
24775
+ "tagName": {
24776
+ "text": "param"
24777
+ }
24778
+ },
24779
+ {
24780
+ "name": "edits",
24781
+ "deprecated": false,
24782
+ "deprecationMessage": "",
24783
+ "tagName": {
24784
+ "text": "param"
24785
+ }
24786
+ }
24787
+ ]
24788
+ },
24789
24789
  {
24790
24790
  "name": "applyEdits",
24791
24791
  "file": "packages/core/schematics/migrate-eui-toolbar-menu/index.ts",
@@ -26040,7 +26040,7 @@
26040
26040
  },
26041
26041
  {
26042
26042
  "name": "collectRemovals",
26043
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
26043
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
26044
26044
  "ctype": "miscellaneous",
26045
26045
  "subtype": "function",
26046
26046
  "coverageIgnore": false,
@@ -26056,6 +26056,12 @@
26056
26056
  "deprecated": false,
26057
26057
  "deprecationMessage": ""
26058
26058
  },
26059
+ {
26060
+ "name": "source",
26061
+ "type": "string",
26062
+ "deprecated": false,
26063
+ "deprecationMessage": ""
26064
+ },
26059
26065
  {
26060
26066
  "name": "removals",
26061
26067
  "deprecated": false,
@@ -26073,6 +26079,15 @@
26073
26079
  "text": "param"
26074
26080
  }
26075
26081
  },
26082
+ {
26083
+ "name": "source",
26084
+ "type": "string",
26085
+ "deprecated": false,
26086
+ "deprecationMessage": "",
26087
+ "tagName": {
26088
+ "text": "param"
26089
+ }
26090
+ },
26076
26091
  {
26077
26092
  "name": "removals",
26078
26093
  "deprecated": false,
@@ -26085,7 +26100,7 @@
26085
26100
  },
26086
26101
  {
26087
26102
  "name": "collectRemovals",
26088
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
26103
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
26089
26104
  "ctype": "miscellaneous",
26090
26105
  "subtype": "function",
26091
26106
  "coverageIgnore": false,
@@ -26101,12 +26116,6 @@
26101
26116
  "deprecated": false,
26102
26117
  "deprecationMessage": ""
26103
26118
  },
26104
- {
26105
- "name": "source",
26106
- "type": "string",
26107
- "deprecated": false,
26108
- "deprecationMessage": ""
26109
- },
26110
26119
  {
26111
26120
  "name": "removals",
26112
26121
  "deprecated": false,
@@ -26124,15 +26133,6 @@
26124
26133
  "text": "param"
26125
26134
  }
26126
26135
  },
26127
- {
26128
- "name": "source",
26129
- "type": "string",
26130
- "deprecated": false,
26131
- "deprecationMessage": "",
26132
- "tagName": {
26133
- "text": "param"
26134
- }
26135
- },
26136
26136
  {
26137
26137
  "name": "removals",
26138
26138
  "deprecated": false,
@@ -26145,7 +26145,7 @@
26145
26145
  },
26146
26146
  {
26147
26147
  "name": "collectRemovals",
26148
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
26148
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
26149
26149
  "ctype": "miscellaneous",
26150
26150
  "subtype": "function",
26151
26151
  "coverageIgnore": false,
@@ -26235,7 +26235,7 @@
26235
26235
  },
26236
26236
  {
26237
26237
  "name": "collectRenames",
26238
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
26238
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
26239
26239
  "ctype": "miscellaneous",
26240
26240
  "subtype": "function",
26241
26241
  "coverageIgnore": false,
@@ -26280,7 +26280,7 @@
26280
26280
  },
26281
26281
  {
26282
26282
  "name": "collectRenames",
26283
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
26283
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
26284
26284
  "ctype": "miscellaneous",
26285
26285
  "subtype": "function",
26286
26286
  "coverageIgnore": false,
@@ -26325,7 +26325,7 @@
26325
26325
  },
26326
26326
  {
26327
26327
  "name": "collectRenames",
26328
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
26328
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
26329
26329
  "ctype": "miscellaneous",
26330
26330
  "subtype": "function",
26331
26331
  "coverageIgnore": false,
@@ -26370,7 +26370,7 @@
26370
26370
  },
26371
26371
  {
26372
26372
  "name": "collectRenames",
26373
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
26373
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
26374
26374
  "ctype": "miscellaneous",
26375
26375
  "subtype": "function",
26376
26376
  "coverageIgnore": false,
@@ -26415,7 +26415,7 @@
26415
26415
  },
26416
26416
  {
26417
26417
  "name": "collectRenames",
26418
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
26418
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
26419
26419
  "ctype": "miscellaneous",
26420
26420
  "subtype": "function",
26421
26421
  "coverageIgnore": false,
@@ -26460,7 +26460,7 @@
26460
26460
  },
26461
26461
  {
26462
26462
  "name": "collectRenames",
26463
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
26463
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
26464
26464
  "ctype": "miscellaneous",
26465
26465
  "subtype": "function",
26466
26466
  "coverageIgnore": false,
@@ -28270,7 +28270,7 @@
28270
28270
  },
28271
28271
  {
28272
28272
  "name": "getAttributeSpan",
28273
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
28273
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
28274
28274
  "ctype": "miscellaneous",
28275
28275
  "subtype": "function",
28276
28276
  "coverageIgnore": false,
@@ -28300,7 +28300,7 @@
28300
28300
  },
28301
28301
  {
28302
28302
  "name": "getAttributeSpan",
28303
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
28303
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
28304
28304
  "ctype": "miscellaneous",
28305
28305
  "subtype": "function",
28306
28306
  "coverageIgnore": false,
@@ -29754,7 +29754,7 @@
29754
29754
  },
29755
29755
  {
29756
29756
  "name": "isChipElement",
29757
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
29757
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
29758
29758
  "ctype": "miscellaneous",
29759
29759
  "subtype": "function",
29760
29760
  "coverageIgnore": false,
@@ -29786,7 +29786,7 @@
29786
29786
  },
29787
29787
  {
29788
29788
  "name": "isChipElement",
29789
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
29789
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
29790
29790
  "ctype": "miscellaneous",
29791
29791
  "subtype": "function",
29792
29792
  "coverageIgnore": false,
@@ -29880,7 +29880,7 @@
29880
29880
  },
29881
29881
  {
29882
29882
  "name": "isComponentMetadataProperty",
29883
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
29883
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
29884
29884
  "ctype": "miscellaneous",
29885
29885
  "subtype": "function",
29886
29886
  "coverageIgnore": false,
@@ -29910,7 +29910,7 @@
29910
29910
  },
29911
29911
  {
29912
29912
  "name": "isComponentMetadataProperty",
29913
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
29913
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
29914
29914
  "ctype": "miscellaneous",
29915
29915
  "subtype": "function",
29916
29916
  "coverageIgnore": false,
@@ -29940,7 +29940,7 @@
29940
29940
  },
29941
29941
  {
29942
29942
  "name": "isComponentMetadataProperty",
29943
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
29943
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
29944
29944
  "ctype": "miscellaneous",
29945
29945
  "subtype": "function",
29946
29946
  "coverageIgnore": false,
@@ -29970,7 +29970,7 @@
29970
29970
  },
29971
29971
  {
29972
29972
  "name": "isComponentMetadataProperty",
29973
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
29973
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
29974
29974
  "ctype": "miscellaneous",
29975
29975
  "subtype": "function",
29976
29976
  "coverageIgnore": false,
@@ -30000,7 +30000,7 @@
30000
30000
  },
30001
30001
  {
30002
30002
  "name": "isComponentMetadataProperty",
30003
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
30003
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
30004
30004
  "ctype": "miscellaneous",
30005
30005
  "subtype": "function",
30006
30006
  "coverageIgnore": false,
@@ -30030,7 +30030,7 @@
30030
30030
  },
30031
30031
  {
30032
30032
  "name": "isComponentMetadataProperty",
30033
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
30033
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
30034
30034
  "ctype": "miscellaneous",
30035
30035
  "subtype": "function",
30036
30036
  "coverageIgnore": false,
@@ -30060,7 +30060,7 @@
30060
30060
  },
30061
30061
  {
30062
30062
  "name": "isComponentMetadataProperty",
30063
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
30063
+ "file": "packages/core/schematics/migrate-eui-table/index.ts",
30064
30064
  "ctype": "miscellaneous",
30065
30065
  "subtype": "function",
30066
30066
  "coverageIgnore": false,
@@ -30090,7 +30090,7 @@
30090
30090
  },
30091
30091
  {
30092
30092
  "name": "isComponentMetadataProperty",
30093
- "file": "packages/core/schematics/migrate-eui-table/index.ts",
30093
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
30094
30094
  "ctype": "miscellaneous",
30095
30095
  "subtype": "function",
30096
30096
  "coverageIgnore": false,
@@ -30425,7 +30425,7 @@
30425
30425
  },
30426
30426
  {
30427
30427
  "name": "isTemplateProperty",
30428
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
30428
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
30429
30429
  "ctype": "miscellaneous",
30430
30430
  "subtype": "function",
30431
30431
  "coverageIgnore": false,
@@ -30455,7 +30455,7 @@
30455
30455
  },
30456
30456
  {
30457
30457
  "name": "isTemplateProperty",
30458
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
30458
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
30459
30459
  "ctype": "miscellaneous",
30460
30460
  "subtype": "function",
30461
30461
  "coverageIgnore": false,
@@ -30485,7 +30485,7 @@
30485
30485
  },
30486
30486
  {
30487
30487
  "name": "isTemplateProperty",
30488
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
30488
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
30489
30489
  "ctype": "miscellaneous",
30490
30490
  "subtype": "function",
30491
30491
  "coverageIgnore": false,
@@ -30515,7 +30515,7 @@
30515
30515
  },
30516
30516
  {
30517
30517
  "name": "isTemplateProperty",
30518
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
30518
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
30519
30519
  "ctype": "miscellaneous",
30520
30520
  "subtype": "function",
30521
30521
  "coverageIgnore": false,
@@ -30545,7 +30545,7 @@
30545
30545
  },
30546
30546
  {
30547
30547
  "name": "isTemplateProperty",
30548
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
30548
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
30549
30549
  "ctype": "miscellaneous",
30550
30550
  "subtype": "function",
30551
30551
  "coverageIgnore": false,
@@ -30575,7 +30575,7 @@
30575
30575
  },
30576
30576
  {
30577
30577
  "name": "isTemplateProperty",
30578
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
30578
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
30579
30579
  "ctype": "miscellaneous",
30580
30580
  "subtype": "function",
30581
30581
  "coverageIgnore": false,
@@ -30605,7 +30605,7 @@
30605
30605
  },
30606
30606
  {
30607
30607
  "name": "isTemplateProperty",
30608
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
30608
+ "file": "packages/core/schematics/migrate-eui-table/index.ts",
30609
30609
  "ctype": "miscellaneous",
30610
30610
  "subtype": "function",
30611
30611
  "coverageIgnore": false,
@@ -30635,7 +30635,7 @@
30635
30635
  },
30636
30636
  {
30637
30637
  "name": "isTemplateProperty",
30638
- "file": "packages/core/schematics/migrate-eui-table/index.ts",
30638
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
30639
30639
  "ctype": "miscellaneous",
30640
30640
  "subtype": "function",
30641
30641
  "coverageIgnore": false,
@@ -32323,39 +32323,7 @@
32323
32323
  },
32324
32324
  {
32325
32325
  "name": "migrateInlineTemplates",
32326
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
32327
- "ctype": "miscellaneous",
32328
- "subtype": "function",
32329
- "coverageIgnore": false,
32330
- "deprecated": false,
32331
- "deprecationMessage": "",
32332
- "rawdescription": "",
32333
- "description": "",
32334
- "displayName": "migrateInlineTemplates",
32335
- "args": [
32336
- {
32337
- "name": "source",
32338
- "type": "string",
32339
- "deprecated": false,
32340
- "deprecationMessage": ""
32341
- }
32342
- ],
32343
- "returnType": "string",
32344
- "jsdoctags": [
32345
- {
32346
- "name": "source",
32347
- "type": "string",
32348
- "deprecated": false,
32349
- "deprecationMessage": "",
32350
- "tagName": {
32351
- "text": "param"
32352
- }
32353
- }
32354
- ]
32355
- },
32356
- {
32357
- "name": "migrateInlineTemplates",
32358
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
32326
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
32359
32327
  "ctype": "miscellaneous",
32360
32328
  "subtype": "function",
32361
32329
  "coverageIgnore": false,
@@ -32387,7 +32355,7 @@
32387
32355
  },
32388
32356
  {
32389
32357
  "name": "migrateInlineTemplates",
32390
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
32358
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
32391
32359
  "ctype": "miscellaneous",
32392
32360
  "subtype": "function",
32393
32361
  "coverageIgnore": false,
@@ -32419,7 +32387,7 @@
32419
32387
  },
32420
32388
  {
32421
32389
  "name": "migrateInlineTemplates",
32422
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
32390
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
32423
32391
  "ctype": "miscellaneous",
32424
32392
  "subtype": "function",
32425
32393
  "coverageIgnore": false,
@@ -32451,7 +32419,7 @@
32451
32419
  },
32452
32420
  {
32453
32421
  "name": "migrateInlineTemplates",
32454
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
32422
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
32455
32423
  "ctype": "miscellaneous",
32456
32424
  "subtype": "function",
32457
32425
  "coverageIgnore": false,
@@ -32483,7 +32451,7 @@
32483
32451
  },
32484
32452
  {
32485
32453
  "name": "migrateInlineTemplates",
32486
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
32454
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
32487
32455
  "ctype": "miscellaneous",
32488
32456
  "subtype": "function",
32489
32457
  "coverageIgnore": false,
@@ -32515,7 +32483,7 @@
32515
32483
  },
32516
32484
  {
32517
32485
  "name": "migrateInlineTemplates",
32518
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
32486
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
32519
32487
  "ctype": "miscellaneous",
32520
32488
  "subtype": "function",
32521
32489
  "coverageIgnore": false,
@@ -32547,7 +32515,7 @@
32547
32515
  },
32548
32516
  {
32549
32517
  "name": "migrateInlineTemplates",
32550
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
32518
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
32551
32519
  "ctype": "miscellaneous",
32552
32520
  "subtype": "function",
32553
32521
  "coverageIgnore": false,
@@ -32579,7 +32547,7 @@
32579
32547
  },
32580
32548
  {
32581
32549
  "name": "migrateInlineTemplates",
32582
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
32550
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
32583
32551
  "ctype": "miscellaneous",
32584
32552
  "subtype": "function",
32585
32553
  "coverageIgnore": false,
@@ -32611,7 +32579,7 @@
32611
32579
  },
32612
32580
  {
32613
32581
  "name": "migrateInlineTemplates",
32614
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
32582
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
32615
32583
  "ctype": "miscellaneous",
32616
32584
  "subtype": "function",
32617
32585
  "coverageIgnore": false,
@@ -32766,72 +32734,8 @@
32766
32734
  ]
32767
32735
  },
32768
32736
  {
32769
- "name": "migrateTemplate",
32770
- "file": "packages/core/schematics/migrate-eui-accent/index.ts",
32771
- "ctype": "miscellaneous",
32772
- "subtype": "function",
32773
- "coverageIgnore": false,
32774
- "deprecated": false,
32775
- "deprecationMessage": "",
32776
- "rawdescription": "",
32777
- "description": "",
32778
- "displayName": "migrateTemplate",
32779
- "args": [
32780
- {
32781
- "name": "source",
32782
- "type": "string",
32783
- "deprecated": false,
32784
- "deprecationMessage": ""
32785
- }
32786
- ],
32787
- "returnType": "string",
32788
- "jsdoctags": [
32789
- {
32790
- "name": "source",
32791
- "type": "string",
32792
- "deprecated": false,
32793
- "deprecationMessage": "",
32794
- "tagName": {
32795
- "text": "param"
32796
- }
32797
- }
32798
- ]
32799
- },
32800
- {
32801
- "name": "migrateTemplate",
32802
- "file": "packages/core/schematics/migrate-eui-alert/index.ts",
32803
- "ctype": "miscellaneous",
32804
- "subtype": "function",
32805
- "coverageIgnore": false,
32806
- "deprecated": false,
32807
- "deprecationMessage": "",
32808
- "rawdescription": "",
32809
- "description": "",
32810
- "displayName": "migrateTemplate",
32811
- "args": [
32812
- {
32813
- "name": "source",
32814
- "type": "string",
32815
- "deprecated": false,
32816
- "deprecationMessage": ""
32817
- }
32818
- ],
32819
- "returnType": "string",
32820
- "jsdoctags": [
32821
- {
32822
- "name": "source",
32823
- "type": "string",
32824
- "deprecated": false,
32825
- "deprecationMessage": "",
32826
- "tagName": {
32827
- "text": "param"
32828
- }
32829
- }
32830
- ]
32831
- },
32832
- {
32833
- "name": "migrateTemplate",
32834
- "file": "packages/core/schematics/migrate-eui-avatar/index.ts",
32737
+ "name": "migrateInlineTemplates",
32738
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
32835
32739
  "ctype": "miscellaneous",
32836
32740
  "subtype": "function",
32837
32741
  "coverageIgnore": false,
@@ -32839,7 +32743,7 @@
32839
32743
  "deprecationMessage": "",
32840
32744
  "rawdescription": "",
32841
32745
  "description": "",
32842
- "displayName": "migrateTemplate",
32746
+ "displayName": "migrateInlineTemplates",
32843
32747
  "args": [
32844
32748
  {
32845
32749
  "name": "source",
@@ -32863,7 +32767,7 @@
32863
32767
  },
32864
32768
  {
32865
32769
  "name": "migrateTemplate",
32866
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
32770
+ "file": "packages/core/schematics/migrate-eui-accent/index.ts",
32867
32771
  "ctype": "miscellaneous",
32868
32772
  "subtype": "function",
32869
32773
  "coverageIgnore": false,
@@ -32895,7 +32799,39 @@
32895
32799
  },
32896
32800
  {
32897
32801
  "name": "migrateTemplate",
32898
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
32802
+ "file": "packages/core/schematics/migrate-eui-alert/index.ts",
32803
+ "ctype": "miscellaneous",
32804
+ "subtype": "function",
32805
+ "coverageIgnore": false,
32806
+ "deprecated": false,
32807
+ "deprecationMessage": "",
32808
+ "rawdescription": "",
32809
+ "description": "",
32810
+ "displayName": "migrateTemplate",
32811
+ "args": [
32812
+ {
32813
+ "name": "source",
32814
+ "type": "string",
32815
+ "deprecated": false,
32816
+ "deprecationMessage": ""
32817
+ }
32818
+ ],
32819
+ "returnType": "string",
32820
+ "jsdoctags": [
32821
+ {
32822
+ "name": "source",
32823
+ "type": "string",
32824
+ "deprecated": false,
32825
+ "deprecationMessage": "",
32826
+ "tagName": {
32827
+ "text": "param"
32828
+ }
32829
+ }
32830
+ ]
32831
+ },
32832
+ {
32833
+ "name": "migrateTemplate",
32834
+ "file": "packages/core/schematics/migrate-eui-avatar/index.ts",
32899
32835
  "ctype": "miscellaneous",
32900
32836
  "subtype": "function",
32901
32837
  "coverageIgnore": false,
@@ -33243,6 +33179,38 @@
33243
33179
  }
33244
33180
  ]
33245
33181
  },
33182
+ {
33183
+ "name": "migrateTemplate",
33184
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
33185
+ "ctype": "miscellaneous",
33186
+ "subtype": "function",
33187
+ "coverageIgnore": false,
33188
+ "deprecated": false,
33189
+ "deprecationMessage": "",
33190
+ "rawdescription": "",
33191
+ "description": "",
33192
+ "displayName": "migrateTemplate",
33193
+ "args": [
33194
+ {
33195
+ "name": "source",
33196
+ "type": "string",
33197
+ "deprecated": false,
33198
+ "deprecationMessage": ""
33199
+ }
33200
+ ],
33201
+ "returnType": "string",
33202
+ "jsdoctags": [
33203
+ {
33204
+ "name": "source",
33205
+ "type": "string",
33206
+ "deprecated": false,
33207
+ "deprecationMessage": "",
33208
+ "tagName": {
33209
+ "text": "param"
33210
+ }
33211
+ }
33212
+ ]
33213
+ },
33246
33214
  {
33247
33215
  "name": "migrateTemplate",
33248
33216
  "file": "packages/core/schematics/migrate-eui-tabs/index.ts",
@@ -33367,6 +33335,38 @@
33367
33335
  }
33368
33336
  ]
33369
33337
  },
33338
+ {
33339
+ "name": "migrateTemplate",
33340
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
33341
+ "ctype": "miscellaneous",
33342
+ "subtype": "function",
33343
+ "coverageIgnore": false,
33344
+ "deprecated": false,
33345
+ "deprecationMessage": "",
33346
+ "rawdescription": "",
33347
+ "description": "",
33348
+ "displayName": "migrateTemplate",
33349
+ "args": [
33350
+ {
33351
+ "name": "source",
33352
+ "type": "string",
33353
+ "deprecated": false,
33354
+ "deprecationMessage": ""
33355
+ }
33356
+ ],
33357
+ "returnType": "string",
33358
+ "jsdoctags": [
33359
+ {
33360
+ "name": "source",
33361
+ "type": "string",
33362
+ "deprecated": false,
33363
+ "deprecationMessage": "",
33364
+ "tagName": {
33365
+ "text": "param"
33366
+ }
33367
+ }
33368
+ ]
33369
+ },
33370
33370
  {
33371
33371
  "name": "migrateTemplateWithPaginator",
33372
33372
  "file": "packages/core/schematics/migrate-eui-table/index.ts",
@@ -35331,7 +35331,7 @@
35331
35331
  },
35332
35332
  {
35333
35333
  "name": "unwrapExpression",
35334
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
35334
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
35335
35335
  "ctype": "miscellaneous",
35336
35336
  "subtype": "function",
35337
35337
  "coverageIgnore": false,
@@ -35361,7 +35361,7 @@
35361
35361
  },
35362
35362
  {
35363
35363
  "name": "unwrapExpression",
35364
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
35364
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
35365
35365
  "ctype": "miscellaneous",
35366
35366
  "subtype": "function",
35367
35367
  "coverageIgnore": false,
@@ -35391,7 +35391,7 @@
35391
35391
  },
35392
35392
  {
35393
35393
  "name": "unwrapExpression",
35394
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
35394
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
35395
35395
  "ctype": "miscellaneous",
35396
35396
  "subtype": "function",
35397
35397
  "coverageIgnore": false,
@@ -35421,7 +35421,7 @@
35421
35421
  },
35422
35422
  {
35423
35423
  "name": "unwrapExpression",
35424
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
35424
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
35425
35425
  "ctype": "miscellaneous",
35426
35426
  "subtype": "function",
35427
35427
  "coverageIgnore": false,
@@ -35451,7 +35451,7 @@
35451
35451
  },
35452
35452
  {
35453
35453
  "name": "unwrapExpression",
35454
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
35454
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
35455
35455
  "ctype": "miscellaneous",
35456
35456
  "subtype": "function",
35457
35457
  "coverageIgnore": false,
@@ -35481,7 +35481,7 @@
35481
35481
  },
35482
35482
  {
35483
35483
  "name": "unwrapExpression",
35484
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
35484
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
35485
35485
  "ctype": "miscellaneous",
35486
35486
  "subtype": "function",
35487
35487
  "coverageIgnore": false,
@@ -35511,7 +35511,7 @@
35511
35511
  },
35512
35512
  {
35513
35513
  "name": "unwrapExpression",
35514
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
35514
+ "file": "packages/core/schematics/migrate-eui-table/index.ts",
35515
35515
  "ctype": "miscellaneous",
35516
35516
  "subtype": "function",
35517
35517
  "coverageIgnore": false,
@@ -35541,7 +35541,7 @@
35541
35541
  },
35542
35542
  {
35543
35543
  "name": "unwrapExpression",
35544
- "file": "packages/core/schematics/migrate-eui-table/index.ts",
35544
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
35545
35545
  "ctype": "miscellaneous",
35546
35546
  "subtype": "function",
35547
35547
  "coverageIgnore": false,
@@ -35854,7 +35854,7 @@
35854
35854
  },
35855
35855
  {
35856
35856
  "name": "visitDir",
35857
- "file": "packages/core/schematics/add-eui-imports/index.ts",
35857
+ "file": "packages/core/schematics/fix-no-multiple-empty-lines/index.ts",
35858
35858
  "ctype": "miscellaneous",
35859
35859
  "subtype": "function",
35860
35860
  "coverageIgnore": false,
@@ -35899,7 +35899,7 @@
35899
35899
  },
35900
35900
  {
35901
35901
  "name": "visitDir",
35902
- "file": "packages/core/schematics/fix-no-multiple-empty-lines/index.ts",
35902
+ "file": "packages/core/schematics/add-eui-imports/index.ts",
35903
35903
  "ctype": "miscellaneous",
35904
35904
  "subtype": "function",
35905
35905
  "coverageIgnore": false,
@@ -36079,7 +36079,7 @@
36079
36079
  },
36080
36080
  {
36081
36081
  "name": "visitDir",
36082
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
36082
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
36083
36083
  "ctype": "miscellaneous",
36084
36084
  "subtype": "function",
36085
36085
  "coverageIgnore": false,
@@ -36124,7 +36124,7 @@
36124
36124
  },
36125
36125
  {
36126
36126
  "name": "visitDir",
36127
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
36127
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
36128
36128
  "ctype": "miscellaneous",
36129
36129
  "subtype": "function",
36130
36130
  "coverageIgnore": false,
@@ -36169,7 +36169,7 @@
36169
36169
  },
36170
36170
  {
36171
36171
  "name": "visitDir",
36172
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
36172
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
36173
36173
  "ctype": "miscellaneous",
36174
36174
  "subtype": "function",
36175
36175
  "coverageIgnore": false,
@@ -36214,7 +36214,7 @@
36214
36214
  },
36215
36215
  {
36216
36216
  "name": "visitDir",
36217
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
36217
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
36218
36218
  "ctype": "miscellaneous",
36219
36219
  "subtype": "function",
36220
36220
  "coverageIgnore": false,
@@ -36259,7 +36259,7 @@
36259
36259
  },
36260
36260
  {
36261
36261
  "name": "visitDir",
36262
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
36262
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
36263
36263
  "ctype": "miscellaneous",
36264
36264
  "subtype": "function",
36265
36265
  "coverageIgnore": false,
@@ -36304,7 +36304,7 @@
36304
36304
  },
36305
36305
  {
36306
36306
  "name": "visitDir",
36307
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
36307
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
36308
36308
  "ctype": "miscellaneous",
36309
36309
  "subtype": "function",
36310
36310
  "coverageIgnore": false,
@@ -36349,7 +36349,7 @@
36349
36349
  },
36350
36350
  {
36351
36351
  "name": "visitDir",
36352
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
36352
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
36353
36353
  "ctype": "miscellaneous",
36354
36354
  "subtype": "function",
36355
36355
  "coverageIgnore": false,
@@ -36394,7 +36394,7 @@
36394
36394
  },
36395
36395
  {
36396
36396
  "name": "visitDir",
36397
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
36397
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
36398
36398
  "ctype": "miscellaneous",
36399
36399
  "subtype": "function",
36400
36400
  "coverageIgnore": false,
@@ -36439,7 +36439,7 @@
36439
36439
  },
36440
36440
  {
36441
36441
  "name": "visitDir",
36442
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
36442
+ "file": "packages/core/schematics/migrate-eui-table/index.ts",
36443
36443
  "ctype": "miscellaneous",
36444
36444
  "subtype": "function",
36445
36445
  "coverageIgnore": false,
@@ -36484,7 +36484,7 @@
36484
36484
  },
36485
36485
  {
36486
36486
  "name": "visitDir",
36487
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
36487
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
36488
36488
  "ctype": "miscellaneous",
36489
36489
  "subtype": "function",
36490
36490
  "coverageIgnore": false,
@@ -36529,7 +36529,7 @@
36529
36529
  },
36530
36530
  {
36531
36531
  "name": "visitDir",
36532
- "file": "packages/core/schematics/migrate-eui-table/index.ts",
36532
+ "file": "packages/core/schematics/migrate-eui-tabs/index.ts",
36533
36533
  "ctype": "miscellaneous",
36534
36534
  "subtype": "function",
36535
36535
  "coverageIgnore": false,
@@ -36574,7 +36574,7 @@
36574
36574
  },
36575
36575
  {
36576
36576
  "name": "visitDir",
36577
- "file": "packages/core/schematics/migrate-eui-tabs/index.ts",
36577
+ "file": "packages/core/schematics/migrate-eui-toolbar-menu/index.ts",
36578
36578
  "ctype": "miscellaneous",
36579
36579
  "subtype": "function",
36580
36580
  "coverageIgnore": false,
@@ -36619,7 +36619,7 @@
36619
36619
  },
36620
36620
  {
36621
36621
  "name": "visitDir",
36622
- "file": "packages/core/schematics/migrate-eui-toolbar-menu/index.ts",
36622
+ "file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
36623
36623
  "ctype": "miscellaneous",
36624
36624
  "subtype": "function",
36625
36625
  "coverageIgnore": false,
@@ -36664,7 +36664,7 @@
36664
36664
  },
36665
36665
  {
36666
36666
  "name": "visitDir",
36667
- "file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
36667
+ "file": "packages/core/schematics/migrate-to-signals/index.ts",
36668
36668
  "ctype": "miscellaneous",
36669
36669
  "subtype": "function",
36670
36670
  "coverageIgnore": false,
@@ -36709,7 +36709,7 @@
36709
36709
  },
36710
36710
  {
36711
36711
  "name": "visitDir",
36712
- "file": "packages/core/schematics/migrate-to-signals/index.ts",
36712
+ "file": "packages/core/schematics/migrate-to-standalone/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-standalone/index.ts",
36757
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
36758
36758
  "ctype": "miscellaneous",
36759
36759
  "subtype": "function",
36760
36760
  "coverageIgnore": false,
@@ -36973,7 +36973,7 @@
36973
36973
  },
36974
36974
  {
36975
36975
  "name": "visitNodes",
36976
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
36976
+ "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
36977
36977
  "ctype": "miscellaneous",
36978
36978
  "subtype": "function",
36979
36979
  "coverageIgnore": false,
@@ -36988,6 +36988,12 @@
36988
36988
  "deprecated": false,
36989
36989
  "deprecationMessage": ""
36990
36990
  },
36991
+ {
36992
+ "name": "source",
36993
+ "type": "string",
36994
+ "deprecated": false,
36995
+ "deprecationMessage": ""
36996
+ },
36991
36997
  {
36992
36998
  "name": "edits",
36993
36999
  "deprecated": false,
@@ -37004,6 +37010,15 @@
37004
37010
  "text": "param"
37005
37011
  }
37006
37012
  },
37013
+ {
37014
+ "name": "source",
37015
+ "type": "string",
37016
+ "deprecated": false,
37017
+ "deprecationMessage": "",
37018
+ "tagName": {
37019
+ "text": "param"
37020
+ }
37021
+ },
37007
37022
  {
37008
37023
  "name": "edits",
37009
37024
  "deprecated": false,
@@ -37016,7 +37031,7 @@
37016
37031
  },
37017
37032
  {
37018
37033
  "name": "visitNodes",
37019
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
37034
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
37020
37035
  "ctype": "miscellaneous",
37021
37036
  "subtype": "function",
37022
37037
  "coverageIgnore": false,
@@ -37031,6 +37046,12 @@
37031
37046
  "deprecated": false,
37032
37047
  "deprecationMessage": ""
37033
37048
  },
37049
+ {
37050
+ "name": "source",
37051
+ "type": "string",
37052
+ "deprecated": false,
37053
+ "deprecationMessage": ""
37054
+ },
37034
37055
  {
37035
37056
  "name": "removals",
37036
37057
  "deprecated": false,
@@ -37047,6 +37068,15 @@
37047
37068
  "text": "param"
37048
37069
  }
37049
37070
  },
37071
+ {
37072
+ "name": "source",
37073
+ "type": "string",
37074
+ "deprecated": false,
37075
+ "deprecationMessage": "",
37076
+ "tagName": {
37077
+ "text": "param"
37078
+ }
37079
+ },
37050
37080
  {
37051
37081
  "name": "removals",
37052
37082
  "deprecated": false,
@@ -37059,7 +37089,7 @@
37059
37089
  },
37060
37090
  {
37061
37091
  "name": "visitNodes",
37062
- "file": "packages/core/schematics/migrate-eui-chip-list/index.ts",
37092
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
37063
37093
  "ctype": "miscellaneous",
37064
37094
  "subtype": "function",
37065
37095
  "coverageIgnore": false,
@@ -37074,12 +37104,6 @@
37074
37104
  "deprecated": false,
37075
37105
  "deprecationMessage": ""
37076
37106
  },
37077
- {
37078
- "name": "source",
37079
- "type": "string",
37080
- "deprecated": false,
37081
- "deprecationMessage": ""
37082
- },
37083
37107
  {
37084
37108
  "name": "edits",
37085
37109
  "deprecated": false,
@@ -37096,15 +37120,6 @@
37096
37120
  "text": "param"
37097
37121
  }
37098
37122
  },
37099
- {
37100
- "name": "source",
37101
- "type": "string",
37102
- "deprecated": false,
37103
- "deprecationMessage": "",
37104
- "tagName": {
37105
- "text": "param"
37106
- }
37107
- },
37108
37123
  {
37109
37124
  "name": "edits",
37110
37125
  "deprecated": false,
@@ -37117,7 +37132,7 @@
37117
37132
  },
37118
37133
  {
37119
37134
  "name": "visitNodes",
37120
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
37135
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
37121
37136
  "ctype": "miscellaneous",
37122
37137
  "subtype": "function",
37123
37138
  "coverageIgnore": false,
@@ -37133,13 +37148,7 @@
37133
37148
  "deprecationMessage": ""
37134
37149
  },
37135
37150
  {
37136
- "name": "source",
37137
- "type": "string",
37138
- "deprecated": false,
37139
- "deprecationMessage": ""
37140
- },
37141
- {
37142
- "name": "removals",
37151
+ "name": "edits",
37143
37152
  "deprecated": false,
37144
37153
  "deprecationMessage": ""
37145
37154
  }
@@ -37155,8 +37164,42 @@
37155
37164
  }
37156
37165
  },
37157
37166
  {
37158
- "name": "source",
37159
- "type": "string",
37167
+ "name": "edits",
37168
+ "deprecated": false,
37169
+ "deprecationMessage": "",
37170
+ "tagName": {
37171
+ "text": "param"
37172
+ }
37173
+ }
37174
+ ]
37175
+ },
37176
+ {
37177
+ "name": "visitNodes",
37178
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
37179
+ "ctype": "miscellaneous",
37180
+ "subtype": "function",
37181
+ "coverageIgnore": false,
37182
+ "deprecated": false,
37183
+ "deprecationMessage": "",
37184
+ "rawdescription": "",
37185
+ "description": "",
37186
+ "displayName": "visitNodes",
37187
+ "args": [
37188
+ {
37189
+ "name": "nodes",
37190
+ "deprecated": false,
37191
+ "deprecationMessage": ""
37192
+ },
37193
+ {
37194
+ "name": "edits",
37195
+ "deprecated": false,
37196
+ "deprecationMessage": ""
37197
+ }
37198
+ ],
37199
+ "returnType": "void",
37200
+ "jsdoctags": [
37201
+ {
37202
+ "name": "nodes",
37160
37203
  "deprecated": false,
37161
37204
  "deprecationMessage": "",
37162
37205
  "tagName": {
@@ -37164,7 +37207,7 @@
37164
37207
  }
37165
37208
  },
37166
37209
  {
37167
- "name": "removals",
37210
+ "name": "edits",
37168
37211
  "deprecated": false,
37169
37212
  "deprecationMessage": "",
37170
37213
  "tagName": {
@@ -37175,7 +37218,7 @@
37175
37218
  },
37176
37219
  {
37177
37220
  "name": "visitNodes",
37178
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
37221
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
37179
37222
  "ctype": "miscellaneous",
37180
37223
  "subtype": "function",
37181
37224
  "coverageIgnore": false,
@@ -37218,7 +37261,7 @@
37218
37261
  },
37219
37262
  {
37220
37263
  "name": "visitNodes",
37221
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
37264
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
37222
37265
  "ctype": "miscellaneous",
37223
37266
  "subtype": "function",
37224
37267
  "coverageIgnore": false,
@@ -37234,7 +37277,7 @@
37234
37277
  "deprecationMessage": ""
37235
37278
  },
37236
37279
  {
37237
- "name": "edits",
37280
+ "name": "removals",
37238
37281
  "deprecated": false,
37239
37282
  "deprecationMessage": ""
37240
37283
  }
@@ -37250,7 +37293,7 @@
37250
37293
  }
37251
37294
  },
37252
37295
  {
37253
- "name": "edits",
37296
+ "name": "removals",
37254
37297
  "deprecated": false,
37255
37298
  "deprecationMessage": "",
37256
37299
  "tagName": {
@@ -37261,7 +37304,7 @@
37261
37304
  },
37262
37305
  {
37263
37306
  "name": "visitNodes",
37264
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
37307
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
37265
37308
  "ctype": "miscellaneous",
37266
37309
  "subtype": "function",
37267
37310
  "coverageIgnore": false,
@@ -37304,7 +37347,7 @@
37304
37347
  },
37305
37348
  {
37306
37349
  "name": "visitNodes",
37307
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
37350
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
37308
37351
  "ctype": "miscellaneous",
37309
37352
  "subtype": "function",
37310
37353
  "coverageIgnore": false,
@@ -37347,7 +37390,7 @@
37347
37390
  },
37348
37391
  {
37349
37392
  "name": "visitNodes",
37350
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
37393
+ "file": "packages/core/schematics/migrate-eui-toolbar-menu/index.ts",
37351
37394
  "ctype": "miscellaneous",
37352
37395
  "subtype": "function",
37353
37396
  "coverageIgnore": false,
@@ -37363,7 +37406,25 @@
37363
37406
  "deprecationMessage": ""
37364
37407
  },
37365
37408
  {
37366
- "name": "removals",
37409
+ "name": "source",
37410
+ "type": "string",
37411
+ "deprecated": false,
37412
+ "deprecationMessage": ""
37413
+ },
37414
+ {
37415
+ "name": "edits",
37416
+ "deprecated": false,
37417
+ "deprecationMessage": ""
37418
+ },
37419
+ {
37420
+ "name": "filePath",
37421
+ "type": "string",
37422
+ "deprecated": false,
37423
+ "deprecationMessage": ""
37424
+ },
37425
+ {
37426
+ "name": "context",
37427
+ "type": "SchematicContext",
37367
37428
  "deprecated": false,
37368
37429
  "deprecationMessage": ""
37369
37430
  }
@@ -37379,42 +37440,25 @@
37379
37440
  }
37380
37441
  },
37381
37442
  {
37382
- "name": "removals",
37443
+ "name": "source",
37444
+ "type": "string",
37383
37445
  "deprecated": false,
37384
37446
  "deprecationMessage": "",
37385
37447
  "tagName": {
37386
37448
  "text": "param"
37387
37449
  }
37388
- }
37389
- ]
37390
- },
37391
- {
37392
- "name": "visitNodes",
37393
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
37394
- "ctype": "miscellaneous",
37395
- "subtype": "function",
37396
- "coverageIgnore": false,
37397
- "deprecated": false,
37398
- "deprecationMessage": "",
37399
- "rawdescription": "",
37400
- "description": "",
37401
- "displayName": "visitNodes",
37402
- "args": [
37403
- {
37404
- "name": "nodes",
37405
- "deprecated": false,
37406
- "deprecationMessage": ""
37407
37450
  },
37408
37451
  {
37409
37452
  "name": "edits",
37410
37453
  "deprecated": false,
37411
- "deprecationMessage": ""
37412
- }
37413
- ],
37414
- "returnType": "void",
37415
- "jsdoctags": [
37454
+ "deprecationMessage": "",
37455
+ "tagName": {
37456
+ "text": "param"
37457
+ }
37458
+ },
37416
37459
  {
37417
- "name": "nodes",
37460
+ "name": "filePath",
37461
+ "type": "string",
37418
37462
  "deprecated": false,
37419
37463
  "deprecationMessage": "",
37420
37464
  "tagName": {
@@ -37422,7 +37466,8 @@
37422
37466
  }
37423
37467
  },
37424
37468
  {
37425
- "name": "edits",
37469
+ "name": "context",
37470
+ "type": "SchematicContext",
37426
37471
  "deprecated": false,
37427
37472
  "deprecationMessage": "",
37428
37473
  "tagName": {
@@ -37433,7 +37478,7 @@
37433
37478
  },
37434
37479
  {
37435
37480
  "name": "visitNodes",
37436
- "file": "packages/core/schematics/migrate-eui-toolbar-menu/index.ts",
37481
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
37437
37482
  "ctype": "miscellaneous",
37438
37483
  "subtype": "function",
37439
37484
  "coverageIgnore": false,
@@ -37449,25 +37494,7 @@
37449
37494
  "deprecationMessage": ""
37450
37495
  },
37451
37496
  {
37452
- "name": "source",
37453
- "type": "string",
37454
- "deprecated": false,
37455
- "deprecationMessage": ""
37456
- },
37457
- {
37458
- "name": "edits",
37459
- "deprecated": false,
37460
- "deprecationMessage": ""
37461
- },
37462
- {
37463
- "name": "filePath",
37464
- "type": "string",
37465
- "deprecated": false,
37466
- "deprecationMessage": ""
37467
- },
37468
- {
37469
- "name": "context",
37470
- "type": "SchematicContext",
37497
+ "name": "removals",
37471
37498
  "deprecated": false,
37472
37499
  "deprecationMessage": ""
37473
37500
  }
@@ -37483,34 +37510,7 @@
37483
37510
  }
37484
37511
  },
37485
37512
  {
37486
- "name": "source",
37487
- "type": "string",
37488
- "deprecated": false,
37489
- "deprecationMessage": "",
37490
- "tagName": {
37491
- "text": "param"
37492
- }
37493
- },
37494
- {
37495
- "name": "edits",
37496
- "deprecated": false,
37497
- "deprecationMessage": "",
37498
- "tagName": {
37499
- "text": "param"
37500
- }
37501
- },
37502
- {
37503
- "name": "filePath",
37504
- "type": "string",
37505
- "deprecated": false,
37506
- "deprecationMessage": "",
37507
- "tagName": {
37508
- "text": "param"
37509
- }
37510
- },
37511
- {
37512
- "name": "context",
37513
- "type": "SchematicContext",
37513
+ "name": "removals",
37514
37514
  "deprecated": false,
37515
37515
  "deprecationMessage": "",
37516
37516
  "tagName": {
@@ -40320,30 +40320,30 @@
40320
40320
  "defaultValue": "new Set(['isFlat'])"
40321
40321
  }
40322
40322
  ],
40323
- "packages/core/schematics/migrate-eui-chip/index.ts": [
40323
+ "packages/core/schematics/migrate-eui-popover/index.ts": [
40324
40324
  {
40325
40325
  "name": "REMOVED_INPUTS",
40326
40326
  "ctype": "miscellaneous",
40327
40327
  "subtype": "variable",
40328
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
40328
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
40329
40329
  "coverageIgnore": false,
40330
40330
  "deprecated": false,
40331
40331
  "deprecationMessage": "",
40332
40332
  "type": "unknown",
40333
- "defaultValue": "new Set(['isSquared'])"
40333
+ "defaultValue": "new Set(['type'])"
40334
40334
  }
40335
40335
  ],
40336
- "packages/core/schematics/migrate-eui-popover/index.ts": [
40336
+ "packages/core/schematics/migrate-eui-chip/index.ts": [
40337
40337
  {
40338
40338
  "name": "REMOVED_INPUTS",
40339
40339
  "ctype": "miscellaneous",
40340
40340
  "subtype": "variable",
40341
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
40341
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
40342
40342
  "coverageIgnore": false,
40343
40343
  "deprecated": false,
40344
40344
  "deprecationMessage": "",
40345
40345
  "type": "unknown",
40346
- "defaultValue": "new Set(['type'])"
40346
+ "defaultValue": "new Set(['isSquared'])"
40347
40347
  }
40348
40348
  ],
40349
40349
  "packages/core/schematics/add-eui-imports/selector-map.ts": [
@@ -45163,10 +45163,10 @@
45163
45163
  ]
45164
45164
  }
45165
45165
  ],
45166
- "packages/core/schematics/migrate-eui-button/index.ts": [
45166
+ "packages/core/schematics/migrate-eui-editor/index.ts": [
45167
45167
  {
45168
45168
  "name": "applyEdits",
45169
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45169
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45170
45170
  "ctype": "miscellaneous",
45171
45171
  "subtype": "function",
45172
45172
  "coverageIgnore": false,
@@ -45211,7 +45211,7 @@
45211
45211
  },
45212
45212
  {
45213
45213
  "name": "collectRenames",
45214
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45214
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45215
45215
  "ctype": "miscellaneous",
45216
45216
  "subtype": "function",
45217
45217
  "coverageIgnore": false,
@@ -45254,41 +45254,9 @@
45254
45254
  }
45255
45255
  ]
45256
45256
  },
45257
- {
45258
- "name": "hasEuiButtonAttribute",
45259
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45260
- "ctype": "miscellaneous",
45261
- "subtype": "function",
45262
- "coverageIgnore": false,
45263
- "deprecated": false,
45264
- "deprecationMessage": "",
45265
- "rawdescription": "",
45266
- "description": "",
45267
- "displayName": "hasEuiButtonAttribute",
45268
- "args": [
45269
- {
45270
- "name": "element",
45271
- "type": "TmplAstElement",
45272
- "deprecated": false,
45273
- "deprecationMessage": ""
45274
- }
45275
- ],
45276
- "returnType": "boolean",
45277
- "jsdoctags": [
45278
- {
45279
- "name": "element",
45280
- "type": "TmplAstElement",
45281
- "deprecated": false,
45282
- "deprecationMessage": "",
45283
- "tagName": {
45284
- "text": "param"
45285
- }
45286
- }
45287
- ]
45288
- },
45289
45257
  {
45290
45258
  "name": "isComponentMetadataProperty",
45291
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45259
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45292
45260
  "ctype": "miscellaneous",
45293
45261
  "subtype": "function",
45294
45262
  "coverageIgnore": false,
@@ -45318,7 +45286,7 @@
45318
45286
  },
45319
45287
  {
45320
45288
  "name": "isTemplateProperty",
45321
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45289
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45322
45290
  "ctype": "miscellaneous",
45323
45291
  "subtype": "function",
45324
45292
  "coverageIgnore": false,
@@ -45347,8 +45315,8 @@
45347
45315
  ]
45348
45316
  },
45349
45317
  {
45350
- "name": "migrateEuiButton",
45351
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45318
+ "name": "migrateEuiEditor",
45319
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45352
45320
  "ctype": "miscellaneous",
45353
45321
  "subtype": "function",
45354
45322
  "coverageIgnore": false,
@@ -45356,7 +45324,7 @@
45356
45324
  "deprecationMessage": "",
45357
45325
  "rawdescription": "",
45358
45326
  "description": "",
45359
- "displayName": "migrateEuiButton",
45327
+ "displayName": "migrateEuiEditor",
45360
45328
  "args": [
45361
45329
  {
45362
45330
  "name": "options",
@@ -45382,7 +45350,7 @@
45382
45350
  },
45383
45351
  {
45384
45352
  "name": "migrateInlineTemplates",
45385
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45353
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45386
45354
  "ctype": "miscellaneous",
45387
45355
  "subtype": "function",
45388
45356
  "coverageIgnore": false,
@@ -45414,7 +45382,7 @@
45414
45382
  },
45415
45383
  {
45416
45384
  "name": "migrateTemplate",
45417
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45385
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45418
45386
  "ctype": "miscellaneous",
45419
45387
  "subtype": "function",
45420
45388
  "coverageIgnore": false,
@@ -45446,7 +45414,7 @@
45446
45414
  },
45447
45415
  {
45448
45416
  "name": "unwrapExpression",
45449
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45417
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45450
45418
  "ctype": "miscellaneous",
45451
45419
  "subtype": "function",
45452
45420
  "coverageIgnore": false,
@@ -45476,7 +45444,7 @@
45476
45444
  },
45477
45445
  {
45478
45446
  "name": "visitDir",
45479
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45447
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45480
45448
  "ctype": "miscellaneous",
45481
45449
  "subtype": "function",
45482
45450
  "coverageIgnore": false,
@@ -45521,7 +45489,7 @@
45521
45489
  },
45522
45490
  {
45523
45491
  "name": "visitNodes",
45524
- "file": "packages/core/schematics/migrate-eui-button/index.ts",
45492
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45525
45493
  "ctype": "miscellaneous",
45526
45494
  "subtype": "function",
45527
45495
  "coverageIgnore": false,
@@ -45561,12 +45529,74 @@
45561
45529
  }
45562
45530
  }
45563
45531
  ]
45532
+ },
45533
+ {
45534
+ "name": "warnPropertyAccesses",
45535
+ "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45536
+ "ctype": "miscellaneous",
45537
+ "subtype": "function",
45538
+ "coverageIgnore": false,
45539
+ "deprecated": false,
45540
+ "deprecationMessage": "",
45541
+ "rawdescription": "",
45542
+ "description": "",
45543
+ "displayName": "warnPropertyAccesses",
45544
+ "args": [
45545
+ {
45546
+ "name": "path",
45547
+ "type": "string",
45548
+ "deprecated": false,
45549
+ "deprecationMessage": ""
45550
+ },
45551
+ {
45552
+ "name": "source",
45553
+ "type": "string",
45554
+ "deprecated": false,
45555
+ "deprecationMessage": ""
45556
+ },
45557
+ {
45558
+ "name": "context",
45559
+ "type": "SchematicContext",
45560
+ "deprecated": false,
45561
+ "deprecationMessage": ""
45562
+ }
45563
+ ],
45564
+ "returnType": "void",
45565
+ "jsdoctags": [
45566
+ {
45567
+ "name": "path",
45568
+ "type": "string",
45569
+ "deprecated": false,
45570
+ "deprecationMessage": "",
45571
+ "tagName": {
45572
+ "text": "param"
45573
+ }
45574
+ },
45575
+ {
45576
+ "name": "source",
45577
+ "type": "string",
45578
+ "deprecated": false,
45579
+ "deprecationMessage": "",
45580
+ "tagName": {
45581
+ "text": "param"
45582
+ }
45583
+ },
45584
+ {
45585
+ "name": "context",
45586
+ "type": "SchematicContext",
45587
+ "deprecated": false,
45588
+ "deprecationMessage": "",
45589
+ "tagName": {
45590
+ "text": "param"
45591
+ }
45592
+ }
45593
+ ]
45564
45594
  }
45565
45595
  ],
45566
- "packages/core/schematics/migrate-eui-editor/index.ts": [
45596
+ "packages/core/schematics/migrate-eui-fieldset/index.ts": [
45567
45597
  {
45568
45598
  "name": "applyEdits",
45569
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45599
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45570
45600
  "ctype": "miscellaneous",
45571
45601
  "subtype": "function",
45572
45602
  "coverageIgnore": false,
@@ -45611,7 +45641,7 @@
45611
45641
  },
45612
45642
  {
45613
45643
  "name": "collectRenames",
45614
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45644
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45615
45645
  "ctype": "miscellaneous",
45616
45646
  "subtype": "function",
45617
45647
  "coverageIgnore": false,
@@ -45656,7 +45686,7 @@
45656
45686
  },
45657
45687
  {
45658
45688
  "name": "isComponentMetadataProperty",
45659
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45689
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45660
45690
  "ctype": "miscellaneous",
45661
45691
  "subtype": "function",
45662
45692
  "coverageIgnore": false,
@@ -45686,7 +45716,7 @@
45686
45716
  },
45687
45717
  {
45688
45718
  "name": "isTemplateProperty",
45689
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45719
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45690
45720
  "ctype": "miscellaneous",
45691
45721
  "subtype": "function",
45692
45722
  "coverageIgnore": false,
@@ -45715,8 +45745,8 @@
45715
45745
  ]
45716
45746
  },
45717
45747
  {
45718
- "name": "migrateEuiEditor",
45719
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45748
+ "name": "migrateEuiFieldset",
45749
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45720
45750
  "ctype": "miscellaneous",
45721
45751
  "subtype": "function",
45722
45752
  "coverageIgnore": false,
@@ -45724,7 +45754,7 @@
45724
45754
  "deprecationMessage": "",
45725
45755
  "rawdescription": "",
45726
45756
  "description": "",
45727
- "displayName": "migrateEuiEditor",
45757
+ "displayName": "migrateEuiFieldset",
45728
45758
  "args": [
45729
45759
  {
45730
45760
  "name": "options",
@@ -45750,7 +45780,7 @@
45750
45780
  },
45751
45781
  {
45752
45782
  "name": "migrateInlineTemplates",
45753
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45783
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45754
45784
  "ctype": "miscellaneous",
45755
45785
  "subtype": "function",
45756
45786
  "coverageIgnore": false,
@@ -45782,7 +45812,7 @@
45782
45812
  },
45783
45813
  {
45784
45814
  "name": "migrateTemplate",
45785
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45815
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45786
45816
  "ctype": "miscellaneous",
45787
45817
  "subtype": "function",
45788
45818
  "coverageIgnore": false,
@@ -45814,7 +45844,7 @@
45814
45844
  },
45815
45845
  {
45816
45846
  "name": "unwrapExpression",
45817
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45847
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45818
45848
  "ctype": "miscellaneous",
45819
45849
  "subtype": "function",
45820
45850
  "coverageIgnore": false,
@@ -45844,7 +45874,7 @@
45844
45874
  },
45845
45875
  {
45846
45876
  "name": "visitDir",
45847
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45877
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45848
45878
  "ctype": "miscellaneous",
45849
45879
  "subtype": "function",
45850
45880
  "coverageIgnore": false,
@@ -45889,7 +45919,7 @@
45889
45919
  },
45890
45920
  {
45891
45921
  "name": "visitNodes",
45892
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45922
+ "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45893
45923
  "ctype": "miscellaneous",
45894
45924
  "subtype": "function",
45895
45925
  "coverageIgnore": false,
@@ -45929,74 +45959,12 @@
45929
45959
  }
45930
45960
  }
45931
45961
  ]
45932
- },
45933
- {
45934
- "name": "warnPropertyAccesses",
45935
- "file": "packages/core/schematics/migrate-eui-editor/index.ts",
45936
- "ctype": "miscellaneous",
45937
- "subtype": "function",
45938
- "coverageIgnore": false,
45939
- "deprecated": false,
45940
- "deprecationMessage": "",
45941
- "rawdescription": "",
45942
- "description": "",
45943
- "displayName": "warnPropertyAccesses",
45944
- "args": [
45945
- {
45946
- "name": "path",
45947
- "type": "string",
45948
- "deprecated": false,
45949
- "deprecationMessage": ""
45950
- },
45951
- {
45952
- "name": "source",
45953
- "type": "string",
45954
- "deprecated": false,
45955
- "deprecationMessage": ""
45956
- },
45957
- {
45958
- "name": "context",
45959
- "type": "SchematicContext",
45960
- "deprecated": false,
45961
- "deprecationMessage": ""
45962
- }
45963
- ],
45964
- "returnType": "void",
45965
- "jsdoctags": [
45966
- {
45967
- "name": "path",
45968
- "type": "string",
45969
- "deprecated": false,
45970
- "deprecationMessage": "",
45971
- "tagName": {
45972
- "text": "param"
45973
- }
45974
- },
45975
- {
45976
- "name": "source",
45977
- "type": "string",
45978
- "deprecated": false,
45979
- "deprecationMessage": "",
45980
- "tagName": {
45981
- "text": "param"
45982
- }
45983
- },
45984
- {
45985
- "name": "context",
45986
- "type": "SchematicContext",
45987
- "deprecated": false,
45988
- "deprecationMessage": "",
45989
- "tagName": {
45990
- "text": "param"
45991
- }
45992
- }
45993
- ]
45994
45962
  }
45995
45963
  ],
45996
- "packages/core/schematics/migrate-eui-fieldset/index.ts": [
45964
+ "packages/core/schematics/migrate-eui-icon-svg/index.ts": [
45997
45965
  {
45998
45966
  "name": "applyEdits",
45999
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
45967
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46000
45968
  "ctype": "miscellaneous",
46001
45969
  "subtype": "function",
46002
45970
  "coverageIgnore": false,
@@ -46041,7 +46009,7 @@
46041
46009
  },
46042
46010
  {
46043
46011
  "name": "collectRenames",
46044
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46012
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46045
46013
  "ctype": "miscellaneous",
46046
46014
  "subtype": "function",
46047
46015
  "coverageIgnore": false,
@@ -46086,7 +46054,7 @@
46086
46054
  },
46087
46055
  {
46088
46056
  "name": "isComponentMetadataProperty",
46089
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46057
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46090
46058
  "ctype": "miscellaneous",
46091
46059
  "subtype": "function",
46092
46060
  "coverageIgnore": false,
@@ -46116,7 +46084,7 @@
46116
46084
  },
46117
46085
  {
46118
46086
  "name": "isTemplateProperty",
46119
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46087
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46120
46088
  "ctype": "miscellaneous",
46121
46089
  "subtype": "function",
46122
46090
  "coverageIgnore": false,
@@ -46145,8 +46113,8 @@
46145
46113
  ]
46146
46114
  },
46147
46115
  {
46148
- "name": "migrateEuiFieldset",
46149
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46116
+ "name": "migrateEuiIconSvg",
46117
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46150
46118
  "ctype": "miscellaneous",
46151
46119
  "subtype": "function",
46152
46120
  "coverageIgnore": false,
@@ -46154,7 +46122,7 @@
46154
46122
  "deprecationMessage": "",
46155
46123
  "rawdescription": "",
46156
46124
  "description": "",
46157
- "displayName": "migrateEuiFieldset",
46125
+ "displayName": "migrateEuiIconSvg",
46158
46126
  "args": [
46159
46127
  {
46160
46128
  "name": "options",
@@ -46180,7 +46148,7 @@
46180
46148
  },
46181
46149
  {
46182
46150
  "name": "migrateInlineTemplates",
46183
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46151
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46184
46152
  "ctype": "miscellaneous",
46185
46153
  "subtype": "function",
46186
46154
  "coverageIgnore": false,
@@ -46212,7 +46180,7 @@
46212
46180
  },
46213
46181
  {
46214
46182
  "name": "migrateTemplate",
46215
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46183
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46216
46184
  "ctype": "miscellaneous",
46217
46185
  "subtype": "function",
46218
46186
  "coverageIgnore": false,
@@ -46242,9 +46210,41 @@
46242
46210
  }
46243
46211
  ]
46244
46212
  },
46213
+ {
46214
+ "name": "renameTsPropertyAccesses",
46215
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46216
+ "ctype": "miscellaneous",
46217
+ "subtype": "function",
46218
+ "coverageIgnore": false,
46219
+ "deprecated": false,
46220
+ "deprecationMessage": "",
46221
+ "rawdescription": "",
46222
+ "description": "",
46223
+ "displayName": "renameTsPropertyAccesses",
46224
+ "args": [
46225
+ {
46226
+ "name": "source",
46227
+ "type": "string",
46228
+ "deprecated": false,
46229
+ "deprecationMessage": ""
46230
+ }
46231
+ ],
46232
+ "returnType": "string",
46233
+ "jsdoctags": [
46234
+ {
46235
+ "name": "source",
46236
+ "type": "string",
46237
+ "deprecated": false,
46238
+ "deprecationMessage": "",
46239
+ "tagName": {
46240
+ "text": "param"
46241
+ }
46242
+ }
46243
+ ]
46244
+ },
46245
46245
  {
46246
46246
  "name": "unwrapExpression",
46247
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46247
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46248
46248
  "ctype": "miscellaneous",
46249
46249
  "subtype": "function",
46250
46250
  "coverageIgnore": false,
@@ -46274,7 +46274,7 @@
46274
46274
  },
46275
46275
  {
46276
46276
  "name": "visitDir",
46277
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46277
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46278
46278
  "ctype": "miscellaneous",
46279
46279
  "subtype": "function",
46280
46280
  "coverageIgnore": false,
@@ -46319,7 +46319,7 @@
46319
46319
  },
46320
46320
  {
46321
46321
  "name": "visitNodes",
46322
- "file": "packages/core/schematics/migrate-eui-fieldset/index.ts",
46322
+ "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46323
46323
  "ctype": "miscellaneous",
46324
46324
  "subtype": "function",
46325
46325
  "coverageIgnore": false,
@@ -46361,10 +46361,10 @@
46361
46361
  ]
46362
46362
  }
46363
46363
  ],
46364
- "packages/core/schematics/migrate-eui-icon-svg/index.ts": [
46364
+ "packages/core/schematics/migrate-eui-icon-toggle/index.ts": [
46365
46365
  {
46366
46366
  "name": "applyEdits",
46367
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46367
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46368
46368
  "ctype": "miscellaneous",
46369
46369
  "subtype": "function",
46370
46370
  "coverageIgnore": false,
@@ -46409,7 +46409,7 @@
46409
46409
  },
46410
46410
  {
46411
46411
  "name": "collectRenames",
46412
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46412
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46413
46413
  "ctype": "miscellaneous",
46414
46414
  "subtype": "function",
46415
46415
  "coverageIgnore": false,
@@ -46454,7 +46454,7 @@
46454
46454
  },
46455
46455
  {
46456
46456
  "name": "isComponentMetadataProperty",
46457
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46457
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46458
46458
  "ctype": "miscellaneous",
46459
46459
  "subtype": "function",
46460
46460
  "coverageIgnore": false,
@@ -46484,7 +46484,7 @@
46484
46484
  },
46485
46485
  {
46486
46486
  "name": "isTemplateProperty",
46487
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46487
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46488
46488
  "ctype": "miscellaneous",
46489
46489
  "subtype": "function",
46490
46490
  "coverageIgnore": false,
@@ -46513,8 +46513,8 @@
46513
46513
  ]
46514
46514
  },
46515
46515
  {
46516
- "name": "migrateEuiIconSvg",
46517
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46516
+ "name": "migrateEuiIconToggle",
46517
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46518
46518
  "ctype": "miscellaneous",
46519
46519
  "subtype": "function",
46520
46520
  "coverageIgnore": false,
@@ -46522,7 +46522,7 @@
46522
46522
  "deprecationMessage": "",
46523
46523
  "rawdescription": "",
46524
46524
  "description": "",
46525
- "displayName": "migrateEuiIconSvg",
46525
+ "displayName": "migrateEuiIconToggle",
46526
46526
  "args": [
46527
46527
  {
46528
46528
  "name": "options",
@@ -46548,7 +46548,7 @@
46548
46548
  },
46549
46549
  {
46550
46550
  "name": "migrateInlineTemplates",
46551
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46551
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46552
46552
  "ctype": "miscellaneous",
46553
46553
  "subtype": "function",
46554
46554
  "coverageIgnore": false,
@@ -46580,7 +46580,7 @@
46580
46580
  },
46581
46581
  {
46582
46582
  "name": "migrateTemplate",
46583
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46583
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46584
46584
  "ctype": "miscellaneous",
46585
46585
  "subtype": "function",
46586
46586
  "coverageIgnore": false,
@@ -46612,7 +46612,7 @@
46612
46612
  },
46613
46613
  {
46614
46614
  "name": "renameTsPropertyAccesses",
46615
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46615
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46616
46616
  "ctype": "miscellaneous",
46617
46617
  "subtype": "function",
46618
46618
  "coverageIgnore": false,
@@ -46644,7 +46644,7 @@
46644
46644
  },
46645
46645
  {
46646
46646
  "name": "unwrapExpression",
46647
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46647
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46648
46648
  "ctype": "miscellaneous",
46649
46649
  "subtype": "function",
46650
46650
  "coverageIgnore": false,
@@ -46674,7 +46674,7 @@
46674
46674
  },
46675
46675
  {
46676
46676
  "name": "visitDir",
46677
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46677
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46678
46678
  "ctype": "miscellaneous",
46679
46679
  "subtype": "function",
46680
46680
  "coverageIgnore": false,
@@ -46719,7 +46719,7 @@
46719
46719
  },
46720
46720
  {
46721
46721
  "name": "visitNodes",
46722
- "file": "packages/core/schematics/migrate-eui-icon-svg/index.ts",
46722
+ "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46723
46723
  "ctype": "miscellaneous",
46724
46724
  "subtype": "function",
46725
46725
  "coverageIgnore": false,
@@ -46761,10 +46761,10 @@
46761
46761
  ]
46762
46762
  }
46763
46763
  ],
46764
- "packages/core/schematics/migrate-eui-icon-toggle/index.ts": [
46764
+ "packages/core/schematics/migrate-eui-progress-circle/index.ts": [
46765
46765
  {
46766
46766
  "name": "applyEdits",
46767
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46767
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
46768
46768
  "ctype": "miscellaneous",
46769
46769
  "subtype": "function",
46770
46770
  "coverageIgnore": false,
@@ -46809,7 +46809,7 @@
46809
46809
  },
46810
46810
  {
46811
46811
  "name": "collectRenames",
46812
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46812
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
46813
46813
  "ctype": "miscellaneous",
46814
46814
  "subtype": "function",
46815
46815
  "coverageIgnore": false,
@@ -46854,7 +46854,7 @@
46854
46854
  },
46855
46855
  {
46856
46856
  "name": "isComponentMetadataProperty",
46857
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46857
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
46858
46858
  "ctype": "miscellaneous",
46859
46859
  "subtype": "function",
46860
46860
  "coverageIgnore": false,
@@ -46884,7 +46884,7 @@
46884
46884
  },
46885
46885
  {
46886
46886
  "name": "isTemplateProperty",
46887
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46887
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
46888
46888
  "ctype": "miscellaneous",
46889
46889
  "subtype": "function",
46890
46890
  "coverageIgnore": false,
@@ -46913,8 +46913,8 @@
46913
46913
  ]
46914
46914
  },
46915
46915
  {
46916
- "name": "migrateEuiIconToggle",
46917
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46916
+ "name": "migrateEuiProgressCircle",
46917
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
46918
46918
  "ctype": "miscellaneous",
46919
46919
  "subtype": "function",
46920
46920
  "coverageIgnore": false,
@@ -46922,7 +46922,7 @@
46922
46922
  "deprecationMessage": "",
46923
46923
  "rawdescription": "",
46924
46924
  "description": "",
46925
- "displayName": "migrateEuiIconToggle",
46925
+ "displayName": "migrateEuiProgressCircle",
46926
46926
  "args": [
46927
46927
  {
46928
46928
  "name": "options",
@@ -46948,7 +46948,7 @@
46948
46948
  },
46949
46949
  {
46950
46950
  "name": "migrateInlineTemplates",
46951
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46951
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
46952
46952
  "ctype": "miscellaneous",
46953
46953
  "subtype": "function",
46954
46954
  "coverageIgnore": false,
@@ -46980,7 +46980,7 @@
46980
46980
  },
46981
46981
  {
46982
46982
  "name": "migrateTemplate",
46983
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
46983
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
46984
46984
  "ctype": "miscellaneous",
46985
46985
  "subtype": "function",
46986
46986
  "coverageIgnore": false,
@@ -47010,41 +47010,9 @@
47010
47010
  }
47011
47011
  ]
47012
47012
  },
47013
- {
47014
- "name": "renameTsPropertyAccesses",
47015
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
47016
- "ctype": "miscellaneous",
47017
- "subtype": "function",
47018
- "coverageIgnore": false,
47019
- "deprecated": false,
47020
- "deprecationMessage": "",
47021
- "rawdescription": "",
47022
- "description": "",
47023
- "displayName": "renameTsPropertyAccesses",
47024
- "args": [
47025
- {
47026
- "name": "source",
47027
- "type": "string",
47028
- "deprecated": false,
47029
- "deprecationMessage": ""
47030
- }
47031
- ],
47032
- "returnType": "string",
47033
- "jsdoctags": [
47034
- {
47035
- "name": "source",
47036
- "type": "string",
47037
- "deprecated": false,
47038
- "deprecationMessage": "",
47039
- "tagName": {
47040
- "text": "param"
47041
- }
47042
- }
47043
- ]
47044
- },
47045
47013
  {
47046
47014
  "name": "unwrapExpression",
47047
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
47015
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47048
47016
  "ctype": "miscellaneous",
47049
47017
  "subtype": "function",
47050
47018
  "coverageIgnore": false,
@@ -47074,7 +47042,7 @@
47074
47042
  },
47075
47043
  {
47076
47044
  "name": "visitDir",
47077
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
47045
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47078
47046
  "ctype": "miscellaneous",
47079
47047
  "subtype": "function",
47080
47048
  "coverageIgnore": false,
@@ -47119,7 +47087,7 @@
47119
47087
  },
47120
47088
  {
47121
47089
  "name": "visitNodes",
47122
- "file": "packages/core/schematics/migrate-eui-icon-toggle/index.ts",
47090
+ "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47123
47091
  "ctype": "miscellaneous",
47124
47092
  "subtype": "function",
47125
47093
  "coverageIgnore": false,
@@ -47161,10 +47129,10 @@
47161
47129
  ]
47162
47130
  }
47163
47131
  ],
47164
- "packages/core/schematics/migrate-eui-progress-circle/index.ts": [
47132
+ "packages/core/schematics/migrate-eui-button/index.ts": [
47165
47133
  {
47166
47134
  "name": "applyEdits",
47167
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47135
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47168
47136
  "ctype": "miscellaneous",
47169
47137
  "subtype": "function",
47170
47138
  "coverageIgnore": false,
@@ -47209,7 +47177,7 @@
47209
47177
  },
47210
47178
  {
47211
47179
  "name": "collectRenames",
47212
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47180
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47213
47181
  "ctype": "miscellaneous",
47214
47182
  "subtype": "function",
47215
47183
  "coverageIgnore": false,
@@ -47252,9 +47220,41 @@
47252
47220
  }
47253
47221
  ]
47254
47222
  },
47223
+ {
47224
+ "name": "hasEuiButtonAttribute",
47225
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47226
+ "ctype": "miscellaneous",
47227
+ "subtype": "function",
47228
+ "coverageIgnore": false,
47229
+ "deprecated": false,
47230
+ "deprecationMessage": "",
47231
+ "rawdescription": "",
47232
+ "description": "",
47233
+ "displayName": "hasEuiButtonAttribute",
47234
+ "args": [
47235
+ {
47236
+ "name": "element",
47237
+ "type": "TmplAstElement",
47238
+ "deprecated": false,
47239
+ "deprecationMessage": ""
47240
+ }
47241
+ ],
47242
+ "returnType": "boolean",
47243
+ "jsdoctags": [
47244
+ {
47245
+ "name": "element",
47246
+ "type": "TmplAstElement",
47247
+ "deprecated": false,
47248
+ "deprecationMessage": "",
47249
+ "tagName": {
47250
+ "text": "param"
47251
+ }
47252
+ }
47253
+ ]
47254
+ },
47255
47255
  {
47256
47256
  "name": "isComponentMetadataProperty",
47257
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47257
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47258
47258
  "ctype": "miscellaneous",
47259
47259
  "subtype": "function",
47260
47260
  "coverageIgnore": false,
@@ -47284,7 +47284,7 @@
47284
47284
  },
47285
47285
  {
47286
47286
  "name": "isTemplateProperty",
47287
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47287
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47288
47288
  "ctype": "miscellaneous",
47289
47289
  "subtype": "function",
47290
47290
  "coverageIgnore": false,
@@ -47313,8 +47313,8 @@
47313
47313
  ]
47314
47314
  },
47315
47315
  {
47316
- "name": "migrateEuiProgressCircle",
47317
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47316
+ "name": "migrateEuiButton",
47317
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47318
47318
  "ctype": "miscellaneous",
47319
47319
  "subtype": "function",
47320
47320
  "coverageIgnore": false,
@@ -47322,7 +47322,7 @@
47322
47322
  "deprecationMessage": "",
47323
47323
  "rawdescription": "",
47324
47324
  "description": "",
47325
- "displayName": "migrateEuiProgressCircle",
47325
+ "displayName": "migrateEuiButton",
47326
47326
  "args": [
47327
47327
  {
47328
47328
  "name": "options",
@@ -47348,7 +47348,7 @@
47348
47348
  },
47349
47349
  {
47350
47350
  "name": "migrateInlineTemplates",
47351
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47351
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47352
47352
  "ctype": "miscellaneous",
47353
47353
  "subtype": "function",
47354
47354
  "coverageIgnore": false,
@@ -47380,7 +47380,7 @@
47380
47380
  },
47381
47381
  {
47382
47382
  "name": "migrateTemplate",
47383
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47383
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47384
47384
  "ctype": "miscellaneous",
47385
47385
  "subtype": "function",
47386
47386
  "coverageIgnore": false,
@@ -47412,7 +47412,7 @@
47412
47412
  },
47413
47413
  {
47414
47414
  "name": "unwrapExpression",
47415
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47415
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47416
47416
  "ctype": "miscellaneous",
47417
47417
  "subtype": "function",
47418
47418
  "coverageIgnore": false,
@@ -47442,7 +47442,7 @@
47442
47442
  },
47443
47443
  {
47444
47444
  "name": "visitDir",
47445
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47445
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47446
47446
  "ctype": "miscellaneous",
47447
47447
  "subtype": "function",
47448
47448
  "coverageIgnore": false,
@@ -47487,7 +47487,7 @@
47487
47487
  },
47488
47488
  {
47489
47489
  "name": "visitNodes",
47490
- "file": "packages/core/schematics/migrate-eui-progress-circle/index.ts",
47490
+ "file": "packages/core/schematics/migrate-eui-button/index.ts",
47491
47491
  "ctype": "miscellaneous",
47492
47492
  "subtype": "function",
47493
47493
  "coverageIgnore": false,
@@ -50777,10 +50777,10 @@
50777
50777
  ]
50778
50778
  }
50779
50779
  ],
50780
- "packages/core/schematics/migrate-eui-chip/index.ts": [
50780
+ "packages/core/schematics/migrate-eui-discussion-thread/index.ts": [
50781
50781
  {
50782
50782
  "name": "collectRemovals",
50783
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50783
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
50784
50784
  "ctype": "miscellaneous",
50785
50785
  "subtype": "function",
50786
50786
  "coverageIgnore": false,
@@ -50796,6 +50796,12 @@
50796
50796
  "deprecated": false,
50797
50797
  "deprecationMessage": ""
50798
50798
  },
50799
+ {
50800
+ "name": "source",
50801
+ "type": "string",
50802
+ "deprecated": false,
50803
+ "deprecationMessage": ""
50804
+ },
50799
50805
  {
50800
50806
  "name": "removals",
50801
50807
  "deprecated": false,
@@ -50814,69 +50820,16 @@
50814
50820
  }
50815
50821
  },
50816
50822
  {
50817
- "name": "removals",
50818
- "deprecated": false,
50819
- "deprecationMessage": "",
50820
- "tagName": {
50821
- "text": "param"
50822
- }
50823
- }
50824
- ]
50825
- },
50826
- {
50827
- "name": "getAttributeSpan",
50828
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50829
- "ctype": "miscellaneous",
50830
- "subtype": "function",
50831
- "coverageIgnore": false,
50832
- "deprecated": false,
50833
- "deprecationMessage": "",
50834
- "rawdescription": "",
50835
- "description": "",
50836
- "displayName": "getAttributeSpan",
50837
- "args": [
50838
- {
50839
- "name": "attr",
50840
- "deprecated": false,
50841
- "deprecationMessage": ""
50842
- }
50843
- ],
50844
- "returnType": "{ start: number; end: number }",
50845
- "jsdoctags": [
50846
- {
50847
- "name": "attr",
50823
+ "name": "source",
50824
+ "type": "string",
50848
50825
  "deprecated": false,
50849
50826
  "deprecationMessage": "",
50850
50827
  "tagName": {
50851
50828
  "text": "param"
50852
50829
  }
50853
- }
50854
- ]
50855
- },
50856
- {
50857
- "name": "isChipElement",
50858
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50859
- "ctype": "miscellaneous",
50860
- "subtype": "function",
50861
- "coverageIgnore": false,
50862
- "deprecated": false,
50863
- "deprecationMessage": "",
50864
- "rawdescription": "",
50865
- "description": "",
50866
- "displayName": "isChipElement",
50867
- "args": [
50868
- {
50869
- "name": "element",
50870
- "type": "TmplAstElement",
50871
- "deprecated": false,
50872
- "deprecationMessage": ""
50873
- }
50874
- ],
50875
- "returnType": "boolean",
50876
- "jsdoctags": [
50830
+ },
50877
50831
  {
50878
- "name": "element",
50879
- "type": "TmplAstElement",
50832
+ "name": "removals",
50880
50833
  "deprecated": false,
50881
50834
  "deprecationMessage": "",
50882
50835
  "tagName": {
@@ -50886,8 +50839,8 @@
50886
50839
  ]
50887
50840
  },
50888
50841
  {
50889
- "name": "migrateEuiChip",
50890
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50842
+ "name": "migrateEuiDiscussionThread",
50843
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
50891
50844
  "ctype": "miscellaneous",
50892
50845
  "subtype": "function",
50893
50846
  "coverageIgnore": false,
@@ -50895,7 +50848,7 @@
50895
50848
  "deprecationMessage": "",
50896
50849
  "rawdescription": "",
50897
50850
  "description": "",
50898
- "displayName": "migrateEuiChip",
50851
+ "displayName": "migrateEuiDiscussionThread",
50899
50852
  "args": [
50900
50853
  {
50901
50854
  "name": "options",
@@ -50921,7 +50874,7 @@
50921
50874
  },
50922
50875
  {
50923
50876
  "name": "migrateInlineTemplates",
50924
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50877
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
50925
50878
  "ctype": "miscellaneous",
50926
50879
  "subtype": "function",
50927
50880
  "coverageIgnore": false,
@@ -50953,7 +50906,7 @@
50953
50906
  },
50954
50907
  {
50955
50908
  "name": "migrateTemplate",
50956
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50909
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
50957
50910
  "ctype": "miscellaneous",
50958
50911
  "subtype": "function",
50959
50912
  "coverageIgnore": false,
@@ -50985,7 +50938,7 @@
50985
50938
  },
50986
50939
  {
50987
50940
  "name": "visitDir",
50988
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50941
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
50989
50942
  "ctype": "miscellaneous",
50990
50943
  "subtype": "function",
50991
50944
  "coverageIgnore": false,
@@ -51030,7 +50983,7 @@
51030
50983
  },
51031
50984
  {
51032
50985
  "name": "visitNodes",
51033
- "file": "packages/core/schematics/migrate-eui-chip/index.ts",
50986
+ "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
51034
50987
  "ctype": "miscellaneous",
51035
50988
  "subtype": "function",
51036
50989
  "coverageIgnore": false,
@@ -51045,6 +50998,12 @@
51045
50998
  "deprecated": false,
51046
50999
  "deprecationMessage": ""
51047
51000
  },
51001
+ {
51002
+ "name": "source",
51003
+ "type": "string",
51004
+ "deprecated": false,
51005
+ "deprecationMessage": ""
51006
+ },
51048
51007
  {
51049
51008
  "name": "removals",
51050
51009
  "deprecated": false,
@@ -51061,6 +51020,15 @@
51061
51020
  "text": "param"
51062
51021
  }
51063
51022
  },
51023
+ {
51024
+ "name": "source",
51025
+ "type": "string",
51026
+ "deprecated": false,
51027
+ "deprecationMessage": "",
51028
+ "tagName": {
51029
+ "text": "param"
51030
+ }
51031
+ },
51064
51032
  {
51065
51033
  "name": "removals",
51066
51034
  "deprecated": false,
@@ -51072,10 +51040,10 @@
51072
51040
  ]
51073
51041
  }
51074
51042
  ],
51075
- "packages/core/schematics/migrate-eui-discussion-thread/index.ts": [
51043
+ "packages/core/schematics/migrate-eui-popover/index.ts": [
51076
51044
  {
51077
51045
  "name": "collectRemovals",
51078
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
51046
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51079
51047
  "ctype": "miscellaneous",
51080
51048
  "subtype": "function",
51081
51049
  "coverageIgnore": false,
@@ -51091,12 +51059,6 @@
51091
51059
  "deprecated": false,
51092
51060
  "deprecationMessage": ""
51093
51061
  },
51094
- {
51095
- "name": "source",
51096
- "type": "string",
51097
- "deprecated": false,
51098
- "deprecationMessage": ""
51099
- },
51100
51062
  {
51101
51063
  "name": "removals",
51102
51064
  "deprecated": false,
@@ -51115,16 +51077,37 @@
51115
51077
  }
51116
51078
  },
51117
51079
  {
51118
- "name": "source",
51119
- "type": "string",
51080
+ "name": "removals",
51120
51081
  "deprecated": false,
51121
51082
  "deprecationMessage": "",
51122
51083
  "tagName": {
51123
51084
  "text": "param"
51124
51085
  }
51125
- },
51086
+ }
51087
+ ]
51088
+ },
51089
+ {
51090
+ "name": "getAttributeSpan",
51091
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51092
+ "ctype": "miscellaneous",
51093
+ "subtype": "function",
51094
+ "coverageIgnore": false,
51095
+ "deprecated": false,
51096
+ "deprecationMessage": "",
51097
+ "rawdescription": "",
51098
+ "description": "",
51099
+ "displayName": "getAttributeSpan",
51100
+ "args": [
51126
51101
  {
51127
- "name": "removals",
51102
+ "name": "attr",
51103
+ "deprecated": false,
51104
+ "deprecationMessage": ""
51105
+ }
51106
+ ],
51107
+ "returnType": "{ start: number; end: number }",
51108
+ "jsdoctags": [
51109
+ {
51110
+ "name": "attr",
51128
51111
  "deprecated": false,
51129
51112
  "deprecationMessage": "",
51130
51113
  "tagName": {
@@ -51134,8 +51117,8 @@
51134
51117
  ]
51135
51118
  },
51136
51119
  {
51137
- "name": "migrateEuiDiscussionThread",
51138
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
51120
+ "name": "migrateEuiPopover",
51121
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51139
51122
  "ctype": "miscellaneous",
51140
51123
  "subtype": "function",
51141
51124
  "coverageIgnore": false,
@@ -51143,7 +51126,7 @@
51143
51126
  "deprecationMessage": "",
51144
51127
  "rawdescription": "",
51145
51128
  "description": "",
51146
- "displayName": "migrateEuiDiscussionThread",
51129
+ "displayName": "migrateEuiPopover",
51147
51130
  "args": [
51148
51131
  {
51149
51132
  "name": "options",
@@ -51169,7 +51152,7 @@
51169
51152
  },
51170
51153
  {
51171
51154
  "name": "migrateInlineTemplates",
51172
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
51155
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51173
51156
  "ctype": "miscellaneous",
51174
51157
  "subtype": "function",
51175
51158
  "coverageIgnore": false,
@@ -51201,7 +51184,7 @@
51201
51184
  },
51202
51185
  {
51203
51186
  "name": "migrateTemplate",
51204
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
51187
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51205
51188
  "ctype": "miscellaneous",
51206
51189
  "subtype": "function",
51207
51190
  "coverageIgnore": false,
@@ -51233,7 +51216,7 @@
51233
51216
  },
51234
51217
  {
51235
51218
  "name": "visitDir",
51236
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
51219
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51237
51220
  "ctype": "miscellaneous",
51238
51221
  "subtype": "function",
51239
51222
  "coverageIgnore": false,
@@ -51278,7 +51261,7 @@
51278
51261
  },
51279
51262
  {
51280
51263
  "name": "visitNodes",
51281
- "file": "packages/core/schematics/migrate-eui-discussion-thread/index.ts",
51264
+ "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51282
51265
  "ctype": "miscellaneous",
51283
51266
  "subtype": "function",
51284
51267
  "coverageIgnore": false,
@@ -51293,12 +51276,6 @@
51293
51276
  "deprecated": false,
51294
51277
  "deprecationMessage": ""
51295
51278
  },
51296
- {
51297
- "name": "source",
51298
- "type": "string",
51299
- "deprecated": false,
51300
- "deprecationMessage": ""
51301
- },
51302
51279
  {
51303
51280
  "name": "removals",
51304
51281
  "deprecated": false,
@@ -51315,15 +51292,6 @@
51315
51292
  "text": "param"
51316
51293
  }
51317
51294
  },
51318
- {
51319
- "name": "source",
51320
- "type": "string",
51321
- "deprecated": false,
51322
- "deprecationMessage": "",
51323
- "tagName": {
51324
- "text": "param"
51325
- }
51326
- },
51327
51295
  {
51328
51296
  "name": "removals",
51329
51297
  "deprecated": false,
@@ -51335,10 +51303,10 @@
51335
51303
  ]
51336
51304
  }
51337
51305
  ],
51338
- "packages/core/schematics/migrate-eui-popover/index.ts": [
51306
+ "packages/core/schematics/migrate-eui-chip/index.ts": [
51339
51307
  {
51340
51308
  "name": "collectRemovals",
51341
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51309
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51342
51310
  "ctype": "miscellaneous",
51343
51311
  "subtype": "function",
51344
51312
  "coverageIgnore": false,
@@ -51383,7 +51351,7 @@
51383
51351
  },
51384
51352
  {
51385
51353
  "name": "getAttributeSpan",
51386
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51354
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51387
51355
  "ctype": "miscellaneous",
51388
51356
  "subtype": "function",
51389
51357
  "coverageIgnore": false,
@@ -51412,8 +51380,8 @@
51412
51380
  ]
51413
51381
  },
51414
51382
  {
51415
- "name": "migrateEuiPopover",
51416
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51383
+ "name": "isChipElement",
51384
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51417
51385
  "ctype": "miscellaneous",
51418
51386
  "subtype": "function",
51419
51387
  "coverageIgnore": false,
@@ -51421,7 +51389,39 @@
51421
51389
  "deprecationMessage": "",
51422
51390
  "rawdescription": "",
51423
51391
  "description": "",
51424
- "displayName": "migrateEuiPopover",
51392
+ "displayName": "isChipElement",
51393
+ "args": [
51394
+ {
51395
+ "name": "element",
51396
+ "type": "TmplAstElement",
51397
+ "deprecated": false,
51398
+ "deprecationMessage": ""
51399
+ }
51400
+ ],
51401
+ "returnType": "boolean",
51402
+ "jsdoctags": [
51403
+ {
51404
+ "name": "element",
51405
+ "type": "TmplAstElement",
51406
+ "deprecated": false,
51407
+ "deprecationMessage": "",
51408
+ "tagName": {
51409
+ "text": "param"
51410
+ }
51411
+ }
51412
+ ]
51413
+ },
51414
+ {
51415
+ "name": "migrateEuiChip",
51416
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51417
+ "ctype": "miscellaneous",
51418
+ "subtype": "function",
51419
+ "coverageIgnore": false,
51420
+ "deprecated": false,
51421
+ "deprecationMessage": "",
51422
+ "rawdescription": "",
51423
+ "description": "",
51424
+ "displayName": "migrateEuiChip",
51425
51425
  "args": [
51426
51426
  {
51427
51427
  "name": "options",
@@ -51447,7 +51447,7 @@
51447
51447
  },
51448
51448
  {
51449
51449
  "name": "migrateInlineTemplates",
51450
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51450
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51451
51451
  "ctype": "miscellaneous",
51452
51452
  "subtype": "function",
51453
51453
  "coverageIgnore": false,
@@ -51479,7 +51479,7 @@
51479
51479
  },
51480
51480
  {
51481
51481
  "name": "migrateTemplate",
51482
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51482
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51483
51483
  "ctype": "miscellaneous",
51484
51484
  "subtype": "function",
51485
51485
  "coverageIgnore": false,
@@ -51511,7 +51511,7 @@
51511
51511
  },
51512
51512
  {
51513
51513
  "name": "visitDir",
51514
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51514
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51515
51515
  "ctype": "miscellaneous",
51516
51516
  "subtype": "function",
51517
51517
  "coverageIgnore": false,
@@ -51556,7 +51556,7 @@
51556
51556
  },
51557
51557
  {
51558
51558
  "name": "visitNodes",
51559
- "file": "packages/core/schematics/migrate-eui-popover/index.ts",
51559
+ "file": "packages/core/schematics/migrate-eui-chip/index.ts",
51560
51560
  "ctype": "miscellaneous",
51561
51561
  "subtype": "function",
51562
51562
  "coverageIgnore": false,