@gitsense/gsc-utils 0.1.0

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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/dist/gitsense-chat-utils.cjs.js +10977 -0
  3. package/dist/gitsense-chat-utils.esm.js +10975 -0
  4. package/dist/gsc-utils.cjs.js +11043 -0
  5. package/dist/gsc-utils.esm.js +11041 -0
  6. package/package.json +37 -0
  7. package/src/AnalysisBlockUtils.js +151 -0
  8. package/src/ChatUtils.js +126 -0
  9. package/src/CodeBlockUtils/blockExtractor.js +277 -0
  10. package/src/CodeBlockUtils/blockProcessor.js +559 -0
  11. package/src/CodeBlockUtils/blockProcessor.js.rej +8 -0
  12. package/src/CodeBlockUtils/constants.js +62 -0
  13. package/src/CodeBlockUtils/continuationUtils.js +191 -0
  14. package/src/CodeBlockUtils/headerParser.js +175 -0
  15. package/src/CodeBlockUtils/headerUtils.js +236 -0
  16. package/src/CodeBlockUtils/index.js +83 -0
  17. package/src/CodeBlockUtils/lineNumberFormatter.js +117 -0
  18. package/src/CodeBlockUtils/markerRemover.js +89 -0
  19. package/src/CodeBlockUtils/patchIntegration.js +38 -0
  20. package/src/CodeBlockUtils/relationshipUtils.js +159 -0
  21. package/src/CodeBlockUtils/updateCodeBlock.js +372 -0
  22. package/src/CodeBlockUtils/uuidUtils.js +48 -0
  23. package/src/ContextUtils.js +180 -0
  24. package/src/GSToolBlockUtils.js +108 -0
  25. package/src/GitSenseChatUtils.js +386 -0
  26. package/src/JsonUtils.js +101 -0
  27. package/src/LLMUtils.js +31 -0
  28. package/src/MessageUtils.js +460 -0
  29. package/src/PatchUtils/constants.js +72 -0
  30. package/src/PatchUtils/diagnosticReporter.js +213 -0
  31. package/src/PatchUtils/enhancedPatchProcessor.js +390 -0
  32. package/src/PatchUtils/fuzzyMatcher.js +252 -0
  33. package/src/PatchUtils/hunkCorrector.js +204 -0
  34. package/src/PatchUtils/hunkValidator.js +305 -0
  35. package/src/PatchUtils/index.js +135 -0
  36. package/src/PatchUtils/patchExtractor.js +175 -0
  37. package/src/PatchUtils/patchHeaderFormatter.js +143 -0
  38. package/src/PatchUtils/patchParser.js +289 -0
  39. package/src/PatchUtils/patchProcessor.js +389 -0
  40. package/src/PatchUtils/patchVerifier/constants.js +23 -0
  41. package/src/PatchUtils/patchVerifier/detectAndFixOverlappingHunks.js +281 -0
  42. package/src/PatchUtils/patchVerifier/detectAndFixRedundantChanges.js +404 -0
  43. package/src/PatchUtils/patchVerifier/formatAndAddLineNumbers.js +165 -0
  44. package/src/PatchUtils/patchVerifier/index.js +25 -0
  45. package/src/PatchUtils/patchVerifier/verifyAndCorrectHunkHeaders.js +202 -0
  46. package/src/PatchUtils/patchVerifier/verifyAndCorrectLineNumbers.js +254 -0
  47. package/src/SharedUtils/timestampUtils.js +41 -0
  48. package/src/SharedUtils/versionUtils.js +58 -0
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Component: PatchUtils Header Formatter
3
+ * Block-UUID: 87821582-84d4-46c1-ba5f-ea2591fba1bb
4
+ * Parent-UUID: 1a8f5d2e-c7b9-4e0a-8d1f-9c3b0a4e2f1a
5
+ * Version: 1.0.0
6
+ * Description: Formats the metadata header for a new code block created after applying a patch.
7
+ * Language: JavaScript
8
+ * Created-at: 2025-04-18T02:59:04.322Z
9
+ * Authors: Gemini 2.5 Pro (v1.0.0)
10
+ */
11
+
12
+
13
+ /**
14
+ * Formats the metadata header for a new code block based on source info and patch metadata.
15
+ * Follows the rules specified in the System Prompt for metadata inheritance and updates.
16
+ *
17
+ * @param {object} sourceBlockInfo - The block info object for the source code block (from CodeBlockService).
18
+ * Expected to have a `header` property with source metadata.
19
+ * @param {object} patchBlock - The parsed patch block object (e.g., from patchParser.findAllPatches).
20
+ * Expected to have a `metadata` property with patch metadata.
21
+ * @returns {string} The formatted code block header string with appropriate comment syntax.
22
+ * @throws {Error} If required source or patch metadata is missing.
23
+ */
24
+ function formatCodeBlockHeader(sourceBlockInfo, patchBlock) {
25
+ // --- Function body from original PatchUtils.formatCodeBlockHeader ---
26
+ // --- (Copied Verbatim) ---
27
+ if (!sourceBlockInfo || !sourceBlockInfo.header) {
28
+ throw new Error("formatCodeBlockHeader: Missing sourceBlockInfo or sourceBlockInfo.header.");
29
+ }
30
+ if (!patchBlock || !patchBlock.metadata) {
31
+ throw new Error("formatCodeBlockHeader: Missing patchBlock or patchBlock.metadata.");
32
+ }
33
+
34
+ const sourceHeader = sourceBlockInfo.header;
35
+ const patchMetadata = patchBlock.metadata;
36
+
37
+ // --- Validate required fields ---
38
+ const requiredSource = ['Component', 'Language', 'Description', 'Block-UUID', 'Version', 'Authors'];
39
+ const requiredPatch = ['Source-Block-UUID', 'Target-Block-UUID', 'Source-Version', 'Target-Version', 'Authors'];
40
+
41
+ requiredSource.forEach(key => {
42
+ if (!sourceHeader[key]) throw new Error(`formatCodeBlockHeader: Missing required source metadata key: ${key}`);
43
+ });
44
+ requiredPatch.forEach(key => {
45
+ if (!patchMetadata[key]) throw new Error(`formatCodeBlockHeader: Missing required patch metadata key: ${key}`);
46
+ });
47
+
48
+ // --- Construct New Metadata Object ---
49
+ const newMetadata = {
50
+ 'Component': sourceHeader['Component'], // Preserve from source
51
+ 'Block-UUID': patchMetadata['Target-Block-UUID'], // Use Target UUID from patch
52
+ 'Parent-UUID': patchMetadata['Source-Block-UUID'], // Use Source UUID from patch as Parent
53
+ 'Version': patchMetadata['Target-Version'], // Use Target Version from patch
54
+ 'Description': sourceHeader['Description'], // Preserve Description from source
55
+ 'Language': sourceHeader['Language'], // Preserve Language from source
56
+ 'Created-at': new Date().toISOString(), // New timestamp
57
+ 'Authors': patchMetadata['Authors'] // Use Authors list from patch
58
+ };
59
+
60
+ const language = newMetadata['Language'].toLowerCase();
61
+ let headerLines = [];
62
+ let commentStart = '';
63
+ let commentEnd = '';
64
+ let linePrefix = '';
65
+
66
+ // --- Determine Comment Style ---
67
+ // Based on Code Block Header Format Rules in System Prompt
68
+ switch (language) {
69
+ case 'python':
70
+ case 'py':
71
+ commentStart = '"""';
72
+ commentEnd = '"""';
73
+ break;
74
+ case 'javascript':
75
+ case 'js':
76
+ case 'typescript':
77
+ case 'ts':
78
+ case 'java':
79
+ case 'c':
80
+ case 'cpp':
81
+ case 'csharp':
82
+ case 'cs':
83
+ case 'go':
84
+ case 'php':
85
+ case 'swift':
86
+ case 'kotlin':
87
+ case 'rust':
88
+ case 'css':
89
+ case 'scss':
90
+ case 'less':
91
+ commentStart = '/**';
92
+ linePrefix = ' * ';
93
+ commentEnd = ' */';
94
+ break;
95
+ case 'ruby':
96
+ case 'rb':
97
+ commentStart = '=begin';
98
+ commentEnd = '=end';
99
+ break;
100
+ case 'html':
101
+ case 'xml':
102
+ case 'svg':
103
+ commentStart = '<!--';
104
+ linePrefix = ' '; // Optional: Add space for readability inside comment
105
+ commentEnd = '-->';
106
+ break;
107
+ case 'bash':
108
+ case 'sh':
109
+ case 'shell':
110
+ case 'yaml':
111
+ case 'yml':
112
+ case 'perl':
113
+ case 'powershell':
114
+ case 'ps1':
115
+ // Add other languages using # for single-line comments
116
+ default: // Default to # for unknown or simple languages
117
+ linePrefix = '# ';
118
+ break;
119
+ }
120
+
121
+ // --- Format Metadata Lines ---
122
+ const metadataOrder = [
123
+ 'Component', 'Block-UUID', 'Parent-UUID', 'Version',
124
+ 'Description', 'Language', 'Created-at', 'Authors'
125
+ ];
126
+
127
+ if (commentStart) headerLines.push(commentStart);
128
+
129
+ metadataOrder.forEach(key => {
130
+ if (newMetadata[key]) {
131
+ headerLines.push(`${linePrefix}${key}: ${newMetadata[key]}`);
132
+ }
133
+ });
134
+
135
+ if (commentEnd) headerLines.push(commentEnd);
136
+
137
+ return headerLines.join('\n');
138
+ // --- End of Function Body ---
139
+ }
140
+
141
+ module.exports = {
142
+ formatCodeBlockHeader
143
+ };
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Component: PatchUtils Parser
3
+ * Block-UUID: ce634df9-ff99-482a-a261-56ab34a2546e
4
+ * Parent-UUID: fcc85ec1-0146-40bf-a937-6f7928258cbf
5
+ * Version: 1.1.0
6
+ * Description: Handles parsing, validation, extraction, and detection of traditional unified diff patches. Extracts metadata and raw diff content.
7
+ * Language: JavaScript
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)
10
+ */
11
+
12
+
13
+ const { isValidVersion } = require('../SharedUtils/versionUtils'); // Assuming SharedUtils is one level up
14
+
15
+ /**
16
+ * Determines the type of patch format used based on markers.
17
+ * Primarily looks for traditional unified diff markers after metadata.
18
+ * @param {string} patchText - The patch text
19
+ * @returns {string} 'traditional', or 'unknown'
20
+ */
21
+ function determinePatchFormat(patchText) {
22
+ if (!patchText || typeof patchText !== 'string') {
23
+ return 'unknown';
24
+ }
25
+
26
+ // Check for required metadata header first
27
+ if (!patchText.includes('# Patch Metadata')) {
28
+ return 'unknown'; // Must have metadata header
29
+ }
30
+
31
+ // Check for traditional unified diff markers *after* potential metadata and start marker
32
+ // Look for ---, +++, @@ after the start marker
33
+ const startMarkerIndex = patchText.indexOf('# --- PATCH START MARKER ---');
34
+ if (startMarkerIndex === -1) {
35
+ return 'unknown'; // Must have start marker
36
+ }
37
+
38
+ const contentAfterMarker = patchText.substring(startMarkerIndex);
39
+
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;
42
+
43
+ if (traditionalMarkers.test(contentAfterMarker)) {
44
+ return 'traditional';
45
+ }
46
+
47
+ // Removed check for obsolete '@=' context marker
48
+
49
+ return 'unknown'; // Format doesn't match expected traditional structure after markers
50
+ }
51
+
52
+ /**
53
+ * Extracts metadata from a patch block.
54
+ * Stops at the first sign of patch content (---, +++, @@, start marker).
55
+ * @param {string} patchText - The patch text including metadata.
56
+ * @returns {Object} Extracted metadata object.
57
+ */
58
+ function extractPatchMetadata(patchText) {
59
+ if (!patchText) {
60
+ return {};
61
+ }
62
+
63
+ const metadata = {};
64
+ const lines = patchText.split('\n');
65
+ let inMetadata = true;
66
+
67
+ for (const line of lines) {
68
+ const trimmedLine = line.trim();
69
+
70
+ // Stop processing metadata if we hit content markers or the start marker
71
+ if (trimmedLine === '# --- PATCH START MARKER ---' ||
72
+ line.startsWith('--- ') || // Standard diff header start
73
+ line.startsWith('+++ ') || // Standard diff header start
74
+ line.startsWith('@@ ')) // Standard diff hunk header start
75
+ {
76
+ inMetadata = false;
77
+ break; // Stop reading metadata
78
+ }
79
+
80
+ // Parse metadata lines (format: # Key: Value)
81
+ if (trimmedLine.startsWith('# ')) {
82
+ const metaLine = line.substring(line.indexOf('# ') + 2); // Get content after '# '
83
+ const colonIndex = metaLine.indexOf(':');
84
+
85
+ if (colonIndex > 0) {
86
+ const key = metaLine.substring(0, colonIndex).trim();
87
+ const value = metaLine.substring(colonIndex + 1).trim();
88
+ // Only add if key is not empty
89
+ if (key) {
90
+ metadata[key] = value;
91
+ }
92
+ }
93
+ // Allow lines that are just comments (e.g., # Description continued)
94
+ } else if (trimmedLine !== '' && !trimmedLine.startsWith('# Patch Metadata')) {
95
+ // If we encounter non-empty, non-comment lines before the start marker,
96
+ // it's likely malformed, stop metadata parsing.
97
+ inMetadata = false;
98
+ break;
99
+ }
100
+ }
101
+
102
+ return metadata;
103
+ }
104
+
105
+ /**
106
+ * Validates patch metadata for required fields and version format.
107
+ * @param {Object} metadata - Patch metadata object extracted by extractPatchMetadata.
108
+ * @returns {Array<string>} Array of error messages, empty if valid.
109
+ */
110
+ function validatePatchMetadata(metadata) {
111
+ const errors = [];
112
+ const requiredFields = [
113
+ 'Source-Block-UUID',
114
+ 'Target-Block-UUID',
115
+ 'Source-Version',
116
+ 'Target-Version',
117
+ 'Description',
118
+ 'Authors'
119
+ ];
120
+
121
+ for (const field of requiredFields) {
122
+ // Check for presence and non-empty string value
123
+ if (!metadata[field] || typeof metadata[field] !== 'string' || metadata[field].trim() === '') {
124
+ errors.push(`Missing or empty required metadata field: ${field}`);
125
+ }
126
+ }
127
+
128
+ // Validate version format if present
129
+ if (metadata['Source-Version'] && !isValidVersion(metadata['Source-Version'])) { // Use imported validator
130
+ errors.push(`Invalid Source-Version format: "${metadata['Source-Version']}". Expected X.Y.Z`);
131
+ }
132
+
133
+ if (metadata['Target-Version'] && !isValidVersion(metadata['Target-Version'])) { // Use imported validator
134
+ errors.push(`Invalid Target-Version format: "${metadata['Target-Version']}". Expected X.Y.Z`);
135
+ }
136
+
137
+ // Validate UUIDs are not the template string
138
+ if (metadata['Source-Block-UUID'] === '12d8a596-0620-4725-ba49-ae6fccdfa2ad') {
139
+ errors.push('Source-Block-UUID contains placeholder value "f016e2e4-f97f-4ffe-9f46-ea48f59a3eea".');
140
+ }
141
+ if (metadata['Target-Block-UUID'] === '5bfb717c-aaec-462e-a50e-d096aba0d63f') {
142
+ errors.push('Target-Block-UUID contains placeholder value "12e76392-f0ac-4c9d-a5be-c98401487352".');
143
+ }
144
+
145
+ return errors;
146
+ }
147
+
148
+ /**
149
+ * Extracts the raw unified diff content between the start and end markers.
150
+ * Includes lines with 'NNN: ' prefixes. Excludes the markers themselves.
151
+ * @param {string} patchText - Full patch text with metadata and markers.
152
+ * @param {string} format - Expected format (should be 'traditional').
153
+ * @returns {string} Raw unified diff content, or empty string if not found/invalid.
154
+ */
155
+ function extractPatchContent(patchText, format) {
156
+ if (!patchText || format !== 'traditional') {
157
+ return "";
158
+ }
159
+
160
+ const lines = patchText.split('\n');
161
+ let contentLines = [];
162
+ let inContentBlock = false;
163
+
164
+ for (const line of lines) {
165
+ if (line.trim() === '# --- PATCH START MARKER ---') {
166
+ inContentBlock = true;
167
+ continue; // Skip the marker line itself
168
+ }
169
+
170
+ if (line.trim() === '# --- PATCH END MARKER ---') {
171
+ inContentBlock = false;
172
+ break; // Stop processing once end marker is found
173
+ }
174
+
175
+ if (inContentBlock) {
176
+ contentLines.push(line);
177
+ }
178
+ }
179
+
180
+ return contentLines.join('\n');
181
+ }
182
+
183
+ // Removed extractContextPatches function (obsolete context format)
184
+
185
+ /**
186
+ * Determines if a code block's content represents a patch block
187
+ * by checking for the mandatory metadata header.
188
+ * @param {string} codeBlockContent - The content of the code block (between fences).
189
+ * @returns {boolean} True if the code block is a patch.
190
+ */
191
+ function isPatchBlock(codeBlockContent) {
192
+ if (!codeBlockContent || typeof codeBlockContent !== 'string') {
193
+ return false;
194
+ }
195
+ // Check for the mandatory metadata header using a regex for robustness
196
+ // Allows for potential whitespace variations
197
+ return /^\s*#\s*Patch Metadata\s*\n/.test(codeBlockContent);
198
+ }
199
+
200
+ /**
201
+ * Detects the first valid patch block within a larger message text.
202
+ * @param {string} messageText - The message text to analyze.
203
+ * @returns {Object|null} Patch information object { patchText, metadata, sourceBlockUUID, targetBlockUUID, startIndex, endIndex } or null if no valid patch found.
204
+ */
205
+ function detectPatch(messageText) {
206
+ if (!messageText || typeof messageText !== 'string') {
207
+ return null;
208
+ }
209
+
210
+ // Find the first code block that contains patch metadata
211
+ // Regex looks for ``` optionally followed by 'diff' language hint
212
+ const codeBlockRegex = /```(?:diff)?\s*\n([\s\S]*?)```/g;
213
+ let match;
214
+ while ((match = codeBlockRegex.exec(messageText)) !== null) {
215
+ const blockContent = match[1];
216
+ if (isPatchBlock(blockContent)) { // Use isPatchBlock for check
217
+ const metadata = extractPatchMetadata(blockContent); // Use extractPatchMetadata
218
+ // Basic validation: Check for essential UUIDs
219
+ if (metadata['Source-Block-UUID'] && metadata['Target-Block-UUID'] &&
220
+ metadata['Source-Block-UUID'] !== '26f930c9-2bc8-4906-bdf5-469700b2f857' && // Check placeholders
221
+ metadata['Target-Block-UUID'] !== '48a957eb-dd72-44bb-84a2-0df3c7cb16ed')
222
+ {
223
+ return {
224
+ patchText: blockContent, // Return the content inside the fence
225
+ metadata,
226
+ sourceBlockUUID: metadata['Source-Block-UUID'],
227
+ targetBlockUUID: metadata['Target-Block-UUID'],
228
+ startIndex: match.index, // Store block position if needed
229
+ endIndex: match.index + match[0].length
230
+ };
231
+ }
232
+ }
233
+ }
234
+
235
+ return null; // No valid patch block found
236
+ }
237
+
238
+ /**
239
+ * Finds all valid patch blocks within a message text.
240
+ * @param {string} messageText - The message text to analyze.
241
+ * @returns {Array<Object>} Array of patch information objects.
242
+ */
243
+ function findAllPatches(messageText) {
244
+ if (!messageText || typeof messageText !== 'string') {
245
+ return [];
246
+ }
247
+
248
+ const patches = [];
249
+ const codeBlockRegex = /```(?:diff)?\s*\n([\s\S]*?)```/g;
250
+
251
+ let match;
252
+ while ((match = codeBlockRegex.exec(messageText)) !== null) {
253
+ const blockContent = match[1];
254
+
255
+ if (isPatchBlock(blockContent)) {
256
+ const metadata = extractPatchMetadata(blockContent);
257
+
258
+ // Basic validation: Check for essential UUIDs and non-placeholder values
259
+ if (metadata['Source-Block-UUID'] && metadata['Target-Block-UUID'] &&
260
+ metadata['Source-Block-UUID'] !== 'e898f14f-14f6-4710-b35b-1cf3478fb5da' &&
261
+ metadata['Target-Block-UUID'] !== '0093be2a-fd84-4925-a0c1-13f8a8260cbf')
262
+ {
263
+ patches.push({
264
+ patchText: blockContent,
265
+ metadata,
266
+ sourceBlockUUID: metadata['Source-Block-UUID'],
267
+ targetBlockUUID: metadata['Target-Block-UUID'],
268
+ startIndex: match.index,
269
+ endIndex: match.index + match[0].length
270
+ });
271
+ }
272
+ }
273
+ }
274
+
275
+ return patches;
276
+ }
277
+
278
+
279
+ module.exports = {
280
+ // Removed validateAndParseContextPatch
281
+ determinePatchFormat,
282
+ extractPatchMetadata,
283
+ validatePatchMetadata,
284
+ extractPatchContent,
285
+ // Removed extractContextPatches
286
+ isPatchBlock,
287
+ detectPatch,
288
+ findAllPatches,
289
+ };