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,112 +0,0 @@
1
- import { createLLMClient, generateDocumentation, fixCodeSample } from './index.js';
2
- import { PROVIDER_ENV_KEYS } from '../config/types.js';
3
- async function runTests() {
4
- console.log('=== LLM Client Tests ===\n');
5
- // Find an available provider
6
- const providers = ['deepseek', 'openai', 'anthropic', 'google', 'openrouter', 'ollama'];
7
- let availableProvider = null;
8
- let availableModel = null;
9
- for (const provider of providers) {
10
- const envKey = PROVIDER_ENV_KEYS[provider];
11
- if (!envKey || process.env[envKey]) {
12
- availableProvider = provider;
13
- availableModel = getTestModel(provider);
14
- break;
15
- }
16
- }
17
- if (!availableProvider) {
18
- console.log('No LLM provider available. Set one of these env vars:');
19
- console.log(' DEEPSEEK_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY,');
20
- console.log(' GOOGLE_API_KEY, OPENROUTER_API_KEY, or run Ollama locally');
21
- process.exit(0);
22
- }
23
- console.log(`Using provider: ${availableProvider} (${availableModel})`);
24
- console.log('');
25
- // Test 1: Create client
26
- console.log('Test 1: Create LLM client');
27
- const client = createLLMClient({
28
- provider: availableProvider,
29
- model: availableModel
30
- });
31
- console.log(` provider: ${client.provider}`);
32
- console.log(' ✓ client created\n');
33
- // Test 2: Simple completion
34
- console.log('Test 2: Simple completion');
35
- try {
36
- const response = await client.complete({
37
- messages: [
38
- { role: 'user', content: 'Say "hello" and nothing else.' }
39
- ],
40
- maxTokens: 10
41
- });
42
- console.log(` response: "${response.content.trim()}"`);
43
- console.log(` model: ${response.model}`);
44
- console.log(` tokens: ${response.usage.totalTokens}`);
45
- console.log(' ✓ completion works\n');
46
- }
47
- catch (err) {
48
- console.log(` ✗ completion failed: ${err}`);
49
- process.exit(1);
50
- }
51
- // Test 3: Generate documentation
52
- console.log('Test 3: Generate documentation');
53
- try {
54
- const result = await generateDocumentation(client, {
55
- kind: 'function',
56
- name: 'add',
57
- signature: 'def add(a: int, b: int) -> int',
58
- parameters: [
59
- { name: 'a', type: 'int' },
60
- { name: 'b', type: 'int' }
61
- ],
62
- returnType: 'int',
63
- docstring: 'Add two numbers together.'
64
- });
65
- console.log(` markdown length: ${result.markdown.length} chars`);
66
- console.log(` code example length: ${result.codeExample.length} chars`);
67
- if (result.codeExample.includes('add(')) {
68
- console.log(' ✓ code example calls the function\n');
69
- }
70
- else {
71
- console.log(` code example:\n${result.codeExample}`);
72
- console.log(' ⚠ code example might not call the function\n');
73
- }
74
- }
75
- catch (err) {
76
- console.log(` ✗ doc generation failed: ${err}`);
77
- process.exit(1);
78
- }
79
- // Test 4: Fix broken code
80
- console.log('Test 4: Fix broken code');
81
- try {
82
- const fixed = await fixCodeSample(client, 'print(add(1, 2)', // Missing closing paren
83
- 'SyntaxError: unexpected EOF while parsing', 'This is a code example for the add function');
84
- console.log(` fixed code: ${fixed}`);
85
- if (fixed.includes(')')) {
86
- console.log(' ✓ code was fixed\n');
87
- }
88
- else {
89
- console.log(' ⚠ fix might be incomplete\n');
90
- }
91
- }
92
- catch (err) {
93
- console.log(` ✗ code fix failed: ${err}`);
94
- process.exit(1);
95
- }
96
- console.log('✓ All LLM client tests passed');
97
- }
98
- function getTestModel(provider) {
99
- switch (provider) {
100
- case 'deepseek': return 'deepseek-chat';
101
- case 'openai': return 'gpt-4o-mini';
102
- case 'anthropic': return 'claude-sonnet-4-5-20241022';
103
- case 'google': return 'gemini-2.0-flash';
104
- case 'ollama': return 'llama3.2:1b'; // Small model for testing
105
- case 'openrouter': return 'openai/gpt-4o-mini';
106
- default: return 'gpt-4o-mini';
107
- }
108
- }
109
- runTests().catch(err => {
110
- console.error('Test failed:', err);
111
- process.exit(1);
112
- });
@@ -1,4 +0,0 @@
1
- /**
2
- * Mock tests for LLM client - tests structure without API calls
3
- */
4
- export {};
@@ -1,79 +0,0 @@
1
- /**
2
- * Mock tests for LLM client - tests structure without API calls
3
- */
4
- import { createLLMClient, PROVIDER_BASE_URLS } from './index.js';
5
- function runMockTests() {
6
- console.log('=== LLM Client Mock Tests ===\n');
7
- // Test 1: Client creation for each provider
8
- console.log('Test 1: Create client for each provider');
9
- const providers = ['deepseek', 'openai', 'anthropic', 'google', 'ollama', 'openrouter'];
10
- for (const provider of providers) {
11
- try {
12
- // Create client to verify no errors thrown
13
- createLLMClient({
14
- provider,
15
- model: 'test-model'
16
- });
17
- console.log(` ✓ ${provider}: client created`);
18
- }
19
- catch (err) {
20
- console.log(` ✗ ${provider}: ${err}`);
21
- process.exit(1);
22
- }
23
- }
24
- console.log('');
25
- // Test 2: Verify base URLs
26
- console.log('Test 2: Verify provider base URLs');
27
- const expectedUrls = {
28
- deepseek: 'https://api.deepseek.com/v1',
29
- openai: 'https://api.openai.com/v1',
30
- anthropic: 'https://api.anthropic.com',
31
- google: 'https://generativelanguage.googleapis.com/v1beta/openai',
32
- ollama: 'http://localhost:11434/v1',
33
- openrouter: 'https://openrouter.ai/api/v1'
34
- };
35
- for (const [provider, expectedUrl] of Object.entries(expectedUrls)) {
36
- const actualUrl = PROVIDER_BASE_URLS[provider];
37
- if (actualUrl === expectedUrl) {
38
- console.log(` ✓ ${provider}: ${actualUrl}`);
39
- }
40
- else {
41
- console.log(` ✗ ${provider}: expected ${expectedUrl}, got ${actualUrl}`);
42
- process.exit(1);
43
- }
44
- }
45
- console.log('');
46
- // Test 3: Anthropic vs OpenAI-compatible client selection
47
- console.log('Test 3: Client type selection');
48
- const anthropicClient = createLLMClient({ provider: 'anthropic', model: 'claude-3' });
49
- const openaiClient = createLLMClient({ provider: 'openai', model: 'gpt-4' });
50
- const deepseekClient = createLLMClient({ provider: 'deepseek', model: 'deepseek-v3' });
51
- // Check they're different implementations for anthropic vs others
52
- const anthropicType = anthropicClient.constructor.name;
53
- const openaiType = openaiClient.constructor.name;
54
- const deepseekType = deepseekClient.constructor.name;
55
- console.log(` anthropic client: ${anthropicType}`);
56
- console.log(` openai client: ${openaiType}`);
57
- console.log(` deepseek client: ${deepseekType}`);
58
- if (anthropicType !== openaiType) {
59
- console.log(' ✓ anthropic uses different client than openai');
60
- }
61
- else {
62
- console.log(' ✗ anthropic should use different client');
63
- process.exit(1);
64
- }
65
- if (openaiType === deepseekType) {
66
- console.log(' ✓ deepseek uses same client as openai (OpenAI-compatible)');
67
- }
68
- else {
69
- console.log(' ✗ deepseek should use same client as openai');
70
- process.exit(1);
71
- }
72
- console.log('');
73
- console.log('✓ All mock tests passed\n');
74
- console.log('To run real API tests, set an API key and run:');
75
- console.log(' DEEPSEEK_API_KEY=your-key npx tsx src/llm/llm.test.ts');
76
- console.log(' ANTHROPIC_API_KEY=your-key npx tsx src/llm/llm.test.ts');
77
- console.log(' Or start Ollama locally');
78
- }
79
- runMockTests();
@@ -1,47 +0,0 @@
1
- export interface SkryptPlugin {
2
- name: string;
3
- version?: string;
4
- onInit?: (context: PluginContext) => Promise<void> | void;
5
- onBeforeScan?: (context: PluginContext) => Promise<void> | void;
6
- onAfterScan?: (context: PluginContext, elements: unknown[]) => Promise<unknown[]> | unknown[];
7
- onBeforeGenerate?: (context: PluginContext, elements: unknown[]) => Promise<unknown[]> | unknown[];
8
- onAfterGenerate?: (context: PluginContext, docs: unknown[]) => Promise<unknown[]> | unknown[];
9
- onBeforeWrite?: (context: PluginContext, docs: unknown[]) => Promise<unknown[]> | unknown[];
10
- onAfterWrite?: (context: PluginContext) => Promise<void> | void;
11
- transformContent?: (content: string, filePath: string) => Promise<string> | string;
12
- transformElement?: (element: unknown) => Promise<unknown> | unknown;
13
- }
14
- export interface PluginContext {
15
- sourcePath: string;
16
- outputPath: string;
17
- config: Record<string, unknown>;
18
- logger: {
19
- info: (msg: string) => void;
20
- warn: (msg: string) => void;
21
- error: (msg: string) => void;
22
- };
23
- }
24
- export declare class PluginManager {
25
- private plugins;
26
- private context;
27
- constructor(sourcePath: string, outputPath: string, config?: Record<string, unknown>);
28
- loadPlugins(configPath?: string): Promise<void>;
29
- private findConfigFile;
30
- private loadPluginByName;
31
- register(plugin: SkryptPlugin): void;
32
- runHook<T>(hook: keyof SkryptPlugin, ...args: unknown[]): Promise<T | undefined>;
33
- onInit(): Promise<void>;
34
- onBeforeScan(): Promise<void>;
35
- onAfterScan<T>(elements: T[]): Promise<T[]>;
36
- onBeforeGenerate<T>(elements: T[]): Promise<T[]>;
37
- onAfterGenerate<T>(docs: T[]): Promise<T[]>;
38
- onBeforeWrite<T>(docs: T[]): Promise<T[]>;
39
- onAfterWrite(): Promise<void>;
40
- transformContent(content: string, filePath: string): Promise<string>;
41
- }
42
- export declare const builtinPlugins: {
43
- timestamp: SkryptPlugin;
44
- editOnGithub: (repoUrl: string, branch?: string) => SkryptPlugin;
45
- toc: SkryptPlugin;
46
- };
47
- export declare function definePlugin(plugin: SkryptPlugin): SkryptPlugin;
@@ -1,181 +0,0 @@
1
- // TODO: Plugin system is defined but not yet wired into the generate pipeline
2
- import { existsSync } from 'fs';
3
- import { resolve } from 'path';
4
- import { pathToFileURL } from 'url';
5
- export class PluginManager {
6
- plugins = [];
7
- context;
8
- constructor(sourcePath, outputPath, config = {}) {
9
- this.context = {
10
- sourcePath,
11
- outputPath,
12
- config,
13
- logger: {
14
- info: (msg) => console.log(`[plugin] ${msg}`),
15
- warn: (msg) => console.warn(`[plugin] ${msg}`),
16
- error: (msg) => console.error(`[plugin] ${msg}`),
17
- },
18
- };
19
- }
20
- async loadPlugins(configPath) {
21
- // Load from skrypt.config.js or skrypt.config.ts
22
- const configFile = configPath || this.findConfigFile();
23
- if (!configFile)
24
- return;
25
- try {
26
- console.log(` Loading config: ${configFile}`);
27
- console.warn(' ⚠ Plugin configs execute code — only load trusted files');
28
- const configUrl = pathToFileURL(configFile).href;
29
- const module = await import(configUrl);
30
- const config = module.default || module;
31
- if (config.plugins && Array.isArray(config.plugins)) {
32
- for (const plugin of config.plugins) {
33
- if (typeof plugin === 'string') {
34
- // Load plugin by name
35
- await this.loadPluginByName(plugin);
36
- }
37
- else if (typeof plugin === 'object' && plugin.name) {
38
- // Plugin object
39
- this.register(plugin);
40
- }
41
- }
42
- }
43
- }
44
- catch (err) {
45
- console.error(`Failed to load config: ${err}`);
46
- }
47
- }
48
- findConfigFile() {
49
- const candidates = [
50
- 'skrypt.config.js',
51
- 'skrypt.config.mjs',
52
- 'skrypt.config.ts',
53
- ];
54
- for (const name of candidates) {
55
- const path = resolve(process.cwd(), name);
56
- if (existsSync(path))
57
- return path;
58
- }
59
- return null;
60
- }
61
- async loadPluginByName(name) {
62
- // Validate plugin name — must be a valid npm package name, no path traversal
63
- if (!/^(@[a-zA-Z0-9._-]+\/)?[a-zA-Z0-9._-]+$/.test(name)) {
64
- console.warn(`Skipping plugin with invalid name: ${name}`);
65
- return;
66
- }
67
- // Try to load from node_modules
68
- try {
69
- const module = await import(name);
70
- const plugin = module.default || module;
71
- if (plugin.name) {
72
- this.register(plugin);
73
- }
74
- }
75
- catch {
76
- console.warn(`Failed to load plugin: ${name}`);
77
- }
78
- }
79
- register(plugin) {
80
- this.plugins.push(plugin);
81
- console.log(`Loaded plugin: ${plugin.name}${plugin.version ? ` v${plugin.version}` : ''}`);
82
- }
83
- async runHook(hook, ...args) {
84
- let result = args[0];
85
- for (const plugin of this.plugins) {
86
- const fn = plugin[hook];
87
- if (typeof fn === 'function') {
88
- try {
89
- const hookResult = await fn.call(plugin, this.context, ...args);
90
- if (hookResult !== undefined) {
91
- result = hookResult;
92
- }
93
- }
94
- catch (err) {
95
- console.error(`Plugin ${plugin.name} error in ${hook}: ${err}`);
96
- }
97
- }
98
- }
99
- return result;
100
- }
101
- async onInit() {
102
- await this.runHook('onInit');
103
- }
104
- async onBeforeScan() {
105
- await this.runHook('onBeforeScan');
106
- }
107
- async onAfterScan(elements) {
108
- return (await this.runHook('onAfterScan', elements)) || elements;
109
- }
110
- async onBeforeGenerate(elements) {
111
- return (await this.runHook('onBeforeGenerate', elements)) || elements;
112
- }
113
- async onAfterGenerate(docs) {
114
- return (await this.runHook('onAfterGenerate', docs)) || docs;
115
- }
116
- async onBeforeWrite(docs) {
117
- return (await this.runHook('onBeforeWrite', docs)) || docs;
118
- }
119
- async onAfterWrite() {
120
- await this.runHook('onAfterWrite');
121
- }
122
- async transformContent(content, filePath) {
123
- let result = content;
124
- for (const plugin of this.plugins) {
125
- if (typeof plugin.transformContent === 'function') {
126
- try {
127
- result = await plugin.transformContent(result, filePath);
128
- }
129
- catch (err) {
130
- console.error(`Plugin ${plugin.name} error in transformContent: ${err}`);
131
- }
132
- }
133
- }
134
- return result;
135
- }
136
- }
137
- // Built-in plugins
138
- export const builtinPlugins = {
139
- // Add timestamp to generated files
140
- timestamp: {
141
- name: 'timestamp',
142
- transformContent: (content) => {
143
- const timestamp = new Date().toISOString();
144
- return content.replace(/^(---\n)/, `$1generated_at: "${timestamp}"\n`);
145
- },
146
- },
147
- // Add "Edit on GitHub" links
148
- editOnGithub: (repoUrl, branch = 'main') => ({
149
- name: 'edit-on-github',
150
- transformContent: (content, filePath) => {
151
- const editUrl = `${repoUrl}/edit/${branch}/${filePath}`;
152
- return content.replace(/^(---\n[\s\S]*?---\n)/, `$1\n<EditOnGithub url="${editUrl}" />\n`);
153
- },
154
- }),
155
- // Auto-generate table of contents
156
- toc: {
157
- name: 'toc',
158
- transformContent: (content) => {
159
- const headings = [];
160
- const lines = content.split('\n');
161
- for (const line of lines) {
162
- const match = line.match(/^(#{2,4})\s+(.+)$/);
163
- if (match) {
164
- const level = match[1].length;
165
- const text = match[2];
166
- const anchor = text.toLowerCase().replace(/[^\w]+/g, '-');
167
- headings.push({ level, text, anchor });
168
- }
169
- }
170
- if (headings.length < 2)
171
- return content;
172
- const toc = headings
173
- .map(h => `${' '.repeat(h.level - 2)}- [${h.text}](#${h.anchor})`)
174
- .join('\n');
175
- return content.replace(/^(---\n[\s\S]*?---\n)/, `$1\n## Table of Contents\n\n${toc}\n\n`);
176
- },
177
- },
178
- };
179
- export function definePlugin(plugin) {
180
- return plugin;
181
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,231 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { classifyElement, classifyElements, getRecommendedStructure, getPromptForContentType } from './content-type.js';
3
- function createMockElement(overrides = {}) {
4
- return {
5
- kind: 'function',
6
- name: 'testFunction',
7
- signature: 'function testFunction()',
8
- parameters: [],
9
- filePath: '/src/test.ts',
10
- lineNumber: 1,
11
- isExported: true,
12
- isPublic: true,
13
- ...overrides,
14
- };
15
- }
16
- describe('Content Type Detection', () => {
17
- describe('classifyElement', () => {
18
- it('should classify API elements with multiple parameters', () => {
19
- const element = createMockElement({
20
- name: 'fetchData',
21
- parameters: [
22
- { name: 'url', type: 'string' },
23
- { name: 'options', type: 'RequestOptions' },
24
- { name: 'timeout', type: 'number' },
25
- ],
26
- });
27
- const result = classifyElement(element);
28
- expect(result.type).toBe('api');
29
- expect(result.confidence).toBeGreaterThan(0);
30
- });
31
- it('should classify handler/endpoint patterns as API', () => {
32
- const element = createMockElement({
33
- name: 'userHandler',
34
- kind: 'method',
35
- parentClass: 'UserController',
36
- filePath: '/src/handlers/user.ts',
37
- parameters: [
38
- { name: 'req', type: 'Request' },
39
- { name: 'res', type: 'Response' },
40
- ],
41
- });
42
- const result = classifyElement(element);
43
- expect(result.type).toBe('api');
44
- });
45
- it('should classify HTTP methods as API', () => {
46
- const element = createMockElement({
47
- signature: 'async function handleGET(request: Request): Promise<Response>',
48
- docstring: 'Handles GET requests for user data',
49
- });
50
- const result = classifyElement(element);
51
- expect(result.type).toBe('api');
52
- });
53
- it('should classify config/setup functions as guide', () => {
54
- const element = createMockElement({
55
- name: 'configureDatabase',
56
- });
57
- const result = classifyElement(element);
58
- expect(result.type).toBe('guide');
59
- });
60
- it('should classify init functions as guide', () => {
61
- const element = createMockElement({
62
- name: 'initializeApp',
63
- });
64
- const result = classifyElement(element);
65
- expect(result.type).toBe('guide');
66
- });
67
- it('should classify example files as tutorial', () => {
68
- const element = createMockElement({
69
- name: 'main',
70
- filePath: '/examples/quickstart.ts',
71
- });
72
- const result = classifyElement(element);
73
- expect(result.type).toBe('tutorial');
74
- });
75
- it('should classify demo functions as tutorial', () => {
76
- const element = createMockElement({
77
- name: 'demoFeature',
78
- });
79
- const result = classifyElement(element);
80
- expect(result.type).toBe('tutorial');
81
- });
82
- it('should classify simple functions with few params as tutorial', () => {
83
- const element = createMockElement({
84
- name: 'simpleFunction',
85
- kind: 'function',
86
- parameters: [{ name: 'input', type: 'string' }],
87
- });
88
- const result = classifyElement(element);
89
- // Simple functions default to tutorial
90
- expect(result.type).toBe('tutorial');
91
- });
92
- it('should classify async API patterns correctly', () => {
93
- const element = createMockElement({
94
- signature: 'async function createUser(data: UserData): Promise<User>',
95
- parameters: [
96
- { name: 'data', type: 'UserData' },
97
- { name: 'options', type: 'CreateOptions' },
98
- { name: 'validate', type: 'boolean' },
99
- ],
100
- });
101
- const result = classifyElement(element);
102
- expect(result.type).toBe('api');
103
- });
104
- it('should return tutorial for simple functions with no indicators', () => {
105
- // Simple functions with few params default to tutorial
106
- const element = createMockElement({
107
- name: 'x',
108
- kind: 'function',
109
- parameters: [],
110
- docstring: undefined,
111
- filePath: '/src/utils.ts',
112
- });
113
- const result = classifyElement(element);
114
- // Gets tutorial because simple function with <=1 params
115
- expect(result.type).toBe('tutorial');
116
- });
117
- it('should return overview for class elements with no indicators', () => {
118
- // Classes without other indicators get overview
119
- const element = createMockElement({
120
- name: 'X',
121
- kind: 'class',
122
- parameters: [],
123
- docstring: undefined,
124
- filePath: '/src/utils.ts',
125
- });
126
- const result = classifyElement(element);
127
- expect(result.type).toBe('overview');
128
- });
129
- it('should include reasons for classification', () => {
130
- const element = createMockElement({
131
- name: 'handler',
132
- filePath: '/src/handlers/api.ts',
133
- });
134
- const result = classifyElement(element);
135
- expect(result.reasons.length).toBeGreaterThan(0);
136
- });
137
- });
138
- describe('classifyElements', () => {
139
- it('should group elements by content type', () => {
140
- const elements = [
141
- createMockElement({
142
- name: 'fetchUsers',
143
- kind: 'method',
144
- parentClass: 'UserService',
145
- parameters: [
146
- { name: 'page', type: 'number' },
147
- { name: 'limit', type: 'number' },
148
- { name: 'filter', type: 'Filter' },
149
- ],
150
- }),
151
- createMockElement({
152
- name: 'configureAuth',
153
- kind: 'function',
154
- parameters: [
155
- { name: 'options', type: 'AuthOptions' },
156
- { name: 'provider', type: 'Provider' },
157
- ],
158
- }),
159
- createMockElement({
160
- name: 'exampleUsage',
161
- filePath: '/examples/demo.ts',
162
- }),
163
- ];
164
- const result = classifyElements(elements);
165
- expect(result.get('api')?.length).toBeGreaterThanOrEqual(1);
166
- // configureAuth should be guide (config pattern)
167
- expect(result.get('guide')?.length).toBeGreaterThanOrEqual(1);
168
- expect(result.get('tutorial')?.length).toBeGreaterThanOrEqual(1);
169
- });
170
- it('should handle empty elements array', () => {
171
- const result = classifyElements([]);
172
- expect(result.get('api')).toHaveLength(0);
173
- expect(result.get('guide')).toHaveLength(0);
174
- expect(result.get('tutorial')).toHaveLength(0);
175
- expect(result.get('overview')).toHaveLength(0);
176
- });
177
- });
178
- describe('getRecommendedStructure', () => {
179
- it('should return sections grouped by type', () => {
180
- const elements = [
181
- createMockElement({
182
- name: 'createUser',
183
- parameters: [
184
- { name: 'data', type: 'UserData' },
185
- { name: 'options', type: 'Options' },
186
- { name: 'callback', type: 'Function' },
187
- ],
188
- }),
189
- createMockElement({
190
- name: 'setupDatabase',
191
- }),
192
- ];
193
- const result = getRecommendedStructure(elements);
194
- expect(result.sections.length).toBeGreaterThan(0);
195
- expect(result.stats.api + result.stats.guide + result.stats.tutorial + result.stats.overview).toBe(elements.length);
196
- });
197
- it('should provide stats for each type', () => {
198
- const elements = [
199
- createMockElement({ name: 'api1', parameters: [{ name: 'a' }, { name: 'b' }, { name: 'c' }] }),
200
- createMockElement({ name: 'api2', parameters: [{ name: 'x' }, { name: 'y' }, { name: 'z' }] }),
201
- createMockElement({ name: 'config1' }),
202
- ];
203
- const result = getRecommendedStructure(elements);
204
- expect(typeof result.stats.api).toBe('number');
205
- expect(typeof result.stats.guide).toBe('number');
206
- expect(typeof result.stats.tutorial).toBe('number');
207
- expect(typeof result.stats.overview).toBe('number');
208
- });
209
- });
210
- describe('getPromptForContentType', () => {
211
- it('should return appropriate prompt for api type', () => {
212
- const prompt = getPromptForContentType('api');
213
- expect(prompt).toContain('API reference');
214
- expect(prompt).toContain('parameter');
215
- });
216
- it('should return appropriate prompt for guide type', () => {
217
- const prompt = getPromptForContentType('guide');
218
- expect(prompt).toContain('guide');
219
- expect(prompt).toContain('setup');
220
- });
221
- it('should return appropriate prompt for tutorial type', () => {
222
- const prompt = getPromptForContentType('tutorial');
223
- expect(prompt).toContain('tutorial');
224
- expect(prompt).toContain('beginner');
225
- });
226
- it('should return appropriate prompt for overview type', () => {
227
- const prompt = getPromptForContentType('overview');
228
- expect(prompt).toContain('overview');
229
- });
230
- });
231
- });
@@ -1,4 +0,0 @@
1
- /**
2
- * Integration tests for the full scanning pipeline
3
- */
4
- export {};