@expofp/utils 3.1.15 → 3.2.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/dist/lib/import-json.js +39 -34
- package/package.json +1 -1
package/dist/lib/import-json.js
CHANGED
|
@@ -3,62 +3,67 @@ import { deepFreeze } from './deep-freeze.js';
|
|
|
3
3
|
import { fetchWithRetry } from './fetch-with-retry.js';
|
|
4
4
|
import { importFsPromises } from './import-fs-promises.js';
|
|
5
5
|
const log = debug('efp:utils:importJson');
|
|
6
|
-
let importJsonNotAvailable;
|
|
7
6
|
const jsonFrozen = new WeakSet();
|
|
7
|
+
// undefined = untried, function = works, null = known broken (Safari 14, CSP, etc.)
|
|
8
|
+
let importJsonNative;
|
|
8
9
|
// ET: this is a workaround for Vite that analyzes dynamic imports and removes 'with' option
|
|
9
10
|
// to be removed when Vite supports it properly
|
|
10
|
-
// Cons: can have CSP issues in some environments
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
fetchCache: options?.fetchCache || new Map(),
|
|
16
|
-
importCallback: options?.importCallback,
|
|
17
|
-
signal: options?.signal || null,
|
|
18
|
-
};
|
|
19
|
-
// console.warn('importJson:', resolveContext.forceFetch);
|
|
20
|
-
if (importJsonNotAvailable === undefined && !opts.forceFetch) {
|
|
11
|
+
// Cons: can have CSP issues in some environments.
|
|
12
|
+
// Lazy + try/caught: Safari 14's parser rejects the two-argument import() form at
|
|
13
|
+
// new Function() construction time, before any feature-detect call site can run.
|
|
14
|
+
function getImportJsonNative() {
|
|
15
|
+
if (importJsonNative === undefined) {
|
|
21
16
|
try {
|
|
22
|
-
|
|
23
|
-
importJsonNotAvailable = false;
|
|
17
|
+
importJsonNative = new Function('url', 'return import(url, { with: { type: "json" } });');
|
|
24
18
|
}
|
|
25
19
|
catch {
|
|
26
20
|
log('Dynamic import not available');
|
|
27
|
-
|
|
21
|
+
importJsonNative = null;
|
|
28
22
|
}
|
|
29
23
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
return importJsonNative ?? undefined;
|
|
25
|
+
}
|
|
26
|
+
export async function importJson(url, options) {
|
|
27
|
+
const forceFetch = options?.forceFetch ?? false;
|
|
28
|
+
const fetchCache = options?.fetchCache ?? new Map();
|
|
29
|
+
const signal = options?.signal ?? null;
|
|
30
|
+
let result;
|
|
31
|
+
const native = !forceFetch ? getImportJsonNative() : undefined;
|
|
32
|
+
if (native) {
|
|
33
|
+
try {
|
|
34
|
+
log('Dynamic import', url);
|
|
35
|
+
const module = await native(url);
|
|
36
|
+
result = module.default;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
log('Dynamic import not available');
|
|
40
|
+
importJsonNative = null;
|
|
41
|
+
}
|
|
39
42
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
if (result === undefined) {
|
|
44
|
+
if (url.startsWith('file:') && !forceFetch) {
|
|
45
|
+
log('Read from file system', url);
|
|
46
|
+
result = await readJsonFromFs(new URL(url));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
log('Fetch', url);
|
|
50
|
+
result = await loadJson(url, fetchCache, signal);
|
|
51
|
+
}
|
|
43
52
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// Freeze the imported JSON to make it immutable
|
|
47
|
-
// This is rather a guard against accidental mutations
|
|
53
|
+
options?.importCallback?.(url);
|
|
54
|
+
// Guard against accidental mutations of the imported JSON
|
|
48
55
|
if (typeof result === 'object' && result !== null && !jsonFrozen.has(result)) {
|
|
49
56
|
deepFreeze(result);
|
|
50
57
|
jsonFrozen.add(result);
|
|
51
58
|
}
|
|
52
59
|
return result;
|
|
53
60
|
}
|
|
54
|
-
// const fetchCache = new Map<string, Promise<any>>();
|
|
55
61
|
async function loadJson(url, fetchCache, signal) {
|
|
56
62
|
const key = '__loadJson__' + url;
|
|
57
63
|
if (fetchCache.has(key)) {
|
|
58
64
|
return fetchCache.get(key);
|
|
59
65
|
}
|
|
60
|
-
const dataPromise = (async
|
|
61
|
-
// in browser just use fetch, for node - fetch-retry
|
|
66
|
+
const dataPromise = (async () => {
|
|
62
67
|
const response = await fetchWithRetry(url, { signal });
|
|
63
68
|
if (!response.ok) {
|
|
64
69
|
throw new Error(`Failed to fetch JSON from ${url}`);
|