cciwon-code-review-cli 2.0.4 → 2.0.6
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/bin/code-review.js +166 -2
- package/package.json +1 -1
package/bin/code-review.js
CHANGED
|
@@ -5,6 +5,8 @@ const chalk = require('chalk');
|
|
|
5
5
|
const ora = require('ora');
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
const os = require('os');
|
|
8
10
|
const CodeReviewClient = require('../lib/api-client');
|
|
9
11
|
|
|
10
12
|
const program = new Command();
|
|
@@ -19,6 +21,165 @@ program
|
|
|
19
21
|
const SERVER_URL = process.env.CODE_REVIEW_SERVER || 'http://211.56.247.71:8000';
|
|
20
22
|
const client = new CodeReviewClient(SERVER_URL);
|
|
21
23
|
|
|
24
|
+
// ==========================================
|
|
25
|
+
// Diff 파싱 및 VSCode 표시 함수
|
|
26
|
+
// ==========================================
|
|
27
|
+
function parseDiffAndShowInVSCode(reviewText, originalFilePath) {
|
|
28
|
+
const lines = reviewText.split('\n');
|
|
29
|
+
const diffs = [];
|
|
30
|
+
let currentDiff = null;
|
|
31
|
+
let reviewContent = [];
|
|
32
|
+
let inDiffBlock = false;
|
|
33
|
+
|
|
34
|
+
// 디버깅: 전체 응답 확인
|
|
35
|
+
console.log(chalk.gray('\n[디버그] 응답 텍스트 일부:'));
|
|
36
|
+
console.log(chalk.gray(reviewText.substring(0, 500) + '...\n'));
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < lines.length; i++) {
|
|
39
|
+
const line = lines[i];
|
|
40
|
+
|
|
41
|
+
// unified diff 시작 감지 (--- 와 +++ 패턴)
|
|
42
|
+
// "--- 원본" 또는 "--- a/file" 형식도 지원
|
|
43
|
+
if ((line.startsWith('---') || line.includes('--- ')) &&
|
|
44
|
+
i + 1 < lines.length &&
|
|
45
|
+
(lines[i + 1].startsWith('+++') || lines[i + 1].includes('+++ '))) {
|
|
46
|
+
inDiffBlock = true;
|
|
47
|
+
currentDiff = {
|
|
48
|
+
filename: null,
|
|
49
|
+
diffLines: [line, lines[i + 1]]
|
|
50
|
+
};
|
|
51
|
+
console.log(chalk.yellow(`\n[디버그] diff 블록 발견: ${line}`));
|
|
52
|
+
i++; // +++ 라인 건너뛰기
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// diff 블록 내부
|
|
57
|
+
if (inDiffBlock) {
|
|
58
|
+
if (line.startsWith('@@') || line.startsWith('-') || line.startsWith('+') || line.startsWith(' ')) {
|
|
59
|
+
currentDiff.diffLines.push(line);
|
|
60
|
+
} else if (line.trim() === '' || line.startsWith('===')) {
|
|
61
|
+
// diff 블록 종료
|
|
62
|
+
if (currentDiff) {
|
|
63
|
+
diffs.push(currentDiff);
|
|
64
|
+
console.log(chalk.yellow(`[디버그] diff 블록 종료 (라인 수: ${currentDiff.diffLines.length})`));
|
|
65
|
+
currentDiff = null;
|
|
66
|
+
}
|
|
67
|
+
inDiffBlock = false;
|
|
68
|
+
reviewContent.push(line);
|
|
69
|
+
} else {
|
|
70
|
+
currentDiff.diffLines.push(line);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
// 일반 리뷰 텍스트
|
|
74
|
+
reviewContent.push(line);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 마지막 diff 저장
|
|
79
|
+
if (currentDiff) {
|
|
80
|
+
diffs.push(currentDiff);
|
|
81
|
+
console.log(chalk.yellow(`[디버그] 마지막 diff 블록 저장 (라인 수: ${currentDiff.diffLines.length})`));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log(chalk.cyan(`\n[디버그] 총 ${diffs.length}개의 diff 블록 발견\n`));
|
|
85
|
+
|
|
86
|
+
// diff가 있으면 VSCode로 표시
|
|
87
|
+
if (diffs.length > 0) {
|
|
88
|
+
diffs.forEach((diff, index) => {
|
|
89
|
+
try {
|
|
90
|
+
// 임시 디렉토리 생성
|
|
91
|
+
const tmpDir = path.join(os.tmpdir(), `code-review-${Date.now()}-${index}`);
|
|
92
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
93
|
+
|
|
94
|
+
// 원본/수정본 파일 생성
|
|
95
|
+
const originalFile = path.join(tmpDir, 'original' + path.extname(originalFilePath));
|
|
96
|
+
const modifiedFile = path.join(tmpDir, 'modified' + path.extname(originalFilePath));
|
|
97
|
+
|
|
98
|
+
// diff에서 원본/수정본 코드 추출
|
|
99
|
+
const { original, modified } = extractCodeFromDiff(diff.diffLines, originalFilePath);
|
|
100
|
+
|
|
101
|
+
fs.writeFileSync(originalFile, original);
|
|
102
|
+
fs.writeFileSync(modifiedFile, modified);
|
|
103
|
+
|
|
104
|
+
// VSCode diff 뷰어 열기
|
|
105
|
+
try {
|
|
106
|
+
execSync(`code --diff "${originalFile}" "${modifiedFile}"`, { stdio: 'ignore' });
|
|
107
|
+
console.log(chalk.green(`\n📝 VSCode에서 diff를 열었습니다 (${index + 1}/${diffs.length})`));
|
|
108
|
+
} catch (e) {
|
|
109
|
+
console.log(chalk.yellow(`\n⚠️ VSCode를 열 수 없습니다. diff를 수동으로 확인하세요:`));
|
|
110
|
+
console.log(chalk.gray(diff.diffLines.join('\n')));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 임시 파일은 5분 후 자동 삭제
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
try {
|
|
116
|
+
fs.unlinkSync(originalFile);
|
|
117
|
+
fs.unlinkSync(modifiedFile);
|
|
118
|
+
fs.rmdirSync(tmpDir);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// 무시
|
|
121
|
+
}
|
|
122
|
+
}, 5 * 60 * 1000);
|
|
123
|
+
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(chalk.red(`diff 처리 실패: ${error.message}`));
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 리뷰 텍스트만 반환
|
|
131
|
+
return reviewContent.join('\n').trim();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// diff에서 원본/수정본 추출
|
|
135
|
+
function extractCodeFromDiff(diffLines, originalFilePath) {
|
|
136
|
+
let original = '';
|
|
137
|
+
let modified = '';
|
|
138
|
+
|
|
139
|
+
// 원본 파일이 있으면 읽기
|
|
140
|
+
if (fs.existsSync(originalFilePath)) {
|
|
141
|
+
original = fs.readFileSync(originalFilePath, 'utf-8');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// diff 라인을 파싱해서 수정본 생성
|
|
145
|
+
const originalLines = original.split('\n');
|
|
146
|
+
const modifiedLines = [];
|
|
147
|
+
|
|
148
|
+
let lineNum = 0;
|
|
149
|
+
for (const line of diffLines) {
|
|
150
|
+
if (line.startsWith('@@')) {
|
|
151
|
+
// @@ -15,2 +15,2 @@ 형식 파싱
|
|
152
|
+
const match = line.match(/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);
|
|
153
|
+
if (match) {
|
|
154
|
+
lineNum = parseInt(match[1]) - 1;
|
|
155
|
+
}
|
|
156
|
+
} else if (line.startsWith('-')) {
|
|
157
|
+
// 삭제된 라인 (원본에만 있음)
|
|
158
|
+
lineNum++;
|
|
159
|
+
} else if (line.startsWith('+')) {
|
|
160
|
+
// 추가된 라인 (수정본에만 있음)
|
|
161
|
+
modifiedLines.push(line.substring(1));
|
|
162
|
+
} else if (line.startsWith(' ')) {
|
|
163
|
+
// 변경 없는 라인
|
|
164
|
+
if (lineNum < originalLines.length) {
|
|
165
|
+
modifiedLines.push(originalLines[lineNum]);
|
|
166
|
+
lineNum++;
|
|
167
|
+
} else {
|
|
168
|
+
modifiedLines.push(line.substring(1));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 수정본이 비어있으면 원본을 기반으로 단순 패치 시도
|
|
174
|
+
if (modifiedLines.length === 0) {
|
|
175
|
+
modified = original;
|
|
176
|
+
} else {
|
|
177
|
+
modified = modifiedLines.join('\n');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return { original, modified };
|
|
181
|
+
}
|
|
182
|
+
|
|
22
183
|
// ==========================================
|
|
23
184
|
// 폴더 리뷰 명령어
|
|
24
185
|
// ==========================================
|
|
@@ -108,9 +269,12 @@ program
|
|
|
108
269
|
|
|
109
270
|
spinner.succeed(chalk.green('✅ 리뷰 완료!'));
|
|
110
271
|
|
|
111
|
-
//
|
|
272
|
+
// diff를 파싱하고 VSCode로 표시, 리뷰 텍스트만 반환
|
|
273
|
+
const reviewTextOnly = parseDiffAndShowInVSCode(result.review, absolutePath);
|
|
274
|
+
|
|
275
|
+
// 결과 출력 (리뷰 텍스트만)
|
|
112
276
|
console.log('\n' + chalk.bold.cyan('=== 코드 리뷰 결과 ==='));
|
|
113
|
-
console.log(
|
|
277
|
+
console.log(reviewTextOnly);
|
|
114
278
|
|
|
115
279
|
} catch (error) {
|
|
116
280
|
spinner.fail(chalk.red('❌ 리뷰 실패'));
|