diff --git a/.changeset/renovate-385c5da.md b/.changeset/renovate-385c5da.md new file mode 100644 index 000000000..1d6c10e46 --- /dev/null +++ b/.changeset/renovate-385c5da.md @@ -0,0 +1,5 @@ +--- +'counterfact': patch +--- + +Updated dependency `typescript` to `7.0.2`. diff --git a/.changeset/renovate-8bc1dd8.md b/.changeset/renovate-8bc1dd8.md index 057bb03b9..d29bcad3d 100644 --- a/.changeset/renovate-8bc1dd8.md +++ b/.changeset/renovate-8bc1dd8.md @@ -2,4 +2,4 @@ 'counterfact': patch --- -Updated dependency `astro` to `7.0.7`. +Updated dependency `astro` to `7.1.1`. diff --git a/.changeset/renovate-9aff90f.md b/.changeset/renovate-9aff90f.md index 9579b57e9..d29bcad3d 100644 --- a/.changeset/renovate-9aff90f.md +++ b/.changeset/renovate-9aff90f.md @@ -2,4 +2,4 @@ 'counterfact': patch --- -Updated dependency `astro` to `7.1.0`. +Updated dependency `astro` to `7.1.1`. diff --git a/.changeset/renovate-d5034f6.md b/.changeset/renovate-d5034f6.md index 515a33749..64910b3ff 100644 --- a/.changeset/renovate-d5034f6.md +++ b/.changeset/renovate-d5034f6.md @@ -2,4 +2,4 @@ 'counterfact': patch --- -Updated dependency `posthog-node` to `5.41.0`. +Updated dependency `posthog-node` to `5.45.2`. diff --git a/eslint.config.cjs b/eslint.config.cjs index 2a8a34ac8..94dffdba2 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -1,7 +1,40 @@ "use strict"; +const fs = require("fs"); +const Module = require("module"); const path = require("path"); +function resolveCompatibleTypeScriptPath() { + try { + // precinct still installs a TypeScript 6 copy that matches the current + // typescript-eslint peer range, so prefer that compiler for parser internals + // until the eslint stack natively supports TypeScript 7. + return require.resolve("typescript", { + paths: [path.join(__dirname, "node_modules", "precinct", "node_modules")], + }); + } catch { + return undefined; + } +} + +const compatibleTypeScriptPath = resolveCompatibleTypeScriptPath(); +const originalResolveFilename = Module._resolveFilename; + +Module._resolveFilename = function resolveFilename(request, parent, ...rest) { + if ( + request === "typescript" && + compatibleTypeScriptPath !== undefined && + fs.existsSync(compatibleTypeScriptPath) && + ["/@typescript-eslint/", "/ts-api-utils/"].some((segment) => + parent?.filename?.includes(segment.replaceAll("/", path.sep)), + ) + ) { + return compatibleTypeScriptPath; + } + + return originalResolveFilename.call(this, request, parent, ...rest); +}; + const js = require("@eslint/js"); const prettierPlugin = require("eslint-plugin-prettier"); const typescriptParser = require("@typescript-eslint/parser"); diff --git a/package.json b/package.json index ac47ac667..c7299bc1a 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "prettier": "3.8.5", "recast": "0.23.12", "tsx": "4.23.1", - "typescript": "6.0.3" + "typescript": "7.0.2" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e", "resolutions": { diff --git a/src/server/module-dependency-graph.ts b/src/server/module-dependency-graph.ts index 5a1a95629..14c44191b 100644 --- a/src/server/module-dependency-graph.ts +++ b/src/server/module-dependency-graph.ts @@ -1,24 +1,91 @@ +import { readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import createDebug from "debug"; -import precinct from "precinct"; +import { parse } from "recast"; +import typescriptParser from "recast/parsers/typescript.js"; const debug = createDebug("counterfact:server:module-dependency-graph"); +type AstNode = { + type?: unknown; + [key: string]: unknown; +}; + +function isNode(value: unknown): value is AstNode { + return typeof value === "object" && value !== null; +} + +function extractStringLiteral(value: unknown): string | undefined { + return isNode(value) && typeof value.value === "string" + ? value.value + : undefined; +} + +function dependencyIn(node: AstNode): string | undefined { + if ( + node.type === "ImportDeclaration" || + node.type === "ExportAllDeclaration" || + node.type === "ExportNamedDeclaration" || + node.type === "ImportExpression" + ) { + return extractStringLiteral(node.source); + } + + if ( + node.type === "CallExpression" && + isNode(node.callee) && + node.callee.type === "Identifier" && + node.callee.name === "require" && + Array.isArray(node.arguments) + ) { + return extractStringLiteral(node.arguments[0]); + } +} + +function findDependencies(value: unknown, dependencies: Set) { + if (Array.isArray(value)) { + for (const entry of value) { + findDependencies(entry, dependencies); + } + return; + } + + if (!isNode(value)) { + return; + } + + const dependency = dependencyIn(value); + if (dependency !== undefined) { + dependencies.add(dependency); + } + + for (const entry of Object.values(value)) { + findDependencies(entry, dependencies); + } +} + +function dependenciesIn(source: string): string[] { + const dependencies = new Set(); + + findDependencies(parse(source, { parser: typescriptParser }), dependencies); + + return Array.from(dependencies); +} + /** * Tracks which route files depend on shared modules so that when a shared * module changes, all dependent route files can be reloaded. * - * Dependency edges are extracted using [precinct](https://npm.im/precinct)'s - * static analysis and are stored as a reverse map (`dependency → Set`). + * Dependency edges are extracted from the parsed module syntax and are stored + * as a reverse map (`dependency → Set`). */ export class ModuleDependencyGraph { private readonly dependents = new Map>(); private loadDependencies(path: string) { try { - return precinct.paperwork(path); + return dependenciesIn(readFileSync(path, "utf8")); } catch (error) { debug("could not load dependencies for %s: %o", path, error); return []; diff --git a/src/server/module-loader.ts b/src/server/module-loader.ts index c80062a6b..cdcc2d27b 100644 --- a/src/server/module-loader.ts +++ b/src/server/module-loader.ts @@ -5,6 +5,8 @@ import nodePath, { basename } from "node:path"; import { type FSWatcher, watch } from "chokidar"; import createDebug from "debug"; +import { parse } from "recast"; +import typescriptParser from "recast/parsers/typescript.js"; import { CHOKIDAR_OPTIONS } from "./constants.js"; import { ContextRegistry } from "./context-registry.js"; @@ -31,6 +33,10 @@ const { uncachedRequire } = await import("./uncached-require.cjs"); const debug = createDebug("counterfact:server:module-loader"); +async function assertModuleSyntax(pathName: string) { + parse(await fs.readFile(pathName, "utf8"), { parser: typescriptParser }); +} + /** * Watches the compiled routes directory and dynamically loads/reloads route * modules, context files, and middleware as files are added, changed, or @@ -292,10 +298,16 @@ export class ModuleLoader extends EventTarget { : uncachedImport; let importError: unknown; + let endpoint: ContextModule | Module | undefined; - const endpoint = (await doImport(pathName).catch((error: unknown) => { + try { + if (doImport === uncachedImport) { + await assertModuleSyntax(pathName); + } + endpoint = (await doImport(pathName)) as ContextModule | Module; + } catch (error) { importError = error; - })) as ContextModule | Module; + } if (importError !== undefined) { const isSyntaxError = @@ -308,9 +320,7 @@ export class ModuleLoader extends EventTarget { ); if (this.isContextFile(pathName)) { - const warning = isSyntaxError - ? `Warning: There is a syntax error in the context file: ${displayPath}` - : `Warning: There was an error loading the context file: ${displayPath}`; + const warning = `Warning: There was an error loading the context file: ${displayPath}`; process.stdout.write(`\n${warning}\n`); diff --git a/src/server/transpiler.ts b/src/server/transpiler.ts index 49fe09eee..356a57be1 100644 --- a/src/server/transpiler.ts +++ b/src/server/transpiler.ts @@ -1,12 +1,14 @@ // Stryker disable all +import { execFile as execFileCallback } from "node:child_process"; import { once } from "node:events"; import fs from "node:fs/promises"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; /* eslint-disable security/detect-non-literal-fs-filename -- transpiler consumes watched source files and writes paired outputs under configured directories. */ import { type FSWatcher, watch as chokidarWatch } from "chokidar"; import createDebug from "debug"; -import ts from "typescript"; import { ensureDirectoryExists } from "../util/ensure-directory-exists.js"; import { toForwardSlashPath, pathJoin } from "../util/forward-slash-path.js"; @@ -14,10 +16,14 @@ import { CHOKIDAR_OPTIONS } from "./constants.js"; import { convertFileExtensionsToCjs } from "./convert-js-extensions-to-cjs.js"; const debug = createDebug("counterfact:server:transpiler"); +const execFile = promisify(execFileCallback); +const typescriptCompilerPath = fileURLToPath( + new URL("../../node_modules/typescript/lib/tsc.js", import.meta.url), +); /** * Watches TypeScript source files in `sourcePath` and compiles them to - * JavaScript in `destinationPath` using the TypeScript compiler API. + * JavaScript in `destinationPath` using the TypeScript CLI. * * Used when the runtime cannot execute TypeScript natively (i.e. Node.js * without the `--experimental-strip-types` flag). Each file is compiled @@ -121,50 +127,61 @@ export class Transpiler extends EventTarget { await this.watcher?.close(); } + private compiledDestinationPath(sourcePath: string) { + return pathJoin( + sourcePath + .replace(this.sourcePath, this.destinationPath) + .replace(".ts", ".js"), + ); + } + private async transpileFile( eventName: string, sourcePath: string, destinationPath: string, ): Promise { ensureDirectoryExists(destinationPath); + const compiledDestinationPath = this.compiledDestinationPath(sourcePath); - const source = await fs.readFile(sourcePath, "utf8"); - - const transpileOutput = ts.transpileModule(source, { - compilerOptions: { - module: - ts.ModuleKind[ - this.moduleKind.toLowerCase() === "module" ? "ES2022" : "CommonJS" - ], - - target: ts.ScriptTarget.ES2015, - }, - reportDiagnostics: true, - }); + try { + await execFile(process.execPath, [ + typescriptCompilerPath, + "--ignoreConfig", + "--module", + this.moduleKind.toLowerCase() === "module" ? "ES2022" : "CommonJS", + "--target", + "ES2015", + "--outDir", + this.destinationPath, + "--rootDir", + this.sourcePath, + // TypeScript 7's CLI supports --noCheck, which preserves the prior + // transpileModule behavior of skipping type-checking during cache builds. + "--noCheck", + sourcePath, + ]); + } catch (error) { + debug("error transpiling %s after %s: %o", sourcePath, eventName, error); + this.dispatchEvent(new Event("error")); - if (transpileOutput.diagnostics?.length) { - for (const diagnostic of transpileOutput.diagnostics) { - const message = ts.flattenDiagnosticMessageText( - diagnostic.messageText, - "\n", - ); - debug("TypeScript diagnostic in %s: %s", sourcePath, message); - } + throw new Error(`could not transpile ${sourcePath}`, { cause: error }); } - const result: string = transpileOutput.outputText; - const fullDestination = pathJoin( sourcePath .replace(this.sourcePath, this.destinationPath) .replace(".ts", this.extension), ); - const resultWithTransformedFileExtensions = - convertFileExtensionsToCjs(result); + const resultWithTransformedFileExtensions = convertFileExtensionsToCjs( + await fs.readFile(compiledDestinationPath, "utf8"), + ); try { await fs.writeFile(fullDestination, resultWithTransformedFileExtensions); + if (compiledDestinationPath !== fullDestination) { + await fs.rm(compiledDestinationPath); + } } catch (error) { debug( "error writing transpiled output to %s: %o", @@ -173,7 +190,7 @@ export class Transpiler extends EventTarget { ); this.dispatchEvent(new Event("error")); - throw new Error("could not transpile", { cause: error }); + throw new Error(`could not transpile ${sourcePath}`, { cause: error }); } this.dispatchEvent(new Event("write")); diff --git a/yarn.lock b/yarn.lock index dd794364b..21fc92f51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2179,6 +2179,106 @@ "@typescript-eslint/types" "8.65.0" eslint-visitor-keys "^5.0.0" +"@typescript/typescript-aix-ppc64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz#cdc7ce81d60f1e09034960ddfb1fb880d7a776b6" + integrity sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ== + +"@typescript/typescript-darwin-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz#a55fdfcfa58df58d27db2237cde6a5c1e35a7235" + integrity sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA== + +"@typescript/typescript-darwin-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz#38d1c9172800a91d707bec64d2a370a016634db4" + integrity sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA== + +"@typescript/typescript-freebsd-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz#f1ff8810030b35d2b5be0db6a2dc650460ea94fa" + integrity sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ== + +"@typescript/typescript-freebsd-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz#3d86b03f353c5b1ba95162eb6ce35533bfc294bd" + integrity sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw== + +"@typescript/typescript-linux-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz#d9334d96d6dac6ff85da9c865588948de939e91f" + integrity sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ== + +"@typescript/typescript-linux-arm@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz#ad94b41e1aee2a4dcc6a298c7b67c43345fde32e" + integrity sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ== + +"@typescript/typescript-linux-loong64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz#2965aee4fc873360139d893daafe6397a29138ad" + integrity sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ== + +"@typescript/typescript-linux-mips64el@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz#1a887a311bed3a833f80bfd4a9ed37c271936cf0" + integrity sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA== + +"@typescript/typescript-linux-ppc64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz#8b63c9b2f445b393eb4e43ec21da225dade3577d" + integrity sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA== + +"@typescript/typescript-linux-riscv64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz#b6e8a35c289b3ea97a92a41d461aaeed0d3b36e1" + integrity sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ== + +"@typescript/typescript-linux-s390x@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz#2ef96693be4861f6d17965427e5b009cbbed1a3e" + integrity sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw== + +"@typescript/typescript-linux-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz#73269cb0baba50aea0ca060445a6b88e583f1ce2" + integrity sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A== + +"@typescript/typescript-netbsd-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz#3a3649f97fafa210b4e6e3798c15e06605c8a901" + integrity sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA== + +"@typescript/typescript-netbsd-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz#47ec59491a40c470d2807dc4d2b825528fd979ab" + integrity sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA== + +"@typescript/typescript-openbsd-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz#796be8da0bd989d8a3fb96f2801e38a8365b4baf" + integrity sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ== + +"@typescript/typescript-openbsd-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz#d37fe2a729eb942c076c454ee7f1815faf7d560f" + integrity sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg== + +"@typescript/typescript-sunos-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz#aba8d3464c3565a7044789baba96916bd4ab2c88" + integrity sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g== + +"@typescript/typescript-win32-arm64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz#b9de50a17196383f62620b5f9d0a2f34ad3b60d7" + integrity sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ== + +"@typescript/typescript-win32-x64@7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz#cf3b7b0d6ce5635daca4c8e01c189cdcde47ec3c" + integrity sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g== + "@ungap/structured-clone@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" @@ -7902,7 +8002,33 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" -typescript@6.0.3, typescript@^6.0.3: +typescript@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-7.0.2.tgz#9ec773d7954a8c182c17cc5bbd575aa28bc51582" + integrity sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA== + optionalDependencies: + "@typescript/typescript-aix-ppc64" "7.0.2" + "@typescript/typescript-darwin-arm64" "7.0.2" + "@typescript/typescript-darwin-x64" "7.0.2" + "@typescript/typescript-freebsd-arm64" "7.0.2" + "@typescript/typescript-freebsd-x64" "7.0.2" + "@typescript/typescript-linux-arm" "7.0.2" + "@typescript/typescript-linux-arm64" "7.0.2" + "@typescript/typescript-linux-loong64" "7.0.2" + "@typescript/typescript-linux-mips64el" "7.0.2" + "@typescript/typescript-linux-ppc64" "7.0.2" + "@typescript/typescript-linux-riscv64" "7.0.2" + "@typescript/typescript-linux-s390x" "7.0.2" + "@typescript/typescript-linux-x64" "7.0.2" + "@typescript/typescript-netbsd-arm64" "7.0.2" + "@typescript/typescript-netbsd-x64" "7.0.2" + "@typescript/typescript-openbsd-arm64" "7.0.2" + "@typescript/typescript-openbsd-x64" "7.0.2" + "@typescript/typescript-sunos-x64" "7.0.2" + "@typescript/typescript-win32-arm64" "7.0.2" + "@typescript/typescript-win32-x64" "7.0.2" + +typescript@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21" integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==