From 0b4b5c26920cebb7954bdb2c636c975d15528f0d Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 13 Mar 2024 16:16:02 -0700 Subject: [PATCH] fix: handle path negations when scanning public assets (#2250) --- src/build.ts | 27 +++++++++++++++++++-------- test/fixture/nitro.config.ts | 8 +++++++- test/fixture/public/_unignored.txt | 1 + test/presets/cloudflare-pages.test.ts | 1 + test/tests.ts | 9 +++++++++ 5 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 test/fixture/public/_unignored.txt diff --git a/src/build.ts b/src/build.ts index 7194bbd9fe..3cb75dc6d8 100644 --- a/src/build.ts +++ b/src/build.ts @@ -48,6 +48,9 @@ async function prepareDir(dir: string) { await fse.emptyDir(dir); } +const NEGATION_RE = /^(!?)(.*)$/; +const PARENT_DIR_GLOB_RE = /!?\.\.\//; + export async function copyPublicAssets(nitro: Nitro) { if (nitro.options.noPublicDir) { return; @@ -56,17 +59,25 @@ export async function copyPublicAssets(nitro: Nitro) { const srcDir = asset.dir; const dstDir = join(nitro.options.output.publicDir, asset.baseURL!); if (await isDirectory(srcDir)) { - const publicAssets = await globby("**", { + const includePatterns = [ + "**", + ...nitro.options.ignore.map((p) => { + const [_, negation, pattern] = p.match(NEGATION_RE); + return ( + // Convert ignore to include patterns + (negation ? "" : "!") + + // Make non-glob patterns relative to publicAssetDir + (pattern.startsWith("*") + ? pattern + : relative(srcDir, resolve(nitro.options.srcDir, pattern))) + ); + }), + ].filter((p) => !PARENT_DIR_GLOB_RE.test(p)); + + const publicAssets = await globby(includePatterns, { cwd: srcDir, absolute: false, dot: true, - ignore: nitro.options.ignore - .map((p) => - p.startsWith("*") || p.startsWith("!*") - ? p - : relative(srcDir, resolve(nitro.options.srcDir, p)) - ) - .filter((p) => !p.startsWith("../")), }); await Promise.all( publicAssets.map(async (file) => { diff --git a/test/fixture/nitro.config.ts b/test/fixture/nitro.config.ts index 22a88f19c7..069bb7eadc 100644 --- a/test/fixture/nitro.config.ts +++ b/test/fixture/nitro.config.ts @@ -32,7 +32,13 @@ export default defineNitroConfig({ dir: "files", }, ], - ignore: ["api/**/_*", "middleware/_ignored.ts", "routes/_*.ts", "**/_*.txt"], + ignore: [ + "api/**/_*", + "middleware/_ignored.ts", + "routes/_*.ts", + "**/_*.txt", + "!**/_unignored.txt", + ], appConfig: { "nitro-config": true, dynamic: "initial", diff --git a/test/fixture/public/_unignored.txt b/test/fixture/public/_unignored.txt new file mode 100644 index 0000000000..e65274a35a --- /dev/null +++ b/test/fixture/public/_unignored.txt @@ -0,0 +1 @@ +This file should not be ignored! diff --git a/test/presets/cloudflare-pages.test.ts b/test/presets/cloudflare-pages.test.ts index 4a21ecb5fa..d3c98ec9e7 100644 --- a/test/presets/cloudflare-pages.test.ts +++ b/test/presets/cloudflare-pages.test.ts @@ -40,6 +40,7 @@ describe.skipIf(isWindows)("nitro:preset:cloudflare-pages", async () => { "exclude": [ "/blog/static/*", "/build/*", + "/_unignored.txt", "/favicon.ico", "/json-string", "/api/hello", diff --git a/test/tests.ts b/test/tests.ts index 1007863912..7707a6e2f2 100644 --- a/test/tests.ts +++ b/test/tests.ts @@ -539,6 +539,15 @@ export function testNitro( expect((await callHandler({ url: "/favicon.ico" })).status).toBe(200); } ); + + it.skipIf(ctx.isWorker || ctx.isDev)( + "public files can be un-ignored with patterns", + async () => { + expect((await callHandler({ url: "/_unignored.txt" })).status).toBe( + 200 + ); + } + ); }); describe("headers", () => {