@expofp/loader 1.0.65 → 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.
Files changed (57) hide show
  1. package/dist/bundle/bundle.js +557 -431
  2. package/dist/bundle/bundle.js.map +1 -1
  3. package/dist/bundle/cssTextAssetResolver.offlineFunc-CWvHnYni.js +19 -0
  4. package/dist/bundle/cssTextAssetResolver.offlineFunc-CWvHnYni.js.map +1 -0
  5. package/dist/bundle/{downloadOfflineZip-B8tTyZYe.js → downloadOfflineZip-CNz_lUGZ.js} +701 -687
  6. package/dist/bundle/downloadOfflineZip-CNz_lUGZ.js.map +1 -0
  7. package/dist/bundle/legacyDataUrlBaseResolver.offlineFunc-BPlVJ7wy.js +84 -0
  8. package/dist/bundle/legacyDataUrlBaseResolver.offlineFunc-BPlVJ7wy.js.map +1 -0
  9. package/dist/bundle/makeOffline-Dj-0o5_7.js +76 -0
  10. package/dist/bundle/makeOffline-Dj-0o5_7.js.map +1 -0
  11. package/dist/bundle/makeOfflineBundle-D8tePWGI.js +70 -0
  12. package/dist/bundle/makeOfflineBundle-D8tePWGI.js.map +1 -0
  13. package/dist/bundle/tools-D0u8lBvQ.js +102 -0
  14. package/dist/bundle/tools-D0u8lBvQ.js.map +1 -0
  15. package/dist/esm/_OLD_fetchWithRetry.d.ts +1 -0
  16. package/dist/esm/_OLD_fetchWithRetry.js +101 -0
  17. package/dist/esm/index.d.ts +1 -1
  18. package/dist/esm/index.js +1 -1
  19. package/dist/esm/{loadAndWaitGlobal.d.ts → loadScript.d.ts} +2 -1
  20. package/dist/esm/{loadAndWaitGlobal.js → loadScript.js} +16 -6
  21. package/dist/esm/offline/generateZip.js +22 -2
  22. package/dist/esm/offline/index.d.ts +1 -0
  23. package/dist/esm/offline/index.js +4 -0
  24. package/dist/esm/offline/makeOffline.js +11 -3
  25. package/dist/esm/offline/makeOfflineBundle.js +26 -9
  26. package/dist/esm/offline/tools.d.ts +1 -0
  27. package/dist/esm/offline/tools.js +47 -31
  28. package/dist/esm/resolvers/assetResolver.d.ts +1 -1
  29. package/dist/esm/resolvers/assetResolver.js +1 -1
  30. package/dist/esm/resolvers/bundleAssetsResolver.js +1 -1
  31. package/dist/esm/resolvers/cssTextAssetResolver.d.ts +8 -0
  32. package/dist/esm/resolvers/cssTextAssetResolver.js +15 -0
  33. package/dist/esm/resolvers/cssTextAssetResolver.offlineFunc.d.ts +2 -0
  34. package/dist/esm/resolvers/cssTextAssetResolver.offlineFunc.js +22 -0
  35. package/dist/esm/resolvers/expoRuntimeBranchResolver.js +1 -1
  36. package/dist/esm/resolvers/expoRuntimeGetBranchResolver.js +1 -1
  37. package/dist/esm/resolvers/expoRuntimeResolver.js +1 -1
  38. package/dist/esm/resolvers/httpResolver.d.ts +1 -1
  39. package/dist/esm/resolvers/httpResolver.js +1 -1
  40. package/dist/esm/resolvers/index.js +4 -0
  41. package/dist/esm/resolvers/legacyAssetUrlsResolver.d.ts +4 -1
  42. package/dist/esm/resolvers/legacyAssetUrlsResolver.js +5 -2
  43. package/dist/esm/resolvers/legacyDataResolver.d.ts +4 -1
  44. package/dist/esm/resolvers/legacyDataResolver.js +4 -1
  45. package/dist/esm/resolvers/legacyDataUrlBaseResolver.d.ts +8 -0
  46. package/dist/esm/resolvers/legacyDataUrlBaseResolver.js +15 -0
  47. package/dist/esm/resolvers/legacyDataUrlBaseResolver.offlineFunc.d.ts +2 -0
  48. package/dist/esm/resolvers/legacyDataUrlBaseResolver.offlineFunc.js +140 -0
  49. package/dist/esm/shared.d.ts +1 -0
  50. package/dist/esm/shared.js +10 -2
  51. package/dist/esm/types.d.ts +7 -2
  52. package/package.json +4 -2
  53. package/dist/bundle/downloadOfflineZip-B8tTyZYe.js.map +0 -1
  54. package/dist/bundle/makeOffline-DH6wJEem.js +0 -158
  55. package/dist/bundle/makeOffline-DH6wJEem.js.map +0 -1
  56. package/dist/bundle/makeOfflineBundle-C-xleVMN.js +0 -58
  57. package/dist/bundle/makeOfflineBundle-C-xleVMN.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.offlineMethod) {
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
- throw new Error(`Unknown offlineMethod: ${resolver.offlineMethod}`);
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
- log('Bundling file from url', file.targetFilePath);
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: await blob.arrayBuffer(),
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();
@@ -49,7 +65,8 @@ async function downloadFile(url) {
49
65
  if (!url.includes('/data/fp.svg.ViewBox.js')) {
50
66
  // throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
51
67
  }
52
- console.warn(`Warning: Failed to fetch ${url}: ${response.status}`);
68
+ // console.warn(`Warning: Failed to fetch ${url}: ${response.status}`);
69
+ return;
53
70
  }
54
71
  return await response.blob();
55
72
  })();
