import { promises as fs } from 'fs'; import { dirname, format, join, parse, resolve } from 'path'; import { nonNullable } from './non_nullable.js'; export const cachedLstat = (cache, path) => { let result = cache.get(path); if (result === undefined) { // no await as we want to populate the cache instantly with the promise result = fs.lstat(path); cache.set(path, result); } return result; }; export const cachedReaddir = (cache, path) => { let result = cache.get(path); if (result === undefined) { // no await as we want to populate the cache instantly with the promise result = fs.readdir(path, 'utf-8'); cache.set(path, result); } return result; }; export const cachedReadFile = (cache, path) => { let result = cache.get(path); // Check for null here, as we use the same cache in NFT which sets null on a not found file if (result === undefined || result === null) { // no await as we want to populate the cache instantly with the promise result = fs.readFile(path, 'utf-8'); cache.set(path, result); } return result; }; export const getPathWithExtension = (path, extension) => format({ ...parse(path), base: undefined, ext: extension }); export const safeUnlink = async (path) => { try { await fs.unlink(path); } catch { // no-op } }; // Takes a list of absolute paths and returns an array containing all the // filenames within those directories, if at least one of the directories // exists. If not, an error is thrown. export const listFunctionsDirectories = async function (srcFolders) { const filenamesByDirectory = await Promise.allSettled(srcFolders.map((srcFolder) => listFunctionsDirectory(srcFolder))); const errorMessages = []; const validDirectories = filenamesByDirectory .map((result) => { if (result.status === 'rejected') { // If the error is about `ENOENT` (FileNotFound) then we only throw later if this happens // for all directories. if (result.reason instanceof Error && result.reason.code === 'ENOENT') { return null; } // In any other error case besides `ENOENT` throw immediately throw result.reason; } return result.value; }) .filter(nonNullable); if (validDirectories.length === 0) { throw new Error(`Functions folders do not exist: ${srcFolders.join(', ')} ${errorMessages.join('\n')}`); } return validDirectories.flat(); }; const listFunctionsDirectory = async function (srcFolder) { const filenames = await fs.readdir(srcFolder); return filenames.map((name) => join(srcFolder, name)); }; export const resolveFunctionsDirectories = (input) => { const directories = Array.isArray(input) ? input : [input]; const absoluteDirectories = directories.map((srcFolder) => resolve(srcFolder)); return absoluteDirectories; }; export const mkdirAndWriteFile = async (path, ...params) => { if (typeof path === 'string') { const directory = dirname(path); await fs.mkdir(directory, { recursive: true }); } return fs.writeFile(path, ...params); };