genezio
Version:
Command line utility to interact with Genezio infrastructure.
133 lines (132 loc) • 4.78 kB
JavaScript
import fs from "fs";
import path from "path";
/**
* Computes the paths that the assets should be served at. It will check if the assets and route entries clash. If
* they do, it will generate a specific path for the assets, else it will generate a wildcard path. This way, there
* will be no case where the route entry is not served because the assets entry was too broad.
*
* @param assetsFolder - The path to the assets folder
* @param origin - The origin of the frontend
* @returns The paths that the assets should be served at
*/
export async function computeAssetsPaths(assetsFolder, origin) {
const assets = await treeFs(assetsFolder);
if (!assets) {
return [];
}
let routes;
if (fs.existsSync("app") || fs.existsSync("pages")) {
routes = await mergeFsTrees(await treeFs("app"), await treeFs("pages"));
}
else if (fs.existsSync("src/app") || fs.existsSync("src/pages")) {
routes = await mergeFsTrees(await treeFs("src/app"), await treeFs("src/pages"));
}
else {
routes = new Directory();
}
const paths = recursivePathGenerator(assets, routes);
return paths.map((p) => ({ origin, pattern: p }));
}
export class File {
}
export class Directory {
constructor(children = new Map()) {
this.children = children;
}
}
/**
* Recursively reads the file system and creates a tree of directories and files.
*
* @param fsPath - The path to the directory to read
* @returns The root directory of the tree or undefined if the path does not exist
*/
export async function treeFs(fsPath) {
if (!fs.existsSync(fsPath)) {
return undefined;
}
if (!(await fs.promises.stat(fsPath)).isDirectory()) {
return new File();
}
const dir = new Directory();
await Promise.all((await fs.promises.readdir(fsPath)).map(async (file) => {
const fileStat = await fs.promises.stat(path.join(fsPath, file));
if (fileStat.isDirectory()) {
dir.children.set(file, (await treeFs(path.join(fsPath, file))));
}
else {
dir.children.set(file, new File());
}
}));
return dir;
}
/**
* Merges two file system trees together.
*
* @param root - The root of the first tree
* @param add - The root of the second tree
* @returns The merged tree
*/
export async function mergeFsTrees(root, add) {
if (!root && !add) {
return new Directory();
}
else if (!root && add) {
return add;
}
else if (!add && root) {
return root;
}
const rootCopy = structuredClone(root);
if (rootCopy instanceof File || add instanceof File) {
return rootCopy;
}
for (const [name, entry] of add.children) {
if (entry instanceof File) {
rootCopy.children.set(name, entry);
continue;
}
const existing = rootCopy.children.get(name);
if (!existing) {
rootCopy.children.set(name, entry);
continue;
}
rootCopy.children.set(name, await mergeFsTrees(existing, entry));
}
return rootCopy;
}
/**
* Recursively checks if the assets and route entires clash. If they do, it will generate a specific path for the
* assets, else it will generate a wildcard path. This way, there will be no case where the route entry is not
* served because the assets entry was too broad.
*
* @param assetsEntry - FsEntry of the assets folder
* @param routeEntry - FsEntry of the route (app, pages, src/app, src/pages) folder
* @param currentPath - The current path in the assets folder, used for recursion
* @param paths - The paths that have been generated so far, used for recursion
* @returns The paths that the assets should be served at
*/
export function recursivePathGenerator(assetsEntry, routeEntry, currentPath = "", paths = []) {
if (assetsEntry instanceof File) {
return paths;
}
for (const [name, entry] of assetsEntry.children) {
if (entry instanceof File) {
paths.push([currentPath, name].join("/"));
continue;
}
if (routeEntry instanceof File) {
continue;
}
const routeWildcard = [...routeEntry.children.keys()].find((e) => e.startsWith("[") && e.endsWith("]"));
if (routeEntry.children.has(name)) {
recursivePathGenerator(assetsEntry.children.get(name), routeEntry.children.get(name), [currentPath, name].join("/"), paths);
}
else if (routeWildcard) {
recursivePathGenerator(assetsEntry.children.get(name), routeEntry.children.get(routeWildcard), [currentPath, name].join("/"), paths);
}
else {
paths.push([currentPath, name, "*"].join("/"));
}
}
return paths;
}