Ensure KefinTweaks urls are properly normalized so that duplicate scripts are never loaded

This commit is contained in:
HighImKevin committed 2026-10-11 02:34:55 -04:00
1 parent a1faf72cc4
commit db257efbfb
1 file changed
+44 -9
+44 -9
View File
@@ -671,11 +671,17 @@
return normalizeRoot(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || ''); return normalizeRoot(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || '');
} }
function resolveAssetUrl(root, relativePath) { /**
* Join kefin root + scripts/ + relativePath, collapsing . / .. for site-absolute roots.
* Shared by live resolveAssetUrl and the baked KefinTweaks-injector joinAssetUrl.
*/
function joinAssetUrlForRoot(resolvedRoot, relativePath) {
if (!relativePath) return null; if (!relativePath) return null;
if (/^https?:\/\//i.test(relativePath)) return relativePath; if (/^https?:\/\//i.test(relativePath)) return relativePath;
const normalizedRoot = normalizeRoot(root); const normalizedRoot = normalizeRoot(resolvedRoot);
if (!normalizedRoot) return null;
const base = normalizedRoot + 'scripts/'; const base = normalizedRoot + 'scripts/';
const joined = (base + relativePath).replace(/\\/g, '/'); const joined = (base + relativePath).replace(/\\/g, '/');
@@ -684,7 +690,7 @@
try { try {
return new URL(relativePath, base).href; return new URL(relativePath, base).href;
} catch (e) { } catch (e) {
/* fall through */ /* fall through to collapse */
} }
} }
@@ -704,6 +710,39 @@
return isSiteAbsolute ? '/' + resolved : resolved; return isSiteAbsolute ? '/' + resolved : resolved;
} }
function resolveAssetUrl(root, relativePath) {
return joinAssetUrlForRoot(root, relativePath);
}
/**
* ES5 joinAssetUrl source for buildInjectorScript (closes over resolvedRoot).
* Must stay algorithmically identical to joinAssetUrlForRoot.
*/
function getJoinAssetUrlRuntimeSource() {
return [
' function joinAssetUrl(relativePath) {',
' if (!relativePath) return null;',
' if (/^https?:\\/\\//i.test(relativePath)) return relativePath;',
' var base = resolvedRoot + \'scripts/\';',
' var joined = (base + relativePath).replace(/\\\\/g, \'/\');',
' if (/^https?:\\/\\//i.test(resolvedRoot)) {',
' try { return new URL(relativePath, base).href; } catch (e) {}',
' }',
' var isSiteAbsolute = joined.charAt(0) === \'/\';',
' var parts = joined.split(\'/\');',
' var stack = [];',
' for (var pi = 0; pi < parts.length; pi++) {',
' var p = parts[pi];',
' if (!p || p === \'.\') continue;',
' if (p === \'..\') { stack.pop(); continue; }',
' stack.push(p);',
' }',
' var resolved = stack.join(\'/\');',
' return isSiteAbsolute ? \'/\' + resolved : resolved;',
' }'
].join('\n');
}
function expandScriptToAssets(scriptDef, root, urlSuffix, thirdParty) { function expandScriptToAssets(scriptDef, root, urlSuffix, thirdParty) {
const assets = []; const assets = [];
const suffix = urlSuffix || ''; const suffix = urlSuffix || '';
@@ -989,12 +1028,7 @@
' var resolvedRoot = String(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || \'\').trim();', ' var resolvedRoot = String(cfg.kefinTweaksRootResolved || cfg.kefinTweaksRoot || \'\').trim();',
' if (!resolvedRoot) return;', ' if (!resolvedRoot) return;',
' if (resolvedRoot.charAt(resolvedRoot.length - 1) !== \'/\') resolvedRoot += \'/\';', ' if (resolvedRoot.charAt(resolvedRoot.length - 1) !== \'/\') resolvedRoot += \'/\';',
' function joinAssetUrl(relativePath) {', getJoinAssetUrlRuntimeSource(),
' if (!relativePath) return null;',
' if (/^https?:\\/\\//i.test(relativePath)) return relativePath;',
' var base = resolvedRoot + \'scripts/\';',
' try { return new URL(relativePath, base).href; } catch (e) { return base + relativePath; }',
' }',
' window.KefinTweaksScriptsPreloaded = true;', ' window.KefinTweaksScriptsPreloaded = true;',
' window.KefinTweaksInjectorStamp = ' + stampJson + ';', ' window.KefinTweaksInjectorStamp = ' + stampJson + ';',
' var SCRIPT_DEFINITIONS_BAKED = ' + defsJson + ';', ' var SCRIPT_DEFINITIONS_BAKED = ' + defsJson + ';',
@@ -1260,6 +1294,7 @@
mergeEnabledScripts: mergeEnabledScripts, mergeEnabledScripts: mergeEnabledScripts,
normalizeRoot: normalizeRoot, normalizeRoot: normalizeRoot,
getResolvedKefinRoot: getResolvedKefinRoot, getResolvedKefinRoot: getResolvedKefinRoot,
joinAssetUrlForRoot: joinAssetUrlForRoot,
resolveAssetUrl: resolveAssetUrl, resolveAssetUrl: resolveAssetUrl,
buildLoadPlan: buildLoadPlan, buildLoadPlan: buildLoadPlan,
buildInjectorScript: buildInjectorScript, buildInjectorScript: buildInjectorScript,