fix: normalize Windows backslash paths consistently in frontend path joins
This commit is contained in:
@@ -30,9 +30,9 @@ def _normalized_absolute_path(path_value: str) -> str:
|
||||
def normalize_file_manager_path(path_value: Any) -> str:
|
||||
"""Normalize a local path and recover UI-style separators when necessary.
|
||||
|
||||
The frontend uses backslashes as its canonical subfolder separator. On
|
||||
POSIX, a backslash is a valid filename character, so the literal path is
|
||||
always checked first. It is interpreted as a separator only when the
|
||||
Legacy frontend state may contain backslashes as subfolder separators. On
|
||||
POSIX, a backslash is also a valid filename character, so the literal path
|
||||
is always checked first. It is interpreted as a separator only when the
|
||||
literal path does not exist and the converted path does.
|
||||
"""
|
||||
if not isinstance(path_value, (str, os.PathLike)):
|
||||
|
||||
@@ -927,6 +927,22 @@ test('portable subfolder paths use forward slashes and join to the host path sty
|
||||
joinLocalPath.call(dialog, 'C:\\models\\loras', 'Pony/Styles'),
|
||||
'C:\\models\\loras\\Pony\\Styles'
|
||||
);
|
||||
assert.equal(
|
||||
joinLocalPath.call(dialog, '/', 'models\\Pony'),
|
||||
'/models/Pony'
|
||||
);
|
||||
assert.equal(
|
||||
joinLocalPath.call(dialog, '/models/literal\\name', 'Pony\\Styles'),
|
||||
'/models/literal\\name/Pony/Styles'
|
||||
);
|
||||
assert.equal(
|
||||
joinLocalPath.call(dialog, 'C:\\', 'Pony/Styles'),
|
||||
'C:\\Pony\\Styles'
|
||||
);
|
||||
assert.equal(
|
||||
joinLocalPath.call(dialog, '\\\\server\\share\\', 'Pony/Styles'),
|
||||
'\\\\server\\share\\Pony\\Styles'
|
||||
);
|
||||
});
|
||||
|
||||
test('download subfolder tooltip identifies a folder taken from the workflow model path', () => {
|
||||
|
||||
@@ -1004,13 +1004,19 @@ export const downloadTargetMethods = {
|
||||
},
|
||||
|
||||
joinLocalPath(basePath = '', relativePath = '') {
|
||||
const base = String(basePath || '').replace(/[\/\\]+$/, '');
|
||||
const rawBase = String(basePath || '');
|
||||
const relative = String(relativePath || '').replace(/^[\/\\]+/, '');
|
||||
const usesBackslash = /^[A-Za-z]:\\/.test(rawBase)
|
||||
|| /^\\\\/.test(rawBase)
|
||||
|| (!rawBase.includes('/') && rawBase.includes('\\'));
|
||||
const separator = usesBackslash ? '\\' : '/';
|
||||
const base = rawBase.replace(usesBackslash ? /[\/\\]+$/ : /\/+$/, '')
|
||||
|| (usesBackslash ? (/^\\+$/.test(rawBase) ? '\\' : '') : (/^\/+$/.test(rawBase) ? '/' : ''));
|
||||
if (!base) return this.normalizePathToForward(relative);
|
||||
if (!relative) return base;
|
||||
const separator = base.includes('\\') ? '\\' : '/';
|
||||
const normalizedRelative = relative.replace(/[\/\\]+/g, separator);
|
||||
return `${base}${separator}${normalizedRelative}`;
|
||||
const joiner = base.endsWith(separator) ? '' : separator;
|
||||
return `${base}${joiner}${normalizedRelative}`;
|
||||
},
|
||||
|
||||
getDownloadTargetFolderContext(category = '', subfolder = '', baseDirectory = '') {
|
||||
|
||||
@@ -1533,12 +1533,18 @@ export const missingBrowserMethods = {
|
||||
if (typeof this.joinLocalPath === 'function') {
|
||||
return this.joinLocalPath(basePath, relativePath);
|
||||
}
|
||||
const base = String(basePath || '').replace(/[\/\\]+$/, '');
|
||||
const rawBase = String(basePath || '');
|
||||
const relative = String(relativePath || '').replace(/^[\/\\]+/, '');
|
||||
const usesBackslash = /^[A-Za-z]:\\/.test(rawBase)
|
||||
|| /^\\\\/.test(rawBase)
|
||||
|| (!rawBase.includes('/') && rawBase.includes('\\'));
|
||||
const separator = usesBackslash ? '\\' : '/';
|
||||
const base = rawBase.replace(usesBackslash ? /[\/\\]+$/ : /\/+$/, '')
|
||||
|| (usesBackslash ? (/^\\+$/.test(rawBase) ? '\\' : '') : (/^\/+$/.test(rawBase) ? '/' : ''));
|
||||
if (!base) return relative;
|
||||
if (!relative) return base;
|
||||
const separator = base.includes('\\') ? '\\' : '/';
|
||||
return `${base}${separator}${relative.replace(/[\/\\]+/g, separator)}`;
|
||||
const joiner = base.endsWith(separator) ? '' : separator;
|
||||
return `${base}${joiner}${relative.replace(/[\/\\]+/g, separator)}`;
|
||||
};
|
||||
const buildLocalFolderContext = (folderPath = '', name = 'Folder', category = '') => {
|
||||
const path = String(folderPath || '').trim();
|
||||
|
||||
Reference in New Issue
Block a user