@content-collections/core 0.1.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.
Files changed (87) hide show
  1. package/.turbo/turbo-build.log +14 -0
  2. package/.turbo/turbo-test.log +47 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/LICENSE +21 -0
  5. package/coverage/.tmp/coverage-0.json +1 -0
  6. package/coverage/.tmp/coverage-1.json +1 -0
  7. package/coverage/.tmp/coverage-2.json +1 -0
  8. package/coverage/.tmp/coverage-3.json +1 -0
  9. package/coverage/.tmp/coverage-4.json +1 -0
  10. package/coverage/.tmp/coverage-5.json +1 -0
  11. package/coverage/.tmp/coverage-6.json +1 -0
  12. package/coverage/.tmp/coverage-7.json +1 -0
  13. package/coverage/.tmp/coverage-8.json +1 -0
  14. package/coverage/.tmp/coverage-9.json +1 -0
  15. package/coverage/base.css +224 -0
  16. package/coverage/block-navigation.js +87 -0
  17. package/coverage/builder.ts.html +424 -0
  18. package/coverage/clover.xml +960 -0
  19. package/coverage/collector.ts.html +427 -0
  20. package/coverage/config.ts.html +403 -0
  21. package/coverage/configurationReader.ts.html +409 -0
  22. package/coverage/coverage-final.json +11 -0
  23. package/coverage/events.ts.html +310 -0
  24. package/coverage/favicon.png +0 -0
  25. package/coverage/index.html +251 -0
  26. package/coverage/index.ts.html +106 -0
  27. package/coverage/prettify.css +1 -0
  28. package/coverage/prettify.js +2 -0
  29. package/coverage/sort-arrow-sprite.png +0 -0
  30. package/coverage/sorter.js +196 -0
  31. package/coverage/synchronizer.ts.html +394 -0
  32. package/coverage/transformer.ts.html +607 -0
  33. package/coverage/utils.ts.html +118 -0
  34. package/coverage/writer.ts.html +424 -0
  35. package/dist/index.cjs +416 -0
  36. package/dist/index.d.cts +59 -0
  37. package/dist/index.d.ts +146 -0
  38. package/dist/index.js +630 -0
  39. package/package.json +39 -0
  40. package/src/__tests__/.content-collections/cache/config.001.ts.js +19 -0
  41. package/src/__tests__/.content-collections/cache/config.002.mjs +16 -0
  42. package/src/__tests__/.content-collections/cache/config.002.ts.js +16 -0
  43. package/src/__tests__/.content-collections/cache/config.003.ts.js +24 -0
  44. package/src/__tests__/.content-collections/cache/config.004.mjs +47 -0
  45. package/src/__tests__/.content-collections/different-cache-dir/different.config.js +19 -0
  46. package/src/__tests__/.content-collections/generated-config.002/allPosts.json +13 -0
  47. package/src/__tests__/.content-collections/generated-config.002/index.d.ts +7 -0
  48. package/src/__tests__/.content-collections/generated-config.002/index.js +5 -0
  49. package/src/__tests__/.content-collections/generated-config.004/allAuthors.json +13 -0
  50. package/src/__tests__/.content-collections/generated-config.004/allPosts.json +13 -0
  51. package/src/__tests__/.content-collections/generated-config.004/index.d.ts +10 -0
  52. package/src/__tests__/.content-collections/generated-config.004/index.js +6 -0
  53. package/src/__tests__/collections/posts.ts +15 -0
  54. package/src/__tests__/config.001.ts +19 -0
  55. package/src/__tests__/config.002.ts +14 -0
  56. package/src/__tests__/config.003.ts +6 -0
  57. package/src/__tests__/config.004.ts +47 -0
  58. package/src/__tests__/invalid +1 -0
  59. package/src/__tests__/sources/authors/trillian.md +8 -0
  60. package/src/__tests__/sources/posts/first.md +6 -0
  61. package/src/__tests__/sources/test/001.md +5 -0
  62. package/src/__tests__/sources/test/002.md +5 -0
  63. package/src/__tests__/sources/test/broken-frontmatter +6 -0
  64. package/src/builder.test.ts +180 -0
  65. package/src/builder.ts +113 -0
  66. package/src/collector.test.ts +157 -0
  67. package/src/collector.ts +114 -0
  68. package/src/config.ts +106 -0
  69. package/src/configurationReader.test.ts +104 -0
  70. package/src/configurationReader.ts +108 -0
  71. package/src/events.test.ts +84 -0
  72. package/src/events.ts +75 -0
  73. package/src/index.ts +7 -0
  74. package/src/synchronizer.test.ts +192 -0
  75. package/src/synchronizer.ts +103 -0
  76. package/src/transformer.test.ts +431 -0
  77. package/src/transformer.ts +174 -0
  78. package/src/types.test.ts +137 -0
  79. package/src/types.ts +33 -0
  80. package/src/utils.test.ts +48 -0
  81. package/src/utils.ts +11 -0
  82. package/src/watcher.test.ts +200 -0
  83. package/src/watcher.ts +56 -0
  84. package/src/writer.test.ts +135 -0
  85. package/src/writer.ts +113 -0
  86. package/tsconfig.json +27 -0
  87. package/vite.config.ts +24 -0
