From ce1c90dfbe449def2325f5437181980167f23051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20F?= Date: Sun, 29 Jun 2025 12:17:10 +0000 Subject: [PATCH] Add types --- doc/globals.d.ts | 14 +++ doc/os.d.ts | 290 +++++++++++++++++++++++++++++++++++++++++++++++ doc/std.d.ts | 279 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 583 insertions(+) create mode 100644 doc/globals.d.ts create mode 100644 doc/os.d.ts create mode 100644 doc/std.d.ts diff --git a/doc/globals.d.ts b/doc/globals.d.ts new file mode 100644 index 0000000..173768d --- /dev/null +++ b/doc/globals.d.ts @@ -0,0 +1,14 @@ +/** Command line arguments where argument[0] is the JS script name. */ +declare const scriptArgs: string[]; +/** Print args separated by spaces and a trailing newline. */ +declare function print(...args: any[]): void; + +declare const console: { + /** Print args separated by spaces and a trailing newline. */ + log: typeof print +}; + +interface ImportMeta { + url: string; + main: boolean; +} diff --git a/doc/os.d.ts b/doc/os.d.ts new file mode 100644 index 0000000..4a44430 --- /dev/null +++ b/doc/os.d.ts @@ -0,0 +1,290 @@ +/** + * Provides Operating System specific functions: + * file access, sockets, signals, timers, async I/O, workers (threads) + */ +declare module "os" { + type Success = 0; + type Errno = number; + type NegativeErrno = number; + type Result = T | NegativeErrno; + type ExitStatus = number; + type WaitStatus = number; + type Branded = T & { __brand: B }; // Prevent interchangeable primitives (e.g. number) + type OpenOption = Branded; + type SocketFamily = Branded; + type SocketType = Branded; + type SocketOpt = Branded; + type SocketShutOpt = Branded; + type PollOpt = Branded; + type PollRet = Branded; + type WaitpidOpt = Branded; + type FileDescriptor = Branded; + type Signal = Branded; + type StatMode = Branded; + type Pid = Branded; + type TimerHandle = Branded; + type Callback = () => void; + type Platform = "linux" | "darwin" | "win32" | "js"; + type WorkerMessage = any; + + interface ExecOptions { + /** + * Boolean (default = `true`). If `true`, wait until the process is + * terminated. In this case, exec return the exit code if positive or the + * negated signal number if the process was interrupted by a signal. If + * false, do not block and return the process id of the child. + */ + block?: boolean; + /** Is the file searched in the PATH @default true. */ + usePath?: boolean; + /** Set the file to be executed @default args[0] */ + file?: string, + /** The working directory of the new process */ + cwd?: string, + /** Handler for stdin */ + stdin?: FileDescriptor, + /** Handler for stdout */ + stdout?: FileDescriptor, + /** Handler for stderr */ + stderr?: FileDescriptor, + /** set the process environment from the object key-value pairs. + * If unset, it will inherit them from current process. */ + env?: { [key: string]: string }, + /** Process uid with `setuid` */ + uid?: number, + /** Process gid with `setgid` */ + gid?: number, + } + type ExecNonBlockingOptions = ExecOptions & { block?: false }; + type ExecBlockingOptions = ExecOptions & { block: true }; + + interface Stat { + dev: number; + ino: number; + mode: StatMode; + nlink: number; + uid: number; + gid: number; + rdev: number; + size: number; + blocks: number; + /** milliseconds since 1970 */ + atime: number; + /** milliseconds since 1970 */ + mtime: number; + /** milliseconds since 1970 */ + ctime: number; + } + interface SocketAddr { + /** @example 80 */ + port: number; + /** @example "8.8.8.8" or "::1" */ + addr: string; + /** @default AF_INET */ + family: SocketFamily; + } + interface SocketAddrInfo extends SocketAddr { + socktype: SocketType; + } + interface HintAddr { + /** @example 80 or "http" */ + service?: number | string; + /** @default any */ + family?: SocketFamily; + /** @default any */ + socktype?: SocketType; + } + /* POSIX constants (Windows-specific) */ + export const O_TEXT: OpenOption; + /* POSIX constants */ + export const O_APPEND: OpenOption; + export const O_CREAT: OpenOption; + export const O_EXCL: OpenOption; + export const O_RDONLY: OpenOption; + export const O_RDWR: OpenOption; + export const O_TRUNC: OpenOption; + export const O_WRONLY: OpenOption; + export const S_IFBLK: StatMode; + export const S_IFCHR: StatMode; + export const S_IFDIR: StatMode; + export const S_IFIFO: StatMode; + export const S_IFLNK: StatMode; + export const S_IFMT: StatMode; + export const S_IFREG: StatMode; + export const S_IFSOCK: StatMode; + export const S_ISGID: StatMode; + export const S_ISUID: StatMode; + export const SIGABRT: Signal; + export const SIGALRM: Signal; + export const SIGCHLD: Signal; + export const SIGCONT: Signal; + export const SIGFPE: Signal; + export const SIGILL: Signal; + export const SIGINT: Signal; + export const SIGPIPE: Signal; + export const SIGQUIT: Signal; + export const SIGSEGV: Signal; + export const SIGSTOP: Signal; + export const SIGTERM: Signal; + export const SIGTSTP: Signal; + export const SIGTTIN: Signal; + export const SIGTTOU: Signal; + export const SIGUSR1: Signal; + export const SIGUSR2: Signal; + export const WNOHANG: WaitpidOpt; + export const AF_INET: SocketFamily; + export const AF_INET6: SocketFamily; + export const SOCK_STREAM: SocketType; + export const SOCK_DGRAM: SocketType; + export const SOCK_RAW: SocketType; + //export const SOCK_BLOCK: SocketType; // SOCK_NONBLOCK + export const SO_REUSEADDR: SocketOpt; + export const SO_ERROR: SocketOpt; + export const SO_RCVBUF: SocketOpt; + export const SHUT_RD: SocketShutOpt; + export const SHUT_WR: SocketShutOpt; + export const SHUT_RDWR: SocketShutOpt; + /** string representing the platform. */ + export const platform: Platform; + /** Open a file. Return a handle or `< 0` if error. */ + export function open(filename: string, flags?: OpenOption, mode?: number): Result; + /** Close the file handle `fd`. */ + export function close(fd: FileDescriptor): Result; + /** Seek in the file. Use `std.SEEK_*` for whence */ + export function seek(fd: FileDescriptor, offset: number, whence: number): Result; + export function seek(fd: FileDescriptor, offset: bigint, whence: number): Result; + /** Read `length` bytes from the file handle `fd` to the `ArrayBuffer` buffer at byte position `offset` */ + export function read(fd: FileDescriptor, buffer: ArrayBuffer, offset: number, length: number): Result; + /** Write `length` bytes to the file handle `fd` from the ArrayBuffer `buffer` at byte position `offset` */ + export function write(fd: FileDescriptor, buffer: ArrayBuffer, offset: number, length: number): Result; + /** Return `true` is fd is a TTY (terminal) handle. */ + export function isatty(fd: FileDescriptor): boolean; + /** Return the TTY size as `[width, height]` or `null` if not available. */ + export function ttyGetWinSize(fd: FileDescriptor): [width: number, height: number] | null; + /** Set the TTY in raw mode. */ + export function ttySetRaw(fd: FileDescriptor): void; + /** Remove a file. */ + export function remove(filename: string): Result; + /** Rename a file. */ + export function rename(filename: string): Result; + /** Get the canonicalized absolute pathname of `path` */ + export function realpath(path: string): [absPath: string, code: Success | Errno]; + /** Return the current working directory */ + export function getcwd(): [cwd: string, code: Success | Errno]; + /** Change the current directory. Return 0 if OK or `-errno`. */ + export function chdir(): Result; + /** Create a directory at `path`. Return 0 if OK or `-errno`. */ + export function mkdir(path: string, mode?: number): Result; + /** Get a file status */ + export function stat(path: string): [fileStatus: Stat, code: Success | Errno] + /** Get a link status */ + export function lstat(path: string): [linkStatus: Stat, code: Success | Errno] + /** Change the access and modification times of the file `path` @returns ms since 1970. */ + export function utimes(path: string, atime: number, mtime: number): Result; + /** Create a link at `linkpath` containing the string `target`. */ + export function symlink(target: string, linkpath: string): Result; + /** Get link target */ + export function readlink(path: string): [linkTarget: string, code: Success | Errno]; + /** List directory entries */ + export function readdir(dirPath: string): [dirFilenames: string[], code: Success | Errno]; + /** Set the single `func` read handler to be called each time data can be written to `fd`. */ + export function setReadHandler(fd: FileDescriptor, func: Callback): void; + /** Remove the read handler for `fd`. */ + export function setReadHandler(fd: FileDescriptor, func: null): void; + /** Set the single `func` read handler to be called each time data can be written to `fd`. */ + export function setWriteHandler(fd: FileDescriptor, func: Callback): void; + /** Remove the write handler for `fd`. */ + export function setWriteHandler(fd: FileDescriptor, func: null): void; + /** Set the single `func` to be called when `signal` happens. Work in main thread only */ + export function signal(signal: Signal, func: Callback): void + /** Call the default handler when `signal` happens. */ + export function signal(signal: Signal, func: null): void + /** Ignore when `signal` happens. */ + export function signal(signal: Signal, func: undefined): void + /** Send the signal `sig` to the process `pid`. */ + export function kill(pid: Pid, signal: Signal): Result; + /** Execute a process with the arguments args. */ + export function exec(args: string[], options?: ExecBlockingOptions): Result; + /** Execute a process with the arguments args. */ + export function exec(args: string[], options: ExecNonBlockingOptions): Result; + /** `waitpid` Unix system call. */ + export function waitpid(pid: Pid, options: WaitpidOpt): [ret: Result, status: WaitStatus]; + /** `getpid` Unix system call. */ + export function getpid(): [Pid]; + /** `dup` Unix system call. */ + export function dup(fd: FileDescriptor): Result; + /** `dup2` Unix system call. */ + export function dup2(oldFd: FileDescriptor, newFd: FileDescriptor): Result; + /** `pipe` Unix system call. */ + export function pipe(): [readFd: FileDescriptor, writeFd: FileDescriptor] | null; + /** Sleep during `delay_ms` milliseconds. */ + export function sleep(delay_ms: number): Result; + /** Sleep during `delay_ms` milliseconds. */ + export function sleepAsync(delay_ms: number): Promise>; + /** Call the function func after `delay` ms. */ + export function setTimeout(func: Callback, delay: number): TimerHandle; + /** Cancel a timer. */ + export function clearTimeout(handle: TimerHandle): void; + /** Create a POSIX socket */ + export function socket(family: SocketFamily, type: SocketType): Result; + /** Get a socket option @example os.getsockopt(sock_srv, os.SO_RCVBUF, uintArr1.buffer); */ + export function getsockopt(sockfd: FileDescriptor, name: SocketOpt, data: ArrayBuffer): Result; + /** Set a socket option @example os.setsockopt(sock_srv, os.SO_REUSEADDR, new Uint32Array([1]).buffer); */ + export function setsockopt(sockfd: FileDescriptor, name: SocketOpt, data: ArrayBuffer): Result; + /** Get address information for a given node and/or service @example os.getaddrinfo("localhost", {family:os.AF_INET6}) */ + export function getaddrinfo(node?: string, hint?: HintAddr): Result>; + /** Get current address to which the socket sockfd is bound */ + export function getsockname(sockfd: FileDescriptor): Result; + /** Bind socket to a specific address */ + export function bind(sockfd: FileDescriptor, addr: SocketAddr): Result; + /** Mark `sockfd` as passive socket that will `accept()` a `backlog` number of incoming connection (SOMAXCONN by default). */ + export function listen(sockfd: FileDescriptor, backlog?: number): Result; + /** Shut down part of a full-duplex connection */ + export function shutdown(sockfd: FileDescriptor, type: SocketShutOpt): Result; + /** Accept incoming connections */ + export function accept(sockfd: FileDescriptor): Promise<[remotefd: FileDescriptor, remoteaddr: SocketAddr]>; + /** Connect `sockfd` to `addr` */ + export function connect(sockfd: FileDescriptor, addr: SocketAddr): Promise>; + /** Send `length` byte from `buffer` on `sockfd` @returns bytes sent or <0 if error */ + export function send(sockfd: FileDescriptor, buffer: ArrayBuffer, length?: number): Promise>; + /** Receive `length` byte in `buffer` from `sockfd` @returns bytes received or <0 if error */ + export function recv(sockfd: FileDescriptor, buffer: ArrayBuffer, length?: number): Promise>; + /** Send `length` byte from `buffer` on `sockfd` to `addr` @returns bytes sent or <0 if error */ + export function sendto(sockfd: FileDescriptor, addr: SocketAddr, buffer: ArrayBuffer, length?: number): Promise>; + /** Receive `length` byte in `buffer` from `sockfd` @returns bytes received or <0 if error, and remote address used */ + export function recvfrom(sockfd: FileDescriptor, buffer: ArrayBuffer, length?: number): Promise<[total: Result, from: SocketAddr]>; + + export class Worker { + /** + * In the created worker, `Worker.parent` represents the parent worker + * and is used to send or receive messages. + */ + static parent?: Worker; + /** + * Constructor to create a new thread (worker) with an API close to + * the `WebWorkers`. `module_filename` is a string specifying the + * module filename which is executed in the newly created thread. As + * for dynamically imported module, it is relative to the current + * script or module path. Threads normally don’t share any data and + * communicate between each other with messages. Nested workers are + * not supported. An example is available in `tests/test_worker.js`. + */ + constructor(module_filename: string); + /** + * Send a message to the corresponding worker. msg is cloned in the + * destination worker using an algorithm similar to the HTML structured + * clone algorithm. SharedArrayBuffer are shared between workers. + * + * Current limitations: `Map` and `Set` are not supported yet. + */ + postMessage(msg: WorkerMessage): void; + /** + * Getter and setter. Set a function which is called each time a + * message is received. The function is called with a single argument. + * It is an object with a `data` property containing the received + * message. The thread is not terminated if there is at least one non + * `null` onmessage handler. + */ + onmessage: (msg: WorkerMessage) => void; + } +} diff --git a/doc/std.d.ts b/doc/std.d.ts new file mode 100644 index 0000000..c4716a3 --- /dev/null +++ b/doc/std.d.ts @@ -0,0 +1,279 @@ +/** + * The std module provides wrappers to the libc stdlib.h and stdio.h and a + * few other utilities. + */ +declare module "std" { + import { FileDescriptor, ExitStatus, Errno } from "os"; + + /** + * FILE prototype + */ + export interface FILE { + /** + * Close the file. Return 0 if OK or `-errno` in case of I/O error. + */ + close(): number + /** + * Outputs the string with the UTF-8 encoding. + */ + puts(str: string): void; + /** + * Formatted printf. + * + * The same formats as the standard C library printf are supported. + * Integer format types (e.g. `%d`) truncate the Numbers or BigInts to 32 + * bits. Use the `l` modifier (e.g. `%ld`) to truncate to 64 bits. + */ + printf(format: string, ...args: any[]): number; + /** + * Flush the buffered file. + */ + flush(): void; + /** + * Seek to a give file position (whence is `std.SEEK_*`). `offset` can + * be a number or a bigint. Return 0 if OK or `-errno` in case of I/O + * error. + */ + seek(offset: number, whence: number): number; + /** + * Return the current file position. + */ + tell(): number; + /** + * Return the current file position as a bigint. + */ + tello(): bigint; + /** + * Return true if end of file. + */ + eof(): boolean; + /** + * Return the associated OS handle. + */ + fileno(): FileDescriptor; + /** + * Return true if there was an error. + */ + error(): boolean; + /** + * Clear the error indication. + */ + clearerr(): void; + /** + * Read `length` bytes from the file to the ArrayBuffer `buffer` at + * byte position `position` (wrapper to the libc `fread`). + */ + read(buffer: ArrayBuffer, position: number, length: number): number; + /** + * Write `length` bytes to the file from the ArrayBuffer `buffer` at + * byte position position (wrapper to the libc `fwrite`). + */ + write(buffer: ArrayBuffer, postion: number, length: number): number; + /** + * Return the next line from the file, assuming UTF-8 encoding, excluding + * the trailing line feed. + */ + getline(): string; + /** + * Read `max_size` bytes from the file and return them as a string + * assuming UTF-8 encoding. If `max_size` is not present, the file is + * read up its end. + */ + readAsString(max_size?: number): string; + /** + * Return the next byte from the file. Return -1 if the end of file is + * reached. + */ + getByte(): number + /** + * Write one byte to the file. + */ + putByte(c: number): number; + } + + export interface EvalOptions { + /** + * Boolean (default = `false`). If `true`, error backtraces do not list + * the stack frames below the evalScript. + */ + backtrace_barrier?: boolean; + } + + export interface ErrorObj { + errno?: number; + } + + export interface UrlGetOptions { + /** + * Boolean (default = `false`). If `true`, the response is an + * ArrayBuffer instead of a string. When a string is returned, the + * data is assumed to be UTF-8 encoded. + */ + binary?: boolean; + /** + * Boolean (default = `false`). If `true`, return the an object contains + * the properties response (response content), responseHeaders (headers + * separated by CRLF), status (status code). response is null is case of + * protocol or network error. If full is false, only the response is + * returned if the status is between 200 and 299. Otherwise null is + * returned. + */ + full?: boolean; + } + + export interface UrlGetResponse { + response: T | null; + status: number; + responseHeaders: string; + } + + /** + * Result that either represents a FILE or null on error. + */ + export type FILEResult = FILE | null; + + /** + * Exit the process. + */ + export function exit(n: ExitStatus): never; + /** + * Evaluate the string `str` as a script (global eval). + */ + export function evalScript(str: string, options?: EvalOptions): any; + /** + * Evaluate the file filename as a script (global eval). + */ + export function loadScript(filename: string): any; + /** + * Load the file filename and return it as a string assuming UTF-8 + * encoding. Return `null` in case of I/O error. + */ + export function loadFile(filename: string): string | null; + /** + * Open a file (wrapper to the libc fopen()). Return the FILE object or + * `null` in case of I/O error. If errorObj is not undefined, set its + * `errno` property to the error code or to 0 if no error occured. + */ + export function open(filename: string, flags: string, errorObj?: ErrorObj): FILEResult; + /** + * Open a process by creating a pipe (wrapper to the libc `popen()`). + * Return the `FILE` object or `null` in case of I/O error. If `errorObj` + * is not `undefined`, set its `errno` property to the error code or to 0 + * if no error occured. + */ + export function popen(command: string, flags: string, errorObj?: ErrorObj): FILEResult; + /** + * Open a file from a file handle (wrapper to the libc `fdopen()`). Return + * the `FILE` object or `null` in case of I/O error. If `errorObj` is not + * `undefined`, set its errno property to the error code or to 0 if no + * error occured. + */ + export function fdopen(fd: FileDescriptor, flags: string, errorObj?: ErrorObj): FILEResult; + /** + * Open a temporary file. Return the `FILE` object or `null` in case of I/O + * error. If `errorObj` is not undefined, set its `errno` property to the + * error code or to 0 if no error occured. + */ + export function tmpfile(errorObj?: ErrorObj): FILE; + /** + * Equivalent to `std.out.puts(str)`. + */ + export const puts: typeof out.puts; + /** + * Equivalent to `std.out.printf(fmt, ...args)`. + */ + export const printf: typeof out.printf; + /** + * Equivalent to the libc `sprintf()`. + */ + export function sprintf(format: string, ...args: any[]): string; + const $in: FILE; + /** + * Wrappers to the libc file `stdin`, `stdout`, `stderr`. + */ + export { $in as in }; + /** + * Wrappers to the libc file `stdin`, `stdout`, `stderr`. + */ + export const out: FILE; + /** + * Wrappers to the libc file `stdin`, `stdout`, `stderr`. + */ + export const err: FILE; + /** + * Constants for seek(). + */ + export const SEEK_CUR: number; + /** + * Constants for seek(). + */ + export const SEEK_END: number; + /** + * Constants for seek(). + */ + export const SEEK_SET: number; + /** + * Enumeration object containing the integer value of common errors + * (additional error codes may be defined): + */ + export const Error: { + readonly EACCES: number, + readonly ENOENT: number, + readonly EBADF: number, + readonly ENOSPC: number, + readonly EBUSY: number, + readonly ENOSYS: number, + readonly EEXIST: number, + readonly EPERM: number, + readonly EINVAL: number, + readonly EPIPE: number, + readonly EIO: number, + readonly EAGAIN: number, + readonly EINPROGRESS: number, + readonly EWOULDBLOCK: number, + }; + /** + * Return a string that describes the error `errno`. + */ + export function strerror(errno: Errno): string; + /** + * Manually invoke the cycle removal algorithm. The cycle removal + * algorithm is automatically started when needed, so this function is + * useful in case of specific memory constraints or for testing. + */ + export function gc(): void; + /** + * Return the value of the environment variable `name` or `undefined` if it + * is not defined. + */ + export function getenv(name: string): string | undefined; + /** + * Set the value of the environment variable `name` to the string `value`. + */ + export function setenv(name: string, value: string): void; + /** + * Delete the environment variable `name`. + */ + export function unsetenv(name: string): void; + /** + * Return an object containing the environment variables as key-value pairs. + */ + export function getenviron(): { [key: string]: string }; + /** Download url using the curl command line utility. */ + export function urlGet(url: string, options?: UrlGetOptions): string | null; + export function urlGet(url: string, options: UrlGetOptions & { full?: false, binary: true }): ArrayBuffer | null; + export function urlGet(url: string, options: UrlGetOptions & { full: true, binary?: false }): UrlGetResponse; + export function urlGet(url: string, options: UrlGetOptions & { full: true, binary: true }): UrlGetResponse; + /** + * Parse `str` using a superset of `JSON.parse`. The following extensions are accepted: + * + * - Single line and multiline comments + * - unquoted properties (ASCII-only Javascript identifiers) + * - trailing comma in array and object definitions + * - single quoted strings + * - \\f and \\v are accepted as space characters + * - leading plus in numbers + * - octal (0o prefix) and hexadecimal (0x prefix) numbers + */ + export function parseExtJSON(str: string): any; +}