chore(sse): drop deprecated baseUrl from open-sse tsconfig for TS 7.0 (#8473)

TypeScript 6.x raises TS5101 on `open-sse/tsconfig.json`: `baseUrl` is
deprecated and stops functioning in TypeScript 7.0. It was paired with
`ignoreDeprecations: "5.0"`, which no longer silences it under TS 6 (the
compiler now demands "6.0").

Remove `baseUrl: ".."` and rewrite the `paths` mappings relative to the
tsconfig's own directory, which is how TypeScript resolves them with no
baseUrl set:

  "@/*"                     ./src/*       -> ../src/*
  "@omniroute/open-sse"     ./open-sse    -> ../open-sse
  "@omniroute/open-sse/*"   ./open-sse/*  -> ../open-sse/*

`ignoreDeprecations` goes with it — baseUrl was the only deprecated option
it was suppressing.

Verified by diffing the full tsc error set against the previous config (the
base run used `ignoreDeprecations: "6.0"` so compilation proceeds past the
config error, which otherwise aborts type-checking and masks everything):
zero new errors, 28 fewer. All 28 were in `electron/*.js`, which
`baseUrl: ".."` had been dragging into the open-sse program via
root-relative resolution. Scoping the program back to open-sse also moves
`check:type-coverage` from 92.17% to 94.01%; the ratchet direction is up so
the gate passes, and the baseline is deliberately left alone because the
gain is a measurement-scope change rather than new typing work.

The guard test asserts no tsconfig reintroduces `baseUrl` or
`ignoreDeprecations`, and that every `paths` target still resolves to a real
directory — the second half is the part that matters, since dropping baseUrl
silently changes what those mappings point at.
This commit is contained in:
backryun
2026-07-25 14:53:01 +09:00
committed by GitHub
parent 909642879f
commit 1930b09c6a
3 changed files with 157 additions and 7 deletions

View File

@@ -13,12 +13,10 @@
"strict": false,
"jsx": "react-jsx",
"lib": ["dom", "esnext"],
"ignoreDeprecations": "5.0",
"baseUrl": "..",
"paths": {
"@/*": ["./src/*"],
"@omniroute/open-sse": ["./open-sse"],
"@omniroute/open-sse/*": ["./open-sse/*"]
"@/*": ["../src/*"],
"@omniroute/open-sse": ["../open-sse"],
"@omniroute/open-sse/*": ["../open-sse/*"]
}
},
"include": ["**/*.ts", "**/*.js"]

View File

@@ -11,8 +11,12 @@
// - Rationale: the only tsconfig that covers the full open-sse workspace
// (src+open-sse together). `tsconfig.json` excludes open-sse; the
// `tsconfig.typecheck-core.json` only lists 26 explicit files (partial).
// open-sse/tsconfig.json sets `baseUrl: ".."` and path aliases so it
// resolves both workspaces correctly and yields a representative global %.
// open-sse/tsconfig.json declares path aliases (`@/*`, `@omniroute/open-sse/*`)
// relative to its own directory, so it resolves both workspaces correctly and
// yields a representative global %. It carried a `baseUrl: ".."` until TS 7
// readiness removed it; that also stopped `electron/*.js` from being pulled
// into the program via root-relative resolution, which moved the measured %
// up (~92.2% -> ~94.0%).
//
// Direction: up (% can only improve; ratchet blocks drops once wired into INT).
// Eps: 0.05 (float noise tolerance — type-coverage may vary by ~0.01% between runs).

View File

@@ -0,0 +1,148 @@
/**
* TS 7.0 readiness guard for tsconfig files.
*
* TypeScript 6.x raises `TS5101: Option 'baseUrl' is deprecated and will stop
* functioning in TypeScript 7.0` for any tsconfig that still declares
* `compilerOptions.baseUrl`. The only offender was `open-sse/tsconfig.json`,
* which paired it with `ignoreDeprecations: "5.0"` to silence the warning.
*
* Dropping `baseUrl` changes how `paths` are resolved: without it, every path
* mapping is resolved relative to the directory containing the tsconfig rather
* than relative to `baseUrl`. So asserting "no baseUrl" alone is not enough —
* the mappings have to keep pointing at real directories, or `@/*` and
* `@omniroute/open-sse/*` silently stop resolving. Both halves are asserted here.
*/
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import ts from "typescript";
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
/** Directories that hold generated/vendored copies of tsconfig files. */
const SKIP_DIRS = new Set([
"node_modules",
".build",
".next",
".next-playwright",
".claude",
".git",
"dist",
"dist-electron",
"coverage",
".source",
".tmp",
"_tasks",
"_ideia",
"_mono_repo",
"_references",
]);
function collectTsconfigs(dir: string, found: string[] = []): string[] {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (entry.isDirectory()) {
if (SKIP_DIRS.has(entry.name)) continue;
collectTsconfigs(path.join(dir, entry.name), found);
} else if (/^tsconfig(\..+)?\.json$/.test(entry.name)) {
found.push(path.join(dir, entry.name));
}
}
return found;
}
/**
* tsconfig is JSONC (comments + trailing commas allowed), and glob values like
* `"**/*.ts"` contain `/*` — so a hand-rolled comment stripper corrupts them.
* Use TypeScript's own parser. `extends` is deliberately NOT resolved: each file
* is asserted on what it literally declares.
*/
function readTsconfig(file: string): { compilerOptions?: Record<string, unknown> } {
const { config, error } = ts.readConfigFile(file, (p) => fs.readFileSync(p, "utf8"));
assert.equal(
error,
undefined,
`${path.relative(REPO_ROOT, file)} is not parseable: ${
error && ts.flattenDiagnosticMessageText(error.messageText, " ")
}`
);
return config as { compilerOptions?: Record<string, unknown> };
}
const TSCONFIGS = collectTsconfigs(REPO_ROOT);
test("repo actually has tsconfig files to check", () => {
assert.ok(TSCONFIGS.length > 0, "no tsconfig files discovered — the walker is broken");
});
test("no tsconfig declares the TS 7.0-removed 'baseUrl' option", () => {
const offenders = TSCONFIGS.filter(
(file) => readTsconfig(file).compilerOptions?.baseUrl !== undefined
).map((file) => path.relative(REPO_ROOT, file));
assert.deepEqual(
offenders,
[],
`'baseUrl' is removed in TypeScript 7.0 (TS5101). Drop it and rewrite 'paths' ` +
`relative to the tsconfig's own directory. Offenders: ${offenders.join(", ")}`
);
});
test("no tsconfig needs 'ignoreDeprecations' to silence removed options", () => {
const offenders = TSCONFIGS.filter(
(file) => readTsconfig(file).compilerOptions?.ignoreDeprecations !== undefined
).map((file) => path.relative(REPO_ROOT, file));
assert.deepEqual(
offenders,
[],
`'ignoreDeprecations' only suppresses the symptom — remove the deprecated ` +
`option itself. Offenders: ${offenders.join(", ")}`
);
});
test("every tsconfig 'paths' mapping resolves to a real file or directory", () => {
const broken: string[] = [];
for (const file of TSCONFIGS) {
const compilerOptions = readTsconfig(file).compilerOptions;
const paths = compilerOptions?.paths as Record<string, string[]> | undefined;
if (!paths) continue;
// Without baseUrl, path mappings resolve relative to the tsconfig's directory.
const resolveRoot = path.dirname(file);
for (const [alias, targets] of Object.entries(paths)) {
for (const target of targets) {
// Strip the trailing wildcard segment: "../src/*" -> "../src"
const concrete = target.replace(/\/?\*+$/, "");
const absolute = path.resolve(resolveRoot, concrete);
if (!fs.existsSync(absolute)) {
broken.push(`${path.relative(REPO_ROOT, file)}: "${alias}" -> "${target}"`);
}
}
}
}
assert.deepEqual(
broken,
[],
`path alias targets that do not exist on disk:\n ${broken.join("\n ")}`
);
});
test("open-sse aliases point at the repo-root src/ and open-sse/ directories", () => {
const file = path.join(REPO_ROOT, "open-sse/tsconfig.json");
const paths = readTsconfig(file).compilerOptions?.paths as Record<string, string[]>;
assert.ok(paths, "open-sse/tsconfig.json must keep its path aliases");
const resolveRoot = path.dirname(file);
const resolveAlias = (alias: string) =>
path.resolve(resolveRoot, paths[alias][0].replace(/\/?\*+$/, ""));
assert.equal(resolveAlias("@/*"), path.join(REPO_ROOT, "src"));
assert.equal(resolveAlias("@omniroute/open-sse"), path.join(REPO_ROOT, "open-sse"));
assert.equal(resolveAlias("@omniroute/open-sse/*"), path.join(REPO_ROOT, "open-sse"));
});