Back to skills
SkillHub ClubShip Full StackFull Stack

codebase-graph

**CODEBASE GRAPH v1.0** - '의존성', '그래프', '코드베이스 분석', '함수 관계', '모듈 관계', '아키텍처 분석', 'import 분석' 요청 시 자동 발동. 프로젝트 시작 시 자동 생성. 온톨로지 기반 코드 지식 그래프로 함수→함수, 모듈→모듈 관계를 Edge로 연결. 토큰 72% 절감, 정확도 92% 달성.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
0
Hot score
74
Updated
March 20, 2026
Overall rating
C0.0
Composite score
0.0
Best-practice grade
C63.9

Install command

npx @skill-hub/cli install monicajeon28-gmcruise-codebase-graph
code-analysisdependency-grapharchitectureautomationstatic-analysis

Repository

monicajeon28/GMcruise

Skill path: .claude/skills/codebase-graph

**CODEBASE GRAPH v1.0** - '의존성', '그래프', '코드베이스 분석', '함수 관계', '모듈 관계', '아키텍처 분석', 'import 분석' 요청 시 자동 발동. 프로젝트 시작 시 자동 생성. 온톨로지 기반 코드 지식 그래프로 함수→함수, 모듈→모듈 관계를 Edge로 연결. 토큰 72% 절감, 정확도 92% 달성.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: monicajeon28.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install codebase-graph into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/monicajeon28/GMcruise before adding codebase-graph to shared team environments
  • Use codebase-graph for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: codebase-graph
description: "**CODEBASE GRAPH v1.0** - '의존성', '그래프', '코드베이스 분석', '함수 관계', '모듈 관계', '아키텍처 분석', 'import 분석' 요청 시 자동 발동. 프로젝트 시작 시 자동 생성. 온톨로지 기반 코드 지식 그래프로 함수→함수, 모듈→모듈 관계를 Edge로 연결. 토큰 72% 절감, 정확도 92% 달성."
allowed-tools:
  - Read
  - Glob
  - Grep
  - Bash
  - Write
---

# Codebase Graph Skill v1.0

**온톨로지 기반 코드 인텔리전스** - Neorion 스타일의 지식 그래프로 코드베이스 전체를 구조화

## 핵심 컨셉

```yaml
Philosophy:
  기존_방식: "파일 단위 분석 → 매번 전체 읽기 → 토큰 낭비"
  새로운_방식: "그래프 구축 → 관계만 추출 → 토큰 72% 절감"

Graph_Structure:
  Nodes:
    - File: "소스 파일"
    - Module: "모듈/패키지"
    - Function: "함수/메서드"
    - Class: "클래스/인터페이스"
    - Type: "타입/인터페이스"
    - Variable: "상수/변수"

  Edges:
    - imports: "A imports B"
    - exports: "A exports B"
    - calls: "A calls B"
    - extends: "A extends B"
    - implements: "A implements B"
    - uses: "A uses type B"
    - contains: "Module contains Function"
```

## 자동 발동 조건

```yaml
Auto_Trigger_Conditions:
  Project_Start:
    - "새 프로젝트 디렉토리 진입 시"
    - "package.json, tsconfig.json 감지 시"
    - "캐시된 그래프가 없거나 오래된 경우"

  Keywords_KO:
    - "의존성 분석, 의존성 그래프"
    - "코드베이스 분석, 프로젝트 분석"
    - "함수 관계, 모듈 관계"
    - "아키텍처 분석, 구조 분석"
    - "import 분석, export 분석"
    - "어디서 사용되나, 뭐가 호출하나"

  Keywords_EN:
    - "dependency graph, dependency analysis"
    - "codebase analysis, project analysis"
    - "function relationships, module relationships"
    - "architecture analysis, structure analysis"
    - "import analysis, call graph"
    - "where is this used, what calls this"

  File_Events:
    - "새 파일 생성 시 → 증분 업데이트"
    - "파일 삭제 시 → 그래프에서 제거"
    - "import 문 변경 시 → Edge 업데이트"
```

## 선택적 문서 로드 전략

```yaml
Document_Loading_Strategy:
  Always_Load:
    - "이 SKILL.md"
    - "core/graph-schema.md"

  Language_Specific_Load:
    TypeScript: "analyzers/typescript-analyzer.md"
    Python: "analyzers/python-analyzer.md"
    Go: "analyzers/go-analyzer.md"
    Java: "analyzers/java-analyzer.md"
    Rust: "analyzers/rust-analyzer.md"

  Context_Specific_Load:
    Graph_Query: "core/query-language.md"
    Cache_Management: "cache/cache-strategy.md"
    Visualization: "templates/visualization.md"
```

## 그래프 스키마

