|
47 | 47 | import { existsSync, readFileSync } from "node:fs"; |
48 | 48 | import path from "node:path"; |
49 | 49 | import { fileURLToPath, pathToFileURL } from "node:url"; |
| 50 | +import { workspaceDirs } from "./lib/workspaces.mjs"; |
50 | 51 |
|
51 | 52 | const repoRoot = path.resolve( |
52 | 53 | path.dirname(fileURLToPath(import.meta.url)), |
@@ -164,6 +165,21 @@ export function main(root = repoRoot) { |
164 | 165 | ? JSON.parse(readFileSync(manifest, "utf8")) |
165 | 166 | : undefined; |
166 | 167 | }); |
| 168 | + // A workspace added since the last install has a manifest and no lockfile |
| 169 | + // entry at all, so the comparison above (which walks the lockfile) never |
| 170 | + // reaches it. Found from the root manifest's `workspaces`, not the lockfile. |
| 171 | + const rootManifestPath = path.join(root, "package.json"); |
| 172 | + const workspaces = existsSync(rootManifestPath) |
| 173 | + ? JSON.parse(readFileSync(rootManifestPath, "utf8")).workspaces |
| 174 | + : undefined; |
| 175 | + if (Array.isArray(workspaces) && workspaces.length > 0) { |
| 176 | + for (const { dir, hasManifest } of workspaceDirs(root, workspaces)) { |
| 177 | + if (hasManifest && lock.packages?.[dir] === undefined) |
| 178 | + problems.push( |
| 179 | + ` ${dir}/package.json: a workspace the lockfile has no entry for`, |
| 180 | + ); |
| 181 | + } |
| 182 | + } |
167 | 183 | for (const d of drift) |
168 | 184 | problems.push( |
169 | 185 | ` ${path.posix.join(d.dir || ".", "package.json")} ${d.section}.${d.name}: manifest ${d.manifest ?? "(absent)"}, lockfile ${d.lock ?? "(absent)"}`, |
|
0 commit comments