Skip to content

Commit fb2a7e4

Browse files
committed
feat: add nodejs extension interop, http server URL resolution, internalVars, PHPResponse header/cookie lifecycle, and set_error_handler support
1 parent 85bbe84 commit fb2a7e4

65 files changed

Lines changed: 1953 additions & 174 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
node_modules/
22
tests/cache/
33
*.zip
4+
wordpress-test/
45
wordpress/
56
coverage/
67
.cache/
7-
tests/latest.zip
88
.idea/

‎AGENTS.md‎

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,40 @@
1-
# AI Agent Guidelines for `node-jsphp`
1+
# AI Agent Guidelines for `node-jsphp` (`@nexustools/php`)
22

3-
This document provides operational context and guidance for AI agents working on the `node-jsphp` codebase.
3+
This document provides operational context, architecture directives, and guidance for AI agents working on the `@nexustools/php` codebase.
44

55
## Core Directives
66

77
1. **Synchronous PHP / Asynchronous JS**:
8-
PHP code semantics appear synchronous to the PHP script, but generated JavaScript code MUST run asynchronously using `async/await` so Node.js can handle concurrent requests without blocking.
8+
PHP code semantics appear synchronous to the PHP script, but transpiled JavaScript code MUST run asynchronously using `async/await` so Node.js can handle concurrent execution without blocking the event loop.
99

10-
2. **Stack Trace Masking**:
11-
Never expose raw JavaScript execution stack frames to PHP. Standardize all stack traces in `PHPError` to reflect PHP line numbers or `[INTERNAL]`.
10+
2. **Stack Trace Virtualization**:
11+
Never expose raw JavaScript execution stack frames to PHP. Standardize all stack traces in `PHPError` to reflect PHP source line numbers or `[INTERNAL]`.
1212

1313
3. **No Build Output Directory for Sources**:
14-
TypeScript source files in `src/` must compile to JavaScript `.js` and declaration `.d.ts` files placed directly alongside their corresponding `.ts` sources. Do NOT use a `dist/` or `out/` folder.
14+
TypeScript source files in `src/` compile to JavaScript `.js` and declaration `.d.ts` files placed directly alongside their corresponding `.ts` sources. Do NOT use a `dist/` or `out/` folder.
1515

1616
4. **AST Optimization Rules**:
17-
Always ensure optimizer handles `extension_loaded(...)`, `defined(...)`, and boolean expressions at compile time. Eliminate unreachable `if` branches before generating JS output.
17+
Ensure `ASTOptimizer` optimizes `extension_loaded(...)`, `defined(...)`, `constant(...)`, constant references (`name` / `constref`), and boolean expressions at compile time. Eliminate dead `if` branches prior to code generation.
1818

19-
5. **WordPress & MySQL Compatibility**:
20-
Maintain full compatibility with WordPress database operations and standard themes.
19+
5. **CLI & Server Binaries**:
20+
- `php` (`bin/php.js`): Single-file CLI execution binary.
21+
- `php-fpm` (`bin/php-fpm.js`): FastCGI (FCGI 1.0) binary socket server for Nginx/Apache proxying.
22+
- `php-http-server` (`bin/php-http-server.js`): HTTP web server supporting static file serving and smart URL resolution (`/` -> `index.php`/`index.html`, `/test` -> `test.php`/`test.html`/`test/index.php`).
23+
24+
6. **Internal Variables (`internalVars`)**:
25+
`PHPEngine` and `PHPContext` maintain `internalVars` (`Map<string, any>`) that are invisible to PHP userland (`$GLOBALS`, `get_defined_vars()`, Reflection), but accessible to internal engine methods, AST optimization, and server handlers.
26+
27+
7. **Header & Response Lifecycle**:
28+
HTTP response functions (`header`, `setcookie`, `setrawcookie`, `header_remove`, `headers_list`, `headers_sent`, `http_response_code`) operate on `PHPResponse` attached to `PHPContext`. Calling header functions in CLI mode without a registered server response handler throws a `PHPWarning` / `PHPError`.
29+
30+
8. **Error Handling & `set_error_handler`**:
31+
Supports `set_error_handler`, `restore_error_handler`, `trigger_error`, `error_reporting`, and `ErrorException`. Errors thrown within PHP methods use subclasses of `PHPError` (`PHPFatalError`, `PHPWarning`, `PHPNotice`, `PHPTypeError`, etc.).
32+
33+
9. **Reflection Metadata & JS Source Fallback**:
34+
Function/method metadata is tracked via `.phpMeta` attached by `defineFunction`. If `.phpMeta` is absent, `ReflectionFunction` and `ReflectionMethod` fall back to parsing the function's JavaScript `.toString()` source declaration.
35+
36+
10. **Optional Node.js Interop (`nodejs` extension)**:
37+
Provides Node.js module/package loading (`nodejs_require`), global variable access (`nodejs_global`), eval (`nodejs_eval`), and instantiation (`nodejs_new` / `NodeJS` class) wrapped via `NodeJSObject`.
38+
39+
11. **WordPress & MySQL Compatibility**:
40+
Maintain full compatibility with WordPress database operations (`mysqli`), installation flows, and theme/admin dashboard rendering tested against a local MySQL database.