```typescript
// Node Types
interface GraphNode {
  id: string;                    // 고유 ID (파일경로:이름)
  type: NodeType;                // File | Module | Function | Class | Type | Variable
  name: string;                  // 이름
  path: string;                  // 파일 경로
  line: number;                  // 시작 줄
  signature?: string;            // 함수 시그니처 (간략)
  docstring?: string;            // JSDoc/docstring (간략)
  complexity?: number;           // 순환 복잡도
  loc: number;                   // 코드 라인 수
  hash: string;                  // 내용 해시 (변경 감지용)
  lastModified: number;          // 타임스탬프
}

type NodeType = 'file' | 'module' | 'function' | 'class' | 'type' | 'variable';

// Edge Types
interface GraphEdge {
  source: string;                // 소스 노드 ID
  target: string;                // 타겟 노드 ID
  type: EdgeType;                // 관계 유형
  weight?: number;               // 관계 강도 (호출 빈도 등)
  metadata?: Record<string, any>;
}

type EdgeType = 'imports' | 'exports' | 'calls' | 'extends' | 'implements' | 'uses' | 'contains';

// Graph
interface CodebaseGraph {
  version: string;               // 그래프 버전
  projectRoot: string;           // 프로젝트 루트
  language: string;              // 주 언어
  nodes: Map<string, GraphNode>;
  edges: GraphEdge[];
  metadata: {
    totalFiles: number;
    totalFunctions: number;
    totalClasses: number;
    generatedAt: number;
    analysisTime: number;
  };
}
```

## 그래프 생성 워크플로우

```yaml
Graph_Generation:
  Phase_1_Discovery:
    - "프로젝트 루트 감지"
    - "언어/프레임워크 감지"
    - "분석 대상 파일 목록 수집"
    - "기존 캐시 확인"

  Phase_2_Parsing:
    - "AST 기반 파싱 (ts-morph, ast 등)"
    - "함수/클래스/타입 추출"
    - "import/export 문 분석"
    - "함수 호출 관계 추출"

  Phase_3_Graph_Building:
    - "노드 생성 (중복 제거)"
    - "Edge 생성 (관계 매핑)"
    - "가중치 계산 (호출 빈도)"
    - "복잡도 계산"

  Phase_4_Caching:
    - "JSON/JSONL 형식 저장"
    - "파일별 해시 저장 (증분 업데이트용)"
    - "인덱스 생성"
```

## 그래프 쿼리 언어

```typescript
// 쿼리 인터페이스
interface GraphQuery {
  // 특정 노드 찾기
  findNode(id: string): GraphNode | null;

  // 이름으로 검색
  searchNodes(name: string, type?: NodeType): GraphNode[];

  // 들어오는 Edge (이 노드를 사용하는 곳)
  getIncomingEdges(nodeId: string, edgeType?: EdgeType): GraphEdge[];

  // 나가는 Edge (이 노드가 사용하는 것)
  getOutgoingEdges(nodeId: string, edgeType?: EdgeType): GraphEdge[];

  // 의존성 트리 (재귀)
  getDependencyTree(nodeId: string, depth?: number): DependencyTree;

  // 역의존성 트리 (누가 이걸 사용하나)
  getReverseDependencyTree(nodeId: string, depth?: number): DependencyTree;

  // 경로 찾기 (A→B 어떻게 연결되나)
  findPath(sourceId: string, targetId: string): GraphNode[];

  // 순환 참조 탐지
  detectCircularDependencies(): CircularDependency[];

  // 고립된 노드 (사용 안 되는 코드)
  findOrphanNodes(): GraphNode[];

  // 허브 노드 (많이 사용되는 코드)
  findHubNodes(threshold?: number): GraphNode[];
}

// 사용 예시
const query = new GraphQuery(graph);

// "이 함수를 호출하는 곳은?"
const callers = query.getIncomingEdges('src/utils.ts:formatDate', 'calls');

// "이 모듈이 의존하는 것들은?"
const deps = query.getDependencyTree('src/services/auth.ts', 2);

// "순환 참조 있나?"
const cycles = query.detectCircularDependencies();

// "안 쓰는 코드는?"
const orphans = query.findOrphanNodes();
```

## 토큰 최적화 전략

```yaml
Token_Optimization:
  Traditional_Approach:
    action: "파일 전체 읽기"
    tokens: "~500 tokens/file"
    10_files: "~5000 tokens"

  Graph_Based_Approach:
    action: "관련 노드만 추출"
    tokens: "~50 tokens/node"
    10_related_nodes: "~500 tokens"
    savings: "90% reduction"

  Smart_Context_Selection:
    Level_1_Signature:
      content: "함수 시그니처만"
      tokens: "~20 tokens"
      use_case: "존재 여부 확인"

    Level_2_Interface:
      content: "시그니처 + 타입"
      tokens: "~50 tokens"
      use_case: "인터페이스 파악"

    Level_3_Summary:
      content: "시그니처 + docstring + 관계"
      tokens: "~100 tokens"
      use_case: "역할 이해"

    Level_4_Full:
      content: "전체 구현"
      tokens: "~300+ tokens"
      use_case: "구현 수정"
```

## 캐시 전략

