@gitsense/gsc-utils 0.2.25 → 0.2.27
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/README.md +380 -62
- package/dist/gsc-utils.cjs.js +2203 -331
- package/dist/gsc-utils.esm.js +2203 -331
- package/package.json +1 -1
- package/src/AnalyzerUtils/cloner.js +149 -0
- package/src/AnalyzerUtils/constants.js +1 -1
- package/src/AnalyzerUtils/defaultPromptLoader.js +10 -10
- package/src/AnalyzerUtils/discovery.js +48 -39
- package/src/AnalyzerUtils/index.js +13 -7
- package/src/AnalyzerUtils/instructionLoader.js +6 -6
- package/src/AnalyzerUtils/jsonParser.js +35 -0
- package/src/AnalyzerUtils/management.js +6 -6
- package/src/AnalyzerUtils/saver.js +5 -5
- package/src/AnalyzerUtils/schemaLoader.js +194 -26
- package/src/AnalyzerUtils/updater.js +187 -0
- package/src/CodeBlockUtils/blockProcessor.js +14 -32
- package/src/CodeBlockUtils/index.js +7 -6
- package/src/CodeBlockUtils/lineageTracer.js +95 -0
- package/src/CompactChatUtils/CompactedMessageUtils.js +224 -0
- package/src/CompactChatUtils/README.md +321 -0
- package/src/CompactChatUtils/ReferenceMessageUtils.js +143 -0
- package/src/CompactChatUtils/index.js +40 -0
- package/src/ContextUtils.js +40 -4
- package/src/DomUtils.js +86 -12
- package/src/GSToolBlockUtils.js +66 -1
- package/src/GitSenseChatUtils.js +58 -5
- package/src/MarkdownUtils.js +4 -1
- package/src/MessageUtils.js +1 -1
- package/src/MetaRawResultUtils.js +244 -0
- package/src/PatchUtils/constants.js +9 -3
- package/src/PatchUtils/patchParser.js +60 -36
- package/src/PatchUtils/patchVerifier/detectAndFixOverlappingHunks.js +1 -1
- package/src/SVGUtils.js +57 -0
- package/src/SharedUtils/stringUtils.js +303 -0
- package/src/CodeBlockUtils/blockProcessor.js.rej +0 -8
package/src/MessageUtils.js
CHANGED
|
@@ -363,7 +363,7 @@ function getMessageContentType(messageContent) {
|
|
|
363
363
|
return 'regular'; // Handle non-string input gracefully
|
|
364
364
|
}
|
|
365
365
|
const trimmedContent = messageContent.trimStart(); // Check from the beginning, ignoring leading whitespace
|
|
366
|
-
if (trimmedContent.startsWith('## FILE CONTENT')) {
|
|
366
|
+
if (trimmedContent.startsWith('## FILE CONTENT') || trimmedContent.startsWith('## REFERENCE FILE CONTENT')) {
|
|
367
367
|
return 'file-content-context';
|
|
368
368
|
} else if (trimmedContent.startsWith('## OVERVIEW')) {
|
|
369
369
|
return 'overview-context';
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component: MetaRawResultUtils
|
|
3
|
+
* Block-UUID: 8a4d235b-a9d3-44b8-9c08-47b3678ba1c0
|
|
4
|
+
* Parent-UUID: N/A
|
|
5
|
+
* Version: 1.0.0
|
|
6
|
+
* Description: Utility for parsing and extracting mappings from meta-raw-result messages
|
|
7
|
+
* Language: JavaScript
|
|
8
|
+
* Created-at: 2025-11-15T19:15:00.000Z
|
|
9
|
+
* Authors: GLM-4.6 (v1.0.0)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const ChatUtils = require('./ChatUtils');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extracts and parses all meta-raw-result messages from a chat
|
|
17
|
+
* @param {Object} chat - The chat object containing messages
|
|
18
|
+
* @param {string} model - The model name (optional, for message filtering)
|
|
19
|
+
* @returns {Map<number, Object>} Map of chatId to file metadata
|
|
20
|
+
*/
|
|
21
|
+
function extractMetaRawResultMappings(chat, model = null) {
|
|
22
|
+
const mappings = new Map();
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Get all messages from the chat
|
|
26
|
+
const allMessages = ChatUtils.getChatMessages(chat, model);
|
|
27
|
+
|
|
28
|
+
// Filter for meta-raw-result messages
|
|
29
|
+
const metaRawMessages = allMessages.filter(msg => isMetaRawResultMessage(msg));
|
|
30
|
+
|
|
31
|
+
// Parse each meta-raw-result message
|
|
32
|
+
for (const message of metaRawMessages) {
|
|
33
|
+
const messageMappings = parseMetaRawResultContent(message.message);
|
|
34
|
+
|
|
35
|
+
// Merge mappings into the main map
|
|
36
|
+
for (const [chatId, fileInfo] of messageMappings) {
|
|
37
|
+
mappings.set(chatId, fileInfo);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return mappings;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('Error extracting meta-raw-result mappings:', error);
|
|
44
|
+
return mappings;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validates if a message is a meta-raw-result message
|
|
50
|
+
* @param {Object} message - The message object to validate
|
|
51
|
+
* @returns {boolean} True if message is meta-raw-result type
|
|
52
|
+
*/
|
|
53
|
+
function isMetaRawResultMessage(message) {
|
|
54
|
+
if (!message || !message.message) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check if message type is meta-raw-result
|
|
59
|
+
if (message.type === 'meta-raw-result') {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parses a single meta-raw-result message content
|
|
68
|
+
* @param {string} messageContent - The message content to parse
|
|
69
|
+
* @returns {Map<number, Object>} Map of chatId to file metadata
|
|
70
|
+
*/
|
|
71
|
+
function parseMetaRawResultContent(messageContent) {
|
|
72
|
+
const mappings = new Map();
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
// Split content into lines
|
|
76
|
+
const lines = messageContent.split('\n');
|
|
77
|
+
|
|
78
|
+
// Find the data section
|
|
79
|
+
let dataSectionStart = -1;
|
|
80
|
+
for (let i = 0; i < lines.length; i++) {
|
|
81
|
+
if (lines[i].trimStart().startsWith('## Data ')) {
|
|
82
|
+
dataSectionStart = i;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (dataSectionStart === -1) {
|
|
88
|
+
return mappings; // No data section found
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Find the table header (line with |)
|
|
92
|
+
let headerLine = -1;
|
|
93
|
+
for (let i = dataSectionStart; i < lines.length; i++) {
|
|
94
|
+
if (lines[i].includes('|') && lines[i].includes('Chat ID')) {
|
|
95
|
+
headerLine = i;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (headerLine === -1) {
|
|
101
|
+
return mappings; // No table header found
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Find the separator line (|---|---|...)
|
|
105
|
+
let separatorLine = -1;
|
|
106
|
+
for (let i = headerLine + 1; i < lines.length; i++) {
|
|
107
|
+
if (lines[i].match(/^\|[\s\-\|]*\|$/)) {
|
|
108
|
+
separatorLine = i;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (separatorLine === -1) {
|
|
114
|
+
return mappings; // No separator found
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Parse data rows (everything after the separator)
|
|
118
|
+
for (let i = separatorLine + 1; i < lines.length; i++) {
|
|
119
|
+
const line = lines[i].trim();
|
|
120
|
+
|
|
121
|
+
// Skip empty lines or separator lines
|
|
122
|
+
if (!line || line.match(/^\|[\s\-\|]*\|$/) || !line.includes('|')) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Parse the table row
|
|
127
|
+
const fileInfo = parseTableRow(line);
|
|
128
|
+
if (fileInfo && fileInfo.id) {
|
|
129
|
+
mappings.set(fileInfo.id, fileInfo);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return mappings;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.error('Error parsing meta-raw-result content:', error);
|
|
136
|
+
return mappings;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Parses a single table row from meta-raw-result content
|
|
142
|
+
* @param {string} rowLine - The table row line to parse
|
|
143
|
+
* @returns {Object|null} Parsed file information object or null if parsing failed
|
|
144
|
+
*/
|
|
145
|
+
function parseTableRow(rowLine) {
|
|
146
|
+
try {
|
|
147
|
+
// Split the row by | and clean up
|
|
148
|
+
const cells = rowLine.split('|').map(cell => cell.trim()).filter(cell => cell);
|
|
149
|
+
|
|
150
|
+
if (cells.length < 6) {
|
|
151
|
+
return null; // Not enough columns
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Extract basic information from the table cells
|
|
155
|
+
const repo = cells[0];
|
|
156
|
+
const branch = cells[1];
|
|
157
|
+
const filePath = cells[2];
|
|
158
|
+
const language = cells[3];
|
|
159
|
+
const chatId = parseInt(cells[4], 10);
|
|
160
|
+
|
|
161
|
+
// Parse file path to extract name and path
|
|
162
|
+
const pathParts = filePath.split('/');
|
|
163
|
+
const name = pathParts[pathParts.length - 1];
|
|
164
|
+
const path = filePath;
|
|
165
|
+
|
|
166
|
+
// Create full path
|
|
167
|
+
const fullPath = `${repo}/${path}`;
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
id: chatId,
|
|
171
|
+
name: name,
|
|
172
|
+
path: path,
|
|
173
|
+
repo: repo,
|
|
174
|
+
branch: branch,
|
|
175
|
+
language: language,
|
|
176
|
+
fullPath: fullPath
|
|
177
|
+
};
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error('Error parsing table row:', error);
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Parses size string to bytes
|
|
186
|
+
* @param {string} sizeStr - Size string (e.g., "1.2 KB", "500 B")
|
|
187
|
+
* @returns {number} Size in bytes
|
|
188
|
+
*/
|
|
189
|
+
function parseSize(sizeStr) {
|
|
190
|
+
if (!sizeStr || sizeStr === 'N/A') {
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const match = sizeStr.match(/^([\d.]+)\s*(B|KB|MB|GB)?$/i);
|
|
195
|
+
if (!match) {
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const value = parseFloat(match[1]);
|
|
200
|
+
const unit = (match[2] || 'B').toUpperCase();
|
|
201
|
+
|
|
202
|
+
switch (unit) {
|
|
203
|
+
case 'B': return Math.round(value);
|
|
204
|
+
case 'KB': return Math.round(value * 1024);
|
|
205
|
+
case 'MB': return Math.round(value * 1024 * 1024);
|
|
206
|
+
case 'GB': return Math.round(value * 1024 * 1024 * 1024);
|
|
207
|
+
default: return 0;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Parses tokens string to number
|
|
213
|
+
* @param {string} tokensStr - Tokens string (e.g., "1.2k", "500")
|
|
214
|
+
* @returns {number} Token count
|
|
215
|
+
*/
|
|
216
|
+
function parseTokens(tokensStr) {
|
|
217
|
+
if (!tokensStr || tokensStr === 'N/A') {
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const match = tokensStr.match(/^([\d.]+)(k|m|b)?$/i);
|
|
222
|
+
if (!match) {
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const value = parseFloat(match[1]);
|
|
227
|
+
const suffix = (match[2] || '').toLowerCase();
|
|
228
|
+
|
|
229
|
+
switch (suffix) {
|
|
230
|
+
case 'k': return Math.round(value * 1000);
|
|
231
|
+
case 'm': return Math.round(value * 1000000);
|
|
232
|
+
case 'b': return Math.round(value * 1000000000);
|
|
233
|
+
default: return Math.round(value);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
module.exports = {
|
|
238
|
+
extractMetaRawResultMappings,
|
|
239
|
+
isMetaRawResultMessage,
|
|
240
|
+
parseMetaRawResultContent,
|
|
241
|
+
parseTableRow,
|
|
242
|
+
parseSize,
|
|
243
|
+
parseTokens
|
|
244
|
+
};
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Component: PatchUtils Constants
|
|
3
3
|
* Block-UUID: c6747054-2c8b-461f-910d-0fd725d9a350
|
|
4
4
|
* Parent-UUID: 32adc00e-7509-4219-8e40-6c1319371db9
|
|
5
|
-
* Version: 2.
|
|
5
|
+
* Version: 2.1.0
|
|
6
6
|
* Description: Contains shared constants and regular expressions used by the enhanced patch utilities.
|
|
7
7
|
* Language: JavaScript
|
|
8
8
|
* Created-at: 2025-05-14T16:55:00.000Z
|
|
9
|
-
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Claude 3.7 Sonnet (v2.0.0)
|
|
9
|
+
* Authors: Gemini 2.5 Flash Thinking (v1.0.0), Claude 3.7 Sonnet (v2.0.0), Qwen 3 Coder 480B - Cerebras (v2.1.0)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
|
|
@@ -34,10 +34,14 @@ const DEFAULT_SLIDING_WINDOW_SIZE = 3;
|
|
|
34
34
|
// If context is longer than this, we'll use a sliding window approach
|
|
35
35
|
const MAX_CONTEXT_LINES_FOR_DIRECT_MATCH = 10;
|
|
36
36
|
|
|
37
|
-
//
|
|
37
|
+
// Traditional patch markers
|
|
38
38
|
const PATCH_START_MARKER = '# --- PATCH START MARKER ---';
|
|
39
39
|
const PATCH_END_MARKER = '# --- PATCH END MARKER ---';
|
|
40
40
|
|
|
41
|
+
// Abbreviated patch markers
|
|
42
|
+
const ABBREVIATED_PATCH_START_MARKER = '# --- ABBREVIATED PATCH START MARKER ---';
|
|
43
|
+
const ABBREVIATED_PATCH_END_MARKER = '# --- ABBREVIATED PATCH END MARKER ---';
|
|
44
|
+
|
|
41
45
|
// Patch metadata header
|
|
42
46
|
const PATCH_METADATA_HEADER = '# Patch Metadata';
|
|
43
47
|
|
|
@@ -65,6 +69,8 @@ module.exports = {
|
|
|
65
69
|
MAX_CONTEXT_LINES_FOR_DIRECT_MATCH,
|
|
66
70
|
PATCH_START_MARKER,
|
|
67
71
|
PATCH_END_MARKER,
|
|
72
|
+
ABBREVIATED_PATCH_START_MARKER,
|
|
73
|
+
ABBREVIATED_PATCH_END_MARKER,
|
|
68
74
|
PATCH_METADATA_HEADER,
|
|
69
75
|
REQUIRED_METADATA_FIELDS,
|
|
70
76
|
ORIGINAL_FILE_HEADER,
|
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
* Component: PatchUtils Parser
|
|
3
3
|
* Block-UUID: ce634df9-ff99-482a-a261-56ab34a2546e
|
|
4
4
|
* Parent-UUID: fcc85ec1-0146-40bf-a937-6f7928258cbf
|
|
5
|
-
* Version: 1.
|
|
6
|
-
* Description: Handles parsing, validation, extraction, and detection of traditional unified diff patches. Extracts metadata and raw diff content.
|
|
5
|
+
* Version: 1.2.0
|
|
6
|
+
* Description: Handles parsing, validation, extraction, and detection of traditional unified diff patches and abbreviated patches. Extracts metadata and raw diff content.
|
|
7
7
|
* Language: JavaScript
|
|
8
8
|
* Created-at: 2025-04-18T02:59:04.322Z
|
|
9
|
-
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0)
|
|
9
|
+
* Authors: Gemini 2.5 Pro (v1.0.0), Gemini 2.5 Pro (v1.1.0), Qwen 3 Coder 480B - Cerebras (v1.2.0)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
const { isValidVersion } = require('../SharedUtils/versionUtils'); // Assuming SharedUtils is one level up
|
|
14
|
+
const { PATCH_START_MARKER, PATCH_END_MARKER, PATCH_METADATA_HEADER,
|
|
15
|
+
ORIGINAL_FILE_HEADER, MODIFIED_FILE_HEADER, ABBREVIATED_PATCH_START_MARKER,
|
|
16
|
+
ABBREVIATED_PATCH_END_MARKER } = require('./constants');
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* Determines the type of patch format used based on markers.
|
|
17
|
-
*
|
|
20
|
+
* Looks for traditional unified diff markers or abbreviated patch markers.
|
|
18
21
|
* @param {string} patchText - The patch text
|
|
19
|
-
* @returns {string} 'traditional', or 'unknown'
|
|
22
|
+
* @returns {string} 'traditional', 'abbreviated', or 'unknown'
|
|
20
23
|
*/
|
|
21
24
|
function determinePatchFormat(patchText) {
|
|
22
25
|
if (!patchText || typeof patchText !== 'string') {
|
|
@@ -24,29 +27,33 @@ function determinePatchFormat(patchText) {
|
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
// Check for required metadata header first
|
|
27
|
-
if (!patchText.includes(
|
|
30
|
+
if (!patchText.includes(PATCH_METADATA_HEADER)) {
|
|
28
31
|
return 'unknown'; // Must have metadata header
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
// Check for traditional unified diff markers *after* potential metadata and start marker
|
|
32
35
|
// Look for ---, +++, @@ after the start marker
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
}
|
|
36
|
+
const traditionalStartMarkerIndex = patchText.indexOf(PATCH_START_MARKER);
|
|
37
|
+
if (traditionalStartMarkerIndex !== -1) {
|
|
38
|
+
const contentAfterMarker = patchText.substring(traditionalStartMarkerIndex);
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
// Use regex for more reliable detection within the content part
|
|
41
|
+
const traditionalMarkers = /^\s*--- Original\s*\n\s*\+\+\+ Modified\s*\n\s*@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@/m;
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
if (traditionalMarkers.test(contentAfterMarker)) {
|
|
44
|
+
return 'traditional';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
// Check for abbreviated patch markers
|
|
49
|
+
const abbreviatedStartMarkerIndex = patchText.indexOf(ABBREVIATED_PATCH_START_MARKER);
|
|
50
|
+
if (abbreviatedStartMarkerIndex !== -1) {
|
|
51
|
+
return 'abbreviated';
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
// Removed check for obsolete '@=' context marker
|
|
48
55
|
|
|
49
|
-
return 'unknown'; // Format doesn't match expected
|
|
56
|
+
return 'unknown'; // Format doesn't match expected structures after markers
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
/**
|
|
@@ -68,7 +75,8 @@ function extractPatchMetadata(patchText) {
|
|
|
68
75
|
const trimmedLine = line.trim();
|
|
69
76
|
|
|
70
77
|
// Stop processing metadata if we hit content markers or the start marker
|
|
71
|
-
if (trimmedLine ===
|
|
78
|
+
if (trimmedLine === PATCH_START_MARKER ||
|
|
79
|
+
trimmedLine === ABBREVIATED_PATCH_START_MARKER ||
|
|
72
80
|
line.startsWith('--- ') || // Standard diff header start
|
|
73
81
|
line.startsWith('+++ ') || // Standard diff header start
|
|
74
82
|
line.startsWith('@@ ')) // Standard diff hunk header start
|
|
@@ -91,7 +99,7 @@ function extractPatchMetadata(patchText) {
|
|
|
91
99
|
}
|
|
92
100
|
}
|
|
93
101
|
// Allow lines that are just comments (e.g., # Description continued)
|
|
94
|
-
} else if (trimmedLine !== '' && !trimmedLine.startsWith(
|
|
102
|
+
} else if (trimmedLine !== '' && !trimmedLine.startsWith(PATCH_METADATA_HEADER)) {
|
|
95
103
|
// If we encounter non-empty, non-comment lines before the start marker,
|
|
96
104
|
// it's likely malformed, stop metadata parsing.
|
|
97
105
|
inMetadata = false;
|
|
@@ -135,11 +143,11 @@ function validatePatchMetadata(metadata) {
|
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
// Validate UUIDs are not the template string
|
|
138
|
-
if (metadata['Source-Block-UUID'] === '
|
|
139
|
-
errors.push('Source-Block-UUID contains placeholder value "
|
|
146
|
+
if (metadata['Source-Block-UUID'] === '{{GS-UUID}}') {
|
|
147
|
+
errors.push('Source-Block-UUID contains placeholder value "{{GS-UUID}}".');
|
|
140
148
|
}
|
|
141
|
-
if (metadata['Target-Block-UUID'] === '
|
|
142
|
-
errors.push('Target-Block-UUID contains placeholder value "
|
|
149
|
+
if (metadata['Target-Block-UUID'] === '{{GS-UUID}}') {
|
|
150
|
+
errors.push('Target-Block-UUID contains placeholder value "{{GS-UUID}}".');
|
|
143
151
|
}
|
|
144
152
|
|
|
145
153
|
return errors;
|
|
@@ -152,23 +160,34 @@ function validatePatchMetadata(metadata) {
|
|
|
152
160
|
* @param {string} format - Expected format (should be 'traditional').
|
|
153
161
|
* @returns {string} Raw unified diff content, or empty string if not found/invalid.
|
|
154
162
|
*/
|
|
155
|
-
function extractPatchContent(patchText, format) {
|
|
156
|
-
if (!patchText
|
|
163
|
+
function extractPatchContent(patchText, format = 'traditional') {
|
|
164
|
+
if (!patchText) {
|
|
157
165
|
return "";
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
const lines = patchText.split('\n');
|
|
161
|
-
|
|
162
169
|
let contentLines = [];
|
|
163
170
|
let inContentBlock = false;
|
|
171
|
+
let startMarker, endMarker;
|
|
172
|
+
|
|
173
|
+
// Determine which markers to look for based on format
|
|
174
|
+
if (format === 'traditional') {
|
|
175
|
+
startMarker = PATCH_START_MARKER;
|
|
176
|
+
endMarker = PATCH_END_MARKER;
|
|
177
|
+
} else if (format === 'abbreviated') {
|
|
178
|
+
startMarker = ABBREVIATED_PATCH_START_MARKER;
|
|
179
|
+
endMarker = ABBREVIATED_PATCH_END_MARKER;
|
|
180
|
+
} else {
|
|
181
|
+
return ""; // Unsupported format
|
|
182
|
+
}
|
|
164
183
|
|
|
165
184
|
for (const line of lines) {
|
|
166
|
-
if (line.trim() ===
|
|
185
|
+
if (line.trim() === startMarker) {
|
|
167
186
|
inContentBlock = true;
|
|
168
187
|
continue; // Skip the marker line itself
|
|
169
188
|
}
|
|
170
189
|
|
|
171
|
-
if (line.trim() ===
|
|
190
|
+
if (line.trim() === endMarker) {
|
|
172
191
|
inContentBlock = false;
|
|
173
192
|
break; // Stop processing once end marker is found
|
|
174
193
|
}
|
|
@@ -207,23 +226,25 @@ function detectPatch(messageText) {
|
|
|
207
226
|
}
|
|
208
227
|
|
|
209
228
|
// Find the first code block that contains patch metadata
|
|
210
|
-
// Regex looks for ``` optionally followed by
|
|
211
|
-
const codeBlockRegex = /```(
|
|
229
|
+
// Regex looks for ``` optionally followed by language hint
|
|
230
|
+
const codeBlockRegex = /```([a-zA-Z0-9#+_-]*)?\s*\n([\s\S]*?)```/g;
|
|
212
231
|
let match;
|
|
213
232
|
while ((match = codeBlockRegex.exec(messageText)) !== null) {
|
|
214
|
-
const
|
|
233
|
+
const language = match[1] || '';
|
|
234
|
+
const blockContent = match[2];
|
|
215
235
|
if (isPatchBlock(blockContent)) { // Use isPatchBlock for check
|
|
216
236
|
const metadata = extractPatchMetadata(blockContent); // Use extractPatchMetadata
|
|
217
237
|
// Basic validation: Check for essential UUIDs
|
|
218
238
|
if (metadata['Source-Block-UUID'] && metadata['Target-Block-UUID'] &&
|
|
219
|
-
metadata['Source-Block-UUID'] !== '
|
|
220
|
-
metadata['Target-Block-UUID'] !== '
|
|
239
|
+
metadata['Source-Block-UUID'] !== '{{GS-UUID}}' && // Check placeholders
|
|
240
|
+
metadata['Target-Block-UUID'] !== '{{GS-UUID}}')
|
|
221
241
|
{
|
|
222
242
|
return {
|
|
223
243
|
patchText: blockContent, // Return the content inside the fence
|
|
224
244
|
metadata,
|
|
225
245
|
sourceBlockUUID: metadata['Source-Block-UUID'],
|
|
226
246
|
targetBlockUUID: metadata['Target-Block-UUID'],
|
|
247
|
+
language: language,
|
|
227
248
|
startIndex: match.index, // Store block position if needed
|
|
228
249
|
endIndex: match.index + match[0].length
|
|
229
250
|
};
|
|
@@ -245,25 +266,28 @@ function findAllPatches(messageText) {
|
|
|
245
266
|
}
|
|
246
267
|
|
|
247
268
|
const patches = [];
|
|
248
|
-
|
|
269
|
+
// Find code blocks with any language identifier
|
|
270
|
+
const codeBlockRegex = /```([a-zA-Z0-9#+_-]*)?\s*\n([\s\S]*?)```/g;
|
|
249
271
|
|
|
250
272
|
let match;
|
|
251
273
|
while ((match = codeBlockRegex.exec(messageText)) !== null) {
|
|
252
|
-
const
|
|
274
|
+
const language = match[1] || '';
|
|
275
|
+
const blockContent = match[2];
|
|
253
276
|
|
|
254
277
|
if (isPatchBlock(blockContent)) {
|
|
255
278
|
const metadata = extractPatchMetadata(blockContent);
|
|
256
279
|
|
|
257
280
|
// Basic validation: Check for essential UUIDs and non-placeholder values
|
|
258
281
|
if (metadata['Source-Block-UUID'] && metadata['Target-Block-UUID'] &&
|
|
259
|
-
metadata['Source-Block-UUID'] !== '
|
|
260
|
-
metadata['Target-Block-UUID'] !== '
|
|
282
|
+
metadata['Source-Block-UUID'] !== '{{GS-UUID}}' &&
|
|
283
|
+
metadata['Target-Block-UUID'] !== '{{GS-UUID}}')
|
|
261
284
|
{
|
|
262
285
|
patches.push({
|
|
263
286
|
patchText: blockContent,
|
|
264
287
|
metadata,
|
|
265
288
|
sourceBlockUUID: metadata['Source-Block-UUID'],
|
|
266
289
|
targetBlockUUID: metadata['Target-Block-UUID'],
|
|
290
|
+
language: language,
|
|
267
291
|
startIndex: match.index,
|
|
268
292
|
endIndex: match.index + match[0].length
|
|
269
293
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Component: PatchUtils Detect and Fix Overlapping Hunks
|
|
3
|
-
* Block-UUID:
|
|
3
|
+
* Block-UUID: 7324dab8-24ae-4a42-9dc3-766e69104ef6
|
|
4
4
|
* Parent-UUID: 2308ed72-91ff-48ba-bc80-310c23c01ff1
|
|
5
5
|
* Version: 1.0.0
|
|
6
6
|
* Description: Detects and optionally fixes overlapping hunks in a patch file by merging them.
|
package/src/SVGUtils.js
CHANGED
|
@@ -490,6 +490,18 @@ class SVGUtils {
|
|
|
490
490
|
return this.create(xml, params);
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
+
/**
|
|
494
|
+
* Generate dropZone SVG icon
|
|
495
|
+
* @param {Object} params - Configuration parameters
|
|
496
|
+
* @returns {Element} SVG element
|
|
497
|
+
*/
|
|
498
|
+
static dropZone(params) {
|
|
499
|
+
const xml = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='64' height='64'><path d="M7 18C4.23858 18 2 15.7614 2 13C2 10.2386 4.23858 8 7 8C7.55228 8 8 8.44772 8 9C8 9.55228 7.55228 10 7 10C5.34315 10 4 11.3431 4 13C4 14.6569 5.34315 16 7 16H17C18.6569 16 20 14.6569 20 13C20 11.3431 18.6569 10 17 10C16.4477 10 16 9.55228 16 9C16 8.44772 16.4477 8 17 8C19.7614 8 22 10.2386 22 13C22 15.7614 19.7614 18 17 18H7Z" fill="currentColor"/><path d="M12 2L12 14M12 14L9 11M12 14L15 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
500
|
+
return this.create(xml, params);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
493
505
|
/**
|
|
494
506
|
* Generate dot SVG icon
|
|
495
507
|
* @param {Object} params - Configuration parameters
|
|
@@ -530,6 +542,26 @@ class SVGUtils {
|
|
|
530
542
|
return this.create(xml, params);
|
|
531
543
|
}
|
|
532
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Generate eye SVG icon
|
|
547
|
+
* @param {Object} params - Configuration parameters
|
|
548
|
+
* @returns {Element} SVG element
|
|
549
|
+
*/
|
|
550
|
+
static eye(params) {
|
|
551
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M8 2c1.981 0 3.671.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.45.678-1.367 1.932-2.637 3.023C11.67 13.008 9.981 14 8 14c-1.981 0-3.671-.992-4.933-2.078C1.797 10.83.88 9.576.43 8.898a1.62 1.62 0 0 1 0-1.798c.45-.677 1.367-1.931 2.637-3.022C4.33 2.992 6.019 2 8 2ZM1.679 7.932a.12.12 0 0 0 0 .136c.411.622 1.241 1.75 2.366 2.717C5.176 11.758 6.527 12.5 8 12.5c1.473 0 2.825-.742 3.955-1.715 1.124-.967 1.954-2.096 2.366-2.717a.12.12 0 0 0 0-.136c-.412-.621-1.242-1.75-2.366-2.717C10.824 4.242 9.473 3.5 8 3.5c-1.473 0-2.825.742-3.955 1.715-1.124.967-1.954 2.096-2.366 2.717ZM8 10a2 2 0 1 1-.001-3.999A2 2 0 0 1 8 10Z"></path></svg>`;
|
|
552
|
+
return this.create(xml, params);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Generate eye closed SVG icon
|
|
557
|
+
* @param {Object} params - Configuration parameters
|
|
558
|
+
* @returns {Element} SVG element
|
|
559
|
+
*/
|
|
560
|
+
static eyeClosed(params) {
|
|
561
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M.143 2.31a.75.75 0 0 1 1.047-.167l14.5 10.5a.75.75 0 1 1-.88 1.214l-2.248-1.628C11.346 13.19 9.792 14 8 14c-1.981 0-3.67-.992-4.933-2.078C1.797 10.832.88 9.577.43 8.9a1.619 1.619 0 0 1 0-1.797c.353-.533.995-1.42 1.868-2.305L.31 3.357A.75.75 0 0 1 .143 2.31Zm1.536 5.622A.12.12 0 0 0 1.657 8c0 .021.006.045.022.068.412.621 1.242 1.75 2.366 2.717C5.175 11.758 6.527 12.5 8 12.5c1.195 0 2.31-.488 3.29-1.191L9.063 9.695A2 2 0 0 1 6.058 7.52L3.529 5.688a14.207 14.207 0 0 0-1.85 2.244ZM8 3.5c-.516 0-1.017.09-1.499.251a.75.75 0 1 1-.473-1.423A6.207 6.207 0 0 1 8 2c1.981 0 3.67.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.11.166-.248.365-.41.587a.75.75 0 1 1-1.21-.887c.148-.201.272-.382.371-.53a.119.119 0 0 0 0-.137c-.412-.621-1.242-1.75-2.366-2.717C10.825 4.242 9.473 3.5 8 3.5Z"></path></svg>`;
|
|
562
|
+
return this.create(xml, params);
|
|
563
|
+
}
|
|
564
|
+
|
|
533
565
|
/**
|
|
534
566
|
* Generate file SVG icon
|
|
535
567
|
* @param {Object} params - Configuration parameters
|
|
@@ -1086,6 +1118,16 @@ class SVGUtils {
|
|
|
1086
1118
|
return this.create(xml, params);
|
|
1087
1119
|
}
|
|
1088
1120
|
|
|
1121
|
+
/**
|
|
1122
|
+
* Generate squarCircle SVG icon
|
|
1123
|
+
* @param {Object} params - Configuration parameters
|
|
1124
|
+
* @returns {Element} SVG element
|
|
1125
|
+
*/
|
|
1126
|
+
static squareCircle(params) {
|
|
1127
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M8 16A8 8 0 1 1 8 0a8 8 0 0 1 0 16Zm0-1.5a6.5 6.5 0 1 0 0-13 6.5 6.5 0 0 0 0 13Z"></path><path d="M5 5.75A.75.75 0 0 1 5.75 5h4.5a.75.75 0 0 1 .75.75v4.5a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1-.75-.75Z"></path></svg>`;
|
|
1128
|
+
return this.create(xml, params);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1089
1131
|
/**
|
|
1090
1132
|
* Generate stack SVG icon
|
|
1091
1133
|
* @param {Object} params - Configuration parameters
|
|
@@ -1376,6 +1418,16 @@ class SVGUtils {
|
|
|
1376
1418
|
return this.create(xml, params);
|
|
1377
1419
|
}
|
|
1378
1420
|
|
|
1421
|
+
/**
|
|
1422
|
+
* Generate verticalEllipsis SVG icon
|
|
1423
|
+
* @param {Object} params - Configuration parameters
|
|
1424
|
+
* @returns {Element} SVG element
|
|
1425
|
+
*/
|
|
1426
|
+
static verticalEllipsis(params) {
|
|
1427
|
+
const xml = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16' transform='rotate(90)'><path d='M8 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM1.5 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm13 0a1.5 1.5 0 100-3 1.5 1.5 0 000 3z'></path></svg>`;
|
|
1428
|
+
return this.create(xml, params);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1379
1431
|
/**
|
|
1380
1432
|
* Generate x SVG icon
|
|
1381
1433
|
* @param {Object} params - Configuration parameters
|
|
@@ -1405,6 +1457,11 @@ class SVGUtils {
|
|
|
1405
1457
|
const xml = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'><path fill-rule='evenodd' d='M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z'></path></svg>`;
|
|
1406
1458
|
return this.create(xml, params);
|
|
1407
1459
|
}
|
|
1460
|
+
|
|
1461
|
+
static zai(params) {
|
|
1462
|
+
const xml = `<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em"><title>Z.ai</title><path d="M12.105 2L9.927 4.953H.653L2.83 2h9.276zM23.254 19.048L21.078 22h-9.242l2.174-2.952h9.244zM24 2L9.264 22H0L14.736 2H24z"/></svg>`;
|
|
1463
|
+
return this.create(xml, params);
|
|
1464
|
+
}
|
|
1408
1465
|
}
|
|
1409
1466
|
|
|
1410
1467
|
module.exports = SVGUtils;
|