‎index.d.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
export { PHPEngine, PHPEngineOptions } from "./src/PHPEngine";
22
export { PHPContext, PHPContextOptions } from "./src/PHPContext";
33
export { PHPExtension } from "./src/PHPExtension";
4-
export { PHPError, PHPException, PHPTypeError, PHPParseError, PHPFatalError } from "./src/runtime/errors/PHPError";
4+
export { PHPError, PHPException, PHPTypeError, PHPParseError, PHPFatalError, PHPNotice, PHPWarning, ErrorException, } from "./src/runtime/errors/PHPError";
55
export { PHPObject, PHPClass, PHPMethodMetadata, PHPPropertyMetadata, PHPParameterMetadata } from "./src/runtime/objects/PHPObject";
66
export { Superglobals } from "./src/runtime/superglobals/Superglobals";
77
export { OutputBufferStack } from "./src/runtime/output/OutputBuffer";
88
export { PHPParser } from "./src/parser/PHPParser";
99
export { ASTOptimizer } from "./src/parser/ASTOptimizer";
1010
export { JSTranspiler } from "./src/parser/JSTranspiler";
11+
export { runHTTPServer } from "./src/cli/php-http-server";
12+
export { runFPM } from "./src/cli/php-fpm";
1113
export { defineFunction, FunctionMetaOptions, Reflection, ReflectionClass, ReflectionMethod, ReflectionProperty, ReflectionFunction, ReflectionParameter, ReflectionType, } from "./src/runtime/reflection/Reflection";
14+
export { NodeJSExtension, NodeJSObject, NodeJSService, wrapJSValue, unwrapPHPValue, } from "./src/extensions/nodejs/nodejs";

‎index.js‎

Lines changed: 14 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎index.js.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎index.ts‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
export { PHPEngine, PHPEngineOptions } from "./src/PHPEngine";
22
export { PHPContext, PHPContextOptions } from "./src/PHPContext";
33
export { PHPExtension } from "./src/PHPExtension";
4-
export { PHPError, PHPException, PHPTypeError, PHPParseError, PHPFatalError } from "./src/runtime/errors/PHPError";
4+
export {
5+
PHPError,
6+
PHPException,
7+
PHPTypeError,
8+
PHPParseError,
9+
PHPFatalError,
10+
PHPNotice,
11+
PHPWarning,
12+
ErrorException,
13+
} from "./src/runtime/errors/PHPError";
514
export { PHPObject, PHPClass, PHPMethodMetadata, PHPPropertyMetadata, PHPParameterMetadata } from "./src/runtime/objects/PHPObject";
615
export { Superglobals } from "./src/runtime/superglobals/Superglobals";
716
export { OutputBufferStack } from "./src/runtime/output/OutputBuffer";
817
export { PHPParser } from "./src/parser/PHPParser";
918
export { ASTOptimizer } from "./src/parser/ASTOptimizer";
1019
export { JSTranspiler } from "./src/parser/JSTranspiler";
20+
export { runHTTPServer } from "./src/cli/php-http-server";
21+
export { runFPM } from "./src/cli/php-fpm";
1122
export {
1223
defineFunction,
1324
FunctionMetaOptions,
@@ -19,3 +30,10 @@ export {
1930
ReflectionParameter,
2031
ReflectionType,
2132
} from "./src/runtime/reflection/Reflection";
33+
export {
34+
NodeJSExtension,
35+
NodeJSObject,
36+
NodeJSService,
37+
wrapJSValue,
38+
unwrapPHPValue,
39+
} from "./src/extensions/nodejs/nodejs";

‎src/PHPContext.d.ts‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,45 @@ export interface PHPContextOptions {
88
stdout?: Writable | ((data: string) => void);
99
stderr?: Writable | ((data: string) => void);
1010
superglobals?: SuperglobalsOptions;
11+
errorReporting?: number;
12+
}
13+
export declare class PHPResponse {
14+
statusCode: number;
15+
headers: {
16+
name: string;
17+
value: string;
18+
}[];
19+
headersSent: boolean;
20+
setHeader(name: string, value: string, replace?: boolean): void;
21+
removeHeader(name?: string): void;
22+
getHeader(name: string): string | undefined;
23+
getHeadersList(): string[];
24+
setCookie(name: string, value?: string, expires?: number, path?: string, domain?: string, secure?: boolean, httponly?: boolean, raw?: boolean): void;
1125
}
1226
export declare class PHPContext {
1327
engine: PHPEngine;
1428
cwd: string;
1529
env: Record<string, string>;
1630
vars: Record<string, any>;
31+
internalVars: Map<string, any>;
1732
superglobals: Superglobals;
1833
outputBuffer: OutputBufferStack;
34+
response: PHPResponse;
35+
errorHandlerStack: any[];
36+
errorReportingLevel: number;
1937
includedFiles: Set<string>;
2038
private stdout;
2139
private stderr;
2240
outputText: string;
2341
constructor(engine: PHPEngine, options?: PHPContextOptions);
42+
setErrorHandler(handler: any, levels?: number): any;
43+
restoreErrorHandler(): boolean;
44+
triggerError(message: string, level?: number, file?: string, line?: number): Promise<boolean>;
45+
getInternalVar(name: string): any;
46+
setInternalVar(name: string, value: any): void;
47+
get responseHeaders(): Record<string, string>;
48+
get statusCode(): number;
49+
flushHeaders(): void;
2450
echo(data: any): Promise<void>;
2551
private writeStdout;
2652
getConstant(name: string): any;

0 commit comments

Comments
 (0)