Skip to content
This repository was archived by the owner on Nov 12, 2025. It is now read-only.

Commit 26064ac

Browse files
committed
feat(common): 添加差异渲染函数
- 新增 render_diff 函数,用于将 Git 差异文本渲染为 HTML 格式的可视化对比视图 - 引入并使用 Diff2Html 库进行差异渲染 - 支持自定义渲染配置,如输出格式、颜色方案等
1 parent 136801c commit 26064ac

File tree

9 files changed

+78
-13
lines changed

9 files changed

+78
-13
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"axios": "npm:@candriajs/axios@1.0.14",
8585
"color-convert": "^3.1.0",
8686
"dayjs": "^1.11.13",
87+
"diff2html": "^3.4.51",
8788
"exec": "npm:@candriajs/exec@^1.0.2",
8889
"git-url-parse": "^16.0.1",
8990
"http-proxy-agent": "^7.0.2",

src/common/diff.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import * as Diff2Html from 'diff2html'
2+
import { ColorSchemeType } from 'diff2html/lib/types'
3+
4+
import { MissingDiffMsg } from './errorMsg'
5+
6+
/**
7+
* 渲染差异文本为HTML格式的可视化对比视图
8+
*
9+
* @param diff - 需要渲染的Git差异文本(diff格式字符串)
10+
* @param options - (可选) Diff2Html配置选项,用于自定义渲染行为
11+
* @returns 渲染后的HTML字符串
12+
*
13+
* @example
14+
* // 基本用法
15+
* const html = render_diff(diffText);
16+
*
17+
* @example
18+
* // 自定义配置
19+
* const html = render_diff(diffText, {
20+
* outputFormat: 'line-by-line',
21+
* colorScheme: ColorSchemeType.DARK
22+
* });
23+
*/
24+
export function render_diff (diff: string, options?: Diff2Html.Diff2HtmlConfig): string {
25+
if (!diff) throw new Error(MissingDiffMsg)
26+
const config: Diff2Html.Diff2HtmlConfig = {
27+
drawFileList: false,
28+
diffMaxChanges: 100,
29+
diffMaxLineLength: 300,
30+
matching: 'lines',
31+
colorScheme: ColorSchemeType.LIGHT,
32+
outputFormat: 'side-by-side',
33+
...options
34+
}
35+
const outputHtml = Diff2Html.html(diff, config)
36+
return outputHtml
37+
}

src/common/errorMsg.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,5 @@ export const MIssingSearchQueryMsg = '喵呜~ 搜索查询不能为空哦'
123123

124124
/** 其他 */
125125
export const RateLimitExceededMsg = '喵呜~ 访问速率受限啦 请等待1小时后再试 或 使用访问令牌提升限额'
126+
export const NetworkErrorMsg = '喵呜~ 网络错误,请检查网络连接或代理设置'
127+
export const MissingDiffMsg = '喵呜~ Diff 内容不能为空'

src/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from '@/common/diff'
12
export * from '@/common/errorMsg'
23
export * from '@/common/git'
34
export * from '@/common/markdown'

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
get_local_repo_default_branch,
99
get_relative_time,
1010
get_remote_repo_default_branch,
11+
render_diff,
1112
render_markdown
1213
} from '@/common'
1314
import { create_state_id } from '@/models'
@@ -46,6 +47,7 @@ export {
4647
get_local_repo_default_branch,
4748
get_relative_time,
4849
get_remote_repo_default_branch,
50+
render_diff,
4951
render_markdown
5052
}
5153
export default Client

