From 330a9275c3abe673c2283b3c73ff4f7a7c9b9045 Mon Sep 17 00:00:00 2001 From: ocavue Date: Tue, 21 Apr 2026 20:17:07 +1000 Subject: [PATCH 01/12] refactor(astro): replace tsconfck with get-tsconfig --- .../replace-tsconfck-with-get-tsconfig.md | 6 + packages/astro/package.json | 3 +- packages/astro/src/cli/add/index.ts | 9 +- packages/astro/src/core/config/index.ts | 7 +- packages/astro/src/core/config/settings.ts | 6 +- packages/astro/src/core/config/tsconfig.ts | 157 +++++++++--------- .../tsconfig-handling/extends-array/a.json | 3 + .../tsconfig-handling/extends-array/b.json | 3 + .../extends-array/tsconfig.json | 4 + .../extends-chain/grandparent.json | 3 + .../extends-chain/parent.json | 4 + .../extends-chain/tsconfig.json | 4 + .../test/units/config/config-tsconfig.test.ts | 48 ++++-- pnpm-lock.yaml | 45 +++-- scripts/package.json | 4 +- scripts/smoke/check.js | 4 +- 16 files changed, 185 insertions(+), 125 deletions(-) create mode 100644 .changeset/replace-tsconfck-with-get-tsconfig.md create mode 100644 packages/astro/test/fixtures/tsconfig-handling/extends-array/a.json create mode 100644 packages/astro/test/fixtures/tsconfig-handling/extends-array/b.json create mode 100644 packages/astro/test/fixtures/tsconfig-handling/extends-array/tsconfig.json create mode 100644 packages/astro/test/fixtures/tsconfig-handling/extends-chain/grandparent.json create mode 100644 packages/astro/test/fixtures/tsconfig-handling/extends-chain/parent.json create mode 100644 packages/astro/test/fixtures/tsconfig-handling/extends-chain/tsconfig.json diff --git a/.changeset/replace-tsconfck-with-get-tsconfig.md b/.changeset/replace-tsconfck-with-get-tsconfig.md new file mode 100644 index 000000000000..1603c9a07caa --- /dev/null +++ b/.changeset/replace-tsconfck-with-get-tsconfig.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'astro-scripts': patch +--- + +Replaces the discontinued `tsconfck` dependency with `get-tsconfig` and `jsonc-parser`. This is an internal infrastructure change with no public API change. diff --git a/packages/astro/package.json b/packages/astro/package.json index f7f31951a4a7..078e14912230 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -141,10 +141,12 @@ "esbuild": "^0.27.3", "flattie": "^1.1.1", "fontace": "~0.4.1", + "get-tsconfig": "5.0.0-beta.4", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", + "jsonc-parser": "^3.3.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mrmime": "^2.0.1", @@ -163,7 +165,6 @@ "tinyclip": "^0.1.12", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", - "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.7.4", "unist-util-visit": "^5.1.0", diff --git a/packages/astro/src/cli/add/index.ts b/packages/astro/src/cli/add/index.ts index 1f716b43b08f..a09c9fd90550 100644 --- a/packages/astro/src/cli/add/index.ts +++ b/packages/astro/src/cli/add/index.ts @@ -1089,14 +1089,17 @@ async function updateTSConfig( let inputConfig = await loadTSConfig(cwd); let inputConfigText = ''; - if (inputConfig === 'invalid-config' || inputConfig === 'unknown-error') { + if (inputConfig.error === 'invalid-config') { + logger.warn(`add`, `Couldn't parse tsconfig.json or jsconfig.json: ${inputConfig.message}`); return 'failure'; - } else if (inputConfig === 'missing-config') { + } else if (inputConfig.error === 'missing-config') { logger.debug('add', "Couldn't find tsconfig.json or jsconfig.json, generating one"); + const tsconfigFile = path.join(cwd, 'tsconfig.json'); inputConfig = { tsconfig: defaultTSConfig, - tsconfigFile: path.join(cwd, 'tsconfig.json'), + tsconfigFile: tsconfigFile, rawConfig: defaultTSConfig, + sources: [tsconfigFile], }; } else { inputConfigText = JSON.stringify(inputConfig.rawConfig, null, 2); diff --git a/packages/astro/src/core/config/index.ts b/packages/astro/src/core/config/index.ts index 269be68bf97b..3698e429ae4e 100644 --- a/packages/astro/src/core/config/index.ts +++ b/packages/astro/src/core/config/index.ts @@ -5,4 +5,9 @@ export { } from './config.js'; export { mergeConfig } from './merge.js'; export { createSettings } from './settings.js'; -export { loadTSConfig, updateTSConfigForFramework } from './tsconfig.js'; +export { + loadTSConfig, + updateTSConfigForFramework, + type TSConfigLoadedResult, + type TSConfigResult, +} from './tsconfig.js'; diff --git a/packages/astro/src/core/config/settings.ts b/packages/astro/src/core/config/settings.ts index c672d0c84d55..52c767711a74 100644 --- a/packages/astro/src/core/config/settings.ts +++ b/packages/astro/src/core/config/settings.ts @@ -177,10 +177,8 @@ export async function createSettings( watchFiles.push(fileURLToPath(new URL('./package.json', pathToFileURL(cwd)))); } - if (typeof tsconfig !== 'string') { - watchFiles.push( - ...[tsconfig.tsconfigFile, ...(tsconfig.extended ?? []).map((e) => e.tsconfigFile)], - ); + if (!tsconfig.error) { + watchFiles.push(...tsconfig.sources); settings.tsConfig = tsconfig.tsconfig; settings.tsConfigPath = tsconfig.tsconfigFile; } diff --git a/packages/astro/src/core/config/tsconfig.ts b/packages/astro/src/core/config/tsconfig.ts index ed28b9a931d0..0e495de7ca5d 100644 --- a/packages/astro/src/core/config/tsconfig.ts +++ b/packages/astro/src/core/config/tsconfig.ts @@ -1,13 +1,7 @@ -import { readFile } from 'node:fs/promises'; -import { join } from 'node:path'; -import { - find, - parse, - TSConfckParseError, - type TSConfckParseOptions, - type TSConfckParseResult, - toJson, -} from 'tsconfck'; +import { readFileSync, existsSync } from 'node:fs'; +import { join, normalize } from 'node:path'; +import { readTsconfig, type TsconfigResult } from 'get-tsconfig'; +import { parse as parseJsonc, type ParseError } from 'jsonc-parser'; import type { CompilerOptions, TypeAcquisition } from 'typescript'; export const defaultTSConfig: TSConfig = { extends: 'astro/tsconfigs/base' }; @@ -53,81 +47,94 @@ export const presets = new Map([ ], ]); -type TSConfigResult = Promise< - (TSConfckParseResult & T) | 'invalid-config' | 'missing-config' | 'unknown-error' ->; +export interface TSConfigLoadedResult { + error?: undefined; + /** Absolute path of the root tsconfig/jsconfig file that was loaded. */ + tsconfigFile: string; + /** The merged/resolved config (after `extends` are walked). */ + tsconfig: TSConfig; + /** The user-written, un-merged config. Used by `astro add` to round-trip. */ + rawConfig: TSConfig; + /** + * Every tsconfig file that contributed via `extends`, root-first. + * Includes `tsconfigFile`. Used to populate the dev-server watch list. + */ + sources: string[]; +} + +export type TSConfigResult = + | TSConfigLoadedResult + | { error: 'invalid-config'; message: string } + | { error: 'missing-config' }; /** - * Load a tsconfig.json or jsconfig.json is the former is not found - * @param root The root directory to search in, defaults to `process.cwd()`. - * @param findUp Whether to search for the config file in parent directories, by default only the root directory is searched. + * Load a tsconfig.json or jsconfig.json if the former is not found. + * @param root The directory to search in, defaults to `process.cwd()`. */ -export async function loadTSConfig( - root: string | undefined, - findUp = false, -): Promise> { - const safeCwd = root ?? process.cwd(); - - const [jsconfig, tsconfig] = await Promise.all( - ['jsconfig.json', 'tsconfig.json'].map((configName) => - // `tsconfck` expects its first argument to be a file path, not a directory path, so we'll fake one - find(join(safeCwd, './dummy.txt'), { - root: findUp ? undefined : root, - configName: configName, - }), - ), - ); - - // If we have both files, prefer tsconfig.json - if (tsconfig) { - const parsedConfig = await safeParse(tsconfig, { root: root }); - - if (typeof parsedConfig === 'string') { - return parsedConfig; - } - - // tsconfck does not return the original config, so we need to parse it ourselves - // https://github.com/dominikg/tsconfck/issues/138 - const rawConfig = await readFile(tsconfig, 'utf-8') - .then(toJson) - .then((content) => JSON.parse(content) as TSConfig); - - return { ...parsedConfig, rawConfig }; +export async function loadTSConfig(root: string | undefined): Promise { + const safeCwd = root || process.cwd(); + let tsconfigPath: string | undefined; + + // Find the json file path. Prefer tsconfig.json over jsconfig.json. + for (const configName of ['tsconfig.json', 'jsconfig.json']) { + const possiblePath = join(safeCwd, configName); + if (existsSync(possiblePath)) { + tsconfigPath = possiblePath; + break; + } } - - if (jsconfig) { - const parsedConfig = await safeParse(jsconfig, { root: root }); - - if (typeof parsedConfig === 'string') { - return parsedConfig; - } - - const rawConfig = await readFile(jsconfig, 'utf-8') - .then(toJson) - .then((content) => JSON.parse(content) as TSConfig); - - return { ...parsedConfig, rawConfig: rawConfig }; + if (!tsconfigPath) { + return { + error: 'missing-config', + }; } - return 'missing-config'; -} - -async function safeParse(tsconfigPath: string, options: TSConfckParseOptions = {}): TSConfigResult { + // Read the raw json file + let rawConfig: TSConfig | undefined; try { - const parseResult = await parse(tsconfigPath, options); - - if (parseResult.tsconfig == null) { - return 'missing-config'; + const text = readFileSync(tsconfigPath, 'utf-8'); + const errors: ParseError[] = []; + const parsed = parseJsonc(text, errors, { allowTrailingComma: true }) as TSConfig; + if (errors.length > 0) { + const first = errors[0]; + return { + error: 'invalid-config', + message: `Failed to parse ${tsconfigPath}: Malformed JSONC (error code ${first.error}) at offset ${first.offset}`, + }; } - - return parseResult; + rawConfig = parsed; } catch (e) { - if (e instanceof TSConfckParseError) { - return 'invalid-config'; - } + const message = e instanceof Error ? e.message : String(e); + return { + error: 'invalid-config', + message: `Failed to parse ${tsconfigPath}: ${message}`, + }; + } + if (!rawConfig) { + return { + error: 'invalid-config', + message: `Failed to parse ${tsconfigPath}: Unknown error`, + }; + } - return 'unknown-error'; + // Resolve the tsconfig via `extends` + let resolved: TsconfigResult | undefined; + try { + resolved = readTsconfig(tsconfigPath); + } catch (e) { + const message = e instanceof Error ? e.message : String(e); + return { + error: 'invalid-config', + message: `Failed to resolve ${tsconfigPath}: ${message}`, + }; } + + return { + tsconfigFile: normalize(resolved.path), + tsconfig: resolved.config satisfies TSConfig, + rawConfig, + sources: (resolved.sources || [resolved.path]).map(normalize), + }; } export function updateTSConfigForFramework( @@ -186,7 +193,7 @@ type StripEnums> = { export interface TSConfig { compilerOptions?: StripEnums; compileOnSave?: boolean; - extends?: string; + extends?: string | string[]; files?: string[]; include?: string[]; exclude?: string[]; diff --git a/packages/astro/test/fixtures/tsconfig-handling/extends-array/a.json b/packages/astro/test/fixtures/tsconfig-handling/extends-array/a.json new file mode 100644 index 000000000000..26f214064a91 --- /dev/null +++ b/packages/astro/test/fixtures/tsconfig-handling/extends-array/a.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": { "strict": true } +} diff --git a/packages/astro/test/fixtures/tsconfig-handling/extends-array/b.json b/packages/astro/test/fixtures/tsconfig-handling/extends-array/b.json new file mode 100644 index 000000000000..9702c26820a9 --- /dev/null +++ b/packages/astro/test/fixtures/tsconfig-handling/extends-array/b.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": { "target": "es2022" } +} diff --git a/packages/astro/test/fixtures/tsconfig-handling/extends-array/tsconfig.json b/packages/astro/test/fixtures/tsconfig-handling/extends-array/tsconfig.json new file mode 100644 index 000000000000..a351928b8fec --- /dev/null +++ b/packages/astro/test/fixtures/tsconfig-handling/extends-array/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": ["./a.json", "./b.json"], + "files": ["own"] +} diff --git a/packages/astro/test/fixtures/tsconfig-handling/extends-chain/grandparent.json b/packages/astro/test/fixtures/tsconfig-handling/extends-chain/grandparent.json new file mode 100644 index 000000000000..26f214064a91 --- /dev/null +++ b/packages/astro/test/fixtures/tsconfig-handling/extends-chain/grandparent.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": { "strict": true } +} diff --git a/packages/astro/test/fixtures/tsconfig-handling/extends-chain/parent.json b/packages/astro/test/fixtures/tsconfig-handling/extends-chain/parent.json new file mode 100644 index 000000000000..0ba1fca07da1 --- /dev/null +++ b/packages/astro/test/fixtures/tsconfig-handling/extends-chain/parent.json @@ -0,0 +1,4 @@ +{ + "extends": "./grandparent.json", + "include": ["lib"] +} diff --git a/packages/astro/test/fixtures/tsconfig-handling/extends-chain/tsconfig.json b/packages/astro/test/fixtures/tsconfig-handling/extends-chain/tsconfig.json new file mode 100644 index 000000000000..87ee10bd6f3d --- /dev/null +++ b/packages/astro/test/fixtures/tsconfig-handling/extends-chain/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "./parent.json", + "files": ["child"] +} diff --git a/packages/astro/test/units/config/config-tsconfig.test.ts b/packages/astro/test/units/config/config-tsconfig.test.ts index e85e51ef7a38..b3e622768b8a 100644 --- a/packages/astro/test/units/config/config-tsconfig.test.ts +++ b/packages/astro/test/units/config/config-tsconfig.test.ts @@ -3,17 +3,20 @@ import { readFile } from 'node:fs/promises'; import * as path from 'node:path'; import { describe, it } from 'node:test'; import { fileURLToPath } from 'node:url'; -import { toJson } from 'tsconfck'; -import { loadTSConfig, updateTSConfigForFramework } from '../../../dist/core/config/index.js'; +import { parse as parseJsonc } from 'jsonc-parser'; +import { + loadTSConfig, + updateTSConfigForFramework, + type TSConfigLoadedResult, + type TSConfigResult, +} from '../../../dist/core/config/index.js'; import type { frameworkWithTSSettings } from '../../../dist/core/config/tsconfig.js'; const cwd = fileURLToPath(new URL('../../fixtures/tsconfig-handling/', import.meta.url)); /** Assert that loadTSConfig returned a valid result (not an error string). */ -function assertValidConfig( - config: Awaited>, -): asserts config is Exclude { - assert.ok(typeof config !== 'string', `Expected a valid config but got error: ${config}`); +function assertValidConfig(config: TSConfigResult): asserts config is TSConfigLoadedResult { + assert.ok(!config.error, `Expected a valid config but got error: ${JSON.stringify(config)}`); } describe('TSConfig handling', () => { @@ -27,33 +30,52 @@ describe('TSConfig handling', () => { const config = await loadTSConfig(cwd); assertValidConfig(config); assert.equal(config.tsconfigFile, path.join(cwd, 'tsconfig.json')); - assert.deepEqual(config.tsconfig.files, ['im-a-test']); + assert.deepEqual(config.tsconfig.files, ['./im-a-test']); }); it('can fall back to jsconfig.json if tsconfig.json does not exist', async () => { const config = await loadTSConfig(path.join(cwd, 'jsconfig')); assertValidConfig(config); assert.equal(config.tsconfigFile, path.join(cwd, 'jsconfig', 'jsconfig.json')); - assert.deepEqual(config.tsconfig.files, ['im-a-test-js']); + assert.deepEqual(config.tsconfig.files, ['./im-a-test-js']); }); it('properly return errors when not resolving', async () => { const invalidConfig = await loadTSConfig(path.join(cwd, 'invalid')); const missingConfig = await loadTSConfig(path.join(cwd, 'missing')); - assert.equal(invalidConfig, 'invalid-config'); - assert.equal(missingConfig, 'missing-config'); + assert.equal(invalidConfig.error, 'invalid-config'); + assert.equal(missingConfig.error, 'missing-config'); }); it('does not change baseUrl in raw config', async () => { const loadedConfig = await loadTSConfig(path.join(cwd, 'baseUrl')); assertValidConfig(loadedConfig); - const rawConfig = await readFile(path.join(cwd, 'baseUrl', 'tsconfig.json'), 'utf-8') - .then(toJson) - .then((content) => JSON.parse(content)); + const rawContent = await readFile(path.join(cwd, 'baseUrl', 'tsconfig.json'), 'utf-8'); + const rawConfig = parseJsonc(rawContent, [], { allowTrailingComma: true }); assert.deepEqual(loadedConfig.rawConfig, rawConfig); }); + + it('populates `sources` with the full extends chain, root first', async () => { + const dir = path.join(cwd, 'extends-chain'); + const config = await loadTSConfig(dir); + assertValidConfig(config); + assert.equal(config.sources.length, 3); + assert.ok(config.sources[0].endsWith('tsconfig.json')); + assert.ok(config.sources.some((p) => p.endsWith('parent.json'))); + assert.ok(config.sources.some((p) => p.endsWith('grandparent.json'))); + }); + + it('resolves extends array form (TS 5.0+)', async () => { + const dir = path.join(cwd, 'extends-array'); + const config = await loadTSConfig(dir); + assertValidConfig(config); + assert.equal(config.tsconfig.compilerOptions?.strict, true); + assert.equal(config.tsconfig.compilerOptions?.target, 'es2022'); + assert.deepEqual(config.tsconfig.files, ['./own']); + assert.equal(config.sources.length, 3); + }); }); describe('tsconfig / jsconfig updates', () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79f4ab078724..9786b2ef1301 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -573,6 +573,9 @@ importers: fontace: specifier: ~0.4.1 version: 0.4.1 + get-tsconfig: + specifier: 5.0.0-beta.4 + version: 5.0.0-beta.4 github-slugger: specifier: ^2.0.0 version: 2.0.0 @@ -585,6 +588,9 @@ importers: js-yaml: specifier: ^4.1.1 version: 4.1.1 + jsonc-parser: + specifier: ^3.3.1 + version: 3.3.1 magic-string: specifier: ^0.30.21 version: 0.30.21 @@ -639,9 +645,6 @@ importers: tinyglobby: specifier: ^0.2.15 version: 0.2.16 - tsconfck: - specifier: ^3.1.6 - version: 3.1.6(typescript@5.9.3) ultrahtml: specifier: ^1.6.0 version: 1.6.0 @@ -6950,6 +6953,9 @@ importers: esbuild: specifier: ^0.27.3 version: 0.27.3 + jsonc-parser: + specifier: ^3.3.1 + version: 3.3.1 p-limit: specifier: ^7.3.0 version: 7.3.0 @@ -6959,9 +6965,6 @@ importers: tinyglobby: specifier: ^0.2.15 version: 0.2.16 - tsconfck: - specifier: ^3.1.6 - version: 3.1.6(typescript@5.9.3) packages: @@ -12116,8 +12119,12 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} - get-tsconfig@4.13.6: - resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + get-tsconfig@5.0.0-beta.4: + resolution: {integrity: sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==} + engines: {node: '>=20.20.0'} github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -14961,16 +14968,6 @@ packages: peerDependencies: typescript: '>=4.8.4' - tsconfck@3.1.6: - resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -21327,7 +21324,11 @@ snapshots: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 - get-tsconfig@4.13.6: + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + get-tsconfig@5.0.0-beta.4: dependencies: resolve-pkg-maps: 1.0.0 @@ -24868,16 +24869,12 @@ snapshots: dependencies: typescript: 5.9.3 - tsconfck@3.1.6(typescript@5.9.3): - optionalDependencies: - typescript: 5.9.3 - tslib@2.8.1: {} tsx@4.21.0: dependencies: esbuild: 0.27.3 - get-tsconfig: 4.13.6 + get-tsconfig: 4.14.0 optionalDependencies: fsevents: 2.3.3 diff --git a/scripts/package.json b/scripts/package.json index 64c2858e9534..22bd2e075d0e 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -11,7 +11,7 @@ "esbuild": "^0.27.3", "p-limit": "^7.3.0", "piccolore": "^0.1.3", - "tinyglobby": "^0.2.15", - "tsconfck": "^3.1.6" + "jsonc-parser": "^3.3.1", + "tinyglobby": "^0.2.15" } } diff --git a/scripts/smoke/check.js b/scripts/smoke/check.js index 1f199aac21a1..898ab35f8b0e 100644 --- a/scripts/smoke/check.js +++ b/scripts/smoke/check.js @@ -3,8 +3,8 @@ import { spawn } from 'node:child_process'; import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; import * as path from 'node:path'; +import { parse as parseJsonc } from 'jsonc-parser'; import pLimit from 'p-limit'; -import { toJson } from 'tsconfck'; const skippedExamples = ['toolbar-app', 'component', 'server-islands']; @@ -73,7 +73,7 @@ function prepareExample(examplePath) { if (!existsSync(tsconfigPath)) return const originalConfig = readFileSync(tsconfigPath, 'utf-8'); - const tsconfig = JSON.parse(toJson(originalConfig)); + const tsconfig = parseJsonc(originalConfig, [], { allowTrailingComma: true }); // Swap to strictest config to make sure it also passes tsconfig.extends = 'astro/tsconfigs/strictest'; From c3814c85a92e9b30e1d6d24110b27e5ee80354f6 Mon Sep 17 00:00:00 2001 From: ocavue Date: Tue, 21 Apr 2026 20:59:06 +1000 Subject: [PATCH 02/12] chore: trigger ci From 423260adc88d1099f0405a34707a6d7dced5f249 Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 23 Apr 2026 09:06:32 +1000 Subject: [PATCH 03/12] Delete replace-tsconfck-with-get-tsconfig.md --- .changeset/replace-tsconfck-with-get-tsconfig.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .changeset/replace-tsconfck-with-get-tsconfig.md diff --git a/.changeset/replace-tsconfck-with-get-tsconfig.md b/.changeset/replace-tsconfck-with-get-tsconfig.md deleted file mode 100644 index 1603c9a07caa..000000000000 --- a/.changeset/replace-tsconfck-with-get-tsconfig.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'astro': patch -'astro-scripts': patch ---- - -Replaces the discontinued `tsconfck` dependency with `get-tsconfig` and `jsonc-parser`. This is an internal infrastructure change with no public API change. From 3493012231e34e8115d0c55b2b54609a907fb517 Mon Sep 17 00:00:00 2001 From: ocavue Date: Wed, 29 Apr 2026 23:24:39 +1000 Subject: [PATCH 04/12] chore: trigger ci From e241595fae70cb32c7a1a7a74e610d712a769066 Mon Sep 17 00:00:00 2001 From: ocavue Date: Wed, 29 Apr 2026 23:57:33 +1000 Subject: [PATCH 05/12] chore: trigger ci From 146c3d4a3f76713d711a35cf6e5505b675e91b05 Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 30 Apr 2026 00:18:17 +1000 Subject: [PATCH 06/12] chore: trigger ci From 450e1376c87089fb1492c6ca4698efdc6f3be1be Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 30 Apr 2026 00:49:26 +1000 Subject: [PATCH 07/12] chore: trigger ci From 4497a69ade8daf052638ef12f8b03583a8180514 Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 30 Apr 2026 12:48:15 +1000 Subject: [PATCH 08/12] add debug log --- packages/astro/src/core/config/tsconfig.ts | 8 ++++---- .../test/compile-image-service.test.ts | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/astro/src/core/config/tsconfig.ts b/packages/astro/src/core/config/tsconfig.ts index 0e495de7ca5d..0e29495c135e 100644 --- a/packages/astro/src/core/config/tsconfig.ts +++ b/packages/astro/src/core/config/tsconfig.ts @@ -76,12 +76,12 @@ export async function loadTSConfig(root: string | undefined): Promise { }); describe('dev', () => { - let devServer: DevServer; + let devServer: DevServer | undefined; before(async () => { - devServer = await fixture.startDevServer(); + try { + devServer = await fixture.startDevServer(); + } catch (error) { + console.error('Error starting dev server:', error); + throw error; + } }); after(async () => { - await devServer.stop(); + try { + if (devServer) { + await devServer.stop(); + } + } catch (error) { + console.error('Error stopping dev server:', error); + throw error; + } }); // In dev, the compile service falls back to passthrough because sharp cannot run in workerd. Images are served unoptimized From dd54ece88c5f5113123763fe9b4ee5bbc9a6143b Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 30 Apr 2026 13:36:24 +1000 Subject: [PATCH 09/12] debug --- .../cloudflare/test/compile-image-service.test.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/integrations/cloudflare/test/compile-image-service.test.ts b/packages/integrations/cloudflare/test/compile-image-service.test.ts index 55f11f1e5ac4..cefee3086355 100644 --- a/packages/integrations/cloudflare/test/compile-image-service.test.ts +++ b/packages/integrations/cloudflare/test/compile-image-service.test.ts @@ -36,7 +36,14 @@ describe('CompileImageService', () => { // In dev, the compile service falls back to passthrough because sharp cannot run in workerd. Images are served unoptimized // through the /_image endpoint. it('returns 200 for local images via /_image endpoint', async () => { - const html = await fixture.fetch('/blog/post').then((res) => res.text()); + let html = ''; + + try { + html = await fixture.fetch('/blog/post').then((res) => res.text()); + } catch (error) { + console.error('Error getting html:', error); + throw error; + } const $ = cheerio.load(html); const src = $('img').attr('src')!; assert.ok( From 136bc943af01bb22b9860771920d0d4a1d2a0dfc Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 30 Apr 2026 13:40:40 +1000 Subject: [PATCH 10/12] add more debug log --- .../cloudflare/test/compile-image-service.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/integrations/cloudflare/test/compile-image-service.test.ts b/packages/integrations/cloudflare/test/compile-image-service.test.ts index cefee3086355..3feed2415b9b 100644 --- a/packages/integrations/cloudflare/test/compile-image-service.test.ts +++ b/packages/integrations/cloudflare/test/compile-image-service.test.ts @@ -6,16 +6,26 @@ import { type DevServer, type Fixture, loadFixture, type PreviewServer } from '. describe('CompileImageService', () => { let fixture: Fixture; before(async () => { + console.warn('='.repeat(70)); + console.warn("Starting loadFixture './fixtures/compile-image-service/'"); + fixture = await loadFixture({ root: './fixtures/compile-image-service/', }); + + console.warn("Finish loadFixture './fixtures/compile-image-service/'"); + console.warn('='.repeat(70)); }); describe('dev', () => { let devServer: DevServer | undefined; before(async () => { try { + console.warn('='.repeat(70)); + console.warn('Starting startDevServer'); devServer = await fixture.startDevServer(); + console.warn('Finish startDevServer'); + console.warn('='.repeat(70)); } catch (error) { console.error('Error starting dev server:', error); throw error; @@ -39,7 +49,11 @@ describe('CompileImageService', () => { let html = ''; try { + console.warn('='.repeat(70)); + console.warn('Starting fixture.fetch'); html = await fixture.fetch('/blog/post').then((res) => res.text()); + console.warn('Finish fixture.fetch'); + console.warn('='.repeat(70)); } catch (error) { console.error('Error getting html:', error); throw error; From 07a12c5fd245c52dbca89faddbf2a8e8b5ff70ea Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 30 Apr 2026 13:41:30 +1000 Subject: [PATCH 11/12] only run cloudflare --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 70a16c41ec19..5f3b8f34e70a 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "format:imports:ci": "biome ci --formatter-enabled=false", "test": "pnpm run test:astro && pnpm run test:integrations && pnpm run test:language-tools", "test:astro": "node ./scripts/turbo-run-affected.js test --concurrency=1 --filter=astro --only", - "test:integrations": "node ./scripts/turbo-run-affected.js test --concurrency=1 --filter=create-astro --filter=\"@astrojs/*\" --filter=\"!./packages/language-tools/**/*\" --only", + "test:integrations": "node ./scripts/turbo-run-affected.js test --concurrency=1 --filter=\"@astrojs/cloudflare\" --filter=\"!./packages/language-tools/**/*\" --only", "test:language-tools": "turbo run test --concurrency=1 --filter=\"./packages/language-tools/**/*\" --filter=\"!./packages/language-tools/ts-plugin\" --only", "test:language-tools:no-vs": "turbo run test --filter=\"@astrojs/language-server\" --filter=\"@astrojs/check\" --only", "test:citgm": "pnpm -r --filter=astro test", From b5d08e41d9d5e2e3aa60eb189c210ca65d85210c Mon Sep 17 00:00:00 2001 From: ocavue Date: Thu, 30 Apr 2026 14:09:44 +1000 Subject: [PATCH 12/12] test: await previewServer.stop in cloudflare tests --- packages/integrations/cloudflare/test/client-address.test.ts | 2 +- .../cloudflare/test/prerender-queue-consumers.test.ts | 2 +- .../cloudflare/test/wrangler-preview-platform.test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/integrations/cloudflare/test/client-address.test.ts b/packages/integrations/cloudflare/test/client-address.test.ts index 534b089adf61..5123c4be0863 100644 --- a/packages/integrations/cloudflare/test/client-address.test.ts +++ b/packages/integrations/cloudflare/test/client-address.test.ts @@ -24,7 +24,7 @@ describe('Cloudflare clientAddress', () => { }); after(async () => { - previewServer.stop(); + await previewServer.stop(); }); it('returns the client IP from cf-connecting-ip header', async () => { diff --git a/packages/integrations/cloudflare/test/prerender-queue-consumers.test.ts b/packages/integrations/cloudflare/test/prerender-queue-consumers.test.ts index 0518b194caad..691331731b0d 100644 --- a/packages/integrations/cloudflare/test/prerender-queue-consumers.test.ts +++ b/packages/integrations/cloudflare/test/prerender-queue-consumers.test.ts @@ -14,7 +14,7 @@ describe('Prerender with queue consumers', () => { }); after(async () => { - previewServer.stop(); + await previewServer.stop(); }); it('builds and previews without ERR_MULTIPLE_CONSUMERS', async () => { diff --git a/packages/integrations/cloudflare/test/wrangler-preview-platform.test.ts b/packages/integrations/cloudflare/test/wrangler-preview-platform.test.ts index 1d0dfaad90c3..5f769896ca0c 100644 --- a/packages/integrations/cloudflare/test/wrangler-preview-platform.test.ts +++ b/packages/integrations/cloudflare/test/wrangler-preview-platform.test.ts @@ -15,7 +15,7 @@ describe('WranglerPreviewPlatform', () => { }); after(async () => { - previewServer.stop(); + await previewServer.stop(); }); it('exists', async () => {