Skip to content

Commit a87a875

Browse files
author
gauravchugh
committed
feat(lit-query): fix type inference and monorepo integration
- Fix createQueriesController tuple type inference with recursive types - Add DataTag support to queryOptions - Fix build config and vitest custom-condition resolution - Fix example install scripts for standalone bootstrap
1 parent d545bf7 commit a87a875

File tree

11 files changed

+259
-128
lines changed

11 files changed

+259
-128
lines changed

packages/lit-query/package.json

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -30,63 +30,64 @@
3030
},
3131
"scripts": {
3232
"compile": "tsc --build",
33-
"build": "npm run build:esm && npm run build:cjs",
33+
"build:deps": "pnpm --dir ../query-core run build",
34+
"build": "pnpm run build:deps && pnpm run build:esm && pnpm run build:cjs",
3435
"build:esm": "tsc -p tsconfig.build.json",
3536
"build:cjs": "node -e \"require('node:fs').rmSync('dist-cjs', { recursive: true, force: true })\" && tsc -p tsconfig.build.cjs.json && node scripts/write-cjs-package.mjs",
3637
"test:types": "tsc --noEmit",
37-
"typecheck": "npm run test:types",
38+
"typecheck": "pnpm run test:types",
3839
"test:eslint": "eslint .",
39-
"lint": "npm run test:eslint",
40+
"lint": "pnpm run test:eslint",
4041
"lint:fix": "eslint . --fix",
4142
"format": "prettier --write .",
4243
"format:check": "prettier --check .",
4344
"test:lib": "vitest run",
44-
"test": "npm run test:lib",
45+
"test": "pnpm run test:lib",
4546
"test:lib:dev": "vitest",
46-
"test:watch": "npm run test:lib:dev",
47+
"test:watch": "pnpm run test:lib:dev",
4748
"package:check": "node scripts/check-package.mjs",
4849
"package:smoke:cjs-types": "node scripts/check-cjs-types-smoke.mjs",
49-
"test:build": "publint --strict && attw --pack && npm run package:smoke:cjs-types",
50-
"package:build": "npm run build && npm run test:build",
51-
"measure:bundle": "npm run build && node scripts/measure-bundle.mjs",
50+
"test:build": "publint --strict && attw --pack && pnpm run package:smoke:cjs-types",
51+
"package:build": "pnpm run build && pnpm run test:build",
52+
"measure:bundle": "pnpm run build && node scripts/measure-bundle.mjs",
5253
"measure:bundle:raw": "node scripts/measure-bundle.mjs",
53-
"perf:l3": "npm run build && node scripts/l3-stress.mjs",
54+
"perf:l3": "pnpm run build && node scripts/l3-stress.mjs",
5455
"perf:l3:raw": "node scripts/l3-stress.mjs",
5556
"example:install": "npm --prefix examples/lit-query-e2e-app install",
56-
"example:dev": "npm --prefix examples/lit-query-e2e-app run dev",
57-
"example:e2e": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e",
58-
"example:e2e:headed": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:headed",
59-
"example:e2e:query-error": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:query-error",
60-
"example:e2e:mutation-error": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:mutation-error",
61-
"example:e2e:refetch-button": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:refetch-button",
62-
"example:e2e:lifecycle-reconnect": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:lifecycle-reconnect",
63-
"example:e2e:lifecycle-contract": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:lifecycle-contract",
64-
"example:e2e:all": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:all",
65-
"example:e2e:all:nobuild": "npm --prefix examples/lit-query-e2e-app run e2e:all",
66-
"example:e2e:all:headed": "npm run build && npm --prefix examples/lit-query-e2e-app run e2e:all:headed",
57+
"example:dev": "pnpm --dir examples/lit-query-e2e-app run dev",
58+
"example:e2e": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e",
59+
"example:e2e:headed": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:headed",
60+
"example:e2e:query-error": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:query-error",
61+
"example:e2e:mutation-error": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:mutation-error",
62+
"example:e2e:refetch-button": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:refetch-button",
63+
"example:e2e:lifecycle-reconnect": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:lifecycle-reconnect",
64+
"example:e2e:lifecycle-contract": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:lifecycle-contract",
65+
"example:e2e:all": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:all",
66+
"example:e2e:all:nobuild": "pnpm --dir examples/lit-query-e2e-app run e2e:all",
67+
"example:e2e:all:headed": "pnpm run build && pnpm --dir examples/lit-query-e2e-app run e2e:all:headed",
6768
"example:pagination:install": "npm --prefix examples/lit-query-pagination-app install",
68-
"example:pagination:dev": "npm --prefix examples/lit-query-pagination-app run dev",
69-
"example:pagination:e2e": "npm run build && npm --prefix examples/lit-query-pagination-app run e2e",
70-
"example:pagination:e2e:prefetch": "npm run build && npm --prefix examples/lit-query-pagination-app run e2e:prefetch",
71-
"example:pagination:e2e:error": "npm run build && npm --prefix examples/lit-query-pagination-app run e2e:error",
72-
"example:pagination:e2e:mutations": "npm run build && npm --prefix examples/lit-query-pagination-app run e2e:mutations",
73-
"example:pagination:e2e:boundary": "npm run build && npm --prefix examples/lit-query-pagination-app run e2e:boundary",
74-
"example:pagination:e2e:all": "npm run build && npm --prefix examples/lit-query-pagination-app run e2e:all",
75-
"example:pagination:e2e:all:headed": "npm run build && npm --prefix examples/lit-query-pagination-app run e2e:all:headed",
69+
"example:pagination:dev": "pnpm --dir examples/lit-query-pagination-app run dev",
70+
"example:pagination:e2e": "pnpm run build && pnpm --dir examples/lit-query-pagination-app run e2e",
71+
"example:pagination:e2e:prefetch": "pnpm run build && pnpm --dir examples/lit-query-pagination-app run e2e:prefetch",
72+
"example:pagination:e2e:error": "pnpm run build && pnpm --dir examples/lit-query-pagination-app run e2e:error",
73+
"example:pagination:e2e:mutations": "pnpm run build && pnpm --dir examples/lit-query-pagination-app run e2e:mutations",
74+
"example:pagination:e2e:boundary": "pnpm run build && pnpm --dir examples/lit-query-pagination-app run e2e:boundary",
75+
"example:pagination:e2e:all": "pnpm run build && pnpm --dir examples/lit-query-pagination-app run e2e:all",
76+
"example:pagination:e2e:all:headed": "pnpm run build && pnpm --dir examples/lit-query-pagination-app run e2e:all:headed",
7677
"example:ssr:install": "npm --prefix examples/lit-query-ssr-app install",
77-
"example:ssr:dev": "npm run build && npm --prefix examples/lit-query-ssr-app run dev",
78-
"example:ssr:dev:public-origin": "npm run build && npm --prefix examples/lit-query-ssr-app run dev:public-origin",
79-
"example:ssr:e2e:default": "npm run build && npm --prefix examples/lit-query-ssr-app run e2e",
80-
"example:ssr:e2e:error": "npm run build && npm --prefix examples/lit-query-ssr-app run e2e:error",
81-
"example:ssr:e2e:refreshing": "npm run build && npm --prefix examples/lit-query-ssr-app run e2e:refreshing",
82-
"example:ssr:e2e:public-origin": "npm run build && npm --prefix examples/lit-query-ssr-app run e2e:public-origin",
83-
"example:ssr:e2e": "npm run example:ssr:e2e:default && npm run example:ssr:e2e:public-origin",
84-
"example:ssr:e2e:all:default": "npm run build && npm --prefix examples/lit-query-ssr-app run e2e:all",
85-
"example:ssr:e2e:all:nobuild": "npm --prefix examples/lit-query-ssr-app run e2e:all && npm --prefix examples/lit-query-ssr-app run e2e:public-origin",
86-
"example:ssr:e2e:all": "npm run example:ssr:e2e:all:default && npm run example:ssr:e2e:public-origin",
87-
"demo:setup": "npm run example:install && npm --prefix examples/lit-query-e2e-app exec playwright install chromium",
88-
"demo:gate": "npm run typecheck && npm run lint && npm run format:check && npm test && npm run build && npm run package:check && npm run package:build && npm run example:e2e:all:nobuild && npm run example:ssr:e2e:all:nobuild && npm run measure:bundle:raw && npm run perf:l3:raw",
89-
"demo:gate:headed": "npm run build && npm run example:e2e:all:headed"
78+
"example:ssr:dev": "pnpm run build && pnpm --dir examples/lit-query-ssr-app run dev",
79+
"example:ssr:dev:public-origin": "pnpm run build && pnpm --dir examples/lit-query-ssr-app run dev:public-origin",
80+
"example:ssr:e2e:default": "pnpm run build && pnpm --dir examples/lit-query-ssr-app run e2e",
81+
"example:ssr:e2e:error": "pnpm run build && pnpm --dir examples/lit-query-ssr-app run e2e:error",
82+
"example:ssr:e2e:refreshing": "pnpm run build && pnpm --dir examples/lit-query-ssr-app run e2e:refreshing",
83+
"example:ssr:e2e:public-origin": "pnpm run build && pnpm --dir examples/lit-query-ssr-app run e2e:public-origin",
84+
"example:ssr:e2e": "pnpm run example:ssr:e2e:default && pnpm run example:ssr:e2e:public-origin",
85+
"example:ssr:e2e:all:default": "pnpm run build && pnpm --dir examples/lit-query-ssr-app run e2e:all",
86+
"example:ssr:e2e:all:nobuild": "pnpm --dir examples/lit-query-ssr-app run e2e:all && pnpm --dir examples/lit-query-ssr-app run e2e:public-origin",
87+
"example:ssr:e2e:all": "pnpm run example:ssr:e2e:all:default && pnpm run example:ssr:e2e:public-origin",
88+
"demo:setup": "pnpm run example:install && npm --prefix examples/lit-query-e2e-app exec playwright install chromium",
89+
"demo:gate": "pnpm run typecheck && pnpm run lint && pnpm run format:check && pnpm test && pnpm run build && pnpm run package:check && pnpm run package:build && pnpm run example:e2e:all:nobuild && pnpm run example:ssr:e2e:all:nobuild && pnpm run measure:bundle:raw && pnpm run perf:l3:raw",
90+
"demo:gate:headed": "pnpm run build && pnpm run example:e2e:all:headed"
9091
},
9192
"dependencies": {
9293
"@lit/context": "^1.1.6",

packages/lit-query/scripts/check-cjs-types-smoke.mjs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { promisify } from 'node:util'
77

88
const execFile = promisify(execFileCallback)
99
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'
10+
const pnpmCommand = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
1011
const projectDir = resolve(dirname(fileURLToPath(import.meta.url)), '..')
1112
const typeRootsDir = resolve(projectDir, 'node_modules', '@types')
1213
const tscEntrypoint = resolve(
@@ -37,13 +38,21 @@ async function packProject(destination) {
3738
await mkdir(destination, { recursive: true })
3839

3940
const { stdout } = await execFile(
40-
npmCommand,
41+
pnpmCommand,
4142
['pack', '--json', '--pack-destination', destination],
4243
{
4344
cwd: projectDir,
4445
},
4546
)
46-
const [{ filename }] = JSON.parse(stdout)
47+
const packResult = JSON.parse(stdout)
48+
const filename = Array.isArray(packResult)
49+
? packResult[0]?.filename
50+
: packResult?.filename
51+
52+
if (typeof filename !== 'string') {
53+
throw new Error(`Unexpected pack output: ${stdout}`)
54+
}
55+
4756
return resolve(destination, filename)
4857
}
4958

packages/lit-query/src/QueryClientProvider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ContextProvider } from '@lit/context'
22
import type { QueryClient } from '@tanstack/query-core'
3+
import type { TemplateResult } from 'lit'
34
import { LitElement, html } from 'lit'
45
import {
56
createMissingQueryClientError,
@@ -66,7 +67,7 @@ export class QueryClientProvider extends LitElement {
6667
}
6768
}
6869

69-
render() {
70+
render(): TemplateResult {
7071
return html`<slot></slot>`
7172
}
7273

packages/lit-query/src/createQueriesController.ts

Lines changed: 140 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
QueriesObserver,
33
type DefaultError,
44
type DefinedQueryObserverResult,
5+
type OmitKeyof,
56
type QueriesObserverOptions,
67
type QueryFunction,
78
type QueryKey,
@@ -27,8 +28,48 @@ export type CreateQueriesInput<
2728
TQueryKey extends QueryKey = QueryKey,
2829
> = QueryObserverOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>
2930

31+
type CreateQueriesInputForController<
32+
TQueryFnData = unknown,
33+
TError = DefaultError,
34+
TData = TQueryFnData,
35+
TQueryKey extends QueryKey = QueryKey,
36+
> = OmitKeyof<CreateQueriesInput<TQueryFnData, TError, TData, TQueryKey>, never>
37+
38+
type MAXIMUM_DEPTH = 20
39+
3040
type SkipTokenForCreateQueries = symbol
3141

42+
type GetCreateQueriesInput<T> = T extends {
43+
queryFnData: infer TQueryFnData
44+
error?: infer TError
45+
data: infer TData
46+
}
47+
? CreateQueriesInputForController<TQueryFnData, TError, TData>
48+
: T extends { queryFnData: infer TQueryFnData; error?: infer TError }
49+
? CreateQueriesInputForController<TQueryFnData, TError>
50+
: T extends { data: infer TData; error?: infer TError }
51+
? CreateQueriesInputForController<unknown, TError, TData>
52+
: T extends [infer TQueryFnData, infer TError, infer TData]
53+
? CreateQueriesInputForController<TQueryFnData, TError, TData>
54+
: T extends [infer TQueryFnData, infer TError]
55+
? CreateQueriesInputForController<TQueryFnData, TError>
56+
: T extends [infer TQueryFnData]
57+
? CreateQueriesInputForController<TQueryFnData>
58+
: T extends {
59+
queryFn?:
60+
| QueryFunction<infer TQueryFnData, infer TQueryKey>
61+
| SkipTokenForCreateQueries
62+
select?: (data: any) => infer TData
63+
throwOnError?: ThrowOnError<any, infer TError, any, any>
64+
}
65+
? CreateQueriesInputForController<
66+
TQueryFnData,
67+
unknown extends TError ? DefaultError : TError,
68+
unknown extends TData ? TQueryFnData : TData,
69+
TQueryKey
70+
>
71+
: CreateQueriesInputForController
72+
3273
type GetDefinedOrUndefinedCreateQueriesResult<
3374
T,
3475
TData,
@@ -49,47 +90,102 @@ type GetDefinedOrUndefinedCreateQueriesResult<
4990
: QueryObserverResult<TData, TError>
5091
: QueryObserverResult<TData, TError>
5192

52-
type GetCreateQueriesResult<T> =
53-
T extends { queryFnData: any; error?: infer TError; data: infer TData }
54-
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
55-
: T extends { queryFnData: infer TQueryFnData; error?: infer TError }
56-
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData, TError>
57-
: T extends { data: infer TData; error?: infer TError }
93+
type GetCreateQueriesResult<T> = T extends {
94+
queryFnData: any
95+
error?: infer TError
96+
data: infer TData
97+
}
98+
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
99+
: T extends { queryFnData: infer TQueryFnData; error?: infer TError }
100+
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData, TError>
101+
: T extends { data: infer TData; error?: infer TError }
102+
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
103+
: T extends [any, infer TError, infer TData]
58104
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
59-
: T extends [any, infer TError, infer TData]
60-
? GetDefinedOrUndefinedCreateQueriesResult<T, TData, TError>
61-
: T extends [infer TQueryFnData, infer TError]
62-
? GetDefinedOrUndefinedCreateQueriesResult<
63-
T,
64-
TQueryFnData,
65-
TError
105+
: T extends [infer TQueryFnData, infer TError]
106+
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData, TError>
107+
: T extends [infer TQueryFnData]
108+
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData>
109+
: T extends {
110+
queryFn?:
111+
| QueryFunction<infer TQueryFnData, any>
112+
| SkipTokenForCreateQueries
113+
select?: (data: any) => infer TData
114+
throwOnError?: ThrowOnError<any, infer TError, any, any>
115+
}
116+
? GetDefinedOrUndefinedCreateQueriesResult<
117+
T,
118+
unknown extends TData ? TQueryFnData : TData,
119+
unknown extends TError ? DefaultError : TError
120+
>
121+
: QueryObserverResult
122+
123+
export type CreateQueriesOptions<
124+
T extends Array<any>,
125+
TResults extends Array<any> = [],
126+
TDepth extends ReadonlyArray<number> = [],
127+
> = TDepth['length'] extends MAXIMUM_DEPTH
128+
? Array<CreateQueriesInputForController>
129+
: T extends []
130+
? []
131+
: T extends [infer Head]
132+
? [...TResults, GetCreateQueriesInput<Head>]
133+
: T extends [infer Head, ...infer Tails]
134+
? CreateQueriesOptions<
135+
[...Tails],
136+
[...TResults, GetCreateQueriesInput<Head>],
137+
[...TDepth, 1]
138+
>
139+
: ReadonlyArray<unknown> extends T
140+
? T
141+
: T extends Array<
142+
CreateQueriesInputForController<
143+
infer TQueryFnData,
144+
infer TError,
145+
infer TData,
146+
infer TQueryKey
147+
>
66148
>
67-
: T extends [infer TQueryFnData]
68-
? GetDefinedOrUndefinedCreateQueriesResult<T, TQueryFnData>
69-
: T extends {
70-
queryFn?:
71-
| QueryFunction<infer TQueryFnData, any>
72-
| SkipTokenForCreateQueries
73-
select?: (data: any) => infer TData
74-
throwOnError?: ThrowOnError<any, infer TError, any, any>
75-
}
76-
? GetDefinedOrUndefinedCreateQueriesResult<
77-
T,
78-
unknown extends TData ? TQueryFnData : TData,
79-
unknown extends TError ? DefaultError : TError
80-
>
81-
: QueryObserverResult
82-
83-
export type CreateQueriesResults<TQueryOptions extends readonly unknown[]> = {
84-
[Index in keyof TQueryOptions]: GetCreateQueriesResult<TQueryOptions[Index]>
85-
}
149+
? Array<
150+
CreateQueriesInputForController<
151+
TQueryFnData,
152+
TError,
153+
TData,
154+
TQueryKey
155+
>
156+
>
157+
: Array<CreateQueriesInputForController>
158+
159+
export type CreateQueriesResults<
160+
T extends Array<any>,
161+
TResults extends Array<any> = [],
162+
TDepth extends ReadonlyArray<number> = [],
163+
> = TDepth['length'] extends MAXIMUM_DEPTH
164+
? Array<QueryObserverResult>
165+
: T extends []
166+
? []
167+
: T extends [infer Head]
168+
? [...TResults, GetCreateQueriesResult<Head>]
169+
: T extends [infer Head, ...infer Tails]
170+
? CreateQueriesResults<
171+
[...Tails],
172+
[...TResults, GetCreateQueriesResult<Head>],
173+
[...TDepth, 1]
174+
>
175+
: { [K in keyof T]: GetCreateQueriesResult<T[K]> }
86176

87177
export type CreateQueriesControllerOptions<
88-
TQueryOptions extends readonly CreateQueriesInput[] =
89-
readonly CreateQueriesInput[],
178+
TQueryOptions extends Array<any> = Array<any>,
90179
TCombinedResult = CreateQueriesResults<TQueryOptions>,
91180
> = {
92-
queries: Accessor<TQueryOptions>
181+
queries: Accessor<
182+
| readonly [...CreateQueriesOptions<TQueryOptions>]
183+
| readonly [
184+
...{
185+
[K in keyof TQueryOptions]: GetCreateQueriesInput<TQueryOptions[K]>
186+
},
187+
]
188+
>
93189
combine?: (result: CreateQueriesResults<TQueryOptions>) => TCombinedResult
94190
}
95191

@@ -143,21 +239,24 @@ function resolveQueriesOptions<TCombinedResult>(
143239
} {
144240
const resolvedOptions = readAccessor(optionsAccessor)
145241
const resolvedQueries = readAccessor(resolvedOptions.queries)
242+
const combine =
243+
resolvedOptions.combine as QueriesObserverOptions<TCombinedResult>['combine']
146244

147245
return {
148-
queries: resolvedQueries.map((query: QueryObserverOptions) => {
149-
const defaulted = client.defaultQueryOptions(query)
246+
queries: resolvedQueries.map((query) => {
247+
const defaulted = client.defaultQueryOptions(
248+
query as QueryObserverOptions,
249+
)
150250
;(defaulted as { _optimisticResults?: 'optimistic' })._optimisticResults =
151251
'optimistic'
152252
return defaulted
153253
}),
154-
combine:
155-
resolvedOptions.combine as QueriesObserverOptions<TCombinedResult>['combine'],
254+
combine,
156255
}
157256
}
158257

159258
class QueriesController<
160-
TQueryOptions extends readonly CreateQueriesInput[],
259+
TQueryOptions extends Array<any>,
161260
TCombinedResult,
162261
> extends BaseController<TCombinedResult> {
163262
private readonly options: Accessor<
@@ -367,7 +466,7 @@ class QueriesController<
367466
}
368467

369468
export function createQueriesController<
370-
TQueryOptions extends readonly CreateQueriesInput[],
469+
TQueryOptions extends Array<any>,
371470
TCombinedResult = CreateQueriesResults<TQueryOptions>,
372471
>(
373472
host: ReactiveControllerHost,

0 commit comments

Comments
 (0)