skrypt-ai 0.6.1 → 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 (180) hide show
  1. package/dist/audit/doc-parser.d.ts +5 -0
  2. package/dist/audit/doc-parser.js +106 -0
  3. package/dist/audit/index.d.ts +4 -0
  4. package/dist/audit/index.js +4 -0
  5. package/dist/audit/matcher.d.ts +6 -0
  6. package/dist/audit/matcher.js +94 -0
  7. package/dist/audit/reporter.d.ts +9 -0
  8. package/dist/audit/reporter.js +106 -0
  9. package/dist/audit/types.d.ts +37 -0
  10. package/dist/auth/index.js +6 -4
  11. package/dist/cli.js +12 -2
  12. package/dist/commands/audit.d.ts +2 -0
  13. package/dist/commands/audit.js +59 -0
  14. package/dist/commands/config.d.ts +2 -0
  15. package/dist/commands/config.js +73 -0
  16. package/dist/commands/{generate.d.ts → generate/index.d.ts} +1 -0
  17. package/dist/commands/generate/index.js +393 -0
  18. package/dist/commands/generate/scan.d.ts +41 -0
  19. package/dist/commands/generate/scan.js +256 -0
  20. package/dist/commands/generate/verify.d.ts +14 -0
  21. package/dist/commands/generate/verify.js +122 -0
  22. package/dist/commands/generate/write.d.ts +25 -0
  23. package/dist/commands/generate/write.js +120 -0
  24. package/dist/commands/import.js +4 -1
  25. package/dist/commands/llms-txt.js +6 -4
  26. package/dist/commands/refresh.d.ts +2 -0
  27. package/dist/commands/refresh.js +158 -0
  28. package/dist/commands/review.d.ts +2 -0
  29. package/dist/commands/review.js +110 -0
  30. package/dist/commands/test.js +177 -236
  31. package/dist/commands/watch.js +29 -20
  32. package/dist/config/loader.d.ts +6 -2
  33. package/dist/config/loader.js +39 -3
  34. package/dist/config/types.d.ts +7 -0
  35. package/dist/generator/agents-md.d.ts +25 -0
  36. package/dist/generator/agents-md.js +122 -0
  37. package/dist/generator/generator.js +2 -1
  38. package/dist/generator/index.d.ts +2 -0
  39. package/dist/generator/index.js +2 -0
  40. package/dist/generator/mdx-serializer.d.ts +11 -0
  41. package/dist/generator/mdx-serializer.js +135 -0
  42. package/dist/generator/organizer.d.ts +1 -16
  43. package/dist/generator/organizer.js +0 -38
  44. package/dist/generator/types.d.ts +3 -0
  45. package/dist/generator/writer.js +65 -32
  46. package/dist/github/org-discovery.d.ts +17 -0
  47. package/dist/github/org-discovery.js +93 -0
  48. package/dist/llm/index.d.ts +2 -0
  49. package/dist/llm/index.js +8 -2
  50. package/dist/llm/proxy-client.d.ts +32 -0
  51. package/dist/llm/proxy-client.js +103 -0
  52. package/dist/next-actions/actions.d.ts +2 -0
  53. package/dist/next-actions/actions.js +190 -0
  54. package/dist/next-actions/index.d.ts +6 -0
  55. package/dist/next-actions/index.js +39 -0
  56. package/dist/next-actions/setup.d.ts +2 -0
  57. package/dist/next-actions/setup.js +72 -0
  58. package/dist/next-actions/state.d.ts +7 -0
  59. package/dist/next-actions/state.js +68 -0
  60. package/dist/next-actions/suggest.d.ts +3 -0
  61. package/dist/next-actions/suggest.js +47 -0
  62. package/dist/next-actions/types.d.ts +26 -0
  63. package/dist/refresh/differ.d.ts +9 -0
  64. package/dist/refresh/differ.js +67 -0
  65. package/dist/refresh/index.d.ts +4 -0
  66. package/dist/refresh/index.js +4 -0
  67. package/dist/refresh/manifest.d.ts +18 -0
  68. package/dist/refresh/manifest.js +71 -0
  69. package/dist/refresh/splicer.d.ts +9 -0
  70. package/dist/refresh/splicer.js +50 -0
  71. package/dist/refresh/types.d.ts +37 -0
  72. package/dist/review/index.d.ts +8 -0
  73. package/dist/review/index.js +94 -0
  74. package/dist/review/parser.d.ts +16 -0
  75. package/dist/review/parser.js +95 -0
  76. package/dist/review/types.d.ts +18 -0
  77. package/dist/scanner/csharp.d.ts +0 -4
  78. package/dist/scanner/csharp.js +9 -49
  79. package/dist/scanner/go.d.ts +0 -3
  80. package/dist/scanner/go.js +8 -35
  81. package/dist/scanner/java.d.ts +0 -4
  82. package/dist/scanner/java.js +9 -49
  83. package/dist/scanner/kotlin.d.ts +0 -3
  84. package/dist/scanner/kotlin.js +6 -33
  85. package/dist/scanner/php.d.ts +0 -10
  86. package/dist/scanner/php.js +11 -55
  87. package/dist/scanner/ruby.d.ts +0 -3
  88. package/dist/scanner/ruby.js +8 -38
  89. package/dist/scanner/rust.d.ts +0 -3
  90. package/dist/scanner/rust.js +10 -37
  91. package/dist/scanner/swift.d.ts +0 -3
  92. package/dist/scanner/swift.js +8 -35
  93. package/dist/scanner/types.d.ts +2 -0
  94. package/dist/scanner/utils.d.ts +41 -0
  95. package/dist/scanner/utils.js +97 -0
  96. package/dist/structure/index.d.ts +19 -0
  97. package/dist/structure/index.js +92 -0
  98. package/dist/structure/planner.d.ts +8 -0
  99. package/dist/structure/planner.js +180 -0
  100. package/dist/structure/topology.d.ts +16 -0
  101. package/dist/structure/topology.js +49 -0
  102. package/dist/structure/types.d.ts +26 -0
  103. package/dist/template/docs.json +5 -2
  104. package/dist/template/next.config.mjs +31 -0
  105. package/dist/template/package.json +5 -3
  106. package/dist/template/src/app/layout.tsx +13 -13
  107. package/dist/template/src/app/llms-full.md/route.ts +29 -0
  108. package/dist/template/src/app/llms.txt/route.ts +29 -0
  109. package/dist/template/src/app/md/[...slug]/route.ts +174 -0
  110. package/dist/template/src/app/reference/route.ts +22 -18
  111. package/dist/template/src/app/sitemap.ts +1 -1
  112. package/dist/template/src/components/ai-chat-impl.tsx +206 -0
  113. package/dist/template/src/components/ai-chat.tsx +20 -193
  114. package/dist/template/src/components/mdx/index.tsx +27 -4
  115. package/dist/template/src/lib/fonts.ts +135 -0
  116. package/dist/template/src/middleware.ts +101 -0
  117. package/dist/template/src/styles/globals.css +28 -20
  118. package/dist/testing/comparator.d.ts +7 -0
  119. package/dist/testing/comparator.js +77 -0
  120. package/dist/testing/docker.d.ts +21 -0
  121. package/dist/testing/docker.js +234 -0
  122. package/dist/testing/env.d.ts +16 -0
  123. package/dist/testing/env.js +58 -0
  124. package/dist/testing/extractor.d.ts +9 -0
  125. package/dist/testing/extractor.js +195 -0
  126. package/dist/testing/index.d.ts +6 -0
  127. package/dist/testing/index.js +6 -0
  128. package/dist/testing/runner.d.ts +5 -0
  129. package/dist/testing/runner.js +225 -0
  130. package/dist/testing/types.d.ts +58 -0
  131. package/dist/utils/files.d.ts +0 -8
  132. package/dist/utils/files.js +0 -33
  133. package/package.json +1 -1
  134. package/dist/autofix/autofix.test.js +0 -487
  135. package/dist/commands/generate.js +0 -445
  136. package/dist/generator/generator.test.js +0 -259
  137. package/dist/generator/writer.test.js +0 -411
  138. package/dist/llm/llm.manual-test.js +0 -112
  139. package/dist/llm/llm.mock-test.d.ts +0 -4
  140. package/dist/llm/llm.mock-test.js +0 -79
  141. package/dist/plugins/index.d.ts +0 -47
  142. package/dist/plugins/index.js +0 -181
  143. package/dist/scanner/content-type.test.js +0 -231
  144. package/dist/scanner/integration.test.d.ts +0 -4
  145. package/dist/scanner/integration.test.js +0 -180
  146. package/dist/scanner/scanner.test.js +0 -210
  147. package/dist/scanner/typescript.manual-test.d.ts +0 -1
  148. package/dist/scanner/typescript.manual-test.js +0 -112
  149. package/dist/template/src/app/docs/auth/page.mdx +0 -589
  150. package/dist/template/src/app/docs/autofix/page.mdx +0 -624
  151. package/dist/template/src/app/docs/cli/page.mdx +0 -217
  152. package/dist/template/src/app/docs/config/page.mdx +0 -428
  153. package/dist/template/src/app/docs/configuration/page.mdx +0 -86
  154. package/dist/template/src/app/docs/deployment/page.mdx +0 -112
  155. package/dist/template/src/app/docs/generator/generator.md +0 -504
  156. package/dist/template/src/app/docs/generator/organizer.md +0 -779
  157. package/dist/template/src/app/docs/generator/page.mdx +0 -613
  158. package/dist/template/src/app/docs/github/page.mdx +0 -502
  159. package/dist/template/src/app/docs/llm/anthropic-client.md +0 -549
  160. package/dist/template/src/app/docs/llm/index.md +0 -471
  161. package/dist/template/src/app/docs/llm/page.mdx +0 -428
  162. package/dist/template/src/app/docs/plugins/page.mdx +0 -1793
  163. package/dist/template/src/app/docs/pro/page.mdx +0 -121
  164. package/dist/template/src/app/docs/quickstart/page.mdx +0 -93
  165. package/dist/template/src/app/docs/scanner/content-type.md +0 -599
  166. package/dist/template/src/app/docs/scanner/index.md +0 -212
  167. package/dist/template/src/app/docs/scanner/page.mdx +0 -307
  168. package/dist/template/src/app/docs/scanner/python.md +0 -469
  169. package/dist/template/src/app/docs/scanner/python_parser.md +0 -1056
  170. package/dist/template/src/app/docs/scanner/rust.md +0 -325
  171. package/dist/template/src/app/docs/scanner/typescript.md +0 -201
  172. package/dist/template/src/app/icon.tsx +0 -29
  173. package/dist/utils/validation.d.ts +0 -1
  174. package/dist/utils/validation.js +0 -12
  175. /package/dist/{autofix/autofix.test.d.ts → audit/types.js} +0 -0
  176. /package/dist/{generator/generator.test.d.ts → next-actions/types.js} +0 -0
  177. /package/dist/{generator/writer.test.d.ts → refresh/types.js} +0 -0
  178. /package/dist/{llm/llm.manual-test.d.ts → review/types.js} +0 -0
  179. /package/dist/{scanner/content-type.test.d.ts → structure/types.js} +0 -0
  180. /package/dist/{scanner/scanner.test.d.ts → testing/types.js} +0 -0
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'fs';
2
+ import { splitParams, getLineNumber, getSourceContext } from './utils.js';
2
3
  /**
3
4
  * Scanner for Ruby source files
4
5
  * Extracts: classes, modules, methods (public only)
@@ -86,7 +87,7 @@ export class RubyScanner {
86
87
  if (!name)
87
88
  continue;
88
89
  const superclass = match[2] ?? '';
89
- const lineNumber = this.getLineNumber(source, match.index);
90
+ const lineNumber = getLineNumber(source, match.index);
90
91
  const docstring = this.getDocComment(lines, lineNumber - 1);
91
92
  const signature = superclass
92
93
  ? `class ${name} < ${superclass}`
@@ -103,7 +104,7 @@ export class RubyScanner {
103
104
  isPublic: true,
104
105
  imports,
105
106
  packageName,
106
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
107
+ sourceContext: getSourceContext(lines, lineNumber, 15)
107
108
  });
108
109
  }
109
110
  }
@@ -119,7 +120,7 @@ export class RubyScanner {
119
120
  continue;
120
121
  // Only emit modules that contain constants (FOO = ...) and do NOT
121
122
  // contain class/def definitions — i.e. "leaf" modules.
122
- const lineNumber = this.getLineNumber(source, match.index);
123
+ const lineNumber = getLineNumber(source, match.index);
123
124
  const body = this.getModuleBody(source, match.index);
124
125
  if (body === null)
125
126
  continue;
@@ -140,7 +141,7 @@ export class RubyScanner {
140
141
  isPublic: true,
141
142
  imports,
142
143
  packageName,
143
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
144
+ sourceContext: getSourceContext(lines, lineNumber, 15)
144
145
  });
145
146
  }
146
147
  }
@@ -190,7 +191,7 @@ export class RubyScanner {
190
191
  // Skip initialize (constructor internals)
191
192
  if (name === 'initialize')
192
193
  continue;
193
- const lineNumber = this.getLineNumber(source, match.index);
194
+ const lineNumber = getLineNumber(source, match.index);
194
195
  // Check visibility — skip private / protected
195
196
  const visibility = visibilityMap.get(lineNumber);
196
197
  if (visibility === 'private' || visibility === 'protected')
@@ -223,7 +224,7 @@ export class RubyScanner {
223
224
  isPublic: true,
224
225
  imports,
225
226
  packageName,
226
- sourceContext: this.getSourceContext(lines, lineNumber)
227
+ sourceContext: getSourceContext(lines, lineNumber)
227
228
  });
228
229
  }
229
230
  }
@@ -305,7 +306,7 @@ export class RubyScanner {
305
306
  if (!paramsStr.trim())
306
307
  return [];
307
308
  const params = [];
308
- const parts = this.splitParams(paramsStr);
309
+ const parts = splitParams(paramsStr);
309
310
  for (const part of parts) {
310
311
  const trimmed = part.trim();
311
312
  if (!trimmed)
@@ -348,26 +349,6 @@ export class RubyScanner {
348
349
  }
349
350
  return params;
350
351
  }
351
- splitParams(str) {
352
- const parts = [];
353
- let depth = 0;
354
- let current = '';
355
- for (const char of str) {
356
- if (char === '(' || char === '[' || char === '{')
357
- depth++;
358
- else if (char === ')' || char === ']' || char === '}')
359
- depth--;
360
- else if (char === ',' && depth === 0) {
361
- parts.push(current);
362
- current = '';
363
- continue;
364
- }
365
- current += char;
366
- }
367
- if (current.trim())
368
- parts.push(current);
369
- return parts;
370
- }
371
352
  // ---------------------------------------------------------------------------
372
353
  // Doc comments (YARD and plain #)
373
354
  // ---------------------------------------------------------------------------
@@ -417,15 +398,4 @@ export class RubyScanner {
417
398
  }
418
399
  return undefined;
419
400
  }
420
- // ---------------------------------------------------------------------------
421
- // Helpers
422
- // ---------------------------------------------------------------------------
423
- getLineNumber(source, index) {
424
- return source.slice(0, index).split('\n').length;
425
- }
426
- getSourceContext(lines, lineNumber, context = 5) {
427
- const start = Math.max(0, lineNumber - context - 1);
428
- const end = Math.min(lines.length, lineNumber + context);
429
- return lines.slice(start, end).join('\n');
430
- }
431
401
  }
@@ -16,8 +16,5 @@ export declare class RustScanner implements Scanner {
16
16
  private extractImplMethods;
17
17
  private extractBlock;
18
18
  private parseRustParams;
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 Rust source files
4
5
  * Extracts: pub functions, pub structs, pub enums, impl blocks, traits
@@ -72,7 +73,7 @@ export class RustScanner {
72
73
  const generics = match[4] || '';
73
74
  const paramsStr = match[5];
74
75
  const returnPart = match[6]?.trim() || '';
75
- const lineNumber = this.getLineNumber(source, match.index);
76
+ const lineNumber = getLineNumber(source, match.index);
76
77
  const docstring = this.getDocComment(lines, lineNumber - 1);
77
78
  const parameters = this.parseRustParams(paramsStr);
78
79
  const returnType = returnPart ? returnPart.replace(/^->\s*/, '').trim() : undefined;
