@mui/internal-code-infra 0.0.4-canary.98 → 0.1.1-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +4 -0
  2. package/build/babel-config.d.mts +4 -4
  3. package/build/babelPluginInlineEnvironmentVariables.d.mts +11 -0
  4. package/build/brokenLinksChecker/index.d.mts +147 -0
  5. package/build/changelog/fetchChangelogs.d.mts +3 -0
  6. package/build/cli/cmdArgosPush.d.mts +6 -0
  7. package/build/cli/cmdBuild.d.mts +45 -0
  8. package/build/cli/cmdCopyFiles.d.mts +12 -0
  9. package/build/cli/cmdGenerateChangelog.d.mts +15 -0
  10. package/build/cli/cmdListWorkspaces.d.mts +14 -2
  11. package/build/cli/cmdNetlifyIgnore.d.mts +9 -0
  12. package/build/cli/cmdPublish.d.mts +20 -2
  13. package/build/cli/cmdPublishCanary.d.mts +18 -0
  14. package/build/cli/cmdPublishNewPackage.d.mts +6 -0
  15. package/build/cli/cmdRenameScope.d.mts +18 -0
  16. package/build/cli/cmdSetVersionOverrides.d.mts +3 -0
  17. package/build/eslint/mui/rules/no-restricted-resolved-imports.d.mts +6 -0
  18. package/build/eslint/testConfig.d.mts +1 -7
  19. package/build/utils/babel.d.mts +6 -0
  20. package/build/utils/build.d.mts +3 -15
  21. package/build/utils/extractErrorCodes.d.mts +16 -0
  22. package/build/utils/git.d.mts +9 -0
  23. package/build/utils/github.d.mts +12 -0
  24. package/build/utils/pnpm.d.mts +147 -9
  25. package/build/utils/testUtils.d.mts +21 -0
  26. package/build/utils/typescript.d.mts +2 -2
  27. package/package.json +54 -56
  28. package/src/babel-config.mjs +21 -11
  29. package/src/babelPluginInlineEnvironmentVariables.mjs +45 -0
  30. package/src/brokenLinksChecker/index.mjs +3 -3
  31. package/src/cli/cmdArgosPush.mjs +2 -4
  32. package/src/cli/cmdBuild.mjs +8 -9
  33. package/src/cli/cmdCopyFiles.mjs +3 -3
  34. package/src/cli/cmdListWorkspaces.mjs +3 -31
  35. package/src/cli/cmdPublish.mjs +23 -29
  36. package/src/cli/cmdRenameScope.mjs +77 -0
  37. package/src/cli/cmdSetVersionOverrides.mjs +32 -25
  38. package/src/cli/cmdVale.mjs +3 -6
  39. package/src/cli/cmdValidateBuiltTypes.mjs +3 -4
  40. package/src/cli/index.mjs +2 -0
  41. package/src/eslint/testConfig.mjs +3 -31
  42. package/src/untyped-plugins.d.ts +11 -49
  43. package/src/utils/build.mjs +0 -39
  44. package/src/utils/extractErrorCodes.mjs +12 -7
  45. package/src/utils/pnpm.mjs +380 -16
  46. package/src/utils/testUtils.mjs +35 -0
  47. package/src/utils/typescript.mjs +60 -42
@@ -46,8 +46,6 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
46
46
  const { folder, verbose = false } = argv;
47
47
 
48
48
  const argosToken = requireEnv('ARGOS_TOKEN');
49
- const circleSha1 = requireEnv('CIRCLE_SHA1');
50
- const circleBranch = requireEnv('CIRCLE_BRANCH');
51
49
  const circleBuildNum = requireEnv('CIRCLE_BUILD_NUM');
52
50
 
53
51
  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'argos-screenshots-'));
@@ -92,8 +90,8 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
92
90
  // eslint-disable-next-line no-await-in-loop
