'use strict'; const fs = require('fs'); const path = require('path'); const {execFile} = require('child_process'); const {promisify} = require('util'); const execFileAsync = promisify(execFile); const repoRoot = path.resolve(__dirname, '..', '..', '..'); function isCommandAvailable(command) { const paths = (process.env.PATH || '').split(path.delimiter); const extensions = process.platform === 'win32' && process.env.PATHEXT ? process.env.PATHEXT.split(';') : ['']; for (let i = 0; i < paths.length; i++) { const dir = paths[i]; if (!dir) { continue; } for (let j = 0; j < extensions.length; j++) { const ext = extensions[j]; const fullPath = path.join(dir, `${command}${ext}`); try { fs.accessSync(fullPath, fs.constants.X_OK); return true; } catch { // Keep searching. } } } return false; } function noopLogger() {} function escapeCsvValue(value) { if (value == null) { return ''; } const stringValue = String(value).replace(/\r?\n|\r/g, ' '); if (stringValue.includes('"') || stringValue.includes(',')) { return `"${stringValue.replace(/"/g, '""')}"`; } return stringValue; } function toCsvRow(values) { return values.map(escapeCsvValue).join(','); } module.exports = { execFileAsync, repoRoot, isCommandAvailable, noopLogger, escapeCsvValue, toCsvRow, };