fix(desktop): preserve Windows backslash paths in custom extension command (#9741)
Signed-off-by: Michael Neale <michael.neale@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import {
|
||||
nameToKey,
|
||||
getDefaultFormData,
|
||||
@@ -346,6 +346,36 @@ describe('Extension Utils', () => {
|
||||
])('splits %j correctly', (input, expected) => {
|
||||
expect(splitCmdAndArgs(input)).toEqual(expected);
|
||||
});
|
||||
|
||||
describe('on Windows', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal('window', { electron: { platform: 'win32' } });
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('preserves backslashes in a Windows path', () => {
|
||||
expect(splitCmdAndArgs('C:\\Users\\name\\path\\to\\extension.js')).toEqual({
|
||||
cmd: 'C:\\Users\\name\\path\\to\\extension.js',
|
||||
args: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves backslashes in cmd and args', () => {
|
||||
expect(splitCmdAndArgs('node C:\\Users\\name\\ext.js')).toEqual({
|
||||
cmd: 'node',
|
||||
args: ['C:\\Users\\name\\ext.js'],
|
||||
});
|
||||
});
|
||||
|
||||
it('handles a quoted Windows path containing spaces', () => {
|
||||
expect(splitCmdAndArgs('"C:\\Program Files\\app\\ext.js"')).toEqual({
|
||||
cmd: 'C:\\Program Files\\app\\ext.js',
|
||||
args: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractCommand', () => {
|
||||
|
||||
@@ -168,13 +168,23 @@ export function createExtensionConfig(formData: ExtensionFormData): ExtensionCon
|
||||
}
|
||||
}
|
||||
|
||||
function isWindowsPlatform(): boolean {
|
||||
return typeof window !== 'undefined' && window.electron?.platform === 'win32';
|
||||
}
|
||||
|
||||
export function splitCmdAndArgs(str: string): { cmd: string; args: string[] } {
|
||||
const trimmed = str.trim();
|
||||
if (!trimmed) {
|
||||
return { cmd: '', args: [] };
|
||||
}
|
||||
|
||||
const parsed = parseShellQuote(trimmed);
|
||||
// shell-quote treats `\` as a POSIX escape character, so a Windows path like
|
||||
// `C:\Users\name\ext.js` would lose its backslashes and become `C:Usersnameext.js`.
|
||||
// Doubling backslashes on Windows lets them survive parsing (shell-quote unescapes
|
||||
// `\\` back to `\`), while still honoring quotes for paths containing spaces.
|
||||
const toParse = isWindowsPlatform() ? trimmed.replace(/\\/g, '\\\\') : trimmed;
|
||||
|
||||
const parsed = parseShellQuote(toParse);
|
||||
const words = parsed.filter((item): item is string => typeof item === 'string').map(String);
|
||||
|
||||
const cmd = words[0] || '';
|
||||
|
||||
Reference in New Issue
Block a user