mcp-code-context 2.1.3

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 (112) hide show
  1. package/AGENT_INSTRUCTIONS.md +135 -0
  2. package/CHANGELOG.md +84 -0
  3. package/DEPLOYMENT_INSTRUCTIONS.md +110 -0
  4. package/LICENSE +21 -0
  5. package/README.md +247 -0
  6. package/RELEASE_NOTES_v2.1.3.md +78 -0
  7. package/TROUBLESHOOTING.md +38 -0
  8. package/dist/src/ast/dartCompressor.d.ts +27 -0
  9. package/dist/src/ast/dartCompressor.js +859 -0
  10. package/dist/src/ast/dartCompressor.js.map +1 -0
  11. package/dist/src/ast/phpCompressor.d.ts +24 -0
  12. package/dist/src/ast/phpCompressor.js +634 -0
  13. package/dist/src/ast/phpCompressor.js.map +1 -0
  14. package/dist/src/ast/semanticCompressor.d.ts +22 -0
  15. package/dist/src/ast/semanticCompressor.js +677 -0
  16. package/dist/src/ast/semanticCompressor.js.map +1 -0
  17. package/dist/src/ast/writers/dartWriter.d.ts +37 -0
  18. package/dist/src/ast/writers/dartWriter.js +544 -0
  19. package/dist/src/ast/writers/dartWriter.js.map +1 -0
  20. package/dist/src/ast/writers/phpWriter.d.ts +37 -0
  21. package/dist/src/ast/writers/phpWriter.js +411 -0
  22. package/dist/src/ast/writers/phpWriter.js.map +1 -0
  23. package/dist/src/ast/writers/pyWriter.d.ts +37 -0
  24. package/dist/src/ast/writers/pyWriter.js +355 -0
  25. package/dist/src/ast/writers/pyWriter.js.map +1 -0
  26. package/dist/src/ast/writers/symbolWriter.d.ts +62 -0
  27. package/dist/src/ast/writers/symbolWriter.js +179 -0
  28. package/dist/src/ast/writers/symbolWriter.js.map +1 -0
  29. package/dist/src/ast/writers/tsWriter.d.ts +38 -0
  30. package/dist/src/ast/writers/tsWriter.js +344 -0
  31. package/dist/src/ast/writers/tsWriter.js.map +1 -0
  32. package/dist/src/index.d.ts +117 -0
  33. package/dist/src/index.js +1289 -0
  34. package/dist/src/index.js.map +1 -0
  35. package/dist/src/tests/test-confirmation-flow.d.ts +1 -0
  36. package/dist/src/tests/test-confirmation-flow.js +43 -0
  37. package/dist/src/tests/test-confirmation-flow.js.map +1 -0
  38. package/dist/src/utils/backupManager.d.ts +24 -0
  39. package/dist/src/utils/backupManager.js +59 -0
  40. package/dist/src/utils/backupManager.js.map +1 -0
  41. package/dist/src/utils/confirmationCache.d.ts +16 -0
  42. package/dist/src/utils/confirmationCache.js +40 -0
  43. package/dist/src/utils/confirmationCache.js.map +1 -0
  44. package/dist/src/utils/diffEngine.d.ts +21 -0
  45. package/dist/src/utils/diffEngine.js +163 -0
  46. package/dist/src/utils/diffEngine.js.map +1 -0
  47. package/dist/src/utils/fuzzyMatch.d.ts +8 -0
  48. package/dist/src/utils/fuzzyMatch.js +69 -0
  49. package/dist/src/utils/fuzzyMatch.js.map +1 -0
  50. package/dist/src/utils/ignoreManager.d.ts +22 -0
  51. package/dist/src/utils/ignoreManager.js +135 -0
  52. package/dist/src/utils/ignoreManager.js.map +1 -0
  53. package/dist/tests/debug-replace.d.ts +1 -0
  54. package/dist/tests/debug-replace.js +17 -0
  55. package/dist/tests/debug-replace.js.map +1 -0
  56. package/dist/tests/test-confirmation-flow.d.ts +1 -0
  57. package/dist/tests/test-confirmation-flow.js +43 -0
  58. package/dist/tests/test-confirmation-flow.js.map +1 -0
  59. package/dist/tests/test-dart.d.ts +1 -0
  60. package/dist/tests/test-dart.js +242 -0
  61. package/dist/tests/test-dart.js.map +1 -0
  62. package/dist/tests/test-php-ast.d.ts +1 -0
  63. package/dist/tests/test-php-ast.js +152 -0
  64. package/dist/tests/test-php-ast.js.map +1 -0
  65. package/dist/tests/test-php.d.ts +1 -0
  66. package/dist/tests/test-php.js +234 -0
  67. package/dist/tests/test-php.js.map +1 -0
  68. package/dist/tests/test-smoke.d.ts +5 -0
  69. package/dist/tests/test-smoke.js +83 -0
  70. package/dist/tests/test-smoke.js.map +1 -0
  71. package/dist/tests/writers/test-crlf-handling.d.ts +4 -0
  72. package/dist/tests/writers/test-crlf-handling.js +73 -0
  73. package/dist/tests/writers/test-crlf-handling.js.map +1 -0
  74. package/dist/tests/writers/test-write-smoke.d.ts +9 -0
  75. package/dist/tests/writers/test-write-smoke.js +346 -0
  76. package/dist/tests/writers/test-write-smoke.js.map +1 -0
  77. package/llms.txt +164 -0
  78. package/package.json +57 -0
  79. package/src/ast/dartCompressor.ts +1013 -0
  80. package/src/ast/phpCompressor.ts +814 -0
  81. package/src/ast/semanticCompressor.ts +808 -0
  82. package/src/ast/writers/dartWriter.ts +648 -0
  83. package/src/ast/writers/phpWriter.ts +508 -0
  84. package/src/ast/writers/pyWriter.ts +446 -0
  85. package/src/ast/writers/symbolWriter.ts +277 -0
  86. package/src/ast/writers/tsWriter.ts +418 -0
  87. package/src/index.ts +1553 -0
  88. package/src/utils/backupManager.ts +66 -0
  89. package/src/utils/confirmationCache.ts +61 -0
  90. package/src/utils/diffEngine.ts +223 -0
  91. package/src/utils/fuzzyMatch.ts +86 -0
  92. package/src/utils/ignoreManager.ts +144 -0
  93. package/tests/test-confirmation-flow.ts +49 -0
  94. package/tests/test-dart.d.ts +1 -0
  95. package/tests/test-dart.js +209 -0
  96. package/tests/test-dart.js.map +1 -0
  97. package/tests/test-dart.ts +265 -0
  98. package/tests/test-php-ast.d.ts +1 -0
  99. package/tests/test-php-ast.js +152 -0
  100. package/tests/test-php-ast.js.map +1 -0
  101. package/tests/test-php-ast.ts +155 -0
  102. package/tests/test-php.d.ts +1 -0
  103. package/tests/test-php.js +234 -0
  104. package/tests/test-php.js.map +1 -0
  105. package/tests/test-php.ts +261 -0
  106. package/tests/test-smoke.d.ts +5 -0
  107. package/tests/test-smoke.js +83 -0
  108. package/tests/test-smoke.js.map +1 -0
  109. package/tests/test-smoke.ts +93 -0
  110. package/tests/writers/test-crlf-handling.ts +100 -0
  111. package/tests/writers/test-write-smoke.ts +568 -0
  112. package/tsconfig.json +19 -0