src/models/base/request.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,11 @@ export class Request {
5454
data?: any,
5555
customHeaders?: Record<string, string>
5656
): Promise<ResponseType> {
57-
const url = `${this.baseUrl}/${path}`.replace(/\/+/g, '/')
57+
const url = `${this.baseUrl.replace(/\/+$/, '')}/${path.replace(/^\/+|\/+$/g, '')}`
5858
const config: AxiosRequestConfig = {
5959
headers: this.createHeaders(customHeaders),
6060
params,
61+
maxRedirects: 2,
6162
validateStatus: () => true
6263
}
6364

src/models/platform/github/client.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
MissingClientSecretMsg,
1313
MissingPrivateKeyMsg,
1414
MissingRequestPathMsg,
15+
NetworkErrorMsg,
1516
ProxyTypeNotSupportedMsg,
1617
RateLimitExceededMsg,
1718
UnauthorizedMsg
@@ -416,17 +417,6 @@ export class GitHubClient {
416417
return jwt.sign(payload, this.Private_Key!, { algorithm: 'RS256' })
417418
}
418419

419-
/**
420-
* 获取当前请求的配置
421-
* @returns 当前请求的配置对象
422-
*/
423-
private getCurrentRequestConfig (): RequestConfigType {
424-
return {
425-
...this.currentRequestConfig,
426-
url: this.api_url
427-
}
428-
}
429-
430420
/**
431421
* 设置当前请求的配置
432422
* @protected - 仅在父类与子类中方法中可访问
@@ -446,7 +436,7 @@ export class GitHubClient {
446436
* @returns 返回一个新的 Request 实例
447437
*/
448438
private createRequest (): Request {
449-
const { url, token, tokenType } = this.getCurrentRequestConfig()
439+
const { url, token, tokenType } = this.currentRequestConfig
450440
const proxyConfig = this.proxy?.type !== 'common' ? this.proxy : null
451441
const customHeaders = {
452442
'X-GitHub-Api-Version': '2022-11-28',
@@ -474,6 +464,7 @@ export class GitHubClient {
474464
})
475465
const request = this.createRequest()
476466
const req = await request.get(path, parms, customHeaders)
467+
if (req.statusCode === 500 && req.msg === 'Network Error') throw new Error(NetworkErrorMsg)
477468
if (req.statusCode === 401) throw new Error(UnauthorizedMsg)
478469
if ((req.statusCode === 403 || req.statusCode === 429) && req.headers['x-ratelimit-remaining'] === '0') {
479470
throw new Error(RateLimitExceededMsg)
@@ -509,6 +500,7 @@ export class GitHubClient {
509500
})
510501
const request = this.createRequest()
511502
const req = await request.post(path, data, customHeaders)
503+
if (req.statusCode === 500 && req.msg === 'Network Error') throw new Error(NetworkErrorMsg)
512504
if (req.statusCode === 401) throw new Error(UnauthorizedMsg)
513505
if ((req.statusCode === 403 || req.statusCode === 429) && req.headers['x-ratelimit-remaining'] === '0') {
514506
throw new Error(RateLimitExceededMsg)
@@ -546,6 +538,7 @@ export class GitHubClient {
546538
})
547539
const request = this.createRequest()
548540
const req = await request.patch(path, params, data, customHeaders)
541+
if (req.statusCode === 500 && req.msg === 'Network Error') throw new Error(NetworkErrorMsg)
549542
if (req.statusCode === 401) throw new Error(UnauthorizedMsg)
550543
if ((req.statusCode === 403 || req.statusCode === 429) && req.headers['x-ratelimit-remaining'] === '0') {
551544
throw new Error(RateLimitExceededMsg)
@@ -581,6 +574,7 @@ export class GitHubClient {
581574
})
582575
const request = this.createRequest()
583576
const req = await request.put(path, data, customHeaders)
577+
if (req.statusCode === 500 && req.msg === 'Network Error') throw new Error(NetworkErrorMsg)
584578
if (req.statusCode === 401) throw new Error(UnauthorizedMsg)
585579
if ((req.statusCode === 403 || req.statusCode === 429) && req.headers['x-ratelimit-remaining'] === '0') {
586580
throw new Error(RateLimitExceededMsg)
@@ -618,6 +612,7 @@ export class GitHubClient {
618612
})
619613
const request = this.createRequest()
620614
const req = await request.delete(path, params, data, customHeaders)
615+
if (req.statusCode === 500 && req.msg === 'Network Error') throw new Error(NetworkErrorMsg)
621616
if (req.statusCode === 401) throw new Error(UnauthorizedMsg)
622617
if ((req.statusCode === 403 || req.statusCode === 429) && req.headers['x-ratelimit-remaining'] === '0') {
623618
throw new Error(RateLimitExceededMsg)

src/models/platform/github/pull_request.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import type {
3434
GetPullRequestCommentInfoResponseType,
3535
GetPullRequestCommentsListParamType,
3636
GetPullRequestCommentsListResponseType,
37+
GetPullRequestDiffParamType,
38+
GetPullRequestDiffResponseType,
3739
GetPullRequestFilesListParamType,
3840
GetPullRequestFilesListResponseType,
3941
IssueLabelType,
@@ -873,6 +875,25 @@ export class Pull_Request extends GitHubClient {
873875
}
874876
}
875877

878+
public async get_pull_request_diff (
879+
options: GetPullRequestDiffParamType
880+
): Promise<ApiResponseType<GetPullRequestDiffResponseType>> {
881+
if (!(options.owner || options.repo)) throw new Error(MissingRepoOwnerOrNameMsg)
882+
if (!options.pr_number) throw new Error(MissingPullRequestNumberMsg)
883+
try {
884+
this.setRequestConfig({
885+
url: this.base_url
886+
})
887+
const { owner, repo, pr_number } = options
888+
const res = await this.get(`/${owner}/${repo}/pull/${pr_number}.diff`, null, {
889+
Accept: 'text/plain'
890+
})
891+
return res
892+
} catch (error) {
893+
throw new Error(`[GitHub] 获取拉取请求diff失败: ${(error as Error).message}`)
894+
}
895+
}
896+
876897
/**
877898
* 获取拉取请求文件列表
878899
* 权限:

src/types/platform/pull_request.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ export interface GetPullRequestFilesListParamType extends RepoBaseParamType, Pul
263263
/** 获取拉取请求文件列表响应类型 */
264264
export type GetPullRequestFilesListResponseType = Array<PullRequestFilesListType>
265265

266+
/** 获取拉取请求差异内容参数类型 */
267+
export type GetPullRequestDiffParamType = RepoBaseParamType & PullRequestNumberParamType
268+
/** 获取拉取请求差异内容响应类型 */
269+
export type GetPullRequestDiffResponseType = string
270+
266271
/** 获取拉取请求评论信息参数类型 */
267272
export type GetPullRequestCommentInfoParamType = RepoBaseParamType & CommentIdParamType
268273

0 commit comments

Comments
 (0)