From 0283fb9991ace9abcab1f4978d20d04a3f15e505 Mon Sep 17 00:00:00 2001 From: nishu-murmu Date: Thu, 13 Mar 2025 13:39:59 +0530 Subject: [PATCH 1/7] feat: making negate regex pattern work in zip.exclude --- packages/wxt-demo/wxt.config.ts | 4 ++++ packages/wxt/src/core/zip.ts | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/wxt-demo/wxt.config.ts b/packages/wxt-demo/wxt.config.ts index 6961eea29..bca01bfa1 100644 --- a/packages/wxt-demo/wxt.config.ts +++ b/packages/wxt-demo/wxt.config.ts @@ -16,6 +16,10 @@ export default defineConfig({ }, zip: { downloadPackages: ['sass'], + exclude: [ + '**/*.json', // Exclude all .json files + '!manifest.json', // Include manifest.json + ], }, analysis: { open: true, diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index 092d5c27d..8e616ae92 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -113,6 +113,20 @@ async function zipDir( }, ): Promise { const archive = new JSZip(); + + function negateCheck(exclude: string[], relativePath: string) { + return exclude + ?.map((pattern) => { + if (pattern.startsWith('!')) { + if (relativePath.endsWith('.json')) { + console.log(minimatch(relativePath, pattern.slice(1))); + } + return minimatch(relativePath, pattern.slice(1)); + } + return false; + }) + .filter(Boolean); + } const files = ( await glob(['**/*', ...(options?.include || [])], { cwd: directory, @@ -121,9 +135,27 @@ async function zipDir( onlyFiles: true, }) ).filter((relativePath) => { + let shouldExclude = options?.exclude?.some((pattern) => + minimatch(relativePath, pattern), + ); + console.log( + negateCheck(options?.exclude as string[], relativePath), + relativePath, + ); + // shouldExclude = negateCheck(options?.exclude as string[], relativePath) + // ? true + // : shouldExclude; + // if (relativePath.endsWith('.json')) { + // console.log({ + // should: shouldExclude, + // relativePath, + // dd: options?.exclude, + // }); + // } + return ( options?.include?.some((pattern) => minimatch(relativePath, pattern)) || - !options?.exclude?.some((pattern) => minimatch(relativePath, pattern)) + shouldExclude ); }); const filesToZip = [ From 97aed7c0317f4ddb4a596a4a534f0fade7e06cd0 Mon Sep 17 00:00:00 2001 From: nishu-murmu Date: Sun, 16 Mar 2025 20:51:05 +0530 Subject: [PATCH 2/7] feat: exclude files in .zip except those with a bang ! --- packages/wxt/src/core/zip.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index 092d5c27d..babde3acc 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -121,9 +121,23 @@ async function zipDir( onlyFiles: true, }) ).filter((relativePath) => { + function negateCheck() { + return options?.exclude?.some( + (option) => + option.startsWith('!') && minimatch(relativePath, option.slice(1)), + ); + } + if (negateCheck()) { + return true; + } + const updatedExcludeOptions = options?.exclude?.filter( + (option) => !option.startsWith('!'), + ); return ( options?.include?.some((pattern) => minimatch(relativePath, pattern)) || - !options?.exclude?.some((pattern) => minimatch(relativePath, pattern)) + !updatedExcludeOptions?.some((pattern) => + minimatch(relativePath, pattern), + ) ); }); const filesToZip = [ From 1d9ebee16cb87f088252d6e015af1aa1f90e8287 Mon Sep 17 00:00:00 2001 From: nishu-murmu Date: Thu, 10 Apr 2025 16:12:29 +0530 Subject: [PATCH 3/7] chore: removed unused function. --- packages/wxt/src/core/zip.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index d67db5f51..23ae644c2 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -114,19 +114,6 @@ async function zipDir( ): Promise { const archive = new JSZip(); - function negateCheck(exclude: string[], relativePath: string) { - return exclude - ?.map((pattern) => { - if (pattern.startsWith('!')) { - if (relativePath.endsWith('.json')) { - console.log(minimatch(relativePath, pattern.slice(1))); - } - return minimatch(relativePath, pattern.slice(1)); - } - return false; - }) - .filter(Boolean); - } const files = ( await glob(['**/*', ...(options?.include || [])], { cwd: directory, From ac9ecbbd59cf7154b7487b03d9de5ed555acbb1c Mon Sep 17 00:00:00 2001 From: nishu-murmu Date: Thu, 10 Apr 2025 16:15:11 +0530 Subject: [PATCH 4/7] chore: reverting code in wxt.config.ts in wxt-demo. --- packages/wxt-demo/wxt.config.ts | 4 ---- packages/wxt/src/core/zip.ts | 1 - 2 files changed, 5 deletions(-) diff --git a/packages/wxt-demo/wxt.config.ts b/packages/wxt-demo/wxt.config.ts index 91af1e0e6..eee9f5d39 100644 --- a/packages/wxt-demo/wxt.config.ts +++ b/packages/wxt-demo/wxt.config.ts @@ -15,10 +15,6 @@ export default defineConfig({ }, zip: { downloadPackages: ['sass'], - exclude: [ - '**/*.json', // Exclude all .json files - '!manifest.json', // Include manifest.json - ], }, analysis: { open: true, diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index 23ae644c2..e155739af 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -113,7 +113,6 @@ async function zipDir( }, ): Promise { const archive = new JSZip(); - const files = ( await glob(['**/*', ...(options?.include || [])], { cwd: directory, From 628af36ca659cc1de3dce10df4df45f8076d2041 Mon Sep 17 00:00:00 2001 From: nishu-murmu Date: Thu, 10 Apr 2025 23:32:27 +0530 Subject: [PATCH 5/7] chore: adding tests. --- packages/wxt/e2e/tests/zip.test.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/wxt/e2e/tests/zip.test.ts b/packages/wxt/e2e/tests/zip.test.ts index 3ff265aad..efde648f8 100644 --- a/packages/wxt/e2e/tests/zip.test.ts +++ b/packages/wxt/e2e/tests/zip.test.ts @@ -285,4 +285,26 @@ describe('Zipping', () => { expect(await project.fileExists(sourcesZip)).toBe(false); }, ); + + it('exclude files in .zip except those with a bang !', async () => { + const project = new TestProject({ + name: 'test', + version: '1.0.0', + }); + project.addFile( + 'entrypoints/background.ts', + 'export default defineBackground(() => {});', + ); + const unzipDir = project.resolvePath('.output/test-1.0.0-chrome'); + const sourcesZip = project.resolvePath('.output/test-1.0.0-chrome.zip'); + + await project.zip({ + zip: { + exclude: ['**/*.json', '!manifest.json'], + }, + }); + + await extract(sourcesZip, { dir: unzipDir }); + expect(await project.fileExists(unzipDir, 'manifest.json')).toBe(true); + }); }); From 6b1d61bfc27db066ee5e0e8faadff4de8416e698 Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 14 Jun 2025 16:40:33 -0500 Subject: [PATCH 6/7] Extract util and add unit tests, apply util to both `include` and `exclude`. --- packages/wxt/e2e/tests/zip.test.ts | 2 +- .../__tests__/minimatch-multiple.test.ts | 46 +++++++++++++++++++ .../wxt/src/core/utils/minimatch-multiple.ts | 40 ++++++++++++++++ packages/wxt/src/core/zip.ts | 15 ++---- 4 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 packages/wxt/src/core/utils/__tests__/minimatch-multiple.test.ts create mode 100644 packages/wxt/src/core/utils/minimatch-multiple.ts diff --git a/packages/wxt/e2e/tests/zip.test.ts b/packages/wxt/e2e/tests/zip.test.ts index efde648f8..c370097bc 100644 --- a/packages/wxt/e2e/tests/zip.test.ts +++ b/packages/wxt/e2e/tests/zip.test.ts @@ -286,7 +286,7 @@ describe('Zipping', () => { }, ); - it('exclude files in .zip except those with a bang !', async () => { + it('should include files in the zip when negated in zip.exclude', async () => { const project = new TestProject({ name: 'test', version: '1.0.0', diff --git a/packages/wxt/src/core/utils/__tests__/minimatch-multiple.test.ts b/packages/wxt/src/core/utils/__tests__/minimatch-multiple.test.ts new file mode 100644 index 000000000..34c078e13 --- /dev/null +++ b/packages/wxt/src/core/utils/__tests__/minimatch-multiple.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from 'vitest'; +import { minimatchMultiple } from '../minimatch-multiple'; + +describe('minimatchMultiple', () => { + it('should return false if the pattern array is undefined', () => { + const patterns = undefined; + const search = 'test.json'; + + expect(minimatchMultiple(search, patterns)).toBe(false); + }); + + it('should return false if the pattern array is empty', () => { + const patterns: string[] = []; + const search = 'test.json'; + + expect(minimatchMultiple(search, patterns)).toBe(false); + }); + + it('should return true if the pattern array contains a match', () => { + const patterns = ['test.yml', 'test.json']; + const search = 'test.json'; + + expect(minimatchMultiple(search, patterns)).toBe(true); + }); + + it('should return false if the pattern array does not contain a match', () => { + const patterns = ['test.yml', 'test.json']; + const search = 'test.txt'; + + expect(minimatchMultiple(search, patterns)).toBe(false); + }); + + it('should return false if the pattern matches a negative pattern', () => { + const patterns = ['test.*', '!test.json']; + const search = 'test.json'; + + expect(minimatchMultiple(search, patterns)).toBe(false); + }); + + it('should return false if the pattern matches a negative pattern, regardless of order', () => { + const patterns = ['!test.json', 'test.*']; + const search = 'test.json'; + + expect(minimatchMultiple(search, patterns)).toBe(false); + }); +}); diff --git a/packages/wxt/src/core/utils/minimatch-multiple.ts b/packages/wxt/src/core/utils/minimatch-multiple.ts new file mode 100644 index 000000000..be1bbf0e8 --- /dev/null +++ b/packages/wxt/src/core/utils/minimatch-multiple.ts @@ -0,0 +1,40 @@ +import { minimatch, MinimatchOptions } from 'minimatch'; + +/** + * Run [`minimatch`](https://npmjs.com/package/minimatch) against multiple + * patterns. + * + * Supports negated patterns, the order does not matter. If your `search` string + * matches any of the negative patterns, it will return `false`. + * + * @example + * ```ts + * minimatchMultiple('a.json', ['*.json', '!b.json']); // => true + * minimatchMultiple('b.json', ['*.json', '!b.json']); // => false + * ``` + */ +export function minimatchMultiple( + search: string, + patterns: string[] | undefined, + options?: MinimatchOptions, +): boolean { + if (patterns == null) return false; + + const negatePatterns: string[] = []; + const positivePatterns: string[] = []; + for (const pattern of patterns) { + if (pattern[0] === '!') negatePatterns.push(pattern.slice(1)); + else positivePatterns.push(pattern); + } + + if ( + negatePatterns.some((negatePattern) => + minimatch(search, negatePattern, options), + ) + ) + return false; + + return positivePatterns.some((positivePattern) => + minimatch(search, positivePattern, options), + ); +} diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index eac4a5666..67dbc402b 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -11,6 +11,7 @@ import { registerWxt, wxt } from './wxt'; import JSZip from 'jszip'; import glob from 'fast-glob'; import { normalizePath } from './utils/paths'; +import { minimatchMultiple } from './utils/minimatch-multiple'; /** * Build and zip the extension for distribution. @@ -121,19 +122,9 @@ async function zipDir( onlyFiles: true, }) ).filter((relativePath) => { - const isNegated = options?.exclude?.some( - (option) => - option.startsWith('!') && minimatch(relativePath, option.slice(1)), - ); - if (isNegated) return true; - const updatedExcludeOptions = options?.exclude?.filter( - (option) => !option.startsWith('!'), - ); return ( - options?.include?.some((pattern) => minimatch(relativePath, pattern)) || - !updatedExcludeOptions?.some((pattern) => - minimatch(relativePath, pattern), - ) + minimatchMultiple(relativePath, options?.include) || + !minimatchMultiple(relativePath, options?.exclude) ); }); const filesToZip = [ From ef8163be07041a62a8bf51e00fc342179ad05f5f Mon Sep 17 00:00:00 2001 From: Aaron Date: Sat, 14 Jun 2025 16:46:43 -0500 Subject: [PATCH 7/7] Fix lint --- packages/wxt/src/core/zip.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/wxt/src/core/zip.ts b/packages/wxt/src/core/zip.ts index 67dbc402b..70626d6ae 100644 --- a/packages/wxt/src/core/zip.ts +++ b/packages/wxt/src/core/zip.ts @@ -3,7 +3,6 @@ import path from 'node:path'; import fs from 'fs-extra'; import { safeFilename } from './utils/strings'; import { getPackageJson } from './utils/package'; -import { minimatch } from 'minimatch'; import { formatDuration } from './utils/time'; import { printFileList } from './utils/log/printFileList'; import { findEntrypoints, internalBuild } from './utils/building';