fix(lora-loader): preserve repeated spaces inside lora names

Whitespace cleanup in cleanupLoraSyntax() and the autocomplete blur
formatter collapsed all whitespace runs, including inside <lora:...>
tags. A file named 'test -  0021.safetensors' was rewritten to
'test - 0021' in the node text, so runtime file resolution failed.

Protect lora tags with placeholders (or segment splitting) so only
whitespace between entries is normalized; names inside tags are kept
byte-for-byte.
This commit is contained in:
Will Miao
2026-09-07 19:20:15 +08:00
parent 82b34097fb
commit 53fa22f39c
4 changed files with 106 additions and 3 deletions
@@ -0,0 +1,58 @@
import { describe, it, expect, vi } from 'vitest';
const {
API_MODULE,
APP_MODULE,
AUTOCOMPLETE_MODULE,
} = vi.hoisted(() => ({
API_MODULE: new URL('../../../scripts/api.js', import.meta.url).pathname,
APP_MODULE: new URL('../../../scripts/app.js', import.meta.url).pathname,
AUTOCOMPLETE_MODULE: new URL('../../../web/comfyui/autocomplete.js', import.meta.url).pathname,
}));
vi.mock(API_MODULE, () => ({
api: {
fetchApi: vi.fn(),
},
}));
vi.mock(APP_MODULE, () => ({
app: {
canvas: {
ds: { scale: 1 },
},
extensionManager: {
setting: {
get: vi.fn(),
set: vi.fn(),
},
},
registerExtension: vi.fn(),
},
}));
describe('formatAutocompleteTextOnBlur', () => {
it('preserves repeated spaces inside LoRA names', async () => {
const { formatAutocompleteTextOnBlur } = await import(AUTOCOMPLETE_MODULE);
expect(formatAutocompleteTextOnBlur('<lora:test - 0021:1.00>')).toBe(
'<lora:test - 0021:1.00>'
);
});
it('preserves repeated spaces across multiple LoRA entries', async () => {
const { formatAutocompleteTextOnBlur } = await import(AUTOCOMPLETE_MODULE);
expect(
formatAutocompleteTextOnBlur('<lora:test - 0021:1.00>,<lora:a b:0.50>')
).toBe('<lora:test - 0021:1.00>, <lora:a b:0.50>');
});
it('still normalizes whitespace outside LoRA tags', async () => {
const { formatAutocompleteTextOnBlur } = await import(AUTOCOMPLETE_MODULE);
expect(formatAutocompleteTextOnBlur('masterpiece, best quality')).toBe(
'masterpiece, best quality'
);
});
});