package/dist/index.js ADDED
@@ -0,0 +1,630 @@
1
+ // src/config.ts
2
+ import { z } from "zod";
3
+
4
+ // src/utils.ts
5
+ import camelcase from "camelcase";
6
+ import pluralize from "pluralize";
7
+ function generateTypeName(name) {
8
+ const singularName = pluralize.singular(name);
9
+ return camelcase(singularName, { pascalCase: true });
10
+ }
11
+ function isDefined(value) {
12
+ return value !== void 0 && value !== null;
13
+ }
14
+
15
+ // src/config.ts
16
+ function defineCollection(collection) {
17
+ let typeName = collection.typeName;
18
+ if (!typeName) {
19
+ typeName = generateTypeName(collection.name);
20
+ }
21
+ return {
22
+ ...collection,
23
+ typeName,
24
+ schema: collection.schema(z)
25
+ };
26
+ }
27
+ function defineConfig(config) {
28
+ return config;
29
+ }
30
+
31
+ // src/configurationReader.ts
32
+ import * as esbuild from "esbuild";
33
+ import fs from "fs/promises";
34
+ import path from "path";
35
+
36
+ // package.json
37
+ var package_default = {
38
+ name: "@content-collections/core",
39
+ version: "0.1.0",
40
+ type: "module",
41
+ main: "dist/index.cjs",
42
+ types: "./dist/index.d.ts",
43
+ exports: {
44
+ "./package.json": "./package.json",
45
+ ".": {
46
+ import: "./dist/index.js",
47
+ types: "./dist/index.d.ts"
48
+ }
49
+ },
50
+ scripts: {
51
+ build: "tsup src/index.ts --format esm --dts -d dist",
52
+ typecheck: "tsc",
53
+ test: "vitest --run --coverage"
54
+ },
55
+ devDependencies: {
56
+ "@types/micromatch": "^4.0.6",
57
+ "@types/node": "^20.9.0",
58
+ "@types/pluralize": "^0.0.33",
59
+ "@vitest/coverage-v8": "^1.1.0",
60
+ tsup: "^7.2.0",
61
+ tsx: "^4.1.1",
62
+ typescript: "^5.3.3",
63
+ vitest: "^1.1.0"
64
+ },
65
+ dependencies: {
66
+ "@parcel/watcher": "^2.3.0",
67
+ camelcase: "^8.0.0",
68
+ esbuild: "^0.19.5",
69
+ "fast-glob": "^3.3.2",
70
+ "gray-matter": "^4.0.3",
71
+ micromatch: "^4.0.5",
72
+ pluralize: "^8.0.0",
73
+ zod: "^3.22.4"
74
+ }
75
+ };
76
+
77
+ // src/configurationReader.ts
78
+ import { existsSync } from "fs";
79
+ var ConfigurationError = class extends Error {
80
+ type;
81
+ constructor(type, message) {
82
+ super(message);
83
+ this.type = type;
84
+ }
85
+ };
86
+ var importPathPlugin = {
87
+ name: "import-path",
88
+ setup(build2) {
89
+ build2.onResolve({ filter: /^\@content-collections\/core$/ }, () => {
90
+ return { path: path.join(__dirname, "index.ts"), external: true };
91
+ });
92
+ }
93
+ };
94
+ var defaultConfigName = "content-collection-config.mjs";
95
+ function resolveCacheDir(config, options) {
96
+ if (options.cacheDir) {
97
+ return options.cacheDir;
98
+ }
99
+ return path.join(path.dirname(config), ".content-collections", "cache");
100
+ }
101
+ async function compile(configurationPath, outfile) {
102
+ const plugins = [];
103
+ if (process.env.NODE_ENV === "test") {
104
+ plugins.push(importPathPlugin);
105
+ }
106
+ await esbuild.build({
107
+ entryPoints: [configurationPath],
108
+ external: [...Object.keys(package_default.dependencies), "@content-collections/*"],
109
+ bundle: true,
110
+ platform: "node",
111
+ format: "esm",
112
+ plugins,
113
+ outfile
114
+ });
115
+ }
116
+ function createConfigurationReader() {
117
+ return async (configurationPath, options = {
118
+ configName: defaultConfigName
119
+ }) => {
120
+ if (!existsSync(configurationPath)) {
121
+ throw new ConfigurationError(
122
+ "Read",
123
+ `configuration file ${configurationPath} does not exist`
124
+ );
125
+ }
126
+ const cacheDir = resolveCacheDir(configurationPath, options);
127
+ await fs.mkdir(cacheDir, { recursive: true });
128
+ const outfile = path.join(cacheDir, options.configName);
129
+ try {
130
+ await compile(configurationPath, outfile);
131
+ } catch (error) {
132
+ throw new ConfigurationError(
133
+ "Compile",
134
+ `configuration file ${configurationPath} is invalid: ${error}`
135
+ );
136
+ }
137
+ const module = await import(`file://${path.resolve(outfile)}?x=${Date.now()}`);
138
+ return {
139
+ ...module.default,
140
+ path: configurationPath,
141
+ generateTypes: true
142
+ };
143
+ };
144
+ }
145
+
146
+ // src/collector.ts
147
+ import matter from "gray-matter";
148
+ import fg from "fast-glob";
149
+ import { readFile } from "fs/promises";
150
+ import path2 from "path";
151
+ var CollectError = class extends Error {
152
+ type;
153
+ constructor(type, message) {
154
+ super(message);
155
+ this.type = type;
156
+ }
157
+ };
158
+ function createCollector(emitter, baseDirectory = ".") {
159
+ async function read(filePath) {
160
+ try {
161
+ return await readFile(filePath, "utf-8");
162
+ } catch (error) {
163
+ emitter.emit("collector:read-error", {
164
+ filePath,
165
+ error: new CollectError("Read", String(error))
166
+ });
167
+ return null;
168
+ }
169
+ }
170
+ function parse(file) {
171
+ const { data, content } = matter(file);
172
+ return {
173
+ ...data,
174
+ content
175
+ };
176
+ }
177
+ async function collectFile(directory, filePath) {
178
+ const file = await read(path2.join(directory, filePath));
179
+ if (!file) {
180
+ return null;
181
+ }
182
+ try {
183
+ const data = parse(file);
184
+ return {
185
+ data,
186
+ path: filePath
187
+ };
188
+ } catch (error) {
189
+ emitter.emit("collector:parse-error", {
190
+ filePath: path2.join(directory, filePath),
191
+ error: new CollectError("Parse", String(error))
192
+ });
193
+ return null;
194
+ }
195
+ }
196
+ async function resolveCollection(collection) {
197
+ const collectionDirectory = path2.join(baseDirectory, collection.directory);
198
+ const filePaths = await fg(collection.include, {
199
+ cwd: collectionDirectory,
200
+ onlyFiles: true,
201
+ absolute: false
202
+ });
203
+ const promises = filePaths.map(
204
+ (filePath) => collectFile(collectionDirectory, filePath)
205
+ );
206
+ const files = await Promise.all(promises);
207
+ return {
208
+ ...collection,
209
+ files: files.filter(isDefined)
210
+ };
211
+ }
212
+ async function collect(unresolvedCollections) {
213
+ const promises = unresolvedCollections.map(
214
+ (collection) => resolveCollection(collection)
215
+ );
216
+ return await Promise.all(promises);
217
+ }
218
+ return {
219
+ collect,
220
+ collectFile
221
+ };
222
+ }
223
+
224
+ // src/writer.ts
225
+ import fs2 from "fs/promises";
226
+ import path3 from "path";
227
+ import pluralize2 from "pluralize";
228
+ function createArrayConstName(name) {
229
+ let suffix = name.charAt(0).toUpperCase() + name.slice(1);
230
+ return "all" + pluralize2(suffix);
231
+ }
232
+ async function createDataFile(directory, collection) {
233
+ const dataPath = path3.join(
234
+ directory,
235
+ `${createArrayConstName(collection.name)}.json`
236
+ );
237
+ await fs2.writeFile(
238
+ dataPath,
239
+ JSON.stringify(
240
+ collection.documents.map((doc) => doc.document),
241
+ null,
242
+ 2
243
+ )
244
+ );
245
+ }
246
+ function createDataFiles(directory, collections) {
247
+ return Promise.all(
248
+ collections.map((collection) => createDataFile(directory, collection))
249
+ );
250
+ }
251
+ async function createJavaScriptFile(directory, configuration) {
252
+ const collections = configuration.collections.map(
253
+ ({ name }) => createArrayConstName(name)
254
+ );
255
+ let content = `// generated by content-collections at ${/* @__PURE__ */ new Date()}
256
+
257
+ `;
258
+ for (const name of collections) {
259
+ content += `import ${name} from "./${name}.json";
260
+ `;
261
+ }
262
+ content += "\n";
263
+ content += "export { " + collections.join(", ") + " };\n";
264
+ await fs2.writeFile(path3.join(directory, "index.js"), content, "utf-8");
265
+ }
266
+ async function createTypeDefinitionFile(directory, configuration) {
267
+ if (!configuration.generateTypes) {
268
+ return;
269
+ }
270
+ const importPath = path3.relative(directory, configuration.path);
271
+ let content = `import configuration from "${importPath}";
272
+ import { GetTypeByName } from "@content-collections/core";
273
+ `;
274
+ const collections = configuration.collections;
275
+ for (const collection of collections) {
276
+ content += `
277
+ `;
278
+ content += `export type ${collection.typeName} = GetTypeByName<typeof configuration, "${collection.name}">;
279
+ `;
280
+ content += `export declare const ${createArrayConstName(
281
+ collection.name
282
+ )}: Array<${collection.typeName}>;
283
+ `;
284
+ }
285
+ content += "\n";
286
+ content += "export {};\n";
287
+ await fs2.writeFile(path3.join(directory, "index.d.ts"), content, "utf-8");
288
+ }
289
+ async function createWriter(directory) {
290
+ await fs2.mkdir(directory, { recursive: true });
291
+ return {
292
+ createJavaScriptFile: (configuration) => createJavaScriptFile(directory, configuration),
293
+ createTypeDefinitionFile: (configuration) => createTypeDefinitionFile(directory, configuration),
294
+ createDataFiles: (collections) => createDataFiles(directory, collections)
295
+ };
296
+ }
297
+
298
+ // src/transformer.ts
299
+ import { basename, dirname, extname } from "path";
300
+ import { z as z2 } from "zod";
301
+ var TransformError = class extends Error {
302
+ type;
303
+ constructor(type, message) {
304
+ super(message);
305
+ this.type = type;
306
+ }
307
+ };
308
+ function createPath(path6, ext) {
309
+ let p = path6.slice(0, -ext.length);
310
+ if (p.endsWith("/index")) {
311
+ p = p.slice(0, -6);
312
+ }
313
+ return p;
314
+ }
315
+ function createTransformer(emitter) {
316
+ function createSchema(schema) {
317
+ return z2.object({
318
+ content: z2.string(),
319
+ ...schema
320
+ });
321
+ }
322
+ async function parseFile(collection, file) {
323
+ const { data, path: path6 } = file;
324
+ const schema = createSchema(collection.schema);
325
+ let parsedData = await schema.safeParseAsync(data);
326
+ if (!parsedData.success) {
327
+ emitter.emit("transformer:validation-error", {
328
+ collection,
329
+ file,
330
+ error: new TransformError("Validation", parsedData.error.message)
331
+ });
332
+ return null;
333
+ }
334
+ const ext = extname(path6);
335
+ let extension = ext;
336
+ if (extension.startsWith(".")) {
337
+ extension = extension.slice(1);
338
+ }
339
+ const document = {
340
+ ...parsedData.data,
341
+ _meta: {
342
+ filePath: path6,
343
+ fileName: basename(path6),
344
+ directory: dirname(path6),
345
+ extension,
346
+ path: createPath(path6, ext)
347
+ }
348
+ };
349
+ return {
350
+ document
351
+ };
352
+ }
353
+ async function parseCollection(collection) {
354
+ const promises = collection.files.map(
355
+ (file) => parseFile(collection, file)
356
+ );
357
+ return {
358
+ ...collection,
359
+ documents: (await Promise.all(promises)).filter(isDefined)
360
+ };
361
+ }
362
+ function createContext(collections) {
363
+ return {
364
+ documents: (collection) => {
365
+ const resolved = collections.find((c) => c.name === collection.name);
366
+ if (!resolved) {
367
+ throw new TransformError(
368
+ "Configuration",
369
+ `Collection ${collection.name} not found, do you have registered it in your configuration?`
370
+ );
371
+ }
372
+ return resolved.documents.map((doc) => doc.document);
373
+ }
374
+ };
375
+ }
376
+ async function transformCollection(collections, collection) {
377
+ if (collection.transform) {
378
+ const docs = [];
379
+ const context = createContext(collections);
380
+ for (const doc of collection.documents) {
381
+ try {
382
+ docs.push({
383
+ ...doc,
384
+ document: await collection.transform(context, doc.document)
385
+ });
386
+ } catch (error) {
387
+ if (error instanceof TransformError) {
388
+ emitter.emit("transformer:error", {
389
+ collection,
390
+ error
391
+ });
392
+ } else {
393
+ emitter.emit("transformer:error", {
394
+ collection,
395
+ error: new TransformError("Transform", String(error))
396
+ });
397
+ }
398
+ }
399
+ }
400
+ return docs;
401
+ }
402
+ return collection.documents;
403
+ }
404
+ return async (untransformedCollections) => {
405
+ const promises = untransformedCollections.map(
406
+ (collection) => parseCollection(collection)
407
+ );
408
+ const collections = await Promise.all(promises);
409
+ for (const collection of collections) {
410
+ collection.documents = await transformCollection(collections, collection);
411
+ }
412
+ return collections;
413
+ };
414
+ }
415
+
416
+ // src/synchronizer.ts
417
+ import micromatch from "micromatch";
418
+ import path4 from "path";
419
+ function createSynchronizer(readCollectionFile, collections, baseDirectory = ".") {
420
+ function findCollection(filePath) {
421
+ const resolvedFilePath = path4.resolve(filePath);
422
+ return collections.find((collection) => {
423
+ return resolvedFilePath.startsWith(
424
+ path4.resolve(baseDirectory, collection.directory)
425
+ );
426
+ });
427
+ }
428
+ function createRelativePath(collectionPath, filePath) {
429
+ const resolvedCollectionPath = path4.resolve(baseDirectory, collectionPath);
430
+ const resolvedFilePath = path4.resolve(filePath);
431
+ let relativePath = resolvedFilePath.slice(resolvedCollectionPath.length);
432
+ if (relativePath.startsWith("/")) {
433
+ relativePath = relativePath.slice(1);
434
+ }
435
+ return relativePath;
436
+ }
437
+ function resolve(filePath) {
438
+ const collection = findCollection(filePath);
439
+ if (!collection) {
440
+ return null;
441
+ }
442
+ const relativePath = createRelativePath(collection.directory, filePath);
443
+ if (!micromatch.isMatch(relativePath, collection.include)) {
444
+ return null;
445
+ }
446
+ return {
447
+ collection,
448
+ relativePath
449
+ };
450
+ }
451
+ function deleted(filePath) {
452
+ const resolved = resolve(filePath);
453
+ if (!resolved) {
454
+ return false;
455
+ }
456
+ const { collection, relativePath } = resolved;
457
+ const index = collection.files.findIndex(
458
+ (file) => file.path === relativePath
459
+ );
460
+ const deleted2 = collection.files.splice(index, 1);
461
+ return deleted2.length > 0;
462
+ }
463
+ async function changed(filePath) {
464
+ const resolved = resolve(filePath);
465
+ if (!resolved) {
466
+ return false;
467
+ }
468
+ const { collection, relativePath } = resolved;
469
+ const index = collection.files.findIndex(
470
+ (file2) => file2.path === relativePath
471
+ );
472
+ const file = await readCollectionFile(
473
+ path4.join(baseDirectory, collection.directory),
474
+ relativePath
475
+ );
476
+ if (!file) {
477
+ return false;
478
+ }
479
+ if (index === -1) {
480
+ collection.files.push(file);
481
+ } else {
482
+ collection.files[index] = file;
483
+ }
484
+ return true;
485
+ }
486
+ return {
487
+ deleted,
488
+ changed
489
+ };
490
+ }
491
+
492
+ // src/builder.ts
493
+ import path5 from "path";
494
+
495
+ // src/watcher.ts
496
+ import watcher from "@parcel/watcher";
497
+ async function createWatcher(emitter, paths, sync, build2) {
498
+ const onChange = async (error, events) => {
499
+ if (error) {
500
+ console.error(error);
501
+ return;
502
+ }
503
+ let rebuild = false;
504
+ for (const event of events) {
505
+ if (await sync(event.type, event.path)) {
506
+ emitter.emit("watcher:file-changed", {
507
+ filePath: event.path,
508
+ modification: event.type
509
+ });
510
+ rebuild = true;
511
+ }
512
+ }
513
+ if (rebuild) {
514
+ await build2();
515
+ }
516
+ };
517
+ const subscriptions = await Promise.all(
518
+ paths.map((path6) => watcher.subscribe(path6, onChange))
519
+ );
520
+ return {
521
+ unsubscribe: async () => {
522
+ await Promise.all(
523
+ subscriptions.map((subscription) => subscription.unsubscribe())
524
+ );
525
+ return;
526
+ }
527
+ };
528
+ }
529
+
530
+ // src/events.ts
531
+ import { EventEmitter } from "events";
532
+ function isEventWithError(event) {
533
+ return typeof event === "object" && event !== null && "error" in event;
534
+ }
535
+ function createEmitter() {
536
+ const emitter = new EventEmitter();
537
+ function on(key, listener) {
538
+ emitter.on(key, listener);
539
+ }
540
+ function emit(key, event) {
541
+ emitter.emit(key, event);
542
+ if (isEventWithError(event)) {
543
+ emitter.emit("_error", {
544
+ ...event,
545
+ _event: key
546
+ });
547
+ }
548
+ emitter.emit("_all", {
549
+ ...event,
550
+ _event: key
551
+ });
552
+ }
553
+ return {
554
+ on,
555
+ emit
556
+ };
557
+ }
558
+
559
+ // src/builder.ts
560
+ function resolveOutputDir(baseDirectory, options) {
561
+ if (options.outputDir) {
562
+ return options.outputDir;
563
+ }
564
+ return path5.join(baseDirectory, ".content-collections", "generated");
565
+ }
566
+ async function createBuilder(configurationPath, options = {
567
+ configName: defaultConfigName
568
+ }) {
569
+ const emitter = createEmitter();
570
+ const readConfiguration = createConfigurationReader();
571
+ const configuration = await readConfiguration(configurationPath, options);
572
+ const baseDirectory = path5.dirname(configurationPath);
573
+ const directory = resolveOutputDir(baseDirectory, options);
574
+ const collector = createCollector(emitter, baseDirectory);
575
+ const writer = await createWriter(directory);
576
+ const [resolved] = await Promise.all([
577
+ collector.collect(configuration.collections),
578
+ writer.createJavaScriptFile(configuration),
579
+ writer.createTypeDefinitionFile(configuration)
580
+ ]);
581
+ const synchronizer = createSynchronizer(
582
+ collector.collectFile,
583
+ resolved,
584
+ baseDirectory
585
+ );
586
+ const transform = createTransformer(emitter);
587
+ async function sync(modification, filePath) {
588
+ if (modification === "delete") {
589
+ return synchronizer.deleted(filePath);
590
+ }
591
+ return synchronizer.changed(filePath);
592
+ }
593
+ async function build2() {
594
+ const startedAt = Date.now();
595
+ emitter.emit("builder:start", {
596
+ startedAt
597
+ });
598
+ const collections = await transform(resolved);
599
+ await writer.createDataFiles(collections);
600
+ const pendingOnSuccess = collections.filter((collection) => Boolean(collection.onSuccess)).map(
601
+ (collection) => collection.onSuccess?.(collection.documents.map((doc) => doc.document))
602
+ );
603
+ await Promise.all(pendingOnSuccess.filter(isDefined));
604
+ emitter.emit("builder:end", {
605
+ startedAt,
606
+ endedAt: Date.now()
607
+ });
608
+ }
609
+ async function watch() {
610
+ const paths = resolved.map(
611
+ (collection) => path5.join(baseDirectory, collection.directory)
612
+ );
613
+ const watcher2 = await createWatcher(emitter, paths, sync, build2);
614
+ return watcher2;
615
+ }
616
+ return {
617
+ sync,
618
+ build: build2,
619
+ watch,
620
+ on: emitter.on
621
+ };
622
+ }
623
+ export {
624
+ CollectError,
625
+ ConfigurationError,
626
+ TransformError,
627
+ createBuilder,
628
+ defineCollection,
629
+ defineConfig
630
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@content-collections/core",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.cjs",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ "./package.json": "./package.json",
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "devDependencies": {
15
+ "@types/micromatch": "^4.0.6",
16
+ "@types/node": "^20.9.0",
17
+ "@types/pluralize": "^0.0.33",
18
+ "@vitest/coverage-v8": "^1.1.0",
19
+ "tsup": "^7.2.0",
20
+ "tsx": "^4.1.1",
21
+ "typescript": "^5.3.3",
22
+ "vitest": "^1.1.0"
23
+ },
24
+ "dependencies": {
25
+ "@parcel/watcher": "^2.3.0",
26
+ "camelcase": "^8.0.0",
27
+ "esbuild": "^0.19.5",
28
+ "fast-glob": "^3.3.2",
29
+ "gray-matter": "^4.0.3",
30
+ "micromatch": "^4.0.5",
31
+ "pluralize": "^8.0.0",
32
+ "zod": "^3.22.4"
33
+ },
34
+ "scripts": {
35
+ "build": "tsup src/index.ts --format esm --dts -d dist",
36
+ "typecheck": "tsc",
37
+ "test": "vitest --run --coverage"
38
+ }
39
+ }
@@ -0,0 +1,19 @@
1
+ // src/__tests__/config.001.ts
2
+ import { defineCollection, defineConfig } from "/Users/sdorra/Projects/sdorra/content-collections/packages/core/src/index.ts";
3
+ var posts = defineCollection({
4
+ name: "posts",
5
+ typeName: "Post",
6
+ schema: (z) => ({
7
+ title: z.string().min(5),
8
+ description: z.string().min(10),
9
+ date: z.union([z.string().regex(/^\d{4}-\d{2}-\d{2}$/), z.date()]).transform((val) => new Date(val))
10
+ }),
11
+ directory: "sources/posts",
12
+ include: "**/*.md(x)?"
13
+ });
14
+ var config_001_default = defineConfig({
15
+ collections: [posts]
16
+ });
17
+ export {
18
+ config_001_default as default
19
+ };
@@ -0,0 +1,16 @@
1
+ // src/__tests__/config.002.ts
2
+ import { defineCollection, defineConfig } from "/Users/sdorra/Projects/sdorra/content-collections/packages/core/src/index.ts";
3
+ var posts = defineCollection({
4
+ name: "posts",
5
+ schema: (z) => ({
6
+ title: z.string()
7
+ }),
8
+ directory: "sources/posts",
9
+ include: "**/*.md(x)?"
10
+ });
11
+ var config_002_default = defineConfig({
12
+ collections: [posts]
13
+ });
14
+ export {
15
+ config_002_default as default
16
+ };