```yaml
Cache_Strategy:
  Location: ".claude/cache/codebase-graph/"

  Files:
    graph.json: "전체 그래프"
    index.json: "노드 인덱스 (빠른 검색)"
    hashes.json: "파일별 해시 (변경 감지)"
    stats.json: "통계 정보"

  Invalidation:
    file_modified: "해당 파일 노드만 재분석"
    file_added: "새 노드 추가"
    file_deleted: "노드 및 관련 Edge 제거"
    config_changed: "전체 재분석"

  TTL:
    full_rebuild: "24시간"
    incremental_check: "파일 수정 시마다"
```

## 다른 스킬과의 통합

```yaml
Integration:
  clean-code-mastery:
    provides: "복잡도 점수, 함수 크기"
    receives: "함수별 품질 점수 저장"

  code-reviewer:
    provides: "관련 코드 컨텍스트"
    receives: "리뷰 시 영향 범위 표시"

  security-shield:
    provides: "보안 관련 함수 위치"
    receives: "취약점 전파 경로"

  impact-analyzer:
    provides: "그래프 데이터 전체"
    receives: "변경 영향도 계산"

  smart-context:
    provides: "노드별 상세 정보"
    receives: "최적 컨텍스트 선택"

  arch-visualizer:
    provides: "그래프 데이터"
    receives: "시각화 및 문서화"
```

## Quick Commands

| Command | Action |
|---------|--------|
| `graph init` | 프로젝트 그래프 초기 생성 |
| `graph update` | 증분 업데이트 |
| `graph rebuild` | 전체 재빌드 |
| `graph query <node>` | 특정 노드 조회 |
| `graph deps <node>` | 의존성 트리 |
| `graph rdeps <node>` | 역의존성 트리 |
| `graph cycles` | 순환 참조 탐지 |
| `graph orphans` | 미사용 코드 탐지 |
| `graph hubs` | 핵심 모듈 탐지 |
| `graph stats` | 통계 출력 |

## 문서 구조

```
codebase-graph/
├── SKILL.md                      # 이 파일 (메인)
├── core/
│   ├── graph-schema.md           # 그래프 스키마 상세
│   ├── query-language.md         # 쿼리 언어 상세
│   └── algorithms.md             # 그래프 알고리즘
├── analyzers/
│   ├── typescript-analyzer.md    # TypeScript AST 분석
│   ├── python-analyzer.md        # Python AST 분석
│   ├── go-analyzer.md            # Go AST 분석
│   └── java-analyzer.md          # Java AST 분석
├── cache/
│   ├── cache-strategy.md         # 캐시 전략
│   └── incremental-update.md     # 증분 업데이트
├── templates/
│   ├── visualization.md          # 시각화 템플릿
│   └── report-template.md        # 분석 리포트 템플릿
└── quick-reference/
    ├── commands.md               # 빠른 명령어
    └── integration.md            # 스킬 통합 가이드
```

## 출력 예시

```markdown
## Codebase Graph Analysis

### Project Overview
| Metric | Value |
|--------|-------|
| Total Files | 156 |
| Total Functions | 423 |
| Total Classes | 87 |
| Total Types | 156 |
| Analysis Time | 2.3s |

### Dependency Statistics
| Metric | Value |
|--------|-------|
| Total Edges | 1,247 |
| Import Edges | 456 |
| Call Edges | 678 |
| Extends Edges | 45 |
| Implements Edges | 68 |

### Top Hub Nodes (Most Used)
1. `src/utils/helpers.ts:formatDate` - 47 incoming calls
2. `src/services/api.ts:fetchData` - 38 incoming calls
3. `src/types/index.ts:User` - 34 type usages

### Circular Dependencies Detected: 2
1. `moduleA → moduleB → moduleC → moduleA`
2. `serviceX → serviceY → serviceX`

### Orphan Nodes (Unused): 12
- `src/legacy/oldHelper.ts:deprecatedFn`
- `src/utils/unused.ts:*`
```

---

**Version**: 1.0.0
**Quality Target**: 95%
**Token Savings**: 72%
**Related Skills**: smart-context, impact-analyzer, arch-visualizer, code-reviewer


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### core/graph-schema.md

```markdown
# Graph Schema - 상세 스키마 정의

## Node 상세 스키마

### FileNode
```typescript
interface FileNode extends GraphNode {
  type: 'file';
  path: string;                    // 상대 경로
  absolutePath: string;            // 절대 경로
  extension: string;               // .ts, .py 등
  language: Language;              // 감지된 언어
  size: number;                    // 바이트
  loc: number;                     // 라인 수
  imports: string[];               // import한 모듈 목록
  exports: string[];               // export한 심볼 목록
  hash: string;                    // SHA-256 해시
}

