246 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			246 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as plugins from './tstest.plugins.js';
 | |
| import type { Runtime } from './tstest.classes.runtime.parser.js';
 | |
| import { TapParser } from './tstest.classes.tap.parser.js';
 | |
| 
 | |
| /**
 | |
|  * Runtime-specific configuration options
 | |
|  */
 | |
| export interface RuntimeOptions {
 | |
|   /**
 | |
|    * Environment variables to pass to the runtime
 | |
|    */
 | |
|   env?: Record<string, string>;
 | |
| 
 | |
|   /**
 | |
|    * Additional command-line arguments
 | |
|    */
 | |
|   extraArgs?: string[];
 | |
| 
 | |
|   /**
 | |
|    * Working directory for test execution
 | |
|    */
 | |
|   cwd?: string;
 | |
| 
 | |
|   /**
 | |
|    * Timeout in milliseconds (0 = no timeout)
 | |
|    */
 | |
|   timeout?: number;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Deno-specific configuration options
 | |
|  */
 | |
| export interface DenoOptions extends RuntimeOptions {
 | |
|   /**
 | |
|    * Permissions to grant to Deno
 | |
|    * Default: ['--allow-read', '--allow-env']
 | |
|    */
 | |
|   permissions?: string[];
 | |
| 
 | |
|   /**
 | |
|    * Path to deno.json config file
 | |
|    */
 | |
|   configPath?: string;
 | |
| 
 | |
|   /**
 | |
|    * Path to import map file
 | |
|    */
 | |
|   importMap?: string;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Chromium-specific configuration options
 | |
|  */
 | |
| export interface ChromiumOptions extends RuntimeOptions {
 | |
|   /**
 | |
|    * Chromium launch arguments
 | |
|    */
 | |
|   launchArgs?: string[];
 | |
| 
 | |
|   /**
 | |
|    * Headless mode (default: true)
 | |
|    */
 | |
|   headless?: boolean;
 | |
| 
 | |
|   /**
 | |
|    * Port range for HTTP server
 | |
|    */
 | |
|   portRange?: { min: number; max: number };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Command configuration returned by createCommand()
 | |
|  */
 | |
| export interface RuntimeCommand {
 | |
|   /**
 | |
|    * The main command executable (e.g., 'node', 'deno', 'bun')
 | |
|    */
 | |
|   command: string;
 | |
| 
 | |
|   /**
 | |
|    * Command-line arguments
 | |
|    */
 | |
|   args: string[];
 | |
| 
 | |
|   /**
 | |
|    * Environment variables
 | |
|    */
 | |
|   env?: Record<string, string>;
 | |
| 
 | |
|   /**
 | |
|    * Working directory
 | |
|    */
 | |
|   cwd?: string;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Runtime availability check result
 | |
|  */
 | |
| export interface RuntimeAvailability {
 | |
|   /**
 | |
|    * Whether the runtime is available
 | |
|    */
 | |
|   available: boolean;
 | |
| 
 | |
|   /**
 | |
|    * Version string if available
 | |
|    */
 | |
|   version?: string;
 | |
| 
 | |
|   /**
 | |
|    * Error message if not available
 | |
|    */
 | |
|   error?: string;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Abstract base class for runtime adapters
 | |
|  * Each runtime (Node, Chromium, Deno, Bun) implements this interface
 | |
|  */
 | |
| export abstract class RuntimeAdapter {
 | |
|   /**
 | |
|    * Runtime identifier
 | |
|    */
 | |
|   abstract readonly id: Runtime;
 | |
| 
 | |
|   /**
 | |
|    * Human-readable display name
 | |
|    */
 | |
|   abstract readonly displayName: string;
 | |
| 
 | |
|   /**
 | |
|    * Check if this runtime is available on the system
 | |
|    * @returns Availability information including version
 | |
|    */
 | |
|   abstract checkAvailable(): Promise<RuntimeAvailability>;
 | |
| 
 | |
|   /**
 | |
|    * Create the command configuration for executing a test
 | |
|    * @param testFile - Absolute path to the test file
 | |
|    * @param options - Runtime-specific options
 | |
|    * @returns Command configuration
 | |
|    */
 | |
|   abstract createCommand(testFile: string, options?: RuntimeOptions): RuntimeCommand;
 | |
| 
 | |
|   /**
 | |
|    * Execute a test file and return a TAP parser
 | |
|    * @param testFile - Absolute path to the test file
 | |
|    * @param index - Test index (for display)
 | |
|    * @param total - Total number of tests (for display)
 | |
|    * @param options - Runtime-specific options
 | |
|    * @returns TAP parser with test results
 | |
|    */
 | |
|   abstract run(
 | |
|     testFile: string,
 | |
|     index: number,
 | |
|     total: number,
 | |
|     options?: RuntimeOptions
 | |
|   ): Promise<TapParser>;
 | |
| 
 | |
|   /**
 | |
|    * Get the default options for this runtime
 | |
|    * Can be overridden by subclasses
 | |
|    */
 | |
|   protected getDefaultOptions(): RuntimeOptions {
 | |
|     return {
 | |
|       timeout: 0,
 | |
|       extraArgs: [],
 | |
|       env: {},
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Merge user options with defaults
 | |
|    */
 | |
|   protected mergeOptions<T extends RuntimeOptions>(userOptions?: T): T {
 | |
|     const defaults = this.getDefaultOptions();
 | |
|     return {
 | |
|       ...defaults,
 | |
|       ...userOptions,
 | |
|       env: { ...defaults.env, ...userOptions?.env },
 | |
|       extraArgs: [...(defaults.extraArgs || []), ...(userOptions?.extraArgs || [])],
 | |
|     } as T;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Registry for runtime adapters
 | |
|  * Manages all available runtime implementations
 | |
|  */
 | |
| export class RuntimeAdapterRegistry {
 | |
|   private adapters: Map<Runtime, RuntimeAdapter> = new Map();
 | |
| 
 | |
|   /**
 | |
|    * Register a runtime adapter
 | |
|    */
 | |
|   register(adapter: RuntimeAdapter): void {
 | |
|     this.adapters.set(adapter.id, adapter);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get an adapter by runtime ID
 | |
|    */
 | |
|   get(runtime: Runtime): RuntimeAdapter | undefined {
 | |
|     return this.adapters.get(runtime);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get all registered adapters
 | |
|    */
 | |
|   getAll(): RuntimeAdapter[] {
 | |
|     return Array.from(this.adapters.values());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Check which runtimes are available on the system
 | |
|    */
 | |
|   async checkAvailability(): Promise<Map<Runtime, RuntimeAvailability>> {
 | |
|     const results = new Map<Runtime, RuntimeAvailability>();
 | |
| 
 | |
|     for (const [runtime, adapter] of this.adapters) {
 | |
|       const availability = await adapter.checkAvailable();
 | |
|       results.set(runtime, availability);
 | |
|     }
 | |
| 
 | |
|     return results;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get adapters for a list of runtimes, in order
 | |
|    * @param runtimes - Ordered list of runtimes
 | |
|    * @returns Adapters in the same order, skipping any that aren't registered
 | |
|    */
 | |
|   getAdaptersForRuntimes(runtimes: Runtime[]): RuntimeAdapter[] {
 | |
|     const adapters: RuntimeAdapter[] = [];
 | |
| 
 | |
|     for (const runtime of runtimes) {
 | |
|       const adapter = this.get(runtime);
 | |
|       if (adapter) {
 | |
|         adapters.push(adapter);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return adapters;
 | |
|   }
 | |
| }
 |