Skip to content

Commit

Permalink
fix(deps): update dependency minimatch to v5 (#1032)
Browse files Browse the repository at this point in the history
* fix(deps): update dependency minimatch to v5

* chore(deps): update glob to v8

* refactor: wrap glob and minimatch to support windows paths

* refactor: ensure exclude patterns are unix paths

Also rename `exclude` to `excludePatterns` to clarify these are not os paths

Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Daniel Tschinder <231804+danez@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
4 people committed Jun 3, 2022
1 parent 0dd8174 commit 5aaf915
Show file tree
Hide file tree
Showing 11 changed files with 480 additions and 96 deletions.
453 changes: 407 additions & 46 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Expand Up @@ -65,12 +65,13 @@
"execa": "^5.0.0",
"filter-obj": "^2.0.1",
"find-up": "^5.0.0",
"glob": "^7.1.6",
"glob": "^8.0.3",
"is-builtin-module": "^3.1.0",
"junk": "^3.1.0",
"locate-path": "^6.0.0",
"merge-options": "^3.0.4",
"minimatch": "^4.0.0",
"minimatch": "^5.0.0",
"normalize-path": "^3.0.0",
"p-map": "^4.0.0",
"path-exists": "^4.0.0",
"pkg-dir": "^5.0.0",
Expand All @@ -89,6 +90,7 @@
"@netlify/eslint-config-node": "^6.0.0",
"@types/archiver": "^5.1.1",
"@types/end-of-stream": "^1.4.1",
"@types/normalize-path": "^3.0.0",
"@types/resolve": "^1.20.1",
"@types/semver": "^7.3.8",
"@types/unixify": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/config.ts
@@ -1,9 +1,9 @@
import mergeOptions from 'merge-options'
import minimatch from 'minimatch'

import { FunctionSource } from './function.js'
import type { NodeBundlerName } from './runtimes/node/bundlers/index.js'
import type { NodeVersionString } from './runtimes/node/index.js'
import { minimatch } from './utils/matching.js'

export interface FunctionConfig {
externalNodeModules?: string[]
Expand Down
4 changes: 2 additions & 2 deletions src/runtimes/node/bundlers/esbuild/plugin_dynamic_imports.ts
Expand Up @@ -2,8 +2,8 @@ import { basename, join, relative } from 'path'

import type { Plugin } from '@netlify/esbuild'
import findUp from 'find-up'
import normalizePath from 'normalize-path'
import readPackageJson from 'read-package-json-fast'
import unixify from 'unixify'

import { parseExpression } from '../../parser/index.js'

Expand Down Expand Up @@ -125,7 +125,7 @@ const getShimContents = ({
// relative to the main bundle file, since esbuild will flatten everything
// into a single file.
const relativeResolveDir = relative(srcDir, resolveDir)
const requireArg = relativeResolveDir ? `\`./${unixify(relativeResolveDir)}/$\{args}\`` : 'args'
const requireArg = relativeResolveDir ? `\`./${normalizePath(relativeResolveDir)}/$\{args}\`` : 'args'

if (expressionType === 'require') {
return `module.exports = args => require(${requireArg})`
Expand Down
6 changes: 3 additions & 3 deletions src/runtimes/node/bundlers/esbuild/src_files.ts
Expand Up @@ -6,7 +6,7 @@ import { getDependencyPathsForDependency } from '../zisi/traverse.js'

export const getSrcFiles: GetSrcFilesFunction = async ({ config, mainFile, pluginsModulesPath, srcDir }) => {
const { externalNodeModules = [], includedFiles = [], includedFilesBasePath } = config
const { exclude: excludedPaths, paths: includedFilePaths } = await getPathsOfIncludedFiles(
const { excludePatterns, paths: includedFilePaths } = await getPathsOfIncludedFiles(
includedFiles,
includedFilesBasePath,
)
Expand All @@ -15,8 +15,8 @@ export const getSrcFiles: GetSrcFilesFunction = async ({ config, mainFile, plugi
basedir: srcDir,
pluginsModulesPath,
})
const srcFiles = filterExcludedPaths(dependencyPaths, excludedPaths)
const includedPaths = filterExcludedPaths(includedFilePaths, excludedPaths)
const srcFiles = filterExcludedPaths(dependencyPaths, excludePatterns)
const includedPaths = filterExcludedPaths(includedFilePaths, excludePatterns)

return {
srcFiles: [...srcFiles, ...includedPaths, mainFile],
Expand Down
19 changes: 9 additions & 10 deletions src/runtimes/node/bundlers/nft/index.ts
Expand Up @@ -2,12 +2,11 @@ import { basename, dirname, join, normalize, resolve } from 'path'

import { nodeFileTrace } from '@vercel/nft'
import resolveDependency from '@vercel/nft/out/resolve-dependency.js'
import minimatch from 'minimatch'
import unixify from 'unixify'

import type { FunctionConfig } from '../../../../config.js'
import { FeatureFlags } from '../../../../feature_flags.js'
import { cachedReadFile, FsCache } from '../../../../utils/fs.js'
import { minimatch } from '../../../../utils/matching.js'
import { getBasePath } from '../../utils/base_path.js'
import { filterExcludedPaths, getPathsOfIncludedFiles } from '../../utils/included_files.js'
import type { GetSrcFilesFunction, BundleFunction } from '../index.js'
Expand All @@ -29,7 +28,7 @@ const bundle: BundleFunction = async ({
repositoryRoot = basePath,
}) => {
const { includedFiles = [], includedFilesBasePath } = config
const { exclude: excludedPaths, paths: includedFilePaths } = await getPathsOfIncludedFiles(
const { excludePatterns, paths: includedFilePaths } = await getPathsOfIncludedFiles(
includedFiles,
includedFilesBasePath || basePath,
)
Expand All @@ -45,15 +44,16 @@ const bundle: BundleFunction = async ({
pluginsModulesPath,
name,
})
const filteredIncludedPaths = filterExcludedPaths([...dependencyPaths, ...includedFilePaths], excludedPaths)
const includedPaths = filterExcludedPaths(includedFilePaths, excludePatterns)
const filteredIncludedPaths = [...filterExcludedPaths(dependencyPaths, excludePatterns), ...includedPaths]
const dirnames = filteredIncludedPaths.map((filePath) => normalize(dirname(filePath))).sort()

// Sorting the array to make the checksum deterministic.
const srcFiles = [...filteredIncludedPaths].sort()

return {
basePath: getBasePath(dirnames),
includedFiles: filterExcludedPaths(includedFilePaths, excludedPaths),
includedFiles: includedPaths,
inputs: dependencyPaths,
mainFile,
moduleFormat,
Expand All @@ -63,8 +63,7 @@ const bundle: BundleFunction = async ({
}

const ignoreFunction = (path: string) => {
const normalizedPath = unixify(path)
const shouldIgnore = ignore.some((expression) => minimatch(normalizedPath, expression))
const shouldIgnore = ignore.some((expression) => minimatch(path, expression))

return shouldIgnore
}
Expand Down Expand Up @@ -145,16 +144,16 @@ const traceFilesAndTranspile = async function ({

const getSrcFiles: GetSrcFilesFunction = async function ({ basePath, config, mainFile }) {
const { includedFiles = [], includedFilesBasePath } = config
const { exclude: excludedPaths, paths: includedFilePaths } = await getPathsOfIncludedFiles(
const { excludePatterns, paths: includedFilePaths } = await getPathsOfIncludedFiles(
includedFiles,
includedFilesBasePath,
)
const { fileList: dependencyPaths } = await nodeFileTrace([mainFile], { base: basePath, ignore: ignoreFunction })
const normalizedDependencyPaths = [...dependencyPaths].map((path) =>
basePath ? resolve(basePath, path) : resolve(path),
)
const srcFiles = filterExcludedPaths(normalizedDependencyPaths, excludedPaths)
const includedPaths = filterExcludedPaths(includedFilePaths, excludedPaths)
const srcFiles = filterExcludedPaths(normalizedDependencyPaths, excludePatterns)
const includedPaths = filterExcludedPaths(includedFilePaths, excludePatterns)

return {
srcFiles: [...srcFiles, ...includedPaths],
Expand Down
8 changes: 2 additions & 6 deletions src/runtimes/node/bundlers/zisi/published.ts
@@ -1,13 +1,9 @@
import { promisify } from 'util'

import glob from 'glob'

const pGlob = promisify(glob)
import { glob } from '../../../../utils/matching'

// We use all the files published by the Node.js except some that are not needed
export const getPublishedFiles = async function (modulePath: string): Promise<string[]> {
const ignore = getIgnoredFiles(modulePath)
const publishedFiles = await pGlob(`${modulePath}/**`, {
const publishedFiles = await glob(`${modulePath}/**`, {
ignore,
nodir: true,
absolute: true,
Expand Down
6 changes: 3 additions & 3 deletions src/runtimes/node/bundlers/zisi/src_files.ts
Expand Up @@ -31,7 +31,7 @@ export const getSrcFiles: GetSrcFilesFunction = async function ({
stat,
}) {
const { includedFiles = [], includedFilesBasePath } = config
const { exclude: excludedPaths, paths: includedFilePaths } = await getPathsOfIncludedFiles(
const { excludePatterns, paths: includedFilePaths } = await getPathsOfIncludedFiles(
includedFiles,
includedFilesBasePath,
)
Expand All @@ -45,8 +45,8 @@ export const getSrcFiles: GetSrcFilesFunction = async function ({
// We sort so that the archive's checksum is deterministic.
// Mutating is fine since `Array.filter()` returns a shallow copy
const filteredFiles = uniqueFiles.filter(isNotJunk).sort()
const srcFiles = filterExcludedPaths(filteredFiles, excludedPaths)
const includedPaths = filterExcludedPaths(includedFilePaths, excludedPaths)
const srcFiles = filterExcludedPaths(filteredFiles, excludePatterns)
const includedPaths = filterExcludedPaths(includedFilePaths, excludePatterns)

return { srcFiles: [...srcFiles, ...includedPaths], includedFiles: includedPaths }
}
Expand Down
9 changes: 3 additions & 6 deletions src/runtimes/node/bundlers/zisi/tree_files.ts
@@ -1,17 +1,14 @@
import { Stats } from 'fs'
import { promisify } from 'util'
import type { Stats } from 'fs'

import glob from 'glob'

const pGlob = promisify(glob)
import { glob } from '../../../../utils/matching'

// When using a directory, we include all its descendants except `node_modules`
export const getTreeFiles = async function (srcPath: string, stat: Stats): Promise<string[]> {
if (!stat.isDirectory()) {
return [srcPath]
}

return await pGlob(`${srcPath}/**`, {
return await glob(`${srcPath}/**`, {
ignore: `${srcPath}/**/node_modules/**`,
nodir: true,
absolute: true,
Expand Down
34 changes: 17 additions & 17 deletions src/runtimes/node/utils/included_files.ts
@@ -1,61 +1,61 @@
import { normalize, resolve } from 'path'
import { promisify } from 'util'

import glob from 'glob'
import minimatch from 'minimatch'

const pGlob = promisify(glob)
import { minimatch, glob } from '../../../utils/matching'

// Returns the subset of `paths` that don't match any of the glob expressions
// from `exclude`.
export const filterExcludedPaths = (paths: string[], exclude: string[] = []) => {
if (exclude.length === 0) {
export const filterExcludedPaths = (paths: string[], excludePattern: string[] = []) => {
if (excludePattern.length === 0) {
return paths
}

const excludedPaths = paths.filter((path) => !exclude.some((pattern) => minimatch(path, pattern)))
const excludedPaths = paths.filter((path) => !excludePattern.some((pattern) => minimatch(path, pattern)))

return excludedPaths
}

export const getPathsOfIncludedFiles = async (
includedFiles: string[],
basePath?: string,
): Promise<{ exclude: string[]; paths: string[] }> => {
): Promise<{ excludePatterns: string[]; paths: string[] }> => {
if (basePath === undefined) {
return { exclude: [], paths: [] }
return { excludePatterns: [], paths: [] }
}

// Some of the globs in `includedFiles` might be exclusion patterns, which
// means paths that should NOT be included in the bundle. We need to treat
// these differently, so we iterate on the array and put those paths in a
// `exclude` array and the rest of the paths in an `include` array.
const { include, exclude } = includedFiles.reduce<{ include: string[]; exclude: string[] }>(
const { include, excludePatterns } = includedFiles.reduce<{ include: string[]; excludePatterns: string[] }>(
(acc, path) => {
if (path.startsWith('!')) {
const excludePath = resolve(basePath, path.slice(1))
// convert to unix paths, as minimatch does not support windows paths in patterns
const excludePattern = resolve(basePath, path.slice(1))

return {
include: acc.include,
exclude: [...acc.exclude, excludePath],
excludePatterns: [...acc.excludePatterns, excludePattern],
}
}

return {
include: [...acc.include, path],
exclude: acc.exclude,
excludePatterns: acc.excludePatterns,
}
},
{ include: [], exclude: [] },
{ include: [], excludePatterns: [] },
)

const pathGroups = await Promise.all(
include.map((expression) => pGlob(expression, { absolute: true, cwd: basePath, ignore: exclude, nodir: true })),
include.map((expression) =>
glob(expression, { absolute: true, cwd: basePath, ignore: excludePatterns, nodir: true }),
),
)

// `pathGroups` is an array containing the paths for each expression in the
// `include` array. We flatten it into a single dimension.
const paths = pathGroups.flat()
const normalizedPaths = paths.map(normalize)

return { exclude, paths: [...new Set(normalizedPaths)] }
return { excludePatterns, paths: [...new Set(normalizedPaths)] }
}
29 changes: 29 additions & 0 deletions src/utils/matching.ts
@@ -0,0 +1,29 @@
import { promisify } from 'util'

import globFunction from 'glob'
import minimatchFunction from 'minimatch'
import normalizePath from 'normalize-path'

const pGlob = promisify(globFunction)

/**
* Both glob and minimatch only support unix style slashes in patterns
* For this reason we wrap them and ensure all patters 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: globFunction.IOptions): Promise<string[]> {
let normalizedIgnore
if (options.ignore) {
normalizedIgnore =
typeof options.ignore === 'string'
? normalizePath(options.ignore)
: options.ignore.map((expression) => normalizePath(expression))
}

return pGlob(normalizePath(pattern), { ...options, ignore: normalizedIgnore })
}

export const minimatch = function (target: string, pattern: string, options?: minimatchFunction.IOptions): boolean {
return minimatchFunction(target, normalizePath(pattern), options)
}

1 comment on commit 5aaf915

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⏱ Benchmark results

largeDepsEsbuild: 7.2s

largeDepsNft: 34.8s

Please sign in to comment.