Implementation:Langgenius Dify Component Analyzer
| Knowledge Sources | |
|---|---|
| Domains | Frontend, Build_Tools |
| Last Updated | 2026-02-12 07:00 GMT |
Overview
Shared JavaScript module providing the core ComponentAnalyzer class that computes cognitive complexity, detects React features, counts codebase usage references, and calculates test priority for React components.
Description
component-analyzer.js is the engine behind both the analyze-component.js (test generation) and refactor-component.js (refactoring suggestions) scripts. It exports:
- ComponentAnalyzer class -- The primary analysis class that:
- Detects component type (component, hook, page, layout, provider, base-component, context, store, service) based on file path and code patterns.
- Detects React features including useState, useEffect, useCallback, useMemo, forwardRef, React.memo, useImperativeHandle, Suspense, createPortal, event handlers, Next.js routing hooks, API calls, React Query, and ahooks.
- Calculates cognitive complexity using the SonarJS ESLint plugin, producing both a total file complexity and a maximum single-function complexity, each normalized to a 0-100 scale via piecewise linear mapping with an asymptotic upper region.
- Counts usage references across the codebase by scanning TypeScript source files for import patterns matching the analyzed component.
- Computes a test priority score as a weighted average of complexity (70%) and usage score (30%), yielding a priority level of LOW, MEDIUM, HIGH, or CRITICAL.
- resolveDirectoryEntry(absolutePath, componentPath) -- Resolves a directory to its entry file by checking a priority-ordered list (index.tsx, index.ts, node.tsx, panel.tsx, component.tsx, main.tsx, container.tsx).
- listAnalyzableFiles(dirPath) -- Lists analyzable files in a directory, sorted with common entry files first.
- extractCopyContent(prompt) -- Extracts the copyable AI-assistant prompt section from a formatted prompt string.
- getComplexityLevel(score) -- Returns a human-readable label for a normalized complexity score.
Usage
This module is not run directly. It is imported by analyze-component.js and refactor-component.js as a shared dependency. Extend ComponentAnalyzer to add domain-specific analysis metrics.
Code Reference
Source Location
- Repository: Langgenius_Dify
- File: web/scripts/component-analyzer.js
- Lines: 1-484
Signature
export class ComponentAnalyzer {
analyze(code, filePath, absolutePath)
detectType(filePath, code)
calculateCognitiveComplexity(code) // returns { total, max }
normalizeComplexity(rawComplexity) // returns 0-100
countUsageReferences(filePath, absolutePath) // returns number
collectSearchRoots(resolvedComponentPath)
shouldSkipDir(dirName)
shouldInspectFile(fileName)
static escapeRegExp(value)
calculateTestPriority(complexity, usageCount)
getPriorityLevel(score)
}
export function resolveDirectoryEntry(absolutePath, componentPath)
export function listAnalyzableFiles(dirPath)
export function extractCopyContent(prompt)
export function getComplexityLevel(score)
Import
import {
ComponentAnalyzer,
extractCopyContent,
getComplexityLevel,
listAnalyzableFiles,
resolveDirectoryEntry,
} from './component-analyzer.js'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | Source code content of the component to analyze |
| filePath | string | Yes | Relative file path of the component (used for type detection and display) |
| absolutePath | string | No | Absolute file path (resolved from filePath if omitted); used for usage-reference scanning |
Outputs
| Name | Type | Description |
|---|---|---|
| analysis.name | string | PascalCase component name derived from the filename |
| analysis.type | string | Detected type: component, hook, page, layout, provider, base-component, context, store, or service |
| analysis.complexity | number | Normalized total cognitive complexity (0-100) |
| analysis.maxComplexity | number | Normalized max single-function complexity (0-100) |
| analysis.lineCount | number | Total number of lines in the source file |
| analysis.usageCount | number | Number of files in the codebase that import this component |
| analysis.priority | object | Test priority object with score (0-100), level, usageScore, and complexityScore |
| analysis.has* | boolean | Feature detection flags (hasProps, hasState, hasEffects, hasCallbacks, hasMemo, hasEvents, hasRouter, hasAPI, hasForwardRef, hasComponentMemo, hasSuspense, hasPortal, hasImperativeHandle, hasReactQuery, hasAhooks) |
Usage Examples
Analyze a component programmatically
import { ComponentAnalyzer } from './component-analyzer.js'
import fs from 'node:fs'
const code = fs.readFileSync('app/components/base/button/index.tsx', 'utf-8')
const analyzer = new ComponentAnalyzer()
const analysis = analyzer.analyze(code, 'app/components/base/button/index.tsx')
console.log(analysis.complexity, analysis.priority.level)
Extend for custom analysis
class CustomAnalyzer extends ComponentAnalyzer {
analyze(code, filePath, absolutePath) {
const base = super.analyze(code, filePath, absolutePath)
return { ...base, customMetric: this.computeCustomMetric(code) }
}
}