ext-apps/scripts/check-versions.mjs
Olivier Chafik 605e31b6c5
chore: bump ext-apps to 1.0.1 (#369)
* chore: bump ext-apps to 1.0.1

* chore: update examples to depend on ext-apps ^1.0.1

* fix: revert examples to ext-apps ^1.0.0 and fix cheerio version

- Revert ext-apps dependency to ^1.0.0 (works with 1.0.1 once published)
- Fix accidental cheerio bump in wiki-explorer-server
- Remove broken override attempt

* fix: allow compatible semver ranges in version check

The check-versions script now accepts any compatible semver range,
not just exact version matches. For example, ^1.0.0 is allowed when
root version is 1.0.1, since semver compatibility is maintained.

* style: fix indentation in package.json
2026-01-26 22:32:34 +00:00

80 lines
2.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Checks that example package.json files reference a compatible version
* of @modelcontextprotocol/ext-apps as the root package.json.
*
* This ensures examples stay in sync with the library version.
*/
import { readFileSync, readdirSync, statSync, existsSync } from "fs";
import { join } from "path";
const rootPkg = JSON.parse(readFileSync("package.json", "utf-8"));
const rootVersion = rootPkg.version;
const pkgName = rootPkg.name;
// Parse semver major.minor.patch
const [major, minor] = rootVersion.split(".").map(Number);
/**
* Check if a dependency range is compatible with the root version.
* Allows:
* - "../.." (local dev)
* - "^X.Y.Z" where X.Y matches root major.minor (e.g., ^1.0.0 is compatible with 1.0.1)
* - Exact match like "1.0.1"
*/
function isCompatible(dep) {
if (dep === "../..") return true;
// Handle caret ranges like ^1.0.0
if (dep.startsWith("^")) {
const version = dep.slice(1);
const [depMajor, depMinor] = version.split(".").map(Number);
// For major version 0, minor must match; for major > 0, only major must match
if (major === 0) {
return depMajor === major && depMinor === minor;
}
return depMajor === major;
}
// Handle exact version
if (/^\d+\.\d+\.\d+$/.test(dep)) {
const [depMajor] = dep.split(".").map(Number);
return depMajor === major;
}
return false;
}
let hasError = false;
const examplesDir = "examples";
const examples = readdirSync(examplesDir).filter((d) => {
const pkgPath = join(examplesDir, d, "package.json");
return statSync(join(examplesDir, d)).isDirectory() && existsSync(pkgPath);
});
for (const example of examples) {
const pkgPath = join(examplesDir, example, "package.json");
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
const dep = pkg.dependencies?.[pkgName];
if (dep && !isCompatible(dep)) {
console.error(
`❌ ${pkgPath}: "${pkgName}": "${dep}" is not compatible with root version ${rootVersion}`,
);
hasError = true;
}
}
if (hasError) {
const expectedDep = `^${major}.${minor}.0`;
console.error(
`\nRun the following to fix:\n npm pkg set dependencies.${pkgName}=${expectedDep} --workspaces`,
);
process.exit(1);
} else {
console.log(
`✅ All examples reference compatible ${pkgName} versions (root version: ${rootVersion})`,
);
}