diff --git a/src/config.ts b/src/config.ts index b702218..0af91cd 100644 --- a/src/config.ts +++ b/src/config.ts @@ -28,7 +28,7 @@ export type CLIOptions = { blockedOrigins?: string[]; blockServiceWorkers?: boolean; browser?: string; - caps?: string; + caps?: string[]; cdpEndpoint?: string; config?: string; device?: string; @@ -38,7 +38,7 @@ export type CLIOptions = { ignoreHttpsErrors?: boolean; isolated?: boolean; imageResponses?: 'allow' | 'omit'; - sandbox: boolean; + sandbox?: boolean; outputDir?: string; port?: number; proxyBypass?: string; @@ -89,15 +89,19 @@ export async function resolveConfig(config: Config): Promise { export async function resolveCLIConfig(cliOptions: CLIOptions): Promise { const configInFile = await loadConfig(cliOptions.config); - const cliOverrides = await configFromCLIOptions(cliOptions); - const result = mergeConfig(mergeConfig(defaultConfig, configInFile), cliOverrides); + const envOverrides = configFromEnv(); + const cliOverrides = configFromCLIOptions(cliOptions); + let result = defaultConfig; + result = mergeConfig(result, configInFile); + result = mergeConfig(result, envOverrides); + result = mergeConfig(result, cliOverrides); // Derive artifact output directory from config.outputDir if (result.saveTrace) result.browser.launchOptions.tracesDir = path.join(result.outputDir, 'traces'); return result; } -export async function configFromCLIOptions(cliOptions: CLIOptions): Promise { +export function configFromCLIOptions(cliOptions: CLIOptions): Config { let browserName: 'chromium' | 'firefox' | 'webkit' | undefined; let channel: string | undefined; switch (cliOptions.browser) { @@ -181,7 +185,7 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise c.trim() as ToolCapability), + capabilities: cliOptions.caps as ToolCapability[], network: { allowedOrigins: cliOptions.allowedOrigins, blockedOrigins: cliOptions.blockedOrigins, @@ -194,6 +198,36 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise { if (!configFile) return {}; @@ -251,3 +285,33 @@ function mergeConfig(base: FullConfig, overrides: Config): FullConfig { }, } as FullConfig; } + +export function semicolonSeparatedList(value: string | undefined): string[] | undefined { + if (!value) + return undefined; + return value.split(';').map(v => v.trim()); +} + +export function commaSeparatedList(value: string | undefined): string[] | undefined { + if (!value) + return undefined; + return value.split(',').map(v => v.trim()); +} + +function envToNumber(value: string | undefined): number | undefined { + if (!value) + return undefined; + return +value; +} + +function envToBoolean(value: string | undefined): boolean | undefined { + if (value === 'true' || value === '1') + return true; + if (value === 'false' || value === '0') + return false; + return undefined; +} + +function envToString(value: string | undefined): string | undefined { + return value ? value.trim() : undefined; +} diff --git a/src/program.ts b/src/program.ts index 27c42b6..3035b28 100644 --- a/src/program.ts +++ b/src/program.ts @@ -19,7 +19,7 @@ import { program, Option } from 'commander'; import { startTraceViewerServer } from 'playwright-core/lib/server'; import { startHttpServer, startHttpTransport, startStdioTransport } from './transport.js'; -import { resolveCLIConfig } from './config.js'; +import { commaSeparatedList, resolveCLIConfig, semicolonSeparatedList } from './config.js'; import { Server } from './server.js'; import { packageJSON } from './package.js'; @@ -30,7 +30,7 @@ program .option('--blocked-origins ', 'semicolon-separated list of origins to block the browser from requesting. Blocklist is evaluated before allowlist. If used without the allowlist, requests not matching the blocklist are still allowed.', semicolonSeparatedList) .option('--block-service-workers', 'block service workers') .option('--browser ', 'browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.') - .option('--caps ', 'comma-separated list of additional capabilities to enable, possible values: vision, pdf.') + .option('--caps ', 'comma-separated list of additional capabilities to enable, possible values: vision, pdf.', commaSeparatedList) .option('--cdp-endpoint ', 'CDP endpoint to connect to.') .option('--config ', 'path to the configuration file.') .option('--device ', 'device to emulate, for example: "iPhone 15"') @@ -77,8 +77,4 @@ program } }); -function semicolonSeparatedList(value: string): string[] { - return value.split(';').map(v => v.trim()); -} - void program.parseAsync(process.argv);