From 6ec267be8744d457687c71a85d91f23db6dfe44a Mon Sep 17 00:00:00 2001 From: Luke Nelson Date: Wed, 15 Nov 2023 18:58:00 +0000 Subject: [PATCH] fix(schema): use scule types for `runtimeConfig` type hints (#23696) --- packages/schema/package.json | 1 + packages/schema/src/types/config.ts | 39 ++--------------------------- pnpm-lock.yaml | 10 ++++++-- test/fixtures/basic-types/types.ts | 17 ++++++++++++- 4 files changed, 27 insertions(+), 40 deletions(-) diff --git a/packages/schema/package.json b/packages/schema/package.json index 5b21304b20..30085c58df 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -65,6 +65,7 @@ "hookable": "^5.5.3", "pathe": "^1.1.1", "pkg-types": "^1.0.3", + "scule": "^1.1.0", "std-env": "^3.5.0", "ufo": "^1.3.1", "unimport": "^3.5.0", diff --git a/packages/schema/src/types/config.ts b/packages/schema/src/types/config.ts index f8351a378a..df925a1027 100644 --- a/packages/schema/src/types/config.ts +++ b/packages/schema/src/types/config.ts @@ -4,6 +4,7 @@ import type { Options as VuePluginOptions } from '@vitejs/plugin-vue' import type { Options as VueJsxPluginOptions } from '@vitejs/plugin-vue-jsx' import type { SchemaDefinition } from 'untyped' import type { NitroRuntimeConfig, NitroRuntimeConfigApp } from 'nitropack' +import type { SnakeCase } from 'scule' import type { ConfigSchema } from '../../schema/config' import type { Nuxt } from './nuxt' import type { AppHeadMetaObject } from './head' @@ -11,43 +12,7 @@ export type { SchemaDefinition } from 'untyped' type DeepPartial = T extends Function ? T : T extends Record ? { [P in keyof T]?: DeepPartial } : T -type ExtractUpperChunk = T extends `${infer A}${infer B}` - ? A extends Uppercase - ? B extends `${Uppercase}${infer Rest}` - ? B extends `${infer C}${Rest}` - ? `${A}${C}${ExtractUpperChunk}` - : never - : A - : '' - : never - -type SliceLast = T extends `${infer A}${infer B}` - ? B extends `${infer C}${infer D}` - ? D extends '' - ? A - : `${A}${C}${SliceLast}` - : '' - : never - -type UpperSnakeCase = T extends `${infer A}${infer B}` - ? A extends Uppercase - ? A extends `${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0}` - ? `${A}${UpperSnakeCase}` - : State extends 'lower' | 'upper' - ? B extends `${SliceLast>}${infer Rest}` - ? SliceLast> extends '' - ? `_${A}_${UpperSnakeCase}` - : `_${A}${SliceLast>}_${UpperSnakeCase}` - : B extends Uppercase - ? `_${A}${B}` - : `_${A}${UpperSnakeCase}` - : State extends 'start' - ? `${A}${UpperSnakeCase}` - : never - : State extends 'start' | 'lower' - ? `${Uppercase}${UpperSnakeCase}` - : `_${Uppercase}${UpperSnakeCase}` - : Uppercase +export type UpperSnakeCase = Uppercase> const message = Symbol('message') export type RuntimeValue = T & { [message]?: B } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e0c7ab5b0..fd42e98577 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -443,6 +443,9 @@ importers: pkg-types: specifier: ^1.0.3 version: 1.0.3 + scule: + specifier: ^1.1.0 + version: 1.1.0 std-env: specifier: ^3.5.0 version: 3.5.0 @@ -3768,7 +3771,7 @@ packages: open: 9.1.0 pathe: 1.1.1 pkg-types: 1.0.3 - scule: 1.0.0 + scule: 1.1.0 semver: 7.5.4 std-env: 3.5.0 yaml: 2.3.3 @@ -8194,6 +8197,9 @@ packages: /scule@1.0.0: resolution: {integrity: sha512-4AsO/FrViE/iDNEPaAQlb77tf0csuq27EsVpy6ett584EcRTp6pTDLoGWVxCD77y5iU5FauOvhsI4o1APwPoSQ==} + /scule@1.1.0: + resolution: {integrity: sha512-vRUjqhyM/YWYzT+jsMk6tnl3NkY4A4soJ8uyh3O6Um+JXEQL9ozUCe7pqrxn3CSKokw0hw3nFStfskzpgYwR0g==} + /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -8973,7 +8979,7 @@ packages: mlly: 1.4.2 pathe: 1.1.1 pkg-types: 1.0.3 - scule: 1.0.0 + scule: 1.1.0 strip-literal: 1.3.0 unplugin: 1.5.0 transitivePeerDependencies: diff --git a/test/fixtures/basic-types/types.ts b/test/fixtures/basic-types/types.ts index 7610bfe39f..7f8127dd33 100644 --- a/test/fixtures/basic-types/types.ts +++ b/test/fixtures/basic-types/types.ts @@ -3,7 +3,7 @@ import type { Ref } from 'vue' import type { FetchError } from 'ofetch' import type { NavigationFailure, RouteLocationNormalized, RouteLocationRaw, Router, useRouter as vueUseRouter } from '#vue-router' -import type { AppConfig, RuntimeValue } from 'nuxt/schema' +import type { AppConfig, RuntimeValue, UpperSnakeCase } from 'nuxt/schema' import { defineNuxtConfig } from 'nuxt/config' import { callWithNuxt, isVue3 } from '#app' import type { NavigateToOptions } from '#app/composables/router' @@ -271,6 +271,21 @@ describe('runtimeConfig', () => { expectTypeOf(val.runtimeConfig!.public!.ids).toEqualTypeOf, 'You can override this value at runtime with NUXT_PUBLIC_IDS'>>() expectTypeOf(val.runtimeConfig!.unknown).toEqualTypeOf() }) + + it('correctly converts different kinds of names to snake case', () => { + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP123NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'TEST_APP_NAME'>() + expectTypeOf>().toEqualTypeOf<'T'>() + expectTypeOf>().toEqualTypeOf<'T'>() + }) }) describe('head', () => {