@ruso-0/nreki 6.0.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 (150) hide show
  1. package/CHANGELOG.md +648 -0
  2. package/LICENSE +21 -0
  3. package/README.md +425 -0
  4. package/dist/ast-navigator.d.ts +29 -0
  5. package/dist/ast-navigator.d.ts.map +1 -0
  6. package/dist/ast-navigator.js +279 -0
  7. package/dist/ast-navigator.js.map +1 -0
  8. package/dist/ast-sandbox.d.ts +74 -0
  9. package/dist/ast-sandbox.d.ts.map +1 -0
  10. package/dist/ast-sandbox.js +242 -0
  11. package/dist/ast-sandbox.js.map +1 -0
  12. package/dist/chronos-memory.d.ts +69 -0
  13. package/dist/chronos-memory.d.ts.map +1 -0
  14. package/dist/chronos-memory.js +247 -0
  15. package/dist/chronos-memory.js.map +1 -0
  16. package/dist/circuit-breaker.d.ts +107 -0
  17. package/dist/circuit-breaker.d.ts.map +1 -0
  18. package/dist/circuit-breaker.js +330 -0
  19. package/dist/circuit-breaker.js.map +1 -0
  20. package/dist/compressor-advanced.d.ts +80 -0
  21. package/dist/compressor-advanced.d.ts.map +1 -0
  22. package/dist/compressor-advanced.js +555 -0
  23. package/dist/compressor-advanced.js.map +1 -0
  24. package/dist/compressor.d.ts +81 -0
  25. package/dist/compressor.d.ts.map +1 -0
  26. package/dist/compressor.js +227 -0
  27. package/dist/compressor.js.map +1 -0
  28. package/dist/database.d.ts +169 -0
  29. package/dist/database.d.ts.map +1 -0
  30. package/dist/database.js +1029 -0
  31. package/dist/database.js.map +1 -0
  32. package/dist/embedder.d.ts +73 -0
  33. package/dist/embedder.d.ts.map +1 -0
  34. package/dist/embedder.js +165 -0
  35. package/dist/embedder.js.map +1 -0
  36. package/dist/engine.d.ts +224 -0
  37. package/dist/engine.d.ts.map +1 -0
  38. package/dist/engine.js +582 -0
  39. package/dist/engine.js.map +1 -0
  40. package/dist/hologram/harvester.d.ts +41 -0
  41. package/dist/hologram/harvester.d.ts.map +1 -0
  42. package/dist/hologram/harvester.js +129 -0
  43. package/dist/hologram/harvester.js.map +1 -0
  44. package/dist/hologram/shadow-cache.d.ts +49 -0
  45. package/dist/hologram/shadow-cache.d.ts.map +1 -0
  46. package/dist/hologram/shadow-cache.js +165 -0
  47. package/dist/hologram/shadow-cache.js.map +1 -0
  48. package/dist/hologram/shadow-generator.d.ts +32 -0
  49. package/dist/hologram/shadow-generator.d.ts.map +1 -0
  50. package/dist/hologram/shadow-generator.js +828 -0
  51. package/dist/hologram/shadow-generator.js.map +1 -0
  52. package/dist/hooks/preToolUse.d.ts +63 -0
  53. package/dist/hooks/preToolUse.d.ts.map +1 -0
  54. package/dist/hooks/preToolUse.js +103 -0
  55. package/dist/hooks/preToolUse.js.map +1 -0
  56. package/dist/index.d.ts +19 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +367 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/kernel/kernel-manager.d.ts +52 -0
  61. package/dist/kernel/kernel-manager.d.ts.map +1 -0
  62. package/dist/kernel/kernel-manager.js +197 -0
  63. package/dist/kernel/kernel-manager.js.map +1 -0
  64. package/dist/kernel/kernel-worker.d.ts +9 -0
  65. package/dist/kernel/kernel-worker.d.ts.map +1 -0
  66. package/dist/kernel/kernel-worker.js +76 -0
  67. package/dist/kernel/kernel-worker.js.map +1 -0
  68. package/dist/kernel/nreki-kernel.d.ts +244 -0
  69. package/dist/kernel/nreki-kernel.d.ts.map +1 -0
  70. package/dist/kernel/nreki-kernel.js +1656 -0
  71. package/dist/kernel/nreki-kernel.js.map +1 -0
  72. package/dist/middleware/circuit-breaker.d.ts +32 -0
  73. package/dist/middleware/circuit-breaker.d.ts.map +1 -0
  74. package/dist/middleware/circuit-breaker.js +160 -0
  75. package/dist/middleware/circuit-breaker.js.map +1 -0
  76. package/dist/middleware/file-lock.d.ts +33 -0
  77. package/dist/middleware/file-lock.d.ts.map +1 -0
  78. package/dist/middleware/file-lock.js +55 -0
  79. package/dist/middleware/file-lock.js.map +1 -0
  80. package/dist/middleware/validator.d.ts +26 -0
  81. package/dist/middleware/validator.d.ts.map +1 -0
  82. package/dist/middleware/validator.js +39 -0
  83. package/dist/middleware/validator.js.map +1 -0
  84. package/dist/monitor.d.ts +94 -0
  85. package/dist/monitor.d.ts.map +1 -0
  86. package/dist/monitor.js +221 -0
  87. package/dist/monitor.js.map +1 -0
  88. package/dist/parser-pool.d.ts +28 -0
  89. package/dist/parser-pool.d.ts.map +1 -0
  90. package/dist/parser-pool.js +81 -0
  91. package/dist/parser-pool.js.map +1 -0
  92. package/dist/parser.d.ts +91 -0
  93. package/dist/parser.d.ts.map +1 -0
  94. package/dist/parser.js +311 -0
  95. package/dist/parser.js.map +1 -0
  96. package/dist/pin-memory.d.ts +35 -0
  97. package/dist/pin-memory.d.ts.map +1 -0
  98. package/dist/pin-memory.js +161 -0
  99. package/dist/pin-memory.js.map +1 -0
  100. package/dist/repo-map.d.ts +81 -0
  101. package/dist/repo-map.d.ts.map +1 -0
  102. package/dist/repo-map.js +550 -0
  103. package/dist/repo-map.js.map +1 -0
  104. package/dist/router.d.ts +102 -0
  105. package/dist/router.d.ts.map +1 -0
  106. package/dist/router.js +1989 -0
  107. package/dist/router.js.map +1 -0
  108. package/dist/semantic-edit.d.ts +82 -0
  109. package/dist/semantic-edit.d.ts.map +1 -0
  110. package/dist/semantic-edit.js +529 -0
  111. package/dist/semantic-edit.js.map +1 -0
  112. package/dist/terminal-filter.d.ts +27 -0
  113. package/dist/terminal-filter.d.ts.map +1 -0
  114. package/dist/terminal-filter.js +257 -0
  115. package/dist/terminal-filter.js.map +1 -0
  116. package/dist/undo.d.ts +21 -0
  117. package/dist/undo.d.ts.map +1 -0
  118. package/dist/undo.js +55 -0
  119. package/dist/undo.js.map +1 -0
  120. package/dist/utils/code-tokenizer.d.ts +25 -0
  121. package/dist/utils/code-tokenizer.d.ts.map +1 -0
  122. package/dist/utils/code-tokenizer.js +52 -0
  123. package/dist/utils/code-tokenizer.js.map +1 -0
  124. package/dist/utils/file-filter.d.ts +23 -0
  125. package/dist/utils/file-filter.d.ts.map +1 -0
  126. package/dist/utils/file-filter.js +48 -0
  127. package/dist/utils/file-filter.js.map +1 -0
  128. package/dist/utils/imports.d.ts +32 -0
  129. package/dist/utils/imports.d.ts.map +1 -0
  130. package/dist/utils/imports.js +155 -0
  131. package/dist/utils/imports.js.map +1 -0
  132. package/dist/utils/path-jail.d.ts +27 -0
  133. package/dist/utils/path-jail.d.ts.map +1 -0
  134. package/dist/utils/path-jail.js +95 -0
  135. package/dist/utils/path-jail.js.map +1 -0
  136. package/dist/utils/read-source.d.ts +18 -0
  137. package/dist/utils/read-source.d.ts.map +1 -0
  138. package/dist/utils/read-source.js +22 -0
  139. package/dist/utils/read-source.js.map +1 -0
  140. package/dist/utils/safe-parse.d.ts +20 -0
  141. package/dist/utils/safe-parse.d.ts.map +1 -0
  142. package/dist/utils/safe-parse.js +25 -0
  143. package/dist/utils/safe-parse.js.map +1 -0
  144. package/package.json +75 -0
  145. package/scripts/download-wasm.js +46 -0
  146. package/wasm/.gitkeep +0 -0
  147. package/wasm/tree-sitter-go.wasm +0 -0
  148. package/wasm/tree-sitter-javascript.wasm +0 -0
  149. package/wasm/tree-sitter-python.wasm +0 -0
  150. package/wasm/tree-sitter-typescript.wasm +0 -0