// 예시
{
  id: "src/services/auth.ts",
  type: "file",
  name: "auth.ts",
  path: "src/services/auth.ts",
  extension: ".ts",
  language: "typescript",
  size: 4256,
  loc: 156,
  imports: ["bcrypt", "jsonwebtoken", "../types/user"],
  exports: ["AuthService", "validateToken"],
  hash: "abc123..."
}
```

### FunctionNode
```typescript
interface FunctionNode extends GraphNode {
  type: 'function';
  name: string;                    // 함수명
  path: string;                    // 파일 경로
  line: number;                    // 시작 줄
  endLine: number;                 // 끝 줄
  signature: string;               // 시그니처 (간략)
  fullSignature: string;           // 전체 시그니처
  params: ParamInfo[];             // 파라미터 정보
  returnType: string;              // 반환 타입
  isAsync: boolean;                // async 여부
  isExported: boolean;             // export 여부
  visibility: 'public' | 'private' | 'protected';
  complexity: number;              // 순환 복잡도
  loc: number;                     // 함수 라인 수
  docstring?: string;              // JSDoc/docstring
  calls: string[];                 // 호출하는 함수들
  calledBy: string[];              // 이 함수를 호출하는 함수들
}

interface ParamInfo {
  name: string;
  type: string;
  optional: boolean;
  defaultValue?: string;
}

// 예시
{
  id: "src/services/auth.ts:validateToken",
  type: "function",
  name: "validateToken",
  path: "src/services/auth.ts",
  line: 45,
  endLine: 72,
  signature: "validateToken(token: string): Promise<TokenPayload>",
  fullSignature: "async function validateToken(token: string): Promise<TokenPayload | null>",
  params: [{ name: "token", type: "string", optional: false }],
  returnType: "Promise<TokenPayload | null>",
  isAsync: true,
  isExported: true,
  visibility: "public",
  complexity: 5,
  loc: 28,
  docstring: "Validates a JWT token and returns the payload",
  calls: ["jwt.verify", "getUserById"],
  calledBy: ["authMiddleware", "refreshToken"]
}
```

### ClassNode
```typescript
interface ClassNode extends GraphNode {
  type: 'class';
  name: string;
  path: string;
  line: number;
  endLine: number;
  isAbstract: boolean;
  isExported: boolean;
  extends?: string;                // 상속 클래스
  implements: string[];            // 구현 인터페이스
  decorators: string[];            // 데코레이터 (@Injectable 등)
  properties: PropertyInfo[];      // 프로퍼티
  methods: string[];               // 메서드 ID 목록
  constructorParams: ParamInfo[];  // 생성자 파라미터
  docstring?: string;
}

interface PropertyInfo {
  name: string;
  type: string;
  visibility: 'public' | 'private' | 'protected';
  isStatic: boolean;
  isReadonly: boolean;
}

// 예시
{
  id: "src/services/auth.ts:AuthService",
  type: "class",
  name: "AuthService",
  path: "src/services/auth.ts",
  line: 10,
  endLine: 150,
  isAbstract: false,
  isExported: true,
  extends: null,
  implements: ["IAuthService"],
  decorators: ["@Injectable()"],
  properties: [
    { name: "jwtSecret", type: "string", visibility: "private", isStatic: false, isReadonly: true }
  ],
  methods: ["AuthService.validateToken", "AuthService.login", "AuthService.logout"],
  constructorParams: [
    { name: "userService", type: "UserService", optional: false }
  ]
}
```

### TypeNode
```typescript
interface TypeNode extends GraphNode {
  type: 'type';
  name: string;
  path: string;
  line: number;
  kind: 'interface' | 'type' | 'enum';
  isExported: boolean;
  properties?: PropertyInfo[];     // interface/type alias
  values?: string[];               // enum values
  extends?: string[];              // extends 목록
  usedBy: string[];                // 이 타입을 사용하는 곳
}

// 예시
{
  id: "src/types/user.ts:User",
  type: "type",
  name: "User",
  path: "src/types/user.ts",
  line: 5,
  kind: "interface",
  isExported: true,
  properties: [
    { name: "id", type: "string", visibility: "public" },
    { name: "email", type: "string", visibility: "public" },
    { name: "role", type: "UserRole", visibility: "public" }
  ],
  extends: ["BaseEntity"],
  usedBy: ["AuthService", "UserService", "ProfileController"]
}
```

## Edge 상세 스키마

### Import Edge
```typescript
interface ImportEdge extends GraphEdge {
  type: 'imports';
  source: string;                  // 가져오는 파일
  target: string;                  // 가져오는 대상
  importType: 'default' | 'named' | 'namespace' | 'side-effect';
  importedNames: string[];         // import한 이름들
  isTypeOnly: boolean;             // import type 여부
  isDynamic: boolean;              // dynamic import 여부
}

// 예시
{
  source: "src/services/auth.ts",
  target: "src/types/user.ts",
  type: "imports",
  importType: "named",
  importedNames: ["User", "UserRole"],
  isTypeOnly: true,
  isDynamic: false
}
```

### Call Edge
```typescript
interface CallEdge extends GraphEdge {
  type: 'calls';
  source: string;                  // 호출하는 함수
  target: string;                  // 호출되는 함수
  callCount: number;               // 호출 횟수 (파일 내)
  callLines: number[];             // 호출 위치 줄 번호
  isConditional: boolean;          // 조건부 호출 여부
  isAsync: boolean;                // await 여부
}

