build(release): reference workspace members through the workspace protocol

1504 hand-written ranges pointing at workspace members become workspace:^, so
pnpm pack substitutes each member's real version at publication: sibling
peerDependencies follow the family version instead of being pinned at ^0.0.1,
and a reference to a vendored package follows that package's own line. Without
this, publishing 0.0.2 ships peer ranges naming a version that does not exist,
and 0.0.1-rc.1 does not satisfy ^0.0.1 either.

It also retires ranges that had gone stale against the workspace: ^4.0.0-rc.6
for a 4.0.0-rc.7 checkout, ^3.17.0 for schemastery 3.18.0.

workspace:* stays where an exact published version is the point, which is how
the Landlock entry pins its platform packages.

A workspace constraint now requires the protocol, so a new package cannot
reintroduce a hand-written range. The same constraint caught packages/boot/cmdline
arriving on master without the publishable trio, which this change completes.
This commit is contained in:
imccyu
2026-08-11 00:16:45 +08:00
parent d4128ae57f
commit 2c85c484d3
218 changed files with 1774 additions and 1736 deletions
+32 -1
View File
@@ -80,6 +80,8 @@ interface PackageManifest {
repository?: { type?: string; url?: string; directory?: string }
peerDependencies?: Record<string, string>
devDependencies?: Record<string, string>
dependencies?: Record<string, string>
optionalDependencies?: Record<string, string>
}
/** One workspace manifest and its repo-relative path. */
@@ -380,9 +382,38 @@ function checkRepositoryVersion(): string[] {
return ['package.json: version must be stable X.Y.Z']
}
/** Dependency sections whose ranges reach a published tarball or a local install. */
const dependencySections = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] as const
/**
* Require the `workspace:` protocol for every reference to a workspace member.
*
* A hand-written range says nothing about the version the workspace actually
* carries, and `pnpm pack` leaves it alone: `^0.0.1` published from version
* `0.0.2` names a version that does not exist. The protocol makes pack
* substitute the member's real version, so no release step rewrites ranges.
* @param manifests - every workspace manifest.
* @returns One error per reference that names a workspace member without the protocol.
*/
function checkWorkspaceProtocol(manifests: readonly WorkspaceManifest[]): string[] {
const members = new Set(manifests.map(entry => entry.manifest.name).filter(name => name !== undefined))
const errors: string[] = []
for (const { dir, manifest } of manifests) {
for (const section of dependencySections) {
for (const [name, range] of Object.entries(manifest[section] ?? {})) {
if (!members.has(name) || range.startsWith('workspace:')) continue
errors.push(`${manifest.name ?? dir}: ${section}.${name} must use the workspace: protocol, got ${range}`)
}
}
}
return errors
}
const manifests = workspaceManifests()
const errors = [
...checkRepositoryVersion(),
...workspaceManifests().flatMap(checkWorkspace),
...manifests.flatMap(checkWorkspace),
...checkWorkspaceProtocol(manifests),
...checkHierarchyShape(),
...collectProjectReferenceFaceViolations(root),
]