@content-collections/core 0.2.0 → 0.3.1
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/dist/index.d.ts +40 -10
- package/dist/index.js +188 -101
- package/package.json +3 -2
- package/dist/index.cjs +0 -416
- package/dist/index.d.cts +0 -59
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
import { ZodRawShape, z, ZodObject, ZodTypeAny, ZodString } from 'zod';
|
|
2
|
+
import { parse } from 'yaml';
|
|
3
|
+
|
|
4
|
+
type Parsers = typeof parsers;
|
|
5
|
+
type Parser = keyof typeof parsers;
|
|
6
|
+
declare function frontmatterParser(fileContent: string): {
|
|
7
|
+
content: string;
|
|
8
|
+
};
|
|
9
|
+
declare const parsers: {
|
|
10
|
+
readonly frontmatter: {
|
|
11
|
+
readonly hasContent: true;
|
|
12
|
+
readonly parse: typeof frontmatterParser;
|
|
13
|
+
};
|
|
14
|
+
readonly json: {
|
|
15
|
+
readonly hasContent: false;
|
|
16
|
+
readonly parse: (text: string, reviver?: ((this: any, key: string, value: any) => any) | undefined) => any;
|
|
17
|
+
};
|
|
18
|
+
readonly yaml: {
|
|
19
|
+
readonly hasContent: false;
|
|
20
|
+
readonly parse: typeof parse;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type CacheFn = <TInput, TOutput>(input: TInput, compute: (input: TInput) => Promise<TOutput> | TOutput) => Promise<TOutput>;
|
|
2
25
|
|
|
3
26
|
type Meta = {
|
|
4
27
|
filePath: string;
|
|
@@ -13,30 +36,37 @@ type WithContent = {
|
|
|
13
36
|
type AddContent<TShape extends ZodRawShape> = TShape extends {
|
|
14
37
|
content: ZodTypeAny;
|
|
15
38
|
} ? TShape : TShape & WithContent;
|
|
16
|
-
type
|
|
39
|
+
type GetParsedShape<TParser extends Parser, TShape extends ZodRawShape> = Parsers[TParser]["hasContent"] extends true ? AddContent<TShape> : TShape;
|
|
40
|
+
type GetShape<TParser extends Parser | undefined, TShape extends ZodRawShape> = TParser extends Parser ? GetParsedShape<TParser, TShape> : AddContent<TShape>;
|
|
41
|
+
type Schema<TParser extends Parser | undefined, TShape extends ZodRawShape> = z.infer<ZodObject<GetShape<TParser, TShape>>> & {
|
|
17
42
|
_meta: Meta;
|
|
18
43
|
};
|
|
19
44
|
type Context = {
|
|
20
|
-
documents<TCollection extends AnyCollection>(collection: TCollection): Array<Schema<TCollection["schema"]>>;
|
|
45
|
+
documents<TCollection extends AnyCollection>(collection: TCollection): Array<Schema<TCollection["parser"], TCollection["schema"]>>;
|
|
46
|
+
cache: CacheFn;
|
|
21
47
|
};
|
|
22
48
|
type Z = typeof z;
|
|
23
|
-
type CollectionRequest<TName extends string, TShape extends ZodRawShape, TSchema, TTransformResult, TDocument> = {
|
|
49
|
+
type CollectionRequest<TName extends string, TShape extends ZodRawShape, TParser, TSchema, TTransformResult, TDocument> = {
|
|
24
50
|
name: TName;
|
|
51
|
+
parser?: TParser;
|
|
25
52
|
typeName?: string;
|
|
26
53
|
schema: (z: Z) => TShape;
|
|
27
|
-
transform?: (
|
|
28
|
-
directory: string
|
|
54
|
+
transform?: (data: TSchema, context: Context) => TTransformResult;
|
|
55
|
+
directory: string;
|
|
29
56
|
include: string | string[];
|
|
30
57
|
onSuccess?: (documents: Array<TDocument>) => void | Promise<void>;
|
|
31
58
|
};
|
|
32
|
-
type Collection<TName extends string, TShape extends ZodRawShape, TSchema, TTransformResult, TDocument> = Omit<CollectionRequest<TName, TShape, TSchema, TTransformResult, TDocument>, "schema"> & {
|
|
59
|
+
type Collection<TName extends string, TShape extends ZodRawShape, TParser extends Parser, TSchema, TTransformResult, TDocument> = Omit<CollectionRequest<TName, TShape, TParser, TSchema, TTransformResult, TDocument>, "schema"> & {
|
|
33
60
|
typeName: string;
|
|
34
61
|
schema: TShape;
|
|
62
|
+
parser: TParser;
|
|
35
63
|
};
|
|
36
|
-
type AnyCollection = Collection<any, ZodRawShape, any, any, any>;
|
|
37
|
-
declare function defineCollection<TName extends string, TShape extends ZodRawShape, TSchema = Schema<TShape>, TTransformResult = never, TDocument = [TTransformResult] extends [never] ? Schema<TShape> : Awaited<TTransformResult>>(collection: CollectionRequest<TName, TShape, TSchema, TTransformResult, TDocument>): Collection<TName, TShape, TSchema, TTransformResult, TDocument>;
|
|
64
|
+
type AnyCollection = Collection<any, ZodRawShape, Parser, any, any, any>;
|
|
65
|
+
declare function defineCollection<TName extends string, TShape extends ZodRawShape, TParser extends Parser = "frontmatter", TSchema = Schema<TParser, TShape>, TTransformResult = never, TDocument = [TTransformResult] extends [never] ? Schema<TParser, TShape> : Awaited<TTransformResult>>(collection: CollectionRequest<TName, TShape, TParser, TSchema, TTransformResult, TDocument>): Collection<TName, TShape, TParser, TSchema, TTransformResult, TDocument>;
|
|
66
|
+
type Cache = "memory" | "file" | "none";
|
|
38
67
|
type Configuration<TCollections extends Array<AnyCollection>> = {
|
|
39
68
|
collections: TCollections;
|
|
69
|
+
cache?: Cache;
|
|
40
70
|
};
|
|
41
71
|
type AnyConfiguration = Configuration<Array<AnyCollection>>;
|
|
42
72
|
declare function defineConfig<TConfig extends AnyConfiguration>(config: TConfig): TConfig;
|
|
@@ -44,7 +74,7 @@ declare function defineConfig<TConfig extends AnyConfiguration>(config: TConfig)
|
|
|
44
74
|
type Modification = "create" | "update" | "delete";
|
|
45
75
|
type CollectionFile = {
|
|
46
76
|
data: {
|
|
47
|
-
content
|
|
77
|
+
content?: string;
|
|
48
78
|
[key: string]: unknown;
|
|
49
79
|
};
|
|
50
80
|
path: string;
|
|
@@ -52,7 +82,7 @@ type CollectionFile = {
|
|
|
52
82
|
type CollectionByName<TConfiguration extends AnyConfiguration> = {
|
|
53
83
|
[TCollection in TConfiguration["collections"][number] as TCollection["name"]]: TCollection;
|
|
54
84
|
};
|
|
55
|
-
type GetDocument<TCollection extends AnyCollection> = TCollection extends Collection<any, ZodRawShape, any, any, infer TDocument> ? TDocument : never;
|
|
85
|
+
type GetDocument<TCollection extends AnyCollection> = TCollection extends Collection<any, ZodRawShape, any, any, any, infer TDocument> ? TDocument : never;
|
|
56
86
|
type GetTypeByName<TConfiguration extends AnyConfiguration, TName extends keyof CollectionByName<TConfiguration>, TCollection = CollectionByName<TConfiguration>[TName]> = TCollection extends AnyCollection ? GetDocument<TCollection> : never;
|
|
57
87
|
|
|
58
88
|
type CollectorEvents = {
|
package/dist/index.js
CHANGED
|
@@ -21,9 +21,14 @@ function defineCollection(collection) {
|
|
|
21
21
|
if (!typeName) {
|
|
22
22
|
typeName = generateTypeName(collection.name);
|
|
23
23
|
}
|
|
24
|
+
let parser = collection.parser;
|
|
25
|
+
if (!parser) {
|
|
26
|
+
parser = "frontmatter";
|
|
27
|
+
}
|
|
24
28
|
return {
|
|
25
29
|
...collection,
|
|
26
30
|
typeName,
|
|
31
|
+
parser,
|
|
27
32
|
schema: collection.schema(z)
|
|
28
33
|
};
|
|
29
34
|
}
|
|
@@ -39,9 +44,9 @@ import path from "path";
|
|
|
39
44
|
// package.json
|
|
40
45
|
var package_default = {
|
|
41
46
|
name: "@content-collections/core",
|
|
42
|
-
version: "0.1
|
|
47
|
+
version: "0.3.1",
|
|
43
48
|
type: "module",
|
|
44
|
-
main: "dist/index.
|
|
49
|
+
main: "dist/index.js",
|
|
45
50
|
types: "./dist/index.d.ts",
|
|
46
51
|
exports: {
|
|
47
52
|
"./package.json": "./package.json",
|
|
@@ -79,12 +84,14 @@ var package_default = {
|
|
|
79
84
|
"gray-matter": "^4.0.3",
|
|
80
85
|
micromatch: "^4.0.5",
|
|
81
86
|
pluralize: "^8.0.0",
|
|
87
|
+
yaml: "^2.3.4",
|
|
82
88
|
zod: "^3.22.4"
|
|
83
89
|
}
|
|
84
90
|
};
|
|
85
91
|
|
|
86
92
|
// src/configurationReader.ts
|
|
87
93
|
import { existsSync } from "fs";
|
|
94
|
+
import { createHash } from "crypto";
|
|
88
95
|
var ConfigurationError = class extends Error {
|
|
89
96
|
type;
|
|
90
97
|
constructor(type, message) {
|
|
@@ -114,7 +121,11 @@ async function compile(configurationPath, outfile) {
|
|
|
114
121
|
}
|
|
115
122
|
await esbuild.build({
|
|
116
123
|
entryPoints: [configurationPath],
|
|
117
|
-
|
|
124
|
+
packages: "external",
|
|
125
|
+
external: [
|
|
126
|
+
...Object.keys(package_default.dependencies),
|
|
127
|
+
"@content-collections/*"
|
|
128
|
+
],
|
|
118
129
|
bundle: true,
|
|
119
130
|
platform: "node",
|
|
120
131
|
format: "esm",
|
|
@@ -144,19 +155,56 @@ function createConfigurationReader() {
|
|
|
144
155
|
);
|
|
145
156
|
}
|
|
146
157
|
const module = await import(`file://${path.resolve(outfile)}?x=${Date.now()}`);
|
|
158
|
+
const hash = createHash("sha256");
|
|
159
|
+
hash.update(await fs.readFile(outfile, "utf-8"));
|
|
160
|
+
const checksum = hash.digest("hex");
|
|
147
161
|
return {
|
|
148
162
|
...module.default,
|
|
149
163
|
path: configurationPath,
|
|
150
|
-
generateTypes: true
|
|
164
|
+
generateTypes: true,
|
|
165
|
+
checksum
|
|
151
166
|
};
|
|
152
167
|
};
|
|
153
168
|
}
|
|
154
169
|
|
|
155
170
|
// src/collector.ts
|
|
156
|
-
import matter from "gray-matter";
|
|
157
171
|
import fg from "fast-glob";
|
|
158
172
|
import { readFile } from "fs/promises";
|
|
159
173
|
import path2 from "path";
|
|
174
|
+
|
|
175
|
+
// src/parser.ts
|
|
176
|
+
import matter from "gray-matter";
|
|
177
|
+
import { parse, stringify } from "yaml";
|
|
178
|
+
function frontmatterParser(fileContent) {
|
|
179
|
+
const { data, content } = matter(fileContent, {
|
|
180
|
+
engines: {
|
|
181
|
+
yaml: {
|
|
182
|
+
parse,
|
|
183
|
+
stringify
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
return {
|
|
188
|
+
...data,
|
|
189
|
+
content: content.trim()
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
var parsers = {
|
|
193
|
+
frontmatter: {
|
|
194
|
+
hasContent: true,
|
|
195
|
+
parse: frontmatterParser
|
|
196
|
+
},
|
|
197
|
+
json: {
|
|
198
|
+
hasContent: false,
|
|
199
|
+
parse: JSON.parse
|
|
200
|
+
},
|
|
201
|
+
yaml: {
|
|
202
|
+
hasContent: false,
|
|
203
|
+
parse
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// src/collector.ts
|
|
160
208
|
var CollectError = class extends Error {
|
|
161
209
|
type;
|
|
162
210
|
constructor(type, message) {
|
|
@@ -176,55 +224,37 @@ function createCollector(emitter, baseDirectory = ".") {
|
|
|
176
224
|
return null;
|
|
177
225
|
}
|
|
178
226
|
}
|
|
179
|
-
function
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
...data,
|
|
183
|
-
content
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
async function collectFile(directory, filePath) {
|
|
187
|
-
const file = await read(path2.join(directory, filePath));
|
|
227
|
+
async function collectFile(collection, filePath) {
|
|
228
|
+
const absolutePath = path2.join(baseDirectory, collection.directory, filePath);
|
|
229
|
+
const file = await read(absolutePath);
|
|
188
230
|
if (!file) {
|
|
189
231
|
return null;
|
|
190
232
|
}
|
|
191
233
|
try {
|
|
192
|
-
const data = parse(file);
|
|
234
|
+
const data = parsers[collection.parser].parse(file);
|
|
193
235
|
return {
|
|
194
236
|
data,
|
|
195
237
|
path: filePath
|
|
196
238
|
};
|
|
197
239
|
} catch (error) {
|
|
198
240
|
emitter.emit("collector:parse-error", {
|
|
199
|
-
filePath: path2.join(directory, filePath),
|
|
241
|
+
filePath: path2.join(collection.directory, filePath),
|
|
200
242
|
error: new CollectError("Parse", String(error))
|
|
201
243
|
});
|
|
202
244
|
return null;
|
|
203
245
|
}
|
|
204
246
|
}
|
|
205
|
-
async function
|
|
206
|
-
const collectionDirectory = path2.join(baseDirectory, directory);
|
|
247
|
+
async function resolveCollection(collection) {
|
|
248
|
+
const collectionDirectory = path2.join(baseDirectory, collection.directory);
|
|
207
249
|
const filePaths = await fg(collection.include, {
|
|
208
250
|
cwd: collectionDirectory,
|
|
209
251
|
onlyFiles: true,
|
|
210
252
|
absolute: false
|
|
211
253
|
});
|
|
212
254
|
const promises = filePaths.map(
|
|
213
|
-
(filePath) => collectFile(
|
|
255
|
+
(filePath) => collectFile(collection, filePath)
|
|
214
256
|
);
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
async function resolveCollection(collection) {
|
|
218
|
-
let files = [];
|
|
219
|
-
if (typeof collection.directory === "string") {
|
|
220
|
-
files = await resolveDirectory(collection, collection.directory);
|
|
221
|
-
} else {
|
|
222
|
-
const promises = collection.directory.map(
|
|
223
|
-
(directory) => resolveDirectory(collection, directory)
|
|
224
|
-
);
|
|
225
|
-
const resolved = await Promise.all(promises);
|
|
226
|
-
files = resolved.flat();
|
|
227
|
-
}
|
|
257
|
+
const files = await Promise.all(promises);
|
|
228
258
|
return {
|
|
229
259
|
...collection,
|
|
230
260
|
files: files.filter(isDefined).sort(orderByPath)
|
|
@@ -326,23 +356,27 @@ var TransformError = class extends Error {
|
|
|
326
356
|
this.type = type;
|
|
327
357
|
}
|
|
328
358
|
};
|
|
329
|
-
function createPath(
|
|
330
|
-
let p =
|
|
359
|
+
function createPath(path7, ext) {
|
|
360
|
+
let p = path7.slice(0, -ext.length);
|
|
331
361
|
if (p.endsWith("/index")) {
|
|
332
362
|
p = p.slice(0, -6);
|
|
333
363
|
}
|
|
334
364
|
return p;
|
|
335
365
|
}
|
|
336
|
-
function createTransformer(emitter) {
|
|
337
|
-
function createSchema(schema) {
|
|
366
|
+
function createTransformer(emitter, cacheManager) {
|
|
367
|
+
function createSchema(parserName, schema) {
|
|
368
|
+
const parser = parsers[parserName];
|
|
369
|
+
if (!parser.hasContent) {
|
|
370
|
+
return z2.object(schema);
|
|
371
|
+
}
|
|
338
372
|
return z2.object({
|
|
339
373
|
content: z2.string(),
|
|
340
374
|
...schema
|
|
341
375
|
});
|
|
342
376
|
}
|
|
343
377
|
async function parseFile(collection, file) {
|
|
344
|
-
const { data, path:
|
|
345
|
-
const schema = createSchema(collection.schema);
|
|
378
|
+
const { data, path: path7 } = file;
|
|
379
|
+
const schema = createSchema(collection.parser, collection.schema);
|
|
346
380
|
let parsedData = await schema.safeParseAsync(data);
|
|
347
381
|
if (!parsedData.success) {
|
|
348
382
|
emitter.emit("transformer:validation-error", {
|
|
@@ -352,7 +386,7 @@ function createTransformer(emitter) {
|
|
|
352
386
|
});
|
|
353
387
|
return null;
|
|
354
388
|
}
|
|
355
|
-
const ext = extname(
|
|
389
|
+
const ext = extname(path7);
|
|
356
390
|
let extension = ext;
|
|
357
391
|
if (extension.startsWith(".")) {
|
|
358
392
|
extension = extension.slice(1);
|
|
@@ -360,11 +394,11 @@ function createTransformer(emitter) {
|
|
|
360
394
|
const document = {
|
|
361
395
|
...parsedData.data,
|
|
362
396
|
_meta: {
|
|
363
|
-
filePath:
|
|
364
|
-
fileName: basename(
|
|
365
|
-
directory: dirname(
|
|
397
|
+
filePath: path7,
|
|
398
|
+
fileName: basename(path7),
|
|
399
|
+
directory: dirname(path7),
|
|
366
400
|
extension,
|
|
367
|
-
path: createPath(
|
|
401
|
+
path: createPath(path7, ext)
|
|
368
402
|
}
|
|
369
403
|
};
|
|
370
404
|
return {
|
|
@@ -380,7 +414,7 @@ function createTransformer(emitter) {
|
|
|
380
414
|
documents: (await Promise.all(promises)).filter(isDefined)
|
|
381
415
|
};
|
|
382
416
|
}
|
|
383
|
-
function createContext(collections) {
|
|
417
|
+
function createContext(collections, cache) {
|
|
384
418
|
return {
|
|
385
419
|
documents: (collection) => {
|
|
386
420
|
const resolved = collections.find((c) => c.name === collection.name);
|
|
@@ -391,19 +425,22 @@ function createTransformer(emitter) {
|
|
|
391
425
|
);
|
|
392
426
|
}
|
|
393
427
|
return resolved.documents.map((doc) => doc.document);
|
|
394
|
-
}
|
|
428
|
+
},
|
|
429
|
+
cache: cache.cacheFn
|
|
395
430
|
};
|
|
396
431
|
}
|
|
397
432
|
async function transformCollection(collections, collection) {
|
|
398
433
|
if (collection.transform) {
|
|
399
434
|
const docs = [];
|
|
400
|
-
const context = createContext(collections);
|
|
401
435
|
for (const doc of collection.documents) {
|
|
436
|
+
const cache = cacheManager.cache(collection.name, doc.document._meta.path);
|
|
437
|
+
const context = createContext(collections, cache);
|
|
402
438
|
try {
|
|
403
439
|
docs.push({
|
|
404
440
|
...doc,
|
|
405
|
-
document: await collection.transform(
|
|
441
|
+
document: await collection.transform(doc.document, context)
|
|
406
442
|
});
|
|
443
|
+
await cache.tidyUp();
|
|
407
444
|
} catch (error) {
|
|
408
445
|
if (error instanceof TransformError) {
|
|
409
446
|
emitter.emit("transformer:error", {
|
|
@@ -418,6 +455,7 @@ function createTransformer(emitter) {
|
|
|
418
455
|
}
|
|
419
456
|
}
|
|
420
457
|
}
|
|
458
|
+
await cacheManager.flush();
|
|
421
459
|
return docs;
|
|
422
460
|
}
|
|
423
461
|
return collection.documents;
|
|
@@ -438,26 +476,13 @@ function createTransformer(emitter) {
|
|
|
438
476
|
import micromatch from "micromatch";
|
|
439
477
|
import path4 from "path";
|
|
440
478
|
function createSynchronizer(readCollectionFile, collections, baseDirectory = ".") {
|
|
441
|
-
function
|
|
479
|
+
function findCollection(filePath) {
|
|
442
480
|
const resolvedFilePath = path4.resolve(filePath);
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
directories.push(...collection.directory);
|
|
449
|
-
}
|
|
450
|
-
for (const directory of directories) {
|
|
451
|
-
const resolvedDirectory = path4.resolve(baseDirectory, directory);
|
|
452
|
-
if (resolvedFilePath.startsWith(resolvedDirectory)) {
|
|
453
|
-
return {
|
|
454
|
-
collection,
|
|
455
|
-
directory
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
return null;
|
|
481
|
+
return collections.find((collection) => {
|
|
482
|
+
return resolvedFilePath.startsWith(
|
|
483
|
+
path4.resolve(baseDirectory, collection.directory)
|
|
484
|
+
);
|
|
485
|
+
});
|
|
461
486
|
}
|
|
462
487
|
function createRelativePath(collectionPath, filePath) {
|
|
463
488
|
const resolvedCollectionPath = path4.resolve(baseDirectory, collectionPath);
|
|
@@ -469,12 +494,11 @@ function createSynchronizer(readCollectionFile, collections, baseDirectory = "."
|
|
|
469
494
|
return relativePath;
|
|
470
495
|
}
|
|
471
496
|
function resolve(filePath) {
|
|
472
|
-
const
|
|
473
|
-
if (!
|
|
497
|
+
const collection = findCollection(filePath);
|
|
498
|
+
if (!collection) {
|
|
474
499
|
return null;
|
|
475
500
|
}
|
|
476
|
-
const
|
|
477
|
-
const relativePath = createRelativePath(directory, filePath);
|
|
501
|
+
const relativePath = createRelativePath(collection.directory, filePath);
|
|
478
502
|
if (!micromatch.isMatch(relativePath, collection.include)) {
|
|
479
503
|
return null;
|
|
480
504
|
}
|
|
@@ -504,22 +528,7 @@ function createSynchronizer(readCollectionFile, collections, baseDirectory = "."
|
|
|
504
528
|
const index = collection.files.findIndex(
|
|
505
529
|
(file2) => file2.path === relativePath
|
|
506
530
|
);
|
|
507
|
-
const
|
|
508
|
-
if (typeof collection.directory === "string") {
|
|
509
|
-
directories.push(collection.directory);
|
|
510
|
-
} else {
|
|
511
|
-
directories.push(...collection.directory);
|
|
512
|
-
}
|
|
513
|
-
let file = null;
|
|
514
|
-
for (const directory of directories) {
|
|
515
|
-
file = await readCollectionFile(
|
|
516
|
-
path4.join(baseDirectory, directory),
|
|
517
|
-
relativePath
|
|
518
|
-
);
|
|
519
|
-
if (file) {
|
|
520
|
-
break;
|
|
521
|
-
}
|
|
522
|
-
}
|
|
531
|
+
const file = await readCollectionFile(collection, relativePath);
|
|
523
532
|
if (!file) {
|
|
524
533
|
return false;
|
|
525
534
|
}
|
|
@@ -538,7 +547,7 @@ function createSynchronizer(readCollectionFile, collections, baseDirectory = "."
|
|
|
538
547
|
}
|
|
539
548
|
|
|
540
549
|
// src/builder.ts
|
|
541
|
-
import
|
|
550
|
+
import path6 from "path";
|
|
542
551
|
|
|
543
552
|
// src/watcher.ts
|
|
544
553
|
import * as watcher from "@parcel/watcher";
|
|
@@ -563,7 +572,7 @@ async function createWatcher(emitter, paths, sync, build2) {
|
|
|
563
572
|
}
|
|
564
573
|
};
|
|
565
574
|
const subscriptions = await Promise.all(
|
|
566
|
-
paths.map((
|
|
575
|
+
paths.map((path7) => watcher.subscribe(path7, onChange))
|
|
567
576
|
);
|
|
568
577
|
return {
|
|
569
578
|
unsubscribe: async () => {
|
|
@@ -604,12 +613,96 @@ function createEmitter() {
|
|
|
604
613
|
};
|
|
605
614
|
}
|
|
606
615
|
|
|
616
|
+
// src/cache.ts
|
|
617
|
+
import path5, { join } from "path";
|
|
618
|
+
import { mkdir, readFile as readFile2, unlink, writeFile } from "fs/promises";
|
|
619
|
+
import { existsSync as existsSync2 } from "fs";
|
|
620
|
+
import { createHash as createHash2 } from "crypto";
|
|
621
|
+
function createKey(config, input) {
|
|
622
|
+
return createHash2("sha256").update(config).update(JSON.stringify(input)).digest("hex");
|
|
623
|
+
}
|
|
624
|
+
async function createCacheDirectory(directory) {
|
|
625
|
+
const cacheDirectory = path5.join(directory, ".content-collections", "cache");
|
|
626
|
+
if (!existsSync2(cacheDirectory)) {
|
|
627
|
+
await mkdir(cacheDirectory, { recursive: true });
|
|
628
|
+
}
|
|
629
|
+
return cacheDirectory;
|
|
630
|
+
}
|
|
631
|
+
function fileName(input) {
|
|
632
|
+
return input.replace(/[^a-z0-9]/gi, "_").toLowerCase();
|
|
633
|
+
}
|
|
634
|
+
async function createCacheManager(baseDirectory, configChecksum) {
|
|
635
|
+
const cacheDirectory = await createCacheDirectory(baseDirectory);
|
|
636
|
+
let mapping = {};
|
|
637
|
+
const mappingPath = join(cacheDirectory, "mapping.json");
|
|
638
|
+
if (existsSync2(mappingPath)) {
|
|
639
|
+
mapping = JSON.parse(await readFile2(mappingPath, "utf-8"));
|
|
640
|
+
}
|
|
641
|
+
async function flush() {
|
|
642
|
+
await writeFile(mappingPath, JSON.stringify(mapping));
|
|
643
|
+
}
|
|
644
|
+
function cache(collection, file) {
|
|
645
|
+
const directory = join(
|
|
646
|
+
cacheDirectory,
|
|
647
|
+
fileName(collection),
|
|
648
|
+
fileName(file)
|
|
649
|
+
);
|
|
650
|
+
let collectionMapping = mapping[collection];
|
|
651
|
+
if (!collectionMapping) {
|
|
652
|
+
collectionMapping = {};
|
|
653
|
+
mapping[collection] = collectionMapping;
|
|
654
|
+
}
|
|
655
|
+
let fileMapping = collectionMapping[file];
|
|
656
|
+
if (!fileMapping) {
|
|
657
|
+
fileMapping = [];
|
|
658
|
+
collectionMapping[file] = fileMapping;
|
|
659
|
+
}
|
|
660
|
+
let newFileMapping = [];
|
|
661
|
+
const cacheFn = async (input, fn) => {
|
|
662
|
+
const key = createKey(configChecksum, input);
|
|
663
|
+
newFileMapping.push(key);
|
|
664
|
+
const filePath = join(directory, `${key}.cache`);
|
|
665
|
+
if (fileMapping?.includes(key) || newFileMapping.includes(key)) {
|
|
666
|
+
if (existsSync2(filePath)) {
|
|
667
|
+
return JSON.parse(await readFile2(filePath, "utf-8"));
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
const output = await fn(input);
|
|
671
|
+
if (!existsSync2(directory)) {
|
|
672
|
+
await mkdir(directory, { recursive: true });
|
|
673
|
+
}
|
|
674
|
+
await writeFile(filePath, JSON.stringify(output));
|
|
675
|
+
return output;
|
|
676
|
+
};
|
|
677
|
+
const tidyUp = async () => {
|
|
678
|
+
const filesToDelete = fileMapping?.filter((key) => !newFileMapping.includes(key)) || [];
|
|
679
|
+
for (const key of filesToDelete) {
|
|
680
|
+
const filePath = join(directory, `${key}.cache`);
|
|
681
|
+
if (existsSync2(filePath)) {
|
|
682
|
+
await unlink(filePath);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (collectionMapping) {
|
|
686
|
+
collectionMapping[file] = newFileMapping;
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
return {
|
|
690
|
+
cacheFn,
|
|
691
|
+
tidyUp
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
return {
|
|
695
|
+
cache,
|
|
696
|
+
flush
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
|
|
607
700
|
// src/builder.ts
|
|
608
701
|
function resolveOutputDir(baseDirectory, options) {
|
|
609
702
|
if (options.outputDir) {
|
|
610
703
|
return options.outputDir;
|
|
611
704
|
}
|
|
612
|
-
return
|
|
705
|
+
return path6.join(baseDirectory, ".content-collections", "generated");
|
|
613
706
|
}
|
|
614
707
|
async function createBuilder(configurationPath, options = {
|
|
615
708
|
configName: defaultConfigName
|
|
@@ -617,7 +710,7 @@ async function createBuilder(configurationPath, options = {
|
|
|
617
710
|
const emitter = createEmitter();
|
|
618
711
|
const readConfiguration = createConfigurationReader();
|
|
619
712
|
const configuration = await readConfiguration(configurationPath, options);
|
|
620
|
-
const baseDirectory =
|
|
713
|
+
const baseDirectory = path6.dirname(configurationPath);
|
|
621
714
|
const directory = resolveOutputDir(baseDirectory, options);
|
|
622
715
|
const collector = createCollector(emitter, baseDirectory);
|
|
623
716
|
const writer = await createWriter(directory);
|
|
@@ -631,7 +724,8 @@ async function createBuilder(configurationPath, options = {
|
|
|
631
724
|
resolved,
|
|
632
725
|
baseDirectory
|
|
633
726
|
);
|
|
634
|
-
const
|
|
727
|
+
const cacheManager = await createCacheManager(baseDirectory, configuration.checksum);
|
|
728
|
+
const transform = createTransformer(emitter, cacheManager);
|
|
635
729
|
async function sync(modification, filePath) {
|
|
636
730
|
if (modification === "delete") {
|
|
637
731
|
return synchronizer.deleted(filePath);
|
|
@@ -655,16 +749,9 @@ async function createBuilder(configurationPath, options = {
|
|
|
655
749
|
});
|
|
656
750
|
}
|
|
657
751
|
async function watch() {
|
|
658
|
-
const paths =
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
paths.push(path5.join(baseDirectory, collection.directory));
|
|
662
|
-
} else {
|
|
663
|
-
paths.push(
|
|
664
|
-
...collection.directory.map((dir) => path5.join(baseDirectory, dir))
|
|
665
|
-
);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
752
|
+
const paths = resolved.map(
|
|
753
|
+
(collection) => path6.join(baseDirectory, collection.directory)
|
|
754
|
+
);
|
|
668
755
|
const watcher2 = await createWatcher(emitter, paths, sync, build2);
|
|
669
756
|
return watcher2;
|
|
670
757
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@content-collections/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "dist/index.
|
|
5
|
+
"main": "dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
"./package.json": "./package.json",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"gray-matter": "^4.0.3",
|
|
34
34
|
"micromatch": "^4.0.5",
|
|
35
35
|
"pluralize": "^8.0.0",
|
|
36
|
+
"yaml": "^2.3.4",
|
|
36
37
|
"zod": "^3.22.4"
|
|
37
38
|
},
|
|
38
39
|
"scripts": {
|
package/dist/index.cjs
DELETED
|
@@ -1,416 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var src_exports = {};
|
|
32
|
-
__export(src_exports, {
|
|
33
|
-
applyConfig: () => applyConfig,
|
|
34
|
-
build: () => build2,
|
|
35
|
-
createRunner: () => createRunner,
|
|
36
|
-
defineCollection: () => defineCollection,
|
|
37
|
-
defineConfig: () => defineConfig
|
|
38
|
-
});
|
|
39
|
-
module.exports = __toCommonJS(src_exports);
|
|
40
|
-
var import_path2 = __toESM(require("path"), 1);
|
|
41
|
-
|
|
42
|
-
// src/applyConfig.ts
|
|
43
|
-
var esbuild = __toESM(require("esbuild"), 1);
|
|
44
|
-
var import_promises = __toESM(require("fs/promises"), 1);
|
|
45
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
46
|
-
|
|
47
|
-
// package.json
|
|
48
|
-
var package_default = {
|
|
49
|
-
name: "@mdx-collections/core",
|
|
50
|
-
version: "1.0.0",
|
|
51
|
-
type: "module",
|
|
52
|
-
main: "dist/index.cjs",
|
|
53
|
-
exports: {
|
|
54
|
-
"./package.json": "./package.json",
|
|
55
|
-
".": {
|
|
56
|
-
import: "./dist/index.js",
|
|
57
|
-
require: "./dist/index.cjs"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
types: "./dist/index.d.ts",
|
|
61
|
-
scripts: {
|
|
62
|
-
build: "tsup src/index.ts --format esm,cjs --dts -d dist",
|
|
63
|
-
typecheck: "tsc",
|
|
64
|
-
test: "vitest --run --coverage"
|
|
65
|
-
},
|
|
66
|
-
devDependencies: {
|
|
67
|
-
"@types/micromatch": "^4.0.6",
|
|
68
|
-
"@types/node": "^20.9.0",
|
|
69
|
-
"@types/pluralize": "^0.0.33",
|
|
70
|
-
"@vitest/coverage-v8": "^0.34.6",
|
|
71
|
-
tsup: "^7.2.0",
|
|
72
|
-
tsx: "^4.1.1",
|
|
73
|
-
typescript: "^5.3.2",
|
|
74
|
-
vitest: "^0.34.6"
|
|
75
|
-
},
|
|
76
|
-
dependencies: {
|
|
77
|
-
camelcase: "^8.0.0",
|
|
78
|
-
esbuild: "^0.19.5",
|
|
79
|
-
"fast-glob": "^3.3.2",
|
|
80
|
-
"gray-matter": "^4.0.3",
|
|
81
|
-
micromatch: "^4.0.5",
|
|
82
|
-
pluralize: "^8.0.0",
|
|
83
|
-
zod: "^3.22.4"
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
// src/applyConfig.ts
|
|
88
|
-
var importPathPlugin = {
|
|
89
|
-
name: "import-path",
|
|
90
|
-
setup(build3) {
|
|
91
|
-
build3.onResolve({ filter: /^\@mdx-collections\/core$/ }, () => {
|
|
92
|
-
return { path: import_node_path.default.join(__dirname, "index.ts"), external: true };
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
function resolveCacheDir(config, options) {
|
|
97
|
-
if (options.cacheDir) {
|
|
98
|
-
return options.cacheDir;
|
|
99
|
-
}
|
|
100
|
-
return import_node_path.default.join(import_node_path.default.dirname(config), ".mdx-collections", "cache");
|
|
101
|
-
}
|
|
102
|
-
async function applyConfig(config, options = {
|
|
103
|
-
configName: "mdx-collection-config.mjs"
|
|
104
|
-
}) {
|
|
105
|
-
const cacheDir = resolveCacheDir(config, options);
|
|
106
|
-
await import_promises.default.mkdir(cacheDir, { recursive: true });
|
|
107
|
-
const outfile = import_node_path.default.join(cacheDir, options.configName);
|
|
108
|
-
const plugins = [];
|
|
109
|
-
if (process.env.NODE_ENV === "test") {
|
|
110
|
-
plugins.push(importPathPlugin);
|
|
111
|
-
}
|
|
112
|
-
await esbuild.build({
|
|
113
|
-
entryPoints: [config],
|
|
114
|
-
external: [...Object.keys(package_default.dependencies), "@mdx-collections/*"],
|
|
115
|
-
bundle: true,
|
|
116
|
-
platform: "node",
|
|
117
|
-
format: "esm",
|
|
118
|
-
plugins,
|
|
119
|
-
outfile
|
|
120
|
-
});
|
|
121
|
-
const module2 = await import(`file://${import_node_path.default.resolve(outfile)}?x=${Date.now()}`);
|
|
122
|
-
return {
|
|
123
|
-
...module2.default,
|
|
124
|
-
path: config,
|
|
125
|
-
generateTypes: true
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// src/run.ts
|
|
130
|
-
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
131
|
-
var import_node_path2 = __toESM(require("path"), 1);
|
|
132
|
-
var import_pluralize = __toESM(require("pluralize"), 1);
|
|
133
|
-
|
|
134
|
-
// src/collect.ts
|
|
135
|
-
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
136
|
-
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
137
|
-
var import_promises2 = require("fs/promises");
|
|
138
|
-
var import_path = __toESM(require("path"), 1);
|
|
139
|
-
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
140
|
-
async function collectFile(directory, filePath) {
|
|
141
|
-
const file = await (0, import_promises2.readFile)(import_path.default.join(directory, filePath), "utf-8");
|
|
142
|
-
const { data, content: body } = (0, import_gray_matter.default)(file);
|
|
143
|
-
return {
|
|
144
|
-
data,
|
|
145
|
-
body,
|
|
146
|
-
path: filePath
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
async function resolveCollection(collection) {
|
|
150
|
-
const filePaths = await (0, import_fast_glob.default)(collection.include, {
|
|
151
|
-
cwd: collection.directory,
|
|
152
|
-
onlyFiles: true,
|
|
153
|
-
absolute: false
|
|
154
|
-
});
|
|
155
|
-
const promises = filePaths.map(
|
|
156
|
-
(filePath) => collectFile(collection.directory, filePath)
|
|
157
|
-
);
|
|
158
|
-
return {
|
|
159
|
-
...collection,
|
|
160
|
-
files: await Promise.all(promises)
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
async function collect(unresolvedCollections) {
|
|
164
|
-
const promises = unresolvedCollections.map(
|
|
165
|
-
(collection) => resolveCollection(collection)
|
|
166
|
-
);
|
|
167
|
-
return await Promise.all(promises);
|
|
168
|
-
}
|
|
169
|
-
function createRelativePath(directory, filePath) {
|
|
170
|
-
if (!filePath.startsWith(directory)) {
|
|
171
|
-
throw new Error("Path is not in collection directory");
|
|
172
|
-
}
|
|
173
|
-
let relativePath = filePath.slice(directory.length);
|
|
174
|
-
if (relativePath.startsWith("/")) {
|
|
175
|
-
relativePath = relativePath.slice(1);
|
|
176
|
-
}
|
|
177
|
-
return relativePath;
|
|
178
|
-
}
|
|
179
|
-
function isIncluded(collection, path5) {
|
|
180
|
-
if (path5.startsWith(collection.directory)) {
|
|
181
|
-
const relativePath = createRelativePath(collection.directory, path5);
|
|
182
|
-
return import_micromatch.default.isMatch(relativePath, collection.include);
|
|
183
|
-
}
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
async function syncFile(collection, modification, path5) {
|
|
187
|
-
if ("added" === modification) {
|
|
188
|
-
const file = await collectFile(collection.directory, path5);
|
|
189
|
-
collection.files.push(file);
|
|
190
|
-
} else if ("changed" === modification) {
|
|
191
|
-
const file = await collectFile(collection.directory, path5);
|
|
192
|
-
const index = collection.files.findIndex((file2) => file2.path === path5);
|
|
193
|
-
collection.files[index] = file;
|
|
194
|
-
} else if ("removed" === modification) {
|
|
195
|
-
const index = collection.files.findIndex((file) => file.path === path5);
|
|
196
|
-
collection.files.splice(index, 1);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
function sync(collection, modification, path5) {
|
|
200
|
-
const relativePath = createRelativePath(collection.directory, path5);
|
|
201
|
-
return syncFile(collection, modification, relativePath);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// src/transformer.ts
|
|
205
|
-
var TransformError = class extends Error {
|
|
206
|
-
type;
|
|
207
|
-
constructor(type, message) {
|
|
208
|
-
super(message);
|
|
209
|
-
this.type = type;
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
var throwingErrorHandler = (error) => {
|
|
213
|
-
throw error;
|
|
214
|
-
};
|
|
215
|
-
function isDefined(value) {
|
|
216
|
-
return value !== void 0 && value !== null;
|
|
217
|
-
}
|
|
218
|
-
async function transform(untransformedCollections, errorHandler = throwingErrorHandler) {
|
|
219
|
-
async function parseFile(collection, file) {
|
|
220
|
-
const { data, body, path: path5 } = file;
|
|
221
|
-
let parsedData = await collection.schema.safeParseAsync(data);
|
|
222
|
-
if (!parsedData.success) {
|
|
223
|
-
errorHandler(new TransformError("Validation", parsedData.error.message));
|
|
224
|
-
return null;
|
|
225
|
-
}
|
|
226
|
-
const document = {
|
|
227
|
-
...parsedData.data,
|
|
228
|
-
_meta: {
|
|
229
|
-
path: path5
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
return {
|
|
233
|
-
document,
|
|
234
|
-
content: body
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
async function parseCollection(collection) {
|
|
238
|
-
const promises2 = collection.files.map(
|
|
239
|
-
(file) => parseFile(collection, file)
|
|
240
|
-
);
|
|
241
|
-
return {
|
|
242
|
-
...collection,
|
|
243
|
-
documents: (await Promise.all(promises2)).filter(isDefined)
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
function createContext(collections2, file) {
|
|
247
|
-
return {
|
|
248
|
-
content: async () => file.content,
|
|
249
|
-
documents: (collection) => {
|
|
250
|
-
const resolved = collections2.find((c) => c.name === collection.name);
|
|
251
|
-
if (!resolved) {
|
|
252
|
-
throw new TransformError(
|
|
253
|
-
"Configuration",
|
|
254
|
-
`Collection ${collection.name} not found, do you have registered it in your configuration?`
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
return resolved.documents.map((doc) => doc.document);
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
async function transformCollection(collections2, collection) {
|
|
262
|
-
if (collection.transform) {
|
|
263
|
-
const docs = [];
|
|
264
|
-
for (const doc of collection.documents) {
|
|
265
|
-
const context = createContext(collections2, doc);
|
|
266
|
-
try {
|
|
267
|
-
docs.push({
|
|
268
|
-
...doc,
|
|
269
|
-
document: await collection.transform(context, doc.document)
|
|
270
|
-
});
|
|
271
|
-
} catch (error) {
|
|
272
|
-
if (error instanceof TransformError) {
|
|
273
|
-
errorHandler(error);
|
|
274
|
-
} else {
|
|
275
|
-
errorHandler(new TransformError("Transform", String(error)));
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return docs;
|
|
280
|
-
}
|
|
281
|
-
return collection.documents;
|
|
282
|
-
}
|
|
283
|
-
const promises = untransformedCollections.map(
|
|
284
|
-
(collection) => parseCollection(collection)
|
|
285
|
-
);
|
|
286
|
-
const collections = await Promise.all(promises);
|
|
287
|
-
for (const collection of collections) {
|
|
288
|
-
collection.documents = await transformCollection(collections, collection);
|
|
289
|
-
}
|
|
290
|
-
return collections;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// src/run.ts
|
|
294
|
-
function createArrayConstName(name) {
|
|
295
|
-
let suffix = name.charAt(0).toUpperCase() + name.slice(1);
|
|
296
|
-
return "all" + (0, import_pluralize.default)(suffix);
|
|
297
|
-
}
|
|
298
|
-
async function createDataFiles(collections, directory) {
|
|
299
|
-
for (const collection of collections) {
|
|
300
|
-
const dataPath = import_node_path2.default.join(
|
|
301
|
-
directory,
|
|
302
|
-
`${createArrayConstName(collection.name)}.json`
|
|
303
|
-
);
|
|
304
|
-
await import_promises3.default.writeFile(
|
|
305
|
-
dataPath,
|
|
306
|
-
JSON.stringify(
|
|
307
|
-
collection.documents.map((doc) => doc.document),
|
|
308
|
-
null,
|
|
309
|
-
2
|
|
310
|
-
)
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
async function createJavaScriptFile(configuration, directory) {
|
|
315
|
-
const collections = configuration.collections.map(
|
|
316
|
-
({ name }) => createArrayConstName(name)
|
|
317
|
-
);
|
|
318
|
-
let content = "";
|
|
319
|
-
for (const name of collections) {
|
|
320
|
-
content += `import ${name} from "./${name}.json";
|
|
321
|
-
`;
|
|
322
|
-
}
|
|
323
|
-
content += "\n";
|
|
324
|
-
content += "export { " + collections.join(", ") + " };\n";
|
|
325
|
-
await import_promises3.default.writeFile(import_node_path2.default.join(directory, "index.js"), content, "utf-8");
|
|
326
|
-
}
|
|
327
|
-
async function createTypeDefinitionFile(configuration, directory) {
|
|
328
|
-
const importPath = import_node_path2.default.relative(directory, configuration.path);
|
|
329
|
-
let content = `import mdxConfiguration from "${importPath}";
|
|
330
|
-
import { GetTypeByName } from "@mdx-collections/core";
|
|
331
|
-
`;
|
|
332
|
-
const collections = configuration.collections;
|
|
333
|
-
for (const collection of collections) {
|
|
334
|
-
content += `
|
|
335
|
-
`;
|
|
336
|
-
content += `export type ${collection.typeName} = GetTypeByName<typeof mdxConfiguration, "${collection.name}">;
|
|
337
|
-
`;
|
|
338
|
-
content += `export declare const ${createArrayConstName(
|
|
339
|
-
collection.name
|
|
340
|
-
)}: Array<${collection.typeName}>;
|
|
341
|
-
`;
|
|
342
|
-
}
|
|
343
|
-
content += "\n";
|
|
344
|
-
content += "export {};\n";
|
|
345
|
-
await import_promises3.default.writeFile(import_node_path2.default.join(directory, "index.d.ts"), content, "utf-8");
|
|
346
|
-
}
|
|
347
|
-
async function createRunner(configuration, directory) {
|
|
348
|
-
await import_promises3.default.mkdir(directory, { recursive: true });
|
|
349
|
-
const resolved = await collect(configuration.collections);
|
|
350
|
-
await createJavaScriptFile(configuration, directory);
|
|
351
|
-
if (configuration.generateTypes) {
|
|
352
|
-
await createTypeDefinitionFile(configuration, directory);
|
|
353
|
-
}
|
|
354
|
-
async function run() {
|
|
355
|
-
const collections = await transform(resolved);
|
|
356
|
-
await createDataFiles(collections, directory);
|
|
357
|
-
for (const collection of collections) {
|
|
358
|
-
if (collection.onSuccess) {
|
|
359
|
-
await collection.onSuccess(
|
|
360
|
-
collection.documents.map((doc) => doc.document)
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
return {
|
|
366
|
-
run,
|
|
367
|
-
sync: async (event, path5) => {
|
|
368
|
-
for (const collection of resolved) {
|
|
369
|
-
if (isIncluded(collection, path5)) {
|
|
370
|
-
await sync(collection, event, path5);
|
|
371
|
-
await run();
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// src/utils.ts
|
|
379
|
-
var import_camelcase = __toESM(require("camelcase"), 1);
|
|
380
|
-
var import_pluralize2 = __toESM(require("pluralize"), 1);
|
|
381
|
-
function generateTypeName(name) {
|
|
382
|
-
const singularName = import_pluralize2.default.singular(name);
|
|
383
|
-
return (0, import_camelcase.default)(singularName, { pascalCase: true });
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// src/config.ts
|
|
387
|
-
function defineCollection(collection) {
|
|
388
|
-
let typeName = collection.typeName;
|
|
389
|
-
if (!typeName) {
|
|
390
|
-
typeName = generateTypeName(collection.name);
|
|
391
|
-
}
|
|
392
|
-
return {
|
|
393
|
-
...collection,
|
|
394
|
-
typeName
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
function defineConfig(config) {
|
|
398
|
-
return config;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// src/index.ts
|
|
402
|
-
async function build2(config) {
|
|
403
|
-
const configuration = await applyConfig(config);
|
|
404
|
-
const baseDirectory = import_path2.default.dirname(config);
|
|
405
|
-
const directory = import_path2.default.join(baseDirectory, ".mdx-collections", "generated");
|
|
406
|
-
const runner = await createRunner(configuration, directory);
|
|
407
|
-
await runner.run();
|
|
408
|
-
}
|
|
409
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
410
|
-
0 && (module.exports = {
|
|
411
|
-
applyConfig,
|
|
412
|
-
build,
|
|
413
|
-
createRunner,
|
|
414
|
-
defineCollection,
|
|
415
|
-
defineConfig
|
|
416
|
-
});
|
package/dist/index.d.cts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { ZodTypeAny, z } from 'zod';
|
|
2
|
-
|
|
3
|
-
type Meta = {
|
|
4
|
-
path: string;
|
|
5
|
-
};
|
|
6
|
-
type Document<TSchema extends ZodTypeAny> = z.infer<TSchema> & {
|
|
7
|
-
_meta: Meta;
|
|
8
|
-
};
|
|
9
|
-
type Context = {
|
|
10
|
-
content(): Promise<string>;
|
|
11
|
-
documents<TCollection extends AnyCollection>(collection: TCollection): Array<Document<TCollection["schema"]>>;
|
|
12
|
-
};
|
|
13
|
-
type TransformFn<TSchema extends ZodTypeAny> = ((context: Context, data: Document<TSchema>) => any) | undefined;
|
|
14
|
-
type CollectionRequest<TSchema extends ZodTypeAny, TName extends string, TTransform extends TransformFn<TSchema>, TDocument> = {
|
|
15
|
-
name: TName;
|
|
16
|
-
typeName?: string;
|
|
17
|
-
schema: TSchema;
|
|
18
|
-
transform?: TTransform;
|
|
19
|
-
directory: string;
|
|
20
|
-
include: string | string[];
|
|
21
|
-
onSuccess?: (documents: Array<TDocument>) => void | Promise<void>;
|
|
22
|
-
};
|
|
23
|
-
type Collection<TSchema extends ZodTypeAny, TName extends string, TTransform extends TransformFn<TSchema>, TDocument> = CollectionRequest<TSchema, TName, TTransform, TDocument> & {
|
|
24
|
-
typeName: string;
|
|
25
|
-
};
|
|
26
|
-
type AnyCollection = Collection<ZodTypeAny, any, any, any>;
|
|
27
|
-
declare function defineCollection<TSchema extends ZodTypeAny, TName extends string, TTransform extends TransformFn<TSchema>, TDocument = [TTransform] extends [(...args: any) => any] ? Awaited<ReturnType<TTransform>> : Document<TSchema>>(collection: CollectionRequest<TSchema, TName, TTransform, TDocument>): Collection<TSchema, TName, TTransform, TDocument>;
|
|
28
|
-
type Configuration<TCollections extends Array<AnyCollection>> = {
|
|
29
|
-
collections: TCollections;
|
|
30
|
-
};
|
|
31
|
-
type AnyConfiguration = Configuration<Array<AnyCollection>>;
|
|
32
|
-
declare function defineConfig<TConfig extends AnyConfiguration>(config: TConfig): TConfig;
|
|
33
|
-
|
|
34
|
-
type InternalConfiguration = {
|
|
35
|
-
collections: Array<AnyCollection>;
|
|
36
|
-
path: string;
|
|
37
|
-
generateTypes?: boolean;
|
|
38
|
-
};
|
|
39
|
-
type Options = {
|
|
40
|
-
configName: string;
|
|
41
|
-
cacheDir?: string;
|
|
42
|
-
};
|
|
43
|
-
declare function applyConfig(config: string, options?: Options): Promise<InternalConfiguration>;
|
|
44
|
-
|
|
45
|
-
type Modification = "added" | "changed" | "removed";
|
|
46
|
-
type CollectionByName<TConfiguration extends AnyConfiguration> = {
|
|
47
|
-
[TCollection in TConfiguration["collections"][number] as TCollection["name"]]: TCollection;
|
|
48
|
-
};
|
|
49
|
-
type GetDocument<TCollection extends AnyCollection> = TCollection extends Collection<ZodTypeAny, any, any, infer TDocument> ? TDocument : never;
|
|
50
|
-
type GetTypeByName<TConfiguration extends AnyConfiguration, TName extends keyof CollectionByName<TConfiguration>, TCollection = CollectionByName<TConfiguration>[TName]> = TCollection extends AnyCollection ? GetDocument<TCollection> : never;
|
|
51
|
-
|
|
52
|
-
declare function createRunner(configuration: InternalConfiguration, directory: string): Promise<{
|
|
53
|
-
run: () => Promise<void>;
|
|
54
|
-
sync: (event: Modification, path: string) => Promise<void>;
|
|
55
|
-
}>;
|
|
56
|
-
|
|
57
|
-
declare function build(config: string): Promise<void>;
|
|
58
|
-
|
|
59
|
-
export { AnyCollection, AnyConfiguration, Collection, CollectionRequest, Configuration, Context, Document, GetTypeByName, Meta, Modification, applyConfig, build, createRunner, defineCollection, defineConfig };
|