Skip to content

Commit 866aecf

Browse files
Migrate to catalogs (#10121)
1 parent 0132257 commit 866aecf

File tree

57 files changed

+2255
-1488
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2255
-1488
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
3+
changeKind: internal
4+
packages:
5+
- "@typespec/asset-emitter"
6+
- "@typespec/bundler"
7+
- "@typespec/compiler"
8+
- "@typespec/emitter-framework"
9+
- "@typespec/eslint-plugin"
10+
- "@typespec/events"
11+
- "@typespec/html-program-viewer"
12+
- "@typespec/http-canonicalization"
13+
- "@typespec/http-client-js"
14+
- "@typespec/http-client"
15+
- "@typespec/http-server-csharp"
16+
- "@typespec/http-server-js"
17+
- "@typespec/http-specs"
18+
- "@typespec/http"
19+
- "@typespec/internal-build-utils"
20+
- "@typespec/json-schema"
21+
- "@typespec/library-linter"
22+
- "@typespec/mutator-framework"
23+
- "@typespec/openapi"
24+
- "@typespec/openapi3"
25+
- "@typespec/playground"
26+
- "@typespec/prettier-plugin-typespec"
27+
- "@typespec/protobuf"
28+
- "@typespec/rest"
29+
- "@typespec/spec-api"
30+
- "@typespec/spec-coverage-sdk"
31+
- "@typespec/spector"
32+
- "@typespec/sse"
33+
- "@typespec/streams"
34+
- tmlanguage-generator
35+
- "@typespec/tspd"
36+
- typespec-vscode
37+
- "@typespec/versioning"
38+
- "@typespec/xml"
39+
---
40+
41+
Migrate to catalogs

.github/copilot-instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ TypeSpec is a language for defining cloud service APIs and shapes. This monorepo
109109
- Generate external signatures: `pnpm gen-compiler-extern-signature`
110110
- Regenerate samples: `pnpm regen-samples`
111111
- Regenerate docs: `pnpm regen-docs`
112-
- Sync dependency versions: `pnpm fix-version-mismatch`
112+
- Check catalog usage: `pnpm check-catalog`
113113

114114
## Troubleshooting
115115

.github/workflows/consistency.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ jobs:
103103
- run: pnpm run lint
104104
name: Lint
105105

106-
# Check version mismatch
106+
# Check that all dependencies use the pnpm catalog
107107
version-consistency:
108108
name: Versions consistency
109109
runs-on: ubuntu-latest
@@ -117,5 +117,5 @@ jobs:
117117
- run: pnpm install
118118
name: Install dependencies
119119

120-
- run: pnpm run check-version-mismatch
121-
name: Check version mismatch
120+
- run: pnpm run check-catalog
121+
name: Check catalog usage

cspell.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,6 @@ words:
256256
- strs
257257
- stubbed
258258
- swaggerui
259-
- syncpack
260259
- TCGC
261260
- terlson
262261
- timegm
@@ -337,6 +336,7 @@ ignorePaths:
337336
- packages/mutator-framework/**/*.test.ts
338337
- packages/typespec-vscode/test/scenarios/**
339338
- pnpm-lock.yaml
339+
- pnpm-workspace.yaml
340340
- "**/*.mp4"
341341
- "**/*.plist"
342342
- .git/**

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ RUN pnpm install --filter "@typespec/compiler..."
1919
RUN pnpm --filter "@typespec/compiler..." run build
2020

2121
WORKDIR /app/packages/compiler
22-
RUN npm pack
22+
RUN pnpm pack
2323

2424
# --------------------------------
2525
# Setup final image
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { execSync } from "child_process";
2+
import { readFileSync } from "fs";
3+
import { join, relative } from "path";
4+
import { parse } from "yaml";
5+
import { repoRoot } from "./utils/common.js";
6+
7+
/**
8+
* Validates that all workspace package dependencies use `catalog:` or `workspace:` protocols,
9+
* ensuring versions are centrally managed via the pnpm catalog in pnpm-workspace.yaml.
10+
*/
11+
12+
interface WorkspaceConfig {
13+
catalog?: Record<string, string>;
14+
}
15+
16+
const workspaceConfig: WorkspaceConfig = parse(
17+
readFileSync(join(repoRoot, "pnpm-workspace.yaml"), "utf8"),
18+
);
19+
const catalog = workspaceConfig.catalog ?? {};
20+
21+
/**
22+
* Dependencies that are allowed to use explicit versions instead of catalog:.
23+
* Each entry maps a package.json path (relative to repo root) to a set of dependency names.
24+
*/
25+
const exceptions: Record<string, Set<string>> = {
26+
// vsce needs a real semver for @types/vscode to determine VS Code engine compatibility
27+
"packages/typespec-vscode/package.json": new Set(["@types/vscode"]),
28+
};
29+
30+
const depTypes = ["dependencies", "devDependencies", "peerDependencies"] as const;
31+
32+
const errors: string[] = [];
33+
const warnings: string[] = [];
34+
35+
// Resolve workspace packages from pnpm
36+
const pnpmOutput = execSync("pnpm ls -r --json --depth -1", {
37+
cwd: repoRoot,
38+
encoding: "utf8",
39+
});
40+
const workspacePackages: { path: string }[] = JSON.parse(pnpmOutput);
41+
const packageJsonPaths: string[] = workspacePackages.map((p) =>
42+
join(relative(repoRoot, p.path), "package.json"),
43+
);
44+
45+
for (const relPath of packageJsonPaths) {
46+
const fullPath = join(repoRoot, relPath);
47+
const pkg = JSON.parse(readFileSync(fullPath, "utf8"));
48+
const fileExceptions = exceptions[relPath] ?? new Set();
49+
50+
for (const depType of depTypes) {
51+
const deps: Record<string, string> | undefined = pkg[depType];
52+
if (!deps) continue;
53+
54+
for (const [name, version] of Object.entries(deps)) {
55+
if (version === "catalog:" || version.startsWith("workspace:")) {
56+
continue;
57+
}
58+
if (fileExceptions.has(name)) {
59+
// Allowed exception — but warn if it drifts from the catalog
60+
if (catalog[name] && catalog[name] !== version) {
61+
warnings.push(
62+
`${relPath}: ${depType}.${name} has version "${version}" but catalog has "${catalog[name]}". Keep them in sync.`,
63+
);
64+
}
65+
continue;
66+
}
67+
errors.push(
68+
`${relPath}: ${depType}.${name} uses explicit version "${version}" instead of "catalog:".`,
69+
);
70+
}
71+
}
72+
}
73+
74+
// Check that every catalog entry is actually used somewhere
75+
const usedCatalogEntries = new Set<string>();
76+
for (const relPath of packageJsonPaths) {
77+
const fullPath = join(repoRoot, relPath);
78+
const pkg = JSON.parse(readFileSync(fullPath, "utf8"));
79+
for (const depType of depTypes) {
80+
const deps: Record<string, string> | undefined = pkg[depType];
81+
if (!deps) continue;
82+
for (const [name, version] of Object.entries(deps)) {
83+
if (version === "catalog:") {
84+
usedCatalogEntries.add(name);
85+
}
86+
}
87+
}
88+
}
89+
90+
for (const name of Object.keys(catalog)) {
91+
if (!usedCatalogEntries.has(name)) {
92+
warnings.push(`pnpm-workspace.yaml: catalog entry "${name}" is not used by any package.`);
93+
}
94+
}
95+
96+
// Report results
97+
if (warnings.length > 0) {
98+
console.log(`\n⚠ Warnings (${warnings.length}):`);
99+
for (const w of warnings) {
100+
console.log(` ${w}`);
101+
}
102+
}
103+
104+
if (errors.length > 0) {
105+
console.log(`\n✘ Errors (${errors.length}):`);
106+
for (const e of errors) {
107+
console.log(` ${e}`);
108+
}
109+
console.log(
110+
'\nAll external dependencies must use "catalog:" protocol. Add the version to the catalog in pnpm-workspace.yaml and use "catalog:" in package.json.',
111+
);
112+
process.exit(1);
113+
}
114+
115+
console.log("✔ All dependencies are using catalog: or workspace: protocols.");

package.json

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99
"build:all": "pnpm -r --workspace-concurrency=Infinity build",
1010
"check:eng": "tsc -p ./tsconfig.eng.json --noEmit",
1111
"setup:min": "pnpm install && pnpm --filter \"@typespec/prettier-plugin-typespec...\" --filter \"@typespec/tspd...\" run build",
12-
"check-version-mismatch": "syncpack list-mismatches",
12+
"check-catalog": "tsx eng/common/scripts/check-catalog.ts",
1313
"change": "chronus",
1414
"clean": "pnpm -r run clean",
1515
"cspell": "cspell --no-progress .",
1616
"dogfood": "pnpm install && pnpm build && pnpm -r dogfood",
17-
"fix-version-mismatch": "syncpack fix-mismatches",
1817
"format": "prettier . --write",
1918
"format:check": "prettier . --check",
2019
"format:dir": "prettier --write",
@@ -41,46 +40,35 @@
4140
"tsp-integration": "node packages/tsp-integration/cmd/tsp-integration.js"
4241
},
4342
"devDependencies": {
44-
"@chronus/chronus": "^1.3.1",
45-
"@chronus/github": "^1.0.6",
46-
"@chronus/github-pr-commenter": "^1.0.6",
47-
"@eslint/js": "^10.0.1",
48-
"@microsoft/api-extractor": "^7.57.7",
49-
"@octokit/core": "^7.0.6",
50-
"@octokit/plugin-paginate-graphql": "^6.0.0",
51-
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
52-
"@types/micromatch": "^4.0.10",
53-
"@types/node": "~25.5.0",
54-
"@vitest/coverage-v8": "^4.1.0",
55-
"@vitest/eslint-plugin": "^1.6.12",
56-
"c8": "^11.0.0",
57-
"cspell": "^9.7.0",
58-
"eslint": "^10.0.3",
59-
"eslint-plugin-react-hooks": "7.0.1",
60-
"eslint-plugin-unicorn": "^63.0.0",
61-
"micromatch": "^4.0.8",
62-
"picocolors": "~1.1.1",
63-
"playwright": "^1.58.2",
64-
"prettier": "~3.8.1",
65-
"prettier-plugin-astro": "^0.14.1",
66-
"prettier-plugin-organize-imports": "~4.3.0",
67-
"prettier-plugin-sh": "^0.18.0",
68-
"rimraf": "~6.1.3",
69-
"syncpack": "^13.0.3",
70-
"tsx": "^4.21.0",
71-
"typescript": "~5.9.3",
72-
"typescript-eslint": "^8.57.0",
73-
"vitest": "^4.1.0",
74-
"yaml": "~2.8.2"
75-
},
76-
"syncpack": {
77-
"dependencyTypes": [
78-
"dev",
79-
"overrides",
80-
"peer",
81-
"pnpmOverrides",
82-
"prod",
83-
"resolutions"
84-
]
43+
"@chronus/chronus": "catalog:",
44+
"@chronus/github": "catalog:",
45+
"@chronus/github-pr-commenter": "catalog:",
46+
"@eslint/js": "catalog:",
47+
"@microsoft/api-extractor": "catalog:",
48+
"@octokit/core": "catalog:",
49+
"@octokit/plugin-paginate-graphql": "catalog:",
50+
"@octokit/plugin-rest-endpoint-methods": "catalog:",
51+
"@types/micromatch": "catalog:",
52+
"@types/node": "catalog:",
53+
"@vitest/coverage-v8": "catalog:",
54+
"@vitest/eslint-plugin": "catalog:",
55+
"c8": "catalog:",
56+
"cspell": "catalog:",
57+
"eslint": "catalog:",
58+
"eslint-plugin-react-hooks": "catalog:",
59+
"eslint-plugin-unicorn": "catalog:",
60+
"micromatch": "catalog:",
61+
"picocolors": "catalog:",
62+
"playwright": "catalog:",
63+
"prettier": "catalog:",
64+
"prettier-plugin-astro": "catalog:",
65+
"prettier-plugin-organize-imports": "catalog:",
66+
"prettier-plugin-sh": "catalog:",
67+
"rimraf": "catalog:",
68+
"tsx": "catalog:",
69+
"typescript": "catalog:",
70+
"typescript-eslint": "catalog:",
71+
"vitest": "catalog:",
72+
"yaml": "catalog:"
8573
}
8674
}