@@ -92,7 +93,7 @@ export class RustScanner {
92
93
  isPublic: true,
93
94
  imports,
94
95
  packageName,
95
- sourceContext: this.getSourceContext(lines, lineNumber)
96
+ sourceContext: getSourceContext(lines, lineNumber)
96
97
  });
97
98
  }
98
99
  }
@@ -110,7 +111,7 @@ export class RustScanner {
110
111
  const kind = match[1];
111
112
  const name = match[2];
112
113
  const generics = match[3] || '';
113
- const lineNumber = this.getLineNumber(source, match.index);
114
+ const lineNumber = getLineNumber(source, match.index);
114
115
  const docstring = this.getDocComment(lines, lineNumber - 1);
115
116
  const signature = `pub ${kind} ${name}${generics}`;
116
117
  elements.push({
@@ -125,7 +126,7 @@ export class RustScanner {
125
126
  isPublic: true,
126
127
  imports,
127
128
  packageName,
128
- sourceContext: this.getSourceContext(lines, lineNumber, 20)
129
+ sourceContext: getSourceContext(lines, lineNumber, 20)
129
130
  });
130
131
  }
131
132
  }
@@ -136,7 +137,7 @@ export class RustScanner {
136
137
  while ((match = traitRegex.exec(source)) !== null) {
137
138
  const name = match[1];
138
139
  const generics = match[2] || '';
139
- const lineNumber = this.getLineNumber(source, match.index);
140
+ const lineNumber = getLineNumber(source, match.index);
140
141
  const docstring = this.getDocComment(lines, lineNumber - 1);
141
142
  const signature = `pub trait ${name}${generics}`;
142
143
  elements.push({
@@ -151,7 +152,7 @@ export class RustScanner {
151
152
  isPublic: true,
152
153
  imports,
153
154
  packageName,
154
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
155
+ sourceContext: getSourceContext(lines, lineNumber, 15)
155
156
  });
156
157
  }
157
158
  }
@@ -180,7 +181,7 @@ export class RustScanner {
180
181
  const returnPart = methodMatch[5]?.trim() || '';
181
182
  const bodyIndex = implBody.indexOf(methodMatch[0]);
182
183
  const fullIndex = implStart + implMatch[0].length + bodyIndex;
183
- const lineNumber = this.getLineNumber(source, fullIndex);
184
+ const lineNumber = getLineNumber(source, fullIndex);
184
185
  const docstring = this.getDocComment(lines, lineNumber - 1);
185
186
  const parameters = this.parseRustParams(paramsStr);
186
187
  const returnType = returnPart ? returnPart.replace(/^->\s*/, '').trim() : undefined;
@@ -201,7 +202,7 @@ export class RustScanner {
201
202
  isPublic: true,
202
203
  imports,
203
204
  packageName,
204
- sourceContext: this.getSourceContext(lines, lineNumber)
205
+ sourceContext: getSourceContext(lines, lineNumber)
205
206
  });
206
207
  }
