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.
- package/README.md +220 -0
- package/dist/browser.d.ts +8 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +122 -0
- package/dist/browser.js.map +1 -0
- package/dist/checks/clickability.d.ts +3 -0
- package/dist/checks/clickability.d.ts.map +1 -0
- package/dist/checks/clickability.js +125 -0
- package/dist/checks/clickability.js.map +1 -0
- package/dist/checks/index.d.ts +9 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +27 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/checks/overflow.d.ts +3 -0
- package/dist/checks/overflow.d.ts.map +1 -0
- package/dist/checks/overflow.js +107 -0
- package/dist/checks/overflow.js.map +1 -0
- package/dist/checks/text-overflow.d.ts +3 -0
- package/dist/checks/text-overflow.d.ts.map +1 -0
- package/dist/checks/text-overflow.js +136 -0
- package/dist/checks/text-overflow.js.map +1 -0
- package/dist/checks/touch-targets.d.ts +3 -0
- package/dist/checks/touch-targets.d.ts.map +1 -0
- package/dist/checks/touch-targets.js +118 -0
- package/dist/checks/touch-targets.js.map +1 -0
- package/dist/checks/visibility.d.ts +3 -0
- package/dist/checks/visibility.d.ts.map +1 -0
- package/dist/checks/visibility.js +132 -0
- package/dist/checks/visibility.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +270 -0
- package/dist/cli.js.map +1 -0
- package/dist/frameworks/detector.d.ts +19 -0
- package/dist/frameworks/detector.d.ts.map +1 -0
- package/dist/frameworks/detector.js +132 -0
- package/dist/frameworks/detector.js.map +1 -0
- package/dist/frameworks/index.d.ts +44 -0
- package/dist/frameworks/index.d.ts.map +1 -0
- package/dist/frameworks/index.js +138 -0
- package/dist/frameworks/index.js.map +1 -0
- package/dist/frameworks/next.d.ts +34 -0
- package/dist/frameworks/next.d.ts.map +1 -0
- package/dist/frameworks/next.js +160 -0
- package/dist/frameworks/next.js.map +1 -0
- package/dist/frameworks/sveltekit.d.ts +34 -0
- package/dist/frameworks/sveltekit.d.ts.map +1 -0
- package/dist/frameworks/sveltekit.js +150 -0
- package/dist/frameworks/sveltekit.js.map +1 -0
- package/dist/frameworks/vite.d.ts +40 -0
- package/dist/frameworks/vite.d.ts.map +1 -0
- package/dist/frameworks/vite.js +211 -0
- package/dist/frameworks/vite.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +402 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/reporter.d.ts +4 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +103 -0
- package/dist/reporter.js.map +1 -0
- package/dist/runner.d.ts +8 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +63 -0
- package/dist/runner.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- 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":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAejC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAA6B,EAAE;IACnE,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAE5E,2BAA2B;IAC3B,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO;YACL,OAAO,EAAE,IAA+B;YACxC,IAAI;YACJ,OAAO,EAAE,oBAAoB,IAAI,EAAE;YACnC,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,4CAA4C;YAC9C,CAAC;SACF,CAAC;IACJ,CAAC;IAED,wCAAwC;IACxC,MAAM,cAAc,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAEzD,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC5B,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAErC,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE;QAChD,GAAG,EAAE,WAAW;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QACjC,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,8BAA8B;IAC9B,MAAM,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAEjC,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,IAAI;QACJ,OAAO,EAAE,oBAAoB,IAAI,EAAE;QACnC,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,IAAI,aAAa,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;gBAC3C,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC9B,uCAAuC;gBACvC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC1D,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;oBAC1B,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAU,EAAE,OAAO,GAAG,KAAK;IAChE,wDAAwD;IACxD,8DAA8D;IAC9D,MAAM,IAAI,CAAC,eAAe,CACxB,GAAG,EAAE;QACH,mCAAmC;QACnC,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACb,4CAA4C;YAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC/C,IAAI,IAAI,IAAI,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,iCAAiC;QACjC,kDAAkD;QAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,eAAe,CAAC;QACtC,IAAI,IAAI,CAAC,YAAY,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,yDAAyD;QACzD,8DAA8D;QAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC;IACpG,CAAC,EACD,EAAE,OAAO,EAAE,CACZ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAU;IAC7C,sBAAsB;IACtB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,qCAAqC,CAAC,CAAC;IAExE,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,4CAA4C;QAC5C,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAW,EAAE,EAAE,CAAC,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QACzD,8CAA8C;QAC9C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,8BAA8B;IAC9B,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE;QAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAChD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAsB,OAAO,CAAC,GAAG,EAAE;IAClE,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACtG,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAE5G,IAAI,SAAS,IAAI,WAAW,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,cAAsB,OAAO,CAAC,GAAG,EAAE;IAC3D,MAAM,MAAM,GAAa,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,UAAU,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAEjD,sCAAsC;IACtC,uEAAuE;IACvE,uCAAuC;IAEvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,IAAY;IAC5C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,EAAE,EAAE;YACvD,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,OAAe;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,SAAS,EAAE,CAAC;YACd,OAAO;QACT,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,+BAA+B,OAAO,IAAI,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,oBAAoB,CAAC,WAAmB;IAC/C,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -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
|