@@ -1,2 +1,3 @@
1
1
  export declare function makeUniqueJsonTargetPathFromString(str: string, namespace?: string): string;
2
+ export declare function relativeUrlToFilePath(relativeUrl: string): string;
2
3
  export declare function makeTargetPathFromUrl(url: string, prefix?: string): string;
@@ -17,6 +17,52 @@ export function makeUniqueJsonTargetPathFromString(str, namespace = '') {
17
17
  return './' + result;
18
18
  // handle directory case
19
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
+ }
20
66
  export function makeTargetPathFromUrl(url, prefix = '') {
21
67
  // https://example.com/dir1/dir2/a.js => "{prefix}{origin-slug}/dir1/dir2/a.js";
22
68
  // https://example.com/dir1/dir2/a.js?params => "{prefix}{origin-slug}/dir1/dir2/a{paramsmd5hash}.js";
@@ -30,37 +76,7 @@ export function makeTargetPathFromUrl(url, prefix = '') {
30
76
  const urlObj = new URL(url);
31
77
  const origin = `${urlObj.protocol}//${urlObj.host}`;
32
78
  const originSlug = slugifyFsUnique(origin);
33
- let pathname = urlObj.pathname;
34
- let search = urlObj.search;
35
- // if path doesn't end with extension, throw
36
- if (!pathname.match(/\.[^\/]+$/)) {
37
- throw new Error(`Cannot make target path from URL without file extension: ${url}`);
38
- }
39
- const extension = pathname.substring(pathname.lastIndexOf('.'));
40
- let pathnameWithoutExtension = pathname.substring(0, pathname.lastIndexOf('.'));
41
- // check the pathname contains only valid fs characters
42
- const invalidPathnameChars = pathnameWithoutExtension.match(/[^a-zA-Z0-9\-._\/]/g);
43
- if (invalidPathnameChars) {
44
- const fixedPathnameWithoutExtension = slugifyFsUnique(pathnameWithoutExtension);
45
- log(`Pathname contains invalid filesystem characters (${[...new Set(invalidPathnameChars)].join(', ')}), slugifying it: ${pathnameWithoutExtension}${extension} => ${fixedPathnameWithoutExtension}${extension}`);
46
- pathnameWithoutExtension = fixedPathnameWithoutExtension;
47
- }
48
- pathname = pathnameWithoutExtension + extension;
49
- if (pathname.length > 120) {
50
- log(`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';
@@ -2,5 +2,5 @@ export declare function resolveAssetRefSync(ref: string): string;
2
2
  export declare const assetResolver: {
3
3
  schema: string;
4
4
  resolveRef: (ref: string) => Promise<string>;
5
- offlineMethod: "localizeRef";
5
+ offlineFunc: "localizeRef";
6
6
  };
@@ -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
- offlineMethod: 'localizeRef',
11
+ offlineFunc: 'localizeRef',
12
12
  };
13
13
  // async *makeOfflineRef(ref: string) {
14
14
  // log('assetResolver makeOfflineRef:', ref);
@@ -16,5 +16,5 @@ export const bundleAssetsResolver = {
16
16
  return assets;
17
17
  });
18
18
  },
19
- offlineMethod: 'localizeRef',
19
+ offlineFunc: 'localizeRef',
20
20
  };
@@ -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,2 @@
1
+ import { OfflineFunc } from '../types';
2
+ export declare const offlineFunc: OfflineFunc;
@@ -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
+ }
@@ -16,5 +16,5 @@ export const expoRuntimeBranchResolver = {
16
16
  };
17
17
  });
18
18
  },
19
- offlineMethod: 'resolveRef',
19
+ offlineFunc: 'resolveRef',
20
20
  };
@@ -10,5 +10,5 @@ export const expoRuntimeGetBranchResolver = {
10
10
  const url = `https://${expo}.expofp.com/get-branch`;
11
11
  return importJson(url, context);
12
12
  },
13
- offlineMethod: 'resolveRef',
13
+ offlineFunc: 'resolveRef',
14
14
  };
@@ -35,5 +35,5 @@ export const expoRuntimeResolver = {
35
35
  // yield { data, targetFilePath };
36
36
  // return targetFilePath;
37
37
  // },
38
- offlineMethod: 'resolveRef',
38
+ offlineFunc: 'resolveRef',
39
39
  };
@@ -1,5 +1,5 @@
1
1
  export declare const httpResolver: {
2
2
  canResolve(ref: string): boolean;
3
3
  resolveRef(ref: string, context: import("../resolve").ResolveContextInternal): Promise<any>;
4
- offlineMethod: "resolveRef";
4
+ offlineFunc: "resolveRef";
5
5
  };
@@ -10,5 +10,5 @@ export const httpResolver = {
10
10
  throw new Error(`Unexpected ref in httpResolver: ${ref}`);
11
11
  return importJson(ref, context);
12
12
  },
13
- offlineMethod: 'resolveRef',
13
+ offlineFunc: 'resolveRef',
14
14
  };
@@ -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
- offlineMethod: "resolveRef";
8
+ offlineFunc: "resolveRef";
6
9
  };