207
208
  }
@@ -230,7 +231,7 @@ export class RustScanner {
230
231
  if (!paramsStr.trim())
231
232
  return [];
232
233
  const params = [];
233
- const parts = this.splitParams(paramsStr);
234
+ const parts = splitParams(paramsStr);
234
235
  for (const part of parts) {
235
236
  const trimmed = part.trim();
236
237
  if (!trimmed)
@@ -250,29 +251,6 @@ export class RustScanner {
250
251
  }
251
252
  return params;
252
253
  }
253
- splitParams(str) {
254
- const parts = [];
255
- let depth = 0;
256
- let current = '';
257
- for (const char of str) {
258
- if (char === '<' || char === '(' || char === '[' || char === '{')
259
- depth++;
260
- else if (char === '>' || char === ')' || char === ']' || char === '}')
261
- depth--;
262
- else if (char === ',' && depth === 0) {
263
- parts.push(current);
264
- current = '';
265
- continue;
266
- }
267
- current += char;
268
- }
269
- if (current.trim())
270
- parts.push(current);
271
- return parts;
272
- }
273
- getLineNumber(source, index) {
274
- return source.slice(0, index).split('\n').length;
275
- }
276
254
  getDocComment(lines, lineIndex) {
277
255
  const comments = [];
278
256
  let i = lineIndex - 1;
@@ -296,9 +274,4 @@ export class RustScanner {
296
274
  }
297
275
  return comments.length > 0 ? comments.join('\n') : undefined;
298
276
  }
299
- getSourceContext(lines, lineNumber, context = 5) {
300
- const start = Math.max(0, lineNumber - context - 1);
301
- const end = Math.min(lines.length, lineNumber + context);
302
- return lines.slice(start, end).join('\n');
303
- }
304
277
  }
