-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathformatter.js
More file actions
132 lines (108 loc) · 3.91 KB
/
Copy pathformatter.js
File metadata and controls
132 lines (108 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
(function (root) {
"use strict";
class FormatError extends Error {
constructor(message, code) {
super(message);
this.name = "FormatError";
this.code = code;
}
}
function joinFragments(previous, next) {
if (!previous) return next;
if (!next) return previous;
const needsSpace = /[A-Za-z0-9]$/.test(previous) && /^[A-Za-z0-9]/.test(next);
return `${previous}${needsSpace ? " " : ""}${next}`;
}
function readSectionMarker(line) {
const withColon = line.match(/^(问题|处理)\s*[::]\s*(.*)$/u);
if (withColon) {
return { section: withColon[1] === "问题" ? "problems" : "actions", rest: withColon[2] };
}
if (line === "问题" || line === "处理") {
return { section: line === "问题" ? "problems" : "actions", rest: "" };
}
return null;
}
function readItem(line) {
const numbered = line.match(/^(?:\d+\s*[.、.)]|[((]\s*\d+\s*[))])\s*(.*)$/u);
if (numbered) return numbered[1].trim();
const bulleted = line.match(/^[-*•·]\s*(.*)$/u);
if (bulleted) return bulleted[1].trim();
return null;
}
function formatGitCopy(input) {
if (typeof input !== "string" || !input.trim()) {
throw new FormatError("请先粘贴需要整理的 Git 文案。", "EMPTY_INPUT");
}
const lines = input
.replace(/^\uFEFF/u, "")
.replace(/\r\n?/g, "\n")
.split("\n")
.map((line) => line.trim());
const titleParts = [];
const sections = { problems: [], actions: [] };
let currentSection = null;
let foundProblems = false;
let foundActions = false;
function addContent(sectionName, content) {
if (!content) return;
const item = readItem(content);
if (item !== null) {
if (item) sections[sectionName].push(item);
return;
}
const items = sections[sectionName];
if (items.length === 0) {
items.push(content);
} else {
items[items.length - 1] = joinFragments(items[items.length - 1], content);
}
}
for (const line of lines) {
if (!line) continue;
const marker = readSectionMarker(line);
if (marker) {
if (marker.section === "problems") {
if (foundActions) {
throw new FormatError("“问题”分区应位于“处理”分区之前。", "INVALID_SECTION_ORDER");
}
foundProblems = true;
} else {
foundActions = true;
}
currentSection = marker.section;
addContent(currentSection, marker.rest);
continue;
}
if (!currentSection) {
titleParts.push(line);
} else {
addContent(currentSection, line);
}
}
const title = titleParts.reduce(joinFragments, "");
if (!title) {
throw new FormatError("请在第一行填写总标题。", "MISSING_TITLE");
}
if (!foundProblems) {
throw new FormatError("未找到“问题:”分区,请补充后再格式化。", "MISSING_PROBLEMS_SECTION");
}
if (!foundActions) {
throw new FormatError("未找到“处理:”分区,请补充后再格式化。", "MISSING_ACTIONS_SECTION");
}
if (sections.problems.length === 0) {
throw new FormatError("“问题:”下至少需要一条内容。", "EMPTY_PROBLEMS");
}
if (sections.actions.length === 0) {
throw new FormatError("“处理:”下至少需要一条内容。", "EMPTY_ACTIONS");
}
const problemLines = sections.problems.map((item, index) => `${index + 1}. ${item}`);
const actionLines = sections.actions.map((item, index) => `${index + 1}. ${item}`);
return [title, "", "问题:", ...problemLines, "", "处理:", ...actionLines].join("\n");
}
const api = { FormatError, formatGitCopy, joinFragments };
if (typeof module !== "undefined" && module.exports) {
module.exports = api;
}
root.GitCopyFormatter = api;
})(typeof globalThis !== "undefined" ? globalThis : this);