packages/asset-emitter/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@
4545
"@typespec/compiler": "workspace:^"
4646
},
4747
"devDependencies": {
48-
"@types/node": "~25.5.0",
48+
"@types/node": "catalog:",
4949
"@typespec/compiler": "workspace:^",
50-
"@vitest/coverage-v8": "^4.1.0",
51-
"@vitest/ui": "^4.1.0",
52-
"c8": "^11.0.0",
53-
"rimraf": "~6.1.3",
54-
"typescript": "~5.9.3",
55-
"vitest": "^4.1.0"
50+
"@vitest/coverage-v8": "catalog:",
51+
"@vitest/ui": "catalog:",
52+
"c8": "catalog:",
53+
"rimraf": "catalog:",
54+
"typescript": "catalog:",
55+
"vitest": "catalog:"
5656
}
5757
}

packages/astro-utils/package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,20 @@
2323
"watch": "tsc -p ./tsconfig.build.json --watch"
2424
},
2525
"devDependencies": {
26-
"@types/react": "~19.2.14",
27-
"astro": "^6.0.4"
26+
"@types/react": "catalog:",
27+
"astro": "catalog:"
2828
},
2929
"peerDependencies": {
30-
"astro": "^6.0.4"
30+
"astro": "catalog:"
3131
},
3232
"dependencies": {
33-
"@astrojs/check": "^0.9.7",
34-
"@astrojs/starlight": "^0.38.1",
35-
"@expressive-code/core": "^0.41.7",
33+
"@astrojs/check": "catalog:",
34+
"@astrojs/starlight": "catalog:",
35+
"@expressive-code/core": "catalog:",
3636
"@typespec/playground": "workspace:^",
37-
"astro-expressive-code": "^0.41.7",
38-
"pathe": "^2.0.3",
39-
"react": "~19.2.4",
40-
"typescript": "~5.9.3"
37+
"astro-expressive-code": "catalog:",
38+
"pathe": "catalog:",
39+
"react": "catalog:",
40+
"typescript": "catalog:"
4141
}
4242
}

packages/best-practices/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@
4444
"@typespec/compiler": "workspace:^"
4545
},
4646
"devDependencies": {
47-
"@types/node": "~25.5.0",
47+
"@types/node": "catalog:",
4848
"@typespec/compiler": "workspace:^",
49-
"@vitest/coverage-v8": "^4.1.0",
50-
"@vitest/ui": "^4.1.0",
51-
"c8": "^11.0.0",
52-
"rimraf": "~6.1.3",
53-
"typescript": "~5.9.3",
54-
"vitest": "^4.1.0"
49+
"@vitest/coverage-v8": "catalog:",
50+
"@vitest/ui": "catalog:",
51+
"c8": "catalog:",
52+
"rimraf": "catalog:",
53+
"typescript": "catalog:",
54+
"vitest": "catalog:"
5555
}
5656
}

0 commit comments

Comments
 (0)