93
91
  const result = await upload({
94
92
  root: `${tempDir}/${i}`,
95
- commit: circleSha1,
96
- branch: circleBranch,
93
+ // The SDK resolves `commit` and `branch`: it reads `ARGOS_COMMIT` and `ARGOS_BRANCH`
94
+ // first and falls back to `CIRCLE_SHA1` and `CIRCLE_BRANCH`.
97
95
  token: argosToken,
98
96
  threshold,
99
97
  parallel: {
@@ -1,20 +1,20 @@
1
1
  /* eslint-disable no-console */
2
2
  import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
3
- import { $ } from 'execa';
4
3
  import { globby } from 'globby';
5
4
  import * as fs from 'node:fs/promises';
6
5
  import * as path from 'node:path';
7
6
  import { sep as posixSep } from 'node:path/posix';
8
7
  import * as semver from 'semver';
8
+ import { mapAsync } from 'es-toolkit/array';
9
9
 
10
10
  import {
11
11
  createPackageBin,
12
12
  createPackageExports,
13
13
  createPackageImports,
14
14
  getOutExtension,
15
- mapConcurrently,
16
15
  validatePkgJson,
17
16
  } from '../utils/build.mjs';
17
+ import { readPnpmConfig } from '../utils/pnpm.mjs';
18
18
 
19
19
  /**
20
20
  * @typedef {Object} Args
@@ -30,7 +30,7 @@ import {
30
30
  * @property {string[]} ignore - Globs to be ignored by Babel.
31
31
  * @property {string[]} [copy] - Files/Directories to be copied. Can be a glob pattern.
32
32
  * @property {boolean} [enableReactCompiler] - Whether to use the React compiler.
33
- * @property {boolean} [tsgo] - Whether to build types using typescript native (tsgo).
33
+ * @property {boolean} [tsgo] - Whether to build types using the native TypeScript compiler.
34
34
  * @property {boolean} [flat] - Deprecated no-op; flat builds are always used.
35
35
  * @property {boolean} expand - Whether to enumerate glob patterns in exports/imports into concrete entries.
36
36
  */
@@ -229,9 +229,9 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
229
229
  })
230
230
  .option('tsgo', {
231
231
  type: 'boolean',
232
- default: process.env.MUI_USE_TSGO,
232
+ default: false,
233
233
  description:
234
- 'Uses tsgo cli instead of tsc for type generation. Can also be set via env var "MUI_USE_TSGO"',
234
+ 'Use the native TypeScript compiler instead of the TS6 JS compiler for type generation',
235
235
  })
236
236
  .option('flat', {
237
237
  type: 'boolean',
@@ -279,8 +279,7 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
279
279
  if (babelRuntimeVersion === 'catalog:') {
280
280
  // resolve the version from the given package
281
281
  // outputs the pnpm-workspace.yaml config as json
282
- const { stdout: configStdout } = await $`pnpm config list --json`;
283
- const pnpmWorkspaceConfig = JSON.parse(configStdout);
282
+ const pnpmWorkspaceConfig = await readPnpmConfig();
284
283
  babelRuntimeVersion = pnpmWorkspaceConfig.catalog['@babel/runtime'];
285
284
  }
286
285
 
@@ -479,7 +478,7 @@ async function copyHandler({ cwd, globs = [], buildDir, verbose = false }) {
479
478
  console.log('⓿ No files to copy.');
480
479
  }
481
480
  }
482
- await mapConcurrently(
481
+ await mapAsync(
483
482
  defaultFiles,
484
483
  async (file) => {
485
484
  if (typeof file === 'string') {
@@ -492,7 +491,7 @@ async function copyHandler({ cwd, globs = [], buildDir, verbose = false }) {
492
491
  await recursiveCopy({ source: file.sourcePath, target: file.targetPath, verbose });
493
492
  }
494
493
  },
495
- 20,
494
+ { concurrency: 20 },
496
495
  );
497
496
  console.log(`📋 Copied ${defaultFiles.length} files.`);
498
497
  }
@@ -2,7 +2,7 @@ import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
2
2
  import { globby } from 'globby';
3
3
  import fs from 'node:fs/promises';
4
4
  import path from 'node:path';
5
- import { mapConcurrently } from '../utils/build.mjs';
5
+ import { mapAsync } from 'es-toolkit/array';
6
6
 
7
7
  /**
8
8
  * @typedef {Object} Args
@@ -106,12 +106,12 @@ async function processGlobs({ globs, cwd, silent = true, buildDir }) {
106
106
  });
107
107
  });
108
108
 
109
- await mapConcurrently(
109
+ await mapAsync(
110
110
  filesToProcess,
111
111
  async (file) => {
112
112
  await recursiveCopy({ source: file.sourcePath, target: file.targetPath, silent });
113
113
  },
114
- 50,
114
+ { concurrency: 50 },
115
115
  );
116
116
  return filesToProcess.length;
117
117
  }
@@ -6,14 +6,12 @@
6
6
  * @typedef {import('../utils/pnpm.mjs').PublicPackage} PublicPackage
7
7
  */
8
8
 
9
- import * as fs from 'node:fs/promises';
10
- import * as path from 'node:path';
11
9
  import { getWorkspacePackages } from '../utils/pnpm.mjs';
12
10
 
13
11
  /**
14
12
  * @typedef {Object} Args
15
13
  * @property {boolean} [publicOnly] - Whether to filter to only public packages
16
- * @property {'json'|'path'|'name'|'publish-dir'} [output] - Output format (name, path, or json)
14
+ * @property {'json'|'path'|'name'} [output] - Output format (name, path, or json)
17
15
  * @property {string} [sinceRef] - Git reference to filter changes since
18
16
  * @property {string[]} [filter] - Same as filtering packages with --filter in pnpm. Only include packages matching the filter. See https://pnpm.io/filtering.
19
17
  */
@@ -30,10 +28,10 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
30
28
  })
31
29
  .option('output', {
32
30
  type: 'string',
33
- choices: ['json', 'path', 'name', 'publish-dir'],
31
+ choices: ['json', 'path', 'name'],
34
32
  default: 'path',
35
33
  description:
36
- 'Output format: name (package names), path (package paths), publish-dir (publish directories), or json (full JSON)',
34
+ 'Output format: name (package names), path (package paths), or json (full JSON)',
37
35
  })
38
36
  .option('since-ref', {
39
37
  type: 'string',
@@ -60,32 +58,6 @@ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
60
58
  packages.forEach((pkg) => {
61
59
  console.log(pkg.path);
62
60
  });
63
- } else if (output === 'publish-dir') {
64
- // Works around https://github.com/stackblitz-labs/pkg.pr.new/issues/389: pkg-pr-new rewrites
65
- // workspace:* deps to its URLs in the source package.json, but `pnpm pack` honors
66
- // publishConfig.directory and packs the build package.json, whose workspace:* deps are left to
67
- // resolve to plain versions. Pointing pkg-pr-new at the build dir makes both act on the same file.
68
- // Note: #389 was closed by pkg-pr-new#499, but that only fixed the tarball location, not the dep
69
- // resolution — verified still broken on 0.0.78. Do not remove until the packed deps are URLs
70
- // without this. Removing it prematurely regressed publishing once (see mui-public#1354).
71
- // Print publish directories (package.json publishConfig.directory or package path)
72
- const publishDirs = await Promise.all(
73
- packages.map(async (pkg) => {
74
- const packageJsonPath = path.join(pkg.path, 'package.json');
75
- const packageJsonContent = await fs.readFile(packageJsonPath, 'utf8');
76
- const packageJson = JSON.parse(packageJsonContent);
77
-
78
- if (packageJson.publishConfig?.directory) {
79
- return path.join(pkg.path, packageJson.publishConfig.directory);
80
- }
81
-
82
- return pkg.path;
83
- }),
84
- );
85
-
86
- publishDirs.forEach((dir) => {
87
- console.log(dir);
88
- });
89
61
  } else if (output === 'name') {
90
62
  // Print package names (default)
91
63
  packages.forEach((pkg) => {
@@ -20,6 +20,7 @@ import * as semver from 'semver';
20
20
  import { persistentAuthStrategy } from '../utils/github.mjs';
21
21
  import {
22
22
  getPackagesNeedingManualPublish,
23
+ getReleaseVersion,
23
24
  getWorkspacePackages,
24
25
  publishPackages,
25
26
  validatePublishDependencies,
@@ -42,19 +43,6 @@ function getOctokit() {
42
43
  * @property {string[]} [filter] Same as filtering packages with --filter in pnpm. Only publish packages matching the filter. See https://pnpm.io/filtering.
43
44
  */
44
45
 
45
- /**
46
- * Get the version to release from the root package.json
47
- * @returns {Promise<string | null>} Version string
48
- */
49
- async function getReleaseVersion() {
50
- // `--json` is required: pnpm 11 returns the raw value (e.g. `9.4.0`) for a
51
- // single field without it, which is not valid JSON. The flag forces quoted
52
- // output (`"9.4.0"`) across pnpm 9/10/11.
53
- const result = await $`pnpm pkg get version --json`;
54
- const version = JSON.parse(result.stdout.trim());
55
- return semver.valid(version);
56
- }
57
-
58
46
  /**
59
47
  * Parse changelog to extract content for a specific version
60
48
  * @param {string} changelogPath - Path to CHANGELOG.md
@@ -510,6 +498,8 @@ async function determineGitSha(octokit, repoInfo) {
510
498
  await octokit.search.issuesAndPullRequests({
511
499
  advanced_search: 'true',
512
500
  q: `is:pr is:merged label:release repo:${repoInfo.owner}/${repoInfo.repo}`,
501
+ sort: 'created',
502
+ order: 'desc',
513
503
  per_page: 1,
514
504
  })
515
505
  ).data.items;
@@ -522,29 +512,33 @@ async function determineGitSha(octokit, repoInfo) {
522
512
  `🫆 Found the latest merged release PR: ${chalk.bold(pulls[0].title)} (${pulls[0].html_url})`,
523
513
  );
524
514
 
525
- const commits = (
526
- await octokit.search.commits({
527
- q: `repo:${repoInfo.owner}/${repoInfo.repo} author:${pulls[0].user?.login} [release]`,
528
- per_page: 100,
529
- })
530
- ).data.items;
531
-
532
- if (!commits.length) {
533
- console.error(
534
- `❌🚨 Could not find any commits associated with the release PR: ${pulls[0].html_url}`,
535
- );
515
+ const pull = (await octokit.pulls.get({ ...repoInfo, pull_number: pulls[0].number })).data;
516
+ const mergeCommitSha = pull.merge_commit_sha;
517
+ if (!mergeCommitSha) {
518
+ console.error(`❌🚨 Could not determine the merge commit of ${pulls[0].html_url}.`);
536
519
  return undefined;
537
520
  }
538
- const relevantData = commits.map((commit) => ({
521
+
522
+ // Recent commits on the PR's target branch, to allow releasing from a different commit.
523
+ const commits = (
524
+ await octokit.repos.listCommits({ ...repoInfo, sha: pull.base.ref, per_page: 20 })
525
+ ).data;
526
+
527
+ const toChoice = (/** @type {(typeof commits)[number]} */ commit) => ({
539
528
  value: commit.sha,
540
529
  name: `(${commit.sha.slice(0, 7)}) ${commit.commit.message.split('\n')[0]} by ${commit.author?.login ?? 'no author'} on ${new Date(commit.commit.committer?.date ?? '').toISOString()}`,
541
- desciption: commit.commit.message,
542
- }));
530
+ description: commit.commit.message,
531
+ });
532
+ const choices = commits.map(toChoice);
533
+ if (!choices.some((choice) => choice.value === mergeCommitSha)) {
534
+ const mergeCommit = (await octokit.repos.getCommit({ ...repoInfo, ref: mergeCommitSha })).data;
535
+ choices.unshift(toChoice(mergeCommit));
536
+ }
543
537
 
544
538
  const result = await select({
545
539
  message: 'Select the commit to release from:',
546
- choices: relevantData,
547
- default: relevantData[0].value,
540
+ choices,
541
+ default: mergeCommitSha,
548
542
  pageSize: 10,
549
543
  });
550
544
  return result;
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+
3
+ /* eslint-disable no-console */
4
+
5
+ import chalk from 'chalk';
6
+
7
+ import { getWorkspacePackages, renameWorkspaceScope } from '../utils/pnpm.mjs';
8
+
9
+ /**
10
+ * A scope is a single `@`-prefixed segment. Letting a `/` through would build
11
+ * names like `@acme/private/pkg`, which only npm rejects, long after every
12
+ * matching manifest has been rewritten.
13
+ */
14
+ const SCOPE_PATTERN = /^@[a-z0-9-~][a-z0-9-._~]*$/;
15
+
16
+ /**
17
+ * @typedef {Object} Args
18
+ * @property {[string, string]} alias Source and target scope
19
+ */
20
+
21
+ /**
22
+ * @param {string} alias
23
+ * @returns {[string, string]}
24
+ */
25
+ export function parseAlias(alias) {
26
+ const parts = alias.split(':');
27
+ const [from, to] = parts;
28
+ if (parts.length !== 2 || !SCOPE_PATTERN.test(from) || !SCOPE_PATTERN.test(to)) {
29
+ throw new Error(
30
+ `Invalid scope mapping "${alias}". Expected exactly two npm scopes separated by a colon, e.g. "@acme:@acme-private".`,
31
+ );
32
+ }
33
+ if (from === to) {
34
+ throw new Error(`Invalid scope mapping "${alias}". The source and target scope are the same.`);
35
+ }
36
+ return [from, to];
37
+ }
38
+
39
+ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
40
+ command: 'rename-scope <alias>',
41
+ describe: 'Move publishable workspace packages to a different npm scope',
42
+ builder: (yargs) =>
43
+ yargs
44
+ .positional('alias', {
45
+ type: 'string',
46
+ describe: 'Scope mapping written as "@from:@to"',
47
+ coerce: parseAlias,
48
+ })
49
+ .example(
50
+ '$0 rename-scope @acme:@acme-private',
51
+ 'Publish the workspace @acme packages under @acme-private',
52
+ ),
53
+ handler: async (argv) => {
54
+ const [from, to] = argv.alias;
55
+ const packages = await getWorkspacePackages();
56
+ const renamed = await renameWorkspaceScope(packages, from, to);
57
+
58
+ // Matching nothing means the mapping is wrong or stale. Carrying on would
59
+ // publish under the original scope, so fail instead of reporting success.
60
+ if (renamed.size === 0) {
61
+ throw new Error(
62
+ `No publishable workspace packages found in ${from}. Check the scope mapping "${from}:${to}", or the workspace may already have been renamed.`,
63
+ );
64
+ }
65
+
66
+ for (const [oldName, newName] of renamed) {
67
+ console.log(`📦 ${oldName} → ${chalk.bold(newName)}`);
68
+ }
69
+
70
+ console.log(
71
+ chalk.yellow(
72
+ '\n⚠️ Workspace manifests were rewritten in place and are not restored. The next install\n' +
73
+ 'rewrites pnpm-lock.yaml to match. Discard both before committing.',
74
+ ),
75
+ );
76
+ },
77
+ });
@@ -3,7 +3,9 @@
3
3
  import * as semver from 'semver';
4
4
  import { $ } from 'execa';
5
5
  import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
6
+ import { parseWantedDependency } from '@pnpm/parse-wanted-dependency';
6
7
  import {
8
+ getMinimumReleaseAgePolicy,
7
9
  resolveVersion,
8
10
  findDependencyVersionFromSpec,
9
11
  writeOverridesToWorkspace,
@@ -17,61 +19,62 @@ import {
17
19
  /**
18
20
  * Process a single package override
19
21
  * @param {string} packageSpec - Package specifier in format "package@version"
22
+ * @param {import('@pnpm/config.version-policy').PublishedByPolicy} policy - Registry cooldown to resolve within
20
23
  * @returns {Promise<Record<string, string>>} Overrides object for this package
21
24
  */
22
- async function processPackageOverride(packageSpec) {
25
+ async function processPackageOverride(packageSpec, policy) {
23
26
  /** @type {Record<string, string>} */
24
27
  const overrides = {};
25
28
 
26
- // Extract package name to check for special cases
27
- const lastAtIndex = packageSpec.lastIndexOf('@');
28
- if (lastAtIndex === -1) {
29
+ const { alias: packageName, bareSpecifier: version } = parseWantedDependency(packageSpec);
30
+ if (!packageName || version === undefined) {
29
31
  throw new Error(`Invalid package specifier: ${packageSpec}`);
30
32
  }
31
33
 
32
- const packageName = packageSpec.slice(0, lastAtIndex);
33
- const version = packageSpec.slice(lastAtIndex + 1);
34
-
35
- if (!packageName || !version || version === 'stable') {
34
+ // An empty version is distinct from a missing one: CI interpolates a matrix
35
+ // value into `--pkg pkg@<version>`, and the leg that leaves it unset must skip
36
+ // the override rather than fail the job.
37
+ if (!version || version === 'stable') {
36
38
  return overrides;
37
39
  }
38
40
 
39
41
  // eslint-disable-next-line no-console
40
42
  console.log(`Resolving overrides for ${packageName} version: ${version}`);
41
43
 
44
+ /** @param {string} spec */
45
+ const resolve = (spec) => resolveVersion(spec, policy);
46
+
42
47
  if (packageName === 'react') {
43
48
  // Special case for React - also override related packages
44
- overrides.react = await resolveVersion(packageSpec);
45
- overrides['react-dom'] = await resolveVersion(`react-dom@${version}`);
46
- overrides['react-is'] = await resolveVersion(`react-is@${version}`);
49
+ overrides.react = await resolve(packageSpec);
50
+ overrides['react-dom'] = await resolve(`react-dom@${version}`);
51
+ overrides['react-is'] = await resolve(`react-is@${version}`);
47
52
  overrides.scheduler = await findDependencyVersionFromSpec(
48
53
  `react-dom@${overrides['react-dom']}`,
49
54
  'scheduler',
55
+ policy,
50
56
  );
51
57
 
52
58
  const reactMajor = semver.major(overrides.react);
53
59
  if (reactMajor === 17) {
54
- overrides['@testing-library/react'] = await resolveVersion('@testing-library/react@^12.1.0');
60
+ overrides['@testing-library/react'] = await resolve('@testing-library/react@^12.1.0');
55
61
  }
56
62
  } else if (packageName === '@mui/material') {
57
63
  // Special case for MUI - also override related packages
58
- overrides['@mui/material'] = await resolveVersion(`@mui/material@${version}`);
59
- overrides['@mui/system'] = await resolveVersion(`@mui/system@${version}`);
60
- overrides['@mui/icons-material'] = await resolveVersion(`@mui/icons-material@${version}`);
61
- overrides['@mui/utils'] = await resolveVersion(`@mui/utils@${version}`);
62
- overrides['@mui/material-nextjs'] = await resolveVersion(`@mui/material-nextjs@${version}`);
64
+ overrides['@mui/material'] = await resolve(`@mui/material@${version}`);
65
+ overrides['@mui/system'] = await resolve(`@mui/system@${version}`);
66
+ overrides['@mui/icons-material'] = await resolve(`@mui/icons-material@${version}`);
67
+ overrides['@mui/utils'] = await resolve(`@mui/utils@${version}`);
68
+ overrides['@mui/material-nextjs'] = await resolve(`@mui/material-nextjs@${version}`);
63
69
 
64
- const latest = await resolveVersion(`@mui/material@latest`);
70
+ const latest = await resolve(`@mui/material@latest`);
65
71
  const latestMajor = semver.major(latest);
66
72
  const muiMajor = semver.major(overrides['@mui/material']);
67
- if (muiMajor < latestMajor) {
68
- overrides['@mui/lab'] = await resolveVersion(`@mui/lab@latest-v${muiMajor}`);
69
- } else {
70
- overrides['@mui/lab'] = await resolveVersion(`@mui/lab@latest`);
71
- }
73
+ const labTag = muiMajor < latestMajor ? `latest-v${muiMajor}` : 'latest';
74
+ overrides['@mui/lab'] = await resolve(`@mui/lab@${labTag}`);
72
75
  } else {
73
76
  // Generic case for other packages
74
- overrides[packageName] = await resolveVersion(packageSpec);
77
+ overrides[packageName] = await resolve(packageSpec);
75
78
  }
76
79
 
77
80
  return overrides;
@@ -89,8 +92,12 @@ async function handler(args) {
89
92
  return;
90
93
  }
91
94
 
95
+ // Read once and thread through: every override must land on a version that
96
+ // clears the same cooldown the following `pnpm dedupe` enforces.
97
+ const policy = await getMinimumReleaseAgePolicy();
98
+
92
99
  const packageOverridePromises = args.pkg.map((packageSpec) =>
93
- processPackageOverride(packageSpec),
100
+ processPackageOverride(packageSpec, policy),
94
101
  );
95
102
  const packageOverrideResults = await Promise.all(packageOverridePromises);
96
103
 
@@ -7,7 +7,7 @@ import * as path from 'node:path';
7
7
  import { pipeline } from 'node:stream/promises';
8
8
  import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
9
9
  import { $ } from 'execa';
10
- import { mapConcurrently } from '../utils/build.mjs';
10
+ import { mapAsync } from 'es-toolkit/array';
11
11
 
12
12
  const LATEST_RELEASE_URL = 'https://api.github.com/repos/vale-cli/vale/releases/latest';
13
13
 
@@ -342,7 +342,7 @@ export function getReplacementText(alert) {
342
342
  export async function applyFixes(results, fixLevel) {
343
343
  const entries = Object.entries(results);
344
344
 
345
- const perFileResults = await mapConcurrently(
345
+ const perFileResults = await mapAsync(
346
346
  entries,
347
347
  async ([filePath, alerts]) => {
348
348
  const content = await fs.readFile(filePath, 'utf-8');
@@ -406,15 +406,12 @@ export async function applyFixes(results, fixLevel) {
406
406
 
407
407
  return { fixed: fileFixed, skipped: alerts.length - fixableAlerts.length };
408
408
  },
409
- 10,
409
+ { concurrency: 10 },
410
410
  );
411
411
 
412
412
  let fixed = 0;
413
413
  let skipped = 0;
414
414
  for (const result of perFileResults) {
415
- if (result instanceof Error) {
416
- throw result;
417
- }
418
415
  fixed += result.fixed;
419
416
  skipped += result.skipped;
420
417
  }
@@ -2,8 +2,7 @@
2
2
  import { globby } from 'globby';
3
3
  import * as fs from 'node:fs/promises';
4
4
  import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
5
-
6
- import { mapConcurrently } from '../utils/build.mjs';
5
+ import { mapAsync } from 'es-toolkit/array';
7
6
 
8
7
  const DYNAMIC_PACKAGES_IMPORT_REGEX = /import\((['"])packages\//gm;
9
8
 
@@ -22,14 +21,14 @@ async function validateFiles() {
22
21
  });
23
22
 
24
23
  const invalidFiles = (
25
- await mapConcurrently(
24
+ await mapAsync(
26
25
  declarationFiles,
27
26
  async (declarationFile) => {
28
27
  const content = await fs.readFile(declarationFile, 'utf-8');
29
28
  const matches = Array.from(content.matchAll(DYNAMIC_PACKAGES_IMPORT_REGEX));
30
29
  return matches.length > 0 ? declarationFile : undefined;
31
30
  },
32
- 20,
31
+ { concurrency: 20 },
33
32
  )
34
33
  ).filter((file) => typeof file === 'string');
35
34
 
package/src/cli/index.mjs CHANGED
@@ -14,6 +14,7 @@ import cmdNetlifyIgnore from './cmdNetlifyIgnore.mjs';
14
14
  import cmdPublish from './cmdPublish.mjs';
15
15
  import cmdPublishCanary from './cmdPublishCanary.mjs';
16
16
  import cmdPublishNewPackage from './cmdPublishNewPackage.mjs';
17
+ import cmdRenameScope from './cmdRenameScope.mjs';
17
18
  import cmdSetVersionOverrides from './cmdSetVersionOverrides.mjs';
18
19
  import cmdVale from './cmdVale.mjs';
19
20
  import cmdValidateBuiltTypes from './cmdValidateBuiltTypes.mjs';
@@ -47,6 +48,7 @@ await yargs(hideBin(process.argv))
47
48
  .command(cmdPublish)
48
49
  .command(cmdPublishCanary)
49
50
  .command(cmdPublishNewPackage)
51
+ .command(cmdRenameScope)
50
52
  .command(cmdSetVersionOverrides)
51
53
  .command(cmdVale)
52
54
  .command(cmdValidateBuiltTypes)
@@ -1,8 +1,6 @@
1
- import mochaPlugin from 'eslint-plugin-mocha';
2
1
  import vitestPlugin from '@vitest/eslint-plugin';
3
2
  import testingLibrary from 'eslint-plugin-testing-library';
4
3
  import { defineConfig } from 'eslint/config';
5
- import globals from 'globals';
6
4
  import * as tseslint from 'typescript-eslint';
7
5
  import { EXTENSION_TS } from './extensions.mjs';
8
6
 
@@ -44,16 +42,11 @@ export const baseSpecRules = {
44
42
  };
45
43
 
46
44
  /**
47
- * @param {Object} [options]
48
- * @param {boolean} [options.useMocha]
49
- * @param {boolean} [options.useVitest]
50
45
  * @returns {import('eslint').Linter.Config[]}
51
46
  */
52
- export function createTestConfig(options = {}) {
53
- const { useMocha = true, useVitest = false } = options;
47
+ export function createTestConfig() {
54
48
  return defineConfig(
55
- useMocha ? mochaPlugin.configs.recommended : {},
56
- useVitest ? vitestPlugin.configs.recommended : {},
49
+ vitestPlugin.configs.recommended,
57
50
  testingLibrary.configs['flat/dom'],
58
51
  testingLibrary.configs['flat/react'],
59
52
  {
@@ -63,7 +56,6 @@ export function createTestConfig(options = {}) {
63
56
  parserOptions: {
64
57
  ecmaVersion: 7,
65
58
  },
66
- globals: globals.mocha,
67
59
  },
68
60
  rules: {
69
61
  'compat/compat': 'off',
@@ -99,27 +91,7 @@ export function createTestConfig(options = {}) {
99
91
  'testing-library/no-node-access': 'off',
100
92
  '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
101
93
  // end migration
102
- ...(useMocha
103
- ? {
104
- 'mocha/consistent-spacing-between-blocks': 'off',
105
-
106
- // upgraded level from recommended
107
- 'mocha/no-pending-tests': 'error',
108
-
109
- // no rationale provided in /recommended
110
- 'mocha/no-mocha-arrows': 'off',
111
- // definitely a useful rule but too many false positives
112
- // due to `describeConformance`
113
- // "If you're using dynamically generated tests, you should disable this rule.""
114
- 'mocha/no-setup-in-describe': 'off',
115
- // `beforeEach` for a single case is optimized for change
116
- // when we add a test we don't have to refactor the existing
117
- // test to `beforeEach`.
118
- // `beforeEach`+`afterEach` also means that the `beforeEach`
119
- // is cleaned up in `afterEach` if the test causes a crash
120
- 'mocha/no-hooks-for-single-case': 'off',
121
- }
122
- : {}),
94
+ 'vitest/prefer-importing-vitest-globals': 'error',
123
95
  },
124
96
  },
125
97
  );