skrypt-ai 0.7.0 → 0.8.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 (110) hide show
  1. package/dist/auth/index.js +3 -3
  2. package/dist/cli.js +1 -1
  3. package/dist/commands/cron.js +0 -4
  4. package/dist/commands/generate/index.d.ts +3 -0
  5. package/dist/commands/generate/index.js +393 -0
  6. package/dist/commands/generate/scan.d.ts +41 -0
  7. package/dist/commands/generate/scan.js +256 -0
  8. package/dist/commands/generate/verify.d.ts +14 -0
  9. package/dist/commands/generate/verify.js +122 -0
  10. package/dist/commands/generate/write.d.ts +25 -0
  11. package/dist/commands/generate/write.js +120 -0
  12. package/dist/commands/import.js +4 -1
  13. package/dist/commands/llms-txt.js +6 -4
  14. package/dist/config/loader.d.ts +0 -1
  15. package/dist/config/loader.js +1 -1
  16. package/dist/generator/agents-md.d.ts +25 -0
  17. package/dist/generator/agents-md.js +122 -0
  18. package/dist/generator/index.d.ts +2 -0
  19. package/dist/generator/index.js +2 -0
  20. package/dist/generator/mdx-serializer.d.ts +11 -0
  21. package/dist/generator/mdx-serializer.js +135 -0
  22. package/dist/generator/organizer.d.ts +1 -16
  23. package/dist/generator/organizer.js +0 -38
  24. package/dist/generator/writer.js +5 -4
  25. package/dist/llm/proxy-client.d.ts +32 -0
  26. package/dist/llm/proxy-client.js +103 -0
  27. package/dist/scanner/csharp.d.ts +0 -4
  28. package/dist/scanner/csharp.js +9 -49
  29. package/dist/scanner/go.d.ts +0 -3
  30. package/dist/scanner/go.js +8 -35
  31. package/dist/scanner/java.d.ts +0 -4
  32. package/dist/scanner/java.js +9 -49
  33. package/dist/scanner/kotlin.d.ts +0 -3
  34. package/dist/scanner/kotlin.js +6 -33
  35. package/dist/scanner/php.d.ts +0 -10
  36. package/dist/scanner/php.js +11 -55
  37. package/dist/scanner/ruby.d.ts +0 -3
  38. package/dist/scanner/ruby.js +8 -38
  39. package/dist/scanner/rust.d.ts +0 -3
  40. package/dist/scanner/rust.js +10 -37
  41. package/dist/scanner/swift.d.ts +0 -3
  42. package/dist/scanner/swift.js +8 -35
  43. package/dist/scanner/utils.d.ts +41 -0
  44. package/dist/scanner/utils.js +97 -0
  45. package/dist/template/docs.json +5 -2
  46. package/dist/template/next.config.mjs +31 -0
  47. package/dist/template/package.json +5 -3
  48. package/dist/template/src/app/layout.tsx +13 -13
  49. package/dist/template/src/app/llms-full.md/route.ts +29 -0
  50. package/dist/template/src/app/llms.txt/route.ts +29 -0
  51. package/dist/template/src/app/md/[...slug]/route.ts +174 -0
  52. package/dist/template/src/app/reference/route.ts +22 -18
  53. package/dist/template/src/app/sitemap.ts +1 -1
  54. package/dist/template/src/components/ai-chat-impl.tsx +206 -0
  55. package/dist/template/src/components/ai-chat.tsx +20 -193
  56. package/dist/template/src/components/mdx/index.tsx +27 -4
  57. package/dist/template/src/lib/fonts.ts +135 -0
  58. package/dist/template/src/middleware.ts +101 -0
  59. package/dist/template/src/styles/globals.css +28 -20
  60. package/dist/utils/files.d.ts +0 -8
  61. package/dist/utils/files.js +0 -33
  62. package/package.json +1 -1
  63. package/dist/autofix/autofix.test.d.ts +0 -1
  64. package/dist/autofix/autofix.test.js +0 -487
  65. package/dist/commands/generate.d.ts +0 -9
  66. package/dist/commands/generate.js +0 -739
  67. package/dist/generator/generator.test.d.ts +0 -1
  68. package/dist/generator/generator.test.js +0 -259
  69. package/dist/generator/writer.test.d.ts +0 -1
  70. package/dist/generator/writer.test.js +0 -411
  71. package/dist/llm/llm.manual-test.d.ts +0 -1
  72. package/dist/llm/llm.manual-test.js +0 -112
  73. package/dist/llm/llm.mock-test.d.ts +0 -4
  74. package/dist/llm/llm.mock-test.js +0 -79
  75. package/dist/plugins/index.d.ts +0 -47
  76. package/dist/plugins/index.js +0 -181
  77. package/dist/scanner/content-type.test.d.ts +0 -1
  78. package/dist/scanner/content-type.test.js +0 -231
  79. package/dist/scanner/integration.test.d.ts +0 -4
  80. package/dist/scanner/integration.test.js +0 -180
  81. package/dist/scanner/scanner.test.d.ts +0 -1
  82. package/dist/scanner/scanner.test.js +0 -210
  83. package/dist/scanner/typescript.manual-test.d.ts +0 -1
  84. package/dist/scanner/typescript.manual-test.js +0 -112
  85. package/dist/template/src/app/docs/auth/page.mdx +0 -589
  86. package/dist/template/src/app/docs/autofix/page.mdx +0 -624
  87. package/dist/template/src/app/docs/cli/page.mdx +0 -217
  88. package/dist/template/src/app/docs/config/page.mdx +0 -428
  89. package/dist/template/src/app/docs/configuration/page.mdx +0 -86
  90. package/dist/template/src/app/docs/deployment/page.mdx +0 -112
  91. package/dist/template/src/app/docs/generator/generator.md +0 -504
  92. package/dist/template/src/app/docs/generator/organizer.md +0 -779
  93. package/dist/template/src/app/docs/generator/page.mdx +0 -613
  94. package/dist/template/src/app/docs/github/page.mdx +0 -502
  95. package/dist/template/src/app/docs/llm/anthropic-client.md +0 -549
  96. package/dist/template/src/app/docs/llm/index.md +0 -471
  97. package/dist/template/src/app/docs/llm/page.mdx +0 -428
  98. package/dist/template/src/app/docs/plugins/page.mdx +0 -1793
  99. package/dist/template/src/app/docs/pro/page.mdx +0 -121
  100. package/dist/template/src/app/docs/quickstart/page.mdx +0 -93
  101. package/dist/template/src/app/docs/scanner/content-type.md +0 -599
  102. package/dist/template/src/app/docs/scanner/index.md +0 -212
  103. package/dist/template/src/app/docs/scanner/page.mdx +0 -307
  104. package/dist/template/src/app/docs/scanner/python.md +0 -469
  105. package/dist/template/src/app/docs/scanner/python_parser.md +0 -1056
  106. package/dist/template/src/app/docs/scanner/rust.md +0 -325
  107. package/dist/template/src/app/docs/scanner/typescript.md +0 -201
  108. package/dist/template/src/app/icon.tsx +0 -29
  109. package/dist/utils/validation.d.ts +0 -1
  110. package/dist/utils/validation.js +0 -12
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'fs';
2
+ import { splitParams, getLineNumber, getSourceContext, findMatchingBrace } from './utils.js';
2
3
  /**
3
4
  * Scanner for C# source files
4
5
  * Extracts: public classes, interfaces, enums, structs, records, methods
@@ -67,7 +68,7 @@ export class CSharpScanner {
67
68
  // Extract generics with depth counting to handle nested generics
68
69
  const afterName = match.index + match[0].length;
69
70
  const generics = this.extractGenerics(source, afterName);
70
- const lineNumber = this.getLineNumber(source, match.index);
71
+ const lineNumber = getLineNumber(source, match.index);
71
72
  const docstring = this.getDocComment(lines, lineNumber - 1);
72
73
  // For records with primary constructor params, extract them
73
74
  let parameters = [];
@@ -90,7 +91,7 @@ export class CSharpScanner {
90
91
  isPublic: true,
91
92
  imports,
92
93
  packageName,
93
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
94
+ sourceContext: getSourceContext(lines, lineNumber, 15)
94
95
  });
95
96
  }
96
97
  }
@@ -150,7 +151,7 @@ export class CSharpScanner {
150
151
  returnType === 'record') {
151
152
  continue;
152
153
  }
153
- const lineNumber = this.getLineNumber(source, match.index);
154
+ const lineNumber = getLineNumber(source, match.index);
154
155
  const docstring = this.getDocComment(lines, lineNumber - 1);
155
156
  const parameters = this.parseCSharpParams(paramsStr);
156
157
  const isAsync = modifiers.includes('async');
@@ -173,7 +174,7 @@ export class CSharpScanner {
173
174
  isPublic: true,
174
175
  imports,
175
176
  packageName,
176
- sourceContext: this.getSourceContext(lines, lineNumber)
177
+ sourceContext: getSourceContext(lines, lineNumber)
177
178
  });
178
179
  }
179
180
  // Also extract interface method signatures (no body, just declarations)
@@ -228,7 +229,7 @@ export class CSharpScanner {
228
229
  if (paramsStr === undefined)
229
230
  continue;
230
231
  const absoluteIndex = range.bodyStart + match.index;
231
- const lineNumber = this.getLineNumber(source, absoluteIndex);
232
+ const lineNumber = getLineNumber(source, absoluteIndex);
232
233
  const docstring = this.getDocComment(lines, lineNumber - 1);
233
234
  const parameters = this.parseCSharpParams(paramsStr);
234
235
  const signature = `${returnType} ${name}(${paramsStr})`;
@@ -247,7 +248,7 @@ export class CSharpScanner {
247
248
  isPublic: true,
248
249
  imports,
249
250
  packageName,
250
- sourceContext: this.getSourceContext(lines, lineNumber)
251
+ sourceContext: getSourceContext(lines, lineNumber)
251
252
  });
252
253
  }
253
254
  }
@@ -271,7 +272,7 @@ export class CSharpScanner {
271
272
  if (semicolonBefore !== -1 && semicolonBefore < afterMatch)
272
273
  continue;
273
274
  // Find matching closing brace
274
- const bodyEnd = this.findMatchingBrace(source, afterMatch);
275
+ const bodyEnd = findMatchingBrace(source, afterMatch);
275
276
  if (bodyEnd === -1)
276
277
  continue;
277
278
  ranges.push({
@@ -284,19 +285,6 @@ export class CSharpScanner {
284
285
  }
285
286
  return ranges;
286
287
  }
287
- findMatchingBrace(source, openIndex) {
288
- let depth = 0;
289
- for (let i = openIndex; i < source.length; i++) {
290
- if (source[i] === '{')
291
- depth++;
292
- else if (source[i] === '}') {
293
- depth--;
294
- if (depth === 0)
295
- return i;
296
- }
297
- }
298
- return -1;
299
- }
300
288
  findParentClass(index, classRanges) {
301
289
  for (const range of classRanges) {
302
290
  if (index > range.bodyStart && index < range.bodyEnd) {
@@ -309,7 +297,7 @@ export class CSharpScanner {
309
297
  if (!paramsStr.trim())
310
298
  return [];
311
299
  const params = [];
312
- const parts = this.splitParams(paramsStr);
300
+ const parts = splitParams(paramsStr);
313
301
  for (const part of parts) {
314
302
  const trimmed = part.trim();
315
303
  if (!trimmed)
@@ -337,29 +325,6 @@ export class CSharpScanner {
337
325
  }
338
326
  return params;
339
327
  }
340
- splitParams(str) {
341
- const parts = [];
342
- let depth = 0;
343
- let current = '';
344
- for (const char of str) {
345
- if (char === '<' || char === '(' || char === '[' || char === '{')
346
- depth++;
347
- else if (char === '>' || char === ')' || char === ']' || char === '}')
348
- depth--;
349
- else if (char === ',' && depth === 0) {
350
- parts.push(current);
351
- current = '';
352
- continue;
353
- }
354
- current += char;
355
- }
356
- if (current.trim())
357
- parts.push(current);
358
- return parts;
359
- }
360
- getLineNumber(source, index) {
361
- return source.slice(0, index).split('\n').length;
362
- }
363
328
  getDocComment(lines, lineIndex) {
364
329
  const comments = [];
365
330
  let i = lineIndex - 1;
@@ -413,9 +378,4 @@ export class CSharpScanner {
413
378
  }
414
379
  return '';
415
380
  }
416
- getSourceContext(lines, lineNumber, context = 5) {
417
- const start = Math.max(0, lineNumber - context - 1);
418
- const end = Math.min(lines.length, lineNumber + context);
419
- return lines.slice(start, end).join('\n');
420
- }
421
381
  }
@@ -12,9 +12,6 @@ export declare class GoScanner implements Scanner {
12
12
  private extractMethods;
13
13
  private extractTypes;
14
14
  private parseGoParams;
15
- private splitParams;
16
15
  private parseReturnType;
17
- private getLineNumber;
18
16
  private getDocComment;
19
- private getSourceContext;
20
17
  }
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'fs';
2
+ import { splitParamsNoAngleBrackets, getLineNumber, getSourceContext } from './utils.js';
2
3
  /**
3
4
  * Scanner for Go source files
4
5
  * Extracts: functions, methods, types (structs), interfaces
@@ -71,7 +72,7 @@ export class GoScanner {
71
72
  continue;
72
73
  const typeParams = match[2] ?? '';
73
74
  const returnPart = (match[4] ?? '').trim();
74
- const lineNumber = this.getLineNumber(source, match.index);
75
+ const lineNumber = getLineNumber(source, match.index);
75
76
  const docstring = this.getDocComment(lines, lineNumber - 1);
76
77
  const parameters = this.parseGoParams(paramsStr);
77
78
  const returnType = this.parseReturnType(returnPart);
@@ -89,7 +90,7 @@ export class GoScanner {
89
90
  isPublic: true,
90
91
  imports,
91
92
  packageName,
92
- sourceContext: this.getSourceContext(lines, lineNumber)
93
+ sourceContext: getSourceContext(lines, lineNumber)
93
94
  });
94
95
  }
95
96
  }
@@ -106,7 +107,7 @@ export class GoScanner {
106
107
  continue;
107
108
  const typeParams = match[4] ?? '';
108
109
  const returnPart = (match[6] ?? '').trim();
109
- const lineNumber = this.getLineNumber(source, match.index);
110
+ const lineNumber = getLineNumber(source, match.index);
110
111
  const docstring = this.getDocComment(lines, lineNumber - 1);
111
112
  const parameters = this.parseGoParams(paramsStr);
112
113
  const returnType = this.parseReturnType(returnPart);
@@ -126,7 +127,7 @@ export class GoScanner {
126
127
  isPublic: true,
127
128
  imports,
128
129
  packageName,
129
- sourceContext: this.getSourceContext(lines, lineNumber)
130
+ sourceContext: getSourceContext(lines, lineNumber)
130
131
  });
131
132
  }
132
133
  }
@@ -139,7 +140,7 @@ export class GoScanner {
139
140
  if (!name)
140
141
  continue;
141
142
  const isInterface = match[0].includes('interface');
142
- const lineNumber = this.getLineNumber(source, match.index);
143
+ const lineNumber = getLineNumber(source, match.index);
143
144
  const docstring = this.getDocComment(lines, lineNumber - 1);
144
145
  const signature = `type ${name} ${isInterface ? 'interface' : 'struct'}`;
145
146
  elements.push({
@@ -154,7 +155,7 @@ export class GoScanner {
154
155
  isPublic: true,
155
156
  imports,
156
157
  packageName,
157
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
158
+ sourceContext: getSourceContext(lines, lineNumber, 15)
158
159
  });
159
160
  }
160
161
  }
@@ -163,7 +164,7 @@ export class GoScanner {
163
164
  return [];
164
165
  const params = [];
165
166
  // Split by comma but respect parentheses
166
- const parts = this.splitParams(paramsStr);
167
+ const parts = splitParamsNoAngleBrackets(paramsStr);
167
168
  for (const part of parts) {
168
169
  const trimmed = part.trim();
169
170
  if (!trimmed)
@@ -185,26 +186,6 @@ export class GoScanner {
185
186
  }
186
187
  return params;
187
188
  }
188
- splitParams(str) {
189
- const parts = [];
190
- let depth = 0;
191
- let current = '';
192
- for (const char of str) {
193
- if (char === '(' || char === '[' || char === '{')
194
- depth++;
195
- else if (char === ')' || char === ']' || char === '}')
196
- depth--;
197
- else if (char === ',' && depth === 0) {
198
- parts.push(current);
199
- current = '';
200
- continue;
201
- }
202
- current += char;
203
- }
204
- if (current.trim())
205
- parts.push(current);
206
- return parts;
207
- }
208
189
  parseReturnType(returnPart) {
209
190
  const trimmed = returnPart.trim();
210
191
  if (!trimmed)
@@ -215,9 +196,6 @@ export class GoScanner {
215
196
  }
216
197
  return trimmed || undefined;
217
198
  }
218
- getLineNumber(source, index) {
219
- return source.slice(0, index).split('\n').length;
220
- }
221
199
  getDocComment(lines, lineIndex) {
222
200
  const comments = [];
223
201
  let i = lineIndex - 1;
@@ -261,9 +239,4 @@ export class GoScanner {
261
239
  }
262
240
  return comments.length > 0 ? comments.join('\n') : undefined;
263
241
  }
264
- getSourceContext(lines, lineNumber, context = 5) {
265
- const start = Math.max(0, lineNumber - context - 1);
266
- const end = Math.min(lines.length, lineNumber + context);
267
- return lines.slice(start, end).join('\n');
268
- }
269
242
  }
@@ -25,15 +25,11 @@ export declare class JavaScanner implements Scanner {
25
25
  * Finds all class/interface/enum/record declarations and their brace-delimited ranges.
26
26
  */
