@eui/core 22.0.0-alpha.12 → 22.0.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/docs/changelog.html +20 -0
- package/docs/interfaces/Edit-3.html +1 -1
- package/docs/interfaces/Edit-4.html +1 -1
- package/docs/interfaces/Schema-13.html +1 -1
- package/docs/interfaces/Schema-15.html +1 -1
- package/docs/interfaces/Schema-16.html +1 -1
- package/docs/interfaces/Schema-17.html +1 -1
- package/docs/interfaces/Schema-18.html +1 -1
- package/docs/interfaces/Schema-2.html +52 -1
- package/docs/interfaces/Schema-20.html +1 -1
- package/docs/interfaces/Schema-21.html +1 -1
- package/docs/interfaces/Schema-3.html +1 -52
- package/docs/interfaces/Schema-7.html +1 -1
- package/docs/interfaces/Schema-8.html +1 -1
- package/docs/js/search/search_index.js +2 -2
- package/docs/json/documentation.json +511 -511
- package/docs/llms.txt +65 -65
- package/docs/miscellaneous/functions.html +479 -479
- package/docs/miscellaneous/variables.html +31 -31
- package/docs/properties.html +1 -1
- package/package.json +2 -2
|
@@ -968,12 +968,12 @@
|
|
|
968
968
|
},
|
|
969
969
|
{
|
|
970
970
|
"name": "Edit",
|
|
971
|
-
"id": "interface-Edit-
|
|
972
|
-
"file": "packages/core/schematics/migrate-
|
|
971
|
+
"id": "interface-Edit-cac2ac952d8245647e8a48b450e8f127a36bcffb394cf2cd81fe9c0810ed02c19e5e1629dbf29a68a5c6f675aed99570e9ac04ae470e13315e20c92cc0c6c453-3",
|
|
972
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
973
973
|
"deprecated": false,
|
|
974
974
|
"deprecationMessage": "",
|
|
975
975
|
"type": "interface",
|
|
976
|
-
"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",
|
|
976
|
+
"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",
|
|
977
977
|
"displayName": "Edit",
|
|
978
978
|
"properties": [
|
|
979
979
|
{
|
|
@@ -985,7 +985,7 @@
|
|
|
985
985
|
"indexKey": "",
|
|
986
986
|
"optional": false,
|
|
987
987
|
"description": "",
|
|
988
|
-
"line":
|
|
988
|
+
"line": 14,
|
|
989
989
|
"rawdescription": "\n"
|
|
990
990
|
},
|
|
991
991
|
{
|
|
@@ -997,7 +997,7 @@
|
|
|
997
997
|
"indexKey": "",
|
|
998
998
|
"optional": false,
|
|
999
999
|
"description": "",
|
|
1000
|
-
"line":
|
|
1000
|
+
"line": 15,
|
|
1001
1001
|
"rawdescription": "\n"
|
|
1002
1002
|
},
|
|
1003
1003
|
{
|
|
@@ -1009,7 +1009,7 @@
|
|
|
1009
1009
|
"indexKey": "",
|
|
1010
1010
|
"optional": false,
|
|
1011
1011
|
"description": "",
|
|
1012
|
-
"line":
|
|
1012
|
+
"line": 13,
|
|
1013
1013
|
"rawdescription": "\n"
|
|
1014
1014
|
}
|
|
1015
1015
|
],
|
|
@@ -1027,12 +1027,12 @@
|
|
|
1027
1027
|
},
|
|
1028
1028
|
{
|
|
1029
1029
|
"name": "Edit",
|
|
1030
|
-
"id": "interface-Edit-
|
|
1031
|
-
"file": "packages/core/schematics/migrate-
|
|
1030
|
+
"id": "interface-Edit-d36032102ed30a7ada1e3d36bb9ca41b7234b855760cac9783a25818f7ffe2097e1ebd8e808b574ddec0760f827272f6cd561f45f3eb1578f87f39ee2633730a-4",
|
|
1031
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
1032
1032
|
"deprecated": false,
|
|
1033
1033
|
"deprecationMessage": "",
|
|
1034
1034
|
"type": "interface",
|
|
1035
|
-
"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",
|
|
1035
|
+
"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",
|
|
1036
1036
|
"displayName": "Edit",
|
|
1037
1037
|
"properties": [
|
|
1038
1038
|
{
|
|
@@ -1044,7 +1044,7 @@
|
|
|
1044
1044
|
"indexKey": "",
|
|
1045
1045
|
"optional": false,
|
|
1046
1046
|
"description": "",
|
|
1047
|
-
"line":
|
|
1047
|
+
"line": 12,
|
|
1048
1048
|
"rawdescription": "\n"
|
|
1049
1049
|
},
|
|
1050
1050
|
{
|
|
@@ -1056,7 +1056,7 @@
|
|
|
1056
1056
|
"indexKey": "",
|
|
1057
1057
|
"optional": false,
|
|
1058
1058
|
"description": "",
|
|
1059
|
-
"line":
|
|
1059
|
+
"line": 13,
|
|
1060
1060
|
"rawdescription": "\n"
|
|
1061
1061
|
},
|
|
1062
1062
|
{
|
|
@@ -1068,7 +1068,7 @@
|
|
|
1068
1068
|
"indexKey": "",
|
|
1069
1069
|
"optional": false,
|
|
1070
1070
|
"description": "",
|
|
1071
|
-
"line":
|
|
1071
|
+
"line": 11,
|
|
1072
1072
|
"rawdescription": "\n"
|
|
1073
1073
|
}
|
|
1074
1074
|
],
|
|
@@ -2195,12 +2195,12 @@
|
|
|
2195
2195
|
},
|
|
2196
2196
|
{
|
|
2197
2197
|
"name": "Schema",
|
|
2198
|
-
"id": "interface-Schema-
|
|
2199
|
-
"file": "packages/core/schematics/
|
|
2198
|
+
"id": "interface-Schema-5cd6db1920bd5b70a44c0b8a7f7e30f600bfd16a9950f218e6d451a1755ced95b462ef9a62ee87e39bcb8c392981b8d2597895bf0a272fd8aea71f03429ed976-1",
|
|
2199
|
+
"file": "packages/core/schematics/icon-migrate/schema.ts",
|
|
2200
2200
|
"deprecated": false,
|
|
2201
2201
|
"deprecationMessage": "",
|
|
2202
2202
|
"type": "interface",
|
|
2203
|
-
"sourceCode": "
|
|
2203
|
+
"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
2204
|
"displayName": "Schema",
|
|
2205
2205
|
"properties": [
|
|
2206
2206
|
{
|
|
@@ -2211,9 +2211,9 @@
|
|
|
2211
2211
|
"type": "boolean",
|
|
2212
2212
|
"indexKey": "",
|
|
2213
2213
|
"optional": true,
|
|
2214
|
-
"description": "",
|
|
2215
|
-
"line":
|
|
2216
|
-
"rawdescription": "\
|
|
2214
|
+
"description": "<p>Whether to perform a dry run without making changes</p>\n",
|
|
2215
|
+
"line": 5,
|
|
2216
|
+
"rawdescription": "\nWhether to perform a dry run without making changes"
|
|
2217
2217
|
},
|
|
2218
2218
|
{
|
|
2219
2219
|
"name": "path",
|
|
@@ -2223,9 +2223,9 @@
|
|
|
2223
2223
|
"type": "string",
|
|
2224
2224
|
"indexKey": "",
|
|
2225
2225
|
"optional": true,
|
|
2226
|
-
"description": "",
|
|
2227
|
-
"line":
|
|
2228
|
-
"rawdescription": "\
|
|
2226
|
+
"description": "<p>The path to scan for files to migrate</p>\n",
|
|
2227
|
+
"line": 3,
|
|
2228
|
+
"rawdescription": "\nThe path to scan for files to migrate"
|
|
2229
2229
|
}
|
|
2230
2230
|
],
|
|
2231
2231
|
"indexSignatures": [],
|
|
@@ -2242,12 +2242,12 @@
|
|
|
2242
2242
|
},
|
|
2243
2243
|
{
|
|
2244
2244
|
"name": "Schema",
|
|
2245
|
-
"id": "interface-Schema-
|
|
2246
|
-
"file": "packages/core/schematics/
|
|
2245
|
+
"id": "interface-Schema-4fe31ff3e9f1d34845a6b865d605e215f33552094b88c3d0eab0b180187fe64ce4d68d687516cb3d62c57d2678a103969b2dacbb18a49b26060f78096678fcce-2",
|
|
2246
|
+
"file": "packages/core/schematics/fix-no-multiple-empty-lines/index.ts",
|
|
2247
2247
|
"deprecated": false,
|
|
2248
2248
|
"deprecationMessage": "",
|
|
2249
2249
|
"type": "interface",
|
|
2250
|
-
"sourceCode": "
|
|
2250
|
+
"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",
|
|
2251
2251
|
"displayName": "Schema",
|
|
2252
2252
|
"properties": [
|
|
2253
2253
|
{
|
|
@@ -2258,9 +2258,9 @@
|
|
|
2258
2258
|
"type": "boolean",
|
|
2259
2259
|
"indexKey": "",
|
|
2260
2260
|
"optional": true,
|
|
2261
|
-
"description": "
|
|
2262
|
-
"line":
|
|
2263
|
-
"rawdescription": "\
|
|
2261
|
+
"description": "",
|
|
2262
|
+
"line": 7,
|
|
2263
|
+
"rawdescription": "\n"
|
|
2264
2264
|
},
|
|
2265
2265
|
{
|
|
2266
2266
|
"name": "path",
|
|
@@ -2270,9 +2270,9 @@
|
|
|
2270
2270
|
"type": "string",
|
|
2271
2271
|
"indexKey": "",
|
|
2272
2272
|
"optional": true,
|
|
2273
|
-
"description": "
|
|
2274
|
-
"line":
|
|
2275
|
-
"rawdescription": "\
|
|
2273
|
+
"description": "",
|
|
2274
|
+
"line": 6,
|
|
2275
|
+
"rawdescription": "\n"
|
|
2276
2276
|
}
|
|
2277
2277
|
],
|
|
2278
2278
|
"indexSignatures": [],
|
|
@@ -3100,12 +3100,12 @@
|
|
|
3100
3100
|
},
|
|
3101
3101
|
{
|
|
3102
3102
|
"name": "Schema",
|
|
3103
|
-
"id": "interface-Schema-
|
|
3104
|
-
"file": "packages/core/schematics/migrate-
|
|
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":
|
|
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":
|
|
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-
|
|
3151
|
-
"file": "packages/core/schematics/migrate-to-
|
|
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":
|
|
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":
|
|
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-
|
|
3198
|
-
"file": "packages/core/schematics/migrate-
|
|
3197
|
+
"id": "interface-Schema-d36032102ed30a7ada1e3d36bb9ca41b7234b855760cac9783a25818f7ffe2097e1ebd8e808b574ddec0760f827272f6cd561f45f3eb1578f87f39ee2633730a-22",
|
|
3198
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/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 { 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",
|
|
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":
|
|
3214
|
+
"line": 7,
|
|
3215
3215
|
"rawdescription": "\n"
|
|
3216
3216
|
},
|
|
3217
3217
|
{
|
|
@@ -3223,7 +3223,7 @@
|
|
|
3223
3223
|
"indexKey": "",
|
|
3224
3224
|
"optional": true,
|
|
3225
3225
|
"description": "",
|
|
3226
|
-
"line":
|
|
3226
|
+
"line": 6,
|
|
3227
3227
|
"rawdescription": "\n"
|
|
3228
3228
|
}
|
|
3229
3229
|
],
|
|
@@ -24833,7 +24833,7 @@
|
|
|
24833
24833
|
},
|
|
24834
24834
|
{
|
|
24835
24835
|
"name": "applyEdits",
|
|
24836
|
-
"file": "packages/core/schematics/migrate-
|
|
24836
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
24837
24837
|
"ctype": "miscellaneous",
|
|
24838
24838
|
"subtype": "function",
|
|
24839
24839
|
"coverageIgnore": false,
|
|
@@ -24878,7 +24878,7 @@
|
|
|
24878
24878
|
},
|
|
24879
24879
|
{
|
|
24880
24880
|
"name": "applyEdits",
|
|
24881
|
-
"file": "packages/core/schematics/migrate-
|
|
24881
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
24882
24882
|
"ctype": "miscellaneous",
|
|
24883
24883
|
"subtype": "function",
|
|
24884
24884
|
"coverageIgnore": false,
|
|
@@ -27068,7 +27068,7 @@
|
|
|
27068
27068
|
},
|
|
27069
27069
|
{
|
|
27070
27070
|
"name": "deduplicateEdits",
|
|
27071
|
-
"file": "packages/core/schematics/migrate-
|
|
27071
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
27072
27072
|
"ctype": "miscellaneous",
|
|
27073
27073
|
"subtype": "function",
|
|
27074
27074
|
"coverageIgnore": false,
|
|
@@ -27098,7 +27098,7 @@
|
|
|
27098
27098
|
},
|
|
27099
27099
|
{
|
|
27100
27100
|
"name": "deduplicateEdits",
|
|
27101
|
-
"file": "packages/core/schematics/migrate-
|
|
27101
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
27102
27102
|
"ctype": "miscellaneous",
|
|
27103
27103
|
"subtype": "function",
|
|
27104
27104
|
"coverageIgnore": false,
|
|
@@ -33623,7 +33623,7 @@
|
|
|
33623
33623
|
},
|
|
33624
33624
|
{
|
|
33625
33625
|
"name": "migrateTypeScript",
|
|
33626
|
-
"file": "packages/core/schematics/migrate-
|
|
33626
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
33627
33627
|
"ctype": "miscellaneous",
|
|
33628
33628
|
"subtype": "function",
|
|
33629
33629
|
"coverageIgnore": false,
|
|
@@ -33645,6 +33645,12 @@
|
|
|
33645
33645
|
"deprecated": false,
|
|
33646
33646
|
"deprecationMessage": ""
|
|
33647
33647
|
},
|
|
33648
|
+
{
|
|
33649
|
+
"name": "tree",
|
|
33650
|
+
"type": "Tree",
|
|
33651
|
+
"deprecated": false,
|
|
33652
|
+
"deprecationMessage": ""
|
|
33653
|
+
},
|
|
33648
33654
|
{
|
|
33649
33655
|
"name": "context",
|
|
33650
33656
|
"type": "SchematicContext",
|
|
@@ -33652,7 +33658,7 @@
|
|
|
33652
33658
|
"deprecationMessage": ""
|
|
33653
33659
|
}
|
|
33654
33660
|
],
|
|
33655
|
-
"returnType": "
|
|
33661
|
+
"returnType": "MigrateResult",
|
|
33656
33662
|
"jsdoctags": [
|
|
33657
33663
|
{
|
|
33658
33664
|
"name": "source",
|
|
@@ -33672,6 +33678,15 @@
|
|
|
33672
33678
|
"text": "param"
|
|
33673
33679
|
}
|
|
33674
33680
|
},
|
|
33681
|
+
{
|
|
33682
|
+
"name": "tree",
|
|
33683
|
+
"type": "Tree",
|
|
33684
|
+
"deprecated": false,
|
|
33685
|
+
"deprecationMessage": "",
|
|
33686
|
+
"tagName": {
|
|
33687
|
+
"text": "param"
|
|
33688
|
+
}
|
|
33689
|
+
},
|
|
33675
33690
|
{
|
|
33676
33691
|
"name": "context",
|
|
33677
33692
|
"type": "SchematicContext",
|
|
@@ -33685,7 +33700,7 @@
|
|
|
33685
33700
|
},
|
|
33686
33701
|
{
|
|
33687
33702
|
"name": "migrateTypeScript",
|
|
33688
|
-
"file": "packages/core/schematics/migrate-
|
|
33703
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
33689
33704
|
"ctype": "miscellaneous",
|
|
33690
33705
|
"subtype": "function",
|
|
33691
33706
|
"coverageIgnore": false,
|
|
@@ -33707,12 +33722,6 @@
|
|
|
33707
33722
|
"deprecated": false,
|
|
33708
33723
|
"deprecationMessage": ""
|
|
33709
33724
|
},
|
|
33710
|
-
{
|
|
33711
|
-
"name": "tree",
|
|
33712
|
-
"type": "Tree",
|
|
33713
|
-
"deprecated": false,
|
|
33714
|
-
"deprecationMessage": ""
|
|
33715
|
-
},
|
|
33716
33725
|
{
|
|
33717
33726
|
"name": "context",
|
|
33718
33727
|
"type": "SchematicContext",
|
|
@@ -33720,7 +33729,7 @@
|
|
|
33720
33729
|
"deprecationMessage": ""
|
|
33721
33730
|
}
|
|
33722
33731
|
],
|
|
33723
|
-
"returnType": "
|
|
33732
|
+
"returnType": "string",
|
|
33724
33733
|
"jsdoctags": [
|
|
33725
33734
|
{
|
|
33726
33735
|
"name": "source",
|
|
@@ -33740,15 +33749,6 @@
|
|
|
33740
33749
|
"text": "param"
|
|
33741
33750
|
}
|
|
33742
33751
|
},
|
|
33743
|
-
{
|
|
33744
|
-
"name": "tree",
|
|
33745
|
-
"type": "Tree",
|
|
33746
|
-
"deprecated": false,
|
|
33747
|
-
"deprecationMessage": "",
|
|
33748
|
-
"tagName": {
|
|
33749
|
-
"text": "param"
|
|
33750
|
-
}
|
|
33751
|
-
},
|
|
33752
33752
|
{
|
|
33753
33753
|
"name": "context",
|
|
33754
33754
|
"type": "SchematicContext",
|
|
@@ -36664,7 +36664,7 @@
|
|
|
36664
36664
|
},
|
|
36665
36665
|
{
|
|
36666
36666
|
"name": "visitDir",
|
|
36667
|
-
"file": "packages/core/schematics/migrate-
|
|
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-
|
|
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-
|
|
36757
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
36758
36758
|
"ctype": "miscellaneous",
|
|
36759
36759
|
"subtype": "function",
|
|
36760
36760
|
"coverageIgnore": false,
|
|
@@ -48390,10 +48390,10 @@
|
|
|
48390
48390
|
]
|
|
48391
48391
|
}
|
|
48392
48392
|
],
|
|
48393
|
-
"packages/core/schematics/migrate-
|
|
48393
|
+
"packages/core/schematics/migrate-to-signals/index.ts": [
|
|
48394
48394
|
{
|
|
48395
48395
|
"name": "applyEdits",
|
|
48396
|
-
"file": "packages/core/schematics/migrate-
|
|
48396
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48397
48397
|
"ctype": "miscellaneous",
|
|
48398
48398
|
"subtype": "function",
|
|
48399
48399
|
"coverageIgnore": false,
|
|
@@ -48436,9 +48436,189 @@
|
|
|
48436
48436
|
}
|
|
48437
48437
|
]
|
|
48438
48438
|
},
|
|
48439
|
+
{
|
|
48440
|
+
"name": "buildTemplateRefMap",
|
|
48441
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48442
|
+
"ctype": "miscellaneous",
|
|
48443
|
+
"subtype": "function",
|
|
48444
|
+
"coverageIgnore": false,
|
|
48445
|
+
"deprecated": false,
|
|
48446
|
+
"deprecationMessage": "",
|
|
48447
|
+
"rawdescription": "Builds a map of template reference variable names (#ref) to EUI class names.\n\nParses the component's template (inline or external) and finds elements like:\n <eui-alert #myAlert> → myAlert → EuiAlertComponent\n <input euiAutocomplete #ac> → ac → EuiAutocompleteComponent\n\nReturns Map<refName, euiClassName>.",
|
|
48448
|
+
"description": "<p>Builds a map of template reference variable names (#ref) to EUI class names.</p>\n<p>Parses the component's template (inline or external) and finds elements like:\n <eui-alert #myAlert> → myAlert → EuiAlertComponent\n <input euiAutocomplete #ac> → ac → EuiAutocompleteComponent</p>\n<p>Returns Map<refName, euiClassName>.</p>\n",
|
|
48449
|
+
"displayName": "buildTemplateRefMap",
|
|
48450
|
+
"args": [
|
|
48451
|
+
{
|
|
48452
|
+
"name": "sourceFile",
|
|
48453
|
+
"deprecated": false,
|
|
48454
|
+
"deprecationMessage": ""
|
|
48455
|
+
},
|
|
48456
|
+
{
|
|
48457
|
+
"name": "source",
|
|
48458
|
+
"type": "string",
|
|
48459
|
+
"deprecated": false,
|
|
48460
|
+
"deprecationMessage": ""
|
|
48461
|
+
},
|
|
48462
|
+
{
|
|
48463
|
+
"name": "filePath",
|
|
48464
|
+
"type": "string",
|
|
48465
|
+
"deprecated": false,
|
|
48466
|
+
"deprecationMessage": ""
|
|
48467
|
+
},
|
|
48468
|
+
{
|
|
48469
|
+
"name": "tree",
|
|
48470
|
+
"type": "Tree",
|
|
48471
|
+
"deprecated": false,
|
|
48472
|
+
"deprecationMessage": ""
|
|
48473
|
+
}
|
|
48474
|
+
],
|
|
48475
|
+
"returnType": "Map<string, string>",
|
|
48476
|
+
"jsdoctags": [
|
|
48477
|
+
{
|
|
48478
|
+
"name": "sourceFile",
|
|
48479
|
+
"deprecated": false,
|
|
48480
|
+
"deprecationMessage": "",
|
|
48481
|
+
"tagName": {
|
|
48482
|
+
"text": "param"
|
|
48483
|
+
}
|
|
48484
|
+
},
|
|
48485
|
+
{
|
|
48486
|
+
"name": "source",
|
|
48487
|
+
"type": "string",
|
|
48488
|
+
"deprecated": false,
|
|
48489
|
+
"deprecationMessage": "",
|
|
48490
|
+
"tagName": {
|
|
48491
|
+
"text": "param"
|
|
48492
|
+
}
|
|
48493
|
+
},
|
|
48494
|
+
{
|
|
48495
|
+
"name": "filePath",
|
|
48496
|
+
"type": "string",
|
|
48497
|
+
"deprecated": false,
|
|
48498
|
+
"deprecationMessage": "",
|
|
48499
|
+
"tagName": {
|
|
48500
|
+
"text": "param"
|
|
48501
|
+
}
|
|
48502
|
+
},
|
|
48503
|
+
{
|
|
48504
|
+
"name": "tree",
|
|
48505
|
+
"type": "Tree",
|
|
48506
|
+
"deprecated": false,
|
|
48507
|
+
"deprecationMessage": "",
|
|
48508
|
+
"tagName": {
|
|
48509
|
+
"text": "param"
|
|
48510
|
+
}
|
|
48511
|
+
}
|
|
48512
|
+
]
|
|
48513
|
+
},
|
|
48514
|
+
{
|
|
48515
|
+
"name": "collectEuiReferences",
|
|
48516
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48517
|
+
"ctype": "miscellaneous",
|
|
48518
|
+
"subtype": "function",
|
|
48519
|
+
"coverageIgnore": false,
|
|
48520
|
+
"deprecated": false,
|
|
48521
|
+
"deprecationMessage": "",
|
|
48522
|
+
"rawdescription": "Scans the source file for class properties or variables typed as EUI component classes.\nReturns a map: localName → Set of signal property names.\n\nHandles:",
|
|
48523
|
+
"description": "<p>Scans the source file for class properties or variables typed as EUI component classes.\nReturns a map: localName → Set of signal property names.</p>\n<p>Handles:</p>\n",
|
|
48524
|
+
"displayName": "collectEuiReferences",
|
|
48525
|
+
"args": [
|
|
48526
|
+
{
|
|
48527
|
+
"name": "sourceFile",
|
|
48528
|
+
"deprecated": false,
|
|
48529
|
+
"deprecationMessage": ""
|
|
48530
|
+
},
|
|
48531
|
+
{
|
|
48532
|
+
"name": "source",
|
|
48533
|
+
"type": "string",
|
|
48534
|
+
"deprecated": false,
|
|
48535
|
+
"deprecationMessage": ""
|
|
48536
|
+
},
|
|
48537
|
+
{
|
|
48538
|
+
"name": "templateRefMap",
|
|
48539
|
+
"type": "Map",
|
|
48540
|
+
"deprecated": false,
|
|
48541
|
+
"deprecationMessage": ""
|
|
48542
|
+
}
|
|
48543
|
+
],
|
|
48544
|
+
"returnType": "Map<string, ReadonlySet<string>>",
|
|
48545
|
+
"jsdoctags": [
|
|
48546
|
+
{
|
|
48547
|
+
"name": "sourceFile",
|
|
48548
|
+
"deprecated": false,
|
|
48549
|
+
"deprecationMessage": "",
|
|
48550
|
+
"tagName": {
|
|
48551
|
+
"text": "param"
|
|
48552
|
+
}
|
|
48553
|
+
},
|
|
48554
|
+
{
|
|
48555
|
+
"name": "source",
|
|
48556
|
+
"type": "string",
|
|
48557
|
+
"deprecated": false,
|
|
48558
|
+
"deprecationMessage": "",
|
|
48559
|
+
"tagName": {
|
|
48560
|
+
"text": "param"
|
|
48561
|
+
}
|
|
48562
|
+
},
|
|
48563
|
+
{
|
|
48564
|
+
"name": "templateRefMap",
|
|
48565
|
+
"type": "Map",
|
|
48566
|
+
"deprecated": false,
|
|
48567
|
+
"deprecationMessage": "",
|
|
48568
|
+
"tagName": {
|
|
48569
|
+
"text": "param"
|
|
48570
|
+
}
|
|
48571
|
+
}
|
|
48572
|
+
]
|
|
48573
|
+
},
|
|
48574
|
+
{
|
|
48575
|
+
"name": "collectTemplateRefs",
|
|
48576
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48577
|
+
"ctype": "miscellaneous",
|
|
48578
|
+
"subtype": "function",
|
|
48579
|
+
"coverageIgnore": false,
|
|
48580
|
+
"deprecated": false,
|
|
48581
|
+
"deprecationMessage": "",
|
|
48582
|
+
"rawdescription": "Recursively walks template AST nodes, collecting #refName → EUI class name mappings.\n\nFor each element with a template reference (#ref), we try to resolve its EUI class:\n1. Match element tag name against EUI_SELECTOR_TO_CLASS (e.g. 'eui-alert' → EuiAlertComponent)\n2. Match element attributes against attribute selectors (e.g. [euiAutocomplete] → EuiAutocompleteComponent)",
|
|
48583
|
+
"description": "<p>Recursively walks template AST nodes, collecting #refName → EUI class name mappings.</p>\n<p>For each element with a template reference (#ref), we try to resolve its EUI class:</p>\n<ol>\n<li>Match element tag name against EUI_SELECTOR_TO_CLASS (e.g. 'eui-alert' → EuiAlertComponent)</li>\n<li>Match element attributes against attribute selectors (e.g. [euiAutocomplete] → EuiAutocompleteComponent)</li>\n</ol>\n",
|
|
48584
|
+
"displayName": "collectTemplateRefs",
|
|
48585
|
+
"args": [
|
|
48586
|
+
{
|
|
48587
|
+
"name": "nodes",
|
|
48588
|
+
"deprecated": false,
|
|
48589
|
+
"deprecationMessage": ""
|
|
48590
|
+
},
|
|
48591
|
+
{
|
|
48592
|
+
"name": "refMap",
|
|
48593
|
+
"type": "Map",
|
|
48594
|
+
"deprecated": false,
|
|
48595
|
+
"deprecationMessage": ""
|
|
48596
|
+
}
|
|
48597
|
+
],
|
|
48598
|
+
"returnType": "void",
|
|
48599
|
+
"jsdoctags": [
|
|
48600
|
+
{
|
|
48601
|
+
"name": "nodes",
|
|
48602
|
+
"deprecated": false,
|
|
48603
|
+
"deprecationMessage": "",
|
|
48604
|
+
"tagName": {
|
|
48605
|
+
"text": "param"
|
|
48606
|
+
}
|
|
48607
|
+
},
|
|
48608
|
+
{
|
|
48609
|
+
"name": "refMap",
|
|
48610
|
+
"type": "Map",
|
|
48611
|
+
"deprecated": false,
|
|
48612
|
+
"deprecationMessage": "",
|
|
48613
|
+
"tagName": {
|
|
48614
|
+
"text": "param"
|
|
48615
|
+
}
|
|
48616
|
+
}
|
|
48617
|
+
]
|
|
48618
|
+
},
|
|
48439
48619
|
{
|
|
48440
48620
|
"name": "deduplicateEdits",
|
|
48441
|
-
"file": "packages/core/schematics/migrate-
|
|
48621
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48442
48622
|
"ctype": "miscellaneous",
|
|
48443
48623
|
"subtype": "function",
|
|
48444
48624
|
"coverageIgnore": false,
|
|
@@ -48467,27 +48647,42 @@
|
|
|
48467
48647
|
]
|
|
48468
48648
|
},
|
|
48469
48649
|
{
|
|
48470
|
-
"name": "
|
|
48471
|
-
"file": "packages/core/schematics/migrate-
|
|
48650
|
+
"name": "findComponentMetadata",
|
|
48651
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48472
48652
|
"ctype": "miscellaneous",
|
|
48473
48653
|
"subtype": "function",
|
|
48474
48654
|
"coverageIgnore": false,
|
|
48475
48655
|
"deprecated": false,
|
|
48476
48656
|
"deprecationMessage": "",
|
|
48477
|
-
"rawdescription": "",
|
|
48478
|
-
"description": "",
|
|
48479
|
-
"displayName": "
|
|
48657
|
+
"rawdescription": "Extracts",
|
|
48658
|
+
"description": "<p>Extracts</p>\n",
|
|
48659
|
+
"displayName": "findComponentMetadata",
|
|
48480
48660
|
"args": [
|
|
48481
48661
|
{
|
|
48482
|
-
"name": "
|
|
48662
|
+
"name": "sourceFile",
|
|
48663
|
+
"deprecated": false,
|
|
48664
|
+
"deprecationMessage": ""
|
|
48665
|
+
},
|
|
48666
|
+
{
|
|
48667
|
+
"name": "source",
|
|
48668
|
+
"type": "string",
|
|
48483
48669
|
"deprecated": false,
|
|
48484
48670
|
"deprecationMessage": ""
|
|
48485
48671
|
}
|
|
48486
48672
|
],
|
|
48487
|
-
"returnType": "
|
|
48673
|
+
"returnType": "literal type | null",
|
|
48488
48674
|
"jsdoctags": [
|
|
48489
48675
|
{
|
|
48490
|
-
"name": "
|
|
48676
|
+
"name": "sourceFile",
|
|
48677
|
+
"deprecated": false,
|
|
48678
|
+
"deprecationMessage": "",
|
|
48679
|
+
"tagName": {
|
|
48680
|
+
"text": "param"
|
|
48681
|
+
}
|
|
48682
|
+
},
|
|
48683
|
+
{
|
|
48684
|
+
"name": "source",
|
|
48685
|
+
"type": "string",
|
|
48491
48686
|
"deprecated": false,
|
|
48492
48687
|
"deprecationMessage": "",
|
|
48493
48688
|
"tagName": {
|
|
@@ -48497,8 +48692,8 @@
|
|
|
48497
48692
|
]
|
|
48498
48693
|
},
|
|
48499
48694
|
{
|
|
48500
|
-
"name": "
|
|
48501
|
-
"file": "packages/core/schematics/migrate-
|
|
48695
|
+
"name": "getDecoratorName",
|
|
48696
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48502
48697
|
"ctype": "miscellaneous",
|
|
48503
48698
|
"subtype": "function",
|
|
48504
48699
|
"coverageIgnore": false,
|
|
@@ -48506,24 +48701,20 @@
|
|
|
48506
48701
|
"deprecationMessage": "",
|
|
48507
48702
|
"rawdescription": "",
|
|
48508
48703
|
"description": "",
|
|
48509
|
-
"displayName": "
|
|
48704
|
+
"displayName": "getDecoratorName",
|
|
48510
48705
|
"args": [
|
|
48511
48706
|
{
|
|
48512
|
-
"name": "
|
|
48513
|
-
"type": "Schema",
|
|
48707
|
+
"name": "callExpr",
|
|
48514
48708
|
"deprecated": false,
|
|
48515
|
-
"deprecationMessage": ""
|
|
48516
|
-
"defaultValue": "{}"
|
|
48709
|
+
"deprecationMessage": ""
|
|
48517
48710
|
}
|
|
48518
48711
|
],
|
|
48519
|
-
"returnType": "
|
|
48712
|
+
"returnType": "string | null",
|
|
48520
48713
|
"jsdoctags": [
|
|
48521
48714
|
{
|
|
48522
|
-
"name": "
|
|
48523
|
-
"type": "Schema",
|
|
48715
|
+
"name": "callExpr",
|
|
48524
48716
|
"deprecated": false,
|
|
48525
48717
|
"deprecationMessage": "",
|
|
48526
|
-
"defaultValue": "{}",
|
|
48527
48718
|
"tagName": {
|
|
48528
48719
|
"text": "param"
|
|
48529
48720
|
}
|
|
@@ -48531,8 +48722,8 @@
|
|
|
48531
48722
|
]
|
|
48532
48723
|
},
|
|
48533
48724
|
{
|
|
48534
|
-
"name": "
|
|
48535
|
-
"file": "packages/core/schematics/migrate-
|
|
48725
|
+
"name": "getTypeAnnotationName",
|
|
48726
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48536
48727
|
"ctype": "miscellaneous",
|
|
48537
48728
|
"subtype": "function",
|
|
48538
48729
|
"coverageIgnore": false,
|
|
@@ -48540,50 +48731,50 @@
|
|
|
48540
48731
|
"deprecationMessage": "",
|
|
48541
48732
|
"rawdescription": "",
|
|
48542
48733
|
"description": "",
|
|
48543
|
-
"displayName": "
|
|
48734
|
+
"displayName": "getTypeAnnotationName",
|
|
48544
48735
|
"args": [
|
|
48545
48736
|
{
|
|
48546
|
-
"name": "
|
|
48547
|
-
"type": "string",
|
|
48548
|
-
"deprecated": false,
|
|
48549
|
-
"deprecationMessage": ""
|
|
48550
|
-
},
|
|
48551
|
-
{
|
|
48552
|
-
"name": "filePath",
|
|
48553
|
-
"type": "string",
|
|
48554
|
-
"deprecated": false,
|
|
48555
|
-
"deprecationMessage": ""
|
|
48556
|
-
},
|
|
48557
|
-
{
|
|
48558
|
-
"name": "context",
|
|
48559
|
-
"type": "SchematicContext",
|
|
48737
|
+
"name": "typeNode",
|
|
48560
48738
|
"deprecated": false,
|
|
48561
48739
|
"deprecationMessage": ""
|
|
48562
48740
|
}
|
|
48563
48741
|
],
|
|
48564
|
-
"returnType": "string",
|
|
48742
|
+
"returnType": "string | null",
|
|
48565
48743
|
"jsdoctags": [
|
|
48566
48744
|
{
|
|
48567
|
-
"name": "
|
|
48568
|
-
"type": "string",
|
|
48745
|
+
"name": "typeNode",
|
|
48569
48746
|
"deprecated": false,
|
|
48570
48747
|
"deprecationMessage": "",
|
|
48571
48748
|
"tagName": {
|
|
48572
48749
|
"text": "param"
|
|
48573
48750
|
}
|
|
48574
|
-
}
|
|
48751
|
+
}
|
|
48752
|
+
]
|
|
48753
|
+
},
|
|
48754
|
+
{
|
|
48755
|
+
"name": "hasEuiReference",
|
|
48756
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48757
|
+
"ctype": "miscellaneous",
|
|
48758
|
+
"subtype": "function",
|
|
48759
|
+
"coverageIgnore": false,
|
|
48760
|
+
"deprecated": false,
|
|
48761
|
+
"deprecationMessage": "",
|
|
48762
|
+
"rawdescription": "Quick check: does the file reference any EUI class name from the signal map?",
|
|
48763
|
+
"description": "<p>Quick check: does the file reference any EUI class name from the signal map?</p>\n",
|
|
48764
|
+
"displayName": "hasEuiReference",
|
|
48765
|
+
"args": [
|
|
48575
48766
|
{
|
|
48576
|
-
"name": "
|
|
48767
|
+
"name": "source",
|
|
48577
48768
|
"type": "string",
|
|
48578
48769
|
"deprecated": false,
|
|
48579
|
-
"deprecationMessage": ""
|
|
48580
|
-
|
|
48581
|
-
|
|
48582
|
-
|
|
48583
|
-
|
|
48770
|
+
"deprecationMessage": ""
|
|
48771
|
+
}
|
|
48772
|
+
],
|
|
48773
|
+
"returnType": "boolean",
|
|
48774
|
+
"jsdoctags": [
|
|
48584
48775
|
{
|
|
48585
|
-
"name": "
|
|
48586
|
-
"type": "
|
|
48776
|
+
"name": "source",
|
|
48777
|
+
"type": "string",
|
|
48587
48778
|
"deprecated": false,
|
|
48588
48779
|
"deprecationMessage": "",
|
|
48589
48780
|
"tagName": {
|
|
@@ -48593,66 +48784,29 @@
|
|
|
48593
48784
|
]
|
|
48594
48785
|
},
|
|
48595
48786
|
{
|
|
48596
|
-
"name": "
|
|
48597
|
-
"file": "packages/core/schematics/migrate-
|
|
48787
|
+
"name": "hasStringRefQuery",
|
|
48788
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48598
48789
|
"ctype": "miscellaneous",
|
|
48599
48790
|
"subtype": "function",
|
|
48600
48791
|
"coverageIgnore": false,
|
|
48601
48792
|
"deprecated": false,
|
|
48602
48793
|
"deprecationMessage": "",
|
|
48603
|
-
"rawdescription": "",
|
|
48604
|
-
"description": "",
|
|
48605
|
-
"displayName": "
|
|
48794
|
+
"rawdescription": "Quick check: does the file have",
|
|
48795
|
+
"description": "<p>Quick check: does the file have</p>\n",
|
|
48796
|
+
"displayName": "hasStringRefQuery",
|
|
48606
48797
|
"args": [
|
|
48607
48798
|
{
|
|
48608
|
-
"name": "
|
|
48609
|
-
"
|
|
48610
|
-
"deprecationMessage": ""
|
|
48611
|
-
},
|
|
48612
|
-
{
|
|
48613
|
-
"name": "specifier",
|
|
48614
|
-
"deprecated": false,
|
|
48615
|
-
"deprecationMessage": ""
|
|
48616
|
-
},
|
|
48617
|
-
{
|
|
48618
|
-
"name": "sourceFile",
|
|
48619
|
-
"deprecated": false,
|
|
48620
|
-
"deprecationMessage": ""
|
|
48621
|
-
},
|
|
48622
|
-
{
|
|
48623
|
-
"name": "edits",
|
|
48799
|
+
"name": "source",
|
|
48800
|
+
"type": "string",
|
|
48624
48801
|
"deprecated": false,
|
|
48625
48802
|
"deprecationMessage": ""
|
|
48626
48803
|
}
|
|
48627
48804
|
],
|
|
48628
|
-
"returnType": "
|
|
48805
|
+
"returnType": "boolean",
|
|
48629
48806
|
"jsdoctags": [
|
|
48630
48807
|
{
|
|
48631
|
-
"name": "
|
|
48632
|
-
"
|
|
48633
|
-
"deprecationMessage": "",
|
|
48634
|
-
"tagName": {
|
|
48635
|
-
"text": "param"
|
|
48636
|
-
}
|
|
48637
|
-
},
|
|
48638
|
-
{
|
|
48639
|
-
"name": "specifier",
|
|
48640
|
-
"deprecated": false,
|
|
48641
|
-
"deprecationMessage": "",
|
|
48642
|
-
"tagName": {
|
|
48643
|
-
"text": "param"
|
|
48644
|
-
}
|
|
48645
|
-
},
|
|
48646
|
-
{
|
|
48647
|
-
"name": "sourceFile",
|
|
48648
|
-
"deprecated": false,
|
|
48649
|
-
"deprecationMessage": "",
|
|
48650
|
-
"tagName": {
|
|
48651
|
-
"text": "param"
|
|
48652
|
-
}
|
|
48653
|
-
},
|
|
48654
|
-
{
|
|
48655
|
-
"name": "edits",
|
|
48808
|
+
"name": "source",
|
|
48809
|
+
"type": "string",
|
|
48656
48810
|
"deprecated": false,
|
|
48657
48811
|
"deprecationMessage": "",
|
|
48658
48812
|
"tagName": {
|
|
@@ -48662,8 +48816,8 @@
|
|
|
48662
48816
|
]
|
|
48663
48817
|
},
|
|
48664
48818
|
{
|
|
48665
|
-
"name": "
|
|
48666
|
-
"file": "packages/core/schematics/migrate-
|
|
48819
|
+
"name": "isAssignmentOperator",
|
|
48820
|
+
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48667
48821
|
"ctype": "miscellaneous",
|
|
48668
48822
|
"subtype": "function",
|
|
48669
48823
|
"coverageIgnore": false,
|
|
@@ -48671,33 +48825,18 @@
|
|
|
48671
48825
|
"deprecationMessage": "",
|
|
48672
48826
|
"rawdescription": "",
|
|
48673
48827
|
"description": "",
|
|
48674
|
-
"displayName": "
|
|
48828
|
+
"displayName": "isAssignmentOperator",
|
|
48675
48829
|
"args": [
|
|
48676
48830
|
{
|
|
48677
|
-
"name": "
|
|
48678
|
-
"type": "DirEntry",
|
|
48679
|
-
"deprecated": false,
|
|
48680
|
-
"deprecationMessage": ""
|
|
48681
|
-
},
|
|
48682
|
-
{
|
|
48683
|
-
"name": "callback",
|
|
48831
|
+
"name": "kind",
|
|
48684
48832
|
"deprecated": false,
|
|
48685
48833
|
"deprecationMessage": ""
|
|
48686
48834
|
}
|
|
48687
48835
|
],
|
|
48688
|
-
"returnType": "
|
|
48836
|
+
"returnType": "boolean",
|
|
48689
48837
|
"jsdoctags": [
|
|
48690
48838
|
{
|
|
48691
|
-
"name": "
|
|
48692
|
-
"type": "DirEntry",
|
|
48693
|
-
"deprecated": false,
|
|
48694
|
-
"deprecationMessage": "",
|
|
48695
|
-
"tagName": {
|
|
48696
|
-
"text": "param"
|
|
48697
|
-
}
|
|
48698
|
-
},
|
|
48699
|
-
{
|
|
48700
|
-
"name": "callback",
|
|
48839
|
+
"name": "kind",
|
|
48701
48840
|
"deprecated": false,
|
|
48702
48841
|
"deprecationMessage": "",
|
|
48703
48842
|
"tagName": {
|
|
@@ -48705,48 +48844,35 @@
|
|
|
48705
48844
|
}
|
|
48706
48845
|
}
|
|
48707
48846
|
]
|
|
48708
|
-
}
|
|
48709
|
-
],
|
|
48710
|
-
"packages/core/schematics/migrate-to-signals/index.ts": [
|
|
48847
|
+
},
|
|
48711
48848
|
{
|
|
48712
|
-
"name": "
|
|
48849
|
+
"name": "migrateToSignals",
|
|
48713
48850
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48714
48851
|
"ctype": "miscellaneous",
|
|
48715
48852
|
"subtype": "function",
|
|
48716
48853
|
"coverageIgnore": false,
|
|
48717
48854
|
"deprecated": false,
|
|
48718
48855
|
"deprecationMessage": "",
|
|
48719
|
-
"rawdescription": "",
|
|
48720
|
-
"description": "",
|
|
48721
|
-
"displayName": "
|
|
48856
|
+
"rawdescription": "Migrates consumer code that accesses EUI component instances programmatically.\n\nWhen EUI migrated",
|
|
48857
|
+
"description": "<p>Migrates consumer code that accesses EUI component instances programmatically.</p>\n<p>When EUI migrated</p>\n",
|
|
48858
|
+
"displayName": "migrateToSignals",
|
|
48722
48859
|
"args": [
|
|
48723
48860
|
{
|
|
48724
|
-
"name": "
|
|
48725
|
-
"type": "
|
|
48726
|
-
"deprecated": false,
|
|
48727
|
-
"deprecationMessage": ""
|
|
48728
|
-
},
|
|
48729
|
-
{
|
|
48730
|
-
"name": "edits",
|
|
48861
|
+
"name": "options",
|
|
48862
|
+
"type": "Schema",
|
|
48731
48863
|
"deprecated": false,
|
|
48732
|
-
"deprecationMessage": ""
|
|
48864
|
+
"deprecationMessage": "",
|
|
48865
|
+
"defaultValue": "{}"
|
|
48733
48866
|
}
|
|
48734
48867
|
],
|
|
48735
|
-
"returnType": "
|
|
48868
|
+
"returnType": "Rule",
|
|
48736
48869
|
"jsdoctags": [
|
|
48737
48870
|
{
|
|
48738
|
-
"name": "
|
|
48739
|
-
"type": "
|
|
48740
|
-
"deprecated": false,
|
|
48741
|
-
"deprecationMessage": "",
|
|
48742
|
-
"tagName": {
|
|
48743
|
-
"text": "param"
|
|
48744
|
-
}
|
|
48745
|
-
},
|
|
48746
|
-
{
|
|
48747
|
-
"name": "edits",
|
|
48871
|
+
"name": "options",
|
|
48872
|
+
"type": "Schema",
|
|
48748
48873
|
"deprecated": false,
|
|
48749
48874
|
"deprecationMessage": "",
|
|
48875
|
+
"defaultValue": "{}",
|
|
48750
48876
|
"tagName": {
|
|
48751
48877
|
"text": "param"
|
|
48752
48878
|
}
|
|
@@ -48754,22 +48880,17 @@
|
|
|
48754
48880
|
]
|
|
48755
48881
|
},
|
|
48756
48882
|
{
|
|
48757
|
-
"name": "
|
|
48883
|
+
"name": "migrateTypeScript",
|
|
48758
48884
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48759
48885
|
"ctype": "miscellaneous",
|
|
48760
48886
|
"subtype": "function",
|
|
48761
48887
|
"coverageIgnore": false,
|
|
48762
48888
|
"deprecated": false,
|
|
48763
48889
|
"deprecationMessage": "",
|
|
48764
|
-
"rawdescription": "
|
|
48765
|
-
"description": "
|
|
48766
|
-
"displayName": "
|
|
48890
|
+
"rawdescription": "",
|
|
48891
|
+
"description": "",
|
|
48892
|
+
"displayName": "migrateTypeScript",
|
|
48767
48893
|
"args": [
|
|
48768
|
-
{
|
|
48769
|
-
"name": "sourceFile",
|
|
48770
|
-
"deprecated": false,
|
|
48771
|
-
"deprecationMessage": ""
|
|
48772
|
-
},
|
|
48773
48894
|
{
|
|
48774
48895
|
"name": "source",
|
|
48775
48896
|
"type": "string",
|
|
@@ -48787,12 +48908,19 @@
|
|
|
48787
48908
|
"type": "Tree",
|
|
48788
48909
|
"deprecated": false,
|
|
48789
48910
|
"deprecationMessage": ""
|
|
48911
|
+
},
|
|
48912
|
+
{
|
|
48913
|
+
"name": "context",
|
|
48914
|
+
"type": "SchematicContext",
|
|
48915
|
+
"deprecated": false,
|
|
48916
|
+
"deprecationMessage": ""
|
|
48790
48917
|
}
|
|
48791
48918
|
],
|
|
48792
|
-
"returnType": "
|
|
48919
|
+
"returnType": "MigrateResult",
|
|
48793
48920
|
"jsdoctags": [
|
|
48794
48921
|
{
|
|
48795
|
-
"name": "
|
|
48922
|
+
"name": "source",
|
|
48923
|
+
"type": "string",
|
|
48796
48924
|
"deprecated": false,
|
|
48797
48925
|
"deprecationMessage": "",
|
|
48798
48926
|
"tagName": {
|
|
@@ -48800,7 +48928,7 @@
|
|
|
48800
48928
|
}
|
|
48801
48929
|
},
|
|
48802
48930
|
{
|
|
48803
|
-
"name": "
|
|
48931
|
+
"name": "filePath",
|
|
48804
48932
|
"type": "string",
|
|
48805
48933
|
"deprecated": false,
|
|
48806
48934
|
"deprecationMessage": "",
|
|
@@ -48809,8 +48937,8 @@
|
|
|
48809
48937
|
}
|
|
48810
48938
|
},
|
|
48811
48939
|
{
|
|
48812
|
-
"name": "
|
|
48813
|
-
"type": "
|
|
48940
|
+
"name": "tree",
|
|
48941
|
+
"type": "Tree",
|
|
48814
48942
|
"deprecated": false,
|
|
48815
48943
|
"deprecationMessage": "",
|
|
48816
48944
|
"tagName": {
|
|
@@ -48818,8 +48946,8 @@
|
|
|
48818
48946
|
}
|
|
48819
48947
|
},
|
|
48820
48948
|
{
|
|
48821
|
-
"name": "
|
|
48822
|
-
"type": "
|
|
48949
|
+
"name": "context",
|
|
48950
|
+
"type": "SchematicContext",
|
|
48823
48951
|
"deprecated": false,
|
|
48824
48952
|
"deprecationMessage": "",
|
|
48825
48953
|
"tagName": {
|
|
@@ -48829,57 +48957,29 @@
|
|
|
48829
48957
|
]
|
|
48830
48958
|
},
|
|
48831
48959
|
{
|
|
48832
|
-
"name": "
|
|
48960
|
+
"name": "resolveElementToEuiClass",
|
|
48833
48961
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48834
48962
|
"ctype": "miscellaneous",
|
|
48835
48963
|
"subtype": "function",
|
|
48836
48964
|
"coverageIgnore": false,
|
|
48837
48965
|
"deprecated": false,
|
|
48838
48966
|
"deprecationMessage": "",
|
|
48839
|
-
"rawdescription": "
|
|
48840
|
-
"description": "<p>
|
|
48841
|
-
"displayName": "
|
|
48967
|
+
"rawdescription": "Given a template element, resolves it to an EUI class name by checking:\n1. Tag name: <eui-alert> → look up 'eui-alert' in EUI_SELECTOR_TO_CLASS\n2. Attribute selectors: <input euiAutocomplete> → look up 'input[euiAutocomplete]' or '[euiAutocomplete]'",
|
|
48968
|
+
"description": "<p>Given a template element, resolves it to an EUI class name by checking:</p>\n<ol>\n<li>Tag name: <eui-alert> → look up 'eui-alert' in EUI_SELECTOR_TO_CLASS</li>\n<li>Attribute selectors: <input euiAutocomplete> → look up 'input[euiAutocomplete]' or '[euiAutocomplete]'</li>\n</ol>\n",
|
|
48969
|
+
"displayName": "resolveElementToEuiClass",
|
|
48842
48970
|
"args": [
|
|
48843
48971
|
{
|
|
48844
|
-
"name": "
|
|
48845
|
-
"
|
|
48846
|
-
"deprecationMessage": ""
|
|
48847
|
-
},
|
|
48848
|
-
{
|
|
48849
|
-
"name": "source",
|
|
48850
|
-
"type": "string",
|
|
48851
|
-
"deprecated": false,
|
|
48852
|
-
"deprecationMessage": ""
|
|
48853
|
-
},
|
|
48854
|
-
{
|
|
48855
|
-
"name": "templateRefMap",
|
|
48856
|
-
"type": "Map",
|
|
48972
|
+
"name": "element",
|
|
48973
|
+
"type": "TmplAstElement",
|
|
48857
48974
|
"deprecated": false,
|
|
48858
48975
|
"deprecationMessage": ""
|
|
48859
48976
|
}
|
|
48860
48977
|
],
|
|
48861
|
-
"returnType": "
|
|
48978
|
+
"returnType": "string | null",
|
|
48862
48979
|
"jsdoctags": [
|
|
48863
48980
|
{
|
|
48864
|
-
"name": "
|
|
48865
|
-
"
|
|
48866
|
-
"deprecationMessage": "",
|
|
48867
|
-
"tagName": {
|
|
48868
|
-
"text": "param"
|
|
48869
|
-
}
|
|
48870
|
-
},
|
|
48871
|
-
{
|
|
48872
|
-
"name": "source",
|
|
48873
|
-
"type": "string",
|
|
48874
|
-
"deprecated": false,
|
|
48875
|
-
"deprecationMessage": "",
|
|
48876
|
-
"tagName": {
|
|
48877
|
-
"text": "param"
|
|
48878
|
-
}
|
|
48879
|
-
},
|
|
48880
|
-
{
|
|
48881
|
-
"name": "templateRefMap",
|
|
48882
|
-
"type": "Map",
|
|
48981
|
+
"name": "element",
|
|
48982
|
+
"type": "TmplAstElement",
|
|
48883
48983
|
"deprecated": false,
|
|
48884
48984
|
"deprecationMessage": "",
|
|
48885
48985
|
"tagName": {
|
|
@@ -48889,33 +48989,38 @@
|
|
|
48889
48989
|
]
|
|
48890
48990
|
},
|
|
48891
48991
|
{
|
|
48892
|
-
"name": "
|
|
48992
|
+
"name": "resolveEuiClassName",
|
|
48893
48993
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48894
48994
|
"ctype": "miscellaneous",
|
|
48895
48995
|
"subtype": "function",
|
|
48896
48996
|
"coverageIgnore": false,
|
|
48897
48997
|
"deprecated": false,
|
|
48898
48998
|
"deprecationMessage": "",
|
|
48899
|
-
"rawdescription": "
|
|
48900
|
-
"description": "<p>
|
|
48901
|
-
"displayName": "
|
|
48999
|
+
"rawdescription": "Resolves the EUI class name from a property declaration.\nChecks: type annotation → decorator class argument → template ref map.",
|
|
49000
|
+
"description": "<p>Resolves the EUI class name from a property declaration.\nChecks: type annotation → decorator class argument → template ref map.</p>\n",
|
|
49001
|
+
"displayName": "resolveEuiClassName",
|
|
48902
49002
|
"args": [
|
|
48903
49003
|
{
|
|
48904
|
-
"name": "
|
|
49004
|
+
"name": "node",
|
|
48905
49005
|
"deprecated": false,
|
|
48906
49006
|
"deprecationMessage": ""
|
|
48907
49007
|
},
|
|
48908
49008
|
{
|
|
48909
|
-
"name": "
|
|
49009
|
+
"name": "sourceFile",
|
|
49010
|
+
"deprecated": false,
|
|
49011
|
+
"deprecationMessage": ""
|
|
49012
|
+
},
|
|
49013
|
+
{
|
|
49014
|
+
"name": "templateRefMap",
|
|
48910
49015
|
"type": "Map",
|
|
48911
49016
|
"deprecated": false,
|
|
48912
49017
|
"deprecationMessage": ""
|
|
48913
49018
|
}
|
|
48914
49019
|
],
|
|
48915
|
-
"returnType": "
|
|
49020
|
+
"returnType": "string | null",
|
|
48916
49021
|
"jsdoctags": [
|
|
48917
49022
|
{
|
|
48918
|
-
"name": "
|
|
49023
|
+
"name": "node",
|
|
48919
49024
|
"deprecated": false,
|
|
48920
49025
|
"deprecationMessage": "",
|
|
48921
49026
|
"tagName": {
|
|
@@ -48923,7 +49028,15 @@
|
|
|
48923
49028
|
}
|
|
48924
49029
|
},
|
|
48925
49030
|
{
|
|
48926
|
-
"name": "
|
|
49031
|
+
"name": "sourceFile",
|
|
49032
|
+
"deprecated": false,
|
|
49033
|
+
"deprecationMessage": "",
|
|
49034
|
+
"tagName": {
|
|
49035
|
+
"text": "param"
|
|
49036
|
+
}
|
|
49037
|
+
},
|
|
49038
|
+
{
|
|
49039
|
+
"name": "templateRefMap",
|
|
48927
49040
|
"type": "Map",
|
|
48928
49041
|
"deprecated": false,
|
|
48929
49042
|
"deprecationMessage": "",
|
|
@@ -48934,27 +49047,27 @@
|
|
|
48934
49047
|
]
|
|
48935
49048
|
},
|
|
48936
49049
|
{
|
|
48937
|
-
"name": "
|
|
49050
|
+
"name": "resolveRefName",
|
|
48938
49051
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48939
49052
|
"ctype": "miscellaneous",
|
|
48940
49053
|
"subtype": "function",
|
|
48941
49054
|
"coverageIgnore": false,
|
|
48942
49055
|
"deprecated": false,
|
|
48943
49056
|
"deprecationMessage": "",
|
|
48944
|
-
"rawdescription": "",
|
|
48945
|
-
"description": "",
|
|
48946
|
-
"displayName": "
|
|
49057
|
+
"rawdescription": "Resolves a reference name from an expression.\nHandles: `ref`, `this.ref`, `this._ref`",
|
|
49058
|
+
"description": "<p>Resolves a reference name from an expression.\nHandles: <code>ref</code>, <code>this.ref</code>, <code>this._ref</code></p>\n",
|
|
49059
|
+
"displayName": "resolveRefName",
|
|
48947
49060
|
"args": [
|
|
48948
49061
|
{
|
|
48949
|
-
"name": "
|
|
49062
|
+
"name": "expr",
|
|
48950
49063
|
"deprecated": false,
|
|
48951
49064
|
"deprecationMessage": ""
|
|
48952
49065
|
}
|
|
48953
49066
|
],
|
|
48954
|
-
"returnType": "
|
|
49067
|
+
"returnType": "string | null",
|
|
48955
49068
|
"jsdoctags": [
|
|
48956
49069
|
{
|
|
48957
|
-
"name": "
|
|
49070
|
+
"name": "expr",
|
|
48958
49071
|
"deprecated": false,
|
|
48959
49072
|
"deprecationMessage": "",
|
|
48960
49073
|
"tagName": {
|
|
@@ -48964,17 +49077,28 @@
|
|
|
48964
49077
|
]
|
|
48965
49078
|
},
|
|
48966
49079
|
{
|
|
48967
|
-
"name": "
|
|
49080
|
+
"name": "tryRewritePropertyAccess",
|
|
48968
49081
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
48969
49082
|
"ctype": "miscellaneous",
|
|
48970
49083
|
"subtype": "function",
|
|
48971
49084
|
"coverageIgnore": false,
|
|
48972
49085
|
"deprecated": false,
|
|
48973
49086
|
"deprecationMessage": "",
|
|
48974
|
-
"rawdescription": "
|
|
48975
|
-
"description": "<p>
|
|
48976
|
-
"displayName": "
|
|
49087
|
+
"rawdescription": "Checks if a property access `ref.prop` should be rewritten to `ref.prop()`.\n\nWe 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)",
|
|
49088
|
+
"description": "<p>Checks if a property access <code>ref.prop</code> should be rewritten to <code>ref.prop()</code>.</p>\n<p>We rewrite if:</p>\n<ul>\n<li><code>ref</code> is tracked in euiRefs</li>\n<li><code>prop</code> is in the signal set for that EUI class</li>\n<li>The access is NOT already a call expression (not <code>ref.prop()</code> or <code>ref.prop(args)</code>)</li>\n<li>The access is NOT a write target (not <code>ref.prop = value</code>)</li>\n<li>The access is NOT a template binding argument (those are unaffected)</li>\n</ul>\n",
|
|
49089
|
+
"displayName": "tryRewritePropertyAccess",
|
|
48977
49090
|
"args": [
|
|
49091
|
+
{
|
|
49092
|
+
"name": "node",
|
|
49093
|
+
"deprecated": false,
|
|
49094
|
+
"deprecationMessage": ""
|
|
49095
|
+
},
|
|
49096
|
+
{
|
|
49097
|
+
"name": "euiRefs",
|
|
49098
|
+
"type": "Map",
|
|
49099
|
+
"deprecated": false,
|
|
49100
|
+
"deprecationMessage": ""
|
|
49101
|
+
},
|
|
48978
49102
|
{
|
|
48979
49103
|
"name": "sourceFile",
|
|
48980
49104
|
"deprecated": false,
|
|
@@ -48987,8 +49111,25 @@
|
|
|
48987
49111
|
"deprecationMessage": ""
|
|
48988
49112
|
}
|
|
48989
49113
|
],
|
|
48990
|
-
"returnType": "
|
|
49114
|
+
"returnType": "Edit | null",
|
|
48991
49115
|
"jsdoctags": [
|
|
49116
|
+
{
|
|
49117
|
+
"name": "node",
|
|
49118
|
+
"deprecated": false,
|
|
49119
|
+
"deprecationMessage": "",
|
|
49120
|
+
"tagName": {
|
|
49121
|
+
"text": "param"
|
|
49122
|
+
}
|
|
49123
|
+
},
|
|
49124
|
+
{
|
|
49125
|
+
"name": "euiRefs",
|
|
49126
|
+
"type": "Map",
|
|
49127
|
+
"deprecated": false,
|
|
49128
|
+
"deprecationMessage": "",
|
|
49129
|
+
"tagName": {
|
|
49130
|
+
"text": "param"
|
|
49131
|
+
}
|
|
49132
|
+
},
|
|
48992
49133
|
{
|
|
48993
49134
|
"name": "sourceFile",
|
|
48994
49135
|
"deprecated": false,
|
|
@@ -49009,7 +49150,7 @@
|
|
|
49009
49150
|
]
|
|
49010
49151
|
},
|
|
49011
49152
|
{
|
|
49012
|
-
"name": "
|
|
49153
|
+
"name": "unwrapExpression",
|
|
49013
49154
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
49014
49155
|
"ctype": "miscellaneous",
|
|
49015
49156
|
"subtype": "function",
|
|
@@ -49018,18 +49159,18 @@
|
|
|
49018
49159
|
"deprecationMessage": "",
|
|
49019
49160
|
"rawdescription": "",
|
|
49020
49161
|
"description": "",
|
|
49021
|
-
"displayName": "
|
|
49162
|
+
"displayName": "unwrapExpression",
|
|
49022
49163
|
"args": [
|
|
49023
49164
|
{
|
|
49024
|
-
"name": "
|
|
49165
|
+
"name": "expression",
|
|
49025
49166
|
"deprecated": false,
|
|
49026
49167
|
"deprecationMessage": ""
|
|
49027
49168
|
}
|
|
49028
49169
|
],
|
|
49029
|
-
"returnType": "
|
|
49170
|
+
"returnType": "ts.Expression",
|
|
49030
49171
|
"jsdoctags": [
|
|
49031
49172
|
{
|
|
49032
|
-
"name": "
|
|
49173
|
+
"name": "expression",
|
|
49033
49174
|
"deprecated": false,
|
|
49034
49175
|
"deprecationMessage": "",
|
|
49035
49176
|
"tagName": {
|
|
@@ -49039,7 +49180,7 @@
|
|
|
49039
49180
|
]
|
|
49040
49181
|
},
|
|
49041
49182
|
{
|
|
49042
|
-
"name": "
|
|
49183
|
+
"name": "visitDir",
|
|
49043
49184
|
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
49044
49185
|
"ctype": "miscellaneous",
|
|
49045
49186
|
"subtype": "function",
|
|
@@ -49048,18 +49189,33 @@
|
|
|
49048
49189
|
"deprecationMessage": "",
|
|
49049
49190
|
"rawdescription": "",
|
|
49050
49191
|
"description": "",
|
|
49051
|
-
"displayName": "
|
|
49192
|
+
"displayName": "visitDir",
|
|
49052
49193
|
"args": [
|
|
49053
49194
|
{
|
|
49054
|
-
"name": "
|
|
49195
|
+
"name": "dir",
|
|
49196
|
+
"type": "DirEntry",
|
|
49197
|
+
"deprecated": false,
|
|
49198
|
+
"deprecationMessage": ""
|
|
49199
|
+
},
|
|
49200
|
+
{
|
|
49201
|
+
"name": "callback",
|
|
49055
49202
|
"deprecated": false,
|
|
49056
49203
|
"deprecationMessage": ""
|
|
49057
49204
|
}
|
|
49058
49205
|
],
|
|
49059
|
-
"returnType": "
|
|
49206
|
+
"returnType": "void",
|
|
49060
49207
|
"jsdoctags": [
|
|
49061
49208
|
{
|
|
49062
|
-
"name": "
|
|
49209
|
+
"name": "dir",
|
|
49210
|
+
"type": "DirEntry",
|
|
49211
|
+
"deprecated": false,
|
|
49212
|
+
"deprecationMessage": "",
|
|
49213
|
+
"tagName": {
|
|
49214
|
+
"text": "param"
|
|
49215
|
+
}
|
|
49216
|
+
},
|
|
49217
|
+
{
|
|
49218
|
+
"name": "callback",
|
|
49063
49219
|
"deprecated": false,
|
|
49064
49220
|
"deprecationMessage": "",
|
|
49065
49221
|
"tagName": {
|
|
@@ -49067,27 +49223,34 @@
|
|
|
49067
49223
|
}
|
|
49068
49224
|
}
|
|
49069
49225
|
]
|
|
49070
|
-
}
|
|
49226
|
+
}
|
|
49227
|
+
],
|
|
49228
|
+
"packages/core/schematics/migrate-eui-tooltip/index.ts": [
|
|
49071
49229
|
{
|
|
49072
|
-
"name": "
|
|
49073
|
-
"file": "packages/core/schematics/migrate-
|
|
49230
|
+
"name": "applyEdits",
|
|
49231
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
49074
49232
|
"ctype": "miscellaneous",
|
|
49075
49233
|
"subtype": "function",
|
|
49076
49234
|
"coverageIgnore": false,
|
|
49077
49235
|
"deprecated": false,
|
|
49078
49236
|
"deprecationMessage": "",
|
|
49079
|
-
"rawdescription": "
|
|
49080
|
-
"description": "
|
|
49081
|
-
"displayName": "
|
|
49237
|
+
"rawdescription": "",
|
|
49238
|
+
"description": "",
|
|
49239
|
+
"displayName": "applyEdits",
|
|
49082
49240
|
"args": [
|
|
49083
49241
|
{
|
|
49084
49242
|
"name": "source",
|
|
49085
49243
|
"type": "string",
|
|
49086
49244
|
"deprecated": false,
|
|
49087
49245
|
"deprecationMessage": ""
|
|
49246
|
+
},
|
|
49247
|
+
{
|
|
49248
|
+
"name": "edits",
|
|
49249
|
+
"deprecated": false,
|
|
49250
|
+
"deprecationMessage": ""
|
|
49088
49251
|
}
|
|
49089
49252
|
],
|
|
49090
|
-
"returnType": "
|
|
49253
|
+
"returnType": "string",
|
|
49091
49254
|
"jsdoctags": [
|
|
49092
49255
|
{
|
|
49093
49256
|
"name": "source",
|
|
@@ -49097,33 +49260,39 @@
|
|
|
49097
49260
|
"tagName": {
|
|
49098
49261
|
"text": "param"
|
|
49099
49262
|
}
|
|
49263
|
+
},
|
|
49264
|
+
{
|
|
49265
|
+
"name": "edits",
|
|
49266
|
+
"deprecated": false,
|
|
49267
|
+
"deprecationMessage": "",
|
|
49268
|
+
"tagName": {
|
|
49269
|
+
"text": "param"
|
|
49270
|
+
}
|
|
49100
49271
|
}
|
|
49101
49272
|
]
|
|
49102
49273
|
},
|
|
49103
49274
|
{
|
|
49104
|
-
"name": "
|
|
49105
|
-
"file": "packages/core/schematics/migrate-
|
|
49275
|
+
"name": "deduplicateEdits",
|
|
49276
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
49106
49277
|
"ctype": "miscellaneous",
|
|
49107
49278
|
"subtype": "function",
|
|
49108
49279
|
"coverageIgnore": false,
|
|
49109
49280
|
"deprecated": false,
|
|
49110
49281
|
"deprecationMessage": "",
|
|
49111
|
-
"rawdescription": "
|
|
49112
|
-
"description": "
|
|
49113
|
-
"displayName": "
|
|
49282
|
+
"rawdescription": "",
|
|
49283
|
+
"description": "",
|
|
49284
|
+
"displayName": "deduplicateEdits",
|
|
49114
49285
|
"args": [
|
|
49115
49286
|
{
|
|
49116
|
-
"name": "
|
|
49117
|
-
"type": "string",
|
|
49287
|
+
"name": "edits",
|
|
49118
49288
|
"deprecated": false,
|
|
49119
49289
|
"deprecationMessage": ""
|
|
49120
49290
|
}
|
|
49121
49291
|
],
|
|
49122
|
-
"returnType": "
|
|
49292
|
+
"returnType": "Edit[]",
|
|
49123
49293
|
"jsdoctags": [
|
|
49124
49294
|
{
|
|
49125
|
-
"name": "
|
|
49126
|
-
"type": "string",
|
|
49295
|
+
"name": "edits",
|
|
49127
49296
|
"deprecated": false,
|
|
49128
49297
|
"deprecationMessage": "",
|
|
49129
49298
|
"tagName": {
|
|
@@ -49133,8 +49302,8 @@
|
|
|
49133
49302
|
]
|
|
49134
49303
|
},
|
|
49135
49304
|
{
|
|
49136
|
-
"name": "
|
|
49137
|
-
"file": "packages/core/schematics/migrate-
|
|
49305
|
+
"name": "isPartOfImport",
|
|
49306
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
49138
49307
|
"ctype": "miscellaneous",
|
|
49139
49308
|
"subtype": "function",
|
|
49140
49309
|
"coverageIgnore": false,
|
|
@@ -49142,10 +49311,10 @@
|
|
|
49142
49311
|
"deprecationMessage": "",
|
|
49143
49312
|
"rawdescription": "",
|
|
49144
49313
|
"description": "",
|
|
49145
|
-
"displayName": "
|
|
49314
|
+
"displayName": "isPartOfImport",
|
|
49146
49315
|
"args": [
|
|
49147
49316
|
{
|
|
49148
|
-
"name": "
|
|
49317
|
+
"name": "node",
|
|
49149
49318
|
"deprecated": false,
|
|
49150
49319
|
"deprecationMessage": ""
|
|
49151
49320
|
}
|
|
@@ -49153,7 +49322,7 @@
|
|
|
49153
49322
|
"returnType": "boolean",
|
|
49154
49323
|
"jsdoctags": [
|
|
49155
49324
|
{
|
|
49156
|
-
"name": "
|
|
49325
|
+
"name": "node",
|
|
49157
49326
|
"deprecated": false,
|
|
49158
49327
|
"deprecationMessage": "",
|
|
49159
49328
|
"tagName": {
|
|
@@ -49163,16 +49332,16 @@
|
|
|
49163
49332
|
]
|
|
49164
49333
|
},
|
|
49165
49334
|
{
|
|
49166
|
-
"name": "
|
|
49167
|
-
"file": "packages/core/schematics/migrate-
|
|
49335
|
+
"name": "migrateEuiTooltip",
|
|
49336
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
49168
49337
|
"ctype": "miscellaneous",
|
|
49169
49338
|
"subtype": "function",
|
|
49170
49339
|
"coverageIgnore": false,
|
|
49171
49340
|
"deprecated": false,
|
|
49172
49341
|
"deprecationMessage": "",
|
|
49173
|
-
"rawdescription": "
|
|
49174
|
-
"description": "
|
|
49175
|
-
"displayName": "
|
|
49342
|
+
"rawdescription": "",
|
|
49343
|
+
"description": "",
|
|
49344
|
+
"displayName": "migrateEuiTooltip",
|
|
49176
49345
|
"args": [
|
|
49177
49346
|
{
|
|
49178
49347
|
"name": "options",
|
|
@@ -49198,7 +49367,7 @@
|
|
|
49198
49367
|
},
|
|
49199
49368
|
{
|
|
49200
49369
|
"name": "migrateTypeScript",
|
|
49201
|
-
"file": "packages/core/schematics/migrate-
|
|
49370
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
49202
49371
|
"ctype": "miscellaneous",
|
|
49203
49372
|
"subtype": "function",
|
|
49204
49373
|
"coverageIgnore": false,
|
|
@@ -49220,12 +49389,6 @@
|
|
|
49220
49389
|
"deprecated": false,
|
|
49221
49390
|
"deprecationMessage": ""
|
|
49222
49391
|
},
|
|
49223
|
-
{
|
|
49224
|
-
"name": "tree",
|
|
49225
|
-
"type": "Tree",
|
|
49226
|
-
"deprecated": false,
|
|
49227
|
-
"deprecationMessage": ""
|
|
49228
|
-
},
|
|
49229
49392
|
{
|
|
49230
49393
|
"name": "context",
|
|
49231
49394
|
"type": "SchematicContext",
|
|
@@ -49233,7 +49396,7 @@
|
|
|
49233
49396
|
"deprecationMessage": ""
|
|
49234
49397
|
}
|
|
49235
49398
|
],
|
|
49236
|
-
"returnType": "
|
|
49399
|
+
"returnType": "string",
|
|
49237
49400
|
"jsdoctags": [
|
|
49238
49401
|
{
|
|
49239
49402
|
"name": "source",
|
|
@@ -49253,15 +49416,6 @@
|
|
|
49253
49416
|
"text": "param"
|
|
49254
49417
|
}
|
|
49255
49418
|
},
|
|
49256
|
-
{
|
|
49257
|
-
"name": "tree",
|
|
49258
|
-
"type": "Tree",
|
|
49259
|
-
"deprecated": false,
|
|
49260
|
-
"deprecationMessage": "",
|
|
49261
|
-
"tagName": {
|
|
49262
|
-
"text": "param"
|
|
49263
|
-
}
|
|
49264
|
-
},
|
|
49265
49419
|
{
|
|
49266
49420
|
"name": "context",
|
|
49267
49421
|
"type": "SchematicContext",
|
|
@@ -49274,145 +49428,24 @@
|
|
|
49274
49428
|
]
|
|
49275
49429
|
},
|
|
49276
49430
|
{
|
|
49277
|
-
"name": "
|
|
49278
|
-
"file": "packages/core/schematics/migrate-
|
|
49279
|
-
"ctype": "miscellaneous",
|
|
49280
|
-
"subtype": "function",
|
|
49281
|
-
"coverageIgnore": false,
|
|
49282
|
-
"deprecated": false,
|
|
49283
|
-
"deprecationMessage": "",
|
|
49284
|
-
"rawdescription": "Given a template element, resolves it to an EUI class name by checking:\n1. Tag name: <eui-alert> → look up 'eui-alert' in EUI_SELECTOR_TO_CLASS\n2. Attribute selectors: <input euiAutocomplete> → look up 'input[euiAutocomplete]' or '[euiAutocomplete]'",
|
|
49285
|
-
"description": "<p>Given a template element, resolves it to an EUI class name by checking:</p>\n<ol>\n<li>Tag name: <eui-alert> → look up 'eui-alert' in EUI_SELECTOR_TO_CLASS</li>\n<li>Attribute selectors: <input euiAutocomplete> → look up 'input[euiAutocomplete]' or '[euiAutocomplete]'</li>\n</ol>\n",
|
|
49286
|
-
"displayName": "resolveElementToEuiClass",
|
|
49287
|
-
"args": [
|
|
49288
|
-
{
|
|
49289
|
-
"name": "element",
|
|
49290
|
-
"type": "TmplAstElement",
|
|
49291
|
-
"deprecated": false,
|
|
49292
|
-
"deprecationMessage": ""
|
|
49293
|
-
}
|
|
49294
|
-
],
|
|
49295
|
-
"returnType": "string | null",
|
|
49296
|
-
"jsdoctags": [
|
|
49297
|
-
{
|
|
49298
|
-
"name": "element",
|
|
49299
|
-
"type": "TmplAstElement",
|
|
49300
|
-
"deprecated": false,
|
|
49301
|
-
"deprecationMessage": "",
|
|
49302
|
-
"tagName": {
|
|
49303
|
-
"text": "param"
|
|
49304
|
-
}
|
|
49305
|
-
}
|
|
49306
|
-
]
|
|
49307
|
-
},
|
|
49308
|
-
{
|
|
49309
|
-
"name": "resolveEuiClassName",
|
|
49310
|
-
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
49311
|
-
"ctype": "miscellaneous",
|
|
49312
|
-
"subtype": "function",
|
|
49313
|
-
"coverageIgnore": false,
|
|
49314
|
-
"deprecated": false,
|
|
49315
|
-
"deprecationMessage": "",
|
|
49316
|
-
"rawdescription": "Resolves the EUI class name from a property declaration.\nChecks: type annotation → decorator class argument → template ref map.",
|
|
49317
|
-
"description": "<p>Resolves the EUI class name from a property declaration.\nChecks: type annotation → decorator class argument → template ref map.</p>\n",
|
|
49318
|
-
"displayName": "resolveEuiClassName",
|
|
49319
|
-
"args": [
|
|
49320
|
-
{
|
|
49321
|
-
"name": "node",
|
|
49322
|
-
"deprecated": false,
|
|
49323
|
-
"deprecationMessage": ""
|
|
49324
|
-
},
|
|
49325
|
-
{
|
|
49326
|
-
"name": "sourceFile",
|
|
49327
|
-
"deprecated": false,
|
|
49328
|
-
"deprecationMessage": ""
|
|
49329
|
-
},
|
|
49330
|
-
{
|
|
49331
|
-
"name": "templateRefMap",
|
|
49332
|
-
"type": "Map",
|
|
49333
|
-
"deprecated": false,
|
|
49334
|
-
"deprecationMessage": ""
|
|
49335
|
-
}
|
|
49336
|
-
],
|
|
49337
|
-
"returnType": "string | null",
|
|
49338
|
-
"jsdoctags": [
|
|
49339
|
-
{
|
|
49340
|
-
"name": "node",
|
|
49341
|
-
"deprecated": false,
|
|
49342
|
-
"deprecationMessage": "",
|
|
49343
|
-
"tagName": {
|
|
49344
|
-
"text": "param"
|
|
49345
|
-
}
|
|
49346
|
-
},
|
|
49347
|
-
{
|
|
49348
|
-
"name": "sourceFile",
|
|
49349
|
-
"deprecated": false,
|
|
49350
|
-
"deprecationMessage": "",
|
|
49351
|
-
"tagName": {
|
|
49352
|
-
"text": "param"
|
|
49353
|
-
}
|
|
49354
|
-
},
|
|
49355
|
-
{
|
|
49356
|
-
"name": "templateRefMap",
|
|
49357
|
-
"type": "Map",
|
|
49358
|
-
"deprecated": false,
|
|
49359
|
-
"deprecationMessage": "",
|
|
49360
|
-
"tagName": {
|
|
49361
|
-
"text": "param"
|
|
49362
|
-
}
|
|
49363
|
-
}
|
|
49364
|
-
]
|
|
49365
|
-
},
|
|
49366
|
-
{
|
|
49367
|
-
"name": "resolveRefName",
|
|
49368
|
-
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
49369
|
-
"ctype": "miscellaneous",
|
|
49370
|
-
"subtype": "function",
|
|
49371
|
-
"coverageIgnore": false,
|
|
49372
|
-
"deprecated": false,
|
|
49373
|
-
"deprecationMessage": "",
|
|
49374
|
-
"rawdescription": "Resolves a reference name from an expression.\nHandles: `ref`, `this.ref`, `this._ref`",
|
|
49375
|
-
"description": "<p>Resolves a reference name from an expression.\nHandles: <code>ref</code>, <code>this.ref</code>, <code>this._ref</code></p>\n",
|
|
49376
|
-
"displayName": "resolveRefName",
|
|
49377
|
-
"args": [
|
|
49378
|
-
{
|
|
49379
|
-
"name": "expr",
|
|
49380
|
-
"deprecated": false,
|
|
49381
|
-
"deprecationMessage": ""
|
|
49382
|
-
}
|
|
49383
|
-
],
|
|
49384
|
-
"returnType": "string | null",
|
|
49385
|
-
"jsdoctags": [
|
|
49386
|
-
{
|
|
49387
|
-
"name": "expr",
|
|
49388
|
-
"deprecated": false,
|
|
49389
|
-
"deprecationMessage": "",
|
|
49390
|
-
"tagName": {
|
|
49391
|
-
"text": "param"
|
|
49392
|
-
}
|
|
49393
|
-
}
|
|
49394
|
-
]
|
|
49395
|
-
},
|
|
49396
|
-
{
|
|
49397
|
-
"name": "tryRewritePropertyAccess",
|
|
49398
|
-
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
49431
|
+
"name": "removeImportSpecifier",
|
|
49432
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
49399
49433
|
"ctype": "miscellaneous",
|
|
49400
49434
|
"subtype": "function",
|
|
49401
49435
|
"coverageIgnore": false,
|
|
49402
49436
|
"deprecated": false,
|
|
49403
49437
|
"deprecationMessage": "",
|
|
49404
|
-
"rawdescription": "
|
|
49405
|
-
"description": "
|
|
49406
|
-
"displayName": "
|
|
49438
|
+
"rawdescription": "",
|
|
49439
|
+
"description": "",
|
|
49440
|
+
"displayName": "removeImportSpecifier",
|
|
49407
49441
|
"args": [
|
|
49408
49442
|
{
|
|
49409
|
-
"name": "
|
|
49443
|
+
"name": "namedImports",
|
|
49410
49444
|
"deprecated": false,
|
|
49411
49445
|
"deprecationMessage": ""
|
|
49412
49446
|
},
|
|
49413
49447
|
{
|
|
49414
|
-
"name": "
|
|
49415
|
-
"type": "Map",
|
|
49448
|
+
"name": "specifier",
|
|
49416
49449
|
"deprecated": false,
|
|
49417
49450
|
"deprecationMessage": ""
|
|
49418
49451
|
},
|
|
@@ -49422,16 +49455,15 @@
|
|
|
49422
49455
|
"deprecationMessage": ""
|
|
49423
49456
|
},
|
|
49424
49457
|
{
|
|
49425
|
-
"name": "
|
|
49426
|
-
"type": "string",
|
|
49458
|
+
"name": "edits",
|
|
49427
49459
|
"deprecated": false,
|
|
49428
49460
|
"deprecationMessage": ""
|
|
49429
49461
|
}
|
|
49430
49462
|
],
|
|
49431
|
-
"returnType": "
|
|
49463
|
+
"returnType": "void",
|
|
49432
49464
|
"jsdoctags": [
|
|
49433
49465
|
{
|
|
49434
|
-
"name": "
|
|
49466
|
+
"name": "namedImports",
|
|
49435
49467
|
"deprecated": false,
|
|
49436
49468
|
"deprecationMessage": "",
|
|
49437
49469
|
"tagName": {
|
|
@@ -49439,8 +49471,7 @@
|
|
|
49439
49471
|
}
|
|
49440
49472
|
},
|
|
49441
49473
|
{
|
|
49442
|
-
"name": "
|
|
49443
|
-
"type": "Map",
|
|
49474
|
+
"name": "specifier",
|
|
49444
49475
|
"deprecated": false,
|
|
49445
49476
|
"deprecationMessage": "",
|
|
49446
49477
|
"tagName": {
|
|
@@ -49456,38 +49487,7 @@
|
|
|
49456
49487
|
}
|
|
49457
49488
|
},
|
|
49458
49489
|
{
|
|
49459
|
-
"name": "
|
|
49460
|
-
"type": "string",
|
|
49461
|
-
"deprecated": false,
|
|
49462
|
-
"deprecationMessage": "",
|
|
49463
|
-
"tagName": {
|
|
49464
|
-
"text": "param"
|
|
49465
|
-
}
|
|
49466
|
-
}
|
|
49467
|
-
]
|
|
49468
|
-
},
|
|
49469
|
-
{
|
|
49470
|
-
"name": "unwrapExpression",
|
|
49471
|
-
"file": "packages/core/schematics/migrate-to-signals/index.ts",
|
|
49472
|
-
"ctype": "miscellaneous",
|
|
49473
|
-
"subtype": "function",
|
|
49474
|
-
"coverageIgnore": false,
|
|
49475
|
-
"deprecated": false,
|
|
49476
|
-
"deprecationMessage": "",
|
|
49477
|
-
"rawdescription": "",
|
|
49478
|
-
"description": "",
|
|
49479
|
-
"displayName": "unwrapExpression",
|
|
49480
|
-
"args": [
|
|
49481
|
-
{
|
|
49482
|
-
"name": "expression",
|
|
49483
|
-
"deprecated": false,
|
|
49484
|
-
"deprecationMessage": ""
|
|
49485
|
-
}
|
|
49486
|
-
],
|
|
49487
|
-
"returnType": "ts.Expression",
|
|
49488
|
-
"jsdoctags": [
|
|
49489
|
-
{
|
|
49490
|
-
"name": "expression",
|
|
49490
|
+
"name": "edits",
|
|
49491
49491
|
"deprecated": false,
|
|
49492
49492
|
"deprecationMessage": "",
|
|
49493
49493
|
"tagName": {
|
|
@@ -49498,7 +49498,7 @@
|
|
|
49498
49498
|
},
|
|
49499
49499
|
{
|
|
49500
49500
|
"name": "visitDir",
|
|
49501
|
-
"file": "packages/core/schematics/migrate-
|
|
49501
|
+
"file": "packages/core/schematics/migrate-eui-tooltip/index.ts",
|
|
49502
49502
|
"ctype": "miscellaneous",
|
|
49503
49503
|
"subtype": "function",
|
|
49504
49504
|
"coverageIgnore": false,
|