diff --git a/package.json b/package.json index da715e9..cab8d01 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "picocolors": "^1.1.1" }, "devDependencies": { - "@changesets/cli": "^2.27.0", + "@changesets/cli": "^2.30.0", "eslint-plugin-react-hooks": "^7.0.1", "oxfmt": "^0.32.0", "oxlint": "^1.47.0", diff --git a/packages/react-doctor/src/cli.ts b/packages/react-doctor/src/cli.ts index 471e36e..edee17c 100644 --- a/packages/react-doctor/src/cli.ts +++ b/packages/react-doctor/src/cli.ts @@ -112,7 +112,7 @@ const resolveDiffMode = async ( const changedSourceFiles = filterSourceFiles(diffInfo.changedFiles); if (changedSourceFiles.length === 0) return false; - if (shouldSkipPrompts) return true; + if (shouldSkipPrompts) return false; if (isScoreOnly) return false; const promptMessage = diffInfo.isCurrentChanges diff --git a/packages/react-doctor/src/constants.ts b/packages/react-doctor/src/constants.ts index 1cb0f8d..d9a4c72 100644 --- a/packages/react-doctor/src/constants.ts +++ b/packages/react-doctor/src/constants.ts @@ -34,8 +34,7 @@ export const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024; // Use a conservative threshold to leave room for the executable path and quoting overhead. export const SPAWN_ARGS_MAX_LENGTH_CHARS = 24_000; -export const OFFLINE_MESSAGE = - "You are offline, could not calculate score. Reconnect to calculate."; +export const OFFLINE_MESSAGE = "Score calculated locally (offline mode)."; export const DEFAULT_BRANCH_CANDIDATES = ["main", "master"]; diff --git a/packages/react-doctor/src/plugin/constants.ts b/packages/react-doctor/src/plugin/constants.ts index 18f37dc..f694014 100644 --- a/packages/react-doctor/src/plugin/constants.ts +++ b/packages/react-doctor/src/plugin/constants.ts @@ -264,6 +264,15 @@ export const RAW_TEXT_PREVIEW_MAX_CHARS = 30; export const REACT_NATIVE_TEXT_COMPONENTS = new Set(["Text", "TextInput"]); +export const REACT_NATIVE_TEXT_COMPONENT_SUFFIXES = new Set([ + "Text", + "Title", + "Label", + "Heading", + "Caption", + "Subtitle", +]); + export const DEPRECATED_RN_MODULE_REPLACEMENTS: Record = { AsyncStorage: "@react-native-async-storage/async-storage", Picker: "@react-native-picker/picker", diff --git a/packages/react-doctor/src/plugin/rules/nextjs.ts b/packages/react-doctor/src/plugin/rules/nextjs.ts index 2c3bc9d..65a3273 100644 --- a/packages/react-doctor/src/plugin/rules/nextjs.ts +++ b/packages/react-doctor/src/plugin/rules/nextjs.ts @@ -181,24 +181,28 @@ export const nextjsMissingMetadata: Rule = { }), }; -const isClientSideRedirect = (node: EsTreeNode): boolean => { +const describeClientSideNavigation = (node: EsTreeNode): string | null => { if (node.type === "CallExpression" && node.callee?.type === "MemberExpression") { const objectName = node.callee.object?.type === "Identifier" ? node.callee.object.name : null; - if ( - objectName === "router" && - (isMemberProperty(node.callee, "push") || isMemberProperty(node.callee, "replace")) - ) - return true; + const methodName = + node.callee.property?.type === "Identifier" ? node.callee.property.name : null; + if (objectName === "router" && (methodName === "push" || methodName === "replace")) { + return `router.${methodName}() in useEffect — use redirect() from next/navigation or handle navigation in an event handler`; + } } if (node.type === "AssignmentExpression" && node.left?.type === "MemberExpression") { const objectName = node.left.object?.type === "Identifier" ? node.left.object.name : null; const propertyName = node.left.property?.type === "Identifier" ? node.left.property.name : null; - if (objectName === "window" && propertyName === "location") return true; - if (objectName === "location" && propertyName === "href") return true; + if (objectName === "window" && propertyName === "location") { + return "window.location assignment in useEffect — use redirect() from next/navigation or handle in middleware instead"; + } + if (objectName === "location" && propertyName === "href") { + return "location.href assignment in useEffect — use redirect() from next/navigation or handle in middleware instead"; + } } - return false; + return null; }; export const nextjsNoClientSideRedirect: Rule = { @@ -209,11 +213,11 @@ export const nextjsNoClientSideRedirect: Rule = { if (!callback) return; walkAst(callback, (child: EsTreeNode) => { - if (isClientSideRedirect(child)) { + const navigationDescription = describeClientSideNavigation(child); + if (navigationDescription) { context.report({ node: child, - message: - "Client-side redirect in useEffect — use redirect() from next/navigation or handle in middleware instead", + message: navigationDescription, }); } }); diff --git a/packages/react-doctor/src/plugin/rules/react-native.ts b/packages/react-doctor/src/plugin/rules/react-native.ts index a82236b..df31fbe 100644 --- a/packages/react-doctor/src/plugin/rules/react-native.ts +++ b/packages/react-doctor/src/plugin/rules/react-native.ts @@ -5,6 +5,7 @@ import { RAW_TEXT_PREVIEW_MAX_CHARS, REACT_NATIVE_LIST_COMPONENTS, REACT_NATIVE_TEXT_COMPONENTS, + REACT_NATIVE_TEXT_COMPONENT_SUFFIXES, } from "../constants.js"; import { hasDirective, isMemberProperty } from "../helpers.js"; import type { EsTreeNode, Rule, RuleContext } from "../types.js"; @@ -53,6 +54,11 @@ const getRawTextDescription = (child: EsTreeNode): string => { return "text content"; }; +const isTextHandlingComponent = (elementName: string): boolean => { + if (REACT_NATIVE_TEXT_COMPONENTS.has(elementName)) return true; + return [...REACT_NATIVE_TEXT_COMPONENT_SUFFIXES].some((suffix) => elementName.endsWith(suffix)); +}; + export const rnNoRawText: Rule = { create: (context: RuleContext) => { let isDomComponentFile = false; @@ -65,11 +71,7 @@ export const rnNoRawText: Rule = { if (isDomComponentFile) return; const elementName = resolveJsxElementName(node.openingElement); - if ( - elementName && - (REACT_NATIVE_TEXT_COMPONENTS.has(elementName) || elementName.endsWith("Text")) - ) - return; + if (elementName && isTextHandlingComponent(elementName)) return; for (const child of node.children ?? []) { if (!isRawTextContent(child)) continue; diff --git a/packages/react-doctor/src/types.ts b/packages/react-doctor/src/types.ts index b0c4827..291f7a5 100644 --- a/packages/react-doctor/src/types.ts +++ b/packages/react-doctor/src/types.ts @@ -68,7 +68,7 @@ export interface PackageJson { dependencies?: Record; devDependencies?: Record; peerDependencies?: Record; - workspaces?: string[] | { packages: string[] }; + workspaces?: string[] | { packages?: string[]; catalog?: Record }; } export interface DependencyInfo { diff --git a/packages/react-doctor/src/utils/discover-project.ts b/packages/react-doctor/src/utils/discover-project.ts index dd6d764..f124b87 100644 --- a/packages/react-doctor/src/utils/discover-project.ts +++ b/packages/react-doctor/src/utils/discover-project.ts @@ -135,6 +135,12 @@ const detectFramework = (dependencies: Record): Framework => { const isCatalogReference = (version: string): boolean => version.startsWith("catalog:"); +const extractCatalogName = (version: string): string | null => { + if (!isCatalogReference(version)) return null; + const name = version.slice("catalog:".length).trim(); + return name.length > 0 ? name : null; +}; + const resolveVersionFromCatalog = ( catalog: Record, packageName: string, @@ -144,7 +150,112 @@ const resolveVersionFromCatalog = ( return null; }; -const resolveCatalogVersion = (packageJson: PackageJson, packageName: string): string | null => { +interface CatalogCollection { + defaultCatalog: Record; + namedCatalogs: Record>; +} + +const parsePnpmWorkspaceCatalogs = (rootDirectory: string): CatalogCollection => { + const workspacePath = path.join(rootDirectory, "pnpm-workspace.yaml"); + if (!isFile(workspacePath)) return { defaultCatalog: {}, namedCatalogs: {} }; + + const content = fs.readFileSync(workspacePath, "utf-8"); + const defaultCatalog: Record = {}; + const namedCatalogs: Record> = {}; + + let currentSection: "none" | "catalog" | "catalogs" | "named-catalog" = "none"; + let currentCatalogName = ""; + + for (const line of content.split("\n")) { + const trimmed = line.trim(); + if (trimmed.length === 0 || trimmed.startsWith("#")) continue; + + const indentLevel = line.search(/\S/); + + if (indentLevel === 0 && trimmed === "catalog:") { + currentSection = "catalog"; + continue; + } + if (indentLevel === 0 && trimmed === "catalogs:") { + currentSection = "catalogs"; + continue; + } + if (indentLevel === 0) { + currentSection = "none"; + continue; + } + + if (currentSection === "catalog" && indentLevel > 0) { + const colonIndex = trimmed.indexOf(":"); + if (colonIndex > 0) { + const key = trimmed.slice(0, colonIndex).trim().replace(/["']/g, ""); + const value = trimmed + .slice(colonIndex + 1) + .trim() + .replace(/["']/g, ""); + if (key && value) defaultCatalog[key] = value; + } + continue; + } + + if (currentSection === "catalogs" && indentLevel > 0) { + if (trimmed.endsWith(":") && !trimmed.includes(" ")) { + currentCatalogName = trimmed.slice(0, -1).replace(/["']/g, ""); + currentSection = "named-catalog"; + namedCatalogs[currentCatalogName] = {}; + continue; + } + } + + if (currentSection === "named-catalog" && indentLevel > 0) { + if (indentLevel <= 2 && trimmed.endsWith(":") && !trimmed.includes(" ")) { + currentCatalogName = trimmed.slice(0, -1).replace(/["']/g, ""); + namedCatalogs[currentCatalogName] = {}; + continue; + } + const colonIndex = trimmed.indexOf(":"); + if (colonIndex > 0 && currentCatalogName) { + const key = trimmed.slice(0, colonIndex).trim().replace(/["']/g, ""); + const value = trimmed + .slice(colonIndex + 1) + .trim() + .replace(/["']/g, ""); + if (key && value) namedCatalogs[currentCatalogName][key] = value; + } + } + } + + return { defaultCatalog, namedCatalogs }; +}; + +const resolveCatalogVersionFromCollection = ( + catalogs: CatalogCollection, + packageName: string, + catalogReference?: string | null, +): string | null => { + if (catalogReference) { + const namedCatalog = catalogs.namedCatalogs[catalogReference]; + if (namedCatalog?.[packageName]) return namedCatalog[packageName]; + } + + if (catalogs.defaultCatalog[packageName]) return catalogs.defaultCatalog[packageName]; + + for (const namedCatalog of Object.values(catalogs.namedCatalogs)) { + if (namedCatalog[packageName]) return namedCatalog[packageName]; + } + + return null; +}; + +const resolveCatalogVersion = ( + packageJson: PackageJson, + packageName: string, + rootDirectory?: string, +): string | null => { + const allDependencies = collectAllDependencies(packageJson); + const rawVersion = allDependencies[packageName]; + const catalogName = rawVersion ? extractCatalogName(rawVersion) : null; + const raw = packageJson as Record; if (isPlainObject(raw.catalog)) { @@ -153,6 +264,13 @@ const resolveCatalogVersion = (packageJson: PackageJson, packageName: string): s } if (isPlainObject(raw.catalogs)) { + if (catalogName && isPlainObject((raw.catalogs as Record)[catalogName])) { + const version = resolveVersionFromCatalog( + (raw.catalogs as Record)[catalogName] as Record, + packageName, + ); + if (version) return version; + } for (const catalogEntries of Object.values(raw.catalogs)) { if (isPlainObject(catalogEntries)) { const version = resolveVersionFromCatalog(catalogEntries, packageName); @@ -161,6 +279,21 @@ const resolveCatalogVersion = (packageJson: PackageJson, packageName: string): s } } + const workspaces = packageJson.workspaces; + if (workspaces && !Array.isArray(workspaces) && isPlainObject(workspaces.catalog)) { + const version = resolveVersionFromCatalog( + workspaces.catalog as Record, + packageName, + ); + if (version) return version; + } + + if (rootDirectory) { + const pnpmCatalogs = parsePnpmWorkspaceCatalogs(rootDirectory); + const pnpmVersion = resolveCatalogVersionFromCollection(pnpmCatalogs, packageName, catalogName); + if (pnpmVersion) return pnpmVersion; + } + return null; }; @@ -252,7 +385,7 @@ const findDependencyInfoFromMonorepoRoot = (directory: string): DependencyInfo = const rootPackageJson = readPackageJson(monorepoPackageJsonPath); const rootInfo = extractDependencyInfo(rootPackageJson); - const catalogVersion = resolveCatalogVersion(rootPackageJson, "react"); + const catalogVersion = resolveCatalogVersion(rootPackageJson, "react", monorepoRoot); const workspaceInfo = findReactInWorkspaces(monorepoRoot, rootPackageJson); return { @@ -342,6 +475,11 @@ export const listWorkspacePackages = (rootDirectory: string): WorkspacePackage[] const packages: WorkspacePackage[] = []; + if (hasReactDependency(packageJson)) { + const rootName = packageJson.name ?? path.basename(rootDirectory); + packages.push({ name: rootName, directory: rootDirectory }); + } + for (const pattern of patterns) { const directories = resolveWorkspaceDirectories(rootDirectory, pattern); for (const workspaceDirectory of directories) { @@ -406,7 +544,18 @@ export const discoverProject = (directory: string): ProjectInfo => { let { reactVersion, framework } = extractDependencyInfo(packageJson); if (!reactVersion) { - reactVersion = resolveCatalogVersion(packageJson, "react"); + reactVersion = resolveCatalogVersion(packageJson, "react", directory); + } + + if (!reactVersion) { + const monorepoRoot = findMonorepoRoot(directory); + if (monorepoRoot) { + const monorepoPackageJsonPath = path.join(monorepoRoot, "package.json"); + if (isFile(monorepoPackageJsonPath)) { + const rootPackageJson = readPackageJson(monorepoPackageJsonPath); + reactVersion = resolveCatalogVersion(rootPackageJson, "react", monorepoRoot); + } + } } if (!reactVersion || framework === "unknown") { diff --git a/packages/react-doctor/tests/discover-project.test.ts b/packages/react-doctor/tests/discover-project.test.ts index 44f9182..50b5488 100644 --- a/packages/react-doctor/tests/discover-project.test.ts +++ b/packages/react-doctor/tests/discover-project.test.ts @@ -44,6 +44,27 @@ describe("discoverProject", () => { expect(() => discoverProject(projectDirectory)).toThrow("No package.json found"); }); + + it("resolves React version from pnpm workspace default catalog", () => { + const projectInfo = discoverProject( + path.join(FIXTURES_DIRECTORY, "pnpm-catalog-workspace", "packages", "ui"), + ); + expect(projectInfo.reactVersion).toBe("^19.0.0"); + }); + + it("resolves React version from pnpm workspace named catalog", () => { + const projectInfo = discoverProject( + path.join(FIXTURES_DIRECTORY, "pnpm-named-catalog", "packages", "app"), + ); + expect(projectInfo.reactVersion).toBe("^19.0.0"); + }); + + it("resolves React version from Bun workspace catalog", () => { + const projectInfo = discoverProject( + path.join(FIXTURES_DIRECTORY, "bun-catalog-workspace", "apps", "web"), + ); + expect(projectInfo.reactVersion).toBe("^19.1.4"); + }); }); describe("listWorkspacePackages", () => { @@ -55,6 +76,17 @@ describe("listWorkspacePackages", () => { expect(packageNames).toContain("ui"); expect(packages).toHaveLength(2); }); + + it("includes monorepo root when it has a React dependency", () => { + const packages = listWorkspacePackages( + path.join(FIXTURES_DIRECTORY, "monorepo-with-root-react"), + ); + const packageNames = packages.map((workspacePackage) => workspacePackage.name); + + expect(packageNames).toContain("monorepo-root"); + expect(packageNames).toContain("ui"); + expect(packages).toHaveLength(2); + }); }); const tempDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "react-doctor-discover-test-")); diff --git a/packages/react-doctor/tests/filter-diagnostics.test.ts b/packages/react-doctor/tests/filter-diagnostics.test.ts index 6a7bc9c..b67e55a 100644 --- a/packages/react-doctor/tests/filter-diagnostics.test.ts +++ b/packages/react-doctor/tests/filter-diagnostics.test.ts @@ -2,6 +2,8 @@ import { describe, expect, it } from "vitest"; import type { Diagnostic, ReactDoctorConfig } from "../src/types.js"; import { filterIgnoredDiagnostics } from "../src/utils/filter-diagnostics.js"; +const TEST_ROOT_DIRECTORY = "/home/user/project"; + const createDiagnostic = (overrides: Partial = {}): Diagnostic => ({ filePath: "src/app.tsx", plugin: "react", @@ -19,7 +21,7 @@ describe("filterIgnoredDiagnostics", () => { it("returns all diagnostics when config has no ignore rules", () => { const diagnostics = [createDiagnostic()]; const config: ReactDoctorConfig = {}; - expect(filterIgnoredDiagnostics(diagnostics, config, "")).toEqual(diagnostics); + expect(filterIgnoredDiagnostics(diagnostics, config, TEST_ROOT_DIRECTORY)).toEqual(diagnostics); }); it("filters diagnostics matching ignored rules", () => { @@ -34,7 +36,7 @@ describe("filterIgnoredDiagnostics", () => { }, }; - const filtered = filterIgnoredDiagnostics(diagnostics, config, ""); + const filtered = filterIgnoredDiagnostics(diagnostics, config, TEST_ROOT_DIRECTORY); expect(filtered).toHaveLength(1); expect(filtered[0].rule).toBe("no-giant-component"); }); @@ -51,7 +53,7 @@ describe("filterIgnoredDiagnostics", () => { }, }; - const filtered = filterIgnoredDiagnostics(diagnostics, config, ""); + const filtered = filterIgnoredDiagnostics(diagnostics, config, TEST_ROOT_DIRECTORY); expect(filtered).toHaveLength(1); expect(filtered[0].filePath).toBe("src/components/Button.tsx"); }); @@ -73,7 +75,7 @@ describe("filterIgnoredDiagnostics", () => { }, }; - const filtered = filterIgnoredDiagnostics(diagnostics, config, ""); + const filtered = filterIgnoredDiagnostics(diagnostics, config, TEST_ROOT_DIRECTORY); expect(filtered).toHaveLength(1); expect(filtered[0].rule).toBe("no-giant-component"); }); @@ -90,7 +92,7 @@ describe("filterIgnoredDiagnostics", () => { }, }; - const filtered = filterIgnoredDiagnostics(diagnostics, config, ""); + const filtered = filterIgnoredDiagnostics(diagnostics, config, TEST_ROOT_DIRECTORY); expect(filtered).toHaveLength(2); }); @@ -106,11 +108,35 @@ describe("filterIgnoredDiagnostics", () => { }, }; - const filtered = filterIgnoredDiagnostics(diagnostics, config, ""); + const filtered = filterIgnoredDiagnostics(diagnostics, config, TEST_ROOT_DIRECTORY); expect(filtered).toHaveLength(1); expect(filtered[0].filePath).toBe("./resources/js/pages/Home.tsx"); }); + it("filters absolute file paths against relative patterns", () => { + const rootDirectory = "/home/user/project"; + const diagnostics = [ + createDiagnostic({ + filePath: "/home/user/project/resources/js/components/ui/Button.tsx", + }), + createDiagnostic({ + filePath: "/home/user/project/resources/js/marketing/Hero.tsx", + }), + createDiagnostic({ + filePath: "/home/user/project/resources/js/pages/Home.tsx", + }), + ]; + const config: ReactDoctorConfig = { + ignore: { + files: ["/resources/js/components/ui/**", "/resources/js/marketing/**"], + }, + }; + + const filtered = filterIgnoredDiagnostics(diagnostics, config, rootDirectory); + expect(filtered).toHaveLength(1); + expect(filtered[0].filePath).toContain("pages/Home.tsx"); + }); + it("handles knip rule identifiers", () => { const diagnostics = [ createDiagnostic({ plugin: "knip", rule: "exports" }), @@ -123,7 +149,7 @@ describe("filterIgnoredDiagnostics", () => { }, }; - const filtered = filterIgnoredDiagnostics(diagnostics, config, ""); + const filtered = filterIgnoredDiagnostics(diagnostics, config, TEST_ROOT_DIRECTORY); expect(filtered).toHaveLength(1); expect(filtered[0].rule).toBe("files"); }); diff --git a/packages/react-doctor/tests/fixtures/bun-catalog-workspace/apps/web/package.json b/packages/react-doctor/tests/fixtures/bun-catalog-workspace/apps/web/package.json new file mode 100644 index 0000000..d5c6ca0 --- /dev/null +++ b/packages/react-doctor/tests/fixtures/bun-catalog-workspace/apps/web/package.json @@ -0,0 +1,8 @@ +{ + "name": "web", + "private": true, + "dependencies": { + "react": "catalog:", + "react-dom": "catalog:" + } +} diff --git a/packages/react-doctor/tests/fixtures/bun-catalog-workspace/package.json b/packages/react-doctor/tests/fixtures/bun-catalog-workspace/package.json new file mode 100644 index 0000000..c32b7fb --- /dev/null +++ b/packages/react-doctor/tests/fixtures/bun-catalog-workspace/package.json @@ -0,0 +1,13 @@ +{ + "name": "bun-catalog-workspace", + "private": true, + "workspaces": { + "packages": [ + "apps/*" + ], + "catalog": { + "react": "^19.1.4", + "react-dom": "^19.1.4" + } + } +} diff --git a/packages/react-doctor/tests/fixtures/monorepo-with-root-react/package.json b/packages/react-doctor/tests/fixtures/monorepo-with-root-react/package.json new file mode 100644 index 0000000..c6baf91 --- /dev/null +++ b/packages/react-doctor/tests/fixtures/monorepo-with-root-react/package.json @@ -0,0 +1,11 @@ +{ + "name": "monorepo-root", + "private": true, + "workspaces": [ + "packages/*" + ], + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0" + } +} diff --git a/packages/react-doctor/tests/fixtures/monorepo-with-root-react/packages/ui/package.json b/packages/react-doctor/tests/fixtures/monorepo-with-root-react/packages/ui/package.json new file mode 100644 index 0000000..fcc2236 --- /dev/null +++ b/packages/react-doctor/tests/fixtures/monorepo-with-root-react/packages/ui/package.json @@ -0,0 +1,7 @@ +{ + "name": "ui", + "private": true, + "dependencies": { + "react": "^19.0.0" + } +} diff --git a/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/package.json b/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/package.json new file mode 100644 index 0000000..00fd74b --- /dev/null +++ b/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/package.json @@ -0,0 +1,4 @@ +{ + "name": "pnpm-catalog-workspace", + "private": true +} diff --git a/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/packages/ui/package.json b/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/packages/ui/package.json new file mode 100644 index 0000000..739e714 --- /dev/null +++ b/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/packages/ui/package.json @@ -0,0 +1,8 @@ +{ + "name": "ui", + "private": true, + "dependencies": { + "react": "catalog:", + "react-dom": "catalog:" + } +} diff --git a/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/pnpm-workspace.yaml b/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/pnpm-workspace.yaml new file mode 100644 index 0000000..2b4e4dc --- /dev/null +++ b/packages/react-doctor/tests/fixtures/pnpm-catalog-workspace/pnpm-workspace.yaml @@ -0,0 +1,11 @@ +packages: + - "packages/*" + +catalog: + react: ^19.0.0 + react-dom: ^19.0.0 + +catalogs: + react_v18: + react: ^18.2.0 + react-dom: ^18.2.0 diff --git a/packages/react-doctor/tests/fixtures/pnpm-named-catalog/package.json b/packages/react-doctor/tests/fixtures/pnpm-named-catalog/package.json new file mode 100644 index 0000000..ef8856a --- /dev/null +++ b/packages/react-doctor/tests/fixtures/pnpm-named-catalog/package.json @@ -0,0 +1,4 @@ +{ + "name": "pnpm-named-catalog", + "private": true +} diff --git a/packages/react-doctor/tests/fixtures/pnpm-named-catalog/packages/app/package.json b/packages/react-doctor/tests/fixtures/pnpm-named-catalog/packages/app/package.json new file mode 100644 index 0000000..7144aae --- /dev/null +++ b/packages/react-doctor/tests/fixtures/pnpm-named-catalog/packages/app/package.json @@ -0,0 +1,8 @@ +{ + "name": "app", + "private": true, + "dependencies": { + "react": "catalog:react_v19_current", + "react-dom": "catalog:react_v19_current" + } +} diff --git a/packages/react-doctor/tests/fixtures/pnpm-named-catalog/pnpm-workspace.yaml b/packages/react-doctor/tests/fixtures/pnpm-named-catalog/pnpm-workspace.yaml new file mode 100644 index 0000000..b3fe4e1 --- /dev/null +++ b/packages/react-doctor/tests/fixtures/pnpm-named-catalog/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +packages: + - "packages/*" + +catalogs: + react_v19_current: + react: ^19.0.0 + react-dom: ^19.0.0 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e341cc6..ce9041d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,8 +19,8 @@ importers: version: 1.1.1 devDependencies: '@changesets/cli': - specifier: ^2.27.0 - version: 2.29.8(@types/node@20.19.33) + specifier: ^2.30.0 + version: 2.30.0(@types/node@20.19.33) eslint-plugin-react-hooks: specifier: ^7.0.1 version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) @@ -189,8 +189,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} '@babel/template@7.28.6': @@ -209,8 +209,8 @@ packages: resolution: {integrity: sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ==} engines: {node: ^20.19.0 || >=22.12.0} - '@changesets/apply-release-plan@7.0.14': - resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} + '@changesets/apply-release-plan@7.1.0': + resolution: {integrity: sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==} '@changesets/assemble-release-plan@6.0.9': resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} @@ -218,12 +218,12 @@ packages: '@changesets/changelog-git@0.2.1': resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} - '@changesets/cli@2.29.8': - resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==} + '@changesets/cli@2.30.0': + resolution: {integrity: sha512-5D3Nk2JPqMI1wK25pEymeWRSlSMdo5QOGlyfrKg0AOufrUcjEE3RQgaCpHoBiM31CSNrtSgdJ0U6zL1rLDDfBA==} hasBin: true - '@changesets/config@3.1.2': - resolution: {integrity: sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==} + '@changesets/config@3.1.3': + resolution: {integrity: sha512-vnXjcey8YgBn2L1OPWd3ORs0bGC4LoYcK/ubpgvzNVr53JXV5GiTVj7fWdMRsoKUH7hhhMAQnsJUqLr21EncNw==} '@changesets/errors@0.2.0': resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} @@ -231,8 +231,8 @@ packages: '@changesets/get-dependents-graph@2.1.3': resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} - '@changesets/get-release-plan@4.0.14': - resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==} + '@changesets/get-release-plan@4.0.15': + resolution: {integrity: sha512-Q04ZaRPuEVZtA+auOYgFaVQQSA98dXiVe/yFaZfY7hoSmQICHGvP0TF4u3EDNHWmmCS4ekA/XSpKlSM2PyTS2g==} '@changesets/get-version-range-type@0.4.0': resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} @@ -243,14 +243,14 @@ packages: '@changesets/logger@0.1.1': resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - '@changesets/parse@0.4.2': - resolution: {integrity: sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==} + '@changesets/parse@0.4.3': + resolution: {integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==} '@changesets/pre@2.0.2': resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} - '@changesets/read@0.6.6': - resolution: {integrity: sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==} + '@changesets/read@0.6.7': + resolution: {integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==} '@changesets/should-skip-package@0.1.2': resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} @@ -439,8 +439,8 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/config-helpers@0.4.2': @@ -451,8 +451,8 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/js@9.39.2': @@ -1513,13 +1513,13 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} @@ -1573,8 +1573,8 @@ packages: birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@1.1.13: + resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -1614,10 +1614,6 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -1834,8 +1830,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} formatly@0.3.0: resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} @@ -2124,8 +2120,8 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2800,7 +2796,7 @@ snapshots: dependencies: '@babel/types': 8.0.0-rc.1 - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.2': {} '@babel/template@7.28.6': dependencies: @@ -2830,9 +2826,9 @@ snapshots: '@babel/helper-string-parser': 8.0.0-rc.2 '@babel/helper-validator-identifier': 8.0.0-rc.1 - '@changesets/apply-release-plan@7.0.14': + '@changesets/apply-release-plan@7.1.0': dependencies: - '@changesets/config': 3.1.2 + '@changesets/config': 3.1.3 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.4 '@changesets/should-skip-package': 0.1.2 @@ -2859,30 +2855,28 @@ snapshots: dependencies: '@changesets/types': 6.1.0 - '@changesets/cli@2.29.8(@types/node@20.19.33)': + '@changesets/cli@2.30.0(@types/node@20.19.33)': dependencies: - '@changesets/apply-release-plan': 7.0.14 + '@changesets/apply-release-plan': 7.1.0 '@changesets/assemble-release-plan': 6.0.9 '@changesets/changelog-git': 0.2.1 - '@changesets/config': 3.1.2 + '@changesets/config': 3.1.3 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 - '@changesets/get-release-plan': 4.0.14 + '@changesets/get-release-plan': 4.0.15 '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.6 + '@changesets/read': 0.6.7 '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 '@inquirer/external-editor': 1.0.3(@types/node@20.19.33) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 - ci-info: 3.9.0 enquirer: 2.4.1 fs-extra: 7.0.1 mri: 1.2.0 - p-limit: 2.3.0 package-manager-detector: 0.2.11 picocolors: 1.1.1 resolve-from: 5.0.0 @@ -2892,11 +2886,12 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@changesets/config@3.1.2': + '@changesets/config@3.1.3': dependencies: '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.1.3 '@changesets/logger': 0.1.1 + '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 @@ -2913,12 +2908,12 @@ snapshots: picocolors: 1.1.1 semver: 7.7.4 - '@changesets/get-release-plan@4.0.14': + '@changesets/get-release-plan@4.0.15': dependencies: '@changesets/assemble-release-plan': 6.0.9 - '@changesets/config': 3.1.2 + '@changesets/config': 3.1.3 '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.6 + '@changesets/read': 0.6.7 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 @@ -2936,7 +2931,7 @@ snapshots: dependencies: picocolors: 1.1.1 - '@changesets/parse@0.4.2': + '@changesets/parse@0.4.3': dependencies: '@changesets/types': 6.1.0 js-yaml: 4.1.1 @@ -2948,11 +2943,11 @@ snapshots: '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 - '@changesets/read@0.6.6': + '@changesets/read@0.6.7': dependencies: '@changesets/git': 3.0.4 '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.2 + '@changesets/parse': 0.4.3 '@changesets/types': 6.1.0 fs-extra: 7.0.1 p-filter: 2.1.0 @@ -3075,11 +3070,11 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.21.2': dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -3091,16 +3086,16 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.3': + '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.12.6 + ajv: 6.14.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.2 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color @@ -3256,14 +3251,14 @@ snapshots: '@manypkg/find-root@1.1.0': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 '@manypkg/get-packages@1.1.3': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -3771,13 +3766,13 @@ snapshots: '@vitest/pretty-format': 4.0.18 tinyrainbow: 3.0.3 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} - ajv@6.12.6: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -3822,7 +3817,7 @@ snapshots: birpc@4.0.0: {} - brace-expansion@1.1.12: + brace-expansion@1.1.13: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 @@ -3859,8 +3854,6 @@ snapshots: chardet@2.1.1: {} - ci-info@3.9.0: {} - cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -3985,17 +3978,17 @@ snapshots: dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 + '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 + '@eslint/eslintrc': 3.3.5 '@eslint/js': 9.39.2 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -4014,7 +4007,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -4024,8 +4017,8 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 esprima@4.0.1: {} @@ -4096,10 +4089,10 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 - flatted@3.3.3: {} + flatted@3.4.2: {} formatly@0.3.0: dependencies: @@ -4338,9 +4331,9 @@ snapshots: mimic-function@5.0.1: {} - minimatch@3.1.2: + minimatch@3.1.5: dependencies: - brace-expansion: 1.1.12 + brace-expansion: 1.1.13 minimist@1.2.8: {} @@ -4769,7 +4762,7 @@ snapshots: terser@5.46.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 optional: true