@jsenv/core
Version:
Tool to develop, test and build js projects
148 lines (144 loc) • 4.5 kB
JavaScript
import { readEntryStatSync } from "@jsenv/filesystem";
import { ensurePathnameTrailingSlash } from "@jsenv/urls";
import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
import { readFileSync, readdirSync } from "node:fs";
import { FILE_AND_SERVER_URLS_CONVERTER } from "./file_and_server_urls_converter.js";
import { jsenvPluginDirectoryListing } from "./jsenv_plugin_directory_listing.js";
import { jsenvPluginFsRedirection } from "./jsenv_plugin_fs_redirection.js";
const directoryContentMagicName = "...";
export const jsenvPluginProtocolFile = ({
spa = true,
magicExtensions,
magicDirectoryIndex,
preserveSymlinks,
directoryListing,
rootDirectoryUrl,
mainFilePath,
packageDirectory,
sourceFilesConfig,
}) => {
return [
jsenvPluginFsRedirection({
spa,
directoryContentMagicName,
magicExtensions,
magicDirectoryIndex,
preserveSymlinks,
}),
{
name: "jsenv:fs_resolution",
appliesDuring: "*",
resolveReference: {
filesystem: (reference) => {
const ownerUrlInfo = reference.ownerUrlInfo;
const baseUrl =
ownerUrlInfo.type === "directory"
? ensurePathnameTrailingSlash(ownerUrlInfo.url)
: ownerUrlInfo.url;
return new URL(reference.specifier, baseUrl).href;
},
},
},
{
name: "jsenv:@fs",
// during build it's fine to use "file://"" urls
// but during dev it's a browser running the code
// so absolute file urls needs to be relativized
appliesDuring: "dev",
resolveReference: (reference) => {
if (reference.specifier.startsWith("/@fs/")) {
return FILE_AND_SERVER_URLS_CONVERTER.asFileUrl(reference.specifier);
}
return null;
},
formatReference: (reference) => {
const { generatedUrl } = reference;
if (!generatedUrl.startsWith("file:")) {
return null;
}
if (reference.original) {
const originalSpecifierPathname =
reference.original.specifierPathname;
if (
originalSpecifierPathname.endsWith(`/${directoryContentMagicName}`)
) {
return originalSpecifierPathname;
}
}
const { rootDirectoryUrl } = reference.ownerUrlInfo.context;
return FILE_AND_SERVER_URLS_CONVERTER.asServerUrl(
generatedUrl,
rootDirectoryUrl,
);
},
},
...(directoryListing
? [
jsenvPluginDirectoryListing({
spa,
...directoryListing,
directoryContentMagicName,
rootDirectoryUrl,
mainFilePath,
packageDirectory,
sourceFilesConfig,
}),
]
: []),
{
name: "jsenv:directory_as_json",
appliesDuring: "*",
fetchUrlContent: (urlInfo) => {
if (!urlInfo.url.startsWith("file:")) {
return null;
}
const { firstReference } = urlInfo;
let { fsStat } = firstReference;
if (!fsStat) {
fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
}
if (!fsStat) {
return null;
}
const isDirectory = fsStat.isDirectory();
if (!isDirectory) {
return null;
}
const directoryContentArray = readdirSync(new URL(urlInfo.url));
const content = JSON.stringify(directoryContentArray, null, " ");
return {
type: "directory",
contentType: "application/json",
content,
};
},
},
{
name: "jsenv:file_url_fetching",
appliesDuring: "*",
fetchUrlContent: (urlInfo) => {
if (!urlInfo.url.startsWith("file:")) {
return null;
}
const { firstReference } = urlInfo;
let { fsStat } = firstReference;
if (!fsStat) {
fsStat = readEntryStatSync(urlInfo.url, { nullIfNotFound: true });
}
const serveFile = (url) => {
const contentType = CONTENT_TYPE.fromUrlExtension(url);
const fileBuffer = readFileSync(new URL(url));
const content = CONTENT_TYPE.isTextual(contentType)
? String(fileBuffer)
: fileBuffer;
return {
content,
contentType,
contentLength: fileBuffer.length,
};
};
return serveFile(urlInfo.url);
},
},
];
};