Skip to content

Commit 26a9975

Browse files
committed
Read files from VFS when a PHP instance is provided
1 parent 2b459e1 commit 26a9975

File tree

4 files changed

+55
-16
lines changed

4 files changed

+55
-16
lines changed

packages/php-wasm/xdebug-bridge/src/lib/start-bridge.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { logger } from '@php-wasm/logger';
2-
import type { PHP } from '@php-wasm/universal';
2+
import type { PHP, PHPWorker, RemoteAPI } from '@php-wasm/universal';
33
import { readdirSync, readFileSync, lstatSync } from 'fs';
44
import path from 'path';
55
import { CDPServer } from './cdp-server';
@@ -11,7 +11,7 @@ export type StartBridgeConfig = {
1111
cdpHost?: string;
1212
dbgpPort?: number;
1313
phpRoot?: string;
14-
phpInstance?: PHP;
14+
phpInstance?: PHP | RemoteAPI<PHPWorker>;
1515
getPHPFile?: (path: string) => string | Promise<string>;
1616
breakOnFirstLine?: boolean;
1717
};
@@ -44,17 +44,25 @@ export async function startBridge(config: StartBridgeConfig) {
4444
logger.log('Running a PHP script with Xdebug enabled...');
4545

4646
// Recursively get a list of .php files in phpRoot
47-
function getPhpFiles(dir: string): string[] {
47+
async function getPhpFiles(dir: string): Promise<string[]> {
4848
const results: string[] = [];
49-
const list = readdirSync(dir);
49+
const list = config.phpInstance
50+
? await config.phpInstance!.listFiles(dir)
51+
: readdirSync(dir);
5052
for (const file of list) {
5153
const filePath = path.join(dir, file);
52-
// lstat avoids crashes when encountering symlinks
53-
const stat = lstatSync(filePath);
54-
if (stat && stat.isDirectory()) {
55-
results.push(...getPhpFiles(filePath));
56-
} else if (file.endsWith('.php')) {
57-
results.push(filePath);
54+
try {
55+
// lstat avoids crashes when encountering symlinks
56+
const stat = config.phpInstance
57+
? await config.phpInstance!.isDir(filePath)
58+
: lstatSync(filePath).isDirectory();
59+
if (stat) {
60+
results.push(...(await getPhpFiles(filePath)));
61+
} else if (file.endsWith('.php')) {
62+
results.push(filePath);
63+
}
64+
} catch {
65+
// Skip this entry if we can't read it
5866
}
5967
}
6068
return results;
@@ -66,7 +74,7 @@ export async function startBridge(config: StartBridgeConfig) {
6674
? config.getPHPFile
6775
: (path: string) => readFileSync(path, 'utf-8');
6876

69-
const phpFiles = getPhpFiles(phpRoot);
77+
const phpFiles = await getPhpFiles(phpRoot);
7078
return new XdebugCDPBridge(dbgpSession, cdpServer, {
7179
knownScriptUrls: phpFiles,
7280
phpRoot,

packages/php-wasm/xdebug-bridge/src/lib/xdebug-cdp-bridge.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ export class XdebugCDPBridge {
7171
// Xdebug connected
7272
this.dbgp.on('connected', () => {
7373
this.xdebugConnected = true;
74-
this.sendDbgpCommand('stdout', '-c 1'); // copies PHP stdout to IDE
75-
this.sendDbgpCommand('stderr', '-c 1'); // copies PHP stderr to IDE
74+
this.sendDbgpCommand('stderr', '-c 1'); // copies PHP stderr to console
7675
});
7776
// Xdebug messages
7877
this.dbgp.on('message', async (xml: string) => {

packages/php-wasm/xdebug-bridge/src/tests/start-bridge.spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import './mocker';
22
import { type MockInstance, vi } from 'vitest';
33
import { WebSocket } from 'ws';
4-
import type { PHP } from '@php-wasm/universal';
4+
import { type PHP } from '@php-wasm/universal';
55
import { EventEmitter } from 'events';
66
import { CDPServer } from '../lib/cdp-server';
77
import { DbgpSession } from '../lib/dbgp-session';
@@ -89,6 +89,7 @@ describe('Bridge', () => {
8989

9090
it('uses phpInstance readFileAsText when provided', async () => {
9191
const php = {
92+
listFiles: vi.fn(() => []),
9293
readFileAsText: vi
9394
.fn()
9495
.mockResolvedValue('<?php echo "Hello World";'),
@@ -114,6 +115,37 @@ describe('Bridge', () => {
114115
expect(getPHPFile).toHaveBeenCalledWith('file:///custom.php');
115116
expect(result).toBe('<?php echo "Hello World";');
116117
});
118+
119+
it('reads PHP files from the filesystem when no phpInstance is provided', async () => {
120+
await startBridge({ phpRoot: '/foo/bar' });
121+
122+
const args = (XdebugCDPBridge as any).mock.calls[0][2];
123+
124+
expect(args.knownScriptUrls).toEqual(['/foo/bar/baz.php']);
125+
});
126+
127+
it('reads files from the virtual filesystem when a PHP instance is provided', async () => {
128+
const filesystem: Record<string, string[]> = {
129+
'/foo': ['bar.php', 'baz'],
130+
'/foo/baz': ['qux.php', 'quux.txt'],
131+
};
132+
133+
const php: Partial<PHP> = {
134+
listFiles: vi.fn(
135+
(directory: string) => filesystem[directory] || []
136+
),
137+
isDir: vi.fn((path: string) => path in filesystem),
138+
};
139+
140+
await startBridge({ phpInstance: php as PHP, phpRoot: '/foo' });
141+
142+
const args = (XdebugCDPBridge as any).mock.calls[0][2];
143+
144+
expect(args.knownScriptUrls).toEqual([
145+
'/foo/bar.php',
146+
'/foo/baz/qux.php',
147+
]);
148+
});
117149
});
118150

119151
describe('Log', () => {

packages/playground/cli/src/run-cli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,8 +745,8 @@ export async function runCLI(args: RunCLIArgs): Promise<RunCLIServer> {
745745

746746
if (args.experimentalDevtools && args.xdebug) {
747747
const bridge = await startBridge({
748-
getPHPFile: async (path: string) =>
749-
await playground!.readFileAsText(path),
748+
phpInstance: playground,
749+
phpRoot: '/wordpress',
750750
});
751751

752752
bridge.start();

0 commit comments

Comments
 (0)