diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsup_monorepo/snapshots/migration_from_tsup_monorepo_success.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsup_monorepo/snapshots/migration_from_tsup_monorepo_success.md index 3aa0b6d868..8b4451c9ce 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsup_monorepo/snapshots/migration_from_tsup_monorepo_success.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_from_tsup_monorepo/snapshots/migration_from_tsup_monorepo_success.md @@ -13,8 +13,8 @@ VITE+ - The Unified Toolchain for the Web • 5 config updates applied, 2 files had imports rewritten • tsup config migrated to tsdown (`vp pack`) → Manual follow-up: - - Please manually merge packages/b/tsdown.config.ts into packages/b/vite.config.ts, see https://viteplus.dev/guide/migrate#tsdown - Please manually merge packages/a/tsdown.config.ts into packages/a/vite.config.ts, see https://viteplus.dev/guide/migrate#tsdown + - Please manually merge packages/b/tsdown.config.ts into packages/b/vite.config.ts, see https://viteplus.dev/guide/migrate#tsdown ``` ## `vpt stat-file packages/a/tsup.config.ts --assert-not file` diff --git a/packages/cli/package.json b/packages/cli/package.json index 39d76fd233..ebd12550f1 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -376,12 +376,12 @@ "cross-spawn": "catalog:", "detect-indent": "catalog:", "detect-newline": "catalog:", - "glob": "catalog:", "jsonc-parser": "catalog:", "lint-staged": "catalog:", "minimatch": "catalog:", "nanotar": "catalog:", "picocolors": "catalog:", + "tinyglobby": "catalog:", "tsdown": "catalog:", "validate-npm-package-name": "catalog:", "verkit": "catalog:", diff --git a/packages/cli/src/__tests__/versions.spec.ts b/packages/cli/src/__tests__/versions.spec.ts index 51fb890c09..141a44d8a0 100644 --- a/packages/cli/src/__tests__/versions.spec.ts +++ b/packages/cli/src/__tests__/versions.spec.ts @@ -9,7 +9,7 @@ import { createRequire } from 'node:module'; import path from 'node:path'; import url from 'node:url'; -import { globSync } from 'glob'; +import { globSync } from 'tinyglobby'; import { describe, expect, it } from 'vitest'; const cliPkgDir = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), '../..'); diff --git a/packages/cli/src/migration/__tests__/migrator.spec.ts b/packages/cli/src/migration/__tests__/migrator.spec.ts index 5f2b4839a0..8f3a5c68f6 100644 --- a/packages/cli/src/migration/__tests__/migrator.spec.ts +++ b/packages/cli/src/migration/__tests__/migrator.spec.ts @@ -1494,7 +1494,7 @@ describe('migrateSetupVpVersion', () => { it('updates exact v1 references in workflows and composite actions', () => { const workflowsDir = path.join(tmpDir, '.github', 'workflows'); const actionDir = path.join(tmpDir, '.github', 'actions', 'setup'); - fs.mkdirSync(path.join(workflowsDir, 'nested'), { recursive: true }); + fs.mkdirSync(path.join(workflowsDir, 'nested.yml'), { recursive: true }); fs.mkdirSync(actionDir, { recursive: true }); const workflowPath = path.join(workflowsDir, 'ci.yml'); @@ -1517,7 +1517,7 @@ describe('migrateSetupVpVersion', () => { actionPath, 'runs:\n using: composite\n steps:\n - uses : voidzero-dev/setup-vp@v1\n', ); - const nestedWorkflowPath = path.join(workflowsDir, 'nested', 'ignored.yml'); + const nestedWorkflowPath = path.join(workflowsDir, 'nested.yml', 'ignored.yml'); fs.writeFileSync(nestedWorkflowPath, '- uses: voidzero-dev/setup-vp@v1\n'); const report = createMigrationReport(); diff --git a/packages/cli/src/migration/migrator/setup.ts b/packages/cli/src/migration/migrator/setup.ts index c889777abd..d864f93227 100644 --- a/packages/cli/src/migration/migrator/setup.ts +++ b/packages/cli/src/migration/migrator/setup.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import path from 'node:path'; import * as prompts from '@voidzero-dev/vite-plus-prompts'; -import { globSync } from 'glob'; +import { globSync } from 'tinyglobby'; import { normalize, normalizeRange } from 'verkit'; import { parse as parseYaml } from 'yaml'; @@ -149,8 +149,9 @@ function collectGithubActionFiles(projectPath: string): string[] { const globOptions = { cwd: path.join(projectPath, '.github'), absolute: true, - nocase: true, - nodir: true, + caseSensitiveMatch: false, + // Otherwise a directory named like `ci.yml` also matches as `ci.yml/**`. + expandDirectories: false, } as const; const workflows = globSync('workflows/*.{yml,yaml}', globOptions); const compositeActions = globSync('**/action.{yml,yaml}', { diff --git a/packages/cli/src/utils/__tests__/workspace.spec.ts b/packages/cli/src/utils/__tests__/workspace.spec.ts index a8b860c021..716923df11 100644 --- a/packages/cli/src/utils/__tests__/workspace.spec.ts +++ b/packages/cli/src/utils/__tests__/workspace.spec.ts @@ -185,8 +185,8 @@ describe('discoverWorkspacePackages', () => { const names = packages.map((p) => p.name).toSorted(); expect(names).toEqual(['bar', 'foo']); const foo = packages.find((p) => p.name === 'foo')!; - // pkg.path uses forward slashes on every platform (normalized from glob's - // native separators), so it compares cleanly against workspace patterns. + // pkg.path uses forward slashes on every platform, so it compares cleanly + // against workspace patterns. expect(foo.path).toBe('packages/foo'); expect(foo.description).toBe('a foo'); expect(foo.version).toBe('1.0.0'); @@ -200,6 +200,13 @@ describe('discoverWorkspacePackages', () => { const packages = discoverWorkspacePackages(['packages/*'], tmpDir); expect(packages.map((p) => p.name)).toEqual(['a']); }); + + it('skips packages excluded by negated patterns', () => { + writeJson(path.join(tmpDir, 'packages/a/package.json'), { name: 'a' }); + writeJson(path.join(tmpDir, 'packages/excluded/package.json'), { name: 'excluded' }); + const packages = discoverWorkspacePackages(['packages/*', '!packages/excluded'], tmpDir); + expect(packages.map((p) => p.name)).toEqual(['a']); + }); }); describe('updatePackageJsonWithDeps', () => { @@ -222,14 +229,14 @@ describe('updatePackageJsonWithDeps', () => { }); describe('findPackageJsonFilesFromPatterns', () => { - it('returns absolute paths for matching package.json files', () => { + it('returns absolute paths with forward slashes for matching package.json files', () => { writeJson(path.join(tmpDir, 'packages/a/package.json'), { name: 'a' }); writeJson(path.join(tmpDir, 'packages/b/package.json'), { name: 'b' }); const result = findPackageJsonFilesFromPatterns(['packages/*'], tmpDir).toSorted(); expect(result).toEqual( [ - path.join(tmpDir, 'packages/a/package.json'), - path.join(tmpDir, 'packages/b/package.json'), + `${tmpDir.replaceAll('\\', '/')}/packages/a/package.json`, + `${tmpDir.replaceAll('\\', '/')}/packages/b/package.json`, ].toSorted(), ); }); diff --git a/packages/cli/src/utils/workspace.ts b/packages/cli/src/utils/workspace.ts index f10d2450b8..04d2b1503f 100644 --- a/packages/cli/src/utils/workspace.ts +++ b/packages/cli/src/utils/workspace.ts @@ -1,8 +1,8 @@ import fs from 'node:fs'; import path from 'node:path'; -import { globSync } from 'glob'; import { minimatch } from 'minimatch'; +import { globSync } from 'tinyglobby'; import { Scalar, YAMLSeq } from 'yaml'; import { detectWorkspace as detectWorkspaceBinding } from '../../binding/index.js'; @@ -32,7 +32,7 @@ export function findPackageJsonFilesFromPatterns(patterns: string[], cwd: string } return globSync( patterns.map((pattern) => `${pattern}/package.json`), - { absolute: true, cwd }, + { absolute: true, cwd, expandDirectories: false }, ); } @@ -134,6 +134,7 @@ export function discoverWorkspacePackages( absolute: false, cwd: rootDir, ignore: ['**/node_modules/**'], + expandDirectories: false, }, ); for (const packageJsonRelativePath of packageJsonRelativePaths) { @@ -148,10 +149,9 @@ export function discoverWorkspacePackages( } packages.push({ name: pkg.name, - // glob returns native separators; normalize to forward slashes so the - // path compares cleanly against workspace-pattern-derived values like - // `parentDirs` on Windows (path.join accepts either separator). - path: path.dirname(packageJsonRelativePath).split(path.sep).join('/'), + // Keep tinyglobby's forward slashes so the path compares cleanly against + // workspace-pattern-derived values like `parentDirs` on Windows. + path: path.posix.dirname(packageJsonRelativePath), description: pkg.description, version: pkg.version, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b97aebd5e0..6839ca4a89 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -389,6 +389,9 @@ catalogs: tinyexec: specifier: ^1.0.1 version: 1.3.1 + tinyglobby: + specifier: ^0.2.15 + version: 0.2.17 tsdown: specifier: ^0.23.1 version: 0.23.1 @@ -566,9 +569,6 @@ importers: detect-newline: specifier: 'catalog:' version: 4.0.1 - glob: - specifier: 'catalog:' - version: 13.0.0 jsonc-parser: specifier: 'catalog:' version: 3.3.1 @@ -584,6 +584,9 @@ importers: picocolors: specifier: 'catalog:' version: 1.1.1 + tinyglobby: + specifier: 'catalog:' + version: 0.2.17 tsdown: specifier: 'catalog:' version: 0.23.1(@arethetypeswrong/core@0.18.2)(@tsdown/css@0.23.1)(@tsdown/exe@0.23.1)(@typescript/native-preview@7.0.0-dev.20260707.2)(@vitejs/devtools@0.7.6(@devframes/json-render@1.0.0(@devframes/hub@1.0.0(@devframes/agentic@1.0.0)(crossws@0.4.12(srvx@1.0.5))(devframe@1.0.0))(devframe@1.0.0))(crossws@0.4.12(srvx@1.0.5))(srvx@1.0.5)(vite@packages+core))(@volar/typescript@2.4.28(typescript@6.0.3))(@vue/language-core@3.3.12)(oxc-resolver@11.24.2)(publint@0.3.24)(tsx@4.23.15)(typescript@6.0.3)(unplugin-unused@0.5.6)(unrun@0.3.1)(vue-tsc@3.3.12(typescript@6.0.3)) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ae2971b596..bbc7540092 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -115,6 +115,7 @@ catalog: terser: ^5.44.1 tinybench: ^6.0.0 tinyexec: ^1.0.1 + tinyglobby: ^0.2.15 tsdown: ^0.23.1 tsx: ^4.22.0 typescript: ^6.0.0