mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
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:
@@ -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"]
|
||||
|
||||
@@ -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).
|
||||
|
||||
148
tests/unit/tsconfig-ts7-readiness.test.ts
Normal file
148
tests/unit/tsconfig-ts7-readiness.test.ts
Normal 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"));
|
||||
});
|
||||
Reference in New Issue
Block a user