@expofp/loader 1.0.63 → 1.0.77
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/dist/bundle/bundle.js +566 -433
- package/dist/bundle/bundle.js.map +1 -1
- package/dist/bundle/cssTextAssetResolver.offlineFunc-CWvHnYni.js +19 -0
- package/dist/bundle/cssTextAssetResolver.offlineFunc-CWvHnYni.js.map +1 -0
- package/dist/bundle/{downloadOfflineZip-RIzZSzeG.js → downloadOfflineZip-CNz_lUGZ.js} +701 -687
- package/dist/bundle/downloadOfflineZip-CNz_lUGZ.js.map +1 -0
- package/dist/bundle/legacyDataUrlBaseResolver.offlineFunc-BPlVJ7wy.js +84 -0
- package/dist/bundle/legacyDataUrlBaseResolver.offlineFunc-BPlVJ7wy.js.map +1 -0
- package/dist/bundle/makeOffline-Dj-0o5_7.js +76 -0
- package/dist/bundle/makeOffline-Dj-0o5_7.js.map +1 -0
- package/dist/bundle/makeOfflineBundle-D8tePWGI.js +70 -0
- package/dist/bundle/makeOfflineBundle-D8tePWGI.js.map +1 -0
- package/dist/bundle/tools-D0u8lBvQ.js +102 -0
- package/dist/bundle/tools-D0u8lBvQ.js.map +1 -0
- package/dist/esm/_OLD_fetchWithRetry.d.ts +1 -0
- package/dist/esm/_OLD_fetchWithRetry.js +101 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/{loadAndWaitGlobal.d.ts → loadScript.d.ts} +2 -1
- package/dist/esm/{loadAndWaitGlobal.js → loadScript.js} +16 -6
- package/dist/esm/offline/generateZip.js +22 -2
- package/dist/esm/offline/index.d.ts +1 -0
- package/dist/esm/offline/index.js +4 -0
- package/dist/esm/offline/makeOffline.js +11 -3
- package/dist/esm/offline/makeOfflineBundle.js +30 -9
- package/dist/esm/offline/tools.d.ts +1 -0
- package/dist/esm/offline/tools.js +49 -33
- package/dist/esm/resolvers/assetResolver.d.ts +1 -1
- package/dist/esm/resolvers/assetResolver.js +1 -1
- package/dist/esm/resolvers/bundleAssetsResolver.js +1 -1
- package/dist/esm/resolvers/cssTextAssetResolver.d.ts +8 -0
- package/dist/esm/resolvers/cssTextAssetResolver.js +15 -0
- package/dist/esm/resolvers/cssTextAssetResolver.offlineFunc.d.ts +2 -0
- package/dist/esm/resolvers/cssTextAssetResolver.offlineFunc.js +22 -0
- package/dist/esm/resolvers/expoRuntimeBranchResolver.js +1 -1
- package/dist/esm/resolvers/expoRuntimeGetBranchResolver.js +1 -1
- package/dist/esm/resolvers/expoRuntimeResolver.js +1 -1
- package/dist/esm/resolvers/httpResolver.d.ts +1 -1
- package/dist/esm/resolvers/httpResolver.js +1 -1
- package/dist/esm/resolvers/index.js +4 -0
- package/dist/esm/resolvers/legacyAssetUrlsResolver.d.ts +4 -1
- package/dist/esm/resolvers/legacyAssetUrlsResolver.js +15 -2
- package/dist/esm/resolvers/legacyDataResolver.d.ts +4 -1
- package/dist/esm/resolvers/legacyDataResolver.js +4 -1
- package/dist/esm/resolvers/legacyDataUrlBaseResolver.d.ts +8 -0
- package/dist/esm/resolvers/legacyDataUrlBaseResolver.js +15 -0
- package/dist/esm/resolvers/legacyDataUrlBaseResolver.offlineFunc.d.ts +2 -0
- package/dist/esm/resolvers/legacyDataUrlBaseResolver.offlineFunc.js +140 -0
- package/dist/esm/shared.d.ts +1 -0
- package/dist/esm/shared.js +10 -2
- package/dist/esm/types.d.ts +7 -2
- package/package.json +7 -3
- package/dist/bundle/downloadOfflineZip-RIzZSzeG.js.map +0 -1
- package/dist/bundle/makeOffline-Doxc2dX7.js +0 -159
- package/dist/bundle/makeOffline-Doxc2dX7.js.map +0 -1
- package/dist/bundle/makeOfflineBundle-BoEPc05D.js +0 -60
- package/dist/bundle/makeOfflineBundle-BoEPc05D.js.map +0 -1
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export async function makeOffline(manifest) {
|
|
2
|
+
const { makeOffline } = await import('./makeOffline');
|
|
3
|
+
return await makeOffline(manifest);
|
|
4
|
+
}
|
|
1
5
|
export async function makeOfflineBundle(manifest) {
|
|
2
6
|
const { makeOfflineBundle } = await import('./makeOfflineBundle');
|
|
3
7
|
return await makeOfflineBundle(manifest);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
2
|
import { canResolve, parseRefValue, resolverResolve, } from '../resolve';
|
|
3
3
|
import { resolvers } from '../resolvers';
|
|
4
|
-
import { createMergedObjectWithOverridenNonRefProps, deepClone } from '../shared';
|
|
4
|
+
import { createMergedObjectWithOverridenNonRefProps, deepClone, shallowClone } from '../shared';
|
|
5
5
|
import { makeTargetPathFromUrl, makeUniqueJsonTargetPathFromString } from './tools';
|
|
6
6
|
const log = debug('efp:loader:makeOffline');
|
|
7
|
+
const logWalk = debug('efp:loader:makeOffline:walk');
|
|
7
8
|
export async function makeOffline(manifest) {
|
|
8
9
|
log('makeOffline', manifest);
|
|
9
10
|
// if (typeof manifest !== 'object' || manifest === null) {
|
|
@@ -37,6 +38,7 @@ async function* makeOfflineInternal(manifest) {
|
|
|
37
38
|
return parent.manifest;
|
|
38
39
|
async function* walk(node, key) {
|
|
39
40
|
// console.log('walk', node, key, node[key]);
|
|
41
|
+
logWalk(key, node[key]);
|
|
40
42
|
// let node[key] = node[key];
|
|
41
43
|
if (typeof node[key] !== 'object' || node[key] === null) {
|
|
42
44
|
return;
|
|
@@ -45,6 +47,7 @@ async function* makeOfflineInternal(manifest) {
|
|
|
45
47
|
// const usedResolvers = new Set<Resolver>();
|
|
46
48
|
// do {
|
|
47
49
|
if ('$ref' in node[key]) {
|
|
50
|
+
logWalk('Found $ref:', node[key].$ref);
|
|
48
51
|
const resolversToUse = resolvers.filter((r) => canResolve(r, node[key].$ref));
|
|
49
52
|
if (resolversToUse.length === 0) {
|
|
50
53
|
throw new Error(`No resolver found for ref: ${node[key].$ref}`);
|
|
@@ -54,7 +57,7 @@ async function* makeOfflineInternal(manifest) {
|
|
|
54
57
|
}
|
|
55
58
|
const resolver = resolversToUse[0];
|
|
56
59
|
let func;
|
|
57
|
-
switch (resolver.
|
|
60
|
+
switch (resolver.offlineFunc) {
|
|
58
61
|
case 'localizeRef':
|
|
59
62
|
func = offlineLocalizeRef;
|
|
60
63
|
break;
|
|
@@ -62,13 +65,18 @@ async function* makeOfflineInternal(manifest) {
|
|
|
62
65
|
func = offlineResolveRef;
|
|
63
66
|
break;
|
|
64
67
|
default:
|
|
65
|
-
|
|
68
|
+
const m = resolver.offlineFunc;
|
|
69
|
+
func = (_resolver, ref, context) => m(ref, context);
|
|
70
|
+
// throw new Error(`Unknown offlineMethod: ${resolver.offlineMethod}`);
|
|
66
71
|
}
|
|
67
72
|
const mergeRef = yield* func(resolver, node[key].$ref, resolveContext);
|
|
68
73
|
if (Object.isFrozen(node))
|
|
69
74
|
throw new Error('Unexpected frozen node during makeOffline');
|
|
70
75
|
node[key] = createMergedObjectWithOverridenNonRefProps({ $ref: mergeRef }, node[key]);
|
|
71
76
|
}
|
|
77
|
+
else {
|
|
78
|
+
node[key] = shallowClone(node[key]);
|
|
79
|
+
}
|
|
72
80
|
// recurse
|
|
73
81
|
if (Array.isArray(node[key])) {
|
|
74
82
|
for (const [index] of node[key].entries()) {
|
|
@@ -20,19 +20,35 @@ export async function* makeOfflineBundle(manifest) {
|
|
|
20
20
|
}
|
|
21
21
|
else if ('url' in file) {
|
|
22
22
|
const blob = await downloadFile(file.url);
|
|
23
|
-
|
|
23
|
+
if (!blob) {
|
|
24
|
+
console.warn(`Skipping file ${file.url} as it could not be downloaded`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
log('Bundling file from url', file.targetFilePath);
|
|
28
|
+
yield {
|
|
29
|
+
path: file.targetFilePath,
|
|
30
|
+
data: await blob.arrayBuffer(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else if ('text' in file) {
|
|
35
|
+
log('Bundling text file', file.targetFilePath);
|
|
24
36
|
yield {
|
|
25
37
|
path: file.targetFilePath,
|
|
26
|
-
data:
|
|
38
|
+
data: new TextEncoder().encode(file.text).buffer,
|
|
27
39
|
};
|
|
28
40
|
}
|
|
41
|
+
else {
|
|
42
|
+
throw new Error('Unknown file type');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (await resolve(offlineData.manifest, '/runtime', { preResolvedRefs })) {
|
|
46
|
+
const html = await getIndexHtml(offlineData.manifest, preResolvedRefs);
|
|
47
|
+
yield {
|
|
48
|
+
path: './index.html',
|
|
49
|
+
data: new TextEncoder().encode(html).buffer,
|
|
50
|
+
};
|
|
29
51
|
}
|
|
30
|
-
// yield* generateJsLoaderFiles();
|
|
31
|
-
const html = await getIndexHtml(offlineData.manifest, preResolvedRefs);
|
|
32
|
-
yield {
|
|
33
|
-
path: './index.html',
|
|
34
|
-
data: new TextEncoder().encode(html).buffer,
|
|
35
|
-
};
|
|
36
52
|
}
|
|
37
53
|
const MAX_CONCURRENT_DOWNLOADS = 10;
|
|
38
54
|
const queue = new Set();
|
|
@@ -45,7 +61,12 @@ async function downloadFile(url) {
|
|
|
45
61
|
log('Fetching file for zip:', url);
|
|
46
62
|
const response = await fetch(url);
|
|
47
63
|
if (!response.ok) {
|
|
48
|
-
|
|
64
|
+
// Rodion's bug. May be missing file.
|
|
65
|
+
if (!url.includes('/data/fp.svg.ViewBox.js')) {
|
|
66
|
+
// throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
|
|
67
|
+
}
|
|
68
|
+
// console.warn(`Warning: Failed to fetch ${url}: ${response.status}`);
|
|
69
|
+
return;
|
|
49
70
|
}
|
|
50
71
|
return await response.blob();
|
|
51
72
|
})();
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
1
2
|
import { hashString } from './hashString';
|
|
2
3
|
import { slugifyFsUnique } from './slugify';
|
|
4
|
+
const log = debug('efp:loader:offline');
|
|
3
5
|
export function makeUniqueJsonTargetPathFromString(str, namespace = '') {
|
|
4
6
|
// const hash = hashString(str);
|
|
5
7
|
let result = slugifyFsUnique(str); // + '-' + hash;
|
|
@@ -15,6 +17,52 @@ export function makeUniqueJsonTargetPathFromString(str, namespace = '') {
|
|
|
15
17
|
return './' + result;
|
|
16
18
|
// handle directory case
|
|
17
19
|
}
|
|
20
|
+
export function relativeUrlToFilePath(relativeUrl) {
|
|
21
|
+
const urlObj = new URL(relativeUrl, 'http://example.com');
|
|
22
|
+
const pathname = relativeUrl.startsWith('/') ? urlObj.pathname : urlObj.pathname.slice(1);
|
|
23
|
+
const search = urlObj.search;
|
|
24
|
+
return pathnameSearchToPahthname(pathname, search);
|
|
25
|
+
}
|
|
26
|
+
const MAX_PATHNAME_LENGTH = 120;
|
|
27
|
+
function pathnameSearchToPahthname(pathname, search) {
|
|
28
|
+
// for directory
|
|
29
|
+
if (pathname.endsWith('/')) {
|
|
30
|
+
// just trust it for now
|
|
31
|
+
// TODO: need to combine with the logic below
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// if path doesn't end with extension, throw
|
|
35
|
+
if (!pathname.match(/\.[^\/]+$/)) {
|
|
36
|
+
throw new Error(`Cannot make target path from URL without file extension: ${pathname}`);
|
|
37
|
+
}
|
|
38
|
+
const extension = pathname.substring(pathname.lastIndexOf('.'));
|
|
39
|
+
let pathnameWithoutExtension = pathname.substring(0, pathname.lastIndexOf('.'));
|
|
40
|
+
// check the pathname contains only valid fs characters
|
|
41
|
+
const invalidPathnameChars = pathnameWithoutExtension.match(/[^a-zA-Z0-9\-._\/]/g);
|
|
42
|
+
if (invalidPathnameChars) {
|
|
43
|
+
const fixedPathnameWithoutExtension = slugifyFsUnique(pathnameWithoutExtension);
|
|
44
|
+
log(`Pathname contains invalid filesystem characters (${[...new Set(invalidPathnameChars)].join(', ')}), slugifying it: ${pathnameWithoutExtension}${extension} => ${fixedPathnameWithoutExtension}${extension}`);
|
|
45
|
+
pathnameWithoutExtension = fixedPathnameWithoutExtension;
|
|
46
|
+
}
|
|
47
|
+
pathname = pathnameWithoutExtension + extension;
|
|
48
|
+
if (pathname.length > MAX_PATHNAME_LENGTH) {
|
|
49
|
+
log(`Pathname is too long (${pathname.length} characters), truncating to ${MAX_PATHNAME_LENGTH} characters: ${pathname}`);
|
|
50
|
+
pathname = pathname.substring(0, MAX_PATHNAME_LENGTH - extension.length) + extension;
|
|
51
|
+
}
|
|
52
|
+
if (search) {
|
|
53
|
+
// create a hash from search params
|
|
54
|
+
const hash = hashString(search);
|
|
55
|
+
const dotIndex = pathname.lastIndexOf('.');
|
|
56
|
+
if (dotIndex !== -1) {
|
|
57
|
+
pathname = `${pathname.slice(0, dotIndex)}.${hash}${pathname.slice(dotIndex)}`;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
pathname = `${pathname}${hash}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return pathname;
|
|
65
|
+
}
|
|
18
66
|
export function makeTargetPathFromUrl(url, prefix = '') {
|
|
19
67
|
// https://example.com/dir1/dir2/a.js => "{prefix}{origin-slug}/dir1/dir2/a.js";
|
|
20
68
|
// https://example.com/dir1/dir2/a.js?params => "{prefix}{origin-slug}/dir1/dir2/a{paramsmd5hash}.js";
|
|
@@ -28,39 +76,7 @@ export function makeTargetPathFromUrl(url, prefix = '') {
|
|
|
28
76
|
const urlObj = new URL(url);
|
|
29
77
|
const origin = `${urlObj.protocol}//${urlObj.host}`;
|
|
30
78
|
const originSlug = slugifyFsUnique(origin);
|
|
31
|
-
|
|
32
|
-
let search = urlObj.search;
|
|
33
|
-
// if path doesn't end with extension, throw
|
|
34
|
-
if (!pathname.match(/\.[^\/]+$/)) {
|
|
35
|
-
throw new Error(`Cannot make target path from URL without file extension: ${url}`);
|
|
36
|
-
}
|
|
37
|
-
const extension = pathname.substring(pathname.lastIndexOf('.'));
|
|
38
|
-
let pathnameWithoutExtension = pathname.substring(0, pathname.lastIndexOf('.'));
|
|
39
|
-
// check the pathname contains only valid fs characters
|
|
40
|
-
const invalidPathnameChars = pathnameWithoutExtension.match(/[^a-zA-Z0-9\-._\/]/g);
|
|
41
|
-
if (invalidPathnameChars) {
|
|
42
|
-
const fixedPathnameWithoutExtension = slugifyFsUnique(pathnameWithoutExtension);
|
|
43
|
-
console.warn(`Warning: pathname contains invalid filesystem characters (${[
|
|
44
|
-
...new Set(invalidPathnameChars),
|
|
45
|
-
].join(', ')}), slugifying it: ${pathnameWithoutExtension}${extension} => ${fixedPathnameWithoutExtension}${extension}`);
|
|
46
|
-
pathnameWithoutExtension = fixedPathnameWithoutExtension;
|
|
47
|
-
}
|
|
48
|
-
pathname = pathnameWithoutExtension + extension;
|
|
49
|
-
if (pathname.length > 120) {
|
|
50
|
-
console.warn(`Warning: pathname is too long (${pathname.length} characters), truncating to 150 characters: ${pathname}`);
|
|
51
|
-
pathname = pathname.substring(0, 120 - extension.length) + extension;
|
|
52
|
-
}
|
|
53
|
-
if (search) {
|
|
54
|
-
// create a hash from search params
|
|
55
|
-
const hash = hashString(search);
|
|
56
|
-
const dotIndex = pathname.lastIndexOf('.');
|
|
57
|
-
if (dotIndex !== -1) {
|
|
58
|
-
pathname = `${pathname.slice(0, dotIndex)}.${hash}${pathname.slice(dotIndex)}`;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
pathname = `${pathname}${hash}`;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
79
|
+
const pathname = pathnameSearchToPahthname(urlObj.pathname, urlObj.search);
|
|
64
80
|
// // handle directory case
|
|
65
81
|
// if (pathname.endsWith('/')) {
|
|
66
82
|
// pathname += '__index.json';
|
|
@@ -8,7 +8,7 @@ export function resolveAssetRefSync(ref) {
|
|
|
8
8
|
export const assetResolver = {
|
|
9
9
|
schema: 'asset',
|
|
10
10
|
resolveRef: async (ref) => resolveAssetRefSync(ref),
|
|
11
|
-
|
|
11
|
+
offlineFunc: 'localizeRef',
|
|
12
12
|
};
|
|
13
13
|
// async *makeOfflineRef(ref: string) {
|
|
14
14
|
// log('assetResolver makeOfflineRef:', ref);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
export declare const log: debug.Debugger;
|
|
3
|
+
export declare const SCHEMA = "css-text-asset";
|
|
4
|
+
export declare const cssTextAssetResolver: {
|
|
5
|
+
schema: string;
|
|
6
|
+
resolveRef(ref: string): Promise<string>;
|
|
7
|
+
offlineFunc: (ref: string, _context: import("../resolve").ResolveContextInternal) => AsyncGenerator<import("../types").LocalFile, string, void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import { parseRefValue } from '../resolve';
|
|
3
|
+
export const log = debug('efp:loader:resolver:cssTextAsset');
|
|
4
|
+
export const SCHEMA = 'css-text-asset';
|
|
5
|
+
export const cssTextAssetResolver = {
|
|
6
|
+
schema: SCHEMA,
|
|
7
|
+
resolveRef(ref) {
|
|
8
|
+
log('cssTextAssetResolver resolveRef:', ref);
|
|
9
|
+
return Promise.resolve(parseRefValue(ref));
|
|
10
|
+
},
|
|
11
|
+
offlineFunc: async function* (ref, _context) {
|
|
12
|
+
const { offlineFunc } = await import('./cssTextAssetResolver.offlineFunc');
|
|
13
|
+
return yield* offlineFunc(ref, _context);
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { makeTargetPathFromUrl } from '../offline/tools';
|
|
2
|
+
import { parseRefValue } from '../resolve';
|
|
3
|
+
import { log, SCHEMA } from './cssTextAssetResolver';
|
|
4
|
+
export const offlineFunc = async function* (ref, _context) {
|
|
5
|
+
const originalCss = parseRefValue(ref);
|
|
6
|
+
const { urls, css } = extractCssUrls(originalCss, makeTargetPathFromUrl);
|
|
7
|
+
for (const { originalUrl, replacedUrl } of urls) {
|
|
8
|
+
yield { url: originalUrl, targetFilePath: replacedUrl };
|
|
9
|
+
}
|
|
10
|
+
return `${SCHEMA}:${css}`;
|
|
11
|
+
};
|
|
12
|
+
function extractCssUrls(css, replace) {
|
|
13
|
+
const urlRegex = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
|
|
14
|
+
const urls = [];
|
|
15
|
+
const replacedCss = css.replace(urlRegex, (_match, quote, url) => {
|
|
16
|
+
const replacedUrl = replace(url);
|
|
17
|
+
urls.push({ originalUrl: url, replacedUrl });
|
|
18
|
+
log('Extracted and replaced URL in CSS:', url, '->', replacedUrl);
|
|
19
|
+
return `url(${quote}${replacedUrl}${quote})`;
|
|
20
|
+
});
|
|
21
|
+
return { urls, css: replacedCss };
|
|
22
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { assetResolver } from './assetResolver';
|
|
2
2
|
import { bundleAssetsResolver } from './bundleAssetsResolver';
|
|
3
|
+
import { cssTextAssetResolver } from './cssTextAssetResolver';
|
|
3
4
|
import { expoRuntimeBranchResolver } from './expoRuntimeBranchResolver';
|
|
4
5
|
import { expoRuntimeGetBranchResolver } from './expoRuntimeGetBranchResolver';
|
|
5
6
|
import { expoRuntimeResolver } from './expoRuntimeResolver';
|
|
6
7
|
import { httpResolver } from './httpResolver';
|
|
7
8
|
import { legacyAssetUrlsResolver } from './legacyAssetUrlsResolver';
|
|
8
9
|
import { legacyDataResolver } from './legacyDataResolver';
|
|
10
|
+
import { legacyDataUrlBaseResolver } from './legacyDataUrlBaseResolver';
|
|
9
11
|
export const resolvers = [
|
|
10
12
|
httpResolver,
|
|
11
13
|
bundleAssetsResolver,
|
|
@@ -13,6 +15,8 @@ export const resolvers = [
|
|
|
13
15
|
expoRuntimeResolver,
|
|
14
16
|
expoRuntimeBranchResolver,
|
|
15
17
|
expoRuntimeGetBranchResolver,
|
|
18
|
+
cssTextAssetResolver,
|
|
16
19
|
legacyDataResolver,
|
|
17
20
|
legacyAssetUrlsResolver,
|
|
21
|
+
legacyDataUrlBaseResolver,
|
|
18
22
|
];
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ResolveContextInternal } from '../resolve';
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Use legacyDataUrlBaseResolver instead
|
|
4
|
+
*/
|
|
2
5
|
export declare const legacyAssetUrlsResolver: {
|
|
3
6
|
schema: string;
|
|
4
7
|
resolveRef(ref: string, context: ResolveContextInternal): Promise<any>;
|
|
5
|
-
|
|
8
|
+
offlineFunc: "resolveRef";
|
|
6
9
|
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { loadAndWaitGlobal } from '../
|
|
1
|
+
import { loadAndWaitGlobal } from '../loadScript';
|
|
2
2
|
import { parseRefValue } from '../resolve';
|
|
3
3
|
import { returnCachedRef } from '../returnCachedRef';
|
|
4
4
|
import { log } from '../logger';
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated Use legacyDataUrlBaseResolver instead
|
|
7
|
+
*/
|
|
5
8
|
export const legacyAssetUrlsResolver = {
|
|
6
9
|
schema: 'legacy-asset-urls',
|
|
7
10
|
resolveRef(ref, context) {
|
|
@@ -73,7 +76,7 @@ export const legacyAssetUrlsResolver = {
|
|
|
73
76
|
return { ...dataFilesAssets, ...populateDataJsAssetsMap(dataUrlBase, data) };
|
|
74
77
|
});
|
|
75
78
|
},
|
|
76
|
-
|
|
79
|
+
offlineFunc: 'resolveRef',
|
|
77
80
|
};
|
|
78
81
|
function populateDataJsAssetsMap(dataUrlBase, data) {
|
|
79
82
|
const links = new Set();
|
|
@@ -88,6 +91,16 @@ function populateDataJsAssetsMap(dataUrlBase, data) {
|
|
|
88
91
|
addLink(data.logo);
|
|
89
92
|
data.exhibitors?.forEach((e) => {
|
|
90
93
|
addLink(e.logo);
|
|
94
|
+
// add same files but with __small and __tiny suffixes
|
|
95
|
+
if (e.logo) {
|
|
96
|
+
const dotIndex = e.logo.lastIndexOf('.');
|
|
97
|
+
if (dotIndex !== -1) {
|
|
98
|
+
const name = e.logo.substring(0, dotIndex);
|
|
99
|
+
const ext = e.logo.substring(dotIndex);
|
|
100
|
+
addLink(`${name}__small${ext}`);
|
|
101
|
+
addLink(`${name}__tiny${ext}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
91
104
|
e.gallery?.forEach((img) => addLink(img));
|
|
92
105
|
});
|
|
93
106
|
data.events?.forEach((e) => {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use legacyDataUrlBaseResolver instead
|
|
3
|
+
*/
|
|
1
4
|
export declare const legacyDataResolver: {
|
|
2
5
|
schema: string;
|
|
3
6
|
resolveRef(ref: string, context: import("../resolve").ResolveContextInternal): Promise<any>;
|
|
4
|
-
|
|
7
|
+
offlineFunc: "resolveRef";
|
|
5
8
|
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { parseRefValue } from '../resolve';
|
|
2
2
|
import { returnCachedRef } from '../returnCachedRef';
|
|
3
3
|
import { log } from '../logger';
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use legacyDataUrlBaseResolver instead
|
|
6
|
+
*/
|
|
4
7
|
export const legacyDataResolver = {
|
|
5
8
|
schema: 'legacy-data',
|
|
6
9
|
resolveRef(ref, context) {
|
|
@@ -13,5 +16,5 @@ export const legacyDataResolver = {
|
|
|
13
16
|
};
|
|
14
17
|
});
|
|
15
18
|
},
|
|
16
|
-
|
|
19
|
+
offlineFunc: 'resolveRef',
|
|
17
20
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
export declare const log: debug.Debugger;
|
|
3
|
+
export declare const SCHEMA = "legacy-data-url-base";
|
|
4
|
+
export declare const legacyDataUrlBaseResolver: {
|
|
5
|
+
schema: string;
|
|
6
|
+
resolveRef(ref: string): Promise<string>;
|
|
7
|
+
offlineFunc: (ref: string, _context: import("../resolve").ResolveContextInternal) => AsyncGenerator<import("../types").LocalFile, string, void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import { parseRefValue } from '../resolve';
|
|
3
|
+
export const log = debug('efp:loader:resolver:legacyDataUrlBase');
|
|
4
|
+
export const SCHEMA = 'legacy-data-url-base';
|
|
5
|
+
export const legacyDataUrlBaseResolver = {
|
|
6
|
+
schema: SCHEMA,
|
|
7
|
+
resolveRef(ref) {
|
|
8
|
+
log('legacyDataResolver resolveRef:', ref);
|
|
9
|
+
return Promise.resolve(parseRefValue(ref));
|
|
10
|
+
},
|
|
11
|
+
offlineFunc: async function* (ref, _context) {
|
|
12
|
+
const { offlineFunc } = await import('./legacyDataUrlBaseResolver.offlineFunc');
|
|
13
|
+
return yield* offlineFunc(ref, _context);
|
|
14
|
+
},
|
|
15
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { loadScript } from '../loadScript';
|
|
2
|
+
import { makeTargetPathFromUrl, relativeUrlToFilePath } from '../offline/tools';
|
|
3
|
+
import { parseRefValue } from '../resolve';
|
|
4
|
+
import { log, SCHEMA } from './legacyDataUrlBaseResolver';
|
|
5
|
+
export const offlineFunc = async function* (ref, context) {
|
|
6
|
+
log('legacyDataResolver offlineFunc:', ref);
|
|
7
|
+
const signal = context.signal;
|
|
8
|
+
const dataUrlBase = parseRefValue(ref);
|
|
9
|
+
const versionUrl = `${dataUrlBase}version.js`;
|
|
10
|
+
try {
|
|
11
|
+
await loadScript(versionUrl, signal);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
console.warn(`Could not load version.js at ${versionUrl}, proceeding without it`);
|
|
15
|
+
}
|
|
16
|
+
const version = globalThis.__fpDataVersion || (+new Date()).toString();
|
|
17
|
+
const localDataUrlBase = makeTargetPathFromUrl(dataUrlBase) + version + '/';
|
|
18
|
+
const dataUrl = `${dataUrlBase}data.js?v=${version}`;
|
|
19
|
+
// data.js
|
|
20
|
+
await loadScript(dataUrl, signal);
|
|
21
|
+
const __data = getAndDeleteGlobal('__data');
|
|
22
|
+
yield* localizeDataJson(__data, dataUrlBase, localDataUrlBase);
|
|
23
|
+
const text = `var __data = ${JSON.stringify(__data, null, 2)};`;
|
|
24
|
+
yield { text, targetFilePath: `${localDataUrlBase}data.js` };
|
|
25
|
+
// wf.data.js
|
|
26
|
+
const wfDataUrl = `${dataUrlBase}wf.data.js?v=${version}`;
|
|
27
|
+
yield { url: wfDataUrl, targetFilePath: `${localDataUrlBase}wf.data.js` };
|
|
28
|
+
// fp.svg.js
|
|
29
|
+
const fpSvgUrl = `${dataUrlBase}fp.svg.js?v=${version}`;
|
|
30
|
+
yield { url: fpSvgUrl, targetFilePath: `${localDataUrlBase}fp.svg.js` };
|
|
31
|
+
// load fp.svg.js to get __fpLayers
|
|
32
|
+
await loadScript(fpSvgUrl, signal);
|
|
33
|
+
const __fpLayers = getAndDeleteGlobal('__fpLayers') || [];
|
|
34
|
+
const fpLayerFiles = __fpLayers.map((x) => `fp.svg.${x.name}.js`);
|
|
35
|
+
for (const layerFile of fpLayerFiles) {
|
|
36
|
+
// fp.svg.{layer}.js
|
|
37
|
+
const layerUrl = `${dataUrlBase}${layerFile}?v=${version}`;
|
|
38
|
+
yield { url: layerUrl, targetFilePath: `${localDataUrlBase}${layerFile}` };
|
|
39
|
+
}
|
|
40
|
+
return `${SCHEMA}:${localDataUrlBase}`;
|
|
41
|
+
};
|
|
42
|
+
function* localizeDataJson(data, dataUrlBase, localDataUrlBase) {
|
|
43
|
+
if (data.logo) {
|
|
44
|
+
const r = z(data.logo);
|
|
45
|
+
yield r.file;
|
|
46
|
+
data.logo = r.localUrl;
|
|
47
|
+
}
|
|
48
|
+
for (const exhibitor of data.exhibitors || []) {
|
|
49
|
+
if (exhibitor.logo) {
|
|
50
|
+
const r = z(exhibitor.logo);
|
|
51
|
+
yield r.file;
|
|
52
|
+
const variants = ['__small', '__tiny'];
|
|
53
|
+
for (const variant of variants) {
|
|
54
|
+
const url = addSuffix(r.file.url, variant);
|
|
55
|
+
const targetFilePath = addSuffix(r.file.targetFilePath, variant);
|
|
56
|
+
yield { url, targetFilePath };
|
|
57
|
+
}
|
|
58
|
+
exhibitor.logo = r.localUrl;
|
|
59
|
+
}
|
|
60
|
+
if (exhibitor.leadingImageUrl) {
|
|
61
|
+
const r = z(exhibitor.leadingImageUrl);
|
|
62
|
+
yield r.file;
|
|
63
|
+
exhibitor.leadingImageUrl = r.localUrl;
|
|
64
|
+
}
|
|
65
|
+
for (const url of exhibitor.gallery || []) {
|
|
66
|
+
const r = z(url);
|
|
67
|
+
yield r.file;
|
|
68
|
+
}
|
|
69
|
+
// if (exhibitor.logo) {
|
|
70
|
+
// const logoUrl = dataUrlBase + exhibitor.logo;
|
|
71
|
+
// const localLogoUrl = relativeUrlToFilePath(exhibitor.logo);
|
|
72
|
+
// const targetFilePath = localDataUrlBase + localLogoUrl;
|
|
73
|
+
// yield { url: logoUrl, targetFilePath };
|
|
74
|
+
// const variants = ['__small', '__tiny'];
|
|
75
|
+
// for (const variant of variants) {
|
|
76
|
+
// const variantLogo = logoUrl.replace(/(\.[^.]*)$/, `${variant}$1`);
|
|
77
|
+
// const variantTargetFilePath = targetFilePath.replace(/(\.[^.]*)$/, `${variant}$1`);
|
|
78
|
+
// yield { url: variantLogo, targetFilePath: variantTargetFilePath };
|
|
79
|
+
// }
|
|
80
|
+
// exhibitor.logo = targetFilePath;
|
|
81
|
+
// }
|
|
82
|
+
}
|
|
83
|
+
for (const event of data.events || []) {
|
|
84
|
+
if (event.logoFile) {
|
|
85
|
+
const r = z(event.logoFile);
|
|
86
|
+
yield r.file;
|
|
87
|
+
event.logoFile = r.localUrl;
|
|
88
|
+
}
|
|
89
|
+
for (const speaker of event.speakers || []) {
|
|
90
|
+
if (speaker.photoFile) {
|
|
91
|
+
const r = z(speaker.photoFile);
|
|
92
|
+
yield r.file;
|
|
93
|
+
speaker.photoFile = r.localUrl;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function z(relativeUrl) {
|
|
98
|
+
const url = dataUrlBase + relativeUrl;
|
|
99
|
+
const localUrl = relativeUrlToFilePath(relativeUrl);
|
|
100
|
+
const targetFilePath = localDataUrlBase + localUrl;
|
|
101
|
+
return {
|
|
102
|
+
file: { url, targetFilePath },
|
|
103
|
+
localUrl,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function getAndDeleteGlobal(globalVar) {
|
|
108
|
+
const value = globalThis[globalVar];
|
|
109
|
+
delete globalThis[globalVar];
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
// abs and relative paths
|
|
113
|
+
function addSuffix(absoluteOrRelativeUrl, suffix) {
|
|
114
|
+
let urlObj;
|
|
115
|
+
let absolute;
|
|
116
|
+
try {
|
|
117
|
+
urlObj = new URL(absoluteOrRelativeUrl);
|
|
118
|
+
absolute = true;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
urlObj = new URL(absoluteOrRelativeUrl, 'http://example.com');
|
|
122
|
+
absolute = false;
|
|
123
|
+
}
|
|
124
|
+
// const urlObj = new URL(absoluteOrRelativeUrl, 'http://example.com');
|
|
125
|
+
const pathname = urlObj.pathname;
|
|
126
|
+
const dotIndex = pathname.lastIndexOf('.');
|
|
127
|
+
if (dotIndex === -1) {
|
|
128
|
+
return absoluteOrRelativeUrl; // no extension found
|
|
129
|
+
}
|
|
130
|
+
const name = pathname.substring(0, dotIndex);
|
|
131
|
+
const extension = pathname.substring(dotIndex);
|
|
132
|
+
urlObj.pathname = name + suffix + extension;
|
|
133
|
+
if (absolute) {
|
|
134
|
+
// return full absolute URL
|
|
135
|
+
return urlObj.toString();
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return urlObj.pathname.slice(1) + urlObj.search;
|
|
139
|
+
}
|
|
140
|
+
}
|
package/dist/esm/shared.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare function createFunction(name: string): (manifest: unknown, ...args: IArguments[]) => Promise<any>;
|
|
2
2
|
export declare function deepFreeze(obj: any): any;
|
|
3
3
|
export declare function deepClone<T>(obj: T): T;
|
|
4
|
+
export declare function shallowClone<T>(obj: T): T;
|
|
4
5
|
export declare function preloadJson(url: string): void;
|
|
5
6
|
export declare function preconnectUrl(url: string): void;
|
|
6
7
|
export declare function createMergedObjectWithOverridenNonRefProps(target: any, source: any): any;
|