-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathfileify.js
117 lines (96 loc) · 3.48 KB
/
fileify.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Stores a remote file locally, for offline use.
/*jslint node */
import console from "node:console";
import crypto from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import process from "node:process";
import url from "node:url";
function user_cache_dir() {
// Returns the path to the user's cache directory, a more permanent alternative
// to the system's temporary directory which gets cleaned out every few days.
// Platform | Path | Example
// ---------|---------------------------------|---------------------------------
// Linux | $XDG_CACHE_HOME or $HOME/.cache | /home/me/.cache
// macOS | $HOME/Library/Caches | /Users/me/Library/Caches
// Windows | $LOCALAPPDATA | C:\Users\me\AppData\Local
if (os.platform() === "win32") {
return process.env.LOCALAPPDATA;
}
if (os.platform() === "darwin") {
return path.join(process.env.HOME, "Library", "Caches");
}
return process.env.XDG_CACHE_HOME ?? path.join(process.env.HOME, ".cache");
}
function replete_cache_dir() {
try {
return path.join(user_cache_dir(), "replete");
} catch (_) {
return os.tmpdir();
}
}
function fileify(http_url, replace_extension) {
// If the URL is already a file URL, we are done.
if (http_url.protocol === "file:") {
return Promise.resolve(http_url);
}
function versioned_path(vary) {
// Construct a temporary path for the file, based on the HTTP URL.
const extension = path.extname(http_url.pathname);
const name = path.basename(http_url.pathname, extension);
const version = crypto.createHash(
"md5"
).update(
vary
).digest(
"hex"
).slice(0, 8);
return path.join(
replete_cache_dir(),
name + "." + version + (replace_extension ?? extension)
);
}
// Check if a cached version of the file is available.
let file = versioned_path(http_url.href);
return fs.promises.stat(file).catch(function () {
// The file is not cached, so download it to the filesystem.
return fetch(http_url).then(function (response) {
if (!response.ok) {
return Promise.reject(
new Error("Failed to download '" + http_url.href + "'.")
);
}
// Should the file be cached indefinitely? Only if the Cache-Control header
// indicates that the file is immutable.
const immutable = (
response.headers.has("cache-control")
&& response.headers.get("cache-control").includes("immutable")
);
if (!immutable) {
file = versioned_path(crypto.randomUUID());
}
return response.arrayBuffer();
}).then(function ensure_directory(array_buffer) {
return fs.promises.mkdir(
path.dirname(file),
{recursive: true, mode: 0o700}
).then(function create_file() {
return fs.promises.writeFile(
file,
new Uint8Array(array_buffer),
{mode: 0o700}
);
});
});
}).then(function () {
return url.pathToFileURL(file);
});
}
if (import.meta.main) {
fileify(
new URL("https://deno.land/x/replete/node_loader.js"),
".mjs"
).then(console.log);
}
export default Object.freeze(fileify);