Skip to content

Commit 5e0bfb1

Browse files
authored
fix(style): gale string type checking bug (#7)
1 parent 7eec17a commit 5e0bfb1

4 files changed

Lines changed: 57 additions & 11 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
ecma-pnpm: true
2020
- run: pnpm install
2121
- run: task check
22+
- run: task test
2223
- run: task build
2324

2425
build-docs:

Taskfile.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ tasks:
1717
- task: ecma:fix
1818
build:
1919
- task: ecma:lib-build
20+
test:
21+
- task: ecma:test
2022

2123
doc:
2224
- task: ecma:doc-build

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pistonite/celera",
3-
"version": "0.2.0",
3+
"version": "0.2.1",
44
"type": "module",
55
"private": true,
66
"description": "In-house UI framework",

src/style/gale.ts

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,22 +188,65 @@ export type GaleKeys<T extends string> = T | GaleBuiltinKey;
188188
/** Hook to be called inside a component to get the `m` function. See {@link gale} */
189189
export type GaleHook<T extends string> = () => GaleFn<T>;
190190
/** The `m` function that turns a style string into class names */
191-
export type GaleFn<T extends string> = <K extends string>(classes: GaleString<K, T>) => string;
191+
export type GaleFn<T extends string> = <K extends string>(classes: GaleString<K, T, []>) => string;
192192

193193
/** Type-safe, space-separated style idents */
194-
export type GaleString<K extends string, T extends string> = K extends T
195-
? K
196-
: K extends `${infer U} ${infer N}`
197-
? U extends T
198-
? GaleString<N, T> extends N
199-
? `${U} ${GaleString<N, T>}`
200-
: Prettify<GaleString<N, T> & { After: U }>
201-
: { InvalidStyleIdent: U }
202-
: { InvalidStyleIdent: K };
194+
export type GaleString<K extends string, T extends string, S extends string[]> = K extends S[number]
195+
? { DuplicateStyleIdent: K }
196+
: K extends T
197+
? K
198+
: K extends `${infer U} ${infer N}`
199+
? U extends S[number]
200+
? { DuplicateStyleIdent: U }
201+
: U extends T
202+
? GaleString<N, T, [...S, U]> extends N
203+
? `${U} ${GaleString<N, T, [...S, U]>}`
204+
: Prettify<ExtendAfter<GaleString<N, T, [...S, U]>, U>>
205+
: { InvalidStyleIdent: U }
206+
: { InvalidStyleIdent: K };
207+
type ExtendAfter<T, U> = T extends { After: string } ? T : T & { After: U };
203208
type Prettify<T> = {
204209
[K in keyof T]: T[K];
205210
} & {};
206211

212+
if (import.meta.vitest) {
213+
const { test, expectTypeOf } = import.meta.vitest;
214+
type Validate<K extends string> = GaleString<K, "foo" | "bar" | `long-${number}`, []>;
215+
test("GaleString", () => {
216+
expectTypeOf<Validate<"bar">>().toExtend<string>();
217+
expectTypeOf<Validate<"foo">>().toExtend<string>();
218+
expectTypeOf<Validate<"biz">>().toEqualTypeOf<{ InvalidStyleIdent: "biz" }>();
219+
220+
expectTypeOf<Validate<"foo bar">>().toExtend<string>();
221+
expectTypeOf<Validate<"foo foo">>().toEqualTypeOf<{
222+
DuplicateStyleIdent: "foo";
223+
After: "foo";
224+
}>();
225+
expectTypeOf<Validate<"foo biz">>().toEqualTypeOf<{
226+
InvalidStyleIdent: "biz";
227+
After: "foo";
228+
}>();
229+
expectTypeOf<Validate<"biz foo">>().toEqualTypeOf<{ InvalidStyleIdent: "biz" }>();
230+
expectTypeOf<Validate<"foo bar biz">>().toEqualTypeOf<{
231+
InvalidStyleIdent: "biz";
232+
After: "bar";
233+
}>();
234+
expectTypeOf<Validate<"foo biz biz">>().toEqualTypeOf<{
235+
InvalidStyleIdent: "biz";
236+
After: "foo";
237+
}>();
238+
expectTypeOf<Validate<"foo biz bar">>().toEqualTypeOf<{
239+
InvalidStyleIdent: "biz";
240+
After: "foo";
241+
}>();
242+
expectTypeOf<Validate<"biz biz bar">>().toEqualTypeOf<{ InvalidStyleIdent: "biz" }>();
243+
expectTypeOf<Validate<"biz biz">>().toEqualTypeOf<{ InvalidStyleIdent: "biz" }>();
244+
expectTypeOf<
245+
Validate<"foo bar long-1 long-2 long-3 long-4 long-5 big long-6 long-7 long-8 long-9">
246+
>().toEqualTypeOf<{ InvalidStyleIdent: "big"; After: "long-5" }>();
247+
});
248+
}
249+
207250
/** Built-in styles for {@link gale} */
208251
export const GALE_BUILTIN_STYLES = {
209252
"wh-100v": {

0 commit comments

Comments
 (0)