diff --git a/README.md b/README.md index e55f98b..ac79c65 100644 --- a/README.md +++ b/README.md @@ -126,10 +126,10 @@ The catalog is generated from the same schema and SDK output as each release. Co ### Build-time source analysis -`@sentry/api/source-analysis` follows references in supplied TypeScript source to discover calls to catalog operations. Install TypeScript only when using this optional build tool; the analyzer is tested with TypeScript 5.9. Its optional peer uses a wildcard so it does not constrain the compiler used by applications that only import the client. +`@sentry/api/source-analysis` follows references in supplied TypeScript source to discover calls to catalog operations. It parses with TypeScript 6's compiler API through `@typescript/typescript6`, since TypeScript 7 no longer ships that API. Install it only when using this optional build tool; the separate package name means it works alongside whichever TypeScript version the project compiles with, including 7. With npm or Bun, its aliased TypeScript 6 dependency is hoisted and its `tsc` bin can replace the project's own in `node_modules/.bin`, so run the project's compiler by path there; pnpm keeps it nested. ```bash -npm install --save-dev @sentry/api typescript@^5.9 +npm install --save-dev @sentry/api @typescript/typescript6 ``` ```ts diff --git a/build.mjs b/build.mjs index f818921..713c956 100644 --- a/build.mjs +++ b/build.mjs @@ -95,5 +95,7 @@ execSync('bun build src/valibot.ts --outdir dist --external valibot', { stdio: " execSync('bun build src/zod.ts --outdir dist --external zod', { stdio: "inherit" }); execSync("bun build src/browser.ts --outdir dist", { stdio: "inherit" }); execSync("bun build src/operations.ts --outdir dist", { stdio: "inherit" }); -execSync("bun build src/source-analysis.ts --outdir dist --external typescript", { stdio: "inherit" }); -execSync("tsc --emitDeclarationOnly", { stdio: "inherit" }); +execSync("bun build src/source-analysis.ts --outdir dist --external @typescript/typescript6", { stdio: "inherit" }); +// @typescript/typescript6 depends on TypeScript 6 under an alias that also +// installs a `tsc` bin, so run this repo's own compiler by path. +execSync("node node_modules/typescript/bin/tsc --emitDeclarationOnly", { stdio: "inherit" }); diff --git a/bun.lock b/bun.lock index ee3d156..a85930b 100644 --- a/bun.lock +++ b/bun.lock @@ -8,17 +8,18 @@ "@hey-api/openapi-ts": "0.91.1", "@types/bun": "^1.3.13", "@types/node": "^22", + "@typescript/typescript6": "^6.0.2", "typescript": "^5.9.3", "valibot": "^1.4.2", "zod": "^3.24.0", }, "peerDependencies": { - "typescript": "*", + "@typescript/typescript6": "^6.0.2", "valibot": "*", "zod": "^3.24.0", }, "optionalPeers": [ - "typescript", + "@typescript/typescript6", "valibot", "zod", ], @@ -43,6 +44,10 @@ "@types/node": ["@types/node@22.19.8", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ebO/Yl+EAvVe8DnMfi+iaAyIqYdK0q/q0y0rw82INWEKJOBe6b/P3YWE8NW7oOlF/nXFNrHwhARrN/hdgDkraA=="], + "@typescript/old": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "@typescript/typescript6": ["@typescript/typescript6@6.0.2", "", { "dependencies": { "@typescript/old": "npm:typescript@^6" }, "bin": { "tsc6": "bin/tsc6" } }, "sha512-mbCddXd+jm7hfx7w2YU64/Av4/NqqeG3GoRZgxPcgoTxYjhrcfJRw9ULch71SS4G+Q3bOXFhRvPqjguN0Hyp5w=="], + "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], diff --git a/lib/source-analysis.ts b/lib/source-analysis.ts index 8f8d171..16e8952 100644 --- a/lib/source-analysis.ts +++ b/lib/source-analysis.ts @@ -1,7 +1,9 @@ /** Build-time analysis of API usage in consumer-supplied TypeScript source. */ import { dirname, posix } from "node:path"; -import ts from "typescript"; +// TypeScript 7 no longer ships the JavaScript compiler API, so load the +// TypeScript 6 one under its own name instead of the consumer's `typescript`. +import ts from "@typescript/typescript6"; import type { ApiOperation } from "./operation-types.js"; /** Identity supplied by the generated SDK operation catalog. */ diff --git a/package.json b/package.json index ec32662..32a0653 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "build": "node build.mjs", "test": "bun test", "test:node": "node --test test/node-cancellation.mjs", - "typecheck": "tsc -p tsconfig.test.json" + "typecheck": "node node_modules/typescript/bin/tsc -p tsconfig.test.json" }, "exports": { ".": { @@ -60,12 +60,12 @@ "url": "https://github.com/getsentry/sentry-api-schema/issues" }, "peerDependencies": { - "typescript": "*", + "@typescript/typescript6": "^6.0.2", "valibot": "*", "zod": "^3.24.0" }, "peerDependenciesMeta": { - "typescript": { + "@typescript/typescript6": { "optional": true }, "valibot": { @@ -79,6 +79,7 @@ "@hey-api/openapi-ts": "0.91.1", "@types/bun": "^1.3.13", "@types/node": "^22", + "@typescript/typescript6": "^6.0.2", "typescript": "^5.9.3", "valibot": "^1.4.2", "zod": "^3.24.0" diff --git a/test/package.test.ts b/test/package.test.ts index e80947a..3ddf7c4 100644 --- a/test/package.test.ts +++ b/test/package.test.ts @@ -12,12 +12,12 @@ const readBundle = (name: string) => describe("package entry points", () => { test("keeps validator and source-analysis peers optional", () => { expect(packageJson.peerDependencies).toEqual({ - typescript: "*", + "@typescript/typescript6": "^6.0.2", valibot: "*", zod: "^3.24.0", }); expect(packageJson.peerDependenciesMeta).toEqual({ - typescript: { optional: true }, + "@typescript/typescript6": { optional: true }, valibot: { optional: true }, zod: { optional: true }, }); @@ -25,7 +25,7 @@ describe("package entry points", () => { test("keeps the root bundle independent from optional tools and validators", async () => { const root = await readBundle("index"); - expect(root).not.toMatch(/from ["']typescript["']/); + expect(root).not.toMatch(/from ["'](?:typescript|@typescript\/typescript6)["']/); expect(root).not.toMatch(/from ["']valibot["']/); expect(root).not.toMatch(/from ["']zod["']/); }); @@ -40,8 +40,8 @@ describe("package entry points", () => { expect(valibot).not.toMatch(/from ["']zod["']/); expect(zod).toMatch(/from ["']zod["']/); expect(zod).not.toMatch(/from ["']valibot["']/); - expect(analysis).toMatch(/from ["']typescript["']/); - expect(analysis).not.toMatch(/from ["'](?:valibot|zod)["']/); + expect(analysis).toMatch(/from ["']@typescript\/typescript6["']/); + expect(analysis).not.toMatch(/from ["'](?:typescript|valibot|zod)["']/); }); test("packs isolated runtime entries, pagination and build-time analysis", () => { @@ -138,7 +138,12 @@ describe("package entry points", () => { })); execFileSync("node", [join(root, "node_modules", "typescript", "bin", "tsc"), "-p", directory]); - symlinkSync(join(root, "node_modules", "typescript"), join(directory, "node_modules", "typescript"), "dir"); + mkdirSync(join(directory, "node_modules", "@typescript"), { recursive: true }); + symlinkSync( + join(root, "node_modules", "@typescript", "typescript6"), + join(directory, "node_modules", "@typescript", "typescript6"), + "dir", + ); writeFileSync(join(directory, "analysis.mjs"), ` import assert from "node:assert/strict"; import { operations } from "@sentry/api/operations";