Files
pyscript/pyscript.core/esm/runtime/_utils.js
2023-06-09 12:53:31 +02:00

134 lines
4.0 KiB
JavaScript

import "@ungap/with-resolvers";
import { getBuffer } from "../fetch-utils.js";
import { absoluteURL } from "../utils.js";
/**
* Trim code only if it's a single line that prettier or other tools might have modified.
* @param {string} code code that might be a single line
* @returns {string}
*/
export const clean = (code) =>
code.replace(/^[^\r\n]+$/, (line) => line.trim());
// REQUIRES INTEGRATION TEST
/* c8 ignore start */
export const io = new WeakMap();
export const stdio = (init) => {
const context = init || console;
const localIO = {
stderr: (context.stderr || console.error).bind(context),
stdout: (context.stdout || console.log).bind(context),
};
return {
stderr: (...args) => localIO.stderr(...args),
stdout: (...args) => localIO.stdout(...args),
async get(engine) {
const runtime = await engine;
io.set(runtime, localIO);
return runtime;
},
};
};
/* c8 ignore stop */
// This should be the only helper needed for all Emscripten based FS exports
export const writeFile = (FS, path, buffer) => {
const { parentPath, name } = FS.analyzePath(path, true);
FS.mkdirTree(parentPath);
return FS.writeFile([parentPath, name].join("/"), new Uint8Array(buffer), {
canOwn: true,
});
};
// This is instead a fallback for Lua or others
export const writeFileShim = (FS, path, buffer) => {
path = resolve(FS, path);
mkdirTree(FS, dirname(path));
return FS.writeFile(path, new Uint8Array(buffer), { canOwn: true });
};
const dirname = (path) => {
const tree = path.split("/");
tree.pop();
return tree.join("/");
};
const mkdirTree = (FS, path) => {
const current = [];
for (const branch of path.split("/")) {
current.push(branch);
if (branch) FS.mkdir(current.join("/"));
}
};
const resolve = (FS, path) => {
const tree = [];
for (const branch of path.split("/")) {
switch (branch) {
case "":
break;
case ".":
break;
case "..":
tree.pop();
break;
default:
tree.push(branch);
}
}
return [FS.cwd()].concat(tree).join("/").replace(/^\/+/, "/");
};
import { all, isArray } from "../utils.js";
const calculateFetchPaths = (config_fetch) => {
// REQUIRES INTEGRATION TEST
/* c8 ignore start */
for (const { files, to_file, from = "" } of config_fetch) {
if (files !== undefined && to_file !== undefined)
throw new Error(
`Cannot use 'to_file' and 'files' parameters together!`,
);
if (files === undefined && to_file === undefined && from.endsWith("/"))
throw new Error(
`Couldn't determine the filename from the path ${from}, please supply 'to_file' parameter.`,
);
}
/* c8 ignore stop */
return config_fetch.flatMap(
({ from = "", to_folder = ".", to_file, files }) => {
if (isArray(files))
return files.map((file) => ({
url: joinPaths([from, file]),
path: joinPaths([to_folder, file]),
}));
const filename = to_file || from.slice(1 + from.lastIndexOf("/"));
return [{ url: from, path: joinPaths([to_folder, filename]) }];
},
);
};
const joinPaths = (parts) => {
const res = parts
.map((part) => part.trim().replace(/(^[/]*|[/]*$)/g, ""))
.filter((p) => p !== "" && p !== ".")
.join("/");
return parts[0].startsWith("/") ? `/${res}` : res;
};
const fetchResolved = (config_fetch, url) =>
fetch(absoluteURL(url, base.get(config_fetch)));
export const base = new WeakMap();
export const fetchPaths = (module, runtime, config_fetch) =>
all(
calculateFetchPaths(config_fetch).map(({ url, path }) =>
fetchResolved(config_fetch, url)
.then(getBuffer)
.then((buffer) => module.writeFile(runtime, path, buffer)),
),
);