kirby-types 0.7.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -6
- package/index.d.ts +10 -5
- package/package.json +9 -9
- package/src/query.d.ts +219 -5
package/README.md
CHANGED
|
@@ -20,16 +20,39 @@ yarn add -D kirby-types
|
|
|
20
20
|
## Basic Usage
|
|
21
21
|
|
|
22
22
|
```ts
|
|
23
|
-
import type { KirbyQuery } from "kirby-types";
|
|
23
|
+
import type { KirbyQuery, ParseKirbyQuery } from "kirby-types";
|
|
24
24
|
|
|
25
25
|
// Strictly typed query
|
|
26
26
|
const query: KirbyQuery = 'page.children.filterBy("featured", true)';
|
|
27
27
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
// Parse query strings into structured objects
|
|
29
|
+
type BasicQuery = ParseKirbyQuery<"site">;
|
|
30
|
+
// Result: { model: "site"; chain: [] }
|
|
31
|
+
|
|
32
|
+
type DotNotationQuery = ParseKirbyQuery<"page.children.listed">;
|
|
33
|
+
// Result: {
|
|
34
|
+
// model: "page";
|
|
35
|
+
// chain: [
|
|
36
|
+
// { type: "property"; name: "children" },
|
|
37
|
+
// { type: "property"; name: "listed" }
|
|
38
|
+
// ]
|
|
39
|
+
// }
|
|
40
|
+
|
|
41
|
+
type MethodQuery = ParseKirbyQuery<'site("home")'>;
|
|
42
|
+
// Result: {
|
|
43
|
+
// model: "site";
|
|
44
|
+
// chain: [{ type: "method"; name: "site"; params: '"home"' }]
|
|
45
|
+
// }
|
|
46
|
+
|
|
47
|
+
type ComplexQuery =
|
|
48
|
+
ParseKirbyQuery<'page.children.filterBy("status", "published")'>;
|
|
49
|
+
// Result: {
|
|
50
|
+
// model: "page";
|
|
51
|
+
// chain: [
|
|
52
|
+
// { type: "property"; name: "children" },
|
|
53
|
+
// { type: "method"; name: "filterBy"; params: '"status", "published"' }
|
|
54
|
+
// ]
|
|
55
|
+
// }
|
|
33
56
|
```
|
|
34
57
|
|
|
35
58
|
## API
|
|
@@ -44,6 +67,7 @@ By clicking on a type name, you will be redirected to the corresponding TypeScri
|
|
|
44
67
|
|
|
45
68
|
- [`KirbyQueryModel`](./src/query.d.ts) - Matches any supported KirbyQL model.
|
|
46
69
|
- [`KirbyQuery`](./src/query.d.ts) - Matches a KirbyQL [`query`](https://getkirby.com/docs/guide/blueprints/query-language).
|
|
70
|
+
- [`ParseKirbyQuery`](./src/query.d.ts) - Parses a KirbyQL query string into a structured object with model and chain information.
|
|
47
71
|
|
|
48
72
|
### Blocks
|
|
49
73
|
|
package/index.d.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
export { KirbyApiResponse } from "./src/api";
|
|
2
|
-
export {
|
|
1
|
+
export type { KirbyApiResponse } from "./src/api";
|
|
2
|
+
export type {
|
|
3
3
|
KirbyBlock,
|
|
4
4
|
KirbyDefaultBlocks,
|
|
5
5
|
KirbyDefaultBlockType,
|
|
6
6
|
} from "./src/blocks";
|
|
7
|
-
export {
|
|
7
|
+
export type {
|
|
8
8
|
KirbyQueryRequest,
|
|
9
9
|
KirbyQueryResponse,
|
|
10
10
|
KirbyQuerySchema,
|
|
11
11
|
} from "./src/kql";
|
|
12
|
-
export { KirbyLayout, KirbyLayoutColumn } from "./src/layout";
|
|
13
|
-
export {
|
|
12
|
+
export type { KirbyLayout, KirbyLayoutColumn } from "./src/layout";
|
|
13
|
+
export type {
|
|
14
|
+
KirbyQuery,
|
|
15
|
+
KirbyQueryChain,
|
|
16
|
+
KirbyQueryModel,
|
|
17
|
+
ParseKirbyQuery,
|
|
18
|
+
} from "./src/query";
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kirby-types",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"packageManager": "pnpm@9.
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"packageManager": "pnpm@9.15.9",
|
|
6
6
|
"description": "A collection of TypeScript types for the Kirby CMS",
|
|
7
7
|
"author": "Johann Schopplich <hello@johannschopplich.com>",
|
|
8
8
|
"license": "MIT",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
27
|
"types": "./index.d.ts",
|
|
28
|
-
"
|
|
28
|
+
"default": "./index.js"
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"types": "./index.d.ts",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"test": "tsd -f \"test/**/*.test-d.ts\""
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@antfu/eslint-config": "^3.
|
|
46
|
-
"bumpp": "^9.
|
|
47
|
-
"eslint": "^9.
|
|
48
|
-
"prettier": "^3.
|
|
49
|
-
"tsd": "^0.
|
|
50
|
-
"typescript": "^5.
|
|
45
|
+
"@antfu/eslint-config": "^3.16.0",
|
|
46
|
+
"bumpp": "^9.11.1",
|
|
47
|
+
"eslint": "^9.27.0",
|
|
48
|
+
"prettier": "^3.5.3",
|
|
49
|
+
"tsd": "^0.32.0",
|
|
50
|
+
"typescript": "^5.8.3"
|
|
51
51
|
}
|
|
52
52
|
}
|
package/src/query.d.ts
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents all supported model names in Kirby Query Language.
|
|
3
|
+
*
|
|
4
|
+
* This type includes all built-in Kirby models that can be used as the starting point
|
|
5
|
+
* for queries, plus any custom models you define.
|
|
6
|
+
*
|
|
7
|
+
* Built-in models include:
|
|
8
|
+
* - `site` - The site object
|
|
9
|
+
* - `page` - A page object
|
|
10
|
+
* - `user` - A user object
|
|
11
|
+
* - `file` - A file object
|
|
12
|
+
* - `collection` - A collection object
|
|
13
|
+
* - `kirby` - The Kirby instance
|
|
14
|
+
* - `content` - Content field data
|
|
15
|
+
* - `item` - Generic item in collections
|
|
16
|
+
* - `arrayItem` - An item in an array
|
|
17
|
+
* - `structureItem` - An item in a structure field
|
|
18
|
+
* - `block` - A block in the blocks field
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* // Using built-in models
|
|
23
|
+
* const siteModel: KirbyQueryModel = "site";
|
|
24
|
+
* const pageModel: KirbyQueryModel = "page";
|
|
25
|
+
*
|
|
26
|
+
* // Using with custom models
|
|
27
|
+
* type CustomModels = "product" | "category";
|
|
28
|
+
* const customModel: KirbyQueryModel<CustomModels> = "product";
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @template CustomModel - Additional custom model names to include
|
|
32
|
+
*/
|
|
1
33
|
export type KirbyQueryModel<CustomModel extends string = never> =
|
|
2
34
|
| "collection"
|
|
3
35
|
| "kirby"
|
|
@@ -12,22 +44,204 @@ export type KirbyQueryModel<CustomModel extends string = never> =
|
|
|
12
44
|
| "block"
|
|
13
45
|
| CustomModel;
|
|
14
46
|
|
|
15
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Helper type for dot notation queries (e.g., `model.property.method`).
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
16
51
|
type DotNotationQuery<M extends string = never> =
|
|
17
52
|
`${KirbyQueryModel<M>}.${string}`;
|
|
18
53
|
|
|
19
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Helper type for function notation queries (e.g., `model(params)` or `model(params).chain`).
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
20
58
|
type FunctionNotationQuery<M extends string = never> =
|
|
21
|
-
`${KirbyQueryModel<M>}(${string})
|
|
59
|
+
| `${KirbyQueryModel<M>}(${string})`
|
|
60
|
+
| `${KirbyQueryModel<M>}(${string})${string}`;
|
|
22
61
|
|
|
23
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Represents query chains that extend beyond a simple model name.
|
|
64
|
+
*
|
|
65
|
+
* This type covers all valid query patterns that start with a model and include
|
|
66
|
+
* additional property access or method calls:
|
|
67
|
+
*
|
|
68
|
+
* - **Dot notation**: `model.property.method()`
|
|
69
|
+
* - **Function calls**: `model(params)`
|
|
70
|
+
* - **Mixed chains**: `model(params).property.method()`
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* // Dot notation queries
|
|
75
|
+
* const dotQuery: KirbyQueryChain = "page.children.listed";
|
|
76
|
+
* const methodQuery: KirbyQueryChain = "page.children.filterBy('featured', true)";
|
|
77
|
+
*
|
|
78
|
+
* // Function notation queries
|
|
79
|
+
* const funcQuery: KirbyQueryChain = 'site("home")';
|
|
80
|
+
* const mixedQuery: KirbyQueryChain = 'page("blog").children.sortBy("date")';
|
|
81
|
+
*
|
|
82
|
+
* // With custom models
|
|
83
|
+
* type CustomModels = "product" | "category";
|
|
84
|
+
* const customQuery: KirbyQueryChain<CustomModels> = "product.price";
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @template M - Optional custom model names to include in validation
|
|
88
|
+
*/
|
|
24
89
|
export type KirbyQueryChain<M extends string = never> =
|
|
25
90
|
| DotNotationQuery<M>
|
|
26
91
|
| FunctionNotationQuery<M>;
|
|
27
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Represents any valid Kirby Query Language (KQL) string.
|
|
95
|
+
*
|
|
96
|
+
* This is the main type for validating KQL queries. It accepts:
|
|
97
|
+
* - Simple model names (e.g., `"site"`, `"page"`)
|
|
98
|
+
* - Property chains (e.g., `"page.children.listed"`)
|
|
99
|
+
* - Method calls (e.g., `'site("home")'`, `'page.filterBy("status", "published")'`)
|
|
100
|
+
* - Complex mixed queries (e.g., `'page("blog").children.filterBy("featured", true).sortBy("date")'`)
|
|
101
|
+
*
|
|
102
|
+
* Invalid queries (unknown models, malformed syntax) will be rejected at the type level.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* // Valid queries
|
|
107
|
+
* const simpleQuery: KirbyQuery = "site";
|
|
108
|
+
* const propertyQuery: KirbyQuery = "page.children.listed";
|
|
109
|
+
* const methodQuery: KirbyQuery = 'page.filterBy("featured", true)';
|
|
110
|
+
* const complexQuery: KirbyQuery = 'site("home").children.sortBy("date", "desc").limit(10)';
|
|
111
|
+
*
|
|
112
|
+
* // Custom models
|
|
113
|
+
* type MyModels = "product" | "category";
|
|
114
|
+
* const customQuery: KirbyQuery<MyModels> = "product.price";
|
|
115
|
+
*
|
|
116
|
+
* // Invalid queries (these will cause TypeScript errors)
|
|
117
|
+
* // const invalid: KirbyQuery = "unknownModel"; // ❌ Unknown model
|
|
118
|
+
* // const invalid: KirbyQuery<MyModels> = "user"; // ❌ Not in custom models
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @template CustomModel - Optional custom model names to include alongside built-in models
|
|
122
|
+
*/
|
|
28
123
|
export type KirbyQuery<CustomModel extends string = never> =
|
|
29
124
|
| KirbyQueryModel<CustomModel>
|
|
30
|
-
// Ensures that it must match the pattern exactly, but not more broadly
|
|
31
125
|
| (string extends KirbyQueryChain<CustomModel>
|
|
32
126
|
? never
|
|
33
127
|
: KirbyQueryChain<CustomModel>);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Parses a Kirby Query Language (KQL) string into a structured object.
|
|
131
|
+
*
|
|
132
|
+
* This type breaks down a query string into its constituent parts:
|
|
133
|
+
* - `model`: The root model the query starts with (e.g., `site`, `page`, `user`)
|
|
134
|
+
* - `chain`: An array of query segments representing the method calls and property accesses
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* // Basic model query
|
|
139
|
+
* type Basic = ParseKirbyQuery<"site">;
|
|
140
|
+
* // Result: { model: "site"; chain: [] }
|
|
141
|
+
*
|
|
142
|
+
* // Property chain query
|
|
143
|
+
* type Props = ParseKirbyQuery<"page.children.listed">;
|
|
144
|
+
* // Result: {
|
|
145
|
+
* // model: "page";
|
|
146
|
+
* // chain: [
|
|
147
|
+
* // { type: "property"; name: "children" },
|
|
148
|
+
* // { type: "property"; name: "listed" }
|
|
149
|
+
* // ]
|
|
150
|
+
* // }
|
|
151
|
+
*
|
|
152
|
+
* // Method call query
|
|
153
|
+
* type Method = ParseKirbyQuery<'site("home")'>;
|
|
154
|
+
* // Result: {
|
|
155
|
+
* // model: "site";
|
|
156
|
+
* // chain: [{ type: "method"; name: "site"; params: '"home"' }]
|
|
157
|
+
* // }
|
|
158
|
+
*
|
|
159
|
+
* // Complex query with mixed property and method calls
|
|
160
|
+
* type Complex = ParseKirbyQuery<'page.children.filterBy("featured", true).sortBy("date")'>;
|
|
161
|
+
* // Result: {
|
|
162
|
+
* // model: "page";
|
|
163
|
+
* // chain: [
|
|
164
|
+
* // { type: "property"; name: "children" },
|
|
165
|
+
* // { type: "method"; name: "filterBy"; params: '"featured", true' },
|
|
166
|
+
* // { type: "method"; name: "sortBy"; params: '"date"' }
|
|
167
|
+
* // ]
|
|
168
|
+
* // }
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @template T - The query string to parse
|
|
172
|
+
* @template M - Optional custom model names to include in validation
|
|
173
|
+
*/
|
|
174
|
+
export type ParseKirbyQuery<T extends string, M extends string = never> =
|
|
175
|
+
// Case 1: Simple model name (e.g., "site", "page")
|
|
176
|
+
T extends KirbyQueryModel<M>
|
|
177
|
+
? { model: T; chain: [] }
|
|
178
|
+
: // Case 2: Dot notation (e.g., "page.children.listed")
|
|
179
|
+
T extends `${infer Model}.${infer Chain}`
|
|
180
|
+
? Model extends KirbyQueryModel<M>
|
|
181
|
+
? { model: Model; chain: ParseQueryChain<Chain> }
|
|
182
|
+
: never
|
|
183
|
+
: // Case 3: Method call only (e.g., 'site("home")')
|
|
184
|
+
T extends `${infer Model}(${infer Params})`
|
|
185
|
+
? Model extends KirbyQueryModel<M>
|
|
186
|
+
? { model: Model; chain: [ParseQuerySegment<T>] }
|
|
187
|
+
: never
|
|
188
|
+
: // Case 4: Method call followed by chain (e.g., 'site("home").children')
|
|
189
|
+
T extends `${infer Model}(${infer Params})${infer Rest}`
|
|
190
|
+
? Model extends KirbyQueryModel<M>
|
|
191
|
+
? Rest extends `.${infer Chain}`
|
|
192
|
+
? {
|
|
193
|
+
model: Model;
|
|
194
|
+
chain: [
|
|
195
|
+
ParseQuerySegment<`${Model}(${Params})`>,
|
|
196
|
+
...ParseQueryChain<Chain>,
|
|
197
|
+
];
|
|
198
|
+
}
|
|
199
|
+
: never
|
|
200
|
+
: never
|
|
201
|
+
: never;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Recursively parses a chain of query segments separated by dots.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts
|
|
208
|
+
* type Chain = ParseQueryChain<"children.listed.first">;
|
|
209
|
+
* // Result: [
|
|
210
|
+
* // { type: "property"; name: "children" },
|
|
211
|
+
* // { type: "property"; name: "listed" },
|
|
212
|
+
* // { type: "property"; name: "first" }
|
|
213
|
+
* // ]
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @internal
|
|
217
|
+
*/
|
|
218
|
+
type ParseQueryChain<T extends string> =
|
|
219
|
+
T extends `${infer First}.${infer Rest}`
|
|
220
|
+
? [ParseQuerySegment<First>, ...ParseQueryChain<Rest>]
|
|
221
|
+
: [ParseQuerySegment<T>];
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Parses a single query segment to determine if it's a property access or method call.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* type Property = ParseQuerySegment<"children">;
|
|
229
|
+
* // Result: { type: "property"; name: "children" }
|
|
230
|
+
*
|
|
231
|
+
* type Method = ParseQuerySegment<'filterBy("status", "published")'>;
|
|
232
|
+
* // Result: { type: "method"; name: "filterBy"; params: '"status", "published"' }
|
|
233
|
+
* ```
|
|
234
|
+
*
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
type ParseQuerySegment<T extends string> =
|
|
238
|
+
T extends `${infer Name}(${infer Params})`
|
|
239
|
+
? {
|
|
240
|
+
type: "method";
|
|
241
|
+
name: Name;
|
|
242
|
+
params: Params;
|
|
243
|
+
}
|
|
244
|
+
: {
|
|
245
|
+
type: "property";
|
|
246
|
+
name: T;
|
|
247
|
+
};
|