@@ -3,6 +3,8 @@ import { QueryEngine } from "@synstack/query";
3
3
import { z } from "zod/v4" ;
4
4
import { getMarkdownEntries , NAME_SEPARATOR } from "./markdown-db.lib.ts" ;
5
5
6
+ type Globs = [ string , ...string [ ] ] ;
7
+
6
8
type BaseConfigSchema = z . ZodObject < {
7
9
query : z . ZodType < unknown > ;
8
10
} > ;
@@ -18,7 +20,7 @@ export class MarkdownDb<
18
20
private _configSchema ;
19
21
private _cwd ;
20
22
private _queryEngine ;
21
- private _glob : string = "**/*.md" ;
23
+ private _globs : Globs = [ "**/*.md" ] ;
22
24
private _entriesPromise : Promise < Entry < CONFIG_SCHEMA > [ ] > | null = null ;
23
25
private _entriesMapPromise : Promise <
24
26
Map < string , Entry < CONFIG_SCHEMA > >
@@ -31,14 +33,19 @@ export class MarkdownDb<
31
33
cwd : FsDir ,
32
34
queryEngine : QueryEngine < any , INPUT > ,
33
35
configSchema : CONFIG_SCHEMA ,
34
- glob : string = "**/*.md" ,
36
+ globs : Globs = [ "**/*.md" ] ,
35
37
) {
36
38
this . _cwd = cwd ;
37
39
this . _queryEngine = queryEngine ;
38
40
this . _configSchema = configSchema ;
39
- this . _glob = glob ;
41
+ this . _globs = globs ;
40
42
}
41
43
44
+ /**
45
+ * Create a MarkdownDb instance for the given directory
46
+ * @param cwd - The FsDir or path to the directory to create the MarkdownDb instance for
47
+ * @returns A new MarkdownDb instance
48
+ */
42
49
public static cwd < INPUT = unknown > ( cwd : FsDir ) {
43
50
const engine = QueryEngine . default < INPUT > ( ) ;
44
51
return new MarkdownDb < INPUT , BaseConfigSchema > (
@@ -48,18 +55,31 @@ export class MarkdownDb<
48
55
) ;
49
56
}
50
57
58
+ /**
59
+ * @returns The QueryEngine
60
+ */
51
61
public get query ( ) {
52
62
return this . _queryEngine ;
53
63
}
54
64
65
+ /**
66
+ * Set a custom query engine to use for matching with custom predicates
67
+ * @param queryEngine - The QueryEngine to use
68
+ * @returns A new MarkdownDb instance
69
+ */
55
70
public setQueryEngine ( queryEngine : QueryEngine < any , INPUT > ) {
56
71
// Update the config schema to use the new query engine's schema
57
72
const newSchema = this . _configSchema . omit ( { query : true } ) . extend ( {
58
73
query : queryEngine . schema ,
59
74
} ) as CONFIG_SCHEMA ;
60
- return new MarkdownDb ( this . _cwd , queryEngine , newSchema , this . _glob ) ;
75
+ return new MarkdownDb ( this . _cwd , queryEngine , newSchema , this . _globs ) ;
61
76
}
62
77
78
+ /**
79
+ * Set the zod schema used to validate extra frontmatter data
80
+ * @param configSchema - The zod schema to use to validate extra frontmatter data
81
+ * @returns A new MarkdownDb instance
82
+ */
63
83
public setConfigSchema < NEW_CONFIG_SCHEMA extends z . ZodObject < any > > (
64
84
configSchema : NEW_CONFIG_SCHEMA ,
65
85
) {
@@ -71,59 +91,76 @@ export class MarkdownDb<
71
91
} ) as NEW_CONFIG_SCHEMA extends z . ZodObject < infer T >
72
92
? z . ZodObject < T & { query : z . ZodType < unknown > } >
73
93
: never ,
74
- this . _glob ,
94
+ this . _globs ,
75
95
) ;
76
96
}
77
97
78
- public setGlob ( glob : string ) {
79
- return new MarkdownDb (
80
- this . _cwd ,
81
- this . _queryEngine ,
82
- this . _configSchema ,
83
- glob ,
84
- ) ;
98
+ /**
99
+ * Filter the markdown files with glob patterns
100
+ * The "**\/*.md" glob is always included
101
+ */
102
+ public setGlobs ( ...globs : Globs ) {
103
+ return new MarkdownDb ( this . _cwd , this . _queryEngine , this . _configSchema , [
104
+ "**/*.md" ,
105
+ ...globs ,
106
+ ] ) ;
85
107
}
86
108
109
+ /**
110
+ * Refresh the markdown entries from the filesystem
111
+ */
87
112
public async refreshEntries ( ) {
88
113
this . _entriesPromise = getMarkdownEntries (
89
114
this . _cwd ,
90
115
this . schema ,
91
- this . _glob ,
116
+ this . _globs ,
92
117
) ;
93
118
this . _entriesMapPromise = this . _entriesPromise . then (
94
119
( entries ) => new Map ( entries . map ( ( entry ) => [ entry . $id , entry ] ) ) ,
95
120
) ;
96
121
this . _parentPatternsMapPromise = null ; // Reset parent entries cache
97
122
}
98
123
99
- public async getEntries ( ) {
124
+ /**
125
+ * Return all entries as an array of unique entries
126
+ */
127
+ public async getAll ( ) {
100
128
if ( ! this . _entriesPromise ) {
101
129
this . _entriesPromise = getMarkdownEntries (
102
130
this . _cwd ,
103
131
this . schema ,
104
- this . _glob ,
132
+ this . _globs ,
105
133
) ;
106
134
}
107
135
return this . _entriesPromise ;
108
136
}
109
137
110
- public async getEntriesMap ( ) {
138
+ /**
139
+ * Return the entries as a Map<id, entry> for quick lookup
140
+ */
141
+ public async getAllMap ( ) {
111
142
if ( ! this . _entriesMapPromise ) {
112
- this . _entriesMapPromise = this . getEntries ( ) . then (
143
+ this . _entriesMapPromise = this . getAll ( ) . then (
113
144
( entries ) => new Map ( entries . map ( ( entry ) => [ entry . $id , entry ] ) ) ,
114
145
) ;
115
146
}
116
147
return this . _entriesMapPromise ! ;
117
148
}
118
149
119
- public async getEntryById ( id : string ) {
120
- const entries = await this . getEntriesMap ( ) ;
150
+ /**
151
+ * Return the entry for the given id
152
+ */
153
+ public async getOneById ( id : string ) {
154
+ const entries = await this . getAllMap ( ) ;
121
155
return entries . get ( id ) ;
122
156
}
123
157
124
- public async getParentEntriesMap ( ) {
158
+ /**
159
+ * Return the parent entries for all entries
160
+ */
161
+ public async getParentsMap ( ) {
125
162
if ( ! this . _parentPatternsMapPromise ) {
126
- this . _parentPatternsMapPromise = this . getEntries ( ) . then ( ( entries ) => {
163
+ this . _parentPatternsMapPromise = this . getAll ( ) . then ( ( entries ) => {
127
164
const entriesMap = new Map ( entries . map ( ( p ) => [ p . $id , p ] ) ) ;
128
165
const parentMap = new Map < string , Entry < CONFIG_SCHEMA > [ ] > ( ) ;
129
166
@@ -150,23 +187,29 @@ export class MarkdownDb<
150
187
return this . _parentPatternsMapPromise ! ;
151
188
}
152
189
153
- public async getParentEntries ( id : string ) {
154
- const parentMap = await this . getParentEntriesMap ( ) ;
190
+ /**
191
+ * Return the parent entries for the given id
192
+ */
193
+ public async getParentsById ( id : string ) {
194
+ const parentMap = await this . getParentsMap ( ) ;
155
195
return parentMap . get ( id ) || [ ] ;
156
196
}
157
197
158
- public async match (
198
+ /**
199
+ * Return all entries matching the input
200
+ */
201
+ public async matchOne (
159
202
input : INPUT ,
160
- config : {
203
+ config ? : {
161
204
/**
162
205
* Skip markdown entries with empty content
163
206
*/
164
207
skipEmpty ?: boolean ;
165
- } = { skipEmpty : false } ,
208
+ } ,
166
209
) {
167
210
// Retrieve all entries and parent entries map
168
- const entries = await this . getEntries ( ) ;
169
- const parentMap = await this . getParentEntriesMap ( ) ;
211
+ const entries = await this . getAll ( ) ;
212
+ const parentMap = await this . getParentsMap ( ) ;
170
213
171
214
const matchingEntries : Entry < CONFIG_SCHEMA > [ ] = [ ] ;
172
215
@@ -191,15 +234,18 @@ export class MarkdownDb<
191
234
skipQueryValidation : true ,
192
235
} )
193
236
) {
194
- if ( config . skipEmpty && ! entry . $content ?. trim ( ) ) continue ;
237
+ if ( config ? .skipEmpty && ! entry . $content ?. trim ( ) ) continue ;
195
238
matchingEntries . push ( entry ) ;
196
239
}
197
240
}
198
241
199
242
return matchingEntries ;
200
243
}
201
244
202
- public async matchAll (
245
+ /**
246
+ * Return all entries matching any of the inputs
247
+ */
248
+ public async matchAny (
203
249
inputs : INPUT [ ] ,
204
250
config : {
205
251
/**
@@ -209,7 +255,7 @@ export class MarkdownDb<
209
255
} = { skipEmpty : false } ,
210
256
) {
211
257
const allResults = await Promise . all (
212
- inputs . map ( ( input ) => this . match ( input , config ) ) ,
258
+ inputs . map ( ( input ) => this . matchOne ( input , config ) ) ,
213
259
) ;
214
260
215
261
// Remove duplicates
@@ -225,10 +271,16 @@ export class MarkdownDb<
225
271
) . sort ( ( a , b ) => a . $file . path . localeCompare ( b . $file . path ) ) ;
226
272
}
227
273
274
+ /**
275
+ * Return the zod/v4 configuration schema
276
+ */
228
277
public get schema ( ) {
229
278
return this . _configSchema ;
230
279
}
231
280
281
+ /**
282
+ * Return the JSON schema representation of the configuration schema
283
+ */
232
284
public get jsonSchema ( ) {
233
285
return z . toJSONSchema ( this . schema ) ;
234
286
}
@@ -245,7 +297,7 @@ export declare namespace MarkdownDb {
245
297
246
298
export namespace Entry {
247
299
export type Infer < T extends MarkdownDb < any , any > > = Awaited <
248
- ReturnType < T [ "getEntries " ] >
300
+ ReturnType < T [ "getAll " ] >
249
301
> [ number ] ;
250
302
}
251
303
}
0 commit comments