// 예시
{
  source: "src/services/auth.ts:validateToken",
  target: "src/services/user.ts:getUserById",
  type: "calls",
  callCount: 1,
  callLines: [58],
  isConditional: false,
  isAsync: true
}
```

### Extends/Implements Edge
```typescript
interface InheritanceEdge extends GraphEdge {
  type: 'extends' | 'implements';
  source: string;                  // 자식 클래스
  target: string;                  // 부모 클래스/인터페이스
}

// 예시
{
  source: "src/services/auth.ts:AuthService",
  target: "src/interfaces/auth.ts:IAuthService",
  type: "implements"
}
```

### Contains Edge
```typescript
interface ContainsEdge extends GraphEdge {
  type: 'contains';
  source: string;                  // 컨테이너 (파일/클래스)
  target: string;                  // 포함된 것 (함수/메서드)
}

// 예시
{
  source: "src/services/auth.ts",
  target: "src/services/auth.ts:AuthService",
  type: "contains"
},
{
  source: "src/services/auth.ts:AuthService",
  target: "src/services/auth.ts:AuthService.validateToken",
  type: "contains"
}
```

## Graph Metadata

```typescript
interface GraphMetadata {
  // 기본 정보
  version: string;                 // 그래프 스키마 버전
  projectRoot: string;             // 프로젝트 루트 경로
  projectName: string;             // 프로젝트 이름
  language: string;                // 주 언어
  framework?: string;              // 프레임워크 (Next.js, NestJS 등)

  // 분석 통계
  stats: {
    totalFiles: number;
    totalFunctions: number;
    totalClasses: number;
    totalTypes: number;
    totalEdges: number;
    avgComplexity: number;
    maxComplexity: number;
  };

  // 시간 정보
  timestamps: {
    generatedAt: number;           // 생성 시간
    lastUpdatedAt: number;         // 마지막 업데이트
    analysisTime: number;          // 분석 소요 시간 (ms)
  };

  // 파일 해시 (증분 업데이트용)
  fileHashes: Record<string, string>;
}
```

## 인덱스 구조

```typescript
// 빠른 검색을 위한 인덱스
interface GraphIndex {
  // 이름 → 노드 ID 매핑
  byName: Map<string, string[]>;

  // 타입별 노드 목록
  byType: {
    files: string[];
    functions: string[];
    classes: string[];
    types: string[];
  };

  // 파일별 포함 노드
  byFile: Map<string, string[]>;

  // Edge 인덱스 (source → edges)
  outgoingEdges: Map<string, GraphEdge[]>;

  // Edge 인덱스 (target → edges)
  incomingEdges: Map<string, GraphEdge[]>;
}
```

## JSON 저장 형식

```json
{
  "version": "1.0.0",
  "metadata": {
    "projectRoot": "/path/to/project",
    "projectName": "my-app",
    "language": "typescript",
    "framework": "nestjs",
    "stats": {
      "totalFiles": 156,
      "totalFunctions": 423,
      "totalClasses": 87,
      "totalTypes": 156,
      "totalEdges": 1247,
      "avgComplexity": 4.2,
      "maxComplexity": 18
    },
    "timestamps": {
      "generatedAt": 1702234567890,
      "lastUpdatedAt": 1702234567890,
      "analysisTime": 2340
    }
  },
  "nodes": [
    {
      "id": "src/services/auth.ts:AuthService",
      "type": "class",
      "name": "AuthService",
      ...
    }
  ],
  "edges": [
    {
      "source": "src/services/auth.ts",
      "target": "src/types/user.ts",
      "type": "imports",
      ...
    }
  ],
  "fileHashes": {
    "src/services/auth.ts": "abc123...",
    "src/types/user.ts": "def456..."
  }
}
```

```

### analyzers/typescript-analyzer.md

```markdown
# TypeScript Analyzer

## 개요

TypeScript/JavaScript 코드베이스를 AST 기반으로 분석하여 그래프 노드와 엣지를 추출합니다.

## 분석 도구

```yaml
Primary_Tools:
  ts-morph: "TypeScript AST 조작 라이브러리"
  typescript: "공식 TypeScript 컴파일러 API"

Fallback_Tools:
  @babel/parser: "Babel AST 파서"
  acorn: "경량 JS 파서"

Pattern_Based:
  regex: "간단한 패턴 매칭 (AST 불가 시)"
```

## AST 기반 분석 (ts-morph)

### 프로젝트 초기화
```typescript
import { Project, SourceFile, SyntaxKind } from 'ts-morph';