27
27
  private findClassRanges;
28
- private findMatchingBrace;
29
28
  /**
30
29
  * Finds the innermost class that contains the given source index,
31
30
  * using brace-depth-aware class ranges.
32
31
  */
33
32
  private findParentClass;
34
33
  private parseParams;
35
- private splitParams;
36
- private getLineNumber;
37
34
  private getJavadoc;
38
- private getSourceContext;
39
35
  }
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'fs';
2
+ import { splitParams, getLineNumber, getSourceContext, findMatchingBrace } from './utils.js';
2
3
  /**
3
4
  * Scanner for Java source files
4
5
  * Extracts: public classes, public methods, public static methods
@@ -73,7 +74,7 @@ export class JavaScanner {
73
74
  // Extract generics using depth-counting helper
74
75
  const afterName = match.index + match[0].length;
75
76
  const generics = this.extractGenerics(source, afterName);
76
- const lineNumber = this.getLineNumber(source, match.index);
77
+ const lineNumber = getLineNumber(source, match.index);
77
78
  const docstring = this.getJavadoc(lines, lineNumber - 1);
78
79
  const signature = `public ${modifier ? modifier + ' ' : ''}${kind} ${name}${generics}`;
79
80
  elements.push({
@@ -88,7 +89,7 @@ export class JavaScanner {
88
89
  isPublic: true,
89
90
  imports,
90
91
  packageName,
91
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
92
+ sourceContext: getSourceContext(lines, lineNumber, 15)
92
93
  });
93
94
  }
94
95
  }
@@ -108,7 +109,7 @@ export class JavaScanner {
108
109
  // Skip if at top level (no indent = not inside a class)
109
110
  if (indent.length === 0)
110
111
  continue;
111
- const lineNumber = this.getLineNumber(source, match.index);
112
+ const lineNumber = getLineNumber(source, match.index);
112
113
  const docstring = this.getJavadoc(lines, lineNumber - 1);
113
114
  const parameters = this.parseParams(paramsStr);
114
115
  const parentClass = this.findParentClass(match.index, classRanges);
@@ -128,7 +129,7 @@ export class JavaScanner {
128
129
  isPublic: true,
129
130
  imports,
130
131
  packageName,
131
- sourceContext: this.getSourceContext(lines, lineNumber)
132
+ sourceContext: getSourceContext(lines, lineNumber)
132
133
  });
133
134
  }
134
135
  }
@@ -155,7 +156,7 @@ export class JavaScanner {
155
156
  continue;
156
157
  // Skip if this method was already extracted as a public method
157
158
  const absoluteIndex = range.bodyStart + match.index;
158
- const lineNumber = this.getLineNumber(source, absoluteIndex);
159
+ const lineNumber = getLineNumber(source, absoluteIndex);
159
160
  const alreadyExtracted = elements.some(e => e.kind === 'method' && e.name === name && e.lineNumber === lineNumber);
160
161
  if (alreadyExtracted)
161
162
  continue;
@@ -176,7 +177,7 @@ export class JavaScanner {
176
177
  isPublic: true,
177
178
  imports,
178
179
  packageName,
179
- sourceContext: this.getSourceContext(lines, lineNumber)
180
+ sourceContext: getSourceContext(lines, lineNumber)
180
181
  });
181
182
  }
182
183
  }
@@ -198,7 +199,7 @@ export class JavaScanner {
198
199
  if (afterMatch === -1)
199
200
  continue;
200
201
  // Find matching closing brace
201
- const bodyEnd = this.findMatchingBrace(source, afterMatch);
202
+ const bodyEnd = findMatchingBrace(source, afterMatch);
202
203
  if (bodyEnd === -1)
203
204
  continue;
204
205
  ranges.push({
@@ -211,19 +212,6 @@ export class JavaScanner {
211
212
  }
212
213
  return ranges;
213
214
  }
214
- findMatchingBrace(source, openIndex) {
215
- let depth = 0;
216
- for (let i = openIndex; i < source.length; i++) {
217
- if (source[i] === '{')
218
- depth++;
219
- else if (source[i] === '}') {
220
- depth--;
221
- if (depth === 0)
222
- return i;
223
- }
224
- }
225
- return -1;
226
- }
227
215
  /**
228
216
  * Finds the innermost class that contains the given source index,
229
217
  * using brace-depth-aware class ranges.
@@ -244,7 +232,7 @@ export class JavaScanner {
244
232
  if (!paramsStr.trim())
245
233
  return [];
246
234
  const params = [];
247
- const parts = this.splitParams(paramsStr);
235
+ const parts = splitParams(paramsStr);
248
236
  for (const part of parts) {
249
237
  const trimmed = part.trim();
250
238
  if (!trimmed)
@@ -264,29 +252,6 @@ export class JavaScanner {
264
252
  }
265
253
  return params;
266
254
  }
267
- splitParams(str) {
268
- const parts = [];
269
- let depth = 0;
270
- let current = '';
271
- for (const char of str) {
272
- if (char === '<' || char === '(' || char === '[')
273
- depth++;
274
- else if (char === '>' || char === ')' || char === ']')
275
- depth--;
276
- else if (char === ',' && depth === 0) {
277
- parts.push(current);
278
- current = '';
279
- continue;
280
- }
281
- current += char;
282
- }
283
- if (current.trim())
284
- parts.push(current);
285
- return parts;
286
- }
287
- getLineNumber(source, index) {
288
- return source.slice(0, index).split('\n').length;
289
- }
290
255
  getJavadoc(lines, lineIndex) {
291
256
  let i = lineIndex - 1;
292
257
  // Skip annotations
@@ -310,9 +275,4 @@ export class JavaScanner {
310
275
  }
311
276
  return undefined;
312
277
  }
313
- getSourceContext(lines, lineNumber, context = 5) {
314
- const start = Math.max(0, lineNumber - context - 1);
315
- const end = Math.min(lines.length, lineNumber + context);
316
- return lines.slice(start, end).join('\n');
317
- }
318
278
  }
@@ -16,8 +16,5 @@ export declare class KotlinScanner implements Scanner {
16
16
  private findClosingBrace;
17
17
  private findParentClass;
18
18
  private parseKotlinParams;
19
- private splitParams;
20
- private getLineNumber;
21
19
  private getDocComment;
22
- private getSourceContext;
23
20
  }
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'fs';
2
+ import { splitParams, getLineNumber, getSourceContext } from './utils.js';
2
3
  /**
3
4
  * Scanner for Kotlin source files
4
5
  * Extracts: classes, data classes, sealed classes, objects, interfaces, enum classes, functions
@@ -95,7 +96,7 @@ export class KotlinScanner {
95
96
  const name = match[3];
96
97
  if (!keyword || !name)
97
98
  continue;
98
- const lineNumber = this.getLineNumber(source, match.index);
99
+ const lineNumber = getLineNumber(source, match.index);
99
100
  // Skip private and internal types
100
101
  const fullLine = lines[lineNumber - 1];
101
102
  if (fullLine && /\b(private|internal)\b/.test(fullLine))
@@ -136,7 +137,7 @@ export class KotlinScanner {
136
137
  isPublic: true,
137
138
  imports,
138
139
  packageName,
139
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
140
+ sourceContext: getSourceContext(lines, lineNumber, 15)
140
141
  });
141
142
  }
142
143
  }
@@ -154,7 +155,7 @@ export class KotlinScanner {
154
155
  if (!name)
155
156
  continue;
156
157
  // Check if this function is preceded by 'private' or 'internal' on the same line
157
- const lineNumber = this.getLineNumber(source, match.index);
158
+ const lineNumber = getLineNumber(source, match.index);
158
159
  const fullLine = lines[lineNumber - 1];
159
160
  if (fullLine && /\b(private|internal)\b/.test(fullLine))
160
161
  continue;
@@ -222,7 +223,7 @@ export class KotlinScanner {
222
223
  isPublic: true,
223
224
  imports,
224
225
  packageName,
225
- sourceContext: this.getSourceContext(lines, lineNumber)
226
+ sourceContext: getSourceContext(lines, lineNumber)
226
227
  });
227
228
  }
228
229
  }
@@ -270,7 +271,7 @@ export class KotlinScanner {
270
271
  if (!paramsStr.trim())
271
272
  return [];
272
273
  const params = [];
273
- const parts = this.splitParams(paramsStr);
274
+ const parts = splitParams(paramsStr);
274
275
  for (const part of parts) {
275
276
  let trimmed = part.trim();
276
277
  if (!trimmed)
@@ -303,29 +304,6 @@ export class KotlinScanner {
303
304
  }
304
305
  return params;
305
306
  }
306
- splitParams(str) {
307
- const parts = [];
308
- let depth = 0;
309
- let current = '';
310
- for (const char of str) {
311
- if (char === '<' || char === '(' || char === '[' || char === '{')
312
- depth++;
313
- else if (char === '>' || char === ')' || char === ']' || char === '}')
314
- depth--;
315
- else if (char === ',' && depth === 0) {
316
- parts.push(current);
317
- current = '';
318
- continue;
319
- }
320
- current += char;
321
- }
322
- if (current.trim())
323
- parts.push(current);
324
- return parts;
325
- }
326
- getLineNumber(source, index) {
327
- return source.slice(0, index).split('\n').length;
328
- }
329
307
  getDocComment(lines, lineIndex) {
330
308
  // Look for KDoc comments (/** ... */) above the declaration