@@ -0,0 +1,355 @@
1
+ /**
2
+ * pyWriter.ts — Python Surgical Writer
3
+ *
4
+ * Uses indentation-based block detection to locate symbol boundaries
5
+ * in Python files. Python's significant whitespace makes this different
6
+ * from brace-delimited languages — we detect block ends by watching
7
+ * for dedentation back to the original level.
8
+ *
9
+ * Supports: .py, .pyi
10
+ */
11
+ // ─── Replace Symbol ─────────────────────────────────────────────────
12
+ /**
13
+ * Replace the full text of a named symbol in a Python file.
14
+ * The newContent should include the def/class signature and body.
15
+ * When className is provided, scopes the search to within that class only.
16
+ */
17
+ export function replacePySymbol(content, symbolName, newContent, className) {
18
+ const lines = content.split("\n");
19
+ const range = findSymbolRange(lines, symbolName, className);
20
+ if (!range) {
21
+ return {
22
+ success: false,
23
+ newContent: content,
24
+ symbolsAffected: [],
25
+ error: className
26
+ ? `Symbol "${symbolName}" not found in class "${className}" in Python file`
27
+ : `Symbol "${symbolName}" not found in Python file`,
28
+ };
29
+ }
30
+ const { start, end } = range;
31
+ // Detect indentation of original
32
+ const originalIndent = getIndent(lines[start]);
33
+ const reindented = reindentPython(newContent.trim(), originalIndent);
34
+ // Splice
35
+ const before = lines.slice(0, start);
36
+ const after = lines.slice(end + 1);
37
+ const result = [...before, reindented, ...after].join("\n");
38
+ return {
39
+ success: true,
40
+ newContent: result,
41
+ symbolsAffected: [symbolName],
42
+ };
43
+ }
44
+ // ─── Insert Code ────────────────────────────────────────────────────
45
+ /**
46
+ * Insert new code at a precise location relative to an anchor symbol.
47
+ * When className is provided, scopes the anchor search to within that class only.
48
+ */
49
+ export function insertPyCode(content, code, anchorSymbol, position, className) {
50
+ const lines = content.split("\n");
51
+ if (!anchorSymbol) {
52
+ // No anchor — append at end of file
53
+ lines.push("", "", code.trim(), "");
54
+ return {
55
+ success: true,
56
+ newContent: lines.join("\n"),
57
+ symbolsAffected: [],
58
+ };
59
+ }
60
+ const range = findSymbolRange(lines, anchorSymbol, className);
61
+ if (!range) {
62
+ return {
63
+ success: false,
64
+ newContent: content,
65
+ symbolsAffected: [],
66
+ error: className
67
+ ? `Anchor symbol "${anchorSymbol}" not found in class "${className}"`
68
+ : `Anchor symbol "${anchorSymbol}" not found`,
69
+ };
70
+ }
71
+ const { start, end } = range;
72
+ const indent = getIndent(lines[start]);
73
+ switch (position) {
74
+ case "before": {
75
+ const reindented = reindentPython(code.trim(), indent);
76
+ // Add proper spacing (PEP 8: two blank lines before top-level, one inside class)
77
+ const spacing = indent === "" ? "\n\n" : "\n";
78
+ lines.splice(start, 0, reindented + spacing);
79
+ break;
80
+ }
81
+ case "after": {
82
+ const reindented = reindentPython(code.trim(), indent);
83
+ const spacing = indent === "" ? "\n\n" : "\n";
84
+ lines.splice(end + 1, 0, spacing + reindented);
85
+ break;
86
+ }
87
+ case "inside_start": {
88
+ // Find the colon line (class Foo:) and insert after it
89
+ const colonLine = findColonLine(lines, start);
90
+ if (colonLine === -1) {
91
+ return {
92
+ success: false,
93
+ newContent: content,
94
+ symbolsAffected: [],
95
+ error: `Cannot find class body start for "${anchorSymbol}"`,
96
+ };
97
+ }
98
+ // Check if there's a docstring, insert after it
99
+ const insertAt = skipDocstring(lines, colonLine + 1);
100
+ const innerIndent = indent + " "; // Python convention: 4-space indent
101
+ const innerCode = reindentPython(code.trim(), innerIndent);
102
+ lines.splice(insertAt, 0, innerCode, "");
103
+ break;
104
+ }
105
+ case "inside_end": {
106
+ const innerIndent = indent + " ";
107
+ const innerCode = reindentPython(code.trim(), innerIndent);
108
+ lines.splice(end + 1, 0, "", innerCode);
109
+ break;
110
+ }
111
+ }
112
+ return {
113
+ success: true,
114
+ newContent: lines.join("\n"),
115
+ symbolsAffected: [anchorSymbol],
116
+ };
117
+ }
118
+ // ─── Rename Symbol ──────────────────────────────────────────────────
119
+ /**
120
+ * Rename all occurrences of a symbol within a Python file.
121
+ */
122
+ export function renamePySymbol(content, oldName, newName) {
123
+ const lines = content.split("\n");
124
+ const range = findSymbolRange(lines, oldName);
125
+ if (!range) {
126
+ return {
127
+ success: false,
128
+ newContent: content,
129
+ symbolsAffected: [],
130
+ error: `Symbol "${oldName}" not found for renaming`,
131
+ };
132
+ }
133
+ // Whole-word replacement
134
+ const escaped = oldName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
135
+ const regex = new RegExp(`\\b${escaped}\\b`, "g");
136
+ const result = content.replace(regex, newName);
137
+ return {
138
+ success: true,
139
+ newContent: result,
140
+ symbolsAffected: [oldName],
141
+ };
142
+ }
143
+ // ─── Remove Symbol ──────────────────────────────────────────────────
144
+ /**
145
+ * Remove a named symbol from a Python file.
146
+ * When className is provided, scopes the search to within that class only.
147
+ */
148
+ export function removePySymbol(content, symbolName, className) {
149
+ const lines = content.split("\n");
150
+ const range = findSymbolRange(lines, symbolName, className);
151
+ if (!range) {
152
+ return {
153
+ success: false,
154
+ newContent: content,
155
+ symbolsAffected: [],
156
+ error: className
157
+ ? `Symbol "${symbolName}" not found in class "${className}" for removal`
158
+ : `Symbol "${symbolName}" not found for removal`,
159
+ };
160
+ }
161
+ // Also remove leading decorators
162
+ let actualStart = range.start;
163
+ while (actualStart > 0 && lines[actualStart - 1].trim().startsWith("@")) {
164
+ actualStart--;
165
+ }
166
+ lines.splice(actualStart, range.end - actualStart + 1);
167
+ let result = lines.join("\n");
168
+ result = result.replace(/\n{3,}/g, "\n\n");
169
+ return {
170
+ success: true,
171
+ newContent: result,
172
+ symbolsAffected: [symbolName],
173
+ };
174
+ }
175
+ /**
176
+ * Find the start and end line indices of a named symbol in a Python file.
177
+ * Uses indentation to detect block boundaries (Python's significant whitespace).
178
+ * When className is provided, scopes the search to within that class only.
179
+ */
180
+ function findSymbolRange(lines, symbolName, className) {
181
+ const escaped = symbolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
182
+ // If className is provided, find the class first, then search within it
183
+ if (className) {
184
+ const escapedClass = className.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
185
+ for (let i = 0; i < lines.length; i++) {
186
+ const trimmed = lines[i].trim();
187
+ if (!new RegExp(`^class\\s+${escapedClass}[\\s(:]`).test(trimmed))
188
+ continue;
189
+ // Found the class — search for the method within it
190
+ const classIndent = measureIndent(lines[i]);
191
+ let j = i + 1;
192
+ while (j < lines.length) {
193
+ const bodyLine = lines[j];
194
+ if (bodyLine.trim() === "") {
195
+ j++;
196
+ continue;
197
+ }
198
+ if (measureIndent(bodyLine) <= classIndent && bodyLine.trim() !== "")
199
+ break;
200
+ const bodyTrimmed = bodyLine.trim();
201
+ const isFunc = new RegExp(`^(?:async\\s+)?def\\s+${escaped}\\s*\\(`).test(bodyTrimmed);
202
+ if (isFunc) {
203
+ const startLine = j;
204
+ const baseIndent = measureIndent(bodyLine);
205
+ // Check for decorators above
206
+ let decoratorStart = startLine;
207
+ while (decoratorStart > 0 &&
208
+ lines[decoratorStart - 1].trim().startsWith("@")) {
209
+ decoratorStart--;
210
+ }
211
+ // Find end of block
212
+ let endLine = startLine;
213
+ let k = startLine + 1;
214
+ while (k < lines.length) {
215
+ const innerLine = lines[k];
216
+ if (innerLine.trim() === "") {
217
+ k++;
218
+ continue;
219
+ }
220
+ if (measureIndent(innerLine) > baseIndent) {
221
+ endLine = k;
222
+ k++;
223
+ }
224
+ else
225
+ break;
226
+ }
227
+ while (endLine > startLine && lines[endLine].trim() === "") {
228
+ endLine--;
229
+ }
230
+ return { start: decoratorStart, end: endLine };
231
+ }
232
+ j++;
233
+ }
234
+ return null; // Method not found within class
235
+ }
236
+ return null; // Class not found
237
+ }
238
+ // Original behavior when no className is provided
239
+ for (let i = 0; i < lines.length; i++) {
240
+ const line = lines[i];
241
+ const trimmed = line.trim();
242
+ const isClass = new RegExp(`^class\\s+${escaped}[\\s(:]`).test(trimmed);
243
+ const isFunc = new RegExp(`^(?:async\\s+)?def\\s+${escaped}\\s*\\(`).test(trimmed);
244
+ if (!isClass && !isFunc)
245
+ continue;
246
+ const startLine = i;
247
+ const baseIndent = measureIndent(line);
248
+ // Also check for decorators above
249
+ let decoratorStart = startLine;
250
+ while (decoratorStart > 0 &&
251
+ lines[decoratorStart - 1].trim().startsWith("@")) {
252
+ decoratorStart--;
253
+ }
254
+ // Find the end of the block
255
+ let endLine = startLine;
256
+ let j = startLine + 1;
257
+ while (j < lines.length) {
258
+ const bodyLine = lines[j];
259
+ if (bodyLine.trim() === "") {
260
+ j++;
261
+ continue;
262
+ }
263
+ if (measureIndent(bodyLine) > baseIndent) {
264
+ endLine = j;
265
+ j++;
266
+ }
267
+ else {
268
+ break;
269
+ }
270
+ }
271
+ // Trim trailing blank lines from the block
272
+ while (endLine > startLine && lines[endLine].trim() === "") {
273
+ endLine--;
274
+ }
275
+ return { start: decoratorStart, end: endLine };
276
+ }
277
+ return null;
278
+ }
279
+ // ─── Utility Functions ──────────────────────────────────────────────
280
+ function measureIndent(line) {
281
+ const match = line.match(/^(\s*)/);
282
+ return match ? match[1].length : 0;
283
+ }
284
+ function getIndent(line) {
285
+ const match = line.match(/^(\s*)/);
286
+ return match ? match[1] : "";
287
+ }
288
+ /**
289
+ * Re-indent a block of Python code to match a target indentation level.
290
+ * Preserves relative indentation within the block.
291
+ */
292
+ function reindentPython(code, targetIndent) {
293
+ const lines = code.split("\n");
294
+ if (lines.length === 0)
295
+ return code;
296
+ // Find minimum non-empty indentation
297
+ let minIndent = Infinity;
298
+ for (const line of lines) {
299
+ if (line.trim() === "")
300
+ continue;
301
+ const indent = measureIndent(line);
302
+ if (indent < minIndent)
303
+ minIndent = indent;
304
+ }
305
+ if (minIndent === Infinity)
306
+ minIndent = 0;
307
+ return lines
308
+ .map((line) => {
309
+ if (line.trim() === "")
310
+ return "";
311
+ return targetIndent + line.slice(minIndent);
312
+ })
313
+ .join("\n");
314
+ }
315
+ /**
316
+ * Find the line containing the colon that starts a class/function body.
317
+ */
318
+ function findColonLine(lines, startIdx) {
319
+ for (let i = startIdx; i < lines.length; i++) {
320
+ if (lines[i].includes(":"))
321
+ return i;
322
+ }
323
+ return -1;
324
+ }
325
+ /**
326
+ * Skip past a docstring (if present) to find the first line of actual code.
327
+ */
328
+ function skipDocstring(lines, startIdx) {
329
+ let i = startIdx;
330
+ // Skip blank lines
331
+ while (i < lines.length && lines[i].trim() === "")
332
+ i++;
333
+ if (i >= lines.length)
334
+ return startIdx;
335
+ const trimmed = lines[i].trim();
336
+ // Look for triple-quoted docstring
337
+ if (trimmed.startsWith('"""') ||
338
+ trimmed.startsWith("'''")) {
339
+ const quote = trimmed.slice(0, 3);
340
+ // Single-line docstring
341
+ if (trimmed.endsWith(quote) && trimmed.length > 3) {
342
+ return i + 1;
343
+ }
344
+ // Multi-line docstring
345
+ i++;
346
+ while (i < lines.length) {
347
+ if (lines[i].trim().endsWith(quote)) {
348
+ return i + 1;
349
+ }
350
+ i++;
351
+ }
352
+ }
353
+ return startIdx;
354
+ }
355
+ //# sourceMappingURL=pyWriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pyWriter.js","sourceRoot":"","sources":["../../../../src/ast/writers/pyWriter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * symbolWriter.ts — Central Dispatcher for Surgical Write Operations
3
+ *
4
+ * Routes write operations to the correct language-specific writer based
5
+ * on file extension. This is the "write" counterpart to semanticCompressor.ts.
6
+ *
7
+ * Supports:
8
+ * - TypeScript/JavaScript (.ts, .tsx, .js, .jsx, .mts, .mjs, .cts, .cjs)
9
+ * - PHP (.php, .phtml)
10
+ * - Dart (.dart)
11
+ * - Python (.py, .pyi)
12
+ */
13
+ import { type WriteResult, type InsertPosition } from "./tsWriter.js";
14
+ export type { WriteResult, InsertPosition };
15
+ /** All extensions supported for surgical writing */
16
+ export declare const WRITABLE_EXTENSIONS: Set<string>;
17
+ /**
18
+ * Replace the full source code of a named symbol in a file.
19
+ * Dispatches to the correct language-specific writer.
20
+ *
21
+ * @param filePath - Used to detect language via extension
22
+ * @param content - Current file content
23
+ * @param symbolName - Name of the symbol to replace
24
+ * @param newContent - Complete replacement code (signature + body)
25
+ * @param className - Optional. Scopes search to within a specific class
26
+ */
27
+ export declare function replaceSymbol(filePath: string, content: string, symbolName: string, newContent: string, className?: string): WriteResult;
28
+ /**
29
+ * Insert new code at a precise location relative to an anchor symbol.
30
+ *
31
+ * @param filePath - Used to detect language via extension
32
+ * @param content - Current file content
33
+ * @param code - The code to insert
34
+ * @param anchorSymbol - Symbol to position relative to (null = end of file)
35
+ * @param position - Where to insert: before, after, inside_start, inside_end
36
+ * @param className - Optional. Scopes anchor search to within a specific class
37
+ */
38
+ export declare function insertCode(filePath: string, content: string, code: string, anchorSymbol: string | null, position: InsertPosition, className?: string): WriteResult;
39
+ /**
40
+ * Rename all occurrences of a symbol within a single file.
41
+ *
42
+ * @param filePath - Used to detect language via extension
43
+ * @param content - Current file content
44
+ * @param oldName - Current symbol name
45
+ * @param newName - New symbol name
46
+ */
47
+ export declare function renameInFile(filePath: string, content: string, oldName: string, newName: string): WriteResult;
48
+ /**
49
+ * Renames all whole-word occurrences of a symbol in a file.
50
+ * UNLIKE renameInFile, this does NOT check for the symbol definition.
51
+ * Used for updating references in dependent files.
52
+ */
53
+ export declare function renameReferencesInFile(filePath: string, content: string, oldName: string, newName: string): WriteResult;
54
+ /**
55
+ * Remove a named symbol from a file.
56
+ *
57
+ * @param filePath - Used to detect language via extension
58
+ * @param content - Current file content
59
+ * @param symbolName - Name of the symbol to remove
60
+ * @param className - Optional. Scopes search to within a specific class
61
+ */
62
+ export declare function removeSymbolFromFile(filePath: string, content: string, symbolName: string, className?: string): WriteResult;
@@ -0,0 +1,179 @@
1
+ /**
2
+ * symbolWriter.ts — Central Dispatcher for Surgical Write Operations
3
+ *
4
+ * Routes write operations to the correct language-specific writer based
5
+ * on file extension. This is the "write" counterpart to semanticCompressor.ts.
6
+ *
7
+ * Supports:
8
+ * - TypeScript/JavaScript (.ts, .tsx, .js, .jsx, .mts, .mjs, .cts, .cjs)
9
+ * - PHP (.php, .phtml)
10
+ * - Dart (.dart)
11
+ * - Python (.py, .pyi)
12
+ */
13
+ import * as path from "node:path";
14
+ import { replaceTSSymbol, insertTSCode, renameTSSymbol, removeTSSymbol, } from "./tsWriter.js";
15
+ import { replacePHPSymbol, insertPHPCode, renamePHPSymbol, removePHPSymbol, } from "./phpWriter.js";
16
+ import { replaceDartSymbol, insertDartCode, renameDartSymbol, removeDartSymbol, } from "./dartWriter.js";
17
+ import { replacePySymbol, insertPyCode, renamePySymbol, removePySymbol, } from "./pyWriter.js";
18
+ // ─── Extension Sets ─────────────────────────────────────────────────
19
+ const TS_EXTENSIONS = new Set([
20
+ ".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs",
21
+ ]);
22
+ const PHP_EXTENSIONS = new Set([".php", ".phtml"]);
23
+ const DART_EXTENSIONS = new Set([".dart"]);
24
+ const PY_EXTENSIONS = new Set([".py", ".pyi"]);
25
+ /** All extensions supported for surgical writing */
26
+ export const WRITABLE_EXTENSIONS = new Set([
27
+ ...TS_EXTENSIONS,
28
+ ...PHP_EXTENSIONS,
29
+ ...DART_EXTENSIONS,
30
+ ...PY_EXTENSIONS,
31
+ ]);
32
+ // ─── Replace Symbol ─────────────────────────────────────────────────
33
+ /**
34
+ * Replace the full source code of a named symbol in a file.
35
+ * Dispatches to the correct language-specific writer.
36
+ *
37
+ * @param filePath - Used to detect language via extension
38
+ * @param content - Current file content
39
+ * @param symbolName - Name of the symbol to replace
40
+ * @param newContent - Complete replacement code (signature + body)
41
+ * @param className - Optional. Scopes search to within a specific class
42
+ */
43
+ export function replaceSymbol(filePath, content, symbolName, newContent, className) {
44
+ const ext = path.extname(filePath).toLowerCase();
45
+ if (TS_EXTENSIONS.has(ext)) {
46
+ return replaceTSSymbol(content, symbolName, newContent, filePath, className);
47
+ }
48
+ if (PHP_EXTENSIONS.has(ext)) {
49
+ return replacePHPSymbol(content, symbolName, newContent, className);
50
+ }
51
+ if (DART_EXTENSIONS.has(ext)) {
52
+ return replaceDartSymbol(content, symbolName, newContent, className);
53
+ }
54
+ if (PY_EXTENSIONS.has(ext)) {
55
+ return replacePySymbol(content, symbolName, newContent, className);
56
+ }
57
+ return {
58
+ success: false,
59
+ newContent: content,
60
+ symbolsAffected: [],
61
+ error: `Unsupported file type "${ext}" for surgical writing. Supported: TypeScript, JavaScript, PHP, Dart, Python.`,
62
+ };
63
+ }
64
+ // ─── Insert Code ────────────────────────────────────────────────────
65
+ /**
66
+ * Insert new code at a precise location relative to an anchor symbol.
67
+ *
68
+ * @param filePath - Used to detect language via extension
69
+ * @param content - Current file content
70
+ * @param code - The code to insert
71
+ * @param anchorSymbol - Symbol to position relative to (null = end of file)
72
+ * @param position - Where to insert: before, after, inside_start, inside_end
73
+ * @param className - Optional. Scopes anchor search to within a specific class
74
+ */
75
+ export function insertCode(filePath, content, code, anchorSymbol, position, className) {
76
+ const ext = path.extname(filePath).toLowerCase();
77
+ if (TS_EXTENSIONS.has(ext)) {
78
+ return insertTSCode(content, code, anchorSymbol, position, filePath, className);
79
+ }
80
+ if (PHP_EXTENSIONS.has(ext)) {
81
+ return insertPHPCode(content, code, anchorSymbol, position, className);
82
+ }
83
+ if (DART_EXTENSIONS.has(ext)) {
84
+ return insertDartCode(content, code, anchorSymbol, position, className);
85
+ }
86
+ if (PY_EXTENSIONS.has(ext)) {
87
+ return insertPyCode(content, code, anchorSymbol, position, className);
88
+ }
89
+ return {
90
+ success: false,
91
+ newContent: content,
92
+ symbolsAffected: [],
93
+ error: `Unsupported file type "${ext}" for code insertion.`,
94
+ };
95
+ }
96
+ // ─── Rename Symbol ──────────────────────────────────────────────────
97
+ /**
98
+ * Rename all occurrences of a symbol within a single file.
99
+ *
100
+ * @param filePath - Used to detect language via extension
101
+ * @param content - Current file content
102
+ * @param oldName - Current symbol name
103
+ * @param newName - New symbol name
104
+ */
105
+ export function renameInFile(filePath, content, oldName, newName) {
106
+ const ext = path.extname(filePath).toLowerCase();
107
+ if (TS_EXTENSIONS.has(ext)) {
108
+ return renameTSSymbol(content, oldName, newName, filePath);
109
+ }
110
+ if (PHP_EXTENSIONS.has(ext)) {
111
+ return renamePHPSymbol(content, oldName, newName);
112
+ }
113
+ if (DART_EXTENSIONS.has(ext)) {
114
+ return renameDartSymbol(content, oldName, newName);
115
+ }
116
+ if (PY_EXTENSIONS.has(ext)) {
117
+ return renamePySymbol(content, oldName, newName);
118
+ }
119
+ return {
120
+ success: false,
121
+ newContent: content,
122
+ symbolsAffected: [],
123
+ error: `Unsupported file type "${ext}" for symbol renaming.`,
124
+ };
125
+ }
126
+ /**
127
+ * Renames all whole-word occurrences of a symbol in a file.
128
+ * UNLIKE renameInFile, this does NOT check for the symbol definition.
129
+ * Used for updating references in dependent files.
130
+ */
131
+ export function renameReferencesInFile(filePath, content, oldName, newName) {
132
+ const ext = path.extname(filePath).toLowerCase();
133
+ // Simple whole-word replacement is generally safe for cross-file reference updates
134
+ // where we ALREADY know via import analysis that the file depends on this symbol.
135
+ // Scape regex special chars
136
+ const escaped = oldName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
137
+ // Use a regex that respects common identifier boundaries across JS/PHP/Dart/Python
138
+ const regex = new RegExp(`(?<=^|[^a-zA-Z0-9_$])(${escaped})(?=[^a-zA-Z0-9_$]|$)`, "g");
139
+ if (!regex.test(content)) {
140
+ return { success: true, newContent: content, symbolsAffected: [] };
141
+ }
142
+ const result = content.replace(regex, newName);
143
+ return {
144
+ success: true,
145
+ newContent: result,
146
+ symbolsAffected: [oldName],
147
+ };
148
+ }
149
+ // ─── Remove Symbol ──────────────────────────────────────────────────
150
+ /**
151
+ * Remove a named symbol from a file.
152
+ *
153
+ * @param filePath - Used to detect language via extension
154
+ * @param content - Current file content
155
+ * @param symbolName - Name of the symbol to remove
156
+ * @param className - Optional. Scopes search to within a specific class
157
+ */
158
+ export function removeSymbolFromFile(filePath, content, symbolName, className) {
159
+ const ext = path.extname(filePath).toLowerCase();
160
+ if (TS_EXTENSIONS.has(ext)) {
161
+ return removeTSSymbol(content, symbolName, filePath, className);
162
+ }
163
+ if (PHP_EXTENSIONS.has(ext)) {
164
+ return removePHPSymbol(content, symbolName, className);
165
+ }
166
+ if (DART_EXTENSIONS.has(ext)) {
167
+ return removeDartSymbol(content, symbolName, className);
168
+ }
169
+ if (PY_EXTENSIONS.has(ext)) {
170
+ return removePySymbol(content, symbolName, className);
171
+ }
172
+ return {
173
+ success: false,
174
+ newContent: content,
175
+ symbolsAffected: [],
176
+ error: `Unsupported file type "${ext}" for symbol removal.`,
177
+ };
178
+ }
179
+ //# sourceMappingURL=symbolWriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbolWriter.js","sourceRoot":"","sources":["../../../../src/ast/writers/symbolWriter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * tsWriter.ts — TypeScript / JavaScript Surgical Writer
3
+ *
4
+ * Uses ts-morph to perform AST-aware code modifications on TypeScript
5
+ * and JavaScript files. This is the most robust writer because ts-morph
6
+ * provides a full read-write AST with source manipulation capabilities.
7
+ *
8
+ * Supports: .ts, .tsx, .js, .jsx, .mts, .mjs, .cts, .cjs
9
+ */
10
+ export interface WriteResult {
11
+ success: boolean;
12
+ newContent: string;
13
+ symbolsAffected: string[];
14
+ error?: string;
15
+ }
16
+ /**
17
+ * Replace the full text of a named symbol in a TypeScript/JavaScript file.
18
+ * The newContent should be the complete replacement (signature + body).
19
+ * When className is provided, scopes the search to within that class only.
20
+ */
21
+ export declare function replaceTSSymbol(content: string, symbolName: string, newContent: string, filePath: string, className?: string): WriteResult;
22
+ export type InsertPosition = "before" | "after" | "inside_start" | "inside_end";
23
+ /**
24
+ * Insert new code at a precise location relative to an anchor symbol.
25
+ * When className is provided, scopes the anchor search to within that class only.
26
+ */
27
+ export declare function insertTSCode(content: string, code: string, anchorSymbol: string | null, position: InsertPosition, filePath: string, className?: string): WriteResult;
28
+ /**
29
+ * Rename all occurrences of a symbol within a single TypeScript/JavaScript file.
30
+ * This performs a smart rename that understands scoping.
31
+ */
32
+ export declare function renameTSSymbol(content: string, oldName: string, newName: string, filePath: string): WriteResult;
33
+ /**
34
+ * Remove a named symbol from a TypeScript/JavaScript file.
35
+ * Returns the file content without the symbol.
36
+ * When className is provided, scopes the search to within that class only.
37
+ */
38
+ export declare function removeTSSymbol(content: string, symbolName: string, filePath: string, className?: string): WriteResult;