@@ -0,0 +1,828 @@
1
+ /**
2
+ * shadow-generator.ts -Tree-sitter based TypeScript file classifier and .d.ts shadow generator.
3
+ *
4
+ * Classifies TypeScript files as PRUNABLE (all exports have explicit type annotations)
5
+ * or UNPRUNABLE (any export relies on type inference). For prunable files, generates
6
+ * lightweight .d.ts shadow content that preserves structural type information.
7
+ *
8
+ * Uses Tree-sitter for accurate AST walking, not regex.
9
+ */
10
+ import Parser from "web-tree-sitter";
11
+ import fs from "fs";
12
+ import path from "path";
13
+ // ─── Helpers ─────────────────────────────────────────────────────────
14
+ const toPosix = (p) => path.normalize(p).replace(/\\/g, "/");
15
+ const IGNORE_DIRS = new Set([
16
+ "node_modules", "dist", "build", ".git", ".next", "coverage",
17
+ ]);
18
+ function isSimpleLiteral(node) {
19
+ const t = node.type;
20
+ // String literal (no template expressions)
21
+ if (t === "string")
22
+ return true;
23
+ // Number literal
24
+ if (t === "number")
25
+ return true;
26
+ // Boolean
27
+ if (t === "true" || t === "false")
28
+ return true;
29
+ // null
30
+ if (t === "null")
31
+ return true;
32
+ // undefined
33
+ if (t === "undefined")
34
+ return true;
35
+ // Negative number: unary_expression with "-" and number
36
+ if (t === "unary_expression") {
37
+ const op = node.child(0);
38
+ const operand = node.child(1);
39
+ if (op?.text === "-" && operand?.type === "number")
40
+ return true;
41
+ }
42
+ return false;
43
+ }
44
+ function literalTypeString(node, isConst) {
45
+ const t = node.type;
46
+ const text = node.text;
47
+ if (t === "string") {
48
+ return isConst ? text : "string";
49
+ }
50
+ if (t === "number") {
51
+ return isConst ? text : "number";
52
+ }
53
+ if (t === "true" || t === "false") {
54
+ return isConst ? text : "boolean";
55
+ }
56
+ if (t === "null")
57
+ return "null";
58
+ if (t === "undefined")
59
+ return "undefined";
60
+ if (t === "unary_expression") {
61
+ // Negative number
62
+ return isConst ? text : "number";
63
+ }
64
+ return "any";
65
+ }
66
+ /**
67
+ * Extract text from startIndex to endIndex of a node, but strip
68
+ * the body block (everything from first '{' at depth 0).
69
+ * Used for functions and methods.
70
+ */
71
+ function extractSignature(content, node) {
72
+ const bodyNode = node.childForFieldName("body");
73
+ if (!bodyNode) {
74
+ // No body (e.g., overload signature) - return as-is
75
+ return content.substring(node.startIndex, node.endIndex);
76
+ }
77
+ // Return everything up to the body
78
+ return content.substring(node.startIndex, bodyNode.startIndex).trimEnd();
79
+ }
80
+ /**
81
+ * Get the text range of a node, preserving original formatting.
82
+ */
83
+ function nodeText(content, node) {
84
+ return content.substring(node.startIndex, node.endIndex);
85
+ }
86
+ function classifyExportedFunction(funcNode) {
87
+ // Function overload signatures (no body) are always prunable
88
+ const body = funcNode.childForFieldName("body");
89
+ if (!body) {
90
+ return { prunable: true, reason: "function overload signature" };
91
+ }
92
+ const returnType = funcNode.childForFieldName("return_type");
93
+ if (returnType) {
94
+ return { prunable: true, reason: "function with explicit return type" };
95
+ }
96
+ return { prunable: false, reason: "function without return type" };
97
+ }
98
+ function classifyExportedVariable(declarator, kind) {
99
+ const typeAnnotation = declarator.childForFieldName("type");
100
+ if (typeAnnotation) {
101
+ return { prunable: true, reason: `${kind} with type annotation` };
102
+ }
103
+ const value = declarator.childForFieldName("value");
104
+ if (!value) {
105
+ return { prunable: false, reason: `${kind} without type annotation or value` };
106
+ }
107
+ // Check for simple literal values
108
+ if (isSimpleLiteral(value)) {
109
+ return { prunable: true, reason: `${kind} with primitive literal` };
110
+ }
111
+ // Everything else is unprunable
112
+ const vt = value.type;
113
+ if (vt === "object")
114
+ return { prunable: false, reason: `${kind} = object literal` };
115
+ if (vt === "array")
116
+ return { prunable: false, reason: `${kind} = array literal` };
117
+ if (vt === "new_expression")
118
+ return { prunable: false, reason: `${kind} = new expression` };
119
+ if (vt === "call_expression")
120
+ return { prunable: false, reason: `${kind} = function call` };
121
+ if (vt === "arrow_function") {
122
+ // Arrow without return type on the const itself
123
+ return { prunable: false, reason: `${kind} = arrow function without type annotation` };
124
+ }
125
+ if (vt === "function_expression" || vt === "function") {
126
+ return { prunable: false, reason: `${kind} = function expression without type annotation` };
127
+ }
128
+ if (vt === "template_string") {
129
+ // Template literals with expressions are unprunable
130
+ const hasExpr = value.children.some(c => c.type === "template_substitution");
131
+ if (hasExpr)
132
+ return { prunable: false, reason: `${kind} = template literal with expressions` };
133
+ // Plain template string (no expressions) - treat as string literal
134
+ return { prunable: true, reason: `${kind} with template literal (no expressions)` };
135
+ }
136
+ return { prunable: false, reason: `${kind} = complex expression (${vt})` };
137
+ }
138
+ /**
139
+ * Classify a single top-level node (export_statement or ambient declaration).
140
+ * Returns null if the node is not an export (skip it).
141
+ */
142
+ function classifyNode(node) {
143
+ // ─── Re-exports ──────────────────────────────────────────
144
+ if (node.type === "export_statement") {
145
+ const source = node.childForFieldName("source");
146
+ // export * from "..." or export { ... } from "..."
147
+ if (source) {
148
+ return { prunable: true, reason: "re-export" };
149
+ }
150
+ // export { localA, localB } (no "from")
151
+ const hasDeclaration = node.childForFieldName("declaration");
152
+ if (!hasDeclaration) {
153
+ // Check if it's export { ... } (named re-export from local scope)
154
+ const hasExportClause = node.children.some(c => c.type === "export_clause");
155
+ if (hasExportClause) {
156
+ return { prunable: true, reason: "local re-export" };
157
+ }
158
+ // export default <expression>
159
+ const defaultKw = node.children.some(c => c.type === "default");
160
+ if (defaultKw) {
161
+ // Check if it's export default class or export default function
162
+ const valueNode = node.children.find(c => c.type !== "export" && c.type !== "default" &&
163
+ c.type !== "comment" && c.type !== ";");
164
+ if (valueNode) {
165
+ if (valueNode.type === "class_declaration" || valueNode.type === "class") {
166
+ return { prunable: true, reason: "export default class" };
167
+ }
168
+ if (valueNode.type === "function_declaration" || valueNode.type === "function") {
169
+ return classifyExportedFunction(valueNode);
170
+ }
171
+ }
172
+ return { prunable: false, reason: "export default expression" };
173
+ }
174
+ return null; // Not a classifiable export
175
+ }
176
+ const decl = hasDeclaration;
177
+ // ─── Interface ───────────────────────────────────────
178
+ if (decl.type === "interface_declaration") {
179
+ return { prunable: true, reason: "interface" };
180
+ }
181
+ // ─── Type alias ──────────────────────────────────────
182
+ if (decl.type === "type_alias_declaration") {
183
+ return { prunable: true, reason: "type alias" };
184
+ }
185
+ // ─── Enum ────────────────────────────────────────────
186
+ if (decl.type === "enum_declaration") {
187
+ return { prunable: true, reason: "enum" };
188
+ }
189
+ // ─── Class (abstract or regular) ─────────────────────
190
+ if (decl.type === "class_declaration" || decl.type === "abstract_class_declaration") {
191
+ return { prunable: true, reason: "class" };
192
+ }
193
+ // ─── Function ────────────────────────────────────────
194
+ if (decl.type === "function_declaration") {
195
+ return classifyExportedFunction(decl);
196
+ }
197
+ // ─── Function overloads (multiple signatures) ────────
198
+ if (decl.type === "function_signature") {
199
+ return { prunable: true, reason: "function overload signature" };
200
+ }
201
+ // ─── Lexical declaration (const/let/var) ─────────────
202
+ if (decl.type === "lexical_declaration" || decl.type === "variable_declaration") {
203
+ const kindNode = decl.child(0);
204
+ const kind = kindNode?.text ?? "const";
205
+ for (const child of decl.children) {
206
+ if (child.type === "variable_declarator") {
207
+ const result = classifyExportedVariable(child, kind);
208
+ if (!result.prunable)
209
+ return result;
210
+ }
211
+ }
212
+ return { prunable: true, reason: `${kind} (all declarators explicit)` };
213
+ }
214
+ // ─── Ambient declarations ────────────────────────────
215
+ if (decl.type === "ambient_declaration") {
216
+ return { prunable: true, reason: "ambient declaration" };
217
+ }
218
+ // Unknown declaration type - conservative: unprunable
219
+ return { prunable: false, reason: `unknown export declaration: ${decl.type}` };
220
+ }
221
+ // ─── Ambient declarations at top level ───────────────────
222
+ if (node.type === "ambient_declaration") {
223
+ return { prunable: true, reason: "ambient declaration" };
224
+ }
225
+ return null; // Not an export, skip
226
+ }
227
+ // ─── Shadow Generation ───────────────────────────────────────────────
228
+ /**
229
+ * Check if a function_declaration at root child index `idx` is the implementation
230
+ * signature of an overload group. True if any earlier sibling is an exported
231
+ * function_declaration or function_signature with the same name and no body.
232
+ */
233
+ function isOverloadImplementation(root, idx, funcName) {
234
+ for (let j = idx - 1; j >= 0; j--) {
235
+ const prev = root.child(j);
236
+ if (prev.type !== "export_statement")
237
+ continue;
238
+ const prevDecl = prev.childForFieldName("declaration");
239
+ if (!prevDecl)
240
+ continue;
241
+ // Previous sibling is a function overload signature (no body, same name)
242
+ if (prevDecl.type === "function_signature") {
243
+ const prevName = prevDecl.childForFieldName("name")?.text;
244
+ if (prevName === funcName)
245
+ return true;
246
+ }
247
+ // Previous sibling is a function_declaration without body (also overload)
248
+ if (prevDecl.type === "function_declaration") {
249
+ const prevName = prevDecl.childForFieldName("name")?.text;
250
+ if (prevName === funcName && !prevDecl.childForFieldName("body")) {
251
+ return true;
252
+ }
253
+ // Different function name - stop looking
254
+ if (prevName !== funcName)
255
+ break;
256
+ }
257
+ // Non-function export - stop looking
258
+ if (prevDecl.type !== "function_declaration" && prevDecl.type !== "function_signature") {
259
+ break;
260
+ }
261
+ }
262
+ return false;
263
+ }
264
+ /**
265
+ * Generate .d.ts shadow content for a prunable file.
266
+ * Walks the AST and emits declaration-only content.
267
+ */
268
+ function generateShadow(content, tree) {
269
+ const lines = [];
270
+ const root = tree.rootNode;
271
+ for (let i = 0; i < root.childCount; i++) {
272
+ const node = root.child(i);
273
+ // ─── Import statements: keep them (needed for type resolution) ───
274
+ if (node.type === "import_statement") {
275
+ // Skip side-effect imports: import "foo" / import 'foo'
276
+ const source = node.childForFieldName("source");
277
+ const hasClause = node.children.some(c => c.type === "import_clause" || c.type === "namespace_import" ||
278
+ c.type === "named_imports");
279
+ if (hasClause || !source) {
280
+ lines.push(nodeText(content, node));
281
+ }
282
+ continue;
283
+ }
284
+ // ─── Ambient declarations ────────────────────────────────────
285
+ if (node.type === "ambient_declaration") {
286
+ lines.push(nodeText(content, node));
287
+ continue;
288
+ }
289
+ // ─── Export statements ───────────────────────────────────────
290
+ if (node.type !== "export_statement")
291
+ continue;
292
+ const source = node.childForFieldName("source");
293
+ // Re-exports: copy verbatim
294
+ if (source) {
295
+ lines.push(nodeText(content, node));
296
+ continue;
297
+ }
298
+ const decl = node.childForFieldName("declaration");
299
+ // export { ... } - copy verbatim
300
+ if (!decl) {
301
+ lines.push(nodeText(content, node));
302
+ continue;
303
+ }
304
+ // ─── Interface / Type / Enum: copy verbatim ─────────────────
305
+ if (decl.type === "interface_declaration" ||
306
+ decl.type === "type_alias_declaration" ||
307
+ decl.type === "enum_declaration") {
308
+ lines.push(nodeText(content, node));
309
+ continue;
310
+ }
311
+ // ─── Class: keep structure, strip method bodies ─────────────
312
+ if (decl.type === "class_declaration" || decl.type === "abstract_class_declaration") {
313
+ lines.push(emitClassShadow(content, node, decl));
314
+ continue;
315
+ }
316
+ // ─── Function: emit signature only ──────────────────────────
317
+ if (decl.type === "function_declaration") {
318
+ // Overload exclusion: if this function has a body AND a previous
319
+ // sibling is an overload signature with the same name, this is the
320
+ // implementation signature - invisible in .d.ts, skip it.
321
+ const funcBody = decl.childForFieldName("body");
322
+ if (funcBody) {
323
+ const funcName = decl.childForFieldName("name")?.text;
324
+ if (funcName && isOverloadImplementation(root, i, funcName)) {
325
+ continue; // Skip implementation signature
326
+ }
327
+ }
328
+ lines.push(emitFunctionShadow(content, node, decl));
329
+ continue;
330
+ }
331
+ // ─── Function signature (overload without body) ─────────────
332
+ if (decl.type === "function_signature") {
333
+ lines.push(nodeText(content, node));
334
+ continue;
335
+ }
336
+ // ─── Lexical declaration (const/let/var) ────────────────────
337
+ if (decl.type === "lexical_declaration" || decl.type === "variable_declaration") {
338
+ lines.push(emitVariableShadow(content, decl));
339
+ continue;
340
+ }
341
+ // ─── Ambient declaration ────────────────────────────────────
342
+ if (decl.type === "ambient_declaration") {
343
+ lines.push(nodeText(content, node));
344
+ continue;
345
+ }
346
+ // Fallback: copy verbatim
347
+ lines.push(nodeText(content, node));
348
+ }
349
+ return lines.join("\n") + "\n";
350
+ }
351
+ function emitClassShadow(content, exportNode, classNode) {
352
+ const bodyNode = classNode.childForFieldName("body");
353
+ if (!bodyNode) {
354
+ return nodeText(content, exportNode);
355
+ }
356
+ // Emit everything up to class body opening brace
357
+ let result = content.substring(exportNode.startIndex, bodyNode.startIndex + 1) + "\n";
358
+ // Walk class body members
359
+ for (let j = 0; j < bodyNode.childCount; j++) {
360
+ const member = bodyNode.child(j);
361
+ // Skip { and } tokens
362
+ if (member.type === "{" || member.type === "}")
363
+ continue;
364
+ // Method definitions and constructors: strip body, keep signature
365
+ if (member.type === "method_definition") {
366
+ const methodBody = member.childForFieldName("body");
367
+ if (methodBody) {
368
+ let sig = content.substring(member.startIndex, methodBody.startIndex).trimEnd();
369
+ // Strip default parameter values from signatures (invalid in .d.ts)
370
+ sig = stripParameterDefaults(sig);
371
+ // Constructor parameter properties: strip access modifiers
372
+ // (private/protected/public/readonly are invalid on params in .d.ts)
373
+ const nameNode = member.childForFieldName("name");
374
+ if (nameNode?.text === "constructor") {
375
+ sig = stripConstructorParamProperties(sig);
376
+ }
377
+ result += sig + ";\n";
378
+ }
379
+ else {
380
+ result += nodeText(content, member) + "\n";
381
+ }
382
+ continue;
383
+ }
384
+ // Property declarations: strip initializers (TS1039 in ambient context)
385
+ if (member.type === "public_field_definition" || member.type === "property_declaration") {
386
+ result += emitPropertyDeclaration(content, member) + "\n";
387
+ continue;
388
+ }
389
+ // Everything else (decorators, semicolons, etc.): copy verbatim
390
+ result += nodeText(content, member) + "\n";
391
+ }
392
+ result += "}";
393
+ return result;
394
+ }
395
+ /**
396
+ * Strip default parameter values from a method/constructor signature.
397
+ * e.g. "constructor(private x = 5, y: string = 'a')" -> "constructor(private x: any, y: string)"
398
+ * This is needed because .d.ts files cannot have parameter initializers.
399
+ */
400
+ function stripParameterDefaults(sig) {
401
+ // Find the parameter list between the outermost parens
402
+ const openParen = sig.indexOf("(");
403
+ if (openParen === -1)
404
+ return sig;
405
+ // Find matching close paren. Track () [] {} for depth -NOT <> because
406
+ // arrow functions (=>) would be misread as closing angle brackets.
407
+ // Also skip string literals to avoid depth corruption from chars inside strings.
408
+ let depth = 0;
409
+ let closeParen = -1;
410
+ let inString = null;
411
+ for (let i = openParen; i < sig.length; i++) {
412
+ const ch = sig[i];
413
+ if (inString) {
414
+ if (ch === inString && sig[i - 1] !== "\\")
415
+ inString = null;
416
+ continue;
417
+ }
418
+ if (ch === '"' || ch === "'" || ch === '`') {
419
+ inString = ch;
420
+ continue;
421
+ }
422
+ if (ch === "(" || ch === "[" || ch === "{")
423
+ depth++;
424
+ if (ch === ")" || ch === "]" || ch === "}") {
425
+ depth--;
426
+ if (depth === 0 && ch === ")") {
427
+ closeParen = i;
428
+ break;
429
+ }
430
+ }
431
+ }
432
+ if (closeParen === -1)
433
+ return sig;
434
+ const before = sig.substring(0, openParen + 1);
435
+ const params = sig.substring(openParen + 1, closeParen);
436
+ const after = sig.substring(closeParen);
437
+ const cleanedParams = splitAndCleanParams(params);
438
+ return before + cleanedParams + after;
439
+ }
440
+ function splitAndCleanParams(params) {
441
+ const result = [];
442
+ let depth = 0;
443
+ let current = "";
444
+ let inString = null;
445
+ for (let i = 0; i < params.length; i++) {
446
+ const ch = params[i];
447
+ if (inString) {
448
+ if (ch === inString && params[i - 1] !== "\\")
449
+ inString = null;
450
+ current += ch;
451
+ continue;
452
+ }
453
+ if (ch === '"' || ch === "'" || ch === '`') {
454
+ inString = ch;
455
+ current += ch;
456
+ continue;
457
+ }
458
+ if (ch === "(" || ch === "[" || ch === "{" || ch === "<")
459
+ depth++;
460
+ if (ch === ")" || ch === "]" || ch === "}")
461
+ depth--;
462
+ if (ch === ">" && !(i > 0 && params[i - 1] === "=") && depth > 0)
463
+ depth--;
464
+ if (ch === "," && depth === 0) {
465
+ result.push(cleanSingleParam(current.trim()));
466
+ current = "";
467
+ }
468
+ else {
469
+ current += ch;
470
+ }
471
+ }
472
+ if (current.trim())
473
+ result.push(cleanSingleParam(current.trim()));
474
+ return result.join(", ");
475
+ }
476
+ function cleanSingleParam(param) {
477
+ if (!param)
478
+ return param;
479
+ // Find "=" at depth 0 (the default value).
480
+ // Only track () [] {} - not <> (arrow => would corrupt depth).
481
+ let depth = 0;
482
+ let eqIdx = -1;
483
+ for (let i = 0; i < param.length; i++) {
484
+ const ch = param[i];
485
+ if (ch === "(" || ch === "[" || ch === "{")
486
+ depth++;
487
+ if (ch === ")" || ch === "]" || ch === "}")
488
+ depth--;
489
+ if (ch === "=" && depth === 0 && param[i - 1] !== "!" && param[i + 1] !== ">") {
490
+ eqIdx = i;
491
+ break;
492
+ }
493
+ }
494
+ if (eqIdx === -1)
495
+ return param; // No default value
496
+ const beforeEq = param.substring(0, eqIdx).trimEnd();
497
+ // Check if there's already a type annotation before the =
498
+ // e.g. "y: string = 'a'" -> "y: string" (just strip " = 'a'")
499
+ // e.g. "private x = 5" -> "private x: any" (no type, add : any)
500
+ if (hasTypeAnnotation(beforeEq)) {
501
+ return beforeEq;
502
+ }
503
+ // No type annotation - need to add one. Use the default value to infer a simple type.
504
+ const defaultVal = param.substring(eqIdx + 1).trim();
505
+ const inferredType = inferSimpleType(defaultVal);
506
+ return beforeEq + ": " + inferredType;
507
+ }
508
+ function hasTypeAnnotation(paramBefore) {
509
+ // Walk backward from end, skip whitespace, look for a type annotation pattern.
510
+ // A type annotation has ":" followed by a type. But ":" can also appear in
511
+ // destructuring. We check if there's a ":" that isn't inside brackets.
512
+ let depth = 0;
513
+ for (let i = paramBefore.length - 1; i >= 0; i--) {
514
+ const ch = paramBefore[i];
515
+ if (ch === ")" || ch === ">" || ch === "]" || ch === "}")
516
+ depth++;
517
+ if (ch === "(" || ch === "<" || ch === "[" || ch === "{")
518
+ depth--;
519
+ if (ch === ":" && depth === 0)
520
+ return true;
521
+ }
522
+ return false;
523
+ }
524
+ /**
525
+ * Strip parameter property modifiers from constructor parameters.
526
+ * "constructor(private x: number, protected readonly y: string)"
527
+ * -> "constructor(x: number, y: string)"
528
+ * TS2369: parameter properties are only allowed in constructor implementations.
529
+ */
530
+ function stripConstructorParamProperties(sig) {
531
+ const openParen = sig.indexOf("(");
532
+ if (openParen === -1)
533
+ return sig;
534
+ let depth = 0;
535
+ let closeParen = -1;
536
+ for (let i = openParen; i < sig.length; i++) {
537
+ const ch = sig[i];
538
+ if (ch === "(" || ch === "[" || ch === "{")
539
+ depth++;
540
+ if (ch === ")" || ch === "]" || ch === "}") {
541
+ depth--;
542
+ if (depth === 0 && ch === ")") {
543
+ closeParen = i;
544
+ break;
545
+ }
546
+ }
547
+ }
548
+ if (closeParen === -1)
549
+ return sig;
550
+ const before = sig.substring(0, openParen + 1);
551
+ const params = sig.substring(openParen + 1, closeParen);
552
+ const after = sig.substring(closeParen);
553
+ // Process each param: strip leading access modifiers
554
+ const ACCESS_MODIFIERS = /^(?:(?:private|protected|public|readonly|override)\s+)+/;
555
+ const cleaned = splitParams(params).map(p => {
556
+ const trimmed = p.trim();
557
+ return trimmed.replace(ACCESS_MODIFIERS, "");
558
+ });
559
+ return before + cleaned.join(", ") + after;
560
+ }
561
+ /** Split parameter string respecting nested brackets. */
562
+ function splitParams(params) {
563
+ const result = [];
564
+ let depth = 0;
565
+ let current = "";
566
+ for (let i = 0; i < params.length; i++) {
567
+ const ch = params[i];
568
+ if (ch === "(" || ch === "<" || ch === "[" || ch === "{")
569
+ depth++;
570
+ if (ch === ")" || ch === "]" || ch === "}")
571
+ depth--;
572
+ if (ch === ">" && !(i > 0 && params[i - 1] === "=") && depth > 0)
573
+ depth--;
574
+ if (ch === "," && depth === 0) {
575
+ result.push(current);
576
+ current = "";
577
+ }
578
+ else {
579
+ current += ch;
580
+ }
581
+ }
582
+ if (current.trim())
583
+ result.push(current);
584
+ return result;
585
+ }
586
+ function inferSimpleType(defaultVal) {
587
+ if (/^["']/.test(defaultVal))
588
+ return "string";
589
+ if (/^-?\d/.test(defaultVal))
590
+ return "number";
591
+ if (defaultVal === "true" || defaultVal === "false")
592
+ return "boolean";
593
+ if (defaultVal === "null")
594
+ return "null";
595
+ if (defaultVal === "undefined")
596
+ return "undefined";
597
+ return "any";
598
+ }
599
+ /**
600
+ * Emit a class property declaration, stripping initializers.
601
+ * "private cache = new Map()" -> "private cache: any;"
602
+ * "public name: string = 'x'" -> "public name: string;"
603
+ * "readonly x = 5" -> "readonly x: number;"
604
+ */
605
+ function emitPropertyDeclaration(content, member) {
606
+ const valueNode = member.childForFieldName("value");
607
+ if (!valueNode) {
608
+ // No initializer - emit as-is (already declaration-only)
609
+ const text = nodeText(content, member);
610
+ return text.endsWith(";") ? text : text + ";";
611
+ }
612
+ // Has initializer - strip it
613
+ // Get everything before the "=" sign
614
+ const beforeValue = content.substring(member.startIndex, valueNode.startIndex);
615
+ // Find the "=" and strip it
616
+ const eqIdx = beforeValue.lastIndexOf("=");
617
+ if (eqIdx === -1) {
618
+ const text = nodeText(content, member);
619
+ return text.endsWith(";") ? text : text + ";";
620
+ }
621
+ let declaration = beforeValue.substring(0, eqIdx).trimEnd();
622
+ // Check if there's a type annotation
623
+ if (!hasTypeAnnotation(declaration)) {
624
+ // Infer type from the value
625
+ const valText = nodeText(content, valueNode).trim();
626
+ const inferredType = inferSimpleType(valText);
627
+ declaration += ": " + inferredType;
628
+ }
629
+ return declaration + ";";
630
+ }
631
+ function emitFunctionShadow(content, exportNode, funcNode) {
632
+ const body = funcNode.childForFieldName("body");
633
+ if (!body) {
634
+ // No body (overload signature) - copy as-is
635
+ return nodeText(content, exportNode);
636
+ }
637
+ // Extract signature (everything before the body)
638
+ const beforeExport = content.substring(exportNode.startIndex, funcNode.startIndex);
639
+ const sig = extractSignature(content, funcNode);
640
+ // Check for "default" keyword
641
+ const isDefault = beforeExport.includes("default");
642
+ // In .d.ts files, "declare" is implicit - "export default declare function" is invalid syntax
643
+ const exportPrefix = isDefault ? "export default " : "export declare ";
644
+ // Strip the "export" / "export default" prefix from the signature and re-add with "declare"
645
+ let cleanSig = sig.trimEnd();
646
+ // Strip parameter defaults (invalid in .d.ts ambient context)
647
+ cleanSig = stripParameterDefaults(cleanSig);
648
+ return exportPrefix + cleanSig + ";";
649
+ }
650
+ function emitVariableShadow(content, declNode) {
651
+ const kindNode = declNode.child(0);
652
+ const kind = kindNode?.text ?? "const";
653
+ const isConst = kind === "const";
654
+ const emitKw = isConst ? "const" : "let";
655
+ const parts = [];
656
+ for (const child of declNode.children) {
657
+ if (child.type !== "variable_declarator")
658
+ continue;
659
+ const nameNode = child.childForFieldName("name");
660
+ const typeNode = child.childForFieldName("type");
661
+ const valueNode = child.childForFieldName("value");
662
+ const name = nameNode?.text ?? "unknown";
663
+ if (typeNode) {
664
+ // Has type annotation: emit without value
665
+ const typeText = nodeText(content, typeNode);
666
+ parts.push(`${emitKw} ${name}${typeText}`);
667
+ }
668
+ else if (valueNode && isSimpleLiteral(valueNode)) {
669
+ // Primitive literal
670
+ const litType = literalTypeString(valueNode, isConst);
671
+ parts.push(`${emitKw} ${name}: ${litType}`);
672
+ }
673
+ else {
674
+ // Fallback for complex expressions - use any
675
+ parts.push(`${emitKw} ${name}: any`);
676
+ }
677
+ }
678
+ return `export declare ${parts.join(", ")};`;
679
+ }
680
+ // ─── Main Classification + Generation ────────────────────────────────
681
+ export function classifyAndGenerateShadow(filePath, content, parser, language) {
682
+ parser.setLanguage(language);
683
+ const tree = parser.parse(content);
684
+ try {
685
+ const root = tree.rootNode;
686
+ const reasons = [];
687
+ let hasExports = false;
688
+ let allPrunable = true;
689
+ for (let i = 0; i < root.childCount; i++) {
690
+ const node = root.child(i);
691
+ const classification = classifyNode(node);
692
+ if (classification === null)
693
+ continue;
694
+ hasExports = true;
695
+ reasons.push(`${classification.prunable ? "PRUNABLE" : "UNPRUNABLE"}: ${classification.reason}`);
696
+ if (!classification.prunable) {
697
+ allPrunable = false;
698
+ }
699
+ }
700
+ if (!hasExports) {
701
+ return { prunable: false, shadow: null, reasons: ["no exports"], category: "no-exports" };
702
+ }
703
+ if (!allPrunable) {
704
+ return { prunable: false, shadow: null, reasons, category: "inferred" };
705
+ }
706
+ // Generate shadow .d.ts
707
+ const shadow = generateShadow(content, tree);
708
+ return { prunable: true, shadow, reasons, category: "explicit" };
709
+ }
710
+ finally {
711
+ tree.delete(); // CRITICAL: prevent WASM memory leak
712
+ }
713
+ }
714
+ // ─── Project Scanner ─────────────────────────────────────────────────
715
+ function walkDirectory(dir) {
716
+ const files = [];
717
+ const stack = [dir];
718
+ while (stack.length > 0) {
719
+ const current = stack.pop();
720
+ let entries;
721
+ try {
722
+ entries = fs.readdirSync(current, { withFileTypes: true });
723
+ }
724
+ catch {
725
+ continue;
726
+ }
727
+ for (const entry of entries) {
728
+ if (entry.isDirectory()) {
729
+ if (!IGNORE_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
730
+ stack.push(path.join(current, entry.name));
731
+ }
732
+ }
733
+ else if (/\.(ts|tsx)$/i.test(entry.name) &&
734
+ !entry.name.endsWith(".d.ts")) {
735
+ files.push(toPosix(path.join(current, entry.name)));
736
+ }
737
+ }
738
+ }
739
+ return files;
740
+ }
741
+ export async function scanProject(rootDir, parserPool) {
742
+ // Ensure WASM runtime is initialized before loading languages
743
+ await parserPool.initialize();
744
+ // Load TypeScript language
745
+ const wasmDir = path.join(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/i, "$1")), "..", "..", "wasm");
746
+ const tsWasmPath = path.join(wasmDir, "tree-sitter-typescript.wasm");
747
+ const tsLanguage = await Parser.Language.load(toPosix(tsWasmPath));
748
+ const files = walkDirectory(rootDir);
749
+ const prunable = new Map();
750
+ const unprunable = new Set();
751
+ const ambientFiles = [];
752
+ let noExports = 0;
753
+ // Process files with parser pool for concurrency
754
+ const BATCH_SIZE = 50;
755
+ for (let i = 0; i < files.length; i += BATCH_SIZE) {
756
+ const batch = files.slice(i, i + BATCH_SIZE);
757
+ await Promise.all(batch.map(async (filePath) => {
758
+ let content;
759
+ try {
760
+ content = fs.readFileSync(path.normalize(filePath), "utf-8");
761
+ }
762
+ catch {
763
+ return;
764
+ }
765
+ // Ambient file detection
766
+ if (content.includes("declare global") ||
767
+ content.includes("declare module") ||
768
+ content.includes("/// <reference")) {
769
+ ambientFiles.push(filePath);
770
+ }
771
+ const parser = await parserPool.acquire(tsLanguage, "typescript");
772
+ try {
773
+ const result = classifyAndGenerateShadow(filePath, content, parser, tsLanguage);
774
+ if (result.category === "no-exports") {
775
+ noExports++;
776
+ }
777
+ else if (result.prunable && result.shadow) {
778
+ prunable.set(filePath, result.shadow);
779
+ }
780
+ else {
781
+ unprunable.add(filePath);
782
+ }
783
+ }
784
+ finally {
785
+ parserPool.release("typescript", parser);
786
+ }
787
+ }));
788
+ }
789
+ // Add @types declaration files as ambient.
790
+ // Walk up from rootDir to find node_modules/@types (handles monorepos
791
+ // where tsconfig is in src/ but node_modules is at repo root).
792
+ const typeRoots = [];
793
+ let searchDir = rootDir;
794
+ for (let depth = 0; depth < 5; depth++) {
795
+ const candidate = path.join(searchDir, "node_modules", "@types");
796
+ if (fs.existsSync(candidate)) {
797
+ typeRoots.push(candidate);
798
+ break;
799
+ }
800
+ const parent = path.dirname(searchDir);
801
+ if (parent === searchDir)
802
+ break; // filesystem root
803
+ searchDir = parent;
804
+ }
805
+ for (const root of typeRoots) {
806
+ try {
807
+ for (const pkg of fs.readdirSync(root)) {
808
+ const indexDts = toPosix(path.join(root, pkg, "index.d.ts"));
809
+ if (fs.existsSync(path.normalize(indexDts))) {
810
+ ambientFiles.push(indexDts);
811
+ }
812
+ }
813
+ }
814
+ catch { /* non-fatal */ }
815
+ }
816
+ return {
817
+ prunable,
818
+ unprunable,
819
+ ambientFiles,
820
+ stats: {
821
+ total: files.length,
822
+ pruned: prunable.size,
823
+ unpruned: unprunable.size,
824
+ noExports,
825
+ },
826
+ };
827
+ }
828
+ //# sourceMappingURL=shadow-generator.js.map