Angular Modernizer
    Preparing search index...

    Module @angular-modernizer/plugin-analyzer - v1.2.0

    Project-level analysis plugin for the Angular Modernizer.

    AnalyzerPlugin registers FrameworkDetectorRule, which reports whether the project is an Angular CLI or an Nx workspace. The rules of this plugin only report; they never modify code.

    @angular-modernizer/plugin-analyzer

    Framework detection and project structure analysis plugin for the Angular Modernization Platform.

    The @angular-modernizer/plugin-analyzer package provides general analysis rules for Angular projects. It currently ships one rule, the framework detector. The analyze-project MCP tool runs this plugin (registered under the name analyzer).

    This plugin follows the plugin contract from @angular-modernizer/plugin-system. The framework detector needs no PublicApi tool; it reads the project and its file system from the context:

    class FrameworkDetectorRule implements AnalysisRule {
    async analyze(context: AnalysisContext): Promise<AnalysisResult[]> {
    const { project, filePath } = context;
    // checks nx.json and angular.json in the project root
    }
    }

    Rule ID: analyzer:framework-detector

    Detects whether a project uses Angular CLI or Nx from the configuration files in the project root (the directory of the tsconfig, otherwise the directory of the analyzed file).

    Detection Priority:

    1. Nx: nx.json present
    2. Angular CLI: angular.json present
    3. Unknown: neither file present

    Example Output:

    [
    {
    "ruleId": "analyzer:framework-detector",
    "message": "Project uses Angular CLI",
    "filePath": "/path/to/project/src/main.ts",
    "metadata": {
    "framework": "Angular CLI",
    "hasNxConfig": false,
    "hasAngularConfig": true,
    "projectRoot": "/path/to/project"
    }
    }
    ]

    framework is Nx, Angular CLI or Unknown.

    import { Kernel, RealFileSystemAdapter } from '@angular-modernizer/core';
    import { createPublicApi } from '@angular-modernizer/api';
    import { ContextFactory } from '@angular-modernizer/plugin-system';
    import { AnalyzerPlugin } from '@angular-modernizer/plugin-analyzer';

    const kernel = new Kernel({
    tsConfigPath: './tsconfig.json',
    fileSystem: new RealFileSystemAdapter(),
    plugins: [new AnalyzerPlugin()],
    });

    await kernel.initialize();

    const plugin = kernel.getPlugin('analyzer')!;
    const frameworkRule = plugin
    .getAnalysisRules()
    .find((r) => r.id === 'analyzer:framework-detector')!;

    const project = kernel.getProject();
    const sourceFile = project.getSourceFiles()[0]!;

    const context = ContextFactory.createAnalysisContext({
    sourceFile,
    project,
    api: createPublicApi(project),
    });

    const [result] = await frameworkRule.analyze(context);

    console.log('Framework detected:', result?.metadata?.framework);

    The analyze-project MCP tool creates a kernel with AnalyzerPlugin and runs its rules over the project files; with includeDetails the rule findings are returned in results. Framework, architecture and technology stack in the tool result are detected by the tool itself:

    const analysis = await callTool('analyze-project', {
    rootPath: '/path/to/angular/project',
    includeDetails: true,
    });

    // structuredContent (abridged)
    {
    "framework": { "detected": true, "type": "...", "confidence": 0.9, "indicators": ["..."] },
    "architecture": { "pattern": "...", "confidence": 0.8, "layers": [] },
    "technologyStack": { "languages": [], "frameworks": [], "buildTools": [], "packageManager": "pnpm" },
    "results": [{ "ruleId": "analyzer:framework-detector", "message": "...", "filePath": "..." }]
    }
    packages/plugin-analyzer/
    src/
    rules/
    framework-detector.rule.ts
    index.ts # AnalyzerPlugin, FrameworkDetectorRule
    __tests__/
    framework-detector.rule.test.ts
    fixtures/
    package.json
    tsconfig.json
    jest.config.js
    README.md
    pnpm --filter @angular-modernizer/plugin-analyzer test
    pnpm --filter @angular-modernizer/plugin-analyzer test -- --coverage
    __tests__/fixtures/
    sample-angular-cli-app/
    angular.json
    tsconfig.json
    src/main.ts
    sample-nx-app/
    nx.json
    tsconfig.json
    src/main.ts
    sample-unknown-app/
    tsconfig.json
    src/main.ts
    sample-app/
    legacy.component.ts
    legacy.directive.ts
    modern.component.ts
    import { Kernel } from '@angular-modernizer/core';
    import { ContextFactory } from '@angular-modernizer/plugin-system';
    import { AnalyzerPlugin } from '../src/index.js';
    import { resolve } from 'path';

    describe('FrameworkDetectorRule', () => {
    it('should detect Angular CLI project', async () => {
    const plugin = new AnalyzerPlugin();
    const kernel = new Kernel({
    tsConfigPath: resolve(__dirname, './fixtures/sample-angular-cli-app/tsconfig.json'),
    plugins: [plugin],
    });
    await kernel.initialize();

    const project = kernel.getProject();
    const rule = plugin
    .getAnalysisRules()
    .find((r) => r.id === 'analyzer:framework-detector')!;

    const context = ContextFactory.createAnalysisContext({
    sourceFile: project.getSourceFiles()[0]!,
    project,
    api: {},
    });

    const [result] = await rule.analyze(context);

    expect(result?.metadata?.framework).toBe('Angular CLI');
    });
    });
    • @angular-modernizer/api - Public API with analysis tools
    • @angular-modernizer/core - Kernel and infrastructure
    • @angular-modernizer/plugin-system - Plugin contracts and contexts

    When adding new analysis rules:

    1. Follow the AnalysisRule interface: implement all required members
    2. Use PublicApi tools: do not implement low-level AST logic directly
    3. Include comprehensive tests using real fixtures where possible
    4. Provide meaningful metadata
    5. Update this README with configuration options
    // 1. Implement the rule in src/rules/
    class MyAnalysisRule implements AnalysisRule {
    readonly id = 'analyzer:my-analysis';
    readonly name = 'My Analysis Rule';
    readonly description = 'Analyzes something specific';
    readonly severity = 'info' as const;
    readonly category = 'project-analysis';

    async analyze(context: AnalysisContext): Promise<AnalysisResult[]> {
    const { api, sourceFile, filePath } = context;
    const usesInject = api.transformation.importManager.hasImport(sourceFile, 'inject', '@angular/core');

    return [{ ruleId: this.id, message: `inject imported: ${usesInject}`, filePath }];
    }
    }

    // 2. Add to the plugin (src/index.ts)
    class AnalyzerPlugin implements Plugin {
    getAnalysisRules(): AnalysisRule[] {
    return [this.frameworkDetectorRule, new MyAnalysisRule()];
    }
    }

    Classes

    AnalyzerPlugin
    FrameworkDetectorRule