Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(schema): use scule types for runtimeConfig type hints #23696

Merged
merged 33 commits into from Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4b19bfc
fix: UpperSnakeCase type not correctly handling strings already in up…
luc122c Oct 16, 2023
fb6e2b7
ci: add tests for values already in upper snake case
luc122c Oct 16, 2023
190f8a7
Merge branch 'main' into upper-snake-case-fix
luc122c Oct 16, 2023
04d48fd
ci: use `assertType` syntax for type tests
luc122c Oct 16, 2023
4d938ca
ci: remove `only`
luc122c Oct 16, 2023
3c539a7
ci: fix TypeScript warning for tests
luc122c Oct 16, 2023
ada680b
test: remove `[][0]`
danielroe Oct 16, 2023
c52d8aa
Merge remote-tracking branch 'origin/main' into upper-snake-case-fix
danielroe Oct 16, 2023
922b33c
Fix two of the tests
luc122c Oct 16, 2023
dce3655
test: format input in camelCase
luc122c Oct 16, 2023
3f09698
Revert "test: format input in camelCase"
luc122c Oct 16, 2023
62c8054
test: respect existing rules for conversion
luc122c Oct 16, 2023
23d8b1e
Merge branch 'main' into upper-snake-case-fix
luc122c Oct 19, 2023
734f149
ci: implement check for when input is already in upper case
luc122c Oct 19, 2023
38d3b62
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 19, 2023
d209afe
test: add additional runtime test
luc122c Oct 19, 2023
9fdb9a8
test: add additional type check for values beginning with an underscore
luc122c Oct 19, 2023
247260f
Merge branch 'main' into upper-snake-case-fix
luc122c Oct 20, 2023
45f93d9
Merge branch 'main' into upper-snake-case-fix
luc122c Oct 20, 2023
b54b81f
Merge remote-tracking branch 'origin/main' into upper-snake-case-fix
danielroe Oct 20, 2023
cf2a33a
test: add more type assertion tests to cover other cases
danielroe Oct 20, 2023
8417d3b
test: remove runtime tests
danielroe Oct 20, 2023
ee68efe
test: add test cases for a single character
luc122c Oct 20, 2023
f5e20e7
Merge branch 'main' into upper-snake-case-fix
luc122c Oct 20, 2023
1f32cc3
Merge remote-tracking branch 'origin/main' into upper-snake-case-fix
danielroe Oct 23, 2023
c5f9a49
refactor: use type from `scule`
danielroe Oct 23, 2023
6748b15
Merge commit '5fea1728830777ac8942c74ba8751822716a7aae' into upper-sn…
luc122c Oct 25, 2023
960335c
test: use SnakeCase type rather than returntype of snakeCase function
luc122c Oct 27, 2023
0f38cd7
Apply suggestions from code review
luc122c Oct 27, 2023
f894d0b
Merge commit '37d64a615b7bb4a13a2e722a925764100f832af3' into upper-sn…
luc122c Nov 15, 2023
f6ece85
chore(deps): upgrade scule
luc122c Nov 15, 2023
5e615ed
chore: remove comment
luc122c Nov 15, 2023
73bd6b9
Merge branch 'main' into upper-snake-case-fix
luc122c Nov 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/schema/package.json
Expand Up @@ -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",
Expand Down
39 changes: 2 additions & 37 deletions packages/schema/src/types/config.ts
Expand Up @@ -4,50 +4,15 @@ 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'
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>
export type UpperSnakeCase<S extends string> = Uppercase<SnakeCase<S>>

const message = Symbol('message')
export type RuntimeValue<T, B extends string> = T & { [message]?: B }
Expand Down
10 changes: 8 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion test/fixtures/basic-types/types.ts
Expand Up @@ -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'
Expand Down Expand Up @@ -271,6 +271,21 @@ describe('runtimeConfig', () => {
expectTypeOf(val.runtimeConfig!.public!.ids).toEqualTypeOf<undefined | RuntimeValue<Array<number>, 'You can override this value at runtime with NUXT_PUBLIC_IDS'>>()
expectTypeOf(val.runtimeConfig!.unknown).toEqualTypeOf<unknown>()
})

it('correctly converts different kinds of names to snake case', () => {
expectTypeOf<UpperSnakeCase<'testAppName'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'TEST_APP_NAME'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'test_APP_NAME'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'test_app_NAME'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'testAppNAME'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'testApp123NAME'>>().toEqualTypeOf<'TEST_APP123NAME'>()
expectTypeOf<UpperSnakeCase<'testAPPName'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'testAPP_Name'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'test_APP_Name'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'TESTAppName'>>().toEqualTypeOf<'TEST_APP_NAME'>()
expectTypeOf<UpperSnakeCase<'t'>>().toEqualTypeOf<'T'>()
expectTypeOf<UpperSnakeCase<'T'>>().toEqualTypeOf<'T'>()
})
})

describe('head', () => {
Expand Down