mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(schema): add type hints for runtime config (#18652)
This commit is contained in:
parent
85881b462b
commit
01076d144f
@ -9,10 +9,59 @@ export type { SchemaDefinition } from 'untyped'
|
||||
|
||||
type DeepPartial<T> = T extends Function ? T : T extends Record<string, any> ? { [P in keyof T]?: DeepPartial<T[P]> } : T
|
||||
|
||||
type ExtractUpperChunk<T extends string> = T extends `${infer A}${infer B}`
|
||||
? A extends Uppercase<A>
|
||||
? B extends `${Uppercase<string>}${infer Rest}`
|
||||
? B extends `${infer C}${Rest}`
|
||||
? `${A}${C}${ExtractUpperChunk<Rest>}`
|
||||
: never
|
||||
: A
|
||||
: ''
|
||||
: never
|
||||
|
||||
type SliceLast<T extends string> = T extends `${infer A}${infer B}`
|
||||
? B extends `${infer C}${infer D}`
|
||||
? D extends ''
|
||||
? A
|
||||
: `${A}${C}${SliceLast<D>}`
|
||||
: ''
|
||||
: never
|
||||
|
||||
type UpperSnakeCase<T extends string, State extends 'start' | 'lower' | 'upper' = 'start'> = T extends `${infer A}${infer B}`
|
||||
? A extends Uppercase<A>
|
||||
? A extends `${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0}`
|
||||
? `${A}${UpperSnakeCase<B, 'lower'>}`
|
||||
: State extends 'lower' | 'upper'
|
||||
? B extends `${SliceLast<ExtractUpperChunk<B>>}${infer Rest}`
|
||||
? SliceLast<ExtractUpperChunk<B>> extends ''
|
||||
? `_${A}_${UpperSnakeCase<B, 'start'>}`
|
||||
: `_${A}${SliceLast<ExtractUpperChunk<B>>}_${UpperSnakeCase<Rest, 'start'>}`
|
||||
: B extends Uppercase<B>
|
||||
? `_${A}${B}`
|
||||
: `_${A}${UpperSnakeCase<B, 'lower'>}`
|
||||
: State extends 'start'
|
||||
? `${A}${UpperSnakeCase<B, 'lower'>}`
|
||||
: never
|
||||
: State extends 'start' | 'lower'
|
||||
? `${Uppercase<A>}${UpperSnakeCase<B, 'lower'>}`
|
||||
: `_${Uppercase<A>}${UpperSnakeCase<B, 'lower'>}`
|
||||
: Uppercase<T>
|
||||
|
||||
const message = Symbol('message')
|
||||
export type RuntimeValue<T, B extends string> = T & { [message]?: B }
|
||||
type Overrideable<T extends Record<string, any>, Path extends string = ''> = {
|
||||
[K in keyof T]?: K extends string
|
||||
? T[K] extends Record<string, any>
|
||||
? RuntimeValue<Overrideable<T[K], `${Path}_${UpperSnakeCase<K>}`>, `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`>
|
||||
: RuntimeValue<T[K], `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`>
|
||||
: never
|
||||
}
|
||||
|
||||
/** User configuration in `nuxt.config` file */
|
||||
export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite'>> {
|
||||
export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite' | 'runtimeConfig'>> {
|
||||
// Avoid DeepPartial for vite config interface (#4772)
|
||||
vite?: ConfigSchema['vite']
|
||||
runtimeConfig?: Overrideable<RuntimeConfig>
|
||||
|
||||
/**
|
||||
* Experimental custom config schema
|
||||
|
2
test/fixtures/basic/nuxt.config.ts
vendored
2
test/fixtures/basic/nuxt.config.ts
vendored
@ -49,6 +49,8 @@ export default defineNuxtConfig({
|
||||
}
|
||||
},
|
||||
runtimeConfig: {
|
||||
baseURL: '',
|
||||
baseAPIToken: '',
|
||||
privateConfig: 'secret_key',
|
||||
public: {
|
||||
needsFallback: undefined,
|
||||
|
18
test/fixtures/basic/types.ts
vendored
18
test/fixtures/basic/types.ts
vendored
@ -1,7 +1,7 @@
|
||||
import { expectTypeOf } from 'expect-type'
|
||||
import { describe, it } from 'vitest'
|
||||
import type { Ref } from 'vue'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import type { AppConfig, RuntimeValue } from '@nuxt/schema'
|
||||
|
||||
import type { FetchError } from 'ofetch'
|
||||
import type { NavigationFailure, RouteLocationNormalizedLoaded, RouteLocationRaw, useRouter as vueUseRouter } from 'vue-router'
|
||||
@ -124,9 +124,25 @@ describe('runtimeConfig', () => {
|
||||
it('generated runtimeConfig types', () => {
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
expectTypeOf(runtimeConfig.public.testConfig).toEqualTypeOf<number>()
|
||||
expectTypeOf(runtimeConfig.public.needsFallback).toEqualTypeOf<string>()
|
||||
expectTypeOf(runtimeConfig.privateConfig).toEqualTypeOf<string>()
|
||||
expectTypeOf(runtimeConfig.unknown).toEqualTypeOf<any>()
|
||||
})
|
||||
it('provides hints on overriding these values', () => {
|
||||
const val = defineNuxtConfig({
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
// @ts-expect-error
|
||||
testConfig: 'test'
|
||||
}
|
||||
}
|
||||
})
|
||||
expectTypeOf(val.runtimeConfig!.public!.testConfig).toEqualTypeOf<undefined | RuntimeValue<number, 'You can override this value at runtime with NUXT_PUBLIC_TEST_CONFIG'>>()
|
||||
expectTypeOf(val.runtimeConfig!.privateConfig).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_PRIVATE_CONFIG'>>()
|
||||
expectTypeOf(val.runtimeConfig!.baseURL).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_URL'>>()
|
||||
expectTypeOf(val.runtimeConfig!.baseAPIToken).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_API_TOKEN'>>()
|
||||
expectTypeOf(val.runtimeConfig!.unknown).toEqualTypeOf<any>()
|
||||
})
|
||||
})
|
||||
|
||||
describe('head', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user