From a1ff4a3604fd4f3d85701bdf8b6e5b3d3a35f45a Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 15 Oct 2024 17:06:55 +0200 Subject: [PATCH 01/17] feat(next): make defineConfig generic --- packages/astro/config.d.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/astro/config.d.ts b/packages/astro/config.d.ts index de2a500c25b2..abb31c015827 100644 --- a/packages/astro/config.d.ts +++ b/packages/astro/config.d.ts @@ -11,7 +11,22 @@ type EnvField = typeof import('./dist/env/config.js').envField; * See the full Astro Configuration API Documentation * https://astro.build/config */ -export function defineConfig(config: AstroUserConfig): AstroUserConfig; +// TODO: jsdoc for overridden properties +export function defineConfig< + TDefaultLocale extends string, + const TLocales extends [TDefaultLocale, ...Array], +>( + config: Omit & { + i18n?: { + defaultLocale: TDefaultLocale; + locales: TLocales; + fallback?: { + [Locale in TLocales[number]]?: Exclude; + }; + domains?: Partial>; + } & Pick, 'routing'>; + }, +): AstroUserConfig; /** * Use Astro to generate a fully resolved Vite config From b627d82cec45d21516f70e7a0431c6d2841c4396 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 16 Oct 2024 16:37:22 +0200 Subject: [PATCH 02/17] feat: work on generic type --- packages/astro/config.d.ts | 18 +++--------------- packages/astro/src/config/index.ts | 12 +++++++++++- packages/astro/src/types/public/config.ts | 20 +++++++++++++++----- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/astro/config.d.ts b/packages/astro/config.d.ts index abb31c015827..256a1c82ffc8 100644 --- a/packages/astro/config.d.ts +++ b/packages/astro/config.d.ts @@ -11,22 +11,10 @@ type EnvField = typeof import('./dist/env/config.js').envField; * See the full Astro Configuration API Documentation * https://astro.build/config */ -// TODO: jsdoc for overridden properties export function defineConfig< - TDefaultLocale extends string, - const TLocales extends [TDefaultLocale, ...Array], ->( - config: Omit & { - i18n?: { - defaultLocale: TDefaultLocale; - locales: TLocales; - fallback?: { - [Locale in TLocales[number]]?: Exclude; - }; - domains?: Partial>; - } & Pick, 'routing'>; - }, -): AstroUserConfig; + TDefaultLocale extends string, + const TLocales extends [TDefaultLocale, ...Array], + >(config: AstroUserConfig): AstroUserConfig; /** * Use Astro to generate a fully resolved Vite config diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index 77c33fcc5ffc..f3d6745535a2 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -4,10 +4,20 @@ import { createRouteManifest } from '../core/routing/index.js'; import type { AstroInlineConfig, AstroUserConfig } from '../types/public/config.js'; import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js'; -export function defineConfig(config: AstroUserConfig) { +export function defineConfig< + TDefaultLocale extends string, + const TLocales extends [TDefaultLocale, ...Array], +>(config: AstroUserConfig) { return config; } +defineConfig({ + i18n: { + defaultLocale: 'en', + locales: ['en', 'fr'], + }, +}); + export function getViteConfig( userViteConfig: ViteUserConfig, inlineAstroConfig: AstroInlineConfig = {}, diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 66be4037b2b3..5c7c2af44a6a 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -102,7 +102,10 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * Astro User Config * Docs: https://docs.astro.build/reference/configuration-reference/ */ -export interface AstroUserConfig { +export interface AstroUserConfig< + TDefaultLocale extends string = never, + TLocales extends [TDefaultLocale, ...Array] = never, +> { /** * @docs * @kind heading @@ -1214,7 +1217,7 @@ export interface AstroUserConfig { * * No particular language format or syntax is enforced, but we suggest using lower-case and hyphens as needed (e.g. "es", "pt-br") for greatest compatibility. */ - defaultLocale: string; + defaultLocale: [TDefaultLocale] extends [never] ? string : TDefaultLocale; /** * @docs * @name i18n.locales @@ -1228,7 +1231,8 @@ export interface AstroUserConfig { * * No particular language code format or syntax is enforced, but your project folders containing your content files must match exactly the `locales` items in the list. In the case of multiple `codes` pointing to a custom URL path prefix, store your content files in a folder with the same name as the `path` configured. */ - locales: Locales; + // TODO: handle Locales shape + locales: [TLocales] extends [never] ? Locales : TLocales; /** * @docs @@ -1258,7 +1262,11 @@ export interface AstroUserConfig { * }) * ``` */ - fallback?: Record; + fallback?: [TLocales] extends [never] + ? Record + : { + [Locale in TLocales[number]]?: Exclude; + }; /** * @docs @@ -1444,7 +1452,9 @@ export interface AstroUserConfig { * * See the [Internationalization Guide](https://docs.astro.build/en/guides/internationalization/#domains) for more details, including the limitations of this feature. */ - domains?: Record; + domains?: [TLocales] extends [never] + ? Record + : Partial>; }; /** ! WARNING: SUBJECT TO CHANGE */ From 76d6e6b1751e4c224e832977eacc0aedc604a4c3 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 16 Oct 2024 16:50:06 +0200 Subject: [PATCH 03/17] feat: handle locales shape --- packages/astro/config.d.ts | 6 +++++- packages/astro/src/config/index.ts | 14 +++++--------- packages/astro/src/types/public/config.ts | 17 ++++++++++++++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/packages/astro/config.d.ts b/packages/astro/config.d.ts index 256a1c82ffc8..dfa17726e570 100644 --- a/packages/astro/config.d.ts +++ b/packages/astro/config.d.ts @@ -2,6 +2,7 @@ type ViteUserConfig = import('vite').UserConfig; type ViteUserConfigFn = import('vite').UserConfigFn; type AstroUserConfig = import('./dist/types/public/config.js').AstroUserConfig; +type Locales = import('./dist/types/public/config.js').Locales; type AstroInlineConfig = import('./dist/types/public/config.js').AstroInlineConfig; type ImageServiceConfig = import('./dist/types/public/config.js').ImageServiceConfig; type SharpImageServiceConfig = import('./dist/assets/services/sharp.js').SharpImageServiceConfig; @@ -13,7 +14,10 @@ type EnvField = typeof import('./dist/env/config.js').envField; */ export function defineConfig< TDefaultLocale extends string, - const TLocales extends [TDefaultLocale, ...Array], + const TLocales extends [ + TDefaultLocale | { codes: [TDefaultLocale, ...Array]; path: string }, + ...Locales, + ], >(config: AstroUserConfig): AstroUserConfig; /** diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index f3d6745535a2..00f4197d8ccb 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -1,23 +1,19 @@ import type { UserConfig as ViteUserConfig } from 'vite'; import { Logger } from '../core/logger/core.js'; import { createRouteManifest } from '../core/routing/index.js'; -import type { AstroInlineConfig, AstroUserConfig } from '../types/public/config.js'; +import type { AstroInlineConfig, AstroUserConfig, Locales } from '../types/public/config.js'; import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js'; export function defineConfig< TDefaultLocale extends string, - const TLocales extends [TDefaultLocale, ...Array], + const TLocales extends [ + TDefaultLocale | { codes: [TDefaultLocale, ...Array]; path: string }, + ...Locales, + ], >(config: AstroUserConfig) { return config; } -defineConfig({ - i18n: { - defaultLocale: 'en', - locales: ['en', 'fr'], - }, -}); - export function getViteConfig( userViteConfig: ViteUserConfig, inlineAstroConfig: AstroInlineConfig = {}, diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 5c7c2af44a6a..64a1a68356fc 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -16,6 +16,14 @@ import type { AstroIntegration } from './integrations.js'; export type Locales = (string | { codes: string[]; path: string })[]; +type NormalizeLocales = { + [K in keyof T]: T[K] extends string + ? T[K] + : T[K] extends { codes: Array } + ? T[K]['codes'][number] + : never; +}[number]; + export interface ImageServiceConfig = Record> { entrypoint: 'astro/assets/services/sharp' | (string & {}); config?: T; @@ -104,7 +112,10 @@ export interface ViteUserConfig extends OriginalViteUserConfig { */ export interface AstroUserConfig< TDefaultLocale extends string = never, - TLocales extends [TDefaultLocale, ...Array] = never, + TLocales extends [ + TDefaultLocale | { codes: [TDefaultLocale, ...Array]; path: string }, + ...Locales, + ] = never, > { /** * @docs @@ -1265,7 +1276,7 @@ export interface AstroUserConfig< fallback?: [TLocales] extends [never] ? Record : { - [Locale in TLocales[number]]?: Exclude; + [Locale in NormalizeLocales]?: Exclude, Locale>; }; /** @@ -1454,7 +1465,7 @@ export interface AstroUserConfig< */ domains?: [TLocales] extends [never] ? Record - : Partial>; + : Partial, string>>; }; /** ! WARNING: SUBJECT TO CHANGE */ From 348def6429b5681c460cf5de5b3f58daae8fde07 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 16 Oct 2024 16:51:10 +0200 Subject: [PATCH 04/17] chore: remove todo --- packages/astro/src/types/public/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 64a1a68356fc..5c7b0ba0f30a 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -1242,7 +1242,6 @@ export interface AstroUserConfig< * * No particular language code format or syntax is enforced, but your project folders containing your content files must match exactly the `locales` items in the list. In the case of multiple `codes` pointing to a custom URL path prefix, store your content files in a folder with the same name as the `path` configured. */ - // TODO: handle Locales shape locales: [TLocales] extends [never] ? Locales : TLocales; /** From c9b6ca59b90799dc01768403043859d887255b54 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 16 Oct 2024 16:52:59 +0200 Subject: [PATCH 05/17] chore: changeset --- .changeset/forty-trains-notice.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/forty-trains-notice.md diff --git a/.changeset/forty-trains-notice.md b/.changeset/forty-trains-notice.md new file mode 100644 index 000000000000..f722b7e1a7ae --- /dev/null +++ b/.changeset/forty-trains-notice.md @@ -0,0 +1,9 @@ +--- +'astro': minor +--- + +Makes `defineConfig` generic + +TypeScript will now provide feedback at the type level when using `defineConfig`. For example, it will make sure `i18n.locales` contains `i18n.defaultLocale`. + +This also makes the `AstroUserConfig` generic, but both changes are backward compatible. From 42f4cd4bf75ff43e52a9d7377303657df3160ffb Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 16 Oct 2024 20:21:05 +0200 Subject: [PATCH 06/17] feat: accept 1 generic --- packages/astro/config.d.ts | 13 +++++-------- packages/astro/src/config/index.ts | 12 ++++-------- packages/astro/src/types/public/config.ts | 21 +++++++++++---------- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/packages/astro/config.d.ts b/packages/astro/config.d.ts index dfa17726e570..36883c867d3d 100644 --- a/packages/astro/config.d.ts +++ b/packages/astro/config.d.ts @@ -1,8 +1,9 @@ /// type ViteUserConfig = import('vite').UserConfig; type ViteUserConfigFn = import('vite').UserConfigFn; -type AstroUserConfig = import('./dist/types/public/config.js').AstroUserConfig; type Locales = import('./dist/types/public/config.js').Locales; +type AstroUserDefineConfig = + import('./dist/types/public/config.js').AstroUserDefineConfig; type AstroInlineConfig = import('./dist/types/public/config.js').AstroInlineConfig; type ImageServiceConfig = import('./dist/types/public/config.js').ImageServiceConfig; type SharpImageServiceConfig = import('./dist/assets/services/sharp.js').SharpImageServiceConfig; @@ -12,13 +13,9 @@ type EnvField = typeof import('./dist/env/config.js').envField; * See the full Astro Configuration API Documentation * https://astro.build/config */ -export function defineConfig< - TDefaultLocale extends string, - const TLocales extends [ - TDefaultLocale | { codes: [TDefaultLocale, ...Array]; path: string }, - ...Locales, - ], - >(config: AstroUserConfig): AstroUserConfig; +export function defineConfig( + config: AstroUserDefineConfig, +): AstroUserDefineConfig; /** * Use Astro to generate a fully resolved Vite config diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index 00f4197d8ccb..1faaa6a9654f 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -1,16 +1,12 @@ import type { UserConfig as ViteUserConfig } from 'vite'; import { Logger } from '../core/logger/core.js'; import { createRouteManifest } from '../core/routing/index.js'; -import type { AstroInlineConfig, AstroUserConfig, Locales } from '../types/public/config.js'; +import type { AstroInlineConfig, AstroUserDefineConfig, Locales } from '../types/public/config.js'; import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js'; -export function defineConfig< - TDefaultLocale extends string, - const TLocales extends [ - TDefaultLocale | { codes: [TDefaultLocale, ...Array]; path: string }, - ...Locales, - ], ->(config: AstroUserConfig) { +export function defineConfig( + config: AstroUserDefineConfig, +) { return config; } diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 5c7b0ba0f30a..a26388605a57 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -110,13 +110,9 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * Astro User Config * Docs: https://docs.astro.build/reference/configuration-reference/ */ -export interface AstroUserConfig< - TDefaultLocale extends string = never, - TLocales extends [ - TDefaultLocale | { codes: [TDefaultLocale, ...Array]; path: string }, - ...Locales, - ] = never, -> { +export type AstroUserConfig = AstroUserDefineConfig; + +export interface AstroUserDefineConfig { /** * @docs * @kind heading @@ -1228,7 +1224,9 @@ export interface AstroUserConfig< * * No particular language format or syntax is enforced, but we suggest using lower-case and hyphens as needed (e.g. "es", "pt-br") for greatest compatibility. */ - defaultLocale: [TDefaultLocale] extends [never] ? string : TDefaultLocale; + defaultLocale: [TLocales] extends [never] + ? string + : NormalizeLocales>; /** * @docs * @name i18n.locales @@ -1275,7 +1273,10 @@ export interface AstroUserConfig< fallback?: [TLocales] extends [never] ? Record : { - [Locale in NormalizeLocales]?: Exclude, Locale>; + [Locale in NormalizeLocales>]?: Exclude< + NormalizeLocales>, + Locale + >; }; /** @@ -1464,7 +1465,7 @@ export interface AstroUserConfig< */ domains?: [TLocales] extends [never] ? Record - : Partial, string>>; + : Partial>, string>>; }; /** ! WARNING: SUBJECT TO CHANGE */ From 67b16d3124591eaf7da666854778a814da625673 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 16 Oct 2024 20:22:14 +0200 Subject: [PATCH 07/17] chore: changeset --- .changeset/forty-trains-notice.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.changeset/forty-trains-notice.md b/.changeset/forty-trains-notice.md index f722b7e1a7ae..ac6c51dd3914 100644 --- a/.changeset/forty-trains-notice.md +++ b/.changeset/forty-trains-notice.md @@ -4,6 +4,4 @@ Makes `defineConfig` generic -TypeScript will now provide feedback at the type level when using `defineConfig`. For example, it will make sure `i18n.locales` contains `i18n.defaultLocale`. - -This also makes the `AstroUserConfig` generic, but both changes are backward compatible. +TypeScript will now provide feedback at the type level when using `defineConfig`. For example, it will make sure `i18n.defaultLocale` is one of the locales declared in `i18n.locales` From 93e6393ee83729fa27ef20885ba4093f3aea4fa4 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Wed, 16 Oct 2024 20:42:38 +0200 Subject: [PATCH 08/17] feat: write tests --- packages/astro/config.d.ts | 2 +- packages/astro/src/config/index.ts | 2 +- packages/astro/test/types/define-config.ts | 39 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 packages/astro/test/types/define-config.ts diff --git a/packages/astro/config.d.ts b/packages/astro/config.d.ts index 36883c867d3d..7476a25ac0ee 100644 --- a/packages/astro/config.d.ts +++ b/packages/astro/config.d.ts @@ -13,7 +13,7 @@ type EnvField = typeof import('./dist/env/config.js').envField; * See the full Astro Configuration API Documentation * https://astro.build/config */ -export function defineConfig( +export function defineConfig( config: AstroUserDefineConfig, ): AstroUserDefineConfig; diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index 1faaa6a9654f..8de166477148 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -4,7 +4,7 @@ import { createRouteManifest } from '../core/routing/index.js'; import type { AstroInlineConfig, AstroUserDefineConfig, Locales } from '../types/public/config.js'; import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js'; -export function defineConfig( +export function defineConfig( config: AstroUserDefineConfig, ) { return config; diff --git a/packages/astro/test/types/define-config.ts b/packages/astro/test/types/define-config.ts new file mode 100644 index 000000000000..ca91051c3e5d --- /dev/null +++ b/packages/astro/test/types/define-config.ts @@ -0,0 +1,39 @@ +import { describe, it } from 'node:test'; +import { defineConfig } from '../../dist/config'; +import type { AstroUserDefineConfig } from '../../dist/types/public/config'; +import { expectTypeOf } from 'expect-type'; + +describe('defineConfig()', () => { + it('Infers generics correctly', () => { + expectTypeOf(defineConfig({})).toEqualTypeOf>(); + + expectTypeOf( + defineConfig({ + i18n: { + locales: ['en'], + defaultLocale: 'en', + }, + }), + ).toEqualTypeOf>(); + + expectTypeOf( + defineConfig({ + i18n: { + locales: ['en', 'fr'], + defaultLocale: 'fr', + }, + }), + ).toEqualTypeOf>(); + + expectTypeOf( + defineConfig({ + i18n: { + locales: ['en', { path: 'french', codes: ['fr', 'fr-FR'] }], + defaultLocale: 'en', + }, + }), + ).toEqualTypeOf< + AstroUserDefineConfig<['en', { readonly path: 'french'; readonly codes: ['fr', 'fr-FR'] }]> + >(); + }); +}); From dd8d059d04b41d4d9cf42f8c07a093661d5586ce Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 17 Oct 2024 14:39:36 +0200 Subject: [PATCH 09/17] feat: update docs --- packages/astro/src/types/public/config.ts | 27 +++++++++++------------ 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index a26388605a57..eac95b19b197 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -1215,32 +1215,31 @@ export interface AstroUserDefineConfig { i18n?: { /** * @docs - * @name i18n.defaultLocale - * @type {string} + * @name i18n.locales + * @type {Locales} * @version 3.5.0 * @description * - * The default locale of your website/application. This is a required field. + * A list of all locales supported by the website. This is a required field. * - * No particular language format or syntax is enforced, but we suggest using lower-case and hyphens as needed (e.g. "es", "pt-br") for greatest compatibility. + * Languages can be listed either as individual codes (e.g. `['en', 'es', 'pt-br']`) or mapped to a shared `path` of codes (e.g. `{ path: "english", codes: ["en", "en-US"]}`). These codes will be used to determine the URL structure of your deployed site. + * + * No particular language code format or syntax is enforced, but your project folders containing your content files must match exactly the `locales` items in the list. In the case of multiple `codes` pointing to a custom URL path prefix, store your content files in a folder with the same name as the `path` configured. */ - defaultLocale: [TLocales] extends [never] - ? string - : NormalizeLocales>; + locales: [TLocales] extends [never] ? Locales : TLocales; + /** * @docs - * @name i18n.locales - * @type {Locales} + * @name i18n.defaultLocale + * @type {string} * @version 3.5.0 * @description * - * A list of all locales supported by the website, including the `defaultLocale`. This is a required field. + * The default locale of your website/application, that is one of the specified `locales`. This is a required field. * - * Languages can be listed either as individual codes (e.g. `['en', 'es', 'pt-br']`) or mapped to a shared `path` of codes (e.g. `{ path: "english", codes: ["en", "en-US"]}`). These codes will be used to determine the URL structure of your deployed site. - * - * No particular language code format or syntax is enforced, but your project folders containing your content files must match exactly the `locales` items in the list. In the case of multiple `codes` pointing to a custom URL path prefix, store your content files in a folder with the same name as the `path` configured. + * No particular language format or syntax is enforced, but we suggest using lower-case and hyphens as needed (e.g. "es", "pt-br") for greatest compatibility. */ - locales: [TLocales] extends [never] ? Locales : TLocales; + defaultLocale: [TLocales] extends [never] ? string : NormalizeLocales>; /** * @docs From eac4c72073d3b581e4b437482d6c90a7057eb2d9 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 17 Oct 2024 14:58:33 +0200 Subject: [PATCH 10/17] feat: improve config --- packages/astro/config.d.ts | 44 ------------------------- packages/astro/config.mjs | 16 --------- packages/astro/package.json | 7 +--- packages/astro/src/config/entrypoint.ts | 19 +++++++++++ packages/astro/src/config/index.ts | 23 ++++++++++--- packages/astro/src/env/config.ts | 2 +- 6 files changed, 40 insertions(+), 71 deletions(-) delete mode 100644 packages/astro/config.d.ts delete mode 100644 packages/astro/config.mjs create mode 100644 packages/astro/src/config/entrypoint.ts diff --git a/packages/astro/config.d.ts b/packages/astro/config.d.ts deleted file mode 100644 index 7476a25ac0ee..000000000000 --- a/packages/astro/config.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -/// -type ViteUserConfig = import('vite').UserConfig; -type ViteUserConfigFn = import('vite').UserConfigFn; -type Locales = import('./dist/types/public/config.js').Locales; -type AstroUserDefineConfig = - import('./dist/types/public/config.js').AstroUserDefineConfig; -type AstroInlineConfig = import('./dist/types/public/config.js').AstroInlineConfig; -type ImageServiceConfig = import('./dist/types/public/config.js').ImageServiceConfig; -type SharpImageServiceConfig = import('./dist/assets/services/sharp.js').SharpImageServiceConfig; -type EnvField = typeof import('./dist/env/config.js').envField; - -/** - * See the full Astro Configuration API Documentation - * https://astro.build/config - */ -export function defineConfig( - config: AstroUserDefineConfig, -): AstroUserDefineConfig; - -/** - * Use Astro to generate a fully resolved Vite config - */ -export function getViteConfig( - config: ViteUserConfig, - inlineAstroConfig?: AstroInlineConfig, -): ViteUserConfigFn; - -/** - * Return the configuration needed to use the Sharp-based image service - */ -export function sharpImageService(config?: SharpImageServiceConfig): ImageServiceConfig; - -/** - * Return the configuration needed to use the passthrough image service. This image services does not perform - * any image transformations, and is mainly useful when your platform does not support other image services, or you are - * not using Astro's built-in image processing. - * See: https://docs.astro.build/en/guides/images/#configure-no-op-passthrough-service - */ -export function passthroughImageService(): ImageServiceConfig; - -/** - * Return a valid env field to use in this Astro config for `experimental.env.schema`. - */ -export declare const envField: EnvField; diff --git a/packages/astro/config.mjs b/packages/astro/config.mjs deleted file mode 100644 index d117d806ed32..000000000000 --- a/packages/astro/config.mjs +++ /dev/null @@ -1,16 +0,0 @@ -export { defineConfig, getViteConfig } from './dist/config/index.js'; -export { envField } from './dist/env/config.js'; - -export function sharpImageService(config = {}) { - return { - entrypoint: 'astro/assets/services/sharp', - config, - }; -} - -export function passthroughImageService() { - return { - entrypoint: 'astro/assets/services/noop', - config: {}, - }; -} diff --git a/packages/astro/package.json b/packages/astro/package.json index 89f73b777ba5..fc26066d0528 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -46,10 +46,7 @@ }, "./compiler-runtime": "./dist/runtime/compiler/index.js", "./runtime/*": "./dist/runtime/*", - "./config": { - "types": "./config.d.ts", - "default": "./config.mjs" - }, + "./config": "./dist/config/entrypoint.js", "./container": { "types": "./dist/container/index.d.ts", "default": "./dist/container/index.js" @@ -93,8 +90,6 @@ "types", "astro.js", "index.d.ts", - "config.d.ts", - "config.mjs", "zod.d.ts", "zod.mjs", "env.d.ts", diff --git a/packages/astro/src/config/entrypoint.ts b/packages/astro/src/config/entrypoint.ts new file mode 100644 index 000000000000..fff07f06c003 --- /dev/null +++ b/packages/astro/src/config/entrypoint.ts @@ -0,0 +1,19 @@ +import type { SharpImageServiceConfig } from '../assets/services/sharp.js'; +import type { ImageServiceConfig } from '../types/public/index.js'; + +export { defineConfig, getViteConfig } from './index.js'; +export { envField } from '../env/config.js'; + +export function sharpImageService(config: SharpImageServiceConfig = {}): ImageServiceConfig { + return { + entrypoint: 'astro/assets/services/sharp', + config, + }; +} + +export function passthroughImageService(): ImageServiceConfig { + return { + entrypoint: 'astro/assets/services/noop', + config: {}, + }; +} diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index 8de166477148..2ded62a126cd 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -1,21 +1,28 @@ -import type { UserConfig as ViteUserConfig } from 'vite'; +import type { UserConfig as ViteUserConfig, UserConfigFn as ViteUserConfigFn } from 'vite'; import { Logger } from '../core/logger/core.js'; import { createRouteManifest } from '../core/routing/index.js'; import type { AstroInlineConfig, AstroUserDefineConfig, Locales } from '../types/public/config.js'; import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js'; +/** + * See the full Astro Configuration API Documentation + * https://astro.build/config + */ export function defineConfig( config: AstroUserDefineConfig, ) { return config; } +/** + * Use Astro to generate a fully resolved Vite config + */ export function getViteConfig( userViteConfig: ViteUserConfig, inlineAstroConfig: AstroInlineConfig = {}, -) { +): ViteUserConfigFn { // Return an async Vite config getter which exposes a resolved `mode` and `command` - return async ({ mode, command }: { mode: 'dev'; command: 'serve' | 'build' }) => { + return async ({ mode, command }) => { // Vite `command` is `serve | build`, but Astro uses `dev | build` const cmd = command === 'serve' ? 'dev' : command; @@ -54,7 +61,15 @@ export function getViteConfig( astroContentListenPlugin({ settings, logger, fs }), ], }, - { settings, logger, mode, sync: false, manifest, ssrManifest: devSSRManifest }, + { + settings, + logger, + // TODO: can the custom mode solve that? + mode: mode as 'dev' | 'build', + sync: false, + manifest, + ssrManifest: devSSRManifest, + }, ); await runHookConfigDone({ settings, logger }); return mergeConfig(viteConfig, userViteConfig); diff --git a/packages/astro/src/env/config.ts b/packages/astro/src/env/config.ts index 629a1fe2e4e4..beb91b43b2c6 100644 --- a/packages/astro/src/env/config.ts +++ b/packages/astro/src/env/config.ts @@ -10,7 +10,7 @@ import type { } from './schema.js'; /** - * Return a valid env field to use in this Astro config for `experimental.env.schema`. + * Return a valid env field to use in this Astro config for `env.schema`. */ export const envField = { string: (options: StringFieldInput): StringField => ({ From c0e519d3ef8cdf06a91810fcc347aafb42893feb Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 17 Oct 2024 14:59:44 +0200 Subject: [PATCH 11/17] fix: paths --- packages/astro/test/types/define-config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/test/types/define-config.ts b/packages/astro/test/types/define-config.ts index ca91051c3e5d..3bd2ef22dc00 100644 --- a/packages/astro/test/types/define-config.ts +++ b/packages/astro/test/types/define-config.ts @@ -1,6 +1,6 @@ import { describe, it } from 'node:test'; -import { defineConfig } from '../../dist/config'; -import type { AstroUserDefineConfig } from '../../dist/types/public/config'; +import { defineConfig } from '../../dist/config/index.js'; +import type { AstroUserDefineConfig } from '../../dist/types/public/config.js'; import { expectTypeOf } from 'expect-type'; describe('defineConfig()', () => { From 4e9fdd6dce061a81f637a51e600164e058d3e6ec Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Thu, 17 Oct 2024 15:09:28 +0200 Subject: [PATCH 12/17] Update .changeset/forty-trains-notice.md --- .changeset/forty-trains-notice.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.changeset/forty-trains-notice.md b/.changeset/forty-trains-notice.md index ac6c51dd3914..f77be4673689 100644 --- a/.changeset/forty-trains-notice.md +++ b/.changeset/forty-trains-notice.md @@ -2,6 +2,4 @@ 'astro': minor --- -Makes `defineConfig` generic - -TypeScript will now provide feedback at the type level when using `defineConfig`. For example, it will make sure `i18n.defaultLocale` is one of the locales declared in `i18n.locales` +Improves `defineConfig` type safety. TypeScript will now error if a group of related options do not have coherent types. For example, it will now error if `i18n.defaultLocale` is not one of the locales specified in `i18n.locales` From db2d160ee95811fce2c9bcdddd02be5690fbba42 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Fri, 18 Oct 2024 15:15:44 +0200 Subject: [PATCH 13/17] feat: address reviews --- packages/astro/src/config/entrypoint.ts | 11 +++++++++++ packages/astro/src/types/public/config.ts | 1 + 2 files changed, 12 insertions(+) diff --git a/packages/astro/src/config/entrypoint.ts b/packages/astro/src/config/entrypoint.ts index fff07f06c003..4951792d63ae 100644 --- a/packages/astro/src/config/entrypoint.ts +++ b/packages/astro/src/config/entrypoint.ts @@ -1,9 +1,14 @@ +// IMPORTANT: this file is the entrypoint for "astro/config". Keep it as light as possible! + import type { SharpImageServiceConfig } from '../assets/services/sharp.js'; import type { ImageServiceConfig } from '../types/public/index.js'; export { defineConfig, getViteConfig } from './index.js'; export { envField } from '../env/config.js'; +/** + * Return the configuration needed to use the Sharp-based image service + */ export function sharpImageService(config: SharpImageServiceConfig = {}): ImageServiceConfig { return { entrypoint: 'astro/assets/services/sharp', @@ -11,6 +16,12 @@ export function sharpImageService(config: SharpImageServiceConfig = {}): ImageSe }; } +/** + * Return the configuration needed to use the passthrough image service. This image services does not perform + * any image transformations, and is mainly useful when your platform does not support other image services, or you are + * not using Astro's built-in image processing. + * See: https://docs.astro.build/en/guides/images/#configure-no-op-passthrough-service + */ export function passthroughImageService(): ImageServiceConfig { return { entrypoint: 'astro/assets/services/noop', diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index f47560bb47cd..620899489087 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -112,6 +112,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { */ export type AstroUserConfig = AstroUserDefineConfig; +/** @internal */ export interface AstroUserDefineConfig { /** * @docs From c6c98ffc5a50bb54738926dec540ff5c430784c3 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Fri, 18 Oct 2024 15:20:21 +0200 Subject: [PATCH 14/17] chore: improve types tests --- packages/astro/test/types/define-config.ts | 52 +++++++++++----------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/packages/astro/test/types/define-config.ts b/packages/astro/test/types/define-config.ts index 3bd2ef22dc00..8a921abe58f8 100644 --- a/packages/astro/test/types/define-config.ts +++ b/packages/astro/test/types/define-config.ts @@ -5,35 +5,37 @@ import { expectTypeOf } from 'expect-type'; describe('defineConfig()', () => { it('Infers generics correctly', () => { - expectTypeOf(defineConfig({})).toEqualTypeOf>(); + const config_0 = defineConfig({}); + expectTypeOf(config_0).toEqualTypeOf>(); + expectTypeOf(config_0.i18n!.defaultLocale).toEqualTypeOf(); - expectTypeOf( - defineConfig({ - i18n: { - locales: ['en'], - defaultLocale: 'en', - }, - }), - ).toEqualTypeOf>(); + const config_1 = defineConfig({ + i18n: { + locales: ['en'], + defaultLocale: 'en', + }, + }); + expectTypeOf(config_1).toEqualTypeOf>(); + expectTypeOf(config_1.i18n!.defaultLocale).toEqualTypeOf<'en'>(); - expectTypeOf( - defineConfig({ - i18n: { - locales: ['en', 'fr'], - defaultLocale: 'fr', - }, - }), - ).toEqualTypeOf>(); + const config_2 = defineConfig({ + i18n: { + locales: ['en', 'fr'], + defaultLocale: 'fr', + }, + }); + expectTypeOf(config_2).toEqualTypeOf>(); + expectTypeOf(config_2.i18n!.defaultLocale).toEqualTypeOf<'en' | 'fr'>(); - expectTypeOf( - defineConfig({ - i18n: { - locales: ['en', { path: 'french', codes: ['fr', 'fr-FR'] }], - defaultLocale: 'en', - }, - }), - ).toEqualTypeOf< + const config_3 = defineConfig({ + i18n: { + locales: ['en', { path: 'french', codes: ['fr', 'fr-FR'] }], + defaultLocale: 'en', + }, + }); + expectTypeOf(config_3).toEqualTypeOf< AstroUserDefineConfig<['en', { readonly path: 'french'; readonly codes: ['fr', 'fr-FR'] }]> >(); + expectTypeOf(config_3.i18n!.defaultLocale).toEqualTypeOf<'en' | 'fr' | 'fr-FR'>(); }); }); From 67bdf71705683d304eb2d8bff2ddb13facc22c7e Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Mon, 21 Oct 2024 16:41:42 +0200 Subject: [PATCH 15/17] Update .changeset/forty-trains-notice.md Co-authored-by: Sarah Rainsberger --- .changeset/forty-trains-notice.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/forty-trains-notice.md b/.changeset/forty-trains-notice.md index f77be4673689..29938198d6c8 100644 --- a/.changeset/forty-trains-notice.md +++ b/.changeset/forty-trains-notice.md @@ -2,4 +2,4 @@ 'astro': minor --- -Improves `defineConfig` type safety. TypeScript will now error if a group of related options do not have coherent types. For example, it will now error if `i18n.defaultLocale` is not one of the locales specified in `i18n.locales` +Improves `defineConfig` type safety. TypeScript will now error if a group of related configuration options do not have consistent types. For example, you will now see an error if your language set for `i18n.defaultLocale` is not one of the supported locales specified in `i18n.locales`. From 7b6634048dfec7287e9984b0ec4f9f598c511b77 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Mon, 21 Oct 2024 16:53:36 +0200 Subject: [PATCH 16/17] feat: update error --- packages/astro/src/core/errors/errors-data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index 5ad2b939ed9f..fb93e6e9103e 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -1160,8 +1160,8 @@ export const UnhandledRejection = { * import { defineConfig } from 'astro' * export default defineConfig({ * i18n: { - * defaultLocale: 'en', * locales: ['en', 'fr'], + * defaultLocale: 'en', * }, * }) * ``` From 4dad4686d5f3c65e85c55c9f5a24bd850b966ae1 Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Mon, 21 Oct 2024 18:06:29 +0200 Subject: [PATCH 17/17] feat: remove AstroUserDefineConfig --- packages/astro/src/config/index.ts | 4 ++-- packages/astro/src/types/public/config.ts | 8 +++----- packages/astro/test/types/define-config.ts | 10 +++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts index 0c92f48d32c1..62316377a8bb 100644 --- a/packages/astro/src/config/index.ts +++ b/packages/astro/src/config/index.ts @@ -1,7 +1,7 @@ import type { UserConfig as ViteUserConfig, UserConfigFn as ViteUserConfigFn } from 'vite'; import { Logger } from '../core/logger/core.js'; import { createRouteManifest } from '../core/routing/index.js'; -import type { AstroInlineConfig, AstroUserDefineConfig, Locales } from '../types/public/config.js'; +import type { AstroInlineConfig, AstroUserConfig, Locales } from '../types/public/config.js'; import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js'; /** @@ -9,7 +9,7 @@ import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js * https://astro.build/config */ export function defineConfig( - config: AstroUserDefineConfig, + config: AstroUserConfig, ) { return config; } diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 620899489087..1e24f419408e 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -109,11 +109,9 @@ export interface ViteUserConfig extends OriginalViteUserConfig { /** * Astro User Config * Docs: https://docs.astro.build/reference/configuration-reference/ - */ -export type AstroUserConfig = AstroUserDefineConfig; - -/** @internal */ -export interface AstroUserDefineConfig { + * + * Generics do not follow semver and may change at any time. + */ export interface AstroUserConfig { /** * @docs * @kind heading diff --git a/packages/astro/test/types/define-config.ts b/packages/astro/test/types/define-config.ts index 8a921abe58f8..9015694e2a9c 100644 --- a/packages/astro/test/types/define-config.ts +++ b/packages/astro/test/types/define-config.ts @@ -1,12 +1,12 @@ import { describe, it } from 'node:test'; import { defineConfig } from '../../dist/config/index.js'; -import type { AstroUserDefineConfig } from '../../dist/types/public/config.js'; +import type { AstroUserConfig } from '../../dist/types/public/index.js'; import { expectTypeOf } from 'expect-type'; describe('defineConfig()', () => { it('Infers generics correctly', () => { const config_0 = defineConfig({}); - expectTypeOf(config_0).toEqualTypeOf>(); + expectTypeOf(config_0).toEqualTypeOf>(); expectTypeOf(config_0.i18n!.defaultLocale).toEqualTypeOf(); const config_1 = defineConfig({ @@ -15,7 +15,7 @@ describe('defineConfig()', () => { defaultLocale: 'en', }, }); - expectTypeOf(config_1).toEqualTypeOf>(); + expectTypeOf(config_1).toEqualTypeOf>(); expectTypeOf(config_1.i18n!.defaultLocale).toEqualTypeOf<'en'>(); const config_2 = defineConfig({ @@ -24,7 +24,7 @@ describe('defineConfig()', () => { defaultLocale: 'fr', }, }); - expectTypeOf(config_2).toEqualTypeOf>(); + expectTypeOf(config_2).toEqualTypeOf>(); expectTypeOf(config_2.i18n!.defaultLocale).toEqualTypeOf<'en' | 'fr'>(); const config_3 = defineConfig({ @@ -34,7 +34,7 @@ describe('defineConfig()', () => { }, }); expectTypeOf(config_3).toEqualTypeOf< - AstroUserDefineConfig<['en', { readonly path: 'french'; readonly codes: ['fr', 'fr-FR'] }]> + AstroUserConfig<['en', { readonly path: 'french'; readonly codes: ['fr', 'fr-FR'] }]> >(); expectTypeOf(config_3.i18n!.defaultLocale).toEqualTypeOf<'en' | 'fr' | 'fr-FR'>(); });