{"version":3,"file":"import-map-overrides.js","sources":["../src/util/includes.js","../src/util/url-parameter.js","../src/api/js-api.js","../src/util/string-regex.js","../node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js","../node_modules/.pnpm/preact@10.5.7/node_modules/preact/dist/preact.module.js","../src/ui/list/module-dialog.component.js","../src/ui/list/external-importmap-dialog.component.js","../src/ui/dev-lib-overrides.component.js","../src/ui/list/list.component.js","../src/ui/popup.component.js","../src/ui/full-ui.component.js","../src/ui/custom-elements.js"],"sourcesContent":["export function includes(obj, item) {\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n if (obj[i] === item) {\n return true;\n }\n }\n return false;\n } else if (typeof obj === \"string\") {\n return obj.indexOf(item) >= 0;\n } else {\n throw Error(`Can't call includes on ${typeof obj}`);\n }\n}\n","// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript\nexport function getParameterByName(name, url = window.location.href) {\n name = name.replace(/[\\[\\]]/g, \"\\\\$&\");\n var regex = new RegExp(\"[?&]\" + name + \"(=([^&#]*)|&|#|$)\"),\n results = regex.exec(url);\n if (!results) return null;\n if (!results[2]) return \"\";\n return decodeURIComponent(results[2].replace(/\\+/g, \" \"));\n}\n","import { escapeStringRegexp } from \"../util/string-regex\";\nimport { includes } from \"../util/includes.js\";\nimport { getParameterByName } from \"../util/url-parameter\";\n\nconst localStoragePrefix = \"import-map-override:\";\nconst disabledOverridesLocalStorageKey = \"import-map-overrides-disabled\";\nconst externalOverridesLocalStorageKey = \"import-map-overrides-external-maps\";\nconst overrideAttribute = \"data-is-importmap-override\";\nconst domainsMeta = \"import-map-overrides-domains\";\nconst allowListPrefix = \"allowlist:\";\nconst denyListPrefix = \"denylist:\";\nexport const queryParamOverridesName = \"imo\";\n\nconst portRegex = /^\\d+$/g;\n\nconst importMapMetaElement = document.querySelector(\n 'meta[name=\"importmap-type\"]'\n);\n\nconst domainsElement = document.querySelector(`meta[name=\"${domainsMeta}\"]`);\n\nconst externalOverrideMapPromises = {};\n\nexport const importMapType = importMapMetaElement\n ? importMapMetaElement.getAttribute(\"content\")\n : \"importmap\";\n\nexport let isDisabled;\n\nif (domainsElement) {\n const content = domainsElement.getAttribute(\"content\");\n if (!content) {\n console.warn(`Invalid ${domainsMeta} meta element - content required.`);\n }\n\n const matchHostname = (domain) =>\n new RegExp(escapeStringRegexp(domain).replace(\"\\\\*\", \".+\")).test(\n window.location.hostname\n );\n\n if (content.indexOf(allowListPrefix) === 0) {\n const allowedDomains = content.slice(allowListPrefix.length).split(\",\");\n isDisabled = !allowedDomains.some(matchHostname);\n } else if (content.indexOf(denyListPrefix) === 0) {\n const deniedDomains = content.slice(denyListPrefix.length).split(\",\");\n isDisabled = deniedDomains.some(matchHostname);\n } else {\n // eslint-disable-next-line no-console\n console.log(\n `Invalid ${domainsMeta} meta content attribute - must start with ${allowListPrefix} or ${denyListPrefix}`\n );\n }\n} else {\n isDisabled = false;\n}\n\nif (!canAccessLocalStorage()) {\n console.warn(\n \"Disabling import-map-overrides, since local storage is not readable\"\n );\n isDisabled = true;\n}\n\nif (!isDisabled) {\n init();\n}\n\nfunction init() {\n const serverOverrides = importMapMetaElement\n ? importMapMetaElement.hasAttribute(\"server-cookie\")\n : false;\n const serverOnly = importMapMetaElement\n ? importMapMetaElement.hasAttribute(\"server-only\")\n : false;\n\n let defaultMapPromise;\n\n window.importMapOverrides = {\n addOverride(moduleName, url) {\n if (portRegex.test(url)) {\n url = imo.getUrlFromPort(moduleName, url);\n }\n const key = localStoragePrefix + moduleName;\n localStorage.setItem(key, url);\n if (serverOverrides) {\n document.cookie = `${key}=${url}`;\n }\n fireChangedEvent();\n return imo.getOverrideMap();\n },\n getOverrideMap(includeDisabled = false) {\n const overrides = createEmptyImportMap();\n const disabledOverrides = imo.getDisabledOverrides();\n\n const setOverride = (moduleName, path) => {\n if (includeDisabled || !(disabledOverrides.indexOf(moduleName) >= 0)) {\n overrides.imports[moduleName] = path;\n }\n };\n\n // get from localstorage\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key.indexOf(localStoragePrefix) === 0) {\n setOverride(\n key.slice(localStoragePrefix.length),\n localStorage.getItem(key)\n );\n }\n }\n\n // get from url if query param exist\n const queryParam = getParameterByName(\n queryParamOverridesName,\n window.parent ? window.parent.location.href : window.location.href\n );\n\n if (queryParam) {\n let queryParamImportMap;\n try {\n queryParamImportMap = JSON.parse(queryParam);\n } catch (e) {\n throw Error(\n `Invalid importMap query param - text content must be json`\n );\n }\n Object.keys(queryParamImportMap.imports).forEach((moduleName) => {\n setOverride(moduleName, queryParamImportMap.imports[moduleName]);\n });\n }\n\n return overrides;\n },\n removeOverride(moduleName) {\n const key = localStoragePrefix + moduleName;\n const hasItem = localStorage.getItem(key) !== null;\n localStorage.removeItem(key);\n if (serverOverrides) {\n document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;\n }\n imo.enableOverride(moduleName);\n fireChangedEvent();\n return hasItem;\n },\n resetOverrides() {\n Object.keys(imo.getOverrideMap(true).imports).forEach((moduleName) => {\n imo.removeOverride(moduleName);\n });\n localStorage.removeItem(disabledOverridesLocalStorageKey);\n localStorage.removeItem(externalOverridesLocalStorageKey);\n fireChangedEvent();\n return imo.getOverrideMap();\n },\n hasOverrides() {\n return Object.keys(imo.getOverrideMap().imports).length > 0;\n },\n getUrlFromPort(moduleName, port) {\n const fileName = moduleName.replace(/@/g, \"\").replace(/\\//g, \"-\");\n return `//localhost:${port}/${fileName}.js`;\n },\n enableUI() {\n const customElementName = \"import-map-overrides-full\";\n const showWhenLocalStorage = \"show-when-local-storage\";\n let customElement = document.querySelector(customElementName);\n\n if (!customElement) {\n customElement = document.createElement(customElementName);\n customElement.setAttribute(showWhenLocalStorage, \"true\");\n document.body.appendChild(customElement);\n }\n\n const localStorageKey = customElement.getAttribute(showWhenLocalStorage);\n if (localStorageKey) {\n localStorage.setItem(localStorageKey, true);\n customElement.renderWithPreact();\n }\n },\n mergeImportMap(originalMap, newMap) {\n const outMap = createEmptyImportMap();\n for (let i in originalMap.imports) {\n outMap.imports[i] = originalMap.imports[i];\n }\n for (let i in newMap.imports) {\n outMap.imports[i] = newMap.imports[i];\n }\n for (let i in originalMap.scopes) {\n outMap.scopes[i] = originalMap.scopes[i];\n }\n for (let i in newMap.scopes) {\n outMap.scopes[i] = newMap.scopes[i];\n }\n return outMap;\n },\n getDefaultMap() {\n return (\n defaultMapPromise ||\n (defaultMapPromise = Array.prototype.reduce.call(\n document.querySelectorAll(\n `script[type=\"${importMapType}\"], script[type=\"overridable-importmap\"]`\n ),\n (promise, scriptEl) => {\n if (scriptEl.hasAttribute(overrideAttribute)) {\n return promise;\n } else {\n let nextPromise;\n if (scriptEl.src) {\n nextPromise = fetchExternalMap(scriptEl.src);\n } else {\n nextPromise = Promise.resolve(JSON.parse(scriptEl.textContent));\n }\n\n return Promise.all([\n promise,\n nextPromise,\n ]).then(([originalMap, newMap]) =>\n imo.mergeImportMap(originalMap, newMap)\n );\n }\n },\n Promise.resolve(createEmptyImportMap())\n ))\n );\n },\n getCurrentPageMap() {\n return Promise.all([\n imo.getDefaultMap(),\n imo.getExternalOverrideMap(imo.getCurrentPageExternalOverrides()),\n ]).then(([defaultMap, externalOverridesMap]) => {\n return imo.mergeImportMap(\n imo.mergeImportMap(defaultMap, externalOverridesMap),\n initialOverrideMap\n );\n });\n },\n getCurrentPageExternalOverrides() {\n const currentPageExternalOverrides = [];\n document\n .querySelectorAll(\n `[${overrideAttribute}]:not([id=\"import-map-overrides\"])`\n )\n .forEach((externalOverrideEl) => {\n currentPageExternalOverrides.push(externalOverrideEl.src);\n });\n return currentPageExternalOverrides;\n },\n getNextPageMap() {\n return Promise.all([\n imo.getDefaultMap(),\n imo.getExternalOverrideMap(),\n ]).then(([defaultMap, externalOverridesMap]) => {\n return imo.mergeImportMap(\n imo.mergeImportMap(defaultMap, externalOverridesMap),\n imo.getOverrideMap()\n );\n });\n },\n disableOverride(moduleName) {\n const disabledOverrides = imo.getDisabledOverrides();\n if (!includes(disabledOverrides, moduleName)) {\n localStorage.setItem(\n disabledOverridesLocalStorageKey,\n JSON.stringify(disabledOverrides.concat(moduleName))\n );\n fireChangedEvent();\n return true;\n } else {\n return false;\n }\n },\n enableOverride(moduleName) {\n const disabledOverrides = imo.getDisabledOverrides();\n const index = disabledOverrides.indexOf(moduleName);\n if (index >= 0) {\n disabledOverrides.splice(index, 1);\n localStorage.setItem(\n disabledOverridesLocalStorageKey,\n JSON.stringify(disabledOverrides)\n );\n fireChangedEvent();\n return true;\n } else {\n return false;\n }\n },\n getDisabledOverrides() {\n const disabledOverrides = localStorage.getItem(\n disabledOverridesLocalStorageKey\n );\n return disabledOverrides ? JSON.parse(disabledOverrides) : [];\n },\n isDisabled(moduleName) {\n return includes(imo.getDisabledOverrides(), moduleName);\n },\n getExternalOverrides() {\n let localStorageValue = localStorage.getItem(\n externalOverridesLocalStorageKey\n );\n return localStorageValue ? JSON.parse(localStorageValue).sort() : [];\n },\n addExternalOverride(url) {\n url = new URL(url, document.baseURI).href;\n const overrides = imo.getExternalOverrides();\n if (includes(overrides, url)) {\n return false;\n } else {\n localStorage.setItem(\n externalOverridesLocalStorageKey,\n JSON.stringify(overrides.concat(url))\n );\n fireChangedEvent();\n return true;\n }\n },\n removeExternalOverride(url) {\n const overrides = imo.getExternalOverrides();\n if (includes(overrides, url)) {\n localStorage.setItem(\n externalOverridesLocalStorageKey,\n JSON.stringify(overrides.filter((override) => override !== url))\n );\n fireChangedEvent();\n return true;\n } else {\n return false;\n }\n },\n getExternalOverrideMap(externalOverrides = imo.getExternalOverrides()) {\n return externalOverrides.reduce((result, externalOverride) => {\n const fetchPromise =\n externalOverrideMapPromises[externalOverride] ||\n (externalOverrideMapPromises[externalOverride] = fetchExternalMap(\n externalOverride\n ));\n return Promise.all([result, fetchPromise]).then(\n ([firstMap, secondMap]) => {\n return imo.mergeImportMap(firstMap, secondMap);\n }\n );\n }, Promise.resolve(createEmptyImportMap()));\n },\n isExternalMapValid(importMapUrl) {\n const promise =\n externalOverrideMapPromises[importMapUrl] ||\n (externalOverrideMapPromises[importMapUrl] = fetchExternalMap(\n importMapUrl\n ));\n return promise.then(() =>\n includes(imo.invalidExternalMaps, importMapUrl)\n );\n },\n invalidExternalMaps: [],\n };\n\n const imo = window.importMapOverrides;\n\n let canFireCustomEvents = true;\n try {\n if (CustomEvent) {\n new CustomEvent(\"a\");\n } else {\n canFireCustomEvents = false;\n }\n } catch (err) {\n canFireCustomEvents = false;\n }\n\n function fireChangedEvent() {\n // Set timeout so that event fires after the change has totally finished\n setTimeout(() => {\n if (canFireCustomEvents) {\n window.dispatchEvent(new CustomEvent(\"import-map-overrides:change\"));\n }\n });\n }\n\n const initialOverrideMap = imo.getOverrideMap();\n const initialExternalOverrideMaps = imo.getExternalOverrides();\n\n let referenceNode;\n\n if (!serverOnly) {\n const overridableImportMap = document.querySelector(\n 'script[type=\"overridable-importmap\"]'\n );\n\n referenceNode = overridableImportMap;\n\n if (!referenceNode) {\n const importMaps = document.querySelectorAll(\n `script[type=\"${importMapType}\"]`\n );\n referenceNode = importMaps ? importMaps[importMaps.length - 1] : null;\n }\n\n if (overridableImportMap) {\n if (overridableImportMap.src) {\n throw Error(\n `import-map-overrides: external import maps with type=\"overridable-importmap\" are not supported`\n );\n }\n let originalMap;\n try {\n originalMap = JSON.parse(overridableImportMap.textContent);\n } catch (e) {\n throw Error(\n `Invalid