fix: resolve PR 371 portability regressions

This commit is contained in:
Affaan Mustafa
2026-03-09 22:05:35 -07:00
committed by Affaan Mustafa
parent 1c5e07ff77
commit af51fcacb7
7 changed files with 141 additions and 21 deletions

View File

@@ -10,7 +10,7 @@
* Fails silently if no formatter is found or installed.
*/
const { execFileSync } = require('child_process');
const { execFileSync, spawnSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const { getPackageManager } = require('../lib/package-manager');
@@ -50,18 +50,23 @@ process.stdin.on('data', chunk => {
function findProjectRoot(startDir) {
let dir = startDir;
let fallbackDir = null;
while (true) {
if (PROJECT_ROOT_MARKERS.some(marker => fs.existsSync(path.join(dir, marker)))) {
if (detectFormatter(dir)) {
return dir;
}
if (!fallbackDir && PROJECT_ROOT_MARKERS.some(marker => fs.existsSync(path.join(dir, marker)))) {
fallbackDir = dir;
}
const parentDir = path.dirname(dir);
if (parentDir === dir) break;
dir = parentDir;
}
return startDir;
return fallbackDir || startDir;
}
function detectFormatter(projectRoot) {
@@ -114,6 +119,33 @@ function getFormatterCommand(formatter, filePath, projectRoot) {
return null;
}
function runFormatterCommand(cmd, projectRoot) {
if (process.platform === 'win32' && cmd.bin.endsWith('.cmd')) {
const result = spawnSync(cmd.bin, cmd.args, {
cwd: projectRoot,
shell: true,
stdio: 'pipe',
timeout: 15000
});
if (result.error) {
throw result.error;
}
if (typeof result.status === 'number' && result.status !== 0) {
throw new Error(result.stderr?.toString() || `Formatter exited with status ${result.status}`);
}
return;
}
execFileSync(cmd.bin, cmd.args, {
cwd: projectRoot,
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 15000
});
}
process.stdin.on('end', () => {
try {
const input = JSON.parse(data);
@@ -126,11 +158,7 @@ process.stdin.on('end', () => {
const cmd = getFormatterCommand(formatter, filePath, projectRoot);
if (cmd) {
execFileSync(cmd.bin, cmd.args, {
cwd: projectRoot,
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 15000
});
runFormatterCommand(cmd, projectRoot);
}
} catch {
// Formatter not installed, file missing, or failed — non-blocking

View File

@@ -2,6 +2,7 @@
'use strict';
const MAX_STDIN = 1024 * 1024;
const path = require('path');
const { splitShellSegments } = require('../lib/shell-split');
const DEV_COMMAND_WORDS = new Set([
@@ -10,13 +11,9 @@ const DEV_COMMAND_WORDS = new Set([
'yarn',
'bun',
'npx',
'bash',
'sh',
'zsh',
'fish',
'tmux'
]);
const SKIPPABLE_PREFIX_WORDS = new Set(['env', 'command', 'builtin', 'exec', 'noglob', 'sudo']);
const SKIPPABLE_PREFIX_WORDS = new Set(['env', 'command', 'builtin', 'exec', 'noglob', 'sudo', 'nohup']);
const PREFIX_OPTION_VALUE_WORDS = {
env: new Set(['-u', '-C', '-S', '--unset', '--chdir', '--split-string']),
sudo: new Set([
@@ -97,6 +94,12 @@ function isOptionToken(token) {
return token.startsWith('-') && token.length > 1;
}
function normalizeCommandWord(token) {
if (!token) return '';
const base = path.basename(token).toLowerCase();
return base.replace(/\.(cmd|exe|bat)$/i, '');
}
function getLeadingCommandWord(segment) {
let index = 0;
let activeWrapper = null;
@@ -122,8 +125,10 @@ function getLeadingCommandWord(segment) {
if (/^[A-Za-z_][A-Za-z0-9_]*=.*/.test(token)) continue;
if (SKIPPABLE_PREFIX_WORDS.has(token)) {
activeWrapper = token;
const normalizedToken = normalizeCommandWord(token);
if (SKIPPABLE_PREFIX_WORDS.has(normalizedToken)) {
activeWrapper = normalizedToken;
continue;
}
@@ -134,7 +139,7 @@ function getLeadingCommandWord(segment) {
continue;
}
return token;
return normalizedToken;
}
return null;