331
309
  let i = lineIndex - 1;
@@ -381,9 +359,4 @@ export class KotlinScanner {
381
359
  }
382
360
  return comments.length > 0 ? comments.join('\n') : undefined;
383
361
  }
384
- getSourceContext(lines, lineNumber, context = 5) {
385
- const start = Math.max(0, lineNumber - context - 1);
386
- const end = Math.min(lines.length, lineNumber + context);
387
- return lines.slice(start, end).join('\n');
388
- }
389
362
  }
@@ -31,10 +31,6 @@ export declare class PHPScanner implements Scanner {
31
31
  * Build a map of class/interface/trait/enum boundaries (start offset, end offset, name)
32
32
  */
33
33
  private getClassBoundaries;
34
- /**
35
- * Find the matching closing brace for an opening brace
36
- */
37
- private findMatchingBrace;
38
34
  /**
39
35
  * Find which class/interface/trait contains the given source offset
40
36
  */
@@ -44,14 +40,8 @@ export declare class PHPScanner implements Scanner {
44
40
  * Handles: type hints (?string, int|string, array), default values
45
41
  */
46
42
  private parsePHPParams;
47
- /**
48
- * Split parameter string by commas, respecting nested brackets
49
- */
50
- private splitParams;
51
- private getLineNumber;
52
43
  /**
53
44
  * Extract PHPDoc block comment above a given line
54
45
  */
55
46
  private getDocComment;
56
- private getSourceContext;
57
47
  }
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'fs';
2
+ import { splitParams, getLineNumber, getSourceContext, findMatchingBrace } from './utils.js';
2
3
  /**
3
4
  * Scanner for PHP source files
4
5
  * Extracts: classes, interfaces, enums, traits, abstract classes,
@@ -64,7 +65,7 @@ export class PHPScanner {
64
65
  if (!name)
65
66
  continue;
66
67
  const fullMatch = match[0];
67
- const lineNumber = this.getLineNumber(source, match.index);
68
+ const lineNumber = getLineNumber(source, match.index);
68
69
  const docstring = this.getDocComment(lines, lineNumber - 1);
69
70
  const signature = fullMatch.trim();
70
71
  elements.push({
@@ -79,7 +80,7 @@ export class PHPScanner {
79
80
  isPublic: true,
80
81
  imports,
81
82
  packageName,
82
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
83
+ sourceContext: getSourceContext(lines, lineNumber, 15)
83
84
  });
84
85
  }
85
86
  }
@@ -128,7 +129,7 @@ export class PHPScanner {
128
129
  const afterParen = source.slice(closeParenIndex + 1);
129
130
  const returnTypeMatch = afterParen.match(/^\s*:\s*([\w\\|?]+)/);
130
131
  const returnType = returnTypeMatch?.[1]?.trim() || undefined;
131
- const lineNumber = this.getLineNumber(source, match.index);
132
+ const lineNumber = getLineNumber(source, match.index);
132
133
  const docstring = this.getDocComment(lines, lineNumber - 1);
133
134
  const parameters = this.parsePHPParams(paramsStr);
134
135
  const parentClass = this.findParentClass(match.index, classBoundaries);
@@ -149,7 +150,7 @@ export class PHPScanner {
149
150
  isPublic: true,
150
151
  imports,
151
152
  packageName,
152
- sourceContext: this.getSourceContext(lines, lineNumber)
153
+ sourceContext: getSourceContext(lines, lineNumber)
153
154
  });
154
155
  }
155
156
  }
@@ -180,7 +181,7 @@ export class PHPScanner {
180
181
  const afterParen = source.slice(closeParenIndex + 1);
181
182
  const returnTypeMatch = afterParen.match(/^\s*:\s*([\w\\|?]+)/);
182
183
  const returnType = returnTypeMatch?.[1]?.trim() || undefined;
183
- const lineNumber = this.getLineNumber(source, match.index);
184
+ const lineNumber = getLineNumber(source, match.index);
184
185
  const docstring = this.getDocComment(lines, lineNumber - 1);
185
186
  const parameters = this.parsePHPParams(paramsStr);
186
187
  // Build signature including params and return type
@@ -199,7 +200,7 @@ export class PHPScanner {
199
200
  isPublic: true,
200
201
  imports,
201
202
  packageName,
202
- sourceContext: this.getSourceContext(lines, lineNumber)
203
+ sourceContext: getSourceContext(lines, lineNumber)
203
204
  });
204
205
  }
205
206
  }
@@ -216,27 +217,13 @@ export class PHPScanner {
216
217
  continue;
217
218
  const start = match.index;
218
219
  const braceStart = source.indexOf('{', start + match[0].length - 1);
219
- const end = this.findMatchingBrace(source, braceStart);
220
+ const end = findMatchingBrace(source, braceStart);
221
+ if (end === -1)
222
+ continue;
220
223
  boundaries.push({ name, start, end });
221
224
  }
222
225
  return boundaries;
223
226
  }
224
- /**
225
- * Find the matching closing brace for an opening brace
226
- */
227
- findMatchingBrace(source, openPos) {
228
- let depth = 0;
229
- for (let i = openPos; i < source.length; i++) {
230
- if (source[i] === '{')
231
- depth++;
232
- else if (source[i] === '}') {
233
- depth--;
234
- if (depth === 0)
235
- return i;
236
- }
237
- }
238
- return source.length;
239
- }
240
227
  /**
241
228
  * Find which class/interface/trait contains the given source offset
242
229
  */
@@ -256,7 +243,7 @@ export class PHPScanner {
256
243
  if (!paramsStr.trim())
257
244
  return [];
258
245
  const params = [];
259
- const parts = this.splitParams(paramsStr);
246
+ const parts = splitParams(paramsStr);
260
247
  for (const part of parts) {
261
248
  const trimmed = part.trim();
262
249
  if (!trimmed)
@@ -276,32 +263,6 @@ export class PHPScanner {
276
263
  }
277
264
  return params;
278
265
  }
279
- /**
280
- * Split parameter string by commas, respecting nested brackets
281
- */
282
- splitParams(str) {
283
- const parts = [];
284
- let depth = 0;
285
- let current = '';
286
- for (const char of str) {
287
- if (char === '(' || char === '[' || char === '{' || char === '<')
288
- depth++;
289
- else if (char === ')' || char === ']' || char === '}' || char === '>')
290
- depth--;
291
- else if (char === ',' && depth === 0) {
292
- parts.push(current);
293
- current = '';
294
- continue;
295
- }
296
- current += char;
297
- }
298
- if (current.trim())
299
- parts.push(current);
300
- return parts;
301
- }
302
- getLineNumber(source, index) {
303
- return source.slice(0, index).split('\n').length;
304
- }
305
266
  /**
306
267
  * Extract PHPDoc block comment above a given line
307
268
  */
@@ -343,9 +304,4 @@ export class PHPScanner {
343
304
  .join('\n');
344
305
  return cleaned || undefined;
345
306
  }
346
- getSourceContext(lines, lineNumber, context = 5) {
347
- const start = Math.max(0, lineNumber - context - 1);
348
- const end = Math.min(lines.length, lineNumber + context);
349
- return lines.slice(start, end).join('\n');
350
- }
351
307
  }
@@ -25,12 +25,9 @@ export declare class RubyScanner implements Scanner {
25
25
  private buildVisibilityMap;
26
26
  private findParentClass;
27
27
  private parseRubyParams;
28
- private splitParams;
29
28
  private getDocComment;
30
29
  /**
31
30
  * Extract @return type from YARD comments above a method.
32
31
  */
33
32
  private extractReturnType;
34
- private getLineNumber;
35
- private getSourceContext;
36
33
  }