diff --git a/package-lock.json b/package-lock.json index 08f5eee408..c4bf9f1e1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11640,10 +11640,13 @@ } }, "node_modules/fdir": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", - "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -18596,9 +18599,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", "engines": { "node": ">=12" @@ -21551,14 +21554,13 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", - "dev": true, + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "license": "MIT", "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">=12.0.0" @@ -24045,9 +24047,9 @@ "devDependencies": { "cpy": "^11.0.0", "cpy-cli": "^5.0.0", - "fast-glob": "^3.2.12", "npm-run-all2": "^6.0.0", "rollup-plugin-node-polyfills": "^0.2.1", + "tinyglobby": "^0.2.13", "tmp-promise": "^3.0.2", "typescript": "^5.0.0", "vite": "^6.0.0", @@ -24398,7 +24400,6 @@ "es-module-lexer": "^1.0.0", "esbuild": "0.25.9", "execa": "^8.0.0", - "fast-glob": "^3.3.3", "filter-obj": "^6.0.0", "find-up": "^7.0.0", "is-path-inside": "^4.0.0", @@ -24413,6 +24414,7 @@ "require-package-name": "^2.0.1", "resolve": "^2.0.0-next.1", "semver": "^7.3.8", + "tinyglobby": "^0.2.15", "tmp-promise": "^3.0.2", "toml": "^3.0.0", "unixify": "^1.0.0", diff --git a/packages/zip-it-and-ship-it/package.json b/packages/zip-it-and-ship-it/package.json index 152bbb96e2..312bd746a9 100644 --- a/packages/zip-it-and-ship-it/package.json +++ b/packages/zip-it-and-ship-it/package.json @@ -52,7 +52,6 @@ "es-module-lexer": "^1.0.0", "esbuild": "0.25.9", "execa": "^8.0.0", - "fast-glob": "^3.3.3", "filter-obj": "^6.0.0", "find-up": "^7.0.0", "is-path-inside": "^4.0.0", @@ -67,6 +66,7 @@ "require-package-name": "^2.0.1", "resolve": "^2.0.0-next.1", "semver": "^7.3.8", + "tinyglobby": "^0.2.15", "tmp-promise": "^3.0.2", "toml": "^3.0.0", "unixify": "^1.0.0", diff --git a/packages/zip-it-and-ship-it/src/runtimes/node/utils/included_files.ts b/packages/zip-it-and-ship-it/src/runtimes/node/utils/included_files.ts index 2fe32ba394..686f7fe765 100644 --- a/packages/zip-it-and-ship-it/src/runtimes/node/utils/included_files.ts +++ b/packages/zip-it-and-ship-it/src/runtimes/node/utils/included_files.ts @@ -1,6 +1,7 @@ import { normalize, resolve } from 'path' +import { lstatSync } from 'fs' -import glob from 'fast-glob' +import { glob } from 'tinyglobby' import { minimatch } from '../../../utils/matching.js' @@ -54,14 +55,21 @@ export const getPathsOfIncludedFiles = async ( dot: true, ignore: excludePatterns, onlyFiles: false, - // get directories as well to get symlinked directories, - // to filter the regular non symlinked directories out mark them with a slash at the end to filter them out. - markDirectories: true, followSymbolicLinks: false, + expandDirectories: false, }) - const paths = pathGroups.filter((path) => !path.endsWith('/')).map(normalize) + const paths = pathGroups.filter(pathFilter).map(normalize) // now filter the non symlinked directories out that got marked with a trailing slash return { excludePatterns, paths } } + +function pathFilter(path: string) { + try { + const stats = lstatSync(path) + return !stats.isDirectory() || stats.isSymbolicLink() + } catch (_err) { + return false + } +} diff --git a/packages/zip-it-and-ship-it/src/utils/matching.ts b/packages/zip-it-and-ship-it/src/utils/matching.ts index 08665faf3e..218bbdfc9e 100644 --- a/packages/zip-it-and-ship-it/src/utils/matching.ts +++ b/packages/zip-it-and-ship-it/src/utils/matching.ts @@ -1,15 +1,16 @@ -import originalGlob from 'fast-glob' import { minimatch as minimatchFunction, type MinimatchOptions } from 'minimatch' import normalizePath from 'normalize-path' +import { glob as originalGlob, type GlobOptions } from 'tinyglobby' /** * Both glob and minimatch only support unix style slashes in patterns * For this reason we wrap them and ensure all patterns are always unixified * We use `normalize-path` here instead of `unixify` because we do not want to remove drive letters */ -export const glob = function (pattern: string, options: originalGlob.Options): Promise { - const normalizedIgnore = options.ignore?.map((expression) => normalizePath(expression)) - return originalGlob(normalizePath(pattern), { ...options, ignore: normalizedIgnore }) +export const glob = function (pattern: string, options: GlobOptions): Promise { + const ignore: string[] = Array.isArray(options.ignore) ? options.ignore : options.ignore ? [options.ignore] : [] + const normalizedIgnore = ignore.map((expression) => normalizePath(expression)) + return originalGlob(normalizePath(pattern), { ...options, ignore: normalizedIgnore, expandDirectories: false }) } export const minimatch = function (target: string, pattern: string, options?: MinimatchOptions): boolean { diff --git a/packages/zip-it-and-ship-it/tests/main.test.ts b/packages/zip-it-and-ship-it/tests/main.test.ts index 035b0c2308..c8bc878a7a 100644 --- a/packages/zip-it-and-ship-it/tests/main.test.ts +++ b/packages/zip-it-and-ship-it/tests/main.test.ts @@ -6,10 +6,10 @@ import cpy from 'cpy' import decompress from 'decompress' import merge from 'deepmerge' import { execa, execaNode } from 'execa' -import glob from 'fast-glob' import isCI from 'is-ci' import { pathExists } from 'path-exists' import semver from 'semver' +import { glob } from 'tinyglobby' import { dir as getTmpDir, tmpName } from 'tmp-promise' import unixify from 'unixify' import { afterAll, afterEach, beforeAll, describe, expect, test, vi } from 'vitest' @@ -2854,7 +2854,7 @@ describe('zip-it-and-ship-it', () => { await decompress(files[0].path, unzipPath) - const fileNames: string[] = await glob('**', { dot: true, cwd: unzipPath }) + const fileNames: string[] = await glob('**', { dot: true, cwd: unzipPath, expandDirectories: false }) const duplicates = fileNames.filter((item, index) => fileNames.indexOf(item) !== index) expect(duplicates).toHaveLength(0) }) diff --git a/packages/zip-it-and-ship-it/tests/telemetry.test.ts b/packages/zip-it-and-ship-it/tests/telemetry.test.ts index cc5730d9ae..806552cf65 100644 --- a/packages/zip-it-and-ship-it/tests/telemetry.test.ts +++ b/packages/zip-it-and-ship-it/tests/telemetry.test.ts @@ -1,7 +1,7 @@ import { join } from 'path' import decompress from 'decompress' -import glob from 'fast-glob' +import { glob } from 'tinyglobby' import { dir as getTmpDir } from 'tmp-promise' import { expect, test } from 'vitest' @@ -31,7 +31,7 @@ test('The telemetry file should be added by default to the function bundle', asy await decompress(result!.path, unzippedPath) - const files = await glob('**/*', { cwd: unzippedPath }) + const files = await glob('**/*', { cwd: unzippedPath, expandDirectories: false }) expect(files.sort()).toEqual([ '___netlify-bootstrap.mjs', '___netlify-entry-point.mjs', diff --git a/packages/zip-it-and-ship-it/tests/v2api.test.ts b/packages/zip-it-and-ship-it/tests/v2api.test.ts index 1c15df6b90..0182d1bf89 100644 --- a/packages/zip-it-and-ship-it/tests/v2api.test.ts +++ b/packages/zip-it-and-ship-it/tests/v2api.test.ts @@ -4,8 +4,8 @@ import { platform } from 'process' import { getPath as getBootstrapPath } from '@netlify/serverless-functions-api' import merge from 'deepmerge' -import glob from 'fast-glob' import { pathExists } from 'path-exists' +import { glob } from 'tinyglobby' import { dir as getTmpDir } from 'tmp-promise' import { afterEach, describe, expect, test, vi } from 'vitest' @@ -128,7 +128,7 @@ describe('V2 functions API', () => { const [{ name: archive, entryFilename, path }] = files - const untranspiledFiles = await glob(`${path}/**/*.ts`) + const untranspiledFiles = await glob(`${path}/**/*.ts`, { expandDirectories: false }) expect(untranspiledFiles).toEqual([]) const func = await importFunctionFile(`${tmpDir}/${archive}/${entryFilename}`)