From 24fb7797d9b8d6cd74ca4289ff310745730bad71 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 24 Jun 2024 10:12:14 +0100 Subject: [PATCH] chore: Extract fs helpers into shared internal-helpers package (#11323) --- packages/integrations/vercel/src/lib/fs.ts | 93 ------------------- packages/integrations/vercel/src/lib/nft.ts | 4 +- .../vercel/src/serverless/adapter.ts | 2 +- .../integrations/vercel/src/static/adapter.ts | 2 +- 4 files changed, 4 insertions(+), 97 deletions(-) delete mode 100644 packages/integrations/vercel/src/lib/fs.ts diff --git a/packages/integrations/vercel/src/lib/fs.ts b/packages/integrations/vercel/src/lib/fs.ts deleted file mode 100644 index 152ee7d7c0..0000000000 --- a/packages/integrations/vercel/src/lib/fs.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type { PathLike } from 'node:fs'; -import { existsSync } from 'node:fs'; -import * as fs from 'node:fs/promises'; -import nodePath from 'node:path'; -import { fileURLToPath } from 'node:url'; - -export async function writeJson(path: PathLike, data: T) { - await fs.writeFile(path, JSON.stringify(data, null, '\t'), { encoding: 'utf-8' }); -} - -export async function removeDir(dir: PathLike) { - await fs.rm(dir, { recursive: true, force: true, maxRetries: 3 }); -} - -export async function emptyDir(dir: PathLike): Promise { - await removeDir(dir); - await fs.mkdir(dir, { recursive: true }); -} - -export async function getFilesFromFolder(dir: URL) { - const data = await fs.readdir(dir, { withFileTypes: true }); - let files: URL[] = []; - for (const item of data) { - if (item.isDirectory()) { - const moreFiles = await getFilesFromFolder(new URL(`./${item.name}/`, dir)); - files = files.concat(moreFiles); - } else { - files.push(new URL(`./${item.name}`, dir)); - } - } - return files; -} - -/** - * Copies files into a folder keeping the folder structure intact. - * The resulting file tree will start at the common ancestor. - * - * @param {URL[]} files A list of files to copy (absolute path). - * @param {URL} outDir Destination folder where to copy the files to (absolute path). - * @param {URL[]} [exclude] A list of files to exclude (absolute path). - * @returns {Promise} The common ancestor of the copied files. - */ -export async function copyFilesToFunction( - files: URL[], - outDir: URL, - exclude: URL[] = [] -): Promise { - const excludeList = exclude.map(fileURLToPath); - const fileList = files.map(fileURLToPath).filter((f) => !excludeList.includes(f)); - - if (files.length === 0) throw new Error('[@astrojs/vercel] No files found to copy'); - - let commonAncestor = nodePath.dirname(fileList[0]); - for (const file of fileList.slice(1)) { - while (!file.startsWith(commonAncestor)) { - commonAncestor = nodePath.dirname(commonAncestor); - } - } - - for (const origin of fileList) { - const dest = new URL(nodePath.relative(commonAncestor, origin), outDir); - - const realpath = await fs.realpath(origin); - const isSymlink = realpath !== origin; - const isDir = (await fs.stat(origin)).isDirectory(); - - // Create directories recursively - if (isDir && !isSymlink) { - await fs.mkdir(new URL('..', dest), { recursive: true }); - } else { - await fs.mkdir(new URL('.', dest), { recursive: true }); - } - - if (isSymlink) { - const realdest = fileURLToPath(new URL(nodePath.relative(commonAncestor, realpath), outDir)); - const target = nodePath.relative(fileURLToPath(new URL('.', dest)), realdest); - // NOTE: when building function per route, dependencies are linked at the first run, then there's no need anymore to do that once more. - // So we check if the destination already exists. If it does, move on. - // Symbolic links here are usually dependencies and not user code. Symbolic links exist because of the pnpm strategy. - if (!existsSync(dest)) { - await fs.symlink(target, dest, isDir ? 'dir' : 'file'); - } - } else if (!isDir) { - await fs.copyFile(origin, dest); - } - } - - return commonAncestor; -} - -export async function writeFile(path: PathLike, content: string) { - await fs.writeFile(path, content, { encoding: 'utf-8' }); -} diff --git a/packages/integrations/vercel/src/lib/nft.ts b/packages/integrations/vercel/src/lib/nft.ts index 3b54ae8cc5..eb80f08e52 100644 --- a/packages/integrations/vercel/src/lib/nft.ts +++ b/packages/integrations/vercel/src/lib/nft.ts @@ -1,7 +1,7 @@ import { relative as relativePath } from 'node:path'; import { fileURLToPath } from 'node:url'; import type { AstroIntegrationLogger } from 'astro'; -import { copyFilesToFunction } from './fs.js'; +import { copyFilesToFolder } from '@astrojs/internal-helpers/fs'; export async function copyDependenciesToFunction( { @@ -72,7 +72,7 @@ export async function copyDependenciesToFunction( } } - const commonAncestor = await copyFilesToFunction( + const commonAncestor = await copyFilesToFolder( [...result.fileList].map((file) => new URL(file, base)).concat(includeFiles), outDir, excludeFiles diff --git a/packages/integrations/vercel/src/serverless/adapter.ts b/packages/integrations/vercel/src/serverless/adapter.ts index aade471508..86bc0b400c 100644 --- a/packages/integrations/vercel/src/serverless/adapter.ts +++ b/packages/integrations/vercel/src/serverless/adapter.ts @@ -16,7 +16,7 @@ import { getAstroImageConfig, getDefaultImageConfig, } from '../image/shared.js'; -import { removeDir, writeJson } from '../lib/fs.js'; +import { removeDir, writeJson } from '@astrojs/internal-helpers/fs'; import { copyDependenciesToFunction } from '../lib/nft.js'; import { escapeRegex, getRedirects } from '../lib/redirects.js'; import { diff --git a/packages/integrations/vercel/src/static/adapter.ts b/packages/integrations/vercel/src/static/adapter.ts index 4a66c558ef..c83ce55ecc 100644 --- a/packages/integrations/vercel/src/static/adapter.ts +++ b/packages/integrations/vercel/src/static/adapter.ts @@ -6,7 +6,7 @@ import { getAstroImageConfig, getDefaultImageConfig, } from '../image/shared.js'; -import { emptyDir, writeJson } from '../lib/fs.js'; +import { emptyDir, writeJson } from '@astrojs/internal-helpers/fs'; import { isServerLikeOutput } from '../lib/prerender.js'; import { getRedirects } from '../lib/redirects.js'; import {