From 6cdc8a494060a91d3c261e1cec3a5565c0b4a388 Mon Sep 17 00:00:00 2001 From: Aditya Singh Date: Sun, 24 May 2026 05:08:15 -0700 Subject: [PATCH] fix: narrow over-broad default pack exclude patterns The default EXCLUDE_PATTERNS dropped real runtime code from packed bundles in two cases: - "*.map" matched any path component ending in ".map", including directories. Packages like es-iterator-helpers ship directories named Iterator.prototype.map/ whose contents are ordinary .js files, so the whole directory was excluded and the bundle crashed at module load. This narrows the pattern to actual source maps (*.js.map, *.cjs.map, *.mjs.map, *.css.map, *.ts.map). - "node_modules/.bin" excluded the CLI shim directory, which some packages reference (for example via existsSync) at module-load time. Removing it from the defaults keeps those shims in the bundle; users who want it gone can add it to their own .mcpbignore. Adds regression tests covering both cases. Fixes #241 --- src/node/files.ts | 10 ++++- test/mcpbignore.test.ts | 98 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/node/files.ts b/src/node/files.ts index 36e64f8..6af07e1 100644 --- a/src/node/files.ts +++ b/src/node/files.ts @@ -24,8 +24,14 @@ export const EXCLUDE_PATTERNS = [ ".babelrc", ".pnp.*", "node_modules/.cache", - "node_modules/.bin", - "*.map", + // Match only source map files. A bare "*.map" also matches directories whose + // name ends in ".map" (for example es-iterator-helpers ships + // Iterator.prototype.map/), silently dropping their runtime code. See #241. + "*.js.map", + "*.cjs.map", + "*.mjs.map", + "*.css.map", + "*.ts.map", ".env.local", ".env.*.local", "npm-debug.log*", diff --git a/test/mcpbignore.test.ts b/test/mcpbignore.test.ts index 26e5ee1..fdc3c24 100644 --- a/test/mcpbignore.test.ts +++ b/test/mcpbignore.test.ts @@ -309,4 +309,102 @@ coverage/`; expect(shouldExclude("debug.log", additionalPatterns)).toBe(true); }); }); + + // Regression tests for #241: the default exclude patterns used to be broad + // enough to drop real runtime code from the bundle. + describe("Default exclude patterns (issue #241)", () => { + it("should still exclude source map files by default", () => { + expect(shouldExclude("dist/index.js.map")).toBe(true); + expect(shouldExclude("dist/index.cjs.map")).toBe(true); + expect(shouldExclude("dist/index.mjs.map")).toBe(true); + expect(shouldExclude("dist/styles.css.map")).toBe(true); + expect(shouldExclude("dist/index.ts.map")).toBe(true); + }); + + it("should not exclude directories whose name ends in .map", () => { + // es-iterator-helpers ships directories such as Iterator.prototype.map/ + // whose contents are real runtime code, not source maps. + expect( + shouldExclude( + "node_modules/es-iterator-helpers/Iterator.prototype.map", + ), + ).toBe(false); + expect( + shouldExclude( + "node_modules/es-iterator-helpers/Iterator.prototype.map/index.js", + ), + ).toBe(false); + expect( + shouldExclude( + "node_modules/es-iterator-helpers/Iterator.prototype.flatMap/index.js", + ), + ).toBe(false); + }); + + it("should not exclude a file that merely ends in .map", () => { + // A bare "*.map" matched these; only true source maps should be dropped. + expect(shouldExclude("data/world.map")).toBe(false); + expect(shouldExclude("src/site.map")).toBe(false); + }); + + it("should not exclude node_modules/.bin by default", () => { + // Some packages reference node_modules/.bin shims at module-load time. + expect(shouldExclude("node_modules/.bin")).toBe(false); + expect(shouldExclude("node_modules/.bin/retire")).toBe(false); + }); + + it("should still exclude node_modules/.cache by default", () => { + expect(shouldExclude("node_modules/.cache")).toBe(true); + expect(shouldExclude("node_modules/.cache/some-file")).toBe(true); + }); + }); + + describe("getAllFiles default exclusions (issue #241)", () => { + let tempDir: string; + + beforeEach(() => { + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "mcpb-241-")); + }); + + afterEach(() => { + fs.rmSync(tempDir, { recursive: true, force: true }); + }); + + it("should keep .map-suffixed directories while dropping source maps", () => { + const pkgDir = path.join( + tempDir, + "node_modules", + "es-iterator-helpers", + "Iterator.prototype.map", + ); + fs.mkdirSync(pkgDir, { recursive: true }); + fs.writeFileSync(path.join(pkgDir, "index.js"), "module.exports = {};"); + + // A real source map sitting next to compiled output should still go away. + const distDir = path.join(tempDir, "dist"); + fs.mkdirSync(distDir, { recursive: true }); + fs.writeFileSync(path.join(distDir, "index.js"), "export default 1;"); + fs.writeFileSync(path.join(distDir, "index.js.map"), "{}"); + + const files = getAllFiles(tempDir, tempDir, {}, []); + const fileNames = Object.keys(files); + + expect(fileNames).toContain( + "node_modules/es-iterator-helpers/Iterator.prototype.map/index.js", + ); + expect(fileNames).toContain("dist/index.js"); + expect(fileNames).not.toContain("dist/index.js.map"); + }); + + it("should keep node_modules/.bin shims", () => { + const binDir = path.join(tempDir, "node_modules", ".bin"); + fs.mkdirSync(binDir, { recursive: true }); + fs.writeFileSync(path.join(binDir, "retire"), "#!/usr/bin/env node\n"); + + const files = getAllFiles(tempDir, tempDir, {}, []); + const fileNames = Object.keys(files); + + expect(fileNames).toContain("node_modules/.bin/retire"); + }); + }); });