@@ -1,7 +1,10 @@
1
- import { loadAndWaitGlobal } from '../loadAndWaitGlobal';
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
- offlineMethod: 'resolveRef',
79
+ offlineFunc: 'resolveRef',
77
80
  };
78
81
  function populateDataJsAssetsMap(dataUrlBase, data) {
79
82
  const links = new Set();
@@ -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
- offlineMethod: "resolveRef";
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
- offlineMethod: 'resolveRef',
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,2 @@
1
+ import { OfflineFunc } from '../types';
2
+ export declare const offlineFunc: OfflineFunc;
@@ -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
+ }
@@ -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;
@@ -33,6 +33,14 @@ export function deepClone(obj) {
33
33
  }
34
34
  return JSON.parse(JSON.stringify(obj));
35
35
  }
36
+ export function shallowClone(obj) {
37
+ if (obj === null || typeof obj !== 'object')
38
+ return obj;
39
+ if (Array.isArray(obj)) {
40
+ return obj.slice();
41
+ }
42
+ return { ...obj };
43
+ }
36
44
  export function preloadJson(url) {
37
45
  if (typeof document === 'undefined')
38
46
  return; // SSR / Node
@@ -213,7 +221,7 @@ export function createMergedObjectWithOverridenNonRefProps(target, source) {
213
221
  }
214
222
  const nonRefKeys = Object.keys(source).filter((key) => key !== '$ref');
215
223
  if (nonRefKeys.length === 0)
216
- return deepClone(target);
224
+ return shallowClone(target);
217
225
  // throw if any is array
218
226
  if (Array.isArray(target)) {
219
227
  throw new Error('Cannot merge into arrays');
@@ -221,7 +229,7 @@ export function createMergedObjectWithOverridenNonRefProps(target, source) {
221
229
  if (target === null || typeof target !== 'object') {
222
230
  throw new Error('Cannot merge into non-object target');
223
231
  }
224
- const result = deepClone({ ...target });
232
+ const result = { ...target }; //deepClone({ ...target });
225
233
  for (const key of nonRefKeys) {
226
234
  result[key] = source[key];
227
235
  }