fix(batch): resolve pandoc path handling and include-subfolders option

- Normalize pandoc command parsing with path.basename() to support bundled binary paths
- Use bundled pandoc binary in convertWithPandoc instead of relying on PATH
- Forward includeSubfolders checkbox state from renderer to main process
- Add pandoc availability check before batch conversion
- Re-enable Start button when batch conversion completes
- Clean up obsolete dist build artifact causing test snapshot warning
- Bump version to 4.4.4
This commit is contained in:
2026-06-30 12:56:33 +05:30
parent 02e307f758
commit d705cfc30b
86 changed files with 16876 additions and 13476 deletions
+76 -77
View File
@@ -4,97 +4,96 @@
*/
describe('sanitizeErrorMessage', () => {
const sanitizeErrorMessage = (message) => {
if (typeof message !== 'string') return String(message);
return message
.replace(/[A-Z]:\\[^\s"']+\\([^\s"'\\]+)/gi, '$1')
.replace(/\/[^\s"']+\/([^\s"'/]+)/g, '$1');
};
const sanitizeErrorMessage = (message) => {
if (typeof message !== 'string') return String(message);
return message
.replace(/[A-Z]:\\[^\s"']+\\([^\s"'\\]+)/gi, '$1')
.replace(/\/[^\s"']+\/([^\s"'/]+)/g, '$1');
};
test('strips Windows absolute paths', () => {
expect(sanitizeErrorMessage('Error in C:\\Users\\test\\file.js'))
.toBe('Error in file.js');
});
test('strips Windows absolute paths', () => {
expect(sanitizeErrorMessage('Error in C:\\Users\\test\\file.js')).toBe('Error in file.js');
});
test('strips Unix absolute paths', () => {
expect(sanitizeErrorMessage('Error in /home/user/project/file.js'))
.toBe('Error in file.js');
});
test('strips Unix absolute paths', () => {
expect(sanitizeErrorMessage('Error in /home/user/project/file.js')).toBe('Error in file.js');
});
test('handles non-string input', () => {
expect(sanitizeErrorMessage(42)).toBe('42');
expect(sanitizeErrorMessage(null)).toBe('null');
});
test('handles non-string input', () => {
expect(sanitizeErrorMessage(42)).toBe('42');
expect(sanitizeErrorMessage(null)).toBe('null');
});
test('preserves messages without paths', () => {
expect(sanitizeErrorMessage('Something went wrong'))
.toBe('Something went wrong');
});
test('preserves messages without paths', () => {
expect(sanitizeErrorMessage('Something went wrong')).toBe('Something went wrong');
});
test('strips nested Windows paths', () => {
expect(sanitizeErrorMessage('Cannot read C:\\Users\\admin\\AppData\\Local\\config.json'))
.toBe('Cannot read config.json');
});
test('strips nested Windows paths', () => {
expect(sanitizeErrorMessage('Cannot read C:\\Users\\admin\\AppData\\Local\\config.json')).toBe(
'Cannot read config.json'
);
});
test('strips nested Unix paths', () => {
expect(sanitizeErrorMessage('File not found: /var/log/app/error.log'))
.toBe('File not found: error.log');
});
test('strips nested Unix paths', () => {
expect(sanitizeErrorMessage('File not found: /var/log/app/error.log')).toBe(
'File not found: error.log'
);
});
test('handles undefined input', () => {
expect(sanitizeErrorMessage(undefined)).toBe('undefined');
});
test('handles undefined input', () => {
expect(sanitizeErrorMessage(undefined)).toBe('undefined');
});
});
describe('createRateLimiter', () => {
const createRateLimiter = (minIntervalMs = 2000) => {
let lastCall = 0;
return function canProceed() {
const now = Date.now();
if (now - lastCall < minIntervalMs) return false;
lastCall = now;
return true;
};
const createRateLimiter = (minIntervalMs = 2000) => {
let lastCall = 0;
return function canProceed() {
const now = Date.now();
if (now - lastCall < minIntervalMs) return false;
lastCall = now;
return true;
};
};
test('allows first call', () => {
const limiter = createRateLimiter(1000);
expect(limiter()).toBe(true);
});
test('allows first call', () => {
const limiter = createRateLimiter(1000);
expect(limiter()).toBe(true);
});
test('blocks rapid calls', () => {
const limiter = createRateLimiter(1000);
limiter(); // first call
expect(limiter()).toBe(false); // too soon
});
test('blocks rapid calls', () => {
const limiter = createRateLimiter(1000);
limiter(); // first call
expect(limiter()).toBe(false); // too soon
});
test('allows call after interval', () => {
jest.useFakeTimers();
const limiter = createRateLimiter(1000);
limiter();
jest.advanceTimersByTime(1001);
expect(limiter()).toBe(true);
jest.useRealTimers();
});
test('allows call after interval', () => {
jest.useFakeTimers();
const limiter = createRateLimiter(1000);
limiter();
jest.advanceTimersByTime(1001);
expect(limiter()).toBe(true);
jest.useRealTimers();
});
test('uses default interval of 2000ms', () => {
jest.useFakeTimers();
const limiter = createRateLimiter();
limiter();
jest.advanceTimersByTime(1999);
expect(limiter()).toBe(false);
jest.advanceTimersByTime(2);
expect(limiter()).toBe(true);
jest.useRealTimers();
});
test('uses default interval of 2000ms', () => {
jest.useFakeTimers();
const limiter = createRateLimiter();
limiter();
jest.advanceTimersByTime(1999);
expect(limiter()).toBe(false);
jest.advanceTimersByTime(2);
expect(limiter()).toBe(true);
jest.useRealTimers();
});
test('resets after successful call', () => {
jest.useFakeTimers();
const limiter = createRateLimiter(500);
limiter();
jest.advanceTimersByTime(501);
limiter(); // resets the timer
expect(limiter()).toBe(false); // too soon after second call
jest.useRealTimers();
});
test('resets after successful call', () => {
jest.useFakeTimers();
const limiter = createRateLimiter(500);
limiter();
jest.advanceTimersByTime(501);
limiter(); // resets the timer
expect(limiter()).toBe(false); // too soon after second call
jest.useRealTimers();
});
});