function initProject(rootDir: string): Project {
  const project = new Project({
    tsConfigFilePath: `${rootDir}/tsconfig.json`,
    skipAddingFilesFromTsConfig: false,
  });

  // 또는 수동으로 파일 추가
  project.addSourceFilesAtPaths([
    `${rootDir}/src/**/*.ts`,
    `${rootDir}/src/**/*.tsx`,
  ]);

  return project;
}
```

### 파일 분석
```typescript
function analyzeFile(sourceFile: SourceFile): FileNode {
  const filePath = sourceFile.getFilePath();

  return {
    id: filePath,
    type: 'file',
    name: sourceFile.getBaseName(),
    path: filePath,
    extension: sourceFile.getExtension(),
    language: 'typescript',
    loc: sourceFile.getEndLineNumber(),
    imports: extractImports(sourceFile),
    exports: extractExports(sourceFile),
    hash: computeHash(sourceFile.getFullText()),
  };
}
```

### Import 추출
```typescript
function extractImports(sourceFile: SourceFile): ImportInfo[] {
  const imports: ImportInfo[] = [];

  // import 문 분석
  sourceFile.getImportDeclarations().forEach(importDecl => {
    const moduleSpecifier = importDecl.getModuleSpecifierValue();
    const namedImports = importDecl.getNamedImports();
    const defaultImport = importDecl.getDefaultImport();
    const namespaceImport = importDecl.getNamespaceImport();

    imports.push({
      source: sourceFile.getFilePath(),
      target: resolveModule(moduleSpecifier, sourceFile),
      type: 'imports',
      importType: defaultImport ? 'default' :
                  namespaceImport ? 'namespace' :
                  namedImports.length > 0 ? 'named' : 'side-effect',
      importedNames: [
        ...(defaultImport ? [defaultImport.getText()] : []),
        ...(namespaceImport ? [namespaceImport.getText()] : []),
        ...namedImports.map(n => n.getName()),
      ],
      isTypeOnly: importDecl.isTypeOnly(),
    });
  });

  // Dynamic import 분석
  sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)
    .filter(call => call.getExpression().getText() === 'import')
    .forEach(dynamicImport => {
      const arg = dynamicImport.getArguments()[0];
      if (arg) {
        imports.push({
          source: sourceFile.getFilePath(),
          target: arg.getText().replace(/['"]/g, ''),
          type: 'imports',
          importType: 'named',
          importedNames: [],
          isDynamic: true,
        });
      }
    });

  return imports;
}
```

### 함수 추출
```typescript
function extractFunctions(sourceFile: SourceFile): FunctionNode[] {
  const functions: FunctionNode[] = [];

  // 함수 선언
  sourceFile.getFunctions().forEach(func => {
    functions.push(analyzeFunctionDeclaration(func, sourceFile));
  });

  // Arrow 함수 (변수에 할당된)
  sourceFile.getVariableDeclarations().forEach(varDecl => {
    const initializer = varDecl.getInitializer();
    if (initializer?.getKind() === SyntaxKind.ArrowFunction) {
      functions.push(analyzeArrowFunction(varDecl, sourceFile));
    }
  });

  return functions;
}

function analyzeFunctionDeclaration(func: FunctionDeclaration, sourceFile: SourceFile): FunctionNode {
  const name = func.getName() || 'anonymous';
  const filePath = sourceFile.getFilePath();

  return {
    id: `${filePath}:${name}`,
    type: 'function',
    name,
    path: filePath,
    line: func.getStartLineNumber(),
    endLine: func.getEndLineNumber(),
    signature: generateSignature(func),
    fullSignature: func.getSignature()?.getDeclaration().getText() || '',
    params: func.getParameters().map(p => ({
      name: p.getName(),
      type: p.getType().getText(),
      optional: p.isOptional(),
      defaultValue: p.getInitializer()?.getText(),
    })),
    returnType: func.getReturnType().getText(),
    isAsync: func.isAsync(),
    isExported: func.isExported(),
    visibility: 'public',
    complexity: calculateComplexity(func),
    loc: func.getEndLineNumber() - func.getStartLineNumber() + 1,
    docstring: func.getJsDocs()[0]?.getDescription() || undefined,
    calls: extractFunctionCalls(func),
  };
}

function generateSignature(func: FunctionDeclaration): string {
  const name = func.getName() || 'anonymous';
  const params = func.getParameters()
    .map(p => `${p.getName()}: ${simplifyType(p.getType().getText())}`)
    .join(', ');
  const returnType = simplifyType(func.getReturnType().getText());

  return `${name}(${params}): ${returnType}`;
}

function simplifyType(type: string): string {
  // 복잡한 제네릭 단순화
  if (type.length > 50) {
    return type.substring(0, 47) + '...';
  }
  return type;
}
```

### 클래스 추출
```typescript
function extractClasses(sourceFile: SourceFile): ClassNode[] {
  return sourceFile.getClasses().map(cls => {
    const name = cls.getName() || 'AnonymousClass';
    const filePath = sourceFile.getFilePath();

    return {
      id: `${filePath}:${name}`,
      type: 'class',
      name,
      path: filePath,
      line: cls.getStartLineNumber(),
      endLine: cls.getEndLineNumber(),
      isAbstract: cls.isAbstract(),
      isExported: cls.isExported(),
      extends: cls.getExtends()?.getText(),
      implements: cls.getImplements().map(i => i.getText()),
      decorators: cls.getDecorators().map(d => d.getName()),
      properties: cls.getProperties().map(p => ({
        name: p.getName(),
        type: p.getType().getText(),
        visibility: getVisibility(p),
        isStatic: p.isStatic(),
        isReadonly: p.isReadonly(),
      })),
      methods: cls.getMethods().map(m => `${filePath}:${name}.${m.getName()}`),
      constructorParams: cls.getConstructors()[0]?.getParameters().map(p => ({
        name: p.getName(),
        type: p.getType().getText(),
        optional: p.isOptional(),
      })) || [],
      docstring: cls.getJsDocs()[0]?.getDescription(),
    };
  });
}
```

### 함수 호출 추출
```typescript
function extractFunctionCalls(node: Node): string[] {
  const calls: string[] = [];

  node.getDescendantsOfKind(SyntaxKind.CallExpression).forEach(call => {
    const expression = call.getExpression();
    let callName: string;

    if (expression.getKind() === SyntaxKind.PropertyAccessExpression) {
      // this.method() 또는 obj.method()
      callName = expression.getText();
    } else if (expression.getKind() === SyntaxKind.Identifier) {
      // directCall()
      callName = expression.getText();
    } else {
      return;
    }

    // 내장 함수 제외
    if (!isBuiltInFunction(callName)) {
      calls.push(callName);
    }
  });

  return [...new Set(calls)]; // 중복 제거
}

function isBuiltInFunction(name: string): boolean {
  const builtIns = [
    'console.log', 'console.error', 'console.warn',
    'JSON.parse', 'JSON.stringify',
    'Object.keys', 'Object.values', 'Object.entries',
    'Array.isArray', 'Promise.resolve', 'Promise.reject',
    'parseInt', 'parseFloat', 'isNaN', 'isFinite',
    'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
  ];
  return builtIns.includes(name) || name.startsWith('Math.');
}
```

### 순환 복잡도 계산
```typescript
function calculateComplexity(node: Node): number {
  let complexity = 1; // 기본 경로

  const countKinds = [
    SyntaxKind.IfStatement,
    SyntaxKind.ConditionalExpression,    // 삼항 연산자
    SyntaxKind.ForStatement,
    SyntaxKind.ForInStatement,
    SyntaxKind.ForOfStatement,
    SyntaxKind.WhileStatement,
    SyntaxKind.DoStatement,
    SyntaxKind.CatchClause,
    SyntaxKind.CaseClause,               // switch case
    SyntaxKind.BinaryExpression,         // && || 연산자
  ];

  countKinds.forEach(kind => {
    const descendants = node.getDescendantsOfKind(kind);
    if (kind === SyntaxKind.BinaryExpression) {
      // && || 만 카운트
      complexity += descendants.filter(d =>
        d.getOperatorToken().getText() === '&&' ||
        d.getOperatorToken().getText() === '||'
      ).length;
    } else {
      complexity += descendants.length;
    }
  });

  return complexity;
}
```

## 패턴 기반 분석 (Fallback)

AST 파싱이 불가능한 경우 정규식 기반 분석:

```typescript
const PATTERNS = {
  // Import
  importStatement: /import\s+(?:type\s+)?(?:(\w+)|{([^}]+)}|\*\s+as\s+(\w+))\s+from\s+['"]([^'"]+)['"]/g,
  dynamicImport: /import\(['"]([^'"]+)['"]\)/g,
  require: /require\(['"]([^'"]+)['"]\)/g,

  // Export
  namedExport: /export\s+(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/g,
  defaultExport: /export\s+default\s+(?:function\s+)?(\w+)?/g,
  reExport: /export\s+{([^}]+)}\s+from\s+['"]([^'"]+)['"]/g,

  // Function
  functionDecl: /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)(?:\s*:\s*([^\s{]+))?/g,
  arrowFunction: /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\([^)]*\)\s*(?::\s*[^=]+)?\s*=>/g,

  // Class
  classDecl: /(?:export\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([^\s{]+))?/g,
  classMethod: /(?:async\s+)?(\w+)\s*\(([^)]*)\)(?:\s*:\s*([^\s{]+))?\s*{/g,

  // Interface/Type
  interfaceDecl: /(?:export\s+)?interface\s+(\w+)(?:\s+extends\s+([^\s{]+))?/g,
  typeAlias: /(?:export\s+)?type\s+(\w+)\s*=/g,

  // Function Call
  functionCall: /(?<!function\s)(?<!class\s)(\w+)\s*\(/g,
};

function analyzeWithPatterns(content: string, filePath: string): PartialGraph {
  const nodes: GraphNode[] = [];
  const edges: GraphEdge[] = [];

  // Import 추출
  let match;
  while ((match = PATTERNS.importStatement.exec(content)) !== null) {
    const [_, defaultImport, namedImports, namespaceImport, modulePath] = match;
    edges.push({
      source: filePath,
      target: modulePath,
      type: 'imports',
      importedNames: [defaultImport, namespaceImport, ...(namedImports?.split(',').map(s => s.trim()) || [])].filter(Boolean),
    });
  }

  // Function 추출
  while ((match = PATTERNS.functionDecl.exec(content)) !== null) {
    const [fullMatch, name, params, returnType] = match;
    const line = content.substring(0, match.index).split('\n').length;
    nodes.push({
      id: `${filePath}:${name}`,
      type: 'function',
      name,
      path: filePath,
      line,
      signature: `${name}(${params}): ${returnType || 'void'}`,
    });
  }

  // Class 추출
  while ((match = PATTERNS.classDecl.exec(content)) !== null) {
    const [_, name, extendsClass, implementsInterfaces] = match;
    const line = content.substring(0, match.index).split('\n').length;
    nodes.push({
      id: `${filePath}:${name}`,
      type: 'class',
      name,
      path: filePath,
      line,
      extends: extendsClass,
      implements: implementsInterfaces?.split(',').map(s => s.trim()) || [],
    });
  }

  return { nodes, edges };
}
```

## NestJS 특화 분석

```typescript
const NESTJS_DECORATORS = {
  // Controller 관련
  Controller: { type: 'controller', routePrefix: true },
  Get: { type: 'route', method: 'GET' },
  Post: { type: 'route', method: 'POST' },
  Put: { type: 'route', method: 'PUT' },
  Delete: { type: 'route', method: 'DELETE' },
  Patch: { type: 'route', method: 'PATCH' },

  // 서비스 관련
  Injectable: { type: 'service' },

  // 모듈 관련
  Module: { type: 'module' },

  // Guard, Pipe 등
  UseGuards: { type: 'guard' },
  UsePipes: { type: 'pipe' },
  UseInterceptors: { type: 'interceptor' },
};

function analyzeNestJSDecorators(cls: ClassDeclaration): NestJSMetadata {
  const decorators = cls.getDecorators();
  const metadata: NestJSMetadata = {
    type: 'unknown',
    routes: [],
    dependencies: [],
  };

  decorators.forEach(dec => {
    const name = dec.getName();
    const config = NESTJS_DECORATORS[name];

    if (config) {
      metadata.type = config.type;

      if (config.routePrefix) {
        // @Controller('users')
        const arg = dec.getArguments()[0];
        metadata.routePrefix = arg?.getText().replace(/['"]/g, '');
      }
    }
  });

  // 메서드의 라우트 데코레이터 분석
  cls.getMethods().forEach(method => {
    method.getDecorators().forEach(dec => {
      const name = dec.getName();
      const config = NESTJS_DECORATORS[name];

      if (config?.type === 'route') {
        const arg = dec.getArguments()[0];
        metadata.routes.push({
          method: config.method,
          path: arg?.getText().replace(/['"]/g, '') || '',
          handler: method.getName(),
        });
      }
    });
  });

  // 생성자 의존성 주입 분석
  const constructor = cls.getConstructors()[0];
  if (constructor) {
    constructor.getParameters().forEach(param => {
      const type = param.getType().getText();
      if (!type.startsWith('string') && !type.startsWith('number')) {
        metadata.dependencies.push(type);
      }
    });
  }

  return metadata;
}
```

## 분석 성능 최적화

```typescript
// 병렬 처리
async function analyzeFilesInParallel(
  files: string[],
  concurrency: number = 4
): Promise<GraphNode[]> {
  const results: GraphNode[] = [];
  const chunks = chunkArray(files, concurrency);

  for (const chunk of chunks) {
    const chunkResults = await Promise.all(
      chunk.map(file => analyzeFile(file))
    );
    results.push(...chunkResults.flat());
  }

  return results;
}

// 증분 분석
async function incrementalAnalysis(
  project: Project,
  previousHashes: Record<string, string>
): Promise<IncrementalResult> {
  const changedFiles: string[] = [];
  const addedFiles: string[] = [];
  const removedFiles: string[] = [];

  const currentFiles = new Set(project.getSourceFiles().map(f => f.getFilePath()));
  const previousFiles = new Set(Object.keys(previousHashes));

  // 변경/추가 파일 감지
  for (const file of currentFiles) {
    const content = project.getSourceFile(file)?.getFullText() || '';
    const currentHash = computeHash(content);

    if (!previousFiles.has(file)) {
      addedFiles.push(file);
    } else if (previousHashes[file] !== currentHash) {
      changedFiles.push(file);
    }
  }

  // 삭제된 파일 감지
  for (const file of previousFiles) {
    if (!currentFiles.has(file)) {
      removedFiles.push(file);
    }
  }

  return { changedFiles, addedFiles, removedFiles };
}
```

```

codebase-graph | SkillHub