wukong-gitlog-cli 1.0.34 → 1.0.35
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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/utils/authorNormalizer.mjs +41 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.0.35](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v1.0.34...v1.0.35) (2025-12-12)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* 🎸 createAuthorNormalizer ([a23a80e](https://github.com/tomatobybike/wukong-gitlog-cli/commit/a23a80e6d664cc5db89b40a63456d8e8d4b2c321))
|
|
11
|
+
|
|
5
12
|
### [1.0.34](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v1.0.33...v1.0.34) (2025-12-12)
|
|
6
13
|
|
|
7
14
|
|
package/package.json
CHANGED
|
@@ -1,42 +1,69 @@
|
|
|
1
1
|
// authorNormalizer.js
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
3
|
+
* 按邮箱自动归一化作者名字
|
|
5
4
|
* - 优先使用中文姓名
|
|
6
5
|
* - 如果同邮箱出现多个非中文名,保持第一个
|
|
7
|
-
* -
|
|
6
|
+
* - 自动清理空格与不可见字符
|
|
7
|
+
* - 保留原始 author 以便 debug
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
9
|
export function createAuthorNormalizer() {
|
|
11
10
|
const map = {} // email -> canonical name
|
|
11
|
+
const originalMap = {} // email -> 原始所有 author 名
|
|
12
12
|
|
|
13
13
|
function isChinese(str) {
|
|
14
14
|
return /[\u4e00-\u9fa5]/.test(str)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
function cleanName(str) {
|
|
18
|
+
if (!str) return ''
|
|
19
|
+
return str
|
|
20
|
+
// eslint-disable-next-line no-misleading-character-class
|
|
21
|
+
.replace(/[\u200B\u200C\u200D\uFEFF]/g, '') // 去零宽空格
|
|
22
|
+
.replace(/\s+/g, ' ') // 多空格 -> 单空格
|
|
23
|
+
.trim()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function cleanEmail(str) {
|
|
27
|
+
return (str || '').trim()
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
function getAuthor(name, email) {
|
|
18
|
-
|
|
31
|
+
const cleanedName = cleanName(name)
|
|
32
|
+
const cleanedEmail = cleanEmail(email)
|
|
33
|
+
|
|
34
|
+
if (!cleanedEmail) return cleanedName || 'Unknown'
|
|
19
35
|
|
|
20
|
-
|
|
36
|
+
// 记录原始 author 便于 debug
|
|
37
|
+
if (!originalMap[cleanedEmail]) originalMap[cleanedEmail] = new Set()
|
|
38
|
+
if (cleanedName) originalMap[cleanedEmail].add(cleanedName)
|
|
39
|
+
|
|
40
|
+
const canonical = map[cleanedEmail]
|
|
21
41
|
|
|
22
42
|
// 首次遇到这个邮箱 → 记录当前作者名
|
|
23
43
|
if (!canonical) {
|
|
24
|
-
map[
|
|
25
|
-
return
|
|
44
|
+
map[cleanedEmail] = cleanedName || cleanedEmail
|
|
45
|
+
return map[cleanedEmail]
|
|
26
46
|
}
|
|
27
47
|
|
|
28
|
-
//
|
|
29
|
-
if (isChinese(
|
|
30
|
-
map[
|
|
31
|
-
return
|
|
48
|
+
// 新名是中文 → 覆盖旧的
|
|
49
|
+
if (isChinese(cleanedName)) {
|
|
50
|
+
map[cleanedEmail] = cleanedName
|
|
51
|
+
return map[cleanedEmail]
|
|
32
52
|
}
|
|
33
53
|
|
|
34
|
-
//
|
|
54
|
+
// 新名非中文 → 保留已有中文或旧名
|
|
35
55
|
return canonical
|
|
36
56
|
}
|
|
37
57
|
|
|
38
58
|
return {
|
|
39
59
|
getAuthor,
|
|
40
|
-
getMap: () => map
|
|
60
|
+
getMap: () => map,
|
|
61
|
+
getOriginalMap: () => {
|
|
62
|
+
const res = {}
|
|
63
|
+
for (const [email, names] of Object.entries(originalMap)) {
|
|
64
|
+
res[email] = Array.from(names)
|
|
65
|
+
}
|
|
66
|
+
return res
|
|
67
|
+
}
|
|
41
68
|
}
|
|
42
69
|
}
|