rlint 0.4.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 (74) hide show
  1. package/README.md +220 -0
  2. package/dist/browser.d.ts +8 -0
  3. package/dist/browser.d.ts.map +1 -0
  4. package/dist/browser.js +122 -0
  5. package/dist/browser.js.map +1 -0
  6. package/dist/checks/clickability.d.ts +3 -0
  7. package/dist/checks/clickability.d.ts.map +1 -0
  8. package/dist/checks/clickability.js +125 -0
  9. package/dist/checks/clickability.js.map +1 -0
  10. package/dist/checks/index.d.ts +9 -0
  11. package/dist/checks/index.d.ts.map +1 -0
  12. package/dist/checks/index.js +27 -0
  13. package/dist/checks/index.js.map +1 -0
  14. package/dist/checks/overflow.d.ts +3 -0
  15. package/dist/checks/overflow.d.ts.map +1 -0
  16. package/dist/checks/overflow.js +107 -0
  17. package/dist/checks/overflow.js.map +1 -0
  18. package/dist/checks/text-overflow.d.ts +3 -0
  19. package/dist/checks/text-overflow.d.ts.map +1 -0
  20. package/dist/checks/text-overflow.js +136 -0
  21. package/dist/checks/text-overflow.js.map +1 -0
  22. package/dist/checks/touch-targets.d.ts +3 -0
  23. package/dist/checks/touch-targets.d.ts.map +1 -0
  24. package/dist/checks/touch-targets.js +118 -0
  25. package/dist/checks/touch-targets.js.map +1 -0
  26. package/dist/checks/visibility.d.ts +3 -0
  27. package/dist/checks/visibility.d.ts.map +1 -0
  28. package/dist/checks/visibility.js +132 -0
  29. package/dist/checks/visibility.js.map +1 -0
  30. package/dist/cli.d.ts +3 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +270 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/frameworks/detector.d.ts +19 -0
  35. package/dist/frameworks/detector.d.ts.map +1 -0
  36. package/dist/frameworks/detector.js +132 -0
  37. package/dist/frameworks/detector.js.map +1 -0
  38. package/dist/frameworks/index.d.ts +44 -0
  39. package/dist/frameworks/index.d.ts.map +1 -0
  40. package/dist/frameworks/index.js +138 -0
  41. package/dist/frameworks/index.js.map +1 -0
  42. package/dist/frameworks/next.d.ts +34 -0
  43. package/dist/frameworks/next.d.ts.map +1 -0
  44. package/dist/frameworks/next.js +160 -0
  45. package/dist/frameworks/next.js.map +1 -0
  46. package/dist/frameworks/sveltekit.d.ts +34 -0
  47. package/dist/frameworks/sveltekit.d.ts.map +1 -0
  48. package/dist/frameworks/sveltekit.js +150 -0
  49. package/dist/frameworks/sveltekit.js.map +1 -0
  50. package/dist/frameworks/vite.d.ts +40 -0
  51. package/dist/frameworks/vite.d.ts.map +1 -0
  52. package/dist/frameworks/vite.js +211 -0
  53. package/dist/frameworks/vite.js.map +1 -0
  54. package/dist/index.d.ts +18 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +22 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/mcp-server.d.ts +3 -0
  59. package/dist/mcp-server.d.ts.map +1 -0
  60. package/dist/mcp-server.js +402 -0
  61. package/dist/mcp-server.js.map +1 -0
  62. package/dist/reporter.d.ts +4 -0
  63. package/dist/reporter.d.ts.map +1 -0
  64. package/dist/reporter.js +103 -0
  65. package/dist/reporter.js.map +1 -0
  66. package/dist/runner.d.ts +8 -0
  67. package/dist/runner.d.ts.map +1 -0
  68. package/dist/runner.js +63 -0
  69. package/dist/runner.js.map +1 -0
  70. package/dist/types.d.ts +96 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +2 -0
  73. package/dist/types.js.map +1 -0
  74. package/package.json +69 -0
