/
githubmirror
/
angular-cli
Обзор
Документация
Войти
/
githubmirror
/
angular-cli
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/angular/cli/src/commands/mcp/tools/onpush-zoneless-migration/migrate-single-file.ts
94 строки
3 KB
Charles Lyding
refactor(@angular/cli): migrate MCP server to @modelcontextprotocol/server v2
04 авг 2026, 09:55
04 авг 2026, 09:55
b81b880
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import type { ServerContext } from '@modelcontextprotocol/server'; import type { SourceFile } from 'typescript'; import type { Host } from '../../host'; import { analyzeForUnsupportedZoneUses } from './analyze-for-unsupported-zone-uses'; import { migrateTestFile } from './migrate-test-file'; import { generateZonelessMigrationInstructionsForComponent } from './prompts'; import { sendDebugMessage } from './send-debug-message'; import { getImportSpecifier, loadTypescript } from './ts-utils'; import type { MigrationResponse } from './types'; const supportedStrategies: ReadonlySet<string> = new Set(['OnPush', 'Default', 'Eager']); export async function migrateSingleFile( sourceFile: SourceFile, host: Host, extras: ServerContext, ): Promise<MigrationResponse | null> { const testBedSpecifier = await getImportSpecifier(sourceFile, '@angular/core/testing', 'TestBed'); const isTestFile = sourceFile.fileName.endsWith('.spec.ts') || !!testBedSpecifier; if (isTestFile) { return migrateTestFile(sourceFile, host); } const unsupportedZoneUseResponse = await analyzeForUnsupportedZoneUses(sourceFile); if (unsupportedZoneUseResponse) { return unsupportedZoneUseResponse; } let detectedStrategy: string | undefined; let hasComponentDecorator = false; const componentSpecifier = await getImportSpecifier(sourceFile, '@angular/core', 'Component'); if (!componentSpecifier) { sendDebugMessage(`No component decorator found in file: ${sourceFile.fileName}`, extras); return null; } const ts = await loadTypescript(); ts.forEachChild(sourceFile, function visit(node) { if (detectedStrategy) { return; // Already found, no need to traverse further } if (ts.isDecorator(node) && ts.isCallExpression(node.expression)) { const callExpr = node.expression; if (callExpr.expression.getText(sourceFile) === 'Component') { hasComponentDecorator = true; if (callExpr.arguments.length > 0 && ts.isObjectLiteralExpression(callExpr.arguments[0])) { const componentMetadata = callExpr.arguments[0]; for (const prop of componentMetadata.properties) { if ( ts.isPropertyAssignment(prop) && prop.name.getText(sourceFile) === 'changeDetection' ) { if ( ts.isPropertyAccessExpression(prop.initializer) && prop.initializer.expression.getText(sourceFile) === 'ChangeDetectionStrategy' ) { const strategy = prop.initializer.name.text; if (supportedStrategies.has(strategy)) { detectedStrategy = strategy; return; } } } } } } } ts.forEachChild(node, visit); }); if (!hasComponentDecorator || (detectedStrategy && supportedStrategies.has(detectedStrategy))) { sendDebugMessage( `Component decorator found with strategy: ${detectedStrategy} in file: ${sourceFile.fileName}. Skipping migration for file.`, extras, ); return null; } // Component decorator found, but no change detection strategy. return generateZonelessMigrationInstructionsForComponent(sourceFile.fileName); }