@remix-run/multiple-import-maps-polyfill 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +43 -0
- package/README.md +105 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/core.d.ts +6 -0
- package/dist/lib/core.d.ts.map +1 -0
- package/dist/lib/core.js +470 -0
- package/dist/lib/env.d.ts +12 -0
- package/dist/lib/env.d.ts.map +1 -0
- package/dist/lib/env.js +33 -0
- package/dist/lib/features.d.ts +4 -0
- package/dist/lib/features.d.ts.map +1 -0
- package/dist/lib/features.js +70 -0
- package/dist/lib/native-resolve.d.ts +2 -0
- package/dist/lib/native-resolve.d.ts.map +1 -0
- package/dist/lib/native-resolve.js +59 -0
- package/dist/lib/polyfill.d.ts +41 -0
- package/dist/lib/polyfill.d.ts.map +1 -0
- package/dist/lib/polyfill.js +77 -0
- package/dist/lib/resolve.d.ts +16 -0
- package/dist/lib/resolve.d.ts.map +1 -0
- package/dist/lib/resolve.js +167 -0
- package/dist/lib/self.d.ts +3 -0
- package/dist/lib/self.d.ts.map +1 -0
- package/dist/lib/self.js +2 -0
- package/dist/lib/trusted-types.d.ts +15 -0
- package/dist/lib/trusted-types.d.ts.map +1 -0
- package/dist/lib/trusted-types.js +21 -0
- package/package.json +44 -5
- package/src/index.ts +6 -0
- package/src/lib/core.ts +616 -0
- package/src/lib/env.ts +37 -0
- package/src/lib/features.ts +80 -0
- package/src/lib/native-resolve.ts +69 -0
- package/src/lib/polyfill.ts +89 -0
- package/src/lib/resolve.ts +225 -0
- package/src/lib/self.ts +2 -0
- package/src/lib/trusted-types.ts +49 -0
package/dist/lib/env.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { self } from './self.js';
|
|
10
|
+
export const hasDocument = typeof document !== 'undefined';
|
|
11
|
+
export const dynamicImport = (u) => import(__rewriteRelativeImportExtension(u));
|
|
12
|
+
export const defaultFetchOpts = { credentials: 'same-origin' };
|
|
13
|
+
export const version = `remix/multiple-import-maps-polyfill:${Date.now()}:${Math.random()}`;
|
|
14
|
+
export let nonce = '';
|
|
15
|
+
if (hasDocument) {
|
|
16
|
+
let nonceElement = document.querySelector('script[nonce]');
|
|
17
|
+
if (nonceElement)
|
|
18
|
+
nonce = nonceElement.nonce || nonceElement.getAttribute('nonce') || '';
|
|
19
|
+
}
|
|
20
|
+
export const baseUrl = hasDocument
|
|
21
|
+
? document.baseURI
|
|
22
|
+
: typeof location !== 'undefined'
|
|
23
|
+
? `${location.protocol}//${location.host}${location.pathname.includes('/')
|
|
24
|
+
? location.pathname.slice(0, location.pathname.lastIndexOf('/') + 1)
|
|
25
|
+
: location.pathname}`
|
|
26
|
+
: 'about:blank';
|
|
27
|
+
export const createBlob = (source) => URL.createObjectURL(new Blob([source], { type: 'text/javascript' }));
|
|
28
|
+
const dispatchError = (error) => self.dispatchEvent(Object.assign(new Event('error'), { error }));
|
|
29
|
+
export const throwError = (err) => {
|
|
30
|
+
;
|
|
31
|
+
(self.reportError || dispatchError)(err);
|
|
32
|
+
};
|
|
33
|
+
export const fromParent = (parent) => (parent ? ` imported from ${parent}` : '');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../src/lib/features.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB,SAE9B,CAAA;AACD,eAAO,IAAI,0BAA0B,SAAQ,CAAA;AAE7C,eAAO,MAAM,uBAAuB,EAAE,OAAO,CAAC,IAAI,CAqE9B,CAAA"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { hasDocument, nonce, version } from './env.js';
|
|
2
|
+
import { maybeTrustedInnerHTML, maybeTrustedScript, policy } from './trusted-types.js';
|
|
3
|
+
const supports = hasDocument ? HTMLScriptElement.supports : undefined;
|
|
4
|
+
export const supportsImportMaps = Boolean(supports && supports.name === 'supports' && supports('importmap'));
|
|
5
|
+
export let supportsMultipleImportMaps = false;
|
|
6
|
+
export const featureDetectionPromise = (async function () {
|
|
7
|
+
if (!hasDocument || !supportsImportMaps)
|
|
8
|
+
return;
|
|
9
|
+
let msgTag = `s${version}`;
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
let iframe = document.createElement('iframe');
|
|
12
|
+
iframe.style.display = 'none';
|
|
13
|
+
iframe.setAttribute('nonce', nonce);
|
|
14
|
+
let settled = false;
|
|
15
|
+
let timeout = setTimeout(done, 1000);
|
|
16
|
+
function done() {
|
|
17
|
+
if (settled)
|
|
18
|
+
return;
|
|
19
|
+
settled = true;
|
|
20
|
+
clearTimeout(timeout);
|
|
21
|
+
if (iframe.parentNode === document.head)
|
|
22
|
+
document.head.removeChild(iframe);
|
|
23
|
+
window.removeEventListener('message', cb, false);
|
|
24
|
+
resolve();
|
|
25
|
+
}
|
|
26
|
+
function cb({ data }) {
|
|
27
|
+
if (!Array.isArray(data) || data[0] !== msgTag)
|
|
28
|
+
return;
|
|
29
|
+
supportsMultipleImportMaps = data[2] === true;
|
|
30
|
+
done();
|
|
31
|
+
}
|
|
32
|
+
window.addEventListener('message', cb, false);
|
|
33
|
+
let importMapTest = `<script nonce=${nonce || ''}>${policy
|
|
34
|
+
? 't=(window.trustedTypes||window.TrustedTypes).createPolicy("remix/multiple-import-maps-polyfill",{createScript:s=>s});'
|
|
35
|
+
: ''}b=s=>URL.createObjectURL(new Blob([s],{type:'text/javascript'}));c=u=>import(u).then(()=>true,()=>false);i=innerText=>document.head.appendChild(Object.assign(document.createElement('script'),{type:'importmap',nonce:"${nonce}",text:${policy ? 't.createScript(innerText)' : 'innerText'}}));i(\`{"imports":{"x":"\${b('')}"}}\`);i(\`{"imports":{"y":"\${b('')}"}}\`);Promise.all([true,c('y')]).then(a=>parent.postMessage(['${msgTag}'].concat(a),'*'))<${''}/script>`;
|
|
36
|
+
// Safari will call onload eagerly on head injection, but we don't want the Wechat
|
|
37
|
+
// path to trigger before setting srcdoc, therefore we track the timing
|
|
38
|
+
let readyForOnload = false, onloadCalledWhileNotReady = false;
|
|
39
|
+
function doOnload() {
|
|
40
|
+
if (!readyForOnload) {
|
|
41
|
+
onloadCalledWhileNotReady = true;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// WeChat browser doesn't support setting srcdoc scripts
|
|
45
|
+
// But iframe sandboxes don't support contentDocument so we do this as a fallback
|
|
46
|
+
let doc = iframe.contentDocument;
|
|
47
|
+
if (doc && doc.head.childNodes.length === 0) {
|
|
48
|
+
let script = doc.createElement('script');
|
|
49
|
+
if (nonce)
|
|
50
|
+
script.setAttribute('nonce', nonce);
|
|
51
|
+
script.innerText = maybeTrustedScript(importMapTest.slice(15 + (nonce ? nonce.length : 0), -9));
|
|
52
|
+
doc.head.appendChild(script);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
iframe.onload = doOnload;
|
|
56
|
+
// WeChat browser requires append before setting srcdoc
|
|
57
|
+
document.head.appendChild(iframe);
|
|
58
|
+
// setting srcdoc is not supported in React native webviews on iOS
|
|
59
|
+
// setting src to a blob URL results in a navigation event in webviews
|
|
60
|
+
// document.write gives usability warnings
|
|
61
|
+
readyForOnload = true;
|
|
62
|
+
if ('srcdoc' in iframe)
|
|
63
|
+
iframe.srcdoc = maybeTrustedInnerHTML(importMapTest);
|
|
64
|
+
else
|
|
65
|
+
iframe.contentDocument.write(importMapTest);
|
|
66
|
+
// retrigger onload for Safari only if necessary
|
|
67
|
+
if (onloadCalledWhileNotReady)
|
|
68
|
+
doOnload();
|
|
69
|
+
});
|
|
70
|
+
})().catch(() => { });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-resolve.d.ts","sourceRoot":"","sources":["../../src/lib/native-resolve.ts"],"names":[],"mappings":"AAoBA,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAO7E"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { asURL, resolveAndComposeImportMap, resolveIfNotPlainOrUrl, resolveImportMap, } from './resolve.js';
|
|
2
|
+
let importMap = { imports: {}, scopes: {}, integrity: {} };
|
|
3
|
+
const processedScripts = new WeakSet();
|
|
4
|
+
const selector = 'script[type="importmap"]';
|
|
5
|
+
const observer = typeof document === 'undefined' ? undefined : new MutationObserver(processMutations);
|
|
6
|
+
if (observer) {
|
|
7
|
+
observer.observe(document, { childList: true });
|
|
8
|
+
observer.observe(document.head, { childList: true });
|
|
9
|
+
processImportMaps();
|
|
10
|
+
}
|
|
11
|
+
export function resolveModuleUrl(specifier, parentUrl) {
|
|
12
|
+
if (observer)
|
|
13
|
+
processMutations(observer.takeRecords());
|
|
14
|
+
processImportMaps();
|
|
15
|
+
let normalized = resolveIfNotPlainOrUrl(specifier, parentUrl) || asURL(specifier) || specifier;
|
|
16
|
+
let resolved = resolveImportMap(importMap, normalized, parentUrl);
|
|
17
|
+
if (!resolved)
|
|
18
|
+
throw new TypeError(`Unable to resolve specifier '${specifier}' from ${parentUrl}`);
|
|
19
|
+
return resolved;
|
|
20
|
+
}
|
|
21
|
+
function processImportMaps() {
|
|
22
|
+
for (let script of document.querySelectorAll(selector))
|
|
23
|
+
processImportMap(script);
|
|
24
|
+
}
|
|
25
|
+
function processMutations(mutations) {
|
|
26
|
+
for (let mutation of mutations) {
|
|
27
|
+
for (let node of mutation.addedNodes) {
|
|
28
|
+
if (node instanceof HTMLScriptElement && node.matches(selector))
|
|
29
|
+
processImportMap(node);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function processImportMap(script) {
|
|
34
|
+
if (processedScripts.has(script))
|
|
35
|
+
return;
|
|
36
|
+
processedScripts.add(script);
|
|
37
|
+
if (script.src)
|
|
38
|
+
return;
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(script.textContent ?? '');
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!isRecord(parsed))
|
|
47
|
+
return;
|
|
48
|
+
let scopes = {};
|
|
49
|
+
if (isRecord(parsed.scopes)) {
|
|
50
|
+
for (let [scope, entries] of Object.entries(parsed.scopes)) {
|
|
51
|
+
if (isRecord(entries))
|
|
52
|
+
scopes[scope] = entries;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
importMap = resolveAndComposeImportMap({ imports: isRecord(parsed.imports) ? parsed.imports : undefined, scopes }, script.baseURI, importMap);
|
|
56
|
+
}
|
|
57
|
+
function isRecord(value) {
|
|
58
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
59
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
type ModuleNamespace = Record<string, unknown>;
|
|
2
|
+
/**
|
|
3
|
+
* Detects whether the current document can install multiple import maps.
|
|
4
|
+
*
|
|
5
|
+
* Returns `true` only when an isolated feature test verifies support. If the test cannot run or
|
|
6
|
+
* complete under the document's Content Security Policy, this returns `false`. When the polyfill
|
|
7
|
+
* is required, its runtime begins loading in the background.
|
|
8
|
+
*
|
|
9
|
+
* @returns Whether multiple import map support was verified.
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectMultipleImportMapSupport(): Promise<boolean>;
|
|
12
|
+
/**
|
|
13
|
+
* Loads a JavaScript module, using the multiple import map polyfill when required.
|
|
14
|
+
*
|
|
15
|
+
* @param specifier Module specifier to load.
|
|
16
|
+
* @param parentUrl URL to resolve the specifier from. (default: `document.baseURI`)
|
|
17
|
+
* @returns The loaded module namespace.
|
|
18
|
+
*/
|
|
19
|
+
export declare function importModule(specifier: string, parentUrl?: string): Promise<ModuleNamespace>;
|
|
20
|
+
/**
|
|
21
|
+
* Loads a JavaScript module through the polyfill using every import map currently installed in the
|
|
22
|
+
* document. This function does not detect native multiple import map support.
|
|
23
|
+
*
|
|
24
|
+
* @param specifier Module specifier to load.
|
|
25
|
+
* @param parentUrl URL to resolve the specifier from. (default: `document.baseURI`)
|
|
26
|
+
* @returns The loaded module namespace.
|
|
27
|
+
*/
|
|
28
|
+
export declare function importShim(specifier: string, parentUrl?: string): Promise<ModuleNamespace>;
|
|
29
|
+
/**
|
|
30
|
+
* Fetches one or more JavaScript modules through the polyfill for a later polyfilled import. This
|
|
31
|
+
* function does not use native module preloads.
|
|
32
|
+
*
|
|
33
|
+
* Preload failures are ignored. A later import reports the failure if the module is required.
|
|
34
|
+
*
|
|
35
|
+
* @param specifiers Module specifier or specifiers to preload.
|
|
36
|
+
* @param parentUrl URL to resolve the specifiers from. (default: `document.baseURI`)
|
|
37
|
+
* @returns A promise that settles after all module fetches have completed.
|
|
38
|
+
*/
|
|
39
|
+
export declare function preloadShim(specifiers: string | readonly string[], parentUrl?: string): Promise<void>;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=polyfill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polyfill.d.ts","sourceRoot":"","sources":["../../src/lib/polyfill.ts"],"names":[],"mappings":"AAGA,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAgB9C;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,IAAI,OAAO,CAAC,OAAO,CAAC,CAEjE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,MAAyB,GACnC,OAAO,CAAC,eAAe,CAAC,CAG1B;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,GAAE,MAAyB,GACnC,OAAO,CAAC,eAAe,CAAC,CAG1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EACtC,SAAS,GAAE,MAAyB,GACnC,OAAO,CAAC,IAAI,CAAC,CAKf"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { featureDetectionPromise, supportsMultipleImportMaps } from './features.js';
|
|
10
|
+
import { resolveModuleUrl } from './native-resolve.js';
|
|
11
|
+
let runtimePromise;
|
|
12
|
+
const multipleImportMapSupportPromise = featureDetectionPromise.then(() => {
|
|
13
|
+
let supported = supportsMultipleImportMaps;
|
|
14
|
+
// A later import observes the cached rejection; the background warm-up must not be unhandled.
|
|
15
|
+
if (!supported && typeof document !== 'undefined')
|
|
16
|
+
void getRuntime().catch(() => { });
|
|
17
|
+
return supported;
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Detects whether the current document can install multiple import maps.
|
|
21
|
+
*
|
|
22
|
+
* Returns `true` only when an isolated feature test verifies support. If the test cannot run or
|
|
23
|
+
* complete under the document's Content Security Policy, this returns `false`. When the polyfill
|
|
24
|
+
* is required, its runtime begins loading in the background.
|
|
25
|
+
*
|
|
26
|
+
* @returns Whether multiple import map support was verified.
|
|
27
|
+
*/
|
|
28
|
+
export function detectMultipleImportMapSupport() {
|
|
29
|
+
return multipleImportMapSupportPromise;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Loads a JavaScript module, using the multiple import map polyfill when required.
|
|
33
|
+
*
|
|
34
|
+
* @param specifier Module specifier to load.
|
|
35
|
+
* @param parentUrl URL to resolve the specifier from. (default: `document.baseURI`)
|
|
36
|
+
* @returns The loaded module namespace.
|
|
37
|
+
*/
|
|
38
|
+
export async function importModule(specifier, parentUrl = document.baseURI) {
|
|
39
|
+
if (await detectMultipleImportMapSupport())
|
|
40
|
+
return import(__rewriteRelativeImportExtension(resolveModuleUrl(specifier, parentUrl)));
|
|
41
|
+
return importShim(specifier, parentUrl);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Loads a JavaScript module through the polyfill using every import map currently installed in the
|
|
45
|
+
* document. This function does not detect native multiple import map support.
|
|
46
|
+
*
|
|
47
|
+
* @param specifier Module specifier to load.
|
|
48
|
+
* @param parentUrl URL to resolve the specifier from. (default: `document.baseURI`)
|
|
49
|
+
* @returns The loaded module namespace.
|
|
50
|
+
*/
|
|
51
|
+
export async function importShim(specifier, parentUrl = document.baseURI) {
|
|
52
|
+
let runtime = await getRuntime();
|
|
53
|
+
return runtime.importShim(specifier, parentUrl);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Fetches one or more JavaScript modules through the polyfill for a later polyfilled import. This
|
|
57
|
+
* function does not use native module preloads.
|
|
58
|
+
*
|
|
59
|
+
* Preload failures are ignored. A later import reports the failure if the module is required.
|
|
60
|
+
*
|
|
61
|
+
* @param specifiers Module specifier or specifiers to preload.
|
|
62
|
+
* @param parentUrl URL to resolve the specifiers from. (default: `document.baseURI`)
|
|
63
|
+
* @returns A promise that settles after all module fetches have completed.
|
|
64
|
+
*/
|
|
65
|
+
export async function preloadShim(specifiers, parentUrl = document.baseURI) {
|
|
66
|
+
try {
|
|
67
|
+
let runtime = await getRuntime();
|
|
68
|
+
await runtime.preloadShim(specifiers, parentUrl);
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
71
|
+
}
|
|
72
|
+
async function getRuntime() {
|
|
73
|
+
runtimePromise ??= import('./core.js');
|
|
74
|
+
let runtime = await runtimePromise;
|
|
75
|
+
runtime.registerNativeModule(import.meta.url);
|
|
76
|
+
return runtime;
|
|
77
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ImportMap {
|
|
2
|
+
imports: Record<string, string | null>;
|
|
3
|
+
scopes: Record<string, Record<string, string | null>>;
|
|
4
|
+
integrity: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
export interface ImportMapJson {
|
|
7
|
+
imports?: Record<string, unknown>;
|
|
8
|
+
scopes?: Record<string, Record<string, unknown>>;
|
|
9
|
+
integrity?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export declare const asURL: (url: string) => string | undefined;
|
|
12
|
+
export declare const resolveUrl: (relUrl: string, parentUrl: string) => string;
|
|
13
|
+
export declare const resolveIfNotPlainOrUrl: (relUrl: string, parentUrl: string) => string | undefined;
|
|
14
|
+
export declare const resolveAndComposeImportMap: (json: ImportMapJson, baseUrl: string, parentMap: ImportMap) => ImportMap;
|
|
15
|
+
export declare const resolveImportMap: (importMap: ImportMap, resolvedOrPlain: string, parentUrl: string) => string | false | undefined;
|
|
16
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/lib/resolve.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAA;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAA;IACrD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,eAAO,MAAM,KAAK,QAAS,MAAM,KAAG,MAAM,GAAG,SAI5C,CAAA;AAED,eAAO,MAAM,UAAU,WAAY,MAAM,aAAa,MAAM,KAAG,MAGT,CAAA;AAEtD,eAAO,MAAM,sBAAsB,WAAY,MAAM,aAAa,MAAM,KAAG,MAAM,GAAG,SAsFnF,CAAA;AAED,eAAO,MAAM,0BAA0B,SAC/B,aAAa,WACV,MAAM,aACJ,SAAS,KACnB,SAyBF,CAAA;AAoBD,eAAO,MAAM,gBAAgB,cAChB,SAAS,mBACH,MAAM,aACZ,MAAM,KAChB,MAAM,GAAG,KAAK,GAAG,SAWnB,CAAA"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const backslashRegEx = /\\/g;
|
|
2
|
+
export const asURL = (url) => {
|
|
3
|
+
try {
|
|
4
|
+
if (url.indexOf(':') !== -1)
|
|
5
|
+
return new URL(url).href;
|
|
6
|
+
}
|
|
7
|
+
catch (_) { }
|
|
8
|
+
};
|
|
9
|
+
export const resolveUrl = (relUrl, parentUrl) => (resolveIfNotPlainOrUrl(relUrl, parentUrl) ||
|
|
10
|
+
asURL(relUrl) ||
|
|
11
|
+
resolveIfNotPlainOrUrl('./' + relUrl, parentUrl));
|
|
12
|
+
export const resolveIfNotPlainOrUrl = (relUrl, parentUrl) => {
|
|
13
|
+
let hIdx = parentUrl.indexOf('#'), qIdx = parentUrl.indexOf('?');
|
|
14
|
+
if (hIdx + qIdx > -2)
|
|
15
|
+
parentUrl = parentUrl.slice(0, hIdx === -1 ? qIdx : qIdx === -1 || qIdx > hIdx ? hIdx : qIdx);
|
|
16
|
+
if (relUrl.indexOf('\\') !== -1)
|
|
17
|
+
relUrl = relUrl.replace(backslashRegEx, '/');
|
|
18
|
+
// protocol-relative
|
|
19
|
+
if (relUrl[0] === '/' && relUrl[1] === '/') {
|
|
20
|
+
return parentUrl.slice(0, parentUrl.indexOf(':') + 1) + relUrl;
|
|
21
|
+
}
|
|
22
|
+
// relative-url
|
|
23
|
+
else if ((relUrl[0] === '.' &&
|
|
24
|
+
(relUrl[1] === '/' ||
|
|
25
|
+
(relUrl[1] === '.' && (relUrl[2] === '/' || (relUrl.length === 2 && (relUrl += '/')))) ||
|
|
26
|
+
(relUrl.length === 1 && (relUrl += '/')))) ||
|
|
27
|
+
relUrl[0] === '/') {
|
|
28
|
+
let parentProtocol = parentUrl.slice(0, parentUrl.indexOf(':') + 1);
|
|
29
|
+
if (parentProtocol === 'blob:') {
|
|
30
|
+
throw new TypeError(`Failed to resolve module specifier "${relUrl}". Invalid relative url or base scheme isn't hierarchical.`);
|
|
31
|
+
}
|
|
32
|
+
// Disabled, but these cases will give inconsistent results for deep backtracking
|
|
33
|
+
//if (parentUrl[parentProtocol.length] !== '/')
|
|
34
|
+
// throw new Error('Cannot resolve');
|
|
35
|
+
// read pathname from parent URL
|
|
36
|
+
// pathname taken to be part after leading "/"
|
|
37
|
+
let pathname;
|
|
38
|
+
if (parentUrl[parentProtocol.length + 1] === '/') {
|
|
39
|
+
// resolving to a :// so we need to read out the auth and host
|
|
40
|
+
if (parentProtocol !== 'file:') {
|
|
41
|
+
pathname = parentUrl.slice(parentProtocol.length + 2);
|
|
42
|
+
pathname = pathname.slice(pathname.indexOf('/') + 1);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
pathname = parentUrl.slice(8);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// resolving to :/ so pathname is the /... part
|
|
50
|
+
pathname = parentUrl.slice(parentProtocol.length + Number(parentUrl[parentProtocol.length] === '/'));
|
|
51
|
+
}
|
|
52
|
+
if (relUrl[0] === '/')
|
|
53
|
+
return parentUrl.slice(0, parentUrl.length - pathname.length - 1) + relUrl;
|
|
54
|
+
// join together and split for removal of .. and . segments
|
|
55
|
+
// looping the string instead of anything fancy for perf reasons
|
|
56
|
+
// '../../../../../z' resolved to 'x/y' is just 'z'
|
|
57
|
+
let segmented = pathname.slice(0, pathname.lastIndexOf('/') + 1) + relUrl;
|
|
58
|
+
let output = [];
|
|
59
|
+
let segmentIndex = -1;
|
|
60
|
+
for (let i = 0; i < segmented.length; i++) {
|
|
61
|
+
// busy reading a segment - only terminate on '/'
|
|
62
|
+
if (segmentIndex !== -1) {
|
|
63
|
+
if (segmented[i] === '/') {
|
|
64
|
+
output.push(segmented.slice(segmentIndex, i + 1));
|
|
65
|
+
segmentIndex = -1;
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// new segment - check if it is relative
|
|
70
|
+
else if (segmented[i] === '.') {
|
|
71
|
+
// ../ segment
|
|
72
|
+
if (segmented[i + 1] === '.' && (segmented[i + 2] === '/' || i + 2 === segmented.length)) {
|
|
73
|
+
output.pop();
|
|
74
|
+
i += 2;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// ./ segment
|
|
78
|
+
else if (segmented[i + 1] === '/' || i + 1 === segmented.length) {
|
|
79
|
+
i += 1;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// it is the start of a new segment
|
|
84
|
+
while (segmented[i] === '/')
|
|
85
|
+
i++;
|
|
86
|
+
segmentIndex = i;
|
|
87
|
+
}
|
|
88
|
+
// finish reading out the last segment
|
|
89
|
+
if (segmentIndex !== -1)
|
|
90
|
+
output.push(segmented.slice(segmentIndex));
|
|
91
|
+
return parentUrl.slice(0, parentUrl.length - pathname.length) + output.join('');
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
export const resolveAndComposeImportMap = (json, baseUrl, parentMap) => {
|
|
95
|
+
let outMap = {
|
|
96
|
+
imports: { ...parentMap.imports },
|
|
97
|
+
scopes: Object.fromEntries(Object.entries(parentMap.scopes).map(([scope, imports]) => [scope, { ...imports }])),
|
|
98
|
+
integrity: { ...parentMap.integrity },
|
|
99
|
+
};
|
|
100
|
+
if (json.imports)
|
|
101
|
+
resolveAndComposePackages(json.imports, outMap.imports, baseUrl, parentMap);
|
|
102
|
+
if (json.scopes)
|
|
103
|
+
for (let s in json.scopes) {
|
|
104
|
+
let resolvedScope = resolveUrl(s, baseUrl);
|
|
105
|
+
resolveAndComposePackages(json.scopes[s], outMap.scopes[resolvedScope] || (outMap.scopes[resolvedScope] = {}), baseUrl, parentMap);
|
|
106
|
+
}
|
|
107
|
+
if (json.integrity)
|
|
108
|
+
resolveAndComposeIntegrity(json.integrity, outMap.integrity, baseUrl);
|
|
109
|
+
return outMap;
|
|
110
|
+
};
|
|
111
|
+
const getMatch = (path, matchObj) => {
|
|
112
|
+
if (matchObj[path])
|
|
113
|
+
return path;
|
|
114
|
+
let sepIndex = path.length;
|
|
115
|
+
do {
|
|
116
|
+
let segment = path.slice(0, sepIndex + 1);
|
|
117
|
+
if (segment in matchObj)
|
|
118
|
+
return segment;
|
|
119
|
+
} while ((sepIndex = path.lastIndexOf('/', sepIndex - 1)) !== -1);
|
|
120
|
+
};
|
|
121
|
+
const applyPackages = (id, packages) => {
|
|
122
|
+
let pkgName = getMatch(id, packages);
|
|
123
|
+
if (pkgName) {
|
|
124
|
+
let pkg = packages[pkgName];
|
|
125
|
+
if (pkg === null)
|
|
126
|
+
return;
|
|
127
|
+
return pkg + id.slice(pkgName.length);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
export const resolveImportMap = (importMap, resolvedOrPlain, parentUrl) => {
|
|
131
|
+
let scopeUrl = parentUrl && getMatch(parentUrl, importMap.scopes);
|
|
132
|
+
while (scopeUrl) {
|
|
133
|
+
let packageResolution = applyPackages(resolvedOrPlain, importMap.scopes[scopeUrl]);
|
|
134
|
+
if (packageResolution)
|
|
135
|
+
return packageResolution;
|
|
136
|
+
scopeUrl = getMatch(scopeUrl.slice(0, scopeUrl.lastIndexOf('/')), importMap.scopes);
|
|
137
|
+
}
|
|
138
|
+
return (applyPackages(resolvedOrPlain, importMap.imports) ||
|
|
139
|
+
(resolvedOrPlain.indexOf(':') !== -1 && resolvedOrPlain));
|
|
140
|
+
};
|
|
141
|
+
const resolveAndComposePackages = (packages, outPackages, baseUrl, parentMap) => {
|
|
142
|
+
for (let p in packages) {
|
|
143
|
+
let resolvedLhs = resolveIfNotPlainOrUrl(p, baseUrl) || p;
|
|
144
|
+
if (outPackages[resolvedLhs] && outPackages[resolvedLhs] !== packages[resolvedLhs]) {
|
|
145
|
+
console.warn(`remix/multiple-import-maps-polyfill: Rejected map override "${resolvedLhs}" from ${outPackages[resolvedLhs]} to ${packages[resolvedLhs]}.`);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
let target = packages[p];
|
|
149
|
+
if (typeof target !== 'string')
|
|
150
|
+
continue;
|
|
151
|
+
let mapped = resolveImportMap(parentMap, resolveIfNotPlainOrUrl(target, baseUrl) || target, baseUrl);
|
|
152
|
+
if (mapped) {
|
|
153
|
+
outPackages[resolvedLhs] = mapped;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
console.warn(`remix/multiple-import-maps-polyfill: Mapping "${p}" -> "${packages[p]}" does not resolve`);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const resolveAndComposeIntegrity = (integrity, outIntegrity, baseUrl) => {
|
|
160
|
+
for (let p in integrity) {
|
|
161
|
+
let resolvedLhs = resolveIfNotPlainOrUrl(p, baseUrl) || p;
|
|
162
|
+
if (outIntegrity[resolvedLhs] && outIntegrity[resolvedLhs] !== integrity[resolvedLhs]) {
|
|
163
|
+
console.warn(`remix/multiple-import-maps-polyfill: Rejected map integrity override "${resolvedLhs}" from ${outIntegrity[resolvedLhs]} to ${integrity[resolvedLhs]}.`);
|
|
164
|
+
}
|
|
165
|
+
outIntegrity[resolvedLhs] = integrity[p];
|
|
166
|
+
}
|
|
167
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self.d.ts","sourceRoot":"","sources":["../../src/lib/self.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,KAAK,EAAE,OAAO,UAAkE,CAAA;AACtF,OAAO,EAAE,KAAK,IAAI,IAAI,EAAE,CAAA"}
|
package/dist/lib/self.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type TrustedHTML = string & {
|
|
2
|
+
readonly __trustedHTML: unique symbol;
|
|
3
|
+
};
|
|
4
|
+
type TrustedScript = string & {
|
|
5
|
+
readonly __trustedScript: unique symbol;
|
|
6
|
+
};
|
|
7
|
+
interface TrustedTypePolicy {
|
|
8
|
+
createHTML(html: string): TrustedHTML;
|
|
9
|
+
createScript(script: string): TrustedScript;
|
|
10
|
+
}
|
|
11
|
+
export declare let policy: TrustedTypePolicy | undefined;
|
|
12
|
+
export declare function maybeTrustedInnerHTML(html: string): string | TrustedHTML;
|
|
13
|
+
export declare function maybeTrustedScript(script: string): string | TrustedScript;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=trusted-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trusted-types.d.ts","sourceRoot":"","sources":["../../src/lib/trusted-types.ts"],"names":[],"mappings":"AAEA,KAAK,WAAW,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,aAAa,EAAE,OAAO,MAAM,CAAA;CAAE,CAAA;AACrE,KAAK,aAAa,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,MAAM,CAAA;CAAE,CAAA;AAEzE,UAAU,iBAAiB;IACzB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IACrC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAA;CAC5C;AAmBD,eAAO,IAAI,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAA;AAehD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,CAExE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAEzE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { self } from './self.js';
|
|
2
|
+
const trustedTypesGlobal = self;
|
|
3
|
+
export let policy;
|
|
4
|
+
if (typeof trustedTypesGlobal !== 'undefined' &&
|
|
5
|
+
(typeof trustedTypesGlobal.trustedTypes !== 'undefined' ||
|
|
6
|
+
typeof trustedTypesGlobal.TrustedTypes !== 'undefined')) {
|
|
7
|
+
try {
|
|
8
|
+
let trustedTypes = (trustedTypesGlobal.trustedTypes || trustedTypesGlobal.TrustedTypes);
|
|
9
|
+
policy = trustedTypes.createPolicy('remix/multiple-import-maps-polyfill', {
|
|
10
|
+
createHTML: (html) => html,
|
|
11
|
+
createScript: (script) => script,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
catch { }
|
|
15
|
+
}
|
|
16
|
+
export function maybeTrustedInnerHTML(html) {
|
|
17
|
+
return policy ? policy.createHTML(html) : html;
|
|
18
|
+
}
|
|
19
|
+
export function maybeTrustedScript(script) {
|
|
20
|
+
return policy ? policy.createScript(script) : script;
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/multiple-import-maps-polyfill",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Polyfill for dynamic JavaScript imports that depend on import maps added at runtime",
|
|
5
|
+
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
5
6
|
"license": "MIT",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
8
9
|
"url": "git+https://github.com/remix-run/remix.git",
|
|
9
10
|
"directory": "packages/multiple-import-maps-polyfill"
|
|
10
11
|
},
|
|
11
|
-
"
|
|
12
|
-
|
|
12
|
+
"homepage": "https://github.com/remix-run/remix/tree/main/packages/multiple-import-maps-polyfill#readme",
|
|
13
|
+
"files": [
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"README.md",
|
|
16
|
+
"dist",
|
|
17
|
+
"src",
|
|
18
|
+
"!src/**/*.test.ts"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"es-module-lexer": "^2.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^24.6.0",
|
|
33
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
34
|
+
"playwright": "^1.60.0",
|
|
35
|
+
"@remix-run/assert": "^0.3.0",
|
|
36
|
+
"@remix-run/node-fetch-server": "^0.14.1",
|
|
37
|
+
"@remix-run/test": "^0.6.0"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"remix",
|
|
41
|
+
"browser",
|
|
42
|
+
"import-maps",
|
|
43
|
+
"modules",
|
|
44
|
+
"polyfill"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsgo -p tsconfig.build.json",
|
|
48
|
+
"clean": "git clean -fdX",
|
|
49
|
+
"test": "pnpm run build && remix test",
|
|
50
|
+
"test:bun": "bun x --bun remix test --type server",
|
|
51
|
+
"typecheck": "tsgo --noEmit"
|
|
13
52
|
}
|
|
14
|
-
}
|
|
53
|
+
}
|