@@ -18,8 +18,5 @@ export declare class SwiftScanner implements Scanner {
18
18
  private extractBlock;
19
19
  private parseSwiftParams;
20
20
  private findDefaultValueSplit;
21
- private splitParams;
22
- private getLineNumber;
23
21
  private getDocComment;
24
- private getSourceContext;
25
22
  }
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'fs';
2
+ import { splitParams, getLineNumber, getSourceContext } from './utils.js';
2
3
  /**
3
4
  * Scanner for Swift source files
4
5
  * Extracts: public/open classes, structs, enums, protocols, actors, functions, methods
@@ -72,7 +73,7 @@ export class SwiftScanner {
72
73
  const name = match[3];
73
74
  if (!access || !kind || !name)
74
75
  continue;
75
- const lineNumber = this.getLineNumber(source, match.index);
76
+ const lineNumber = getLineNumber(source, match.index);
76
77
  const docstring = this.getDocComment(lines, lineNumber - 1);
77
78
  const signature = `${access} ${kind} ${name}`;
78
79
  elements.push({
@@ -87,7 +88,7 @@ export class SwiftScanner {
87
88
  isPublic: true,
88
89
  imports,
89
90
  packageName,
90
- sourceContext: this.getSourceContext(lines, lineNumber, 15)
91
+ sourceContext: getSourceContext(lines, lineNumber, 15)
91
92
  });
92
93
  }
93
94
  }
@@ -143,7 +144,7 @@ export class SwiftScanner {
143
144
  if (!access || !name)
144
145
  continue;
145
146
  // Check if this is at the top level (not indented)
146
- const lineNumber = this.getLineNumber(source, match.index);
147
+ const lineNumber = getLineNumber(source, match.index);
147
148
  const lineContent = lines[lineNumber - 1];
148
149
  if (!lineContent || /^\s+/.test(lineContent))
149
150
  continue;
@@ -169,7 +170,7 @@ export class SwiftScanner {
169
170
  isPublic: true,
170
171
  imports,
171
172
  packageName,
172
- sourceContext: this.getSourceContext(lines, lineNumber)
173
+ sourceContext: getSourceContext(lines, lineNumber)
173
174
  });
174
175
  }
175
176
  }
@@ -202,7 +203,7 @@ export class SwiftScanner {
202
203
  // Calculate line number relative to the full source
203
204
  const bodyOffset = blockStart + 1;
204
205
  const fullIndex = bodyOffset + methodMatch.index;
205
- const lineNumber = this.getLineNumber(source, fullIndex);
206
+ const lineNumber = getLineNumber(source, fullIndex);
206
207
  const docstring = this.getDocComment(lines, lineNumber - 1);
207
208
  const parameters = this.parseSwiftParams(paramsStr);
208
209
  const signature = this.buildSignature(access, name, paramsStr, isAsync, isThrows, isRethrows, returnType);
@@ -221,7 +222,7 @@ export class SwiftScanner {
221
222
  isPublic: true,
222
223
  imports,
223
224
  packageName,
224
- sourceContext: this.getSourceContext(lines, lineNumber)
225
+ sourceContext: getSourceContext(lines, lineNumber)
225
226
  });
226
227
  }
227
228
  }
@@ -262,7 +263,7 @@ export class SwiftScanner {
262
263
  if (!paramsStr.trim())
263
264
  return [];
264
265
  const params = [];
265
- const parts = this.splitParams(paramsStr);
266
+ const parts = splitParams(paramsStr);
266
267
  for (const part of parts) {
267
268
  const trimmed = part.trim();
268
269
  if (!trimmed)
@@ -316,29 +317,6 @@ export class SwiftScanner {
316
317
  }
317
318
  return -1;
318
319
  }
319
- splitParams(str) {
320
- const parts = [];
321
- let depth = 0;
322
- let current = '';
323
- for (const char of str) {
324
- if (char === '<' || char === '(' || char === '[' || char === '{')
325
- depth++;
326
- else if (char === '>' || char === ')' || char === ']' || char === '}')
327
- depth--;
328
- else if (char === ',' && depth === 0) {
329
- parts.push(current);
330
- current = '';
331
- continue;
332
- }
333
- current += char;
334
- }
335
- if (current.trim())
336
- parts.push(current);
337
- return parts;
338
- }
339
- getLineNumber(source, index) {
340
- return source.slice(0, index).split('\n').length;
341
- }
342
320
  getDocComment(lines, lineIndex) {
343
321
  const comments = [];
344
322
  let i = lineIndex - 1;
@@ -384,9 +362,4 @@ export class SwiftScanner {
384
362
  }
385
363
  return comments.length > 0 ? comments.join('\n') : undefined;
386
364
  }
387
- getSourceContext(lines, lineNumber, context = 5) {
388
- const start = Math.max(0, lineNumber - context - 1);
389
- const end = Math.min(lines.length, lineNumber + context);
390
- return lines.slice(start, end).join('\n');
391
- }
392
365
  }
@@ -27,6 +27,8 @@ export interface APIElement {
27
27
  sourceContext?: string;
28
28
  packageName?: string;
29
29
  relatedTypes?: string[];
30
+ sourceLabel?: string;
31
+ sourceRoot?: string;
30
32
  }
31
33
  /**
32
34
  * Result of scanning a file
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared utility functions for language scanners.
3
+ *
4
+ * These helpers are used identically (or near-identically) across
5
+ * multiple scanner implementations. Centralising them here avoids
6
+ * duplicated code and makes future fixes apply everywhere at once.
7
+ */
8
+ /**
9
+ * Split a parameter string by commas while respecting nested brackets.
10
+ * Handles: `<>`, `()`, `[]`, `{}`
11
+ *
12
+ * Used by: Java, C#, Swift, Kotlin, PHP, Rust, Ruby scanners.
13
+ */
14
+ export declare function splitParams(str: string): string[];
15
+ /**
16
+ * Split a parameter string by commas, respecting `()`, `[]`, `{}`
17
+ * but NOT `<>`. Go is the only scanner that uses this variant because
18
+ * Go has no angle-bracket generics in parameter lists.
19
+ */
20
+ export declare function splitParamsNoAngleBrackets(str: string): string[];
21
+ /**
22
+ * Convert a character-index in `source` to a 1-based line number.
23
+ *
24
+ * Used by every regex-based scanner.
25
+ */
26
+ export declare function getLineNumber(source: string, index: number): number;
27
+ /**
28
+ * Return a few lines of source context around `lineNumber` (1-based).
29
+ *
30
+ * @param lines - Pre-split source lines (`source.split('\n')`)
31
+ * @param lineNumber - 1-based line number of the declaration
32
+ * @param context - Number of lines to include before and after (default 5)
33
+ */
34
+ export declare function getSourceContext(lines: string[], lineNumber: number, context?: number): string;
35
+ /**
36
+ * Starting at the opening `{` at `openIndex`, find its matching `}`.
37
+ * Returns the index of the closing brace, or -1 if not found.
38
+ *
39
+ * Used by: Java, C#, PHP scanners (for class-range detection).
40
+ */
41
+ export declare function findMatchingBrace(source: string, openIndex: number): number;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Shared utility functions for language scanners.
3
+ *
4
+ * These helpers are used identically (or near-identically) across
5
+ * multiple scanner implementations. Centralising them here avoids
6
+ * duplicated code and makes future fixes apply everywhere at once.
7
+ */
8
+ /**
9
+ * Split a parameter string by commas while respecting nested brackets.
10
+ * Handles: `<>`, `()`, `[]`, `{}`
11
+ *
12
+ * Used by: Java, C#, Swift, Kotlin, PHP, Rust, Ruby scanners.
13
+ */
14
+ export function splitParams(str) {
15
+ const parts = [];
16
+ let depth = 0;
17
+ let current = '';
18
+ for (const char of str) {
19
+ if (char === '<' || char === '(' || char === '[' || char === '{')
20
+ depth++;
21
+ else if (char === '>' || char === ')' || char === ']' || char === '}')
22
+ depth--;
23
+ else if (char === ',' && depth === 0) {
24
+ parts.push(current);
25
+ current = '';
26
+ continue;
27
+ }
28
+ current += char;
29
+ }
30
+ if (current.trim())
31
+ parts.push(current);
32
+ return parts;
33
+ }
34
+ /**
35
+ * Split a parameter string by commas, respecting `()`, `[]`, `{}`
36
+ * but NOT `<>`. Go is the only scanner that uses this variant because
37
+ * Go has no angle-bracket generics in parameter lists.
38
+ */
39
+ export function splitParamsNoAngleBrackets(str) {
40
+ const parts = [];
41
+ let depth = 0;
42
+ let current = '';
43
+ for (const char of str) {
44
+ if (char === '(' || char === '[' || char === '{')
45
+ depth++;
46
+ else if (char === ')' || char === ']' || char === '}')
47
+ depth--;
48
+ else if (char === ',' && depth === 0) {
49
+ parts.push(current);
50
+ current = '';
51
+ continue;
52
+ }
53
+ current += char;
54
+ }
55
+ if (current.trim())
56
+ parts.push(current);
57
+ return parts;
58
+ }
59
+ /**
60
+ * Convert a character-index in `source` to a 1-based line number.
61
+ *
62
+ * Used by every regex-based scanner.
63
+ */
64
+ export function getLineNumber(source, index) {
65
+ return source.slice(0, index).split('\n').length;
66
+ }
67
+ /**
68
+ * Return a few lines of source context around `lineNumber` (1-based).
69
+ *
70
+ * @param lines - Pre-split source lines (`source.split('\n')`)
71
+ * @param lineNumber - 1-based line number of the declaration
72
+ * @param context - Number of lines to include before and after (default 5)
73
+ */
74
+ export function getSourceContext(lines, lineNumber, context = 5) {
75
+ const start = Math.max(0, lineNumber - context - 1);
76
+ const end = Math.min(lines.length, lineNumber + context);
77
+ return lines.slice(start, end).join('\n');
78
+ }
79
+ /**
80
+ * Starting at the opening `{` at `openIndex`, find its matching `}`.
81
+ * Returns the index of the closing brace, or -1 if not found.
82
+ *
83
+ * Used by: Java, C#, PHP scanners (for class-range detection).
84
+ */
85
+ export function findMatchingBrace(source, openIndex) {
86
+ let depth = 0;
87
+ for (let i = openIndex; i < source.length; i++) {
88
+ if (source[i] === '{')
89
+ depth++;
90
+ else if (source[i] === '}') {
91
+ depth--;
92
+ if (depth === 0)
93
+ return i;
94
+ }
95
+ }
96
+ return -1;
97
+ }
@@ -0,0 +1,19 @@
1
+ import { APIElement } from '../scanner/types.js';
2
+ import { LLMClient } from '../llm/types.js';
3
+ import { GenerationOptions, GeneratedDoc } from '../generator/types.js';
4
+ import { DocStructure } from './types.js';
5
+ export * from './types.js';
6
+ export { analyzeTopology } from './topology.js';
7
+ export { planStructure } from './planner.js';
8
+ /**
9
+ * Plan a smart documentation structure using LLM analysis
10
+ */
11
+ export declare function planSmartStructure(elements: APIElement[], client: LLMClient): Promise<DocStructure>;
12
+ /**
13
+ * Generate documentation following a smart structure plan
14
+ */
15
+ export declare function generateWithStructure(structure: DocStructure, client: LLMClient, outputPath: string, options: GenerationOptions): Promise<{
16
+ filesWritten: number;
17
+ totalDocs: number;
18
+ docs: GeneratedDoc[];
19
+ }>;
@@ -0,0 +1,92 @@
1
+ import { writeFileSync, mkdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { generateForElements } from '../generator/generator.js';
4
+ import { analyzeTopology } from './topology.js';
5
+ import { planStructure } from './planner.js';
6
+ export * from './types.js';
7
+ export { analyzeTopology } from './topology.js';
8
+ export { planStructure } from './planner.js';
9
+ /**
10
+ * Plan a smart documentation structure using LLM analysis
11
+ */
12
+ export async function planSmartStructure(elements, client) {
13
+ const topology = analyzeTopology(elements);
14
+ return planStructure(elements, topology, client);
15
+ }
16
+ /**
17
+ * Generate documentation following a smart structure plan
18
+ */
19
+ export async function generateWithStructure(structure, client, outputPath, options) {
20
+ let filesWritten = 0;
21
+ let totalDocs = 0;
22
+ const allDocs = [];
23
+ // Create category directories
24
+ const categoryDirs = {
25
+ quickstart: outputPath,
26
+ concepts: join(outputPath, 'concepts'),
27
+ guides: join(outputPath, 'guides'),
28
+ api: join(outputPath, 'api'),
29
+ };
30
+ for (const dir of Object.values(categoryDirs)) {
31
+ mkdirSync(dir, { recursive: true });
32
+ }
33
+ // Generate docs page by page
34
+ for (const page of structure.pages) {
35
+ if (page.elements.length === 0)
36
+ continue;
37
+ const dir = categoryDirs[page.category] || outputPath;
38
+ const filePath = join(dir, `${page.slug}.md`);
39
+ // Generate docs for all elements on this page
40
+ const docs = await generateForElements(page.elements, client, {
41
+ ...options,
42
+ onProgress: (progress) => {
43
+ options.onProgress?.({
44
+ ...progress,
45
+ element: `${page.title}: ${progress.element}`,
46
+ });
47
+ },
48
+ });
49
+ // Write the page
50
+ const content = buildPageContent(page, docs);
51
+ writeFileSync(filePath, content);
52
+ filesWritten++;
53
+ totalDocs += docs.length;
54
+ allDocs.push(...docs);
55
+ }
56
+ // Write navigation file
57
+ mkdirSync(join(outputPath, '.skrypt'), { recursive: true });
58
+ const navContent = JSON.stringify(structure.navigation, null, 2);
59
+ writeFileSync(join(outputPath, '.skrypt', 'navigation.json'), navContent);
60
+ return { filesWritten, totalDocs, docs: allDocs };
61
+ }
62
+ /**
63
+ * Build markdown content for a smart-structured page
64
+ */
65
+ function buildPageContent(page, docs) {
66
+ let content = `---\ntitle: ${page.title}\ndescription: ${page.description}\n---\n\n`;
67
+ content += `# ${page.title}\n\n`;
68
+ content += `${page.description}\n\n`;
69
+ for (const doc of docs) {
70
+ if (doc.error)
71
+ continue;
72
+ content += `## \`${doc.element.name}\`\n\n`;
73
+ content += `\`\`\`${doc.codeLanguage}\n${doc.element.signature}\n\`\`\`\n\n`;
74
+ if (doc.markdown) {
75
+ content += doc.markdown + '\n\n';
76
+ }
77
+ const hasMultiLang = doc.typescriptExample && doc.pythonExample;
78
+ if (hasMultiLang) {
79
+ content += '**Examples:**\n\n';
80
+ content += '<CodeGroup>\n\n';
81
+ content += `\`\`\`typescript example.ts\n${doc.typescriptExample}\n\`\`\`\n\n`;
82
+ content += `\`\`\`python example.py\n${doc.pythonExample}\n\`\`\`\n\n`;
83
+ content += '</CodeGroup>\n\n';
84
+ }
85
+ else if (doc.codeExample) {
86
+ content += '**Example:**\n\n';
87
+ content += `\`\`\`${doc.codeLanguage}\n${doc.codeExample}\n\`\`\`\n\n`;
88
+ }
89
+ content += '---\n\n';
90
+ }
91
+ return content;
92
+ }
@@ -0,0 +1,8 @@
1
+ import { APIElement } from '../scanner/types.js';
2
+ import { LLMClient } from '../llm/types.js';
3
+ import { DocStructure } from './types.js';
4
+ import { TopologyAnalysis } from './topology.js';
5
+ /**
6
+ * Use LLM to plan a smart documentation structure
7
+ */
8
+ export declare function planStructure(elements: APIElement[], topology: TopologyAnalysis, client: LLMClient): Promise<DocStructure>;