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
@@ -0,0 +1,34 @@
1
+ import type { Page } from 'puppeteer-core';
2
+ import type { ChildProcess } from 'node:child_process';
3
+ export interface NextServerOptions {
4
+ port?: number;
5
+ projectPath?: string;
6
+ turbo?: boolean;
7
+ }
8
+ export interface NextServer {
9
+ process: ChildProcess;
10
+ port: number;
11
+ baseUrl: string;
12
+ stop: () => Promise<void>;
13
+ }
14
+ /**
15
+ * Start Next.js dev server if not already running
16
+ */
17
+ export declare function startNextServer(options?: NextServerOptions): Promise<NextServer>;
18
+ /**
19
+ * Wait for Next.js hydration to complete
20
+ */
21
+ export declare function waitForHydration(page: Page, timeout?: number): Promise<void>;
22
+ /**
23
+ * Handle next/image lazy loading by scrolling to trigger loads
24
+ */
25
+ export declare function loadLazyImages(page: Page): Promise<void>;
26
+ /**
27
+ * Determine the route type (App Router vs Pages Router)
28
+ */
29
+ export declare function detectRouterType(projectPath?: string): 'app' | 'pages' | 'both' | 'unknown';
30
+ /**
31
+ * Get all routes from Next.js project
32
+ */
33
+ export declare function getRoutes(projectPath?: string): string[];
34
+ //# sourceMappingURL=next.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../src/frameworks/next.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiD1F;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BjF;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB9D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,GAAE,MAAsB,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAc1G;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,WAAW,GAAE,MAAsB,GAAG,MAAM,EAAE,CASvE"}
@@ -0,0 +1,160 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ /**
5
+ * Start Next.js dev server if not already running
6
+ */
7
+ export async function startNextServer(options = {}) {
8
+ const { port = 3000, projectPath = process.cwd(), turbo = false } = options;
9
+ // Check if already running
10
+ const isRunning = await checkServerRunning(port);
11
+ if (isRunning) {
12
+ return {
13
+ process: null,
14
+ port,
15
+ baseUrl: `http://localhost:${port}`,
16
+ stop: async () => {
17
+ // Server was already running, don't stop it
18
+ },
19
+ };
20
+ }
21
+ // Determine if using npm, yarn, or pnpm
22
+ const packageManager = detectPackageManager(projectPath);
23
+ const args = ['run', 'dev'];
24
+ if (turbo) {
25
+ args.push('--turbo');
26
+ }
27
+ args.push('--port', port.toString());
28
+ const serverProcess = spawn(packageManager, args, {
29
+ cwd: projectPath,
30
+ stdio: ['ignore', 'pipe', 'pipe'],
31
+ shell: true,
32
+ });
33
+ // Wait for server to be ready
34
+ await waitForServer(port, 30000);
35
+ return {
36
+ process: serverProcess,
37
+ port,
38
+ baseUrl: `http://localhost:${port}`,
39
+ stop: async () => {
40
+ if (serverProcess && !serverProcess.killed) {
41
+ serverProcess.kill('SIGTERM');
42
+ // Give it time to shut down gracefully
43
+ await new Promise((resolve) => setTimeout(resolve, 1000));
44
+ if (!serverProcess.killed) {
45
+ serverProcess.kill('SIGKILL');
46
+ }
47
+ }
48
+ },
49
+ };
50
+ }
51
+ /**
52
+ * Wait for Next.js hydration to complete
53
+ */
54
+ export async function waitForHydration(page, timeout = 10000) {
55
+ // Next.js sets __NEXT_DATA__ when hydration is complete
56
+ // For App Router, we check for the root layout being hydrated
57
+ await page.waitForFunction(() => {
58
+ // Check for Pages Router hydration
59
+ const nextData = document.getElementById('__NEXT_DATA__');
60
+ if (nextData) {
61
+ // Pages Router: check if React has hydrated
62
+ const root = document.getElementById('__next');
63
+ if (root && root.hasChildNodes()) {
64
+ return true;
65
+ }
66
+ }
67
+ // Check for App Router hydration
68
+ // App Router uses a different hydration mechanism
69
+ const html = document.documentElement;
70
+ if (html.hasAttribute('data-nextjs-router')) {
71
+ return true;
72
+ }
73
+ // Alternative: check if any React root has been hydrated
74
+ // React 18 sets __reactContainer$ prefix on hydrated elements
75
+ const body = document.body;
76
+ const keys = Object.keys(body);
77
+ return keys.some((key) => key.startsWith('__reactFiber$') || key.startsWith('__reactContainer$'));
78
+ }, { timeout });
79
+ }
80
+ /**
81
+ * Handle next/image lazy loading by scrolling to trigger loads
82
+ */
83
+ export async function loadLazyImages(page) {
84
+ // Get all lazy images
85
+ const lazyImages = await page.$$('img[loading="lazy"], img[data-nimg]');
86
+ for (const img of lazyImages) {
87
+ // Scroll image into view to trigger loading
88
+ await img.evaluate((el) => el.scrollIntoView());
89
+ // Small delay to allow image to start loading
90
+ await new Promise(r => setTimeout(r, 100));
91
+ }
92
+ // Wait for all images to load
93
+ await page.waitForFunction(() => {
94
+ const images = document.querySelectorAll('img');
95
+ return Array.from(images).every((img) => img.complete);
96
+ });
97
+ }
98
+ /**
99
+ * Determine the route type (App Router vs Pages Router)
100
+ */
101
+ export function detectRouterType(projectPath = process.cwd()) {
102
+ const hasAppDir = existsSync(join(projectPath, 'app')) || existsSync(join(projectPath, 'src', 'app'));
103
+ const hasPagesDir = existsSync(join(projectPath, 'pages')) || existsSync(join(projectPath, 'src', 'pages'));
104
+ if (hasAppDir && hasPagesDir) {
105
+ return 'both';
106
+ }
107
+ if (hasAppDir) {
108
+ return 'app';
109
+ }
110
+ if (hasPagesDir) {
111
+ return 'pages';
112
+ }
113
+ return 'unknown';
114
+ }
115
+ /**
116
+ * Get all routes from Next.js project
117
+ */
118
+ export function getRoutes(projectPath = process.cwd()) {
119
+ const routes = ['/'];
120
+ const routerType = detectRouterType(projectPath);
121
+ // This is a simplified implementation
122
+ // A full implementation would parse the file system to find all routes
123
+ // For now, return just the index route
124
+ return routes;
125
+ }
126
+ async function checkServerRunning(port) {
127
+ try {
128
+ const response = await fetch(`http://localhost:${port}`, {
129
+ method: 'HEAD',
130
+ });
131
+ return response.ok || response.status < 500;
132
+ }
133
+ catch {
134
+ return false;
135
+ }
136
+ }
137
+ async function waitForServer(port, timeout) {
138
+ const startTime = Date.now();
139
+ while (Date.now() - startTime < timeout) {
140
+ const isRunning = await checkServerRunning(port);
141
+ if (isRunning) {
142
+ return;
143
+ }
144
+ await new Promise((resolve) => setTimeout(resolve, 500));
145
+ }
146
+ throw new Error(`Server did not start within ${timeout}ms`);
147
+ }
148
+ function detectPackageManager(projectPath) {
149
+ if (existsSync(join(projectPath, 'pnpm-lock.yaml'))) {
150
+ return 'pnpm';
151
+ }
152
+ if (existsSync(join(projectPath, 'yarn.lock'))) {
153
+ return 'yarn';
154
+ }
155
+ if (existsSync(join(projectPath, 'bun.lockb'))) {
156
+ return 'bun';
157
+ }
158
+ return 'npm';
159
+ }
160
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","sourceRoot":"","sources":["../../src/frameworks/next.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { Page } from 'puppeteer-core';
2
+ import type { ChildProcess } from 'node:child_process';
3
+ export interface SvelteKitServerOptions {
4
+ port?: number;
5
+ projectPath?: string;
6
+ host?: string;
7
+ }
8
+ export interface SvelteKitServer {
9
+ process: ChildProcess;
10
+ port: number;
11
+ baseUrl: string;
12
+ stop: () => Promise<void>;
13
+ }
14
+ /**
15
+ * Start SvelteKit dev server (uses Vite under the hood)
16
+ */
17
+ export declare function startSvelteKitServer(options?: SvelteKitServerOptions): Promise<SvelteKitServer>;
18
+ /**
19
+ * Wait for SvelteKit hydration to complete
20
+ */
21
+ export declare function waitForHydration(page: Page, timeout?: number): Promise<void>;
22
+ /**
23
+ * Handle SvelteKit routing - wait for navigation to complete
24
+ */
25
+ export declare function waitForNavigation(page: Page, timeout?: number): Promise<void>;
26
+ /**
27
+ * Get routes from SvelteKit project by scanning the routes directory
28
+ */
29
+ export declare function getRoutes(projectPath?: string): string[];
30
+ /**
31
+ * Detect if SvelteKit is using SSR or SPA mode
32
+ */
33
+ export declare function detectRenderMode(projectPath?: string): 'ssr' | 'spa' | 'static';
34
+ //# sourceMappingURL=sveltekit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sveltekit.d.ts","sourceRoot":"","sources":["../../src/frameworks/sveltekit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,eAAe,CAAC,CA+CzG;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BjF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjF;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,WAAW,GAAE,MAAsB,GAAG,MAAM,EAAE,CAevE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,GAAE,MAAsB,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAa9F"}
@@ -0,0 +1,150 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ /**
5
+ * Start SvelteKit dev server (uses Vite under the hood)
6
+ */
7
+ export async function startSvelteKitServer(options = {}) {
8
+ const { port = 5173, projectPath = process.cwd(), host = 'localhost' } = options;
9
+ // Check if already running
10
+ const isRunning = await checkServerRunning(port);
11
+ if (isRunning) {
12
+ return {
13
+ process: null,
14
+ port,
15
+ baseUrl: `http://${host}:${port}`,
16
+ stop: async () => {
17
+ // Server was already running, don't stop it
18
+ },
19
+ };
20
+ }
21
+ // Determine package manager
22
+ const packageManager = detectPackageManager(projectPath);
23
+ const args = ['run', 'dev', '--port', port.toString()];
24
+ if (host !== 'localhost') {
25
+ args.push('--host', host);
26
+ }
27
+ const serverProcess = spawn(packageManager, args, {
28
+ cwd: projectPath,
29
+ stdio: ['ignore', 'pipe', 'pipe'],
30
+ shell: true,
31
+ });
32
+ // Wait for server to be ready
33
+ await waitForServer(port, 30000);
34
+ return {
35
+ process: serverProcess,
36
+ port,
37
+ baseUrl: `http://${host}:${port}`,
38
+ stop: async () => {
39
+ if (serverProcess && !serverProcess.killed) {
40
+ serverProcess.kill('SIGTERM');
41
+ await new Promise((resolve) => setTimeout(resolve, 1000));
42
+ if (!serverProcess.killed) {
43
+ serverProcess.kill('SIGKILL');
44
+ }
45
+ }
46
+ },
47
+ };
48
+ }
49
+ /**
50
+ * Wait for SvelteKit hydration to complete
51
+ */
52
+ export async function waitForHydration(page, timeout = 10000) {
53
+ // SvelteKit marks the document as hydrated when client-side JS takes over
54
+ await page.waitForFunction(() => {
55
+ // Check for Svelte component markers
56
+ // Svelte adds data-svelte-h attribute during hydration
57
+ const root = document.body;
58
+ if (!root)
59
+ return false;
60
+ // Check if Svelte has initialized by looking for internal markers
61
+ // or by checking if the app container has been hydrated
62
+ const svelteMarkers = document.querySelectorAll('[data-sveltekit-hydrate]');
63
+ if (svelteMarkers.length > 0) {
64
+ return true;
65
+ }
66
+ // Alternative: check for Svelte's internal component references
67
+ const keys = Object.keys(root);
68
+ const hasSvelteComponent = keys.some((key) => key.startsWith('__svelte') || key.includes('$$'));
69
+ if (hasSvelteComponent) {
70
+ return true;
71
+ }
72
+ // Fallback: check if the page has loaded and there's content
73
+ return document.readyState === 'complete' && root.innerHTML.trim().length > 0;
74
+ }, { timeout });
75
+ }
76
+ /**
77
+ * Handle SvelteKit routing - wait for navigation to complete
78
+ */
79
+ export async function waitForNavigation(page, timeout = 5000) {
80
+ // SvelteKit uses client-side navigation
81
+ // Wait for the navigation to complete by checking network idle and DOM stability
82
+ await Promise.race([
83
+ page.waitForNetworkIdle({ idleTime: 500 }),
84
+ new Promise(r => setTimeout(r, timeout)),
85
+ ]);
86
+ }
87
+ /**
88
+ * Get routes from SvelteKit project by scanning the routes directory
89
+ */
90
+ export function getRoutes(projectPath = process.cwd()) {
91
+ const routes = ['/'];
92
+ // SvelteKit routes are in src/routes
93
+ const routesDir = join(projectPath, 'src', 'routes');
94
+ if (!existsSync(routesDir)) {
95
+ return routes;
96
+ }
97
+ // This is a simplified implementation
98
+ // A full implementation would recursively scan the routes directory
99
+ // and parse +page.svelte files to extract routes
100
+ return routes;
101
+ }
102
+ /**
103
+ * Detect if SvelteKit is using SSR or SPA mode
104
+ */
105
+ export function detectRenderMode(projectPath = process.cwd()) {
106
+ const svelteConfigPath = join(projectPath, 'svelte.config.js');
107
+ if (!existsSync(svelteConfigPath)) {
108
+ return 'ssr'; // Default is SSR
109
+ }
110
+ // A full implementation would parse the config to detect:
111
+ // - adapter-static for static/SPA
112
+ // - adapter-node/adapter-auto for SSR
113
+ // For now, assume SSR as it's the default
114
+ return 'ssr';
115
+ }
116
+ async function checkServerRunning(port) {
117
+ try {
118
+ const response = await fetch(`http://localhost:${port}`, {
119
+ method: 'HEAD',
120
+ });
121
+ return response.ok || response.status < 500;
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
127
+ async function waitForServer(port, timeout) {
128
+ const startTime = Date.now();
129
+ while (Date.now() - startTime < timeout) {
130
+ const isRunning = await checkServerRunning(port);
131
+ if (isRunning) {
132
+ return;
133
+ }
134
+ await new Promise((resolve) => setTimeout(resolve, 500));
135
+ }
136
+ throw new Error(`Server did not start within ${timeout}ms`);
137
+ }
138
+ function detectPackageManager(projectPath) {
139
+ if (existsSync(join(projectPath, 'pnpm-lock.yaml'))) {
140
+ return 'pnpm';
141
+ }
142
+ if (existsSync(join(projectPath, 'yarn.lock'))) {
143
+ return 'yarn';
144
+ }
145
+ if (existsSync(join(projectPath, 'bun.lockb'))) {
146
+ return 'bun';
147
+ }
148
+ return 'npm';
149
+ }
150
+ //# sourceMappingURL=sveltekit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sveltekit.js","sourceRoot":"","sources":["../../src/frameworks/sveltekit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { Page } from 'puppeteer-core';
2
+ import type { ChildProcess } from 'node:child_process';
3
+ export interface ViteServerOptions {
4
+ port?: number;
5
+ projectPath?: string;
6
+ host?: string;
7
+ mode?: 'development' | 'production';
8
+ }
9
+ export interface ViteServer {
10
+ process: ChildProcess;
11
+ port: number;
12
+ baseUrl: string;
13
+ stop: () => Promise<void>;
14
+ }
15
+ export interface ViteConfig {
16
+ port?: number;
17
+ host?: string | boolean;
18
+ base?: string;
19
+ }
20
+ /**
21
+ * Start Vite dev server
22
+ */
23
+ export declare function startViteServer(options?: ViteServerOptions): Promise<ViteServer>;
24
+ /**
25
+ * Wait for Vite app hydration (React, Vue, etc.)
26
+ */
27
+ export declare function waitForHydration(page: Page, timeout?: number): Promise<void>;
28
+ /**
29
+ * Detect port from Vite config file
30
+ */
31
+ export declare function detectPortFromConfig(projectPath?: string): number | null;
32
+ /**
33
+ * Detect the base path from Vite config
34
+ */
35
+ export declare function detectBasePath(projectPath?: string): string;
36
+ /**
37
+ * Detect what framework Vite is being used with
38
+ */
39
+ export declare function detectViteFramework(projectPath?: string): 'react' | 'vue' | 'svelte' | 'preact' | 'solid' | 'vanilla' | 'unknown';
40
+ //# sourceMappingURL=vite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../../src/frameworks/vite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAoD1F;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CjF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CA0BvF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,GAAE,MAAsB,GAAG,MAAM,CAuB1E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,GAAE,MAAsB,GAClC,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CA+BzE"}
@@ -0,0 +1,211 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ /**
5
+ * Start Vite dev server
6
+ */
7
+ export async function startViteServer(options = {}) {
8
+ const projectPath = options.projectPath || process.cwd();
9
+ // Try to detect port from config if not specified
10
+ const configPort = detectPortFromConfig(projectPath);
11
+ const port = options.port || configPort || 5173;
12
+ const host = options.host || 'localhost';
13
+ // Check if already running
14
+ const isRunning = await checkServerRunning(port);
15
+ if (isRunning) {
16
+ return {
17
+ process: null,
18
+ port,
19
+ baseUrl: `http://${host}:${port}`,
20
+ stop: async () => {
21
+ // Server was already running, don't stop it
22
+ },
23
+ };
24
+ }
25
+ // Determine package manager
26
+ const packageManager = detectPackageManager(projectPath);
27
+ const args = ['run', 'dev', '--port', port.toString()];
28
+ if (host !== 'localhost') {
29
+ args.push('--host', host);
30
+ }
31
+ const serverProcess = spawn(packageManager, args, {
32
+ cwd: projectPath,
33
+ stdio: ['ignore', 'pipe', 'pipe'],
34
+ shell: true,
35
+ });
36
+ // Wait for server to be ready
37
+ await waitForServer(port, 30000);
38
+ return {
39
+ process: serverProcess,
40
+ port,
41
+ baseUrl: `http://${host}:${port}`,
42
+ stop: async () => {
43
+ if (serverProcess && !serverProcess.killed) {
44
+ serverProcess.kill('SIGTERM');
45
+ await new Promise((resolve) => setTimeout(resolve, 1000));
46
+ if (!serverProcess.killed) {
47
+ serverProcess.kill('SIGKILL');
48
+ }
49
+ }
50
+ },
51
+ };
52
+ }
53
+ /**
54
+ * Wait for Vite app hydration (React, Vue, etc.)
55
+ */
56
+ export async function waitForHydration(page, timeout = 10000) {
57
+ await page.waitForFunction(() => {
58
+ // Check for React hydration
59
+ const reactRoot = document.getElementById('root') || document.getElementById('app');
60
+ if (reactRoot) {
61
+ const keys = Object.keys(reactRoot);
62
+ const hasReact = keys.some((key) => key.startsWith('__reactFiber$') || key.startsWith('__reactContainer$'));
63
+ if (hasReact)
64
+ return true;
65
+ }
66
+ // Check for Vue hydration
67
+ const vueApp = document.querySelector('[data-v-app]') || document.getElementById('app');
68
+ if (vueApp) {
69
+ const keys = Object.keys(vueApp);
70
+ const hasVue = keys.some((key) => key.startsWith('__vue'));
71
+ if (hasVue)
72
+ return true;
73
+ }
74
+ // Check for Preact
75
+ const preactRoot = document.getElementById('root') || document.getElementById('app');
76
+ if (preactRoot) {
77
+ const keys = Object.keys(preactRoot);
78
+ const hasPreact = keys.some((key) => key.includes('__preact'));
79
+ if (hasPreact)
80
+ return true;
81
+ }
82
+ // Check for Solid.js
83
+ const solidRoot = document.getElementById('root') || document.getElementById('app');
84
+ if (solidRoot) {
85
+ const keys = Object.keys(solidRoot);
86
+ const hasSolid = keys.some((key) => key.includes('__solid'));
87
+ if (hasSolid)
88
+ return true;
89
+ }
90
+ // Fallback: document is ready and has content
91
+ return document.readyState === 'complete' && document.body.innerHTML.trim().length > 0;
92
+ }, { timeout });
93
+ }
94
+ /**
95
+ * Detect port from Vite config file
96
+ */
97
+ export function detectPortFromConfig(projectPath = process.cwd()) {
98
+ const configFiles = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];
99
+ for (const configFile of configFiles) {
100
+ const configPath = join(projectPath, configFile);
101
+ if (!existsSync(configPath)) {
102
+ continue;
103
+ }
104
+ try {
105
+ const content = readFileSync(configPath, 'utf-8');
106
+ // Simple regex to extract port from config
107
+ // This handles common patterns like:
108
+ // server: { port: 3000 }
109
+ // server: { port: process.env.PORT || 3000 }
110
+ const portMatch = content.match(/server\s*:\s*\{[^}]*port\s*:\s*(\d+)/);
111
+ if (portMatch) {
112
+ return parseInt(portMatch[1], 10);
113
+ }
114
+ }
115
+ catch {
116
+ // Ignore parse errors
117
+ }
118
+ }
119
+ return null;
120
+ }
121
+ /**
122
+ * Detect the base path from Vite config
123
+ */
124
+ export function detectBasePath(projectPath = process.cwd()) {
125
+ const configFiles = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];
126
+ for (const configFile of configFiles) {
127
+ const configPath = join(projectPath, configFile);
128
+ if (!existsSync(configPath)) {
129
+ continue;
130
+ }
131
+ try {
132
+ const content = readFileSync(configPath, 'utf-8');
133
+ // Simple regex to extract base from config
134
+ const baseMatch = content.match(/base\s*:\s*['"]([^'"]+)['"]/);
135
+ if (baseMatch) {
136
+ return baseMatch[1];
137
+ }
138
+ }
139
+ catch {
140
+ // Ignore parse errors
141
+ }
142
+ }
143
+ return '/';
144
+ }
145
+ /**
146
+ * Detect what framework Vite is being used with
147
+ */
148
+ export function detectViteFramework(projectPath = process.cwd()) {
149
+ const packageJsonPath = join(projectPath, 'package.json');
150
+ if (!existsSync(packageJsonPath)) {
151
+ return 'unknown';
152
+ }
153
+ try {
154
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
155
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
156
+ if (deps['react'] || deps['@vitejs/plugin-react']) {
157
+ return 'react';
158
+ }
159
+ if (deps['vue'] || deps['@vitejs/plugin-vue']) {
160
+ return 'vue';
161
+ }
162
+ if (deps['svelte'] || deps['@sveltejs/vite-plugin-svelte']) {
163
+ return 'svelte';
164
+ }
165
+ if (deps['preact'] || deps['@preact/preset-vite']) {
166
+ return 'preact';
167
+ }
168
+ if (deps['solid-js'] || deps['vite-plugin-solid']) {
169
+ return 'solid';
170
+ }
171
+ return 'vanilla';
172
+ }
173
+ catch {
174
+ return 'unknown';
175
+ }
176
+ }
177
+ async function checkServerRunning(port) {
178
+ try {
179
+ const response = await fetch(`http://localhost:${port}`, {
180
+ method: 'HEAD',
181
+ });
182
+ return response.ok || response.status < 500;
183
+ }
184
+ catch {
185
+ return false;
186
+ }
187
+ }
188
+ async function waitForServer(port, timeout) {
189
+ const startTime = Date.now();
190
+ while (Date.now() - startTime < timeout) {
191
+ const isRunning = await checkServerRunning(port);
192
+ if (isRunning) {
193
+ return;
194
+ }
195
+ await new Promise((resolve) => setTimeout(resolve, 500));
196
+ }
197
+ throw new Error(`Server did not start within ${timeout}ms`);
198
+ }
199
+ function detectPackageManager(projectPath) {
200
+ if (existsSync(join(projectPath, 'pnpm-lock.yaml'))) {
201
+ return 'pnpm';
202
+ }
203
+ if (existsSync(join(projectPath, 'yarn.lock'))) {
204
+ return 'yarn';
205
+ }
206
+ if (existsSync(join(projectPath, 'bun.lockb'))) {
207
+ return 'bun';
208
+ }
209
+ return 'npm';
210
+ }
211
+ //# sourceMappingURL=vite.js.map