package/dist/cli.js ADDED
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { launchBrowser } from './browser.js';
5
+ import { runChecks } from './runner.js';
6
+ import { formatResults } from './reporter.js';
7
+ import { existsSync } from 'fs';
8
+ import { resolve } from 'path';
9
+ import { startDevServer, waitForHydration, getFrameworkInfo, needsHydration, } from './frameworks/index.js';
10
+ program
11
+ .name('rlint')
12
+ .description('Catch rendered layout bugs automatically - no screenshots needed')
13
+ .version('0.4.0');
14
+ // Check command - check URLs directly
15
+ program
16
+ .command('check')
17
+ .description('Check a URL for CSS health issues')
18
+ .argument('<urls...>', 'URLs to check')
19
+ .option('-c, --config <path>', 'Path to config file')
20
+ .option('-f, --format <format>', 'Output format: text, json, junit', 'text')
21
+ .option('-o, --only <checks>', 'Only run specific checks (comma-separated)')
22
+ .option('-i, --ignore <selectors>', 'Ignore elements matching selectors (comma-separated)')
23
+ .option('-v, --viewport <size>', 'Viewport size (e.g., 1920x1080 or 375x667,1920x1080 for multiple)')
24
+ .option('--fail-on <severity>', 'Exit with error if issues of this severity found: error, warning', 'error')
25
+ .option('--headed', 'Run browser in headed mode (visible)')
26
+ .option('--wait-for-hydration', 'Wait for SPA hydration before checking', false)
27
+ .option('--framework <framework>', 'Specify framework for hydration detection')
28
+ .action(async (urls, options) => {
29
+ // Load config file if specified
30
+ let config = {};
31
+ if (options.config) {
32
+ const configPath = resolve(process.cwd(), options.config);
33
+ if (existsSync(configPath)) {
34
+ const configModule = await import(configPath);
35
+ config = configModule.default || configModule;
36
+ }
37
+ else {
38
+ console.error(`Config file not found: ${configPath}`);
39
+ process.exit(1);
40
+ }
41
+ }
42
+ // Apply CLI options to config
43
+ if (options.ignore) {
44
+ config.ignore = [
45
+ ...(config.ignore || []),
46
+ ...options.ignore.split(',').map((s) => s.trim()),
47
+ ];
48
+ }
49
+ // Parse viewports
50
+ const viewports = options.viewport
51
+ ? options.viewport.split(',').map((v) => {
52
+ const [width, height] = v.split('x').map(Number);
53
+ return { width, height };
54
+ })
55
+ : [{ width: 1280, height: 720 }];
56
+ // Parse checks to run
57
+ const checksToRun = options.only
58
+ ? options.only.split(',').map((s) => s.trim())
59
+ : undefined;
60
+ // Launch browser (auto-installs Chromium if needed)
61
+ const browser = await launchBrowser({
62
+ headless: !options.headed,
63
+ });
64
+ let hasFailures = false;
65
+ try {
66
+ for (const url of urls) {
67
+ for (const viewport of viewports) {
68
+ const page = await browser.newPage();
69
+ await page.setViewport(viewport);
70
+ try {
71
+ // Navigate to URL
72
+ const fullUrl = url.startsWith('http') || url.startsWith('file://') ? url : `https://${url}`;
73
+ await page.goto(fullUrl, { waitUntil: 'networkidle0' });
74
+ // Wait for hydration if requested
75
+ if (options.waitForHydration) {
76
+ console.log(chalk.dim('Waiting for hydration...'));
77
+ const framework = options.framework;
78
+ await waitForHydration(page, framework);
79
+ }
80
+ // Wait a bit for any animations/transitions
81
+ await new Promise(r => setTimeout(r, 500));
82
+ // Run checks
83
+ const results = await runChecks(page, {
84
+ config,
85
+ checks: checksToRun,
86
+ });
87
+ // Output results
88
+ console.log(formatResults(results, options.format));
89
+ // Check for failures based on fail-on option
90
+ if (options.failOn === 'error' && results.summary.errors > 0) {
91
+ hasFailures = true;
92
+ }
93
+ else if (options.failOn === 'warning' && (results.summary.errors > 0 || results.summary.warnings > 0)) {
94
+ hasFailures = true;
95
+ }
96
+ }
97
+ catch (error) {
98
+ console.error(`Error checking ${url}:`, error);
99
+ hasFailures = true;
100
+ }
101
+ finally {
102
+ await page.close();
103
+ }
104
+ }
105
+ }
106
+ }
107
+ finally {
108
+ await browser.close();
109
+ }
110
+ process.exit(hasFailures ? 1 : 0);
111
+ });
112
+ // Dev command - auto-detect framework and start dev server
113
+ program
114
+ .command('dev')
115
+ .description('Auto-detect framework, start dev server, and check routes')
116
+ .option('-r, --routes <routes>', 'Comma-separated routes to check (default: /)', '/')
117
+ .option('-p, --port <port>', 'Dev server port (uses framework default if not specified)')
118
+ .option('-f, --format <format>', 'Output format: text, json, junit', 'text')
119
+ .option('-o, --only <checks>', 'Only run specific checks (comma-separated)')
120
+ .option('-i, --ignore <selectors>', 'Ignore elements matching selectors (comma-separated)')
121
+ .option('-v, --viewport <size>', 'Viewport size (e.g., 1920x1080)', '1280x720')
122
+ .option('--framework <framework>', 'Specify framework manually (nextjs, sveltekit, vite, etc.)')
123
+ .option('--wait-for-hydration', 'Wait for SPA hydration (default: auto-detect based on framework)')
124
+ .option('--no-wait-for-hydration', 'Skip waiting for hydration')
125
+ .option('--no-start-server', 'Skip starting dev server (assume it\'s already running)')
126
+ .option('--fail-on <severity>', 'Exit with error if issues found: error, warning', 'error')
127
+ .option('--headed', 'Run browser in headed mode (visible)')
128
+ .action(async (options) => {
129
+ await runDevCheck(options);
130
+ });
131
+ async function runDevCheck(options) {
132
+ // Detect or use specified framework
133
+ const frameworkInfo = getFrameworkInfo();
134
+ const framework = options.framework || frameworkInfo.name;
135
+ if (framework === 'unknown') {
136
+ console.error(chalk.red('Error:'), 'Could not detect framework. Please specify with --framework flag.');
137
+ console.error(chalk.dim('Supported frameworks: nextjs, sveltekit, vite, create-react-app, remix, astro, nuxt'));
138
+ process.exit(1);
139
+ }
140
+ console.log(chalk.bold(`\nrlint dev`));
141
+ console.log(chalk.dim(`Framework: ${frameworkInfo.displayName}${frameworkInfo.version ? ` v${frameworkInfo.version}` : ''}`));
142
+ let server = null;
143
+ let baseUrl;
144
+ try {
145
+ // Start dev server if needed
146
+ if (options.startServer !== false) {
147
+ console.log(chalk.dim('Starting dev server...'));
148
+ const port = options.port ? parseInt(options.port, 10) : undefined;
149
+ server = await startDevServer({ framework, port });
150
+ baseUrl = server.baseUrl;
151
+ console.log(chalk.green(`Dev server running at ${baseUrl}`));
152
+ }
153
+ else {
154
+ const port = options.port || frameworkInfo.defaultPort.toString();
155
+ baseUrl = `http://localhost:${port}`;
156
+ console.log(chalk.dim(`Using existing server at ${baseUrl}`));
157
+ }
158
+ // Parse routes
159
+ const routes = options.routes?.split(',').map((r) => r.trim()) || ['/'];
160
+ // Parse viewport
161
+ const [width, height] = (options.viewport || '1280x720').split('x').map(Number);
162
+ const viewport = { width, height };
163
+ // Launch browser (auto-installs Chromium if needed)
164
+ const browser = await launchBrowser({
165
+ headless: !options.headed,
166
+ });
167
+ try {
168
+ // Determine if we should wait for hydration
169
+ const shouldWaitForHydration = options.waitForHydration !== undefined
170
+ ? options.waitForHydration
171
+ : needsHydration(framework);
172
+ // Build config
173
+ const config = {};
174
+ if (options.ignore) {
175
+ config.ignore = options.ignore.split(',').map((s) => s.trim());
176
+ }
177
+ const checksToRun = options.only?.split(',').map((s) => s.trim());
178
+ let hasErrors = false;
179
+ let hasWarnings = false;
180
+ const allResults = [];
181
+ // Check each route
182
+ for (const route of routes) {
183
+ const url = `${baseUrl}${route.startsWith('/') ? route : '/' + route}`;
184
+ console.log(chalk.dim(`\nChecking ${route}...`));
185
+ const page = await browser.newPage();
186
+ await page.setViewport(viewport);
187
+ try {
188
+ await page.goto(url, { waitUntil: 'domcontentloaded' });
189
+ // Wait for hydration if needed
190
+ if (shouldWaitForHydration) {
191
+ console.log(chalk.dim('Waiting for hydration...'));
192
+ await waitForHydration(page, framework);
193
+ }
194
+ // Wait a bit for any animations/transitions
195
+ await new Promise(r => setTimeout(r, 500));
196
+ // Run checks
197
+ const results = await runChecks(page, {
198
+ config,
199
+ checks: checksToRun,
200
+ });
201
+ const output = formatResults(results, options.format);
202
+ allResults.push({
203
+ route,
204
+ output,
205
+ errors: results.summary.errors,
206
+ warnings: results.summary.warnings,
207
+ });
208
+ if (results.summary.errors > 0) {
209
+ hasErrors = true;
210
+ }
211
+ if (results.summary.warnings > 0) {
212
+ hasWarnings = true;
213
+ }
214
+ }
215
+ finally {
216
+ await page.close();
217
+ }
218
+ }
219
+ // Output all results
220
+ console.log(chalk.bold('\n' + '='.repeat(60)));
221
+ console.log(chalk.bold('Results'));
222
+ console.log('='.repeat(60));
223
+ for (const { route, output } of allResults) {
224
+ console.log(chalk.bold(`\nRoute: ${route}`));
225
+ console.log(output);
226
+ }
227
+ // Summary
228
+ const totalErrors = allResults.reduce((sum, r) => sum + r.errors, 0);
229
+ const totalWarnings = allResults.reduce((sum, r) => sum + r.warnings, 0);
230
+ console.log(chalk.bold('\nSummary:'));
231
+ console.log(` Routes checked: ${allResults.length}`);
232
+ if (totalErrors > 0) {
233
+ console.log(chalk.red(` Total errors: ${totalErrors}`));
234
+ }
235
+ if (totalWarnings > 0) {
236
+ console.log(chalk.yellow(` Total warnings: ${totalWarnings}`));
237
+ }
238
+ if (totalErrors === 0 && totalWarnings === 0) {
239
+ console.log(chalk.green(' All checks passed!'));
240
+ }
241
+ // Determine exit code based on fail-on option
242
+ let shouldFail = false;
243
+ if (options.failOn === 'error' && hasErrors) {
244
+ shouldFail = true;
245
+ }
246
+ else if (options.failOn === 'warning' && (hasErrors || hasWarnings)) {
247
+ shouldFail = true;
248
+ }
249
+ if (shouldFail) {
250
+ process.exit(1);
251
+ }
252
+ }
253
+ finally {
254
+ await browser.close();
255
+ }
256
+ }
257
+ catch (error) {
258
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
259
+ process.exit(1);
260
+ }
261
+ finally {
262
+ // Stop dev server if we started it
263
+ if (server) {
264
+ console.log(chalk.dim('\nStopping dev server...'));
265
+ await server.stop();
266
+ }
267
+ }
268
+ }
269
+ program.parse();
270
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export type FrameworkName = 'nextjs' | 'sveltekit' | 'vite' | 'create-react-app' | 'remix' | 'astro' | 'nuxt' | 'unknown';
2
+ export interface DetectedFramework {
3
+ name: FrameworkName;
4
+ version: string | null;
5
+ configFile: string | null;
6
+ }
7
+ /**
8
+ * Auto-detect the framework from package.json or config files
9
+ */
10
+ export declare function detectFramework(projectPath?: string): DetectedFramework;
11
+ /**
12
+ * Check if a framework uses SPA hydration (needs to wait for JS)
13
+ */
14
+ export declare function needsHydration(framework: FrameworkName): boolean;
15
+ /**
16
+ * Get the default port for a framework's dev server
17
+ */
18
+ export declare function getDefaultPort(framework: FrameworkName): number;
19
+ //# sourceMappingURL=detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/frameworks/detector.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,WAAW,GACX,MAAM,GACN,kBAAkB,GAClB,OAAO,GACP,OAAO,GACP,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAOD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,GAAE,MAAsB,GAAG,iBAAiB,CAsFtF;AAuBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,CAEhE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAmB/D"}
@@ -0,0 +1,132 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * Auto-detect the framework from package.json or config files
5
+ */
6
+ export function detectFramework(projectPath = process.cwd()) {
7
+ const packageJsonPath = join(projectPath, 'package.json');
8
+ if (!existsSync(packageJsonPath)) {
9
+ return { name: 'unknown', version: null, configFile: null };
10
+ }
11
+ let packageJson;
12
+ try {
13
+ packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
14
+ }
15
+ catch {
16
+ return { name: 'unknown', version: null, configFile: null };
17
+ }
18
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
19
+ // Check for Next.js
20
+ if (deps['next']) {
21
+ const configFile = findConfigFile(projectPath, ['next.config.js', 'next.config.mjs', 'next.config.ts']);
22
+ return {
23
+ name: 'nextjs',
24
+ version: cleanVersion(deps['next']),
25
+ configFile,
26
+ };
27
+ }
28
+ // Check for SvelteKit
29
+ if (deps['@sveltejs/kit']) {
30
+ const configFile = findConfigFile(projectPath, ['svelte.config.js', 'svelte.config.ts']);
31
+ return {
32
+ name: 'sveltekit',
33
+ version: cleanVersion(deps['@sveltejs/kit']),
34
+ configFile,
35
+ };
36
+ }
37
+ // Check for Nuxt
38
+ if (deps['nuxt'] || deps['nuxt3']) {
39
+ const configFile = findConfigFile(projectPath, ['nuxt.config.js', 'nuxt.config.ts']);
40
+ return {
41
+ name: 'nuxt',
42
+ version: cleanVersion(deps['nuxt'] || deps['nuxt3']),
43
+ configFile,
44
+ };
45
+ }
46
+ // Check for Remix
47
+ if (deps['@remix-run/react'] || deps['remix']) {
48
+ const configFile = findConfigFile(projectPath, ['remix.config.js', 'remix.config.ts']);
49
+ return {
50
+ name: 'remix',
51
+ version: cleanVersion(deps['@remix-run/react'] || deps['remix']),
52
+ configFile,
53
+ };
54
+ }
55
+ // Check for Astro
56
+ if (deps['astro']) {
57
+ const configFile = findConfigFile(projectPath, ['astro.config.mjs', 'astro.config.ts', 'astro.config.js']);
58
+ return {
59
+ name: 'astro',
60
+ version: cleanVersion(deps['astro']),
61
+ configFile,
62
+ };
63
+ }
64
+ // Check for Create React App (react-scripts)
65
+ if (deps['react-scripts']) {
66
+ return {
67
+ name: 'create-react-app',
68
+ version: cleanVersion(deps['react-scripts']),
69
+ configFile: null,
70
+ };
71
+ }
72
+ // Check for Vite (generic)
73
+ if (deps['vite']) {
74
+ const configFile = findConfigFile(projectPath, ['vite.config.js', 'vite.config.ts', 'vite.config.mjs']);
75
+ return {
76
+ name: 'vite',
77
+ version: cleanVersion(deps['vite']),
78
+ configFile,
79
+ };
80
+ }
81
+ return { name: 'unknown', version: null, configFile: null };
82
+ }
83
+ /**
84
+ * Find the first existing config file from a list of possible names
85
+ */
86
+ function findConfigFile(projectPath, possibleNames) {
87
+ for (const name of possibleNames) {
88
+ const filePath = join(projectPath, name);
89
+ if (existsSync(filePath)) {
90
+ return filePath;
91
+ }
92
+ }
93
+ return null;
94
+ }
95
+ /**
96
+ * Clean version string (remove ^ ~ etc.)
97
+ */
98
+ function cleanVersion(version) {
99
+ if (!version)
100
+ return null;
101
+ return version.replace(/^[\^~>=<]+/, '');
102
+ }
103
+ /**
104
+ * Check if a framework uses SPA hydration (needs to wait for JS)
105
+ */
106
+ export function needsHydration(framework) {
107
+ return ['nextjs', 'sveltekit', 'remix', 'nuxt', 'create-react-app', 'astro'].includes(framework);
108
+ }
109
+ /**
110
+ * Get the default port for a framework's dev server
111
+ */
112
+ export function getDefaultPort(framework) {
113
+ switch (framework) {
114
+ case 'nextjs':
115
+ return 3000;
116
+ case 'sveltekit':
117
+ return 5173;
118
+ case 'vite':
119
+ return 5173;
120
+ case 'create-react-app':
121
+ return 3000;
122
+ case 'remix':
123
+ return 3000;
124
+ case 'astro':
125
+ return 4321;
126
+ case 'nuxt':
127
+ return 3000;
128
+ default:
129
+ return 3000;
130
+ }
131
+ }
132
+ //# sourceMappingURL=detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/frameworks/detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import type { Page } from 'puppeteer-core';
2
+ import type { ChildProcess } from 'node:child_process';
3
+ export { detectFramework, needsHydration, getDefaultPort } from './detector.js';
4
+ export type { FrameworkName, DetectedFramework } from './detector.js';
5
+ export * as next from './next.js';
6
+ export * as sveltekit from './sveltekit.js';
7
+ export * as vite from './vite.js';
8
+ import { type FrameworkName } from './detector.js';
9
+ export interface DevServerOptions {
10
+ framework?: FrameworkName;
11
+ port?: number;
12
+ projectPath?: string;
13
+ host?: string;
14
+ }
15
+ export interface DevServer {
16
+ framework: FrameworkName;
17
+ process: ChildProcess | null;
18
+ port: number;
19
+ baseUrl: string;
20
+ stop: () => Promise<void>;
21
+ }
22
+ /**
23
+ * Unified interface to start any framework's dev server
24
+ */
25
+ export declare function startDevServer(options?: DevServerOptions): Promise<DevServer>;
26
+ /**
27
+ * Unified interface to wait for hydration
28
+ */
29
+ export declare function waitForHydration(page: Page, framework?: FrameworkName, timeout?: number): Promise<void>;
30
+ /**
31
+ * Get routes for the detected framework
32
+ */
33
+ export declare function getRoutes(framework?: FrameworkName, projectPath?: string): string[];
34
+ /**
35
+ * Framework information for display
36
+ */
37
+ export declare function getFrameworkInfo(projectPath?: string): {
38
+ name: FrameworkName;
39
+ version: string | null;
40
+ displayName: string;
41
+ needsHydration: boolean;
42
+ defaultPort: number;
43
+ };
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/frameworks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChF,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAmD,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAKpG,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,SAAS,CAAC,CAwDvF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,SAAS,CAAC,EAAE,aAAa,EACzB,OAAO,SAAQ,GACd,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAenF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG;IACtD,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB,CAsBA"}
@@ -0,0 +1,138 @@
1
+ // Re-export all framework utilities
2
+ export { detectFramework, needsHydration, getDefaultPort } from './detector.js';
3
+ export * as next from './next.js';
4
+ export * as sveltekit from './sveltekit.js';
5
+ export * as vite from './vite.js';
6
+ // Import for unified interface
7
+ import { detectFramework, getDefaultPort, needsHydration } from './detector.js';
8
+ import * as next from './next.js';
9
+ import * as sveltekit from './sveltekit.js';
10
+ import * as vite from './vite.js';
11
+ /**
12
+ * Unified interface to start any framework's dev server
13
+ */
14
+ export async function startDevServer(options = {}) {
15
+ const projectPath = options.projectPath || process.cwd();
16
+ const detected = detectFramework(projectPath);
17
+ const framework = options.framework || detected.name;
18
+ const port = options.port || getDefaultPort(framework);
19
+ switch (framework) {
20
+ case 'nextjs': {
21
+ const server = await next.startNextServer({ port, projectPath });
22
+ return {
23
+ framework,
24
+ process: server.process,
25
+ port: server.port,
26
+ baseUrl: server.baseUrl,
27
+ stop: server.stop,
28
+ };
29
+ }
30
+ case 'sveltekit': {
31
+ const server = await sveltekit.startSvelteKitServer({
32
+ port,
33
+ projectPath,
34
+ host: options.host,
35
+ });
36
+ return {
37
+ framework,
38
+ process: server.process,
39
+ port: server.port,
40
+ baseUrl: server.baseUrl,
41
+ stop: server.stop,
42
+ };
43
+ }
44
+ case 'vite':
45
+ case 'create-react-app':
46
+ case 'remix':
47
+ case 'astro':
48
+ case 'nuxt': {
49
+ // These all use Vite or similar dev servers
50
+ const server = await vite.startViteServer({
51
+ port,
52
+ projectPath,
53
+ host: options.host,
54
+ });
55
+ return {
56
+ framework,
57
+ process: server.process,
58
+ port: server.port,
59
+ baseUrl: server.baseUrl,
60
+ stop: server.stop,
61
+ };
62
+ }
63
+ default:
64
+ throw new Error(`Unknown framework: ${framework}. Cannot start dev server.`);
65
+ }
66
+ }
67
+ /**
68
+ * Unified interface to wait for hydration
69
+ */
70
+ export async function waitForHydration(page, framework, timeout = 10000) {
71
+ const projectPath = process.cwd();
72
+ const detected = detectFramework(projectPath);
73
+ const fw = framework || detected.name;
74
+ if (!needsHydration(fw)) {
75
+ // For static sites or unknown frameworks, just wait for load
76
+ await page.waitForFunction(() => document.readyState === 'complete' || document.readyState === 'interactive');
77
+ return;
78
+ }
79
+ switch (fw) {
80
+ case 'nextjs':
81
+ await next.waitForHydration(page, timeout);
82
+ break;
83
+ case 'sveltekit':
84
+ await sveltekit.waitForHydration(page, timeout);
85
+ break;
86
+ case 'vite':
87
+ case 'create-react-app':
88
+ case 'remix':
89
+ case 'astro':
90
+ case 'nuxt':
91
+ await vite.waitForHydration(page, timeout);
92
+ break;
93
+ default:
94
+ // Fallback: wait for document ready
95
+ await page.waitForFunction(() => document.readyState === 'complete' || document.readyState === 'interactive');
96
+ }
97
+ }
98
+ /**
99
+ * Get routes for the detected framework
100
+ */
101
+ export function getRoutes(framework, projectPath) {
102
+ const path = projectPath || process.cwd();
103
+ const detected = detectFramework(path);
104
+ const fw = framework || detected.name;
105
+ switch (fw) {
106
+ case 'nextjs':
107
+ return next.getRoutes(path);
108
+ case 'sveltekit':
109
+ return sveltekit.getRoutes(path);
110
+ default:
111
+ return ['/'];
112
+ }
113
+ }
114
+ /**
115
+ * Framework information for display
116
+ */
117
+ export function getFrameworkInfo(projectPath) {
118
+ const path = projectPath || process.cwd();
119
+ const detected = detectFramework(path);
120
+ const displayNames = {
121
+ nextjs: 'Next.js',
122
+ sveltekit: 'SvelteKit',
123
+ vite: 'Vite',
124
+ 'create-react-app': 'Create React App',
125
+ remix: 'Remix',
126
+ astro: 'Astro',
127
+ nuxt: 'Nuxt',
128
+ unknown: 'Unknown',
129
+ };
130
+ return {
131
+ name: detected.name,
132
+ version: detected.version,
133
+ displayName: displayNames[detected.name],
134
+ needsHydration: needsHydration(detected.name),
135
+ defaultPort: getDefaultPort(detected.name),
136
+ };
137
+ }
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/frameworks/index.ts"],"names":[],"mappings":"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"}