diff --git a/tools/check_external_links.js b/tools/check_external_links.js index a3bff599..5cf9d667 100644 --- a/tools/check_external_links.js +++ b/tools/check_external_links.js @@ -76,18 +76,30 @@ const MAX_REDIRECTS = Math.max( ); const DEFAULT_USER_AGENT = buildUserAgent(settings.userAgent); const IGNORE_HOSTS = parseIgnoreHosts(settings.ignoreHosts); -const PLAYWRIGHT_ENABLED = settings.usePlaywright === true; +const PLAYWRIGHT_RESOLUTION = + settings.usePlaywright === true + ? resolvePlaywrightExecutable(settings.playwrightExecutablePath) + : { path: null, missing: null }; +const PLAYWRIGHT_EXECUTABLE = PLAYWRIGHT_RESOLUTION.path; +const PLAYWRIGHT_ENABLED = settings.usePlaywright === true && !PLAYWRIGHT_RESOLUTION.missing; +if (settings.usePlaywright === true && PLAYWRIGHT_RESOLUTION.missing) { + console.warn( + [ + "Playwright désactivé : impossible de trouver l'exécutable demandé", + `"${PLAYWRIGHT_RESOLUTION.missing}".`, + `Corrigez externalLinks.playwrightExecutablePath dans ${path.relative( + SITE_ROOT, + CONFIG_PATH + )} pour rétablir la vérification enrichie.`, + ].join(" ") + ); +} const PLAYWRIGHT_TIMEOUT_MS = Math.max( 1000, (Number.isFinite(Number(settings.playwrightTimeoutSeconds)) ? Number(settings.playwrightTimeoutSeconds) : DEFAULT_CONFIG.playwrightTimeoutSeconds) * 1000 ); -const PLAYWRIGHT_EXECUTABLE = - typeof settings.playwrightExecutablePath === "string" && - settings.playwrightExecutablePath.trim().length > 0 - ? settings.playwrightExecutablePath.trim() - : null; const PLAYWRIGHT_RECHECK_STATUSES = new Set([403, 426, 429, 502]); const CACHE_TTL_SUCCESS_MS = daysToMs( @@ -181,6 +193,50 @@ function parseIgnoreHosts(raw) { return set; } +// Résout l'exécutable Playwright défini dans la configuration, en tolérant un simple nom présent dans PATH. +function resolvePlaywrightExecutable(rawPath) { + if (typeof rawPath !== "string") { + return { path: null, missing: null }; + } + const trimmed = rawPath.trim(); + if (!trimmed) { + return { path: null, missing: null }; + } + if (fs.existsSync(trimmed)) { + return { path: trimmed, missing: null }; + } + if (!containsPathSeparator(trimmed)) { + const resolved = findExecutableInPath(trimmed); + if (resolved) { + return { path: resolved, missing: null }; + } + } + return { path: null, missing: trimmed }; +} + +function containsPathSeparator(value) { + return value.includes("/") || value.includes("\\"); +} + +// Parcourt la variable d'environnement PATH pour retrouver un binaire par son nom. +function findExecutableInPath(binaryName) { + if (typeof binaryName !== "string" || !binaryName.trim()) { + return null; + } + const searchPath = process.env.PATH || ""; + const directories = searchPath.split(path.delimiter); + for (const directory of directories) { + if (!directory) { + continue; + } + const candidate = path.join(directory, binaryName); + if (fs.existsSync(candidate)) { + return candidate; + } + } + return null; +} + function daysToMs(days) { if (!Number.isFinite(days) || days <= 0) { return 0;