@content-collections/core 0.6.1 → 0.6.3

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 CHANGED
@@ -1,8 +1,9 @@
1
- import z, { ZodRawShape, z as z$1, ZodObject, ZodTypeAny, ZodString } from 'zod';
2
- import { parse } from 'yaml';
1
+ import z__default, { ZodRawShape, z as z$1, ZodObject, ZodTypeAny, ZodString } from 'zod';
2
+ export * from 'zod';
3
3
 
4
4
  type Parsers = typeof parsers;
5
5
  type Parser = keyof typeof parsers;
6
+ declare function parseYaml(content: string): any;
6
7
  declare function frontmatterParser(fileContent: string): {
7
8
  content: string;
8
9
  };
@@ -17,14 +18,14 @@ declare const parsers: {
17
18
  };
18
19
  readonly yaml: {
19
20
  readonly hasContent: false;
20
- readonly parse: typeof parse;
21
+ readonly parse: typeof parseYaml;
21
22
  };
22
23
  };
23
24
 
24
25
  type CacheFn = <TInput, TOutput>(input: TInput, compute: (input: TInput) => Promise<TOutput> | TOutput) => Promise<TOutput>;
25
26
 
26
- declare const literalSchema: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull, z.ZodUndefined, z.ZodDate, z.ZodMap<z.ZodUnknown, z.ZodUnknown>, z.ZodSet<z.ZodUnknown>, z.ZodBigInt]>;
27
- type Literal = z.infer<typeof literalSchema>;
27
+ declare const literalSchema: z__default.ZodUnion<[z__default.ZodString, z__default.ZodNumber, z__default.ZodBoolean, z__default.ZodNull, z__default.ZodUndefined, z__default.ZodDate, z__default.ZodMap<z__default.ZodUnknown, z__default.ZodUnknown>, z__default.ZodSet<z__default.ZodUnknown>, z__default.ZodBigInt]>;
28
+ type Literal = z__default.infer<typeof literalSchema>;
28
29
  type SchemaType = Literal | {
29
30
  [key: string]: SchemaType;
30
31
  } | SchemaType[];
@@ -32,8 +33,8 @@ type NotSerializableError = `The return type of the transform function must be a
32
33
  See https://www.content-collections.dev/docs/serialization for more information.
33
34
 
34
35
  The following type is not valid:`;
35
- declare const serializableSchema: z.ZodRecord<z.ZodString, z.ZodType<SchemaType, z.ZodTypeDef, SchemaType>>;
36
- type Serializable = z.infer<typeof serializableSchema>;
36
+ declare const serializableSchema: z__default.ZodRecord<z__default.ZodString, z__default.ZodType<SchemaType, z__default.ZodTypeDef, SchemaType>>;
37
+ type Serializable = z__default.infer<typeof serializableSchema>;
37
38
 
38
39
  type Meta = {
39
40
  filePath: string;
package/dist/index.js CHANGED
@@ -134,11 +134,14 @@ import path2 from "path";
134
134
  // src/parser.ts
135
135
  import matter from "gray-matter";
136
136
  import { parse, stringify } from "yaml";
137
+ function parseYaml(content) {
138
+ return parse(content.trim());
139
+ }
137
140
  function frontmatterParser(fileContent) {
138
141
  const { data, content } = matter(fileContent, {
139
142
  engines: {
140
143
  yaml: {
141
- parse,
144
+ parse: parseYaml,
142
145
  stringify
143
146
  }
144
147
  }
@@ -159,7 +162,7 @@ var parsers = {
159
162
  },
160
163
  yaml: {
161
164
  hasContent: false,
162
- parse
165
+ parse: parseYaml
163
166
  }
164
167
  };
165
168
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@content-collections/core",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/dist/index.cjs DELETED
@@ -1,919 +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
- CollectError: () => CollectError,
34
- ConfigurationError: () => ConfigurationError,
35
- TransformError: () => TransformError,
36
- createBuilder: () => createBuilder,
37
- defineCollection: () => defineCollection,
38
- defineConfig: () => defineConfig
39
- });
40
- module.exports = __toCommonJS(src_exports);
41
-
42
- // src/config.ts
43
- var import_zod = require("zod");
44
-
45
- // src/utils.ts
46
- var import_pluralize = __toESM(require("pluralize"), 1);
47
- function camelCase(name) {
48
- return name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
49
- }
50
- function generateTypeName(name) {
51
- const singularName = import_pluralize.default.singular(name);
52
- return camelCase(singularName);
53
- }
54
- function isDefined(value) {
55
- return value !== void 0 && value !== null;
56
- }
57
- function orderByPath(a, b) {
58
- return a.path.localeCompare(b.path);
59
- }
60
-
61
- // src/config.ts
62
- var InvalidReturnTypeSymbol = Symbol(`InvalidReturnType`);
63
- function defineCollection(collection) {
64
- let typeName = collection.typeName;
65
- if (!typeName) {
66
- typeName = generateTypeName(collection.name);
67
- }
68
- let parser = collection.parser;
69
- if (!parser) {
70
- parser = "frontmatter";
71
- }
72
- return {
73
- ...collection,
74
- typeName,
75
- parser,
76
- schema: collection.schema(import_zod.z)
77
- };
78
- }
79
- function defineConfig(config) {
80
- return config;
81
- }
82
-
83
- // src/configurationReader.ts
84
- var esbuild = __toESM(require("esbuild"), 1);
85
- var import_promises = __toESM(require("fs/promises"), 1);
86
- var import_node_path = __toESM(require("path"), 1);
87
-
88
- // package.json
89
- var package_default = {
90
- name: "@content-collections/core",
91
- version: "0.6.0",
92
- type: "module",
93
- main: "dist/index.cjs",
94
- types: "./dist/index.d.cts",
95
- exports: {
96
- "./package.json": "./package.json",
97
- ".": {
98
- import: {
99
- default: "./dist/index.js",
100
- types: "./dist/index.d.ts"
101
- },
102
- require: {
103
- default: "./dist/index.cjs",
104
- types: "./dist/index.d.cts"
105
- }
106
- }
107
- },
108
- files: [
109
- "dist",
110
- "README.md"
111
- ],
112
- scripts: {
113
- build: "tsup src/index.ts --format esm,cjs --dts -d dist",
114
- typecheck: "tsc",
115
- test: "vitest --run --coverage",
116
- prepack: "cp ../../README.md ./README.md",
117
- postpack: "rm -f ./README.md"
118
- },
119
- peerDependencies: {
120
- typescript: "^5.0.2"
121
- },
122
- devDependencies: {
123
- "@types/micromatch": "^4.0.7",
124
- "@types/node": "^20.14.9",
125
- "@types/pluralize": "^0.0.33",
126
- "@types/serialize-javascript": "^5.0.4",
127
- "@vitest/coverage-v8": "^1.5.0",
128
- tsup: "^8.0.2",
129
- tsx: "^4.1.1",
130
- typescript: "^5.4.5",
131
- vitest: "^1.5.0"
132
- },
133
- dependencies: {
134
- "@parcel/watcher": "^2.4.1",
135
- esbuild: "^0.21.4",
136
- "fast-glob": "^3.3.2",
137
- "gray-matter": "^4.0.3",
138
- micromatch: "^4.0.7",
139
- pluralize: "^8.0.0",
140
- "serialize-javascript": "^6.0.2",
141
- yaml: "^2.4.1",
142
- zod: "^3.22.5"
143
- }
144
- };
145
-
146
- // src/configurationReader.ts
147
- var import_node_fs = require("fs");
148
- var import_node_crypto = require("crypto");
149
- var ConfigurationError = class extends Error {
150
- type;
151
- constructor(type, message) {
152
- super(message);
153
- this.type = type;
154
- }
155
- };
156
- var importPathPlugin = {
157
- name: "import-path",
158
- setup(build2) {
159
- build2.onResolve({ filter: /^\@content-collections\/core$/ }, () => {
160
- return { path: import_node_path.default.join(__dirname, "index.ts"), external: true };
161
- });
162
- }
163
- };
164
- var defaultConfigName = "content-collection-config.mjs";
165
- function resolveCacheDir(config, options) {
166
- if (options.cacheDir) {
167
- return options.cacheDir;
168
- }
169
- return import_node_path.default.join(import_node_path.default.dirname(config), ".content-collections", "cache");
170
- }
171
- var makeAllPackagesExternalPlugin = (configPath) => ({
172
- name: "make-all-packages-external",
173
- setup: (build2) => {
174
- const filter = /^[^.\/]|^\.[^.\/]|^\.\.[^\/]/;
175
- build2.onResolve({ filter }, (args) => {
176
- if (args.path.includes(configPath)) {
177
- return { path: args.path, external: false };
178
- }
179
- return { path: args.path, external: true };
180
- });
181
- }
182
- });
183
- async function compile(configurationPath, outfile) {
184
- const plugins = [makeAllPackagesExternalPlugin(configurationPath)];
185
- if (process.env.NODE_ENV === "test") {
186
- plugins.push(importPathPlugin);
187
- }
188
- await esbuild.build({
189
- entryPoints: [configurationPath],
190
- packages: "external",
191
- external: [
192
- ...Object.keys(package_default.dependencies),
193
- "@content-collections/*"
194
- ],
195
- bundle: true,
196
- platform: "node",
197
- format: "esm",
198
- plugins,
199
- outfile
200
- });
201
- }
202
- function createConfigurationReader() {
203
- return async (configurationPath, options = {
204
- configName: defaultConfigName
205
- }) => {
206
- if (!(0, import_node_fs.existsSync)(configurationPath)) {
207
- throw new ConfigurationError(
208
- "Read",
209
- `configuration file ${configurationPath} does not exist`
210
- );
211
- }
212
- const cacheDir = resolveCacheDir(configurationPath, options);
213
- await import_promises.default.mkdir(cacheDir, { recursive: true });
214
- const outfile = import_node_path.default.join(cacheDir, options.configName);
215
- try {
216
- await compile(configurationPath, outfile);
217
- } catch (error) {
218
- throw new ConfigurationError(
219
- "Compile",
220
- `configuration file ${configurationPath} is invalid: ${error}`
221
- );
222
- }
223
- const module2 = await import(`file://${import_node_path.default.resolve(outfile)}?x=${Date.now()}`);
224
- const hash = (0, import_node_crypto.createHash)("sha256");
225
- hash.update(await import_promises.default.readFile(outfile, "utf-8"));
226
- const checksum = hash.digest("hex");
227
- return {
228
- ...module2.default,
229
- path: configurationPath,
230
- generateTypes: true,
231
- checksum
232
- };
233
- };
234
- }
235
-
236
- // src/collector.ts
237
- var import_fast_glob = __toESM(require("fast-glob"), 1);
238
- var import_promises2 = require("fs/promises");
239
- var import_path = __toESM(require("path"), 1);
240
-
241
- // src/parser.ts
242
- var import_gray_matter = __toESM(require("gray-matter"), 1);
243
- var import_yaml = require("yaml");
244
- function frontmatterParser(fileContent) {
245
- const { data, content } = (0, import_gray_matter.default)(fileContent, {
246
- engines: {
247
- yaml: {
248
- parse: import_yaml.parse,
249
- stringify: import_yaml.stringify
250
- }
251
- }
252
- });
253
- return {
254
- ...data,
255
- content: content.trim()
256
- };
257
- }
258
- var parsers = {
259
- frontmatter: {
260
- hasContent: true,
261
- parse: frontmatterParser
262
- },
263
- json: {
264
- hasContent: false,
265
- parse: JSON.parse
266
- },
267
- yaml: {
268
- hasContent: false,
269
- parse: import_yaml.parse
270
- }
271
- };
272
-
273
- // src/collector.ts
274
- var CollectError = class extends Error {
275
- type;
276
- constructor(type, message) {
277
- super(message);
278
- this.type = type;
279
- }
280
- };
281
- function createCollector(emitter, baseDirectory = ".") {
282
- async function read(filePath) {
283
- try {
284
- return await (0, import_promises2.readFile)(filePath, "utf-8");
285
- } catch (error) {
286
- emitter.emit("collector:read-error", {
287
- filePath,
288
- error: new CollectError("Read", String(error))
289
- });
290
- return null;
291
- }
292
- }
293
- async function collectFile(collection, filePath) {
294
- const absolutePath = import_path.default.join(baseDirectory, collection.directory, filePath);
295
- const file = await read(absolutePath);
296
- if (!file) {
297
- return null;
298
- }
299
- try {
300
- const data = parsers[collection.parser].parse(file);
301
- return {
302
- data,
303
- path: filePath
304
- };
305
- } catch (error) {
306
- emitter.emit("collector:parse-error", {
307
- filePath: import_path.default.join(collection.directory, filePath),
308
- error: new CollectError("Parse", String(error))
309
- });
310
- return null;
311
- }
312
- }
313
- function createIgnorePattern(collection) {
314
- if (collection.exclude) {
315
- if (Array.isArray(collection.exclude)) {
316
- return collection.exclude;
317
- } else {
318
- return [collection.exclude];
319
- }
320
- }
321
- return void 0;
322
- }
323
- async function resolveCollection(collection) {
324
- const collectionDirectory = import_path.default.join(baseDirectory, collection.directory);
325
- const filePaths = await (0, import_fast_glob.default)(collection.include, {
326
- cwd: collectionDirectory,
327
- onlyFiles: true,
328
- absolute: false,
329
- ignore: createIgnorePattern(collection)
330
- });
331
- const promises = filePaths.map(
332
- (filePath) => collectFile(collection, filePath)
333
- );
334
- const files = await Promise.all(promises);
335
- return {
336
- ...collection,
337
- files: files.filter(isDefined).sort(orderByPath)
338
- };
339
- }
340
- async function collect(unresolvedCollections) {
341
- const promises = unresolvedCollections.map(
342
- (collection) => resolveCollection(collection)
343
- );
344
- return await Promise.all(promises);
345
- }
346
- return {
347
- collect,
348
- collectFile
349
- };
350
- }
351
-
352
- // src/writer.ts
353
- var import_promises3 = __toESM(require("fs/promises"), 1);
354
- var import_node_path2 = __toESM(require("path"), 1);
355
- var import_pluralize2 = __toESM(require("pluralize"), 1);
356
-
357
- // src/serializer.ts
358
- var import_zod2 = __toESM(require("zod"), 1);
359
- var import_serialize_javascript = __toESM(require("serialize-javascript"), 1);
360
- var literalSchema = import_zod2.default.union([
361
- // json
362
- import_zod2.default.string(),
363
- import_zod2.default.number(),
364
- import_zod2.default.boolean(),
365
- import_zod2.default.null(),
366
- // serializable-javascript
367
- import_zod2.default.undefined(),
368
- import_zod2.default.date(),
369
- import_zod2.default.map(import_zod2.default.unknown(), import_zod2.default.unknown()),
370
- import_zod2.default.set(import_zod2.default.unknown()),
371
- import_zod2.default.bigint()
372
- ]);
373
- var schema = import_zod2.default.lazy(
374
- () => import_zod2.default.union([literalSchema, import_zod2.default.array(schema), import_zod2.default.record(schema)])
375
- );
376
- var extension = "js";
377
- var serializableSchema = import_zod2.default.record(schema);
378
- function serialize(value) {
379
- const serializedValue = (0, import_serialize_javascript.default)(value, {
380
- space: 2,
381
- unsafe: true,
382
- ignoreFunction: true
383
- });
384
- return `export default ${serializedValue};`;
385
- }
386
-
387
- // src/writer.ts
388
- function createArrayConstName(name) {
389
- let suffix = name.charAt(0).toUpperCase() + name.slice(1);
390
- return "all" + (0, import_pluralize2.default)(suffix);
391
- }
392
- async function createDataFile(directory, collection) {
393
- const dataPath = import_node_path2.default.join(
394
- directory,
395
- `${createArrayConstName(collection.name)}.${extension}`
396
- );
397
- await import_promises3.default.writeFile(
398
- dataPath,
399
- serialize(collection.documents.map((doc) => doc.document))
400
- );
401
- }
402
- function createDataFiles(directory, collections) {
403
- return Promise.all(
404
- collections.map((collection) => createDataFile(directory, collection))
405
- );
406
- }
407
- async function createJavaScriptFile(directory, configuration) {
408
- const collections = configuration.collections.map(
409
- ({ name }) => createArrayConstName(name)
410
- );
411
- let content = `// generated by content-collections at ${/* @__PURE__ */ new Date()}
412
-
413
- `;
414
- for (const name of collections) {
415
- content += `import ${name} from "./${name}.${extension}";
416
- `;
417
- }
418
- content += "\n";
419
- content += "export { " + collections.join(", ") + " };\n";
420
- await import_promises3.default.writeFile(import_node_path2.default.join(directory, "index.js"), content, "utf-8");
421
- }
422
- function createImportPath(directory, target) {
423
- let importPath = import_node_path2.default.posix.join(
424
- ...import_node_path2.default.relative(directory, target).split(import_node_path2.default.sep)
425
- );
426
- if (!importPath.startsWith(".")) {
427
- importPath = "./" + importPath;
428
- }
429
- return importPath;
430
- }
431
- async function createTypeDefinitionFile(directory, configuration) {
432
- if (!configuration.generateTypes) {
433
- return;
434
- }
435
- const importPath = createImportPath(directory, configuration.path);
436
- let content = `import configuration from "${importPath}";
437
- import { GetTypeByName } from "@content-collections/core";
438
- `;
439
- const collections = configuration.collections;
440
- for (const collection of collections) {
441
- content += `
442
- `;
443
- content += `export type ${collection.typeName} = GetTypeByName<typeof configuration, "${collection.name}">;
444
- `;
445
- content += `export declare const ${createArrayConstName(
446
- collection.name
447
- )}: Array<${collection.typeName}>;
448
- `;
449
- }
450
- content += "\n";
451
- content += "export {};\n";
452
- await import_promises3.default.writeFile(import_node_path2.default.join(directory, "index.d.ts"), content, "utf-8");
453
- }
454
- async function createWriter(directory) {
455
- await import_promises3.default.mkdir(directory, { recursive: true });
456
- return {
457
- createJavaScriptFile: (configuration) => createJavaScriptFile(directory, configuration),
458
- createTypeDefinitionFile: (configuration) => createTypeDefinitionFile(directory, configuration),
459
- createDataFiles: (collections) => createDataFiles(directory, collections)
460
- };
461
- }
462
-
463
- // src/transformer.ts
464
- var import_node_path3 = require("path");
465
- var import_zod3 = require("zod");
466
- var TransformError = class extends Error {
467
- type;
468
- constructor(type, message) {
469
- super(message);
470
- this.type = type;
471
- }
472
- };
473
- function createPath(path7, ext) {
474
- let p = path7.slice(0, -ext.length);
475
- if (p.endsWith("/index")) {
476
- p = p.slice(0, -6);
477
- }
478
- return p;
479
- }
480
- function createTransformer(emitter, cacheManager) {
481
- function createSchema(parserName, schema2) {
482
- const parser = parsers[parserName];
483
- if (!parser.hasContent) {
484
- return import_zod3.z.object(schema2);
485
- }
486
- return import_zod3.z.object({
487
- content: import_zod3.z.string(),
488
- ...schema2
489
- });
490
- }
491
- async function parseFile(collection, file) {
492
- const { data, path: path7 } = file;
493
- const schema2 = createSchema(collection.parser, collection.schema);
494
- let parsedData = await schema2.safeParseAsync(data);
495
- if (!parsedData.success) {
496
- emitter.emit("transformer:validation-error", {
497
- collection,
498
- file,
499
- error: new TransformError("Validation", parsedData.error.message)
500
- });
501
- return null;
502
- }
503
- const ext = (0, import_node_path3.extname)(path7);
504
- let extension2 = ext;
505
- if (extension2.startsWith(".")) {
506
- extension2 = extension2.slice(1);
507
- }
508
- const document = {
509
- ...parsedData.data,
510
- _meta: {
511
- filePath: path7,
512
- fileName: (0, import_node_path3.basename)(path7),
513
- directory: (0, import_node_path3.dirname)(path7),
514
- extension: extension2,
515
- path: createPath(path7, ext)
516
- }
517
- };
518
- return {
519
- document
520
- };
521
- }
522
- async function parseCollection(collection) {
523
- const promises = collection.files.map(
524
- (file) => parseFile(collection, file)
525
- );
526
- return {
527
- ...collection,
528
- documents: (await Promise.all(promises)).filter(isDefined)
529
- };
530
- }
531
- function createContext(collections, collection, cache) {
532
- return {
533
- documents: (collection2) => {
534
- const resolved = collections.find((c) => c.name === collection2.name);
535
- if (!resolved) {
536
- throw new TransformError(
537
- "Configuration",
538
- `Collection ${collection2.name} not found, do you have registered it in your configuration?`
539
- );
540
- }
541
- return resolved.documents.map((doc) => doc.document);
542
- },
543
- collection: {
544
- name: collection.name,
545
- directory: collection.directory
546
- },
547
- cache: cache.cacheFn
548
- };
549
- }
550
- async function transformCollection(collections, collection) {
551
- if (collection.transform) {
552
- const docs = [];
553
- for (const doc of collection.documents) {
554
- const cache = cacheManager.cache(
555
- collection.name,
556
- doc.document._meta.path
557
- );
558
- const context = createContext(collections, collection, cache);
559
- try {
560
- const document = await collection.transform(doc.document, context);
561
- docs.push({
562
- ...doc,
563
- document
564
- });
565
- await cache.tidyUp();
566
- } catch (error) {
567
- if (error instanceof TransformError) {
568
- emitter.emit("transformer:error", {
569
- collection,
570
- error
571
- });
572
- } else {
573
- emitter.emit("transformer:error", {
574
- collection,
575
- error: new TransformError("Transform", String(error))
576
- });
577
- }
578
- }
579
- }
580
- await cacheManager.flush();
581
- return docs;
582
- }
583
- return collection.documents;
584
- }
585
- async function validateDocuments(collection, documents) {
586
- const docs = [];
587
- for (const doc of documents) {
588
- let parsedData = await serializableSchema.safeParseAsync(doc.document);
589
- if (parsedData.success) {
590
- docs.push(doc);
591
- } else {
592
- emitter.emit("transformer:result-error", {
593
- collection,
594
- document: doc.document,
595
- error: new TransformError("Result", parsedData.error.message)
596
- });
597
- }
598
- }
599
- return docs;
600
- }
601
- return async (untransformedCollections) => {
602
- const promises = untransformedCollections.map(
603
- (collection) => parseCollection(collection)
604
- );
605
- const collections = await Promise.all(promises);
606
- for (const collection of collections) {
607
- const documents = await transformCollection(collections, collection);
608
- collection.documents = await validateDocuments(collection, documents);
609
- }
610
- return collections;
611
- };
612
- }
613
-
614
- // src/synchronizer.ts
615
- var import_micromatch = __toESM(require("micromatch"), 1);
616
- var import_node_path4 = __toESM(require("path"), 1);
617
- function createSynchronizer(readCollectionFile, collections, baseDirectory = ".") {
618
- function findCollections(filePath) {
619
- const resolvedFilePath = import_node_path4.default.resolve(filePath);
620
- return collections.filter((collection) => {
621
- return resolvedFilePath.startsWith(
622
- import_node_path4.default.resolve(baseDirectory, collection.directory)
623
- );
624
- });
625
- }
626
- function createRelativePath(collectionPath, filePath) {
627
- const resolvedCollectionPath = import_node_path4.default.resolve(baseDirectory, collectionPath);
628
- const resolvedFilePath = import_node_path4.default.resolve(filePath);
629
- let relativePath = resolvedFilePath.slice(resolvedCollectionPath.length);
630
- if (relativePath.startsWith("/")) {
631
- relativePath = relativePath.slice(1);
632
- }
633
- return relativePath;
634
- }
635
- function resolve(filePath) {
636
- const collections2 = findCollections(filePath);
637
- return collections2.map((collection) => {
638
- const relativePath = createRelativePath(collection.directory, filePath);
639
- return {
640
- collection,
641
- relativePath
642
- };
643
- }).filter(({ collection, relativePath }) => {
644
- return import_micromatch.default.isMatch(relativePath, collection.include, {
645
- ignore: collection.exclude
646
- });
647
- });
648
- }
649
- function deleted(filePath) {
650
- const resolvedCollections = resolve(filePath);
651
- if (resolvedCollections.length === 0) {
652
- return false;
653
- }
654
- let changed2 = false;
655
- for (const { collection, relativePath } of resolvedCollections) {
656
- const index = collection.files.findIndex(
657
- (file) => file.path === relativePath
658
- );
659
- const deleted2 = collection.files.splice(index, 1);
660
- if (deleted2.length > 0) {
661
- changed2 = true;
662
- }
663
- }
664
- return changed2;
665
- }
666
- async function changed(filePath) {
667
- const resolvedCollections = resolve(filePath);
668
- if (resolvedCollections.length === 0) {
669
- return false;
670
- }
671
- let changed2 = false;
672
- for (const { collection, relativePath } of resolvedCollections) {
673
- const index = collection.files.findIndex(
674
- (file2) => file2.path === relativePath
675
- );
676
- const file = await readCollectionFile(collection, relativePath);
677
- if (file) {
678
- changed2 = true;
679
- if (index === -1) {
680
- collection.files.push(file);
681
- collection.files.sort(orderByPath);
682
- } else {
683
- collection.files[index] = file;
684
- }
685
- }
686
- }
687
- return changed2;
688
- }
689
- return {
690
- deleted,
691
- changed
692
- };
693
- }
694
-
695
- // src/builder.ts
696
- var import_node_path6 = __toESM(require("path"), 1);
697
-
698
- // src/watcher.ts
699
- var watcher = __toESM(require("@parcel/watcher"), 1);
700
- async function createWatcher(emitter, paths, sync, build2) {
701
- const onChange = async (error, events) => {
702
- if (error) {
703
- console.error(error);
704
- return;
705
- }
706
- let rebuild = false;
707
- for (const event of events) {
708
- if (await sync(event.type, event.path)) {
709
- emitter.emit("watcher:file-changed", {
710
- filePath: event.path,
711
- modification: event.type
712
- });
713
- rebuild = true;
714
- }
715
- }
716
- if (rebuild) {
717
- await build2();
718
- }
719
- };
720
- const subscriptions = await Promise.all(
721
- paths.map((path7) => watcher.subscribe(path7, onChange))
722
- );
723
- return {
724
- unsubscribe: async () => {
725
- await Promise.all(
726
- subscriptions.map((subscription) => subscription.unsubscribe())
727
- );
728
- return;
729
- }
730
- };
731
- }
732
-
733
- // src/events.ts
734
- var import_node_events = require("events");
735
- function isEventWithError(event) {
736
- return typeof event === "object" && event !== null && "error" in event;
737
- }
738
- function createEmitter() {
739
- const emitter = new import_node_events.EventEmitter();
740
- function on(key, listener) {
741
- emitter.on(key, listener);
742
- }
743
- function emit(key, event) {
744
- emitter.emit(key, event);
745
- if (isEventWithError(event)) {
746
- emitter.emit("_error", {
747
- ...event,
748
- _event: key
749
- });
750
- }
751
- emitter.emit("_all", {
752
- ...event,
753
- _event: key
754
- });
755
- }
756
- return {
757
- on,
758
- emit
759
- };
760
- }
761
-
762
- // src/cache.ts
763
- var import_node_path5 = __toESM(require("path"), 1);
764
- var import_promises4 = require("fs/promises");
765
- var import_node_fs2 = require("fs");
766
- var import_node_crypto2 = require("crypto");
767
- function createKey(config, input) {
768
- return (0, import_node_crypto2.createHash)("sha256").update(config).update(JSON.stringify(input)).digest("hex");
769
- }
770
- async function createCacheDirectory(directory) {
771
- const cacheDirectory = import_node_path5.default.join(directory, ".content-collections", "cache");
772
- if (!(0, import_node_fs2.existsSync)(cacheDirectory)) {
773
- await (0, import_promises4.mkdir)(cacheDirectory, { recursive: true });
774
- }
775
- return cacheDirectory;
776
- }
777
- function fileName(input) {
778
- return input.replace(/[^a-z0-9]/gi, "_").toLowerCase();
779
- }
780
- async function createCacheManager(baseDirectory, configChecksum) {
781
- const cacheDirectory = await createCacheDirectory(baseDirectory);
782
- let mapping = {};
783
- const mappingPath = (0, import_node_path5.join)(cacheDirectory, "mapping.json");
784
- if ((0, import_node_fs2.existsSync)(mappingPath)) {
785
- mapping = JSON.parse(await (0, import_promises4.readFile)(mappingPath, "utf-8"));
786
- }
787
- async function flush() {
788
- await (0, import_promises4.writeFile)(mappingPath, JSON.stringify(mapping));
789
- }
790
- function cache(collection, file) {
791
- const directory = (0, import_node_path5.join)(
792
- cacheDirectory,
793
- fileName(collection),
794
- fileName(file)
795
- );
796
- let collectionMapping = mapping[collection];
797
- if (!collectionMapping) {
798
- collectionMapping = {};
799
- mapping[collection] = collectionMapping;
800
- }
801
- let fileMapping = collectionMapping[file];
802
- if (!fileMapping) {
803
- fileMapping = [];
804
- collectionMapping[file] = fileMapping;
805
- }
806
- let newFileMapping = [];
807
- const cacheFn = async (input, fn) => {
808
- const key = createKey(configChecksum, input);
809
- newFileMapping.push(key);
810
- const filePath = (0, import_node_path5.join)(directory, `${key}.cache`);
811
- if (fileMapping?.includes(key) || newFileMapping.includes(key)) {
812
- if ((0, import_node_fs2.existsSync)(filePath)) {
813
- return JSON.parse(await (0, import_promises4.readFile)(filePath, "utf-8"));
814
- }
815
- }
816
- const output = await fn(input);
817
- if (!(0, import_node_fs2.existsSync)(directory)) {
818
- await (0, import_promises4.mkdir)(directory, { recursive: true });
819
- }
820
- await (0, import_promises4.writeFile)(filePath, JSON.stringify(output));
821
- return output;
822
- };
823
- const tidyUp = async () => {
824
- const filesToDelete = fileMapping?.filter((key) => !newFileMapping.includes(key)) || [];
825
- for (const key of filesToDelete) {
826
- const filePath = (0, import_node_path5.join)(directory, `${key}.cache`);
827
- if ((0, import_node_fs2.existsSync)(filePath)) {
828
- await (0, import_promises4.unlink)(filePath);
829
- }
830
- }
831
- if (collectionMapping) {
832
- collectionMapping[file] = newFileMapping;
833
- }
834
- };
835
- return {
836
- cacheFn,
837
- tidyUp
838
- };
839
- }
840
- return {
841
- cache,
842
- flush
843
- };
844
- }
845
-
846
- // src/builder.ts
847
- function resolveOutputDir(baseDirectory, options) {
848
- if (options.outputDir) {
849
- return options.outputDir;
850
- }
851
- return import_node_path6.default.join(baseDirectory, ".content-collections", "generated");
852
- }
853
- async function createBuilder(configurationPath, options = {
854
- configName: defaultConfigName
855
- }) {
856
- const emitter = createEmitter();
857
- const readConfiguration = createConfigurationReader();
858
- const configuration = await readConfiguration(configurationPath, options);
859
- const baseDirectory = import_node_path6.default.dirname(configurationPath);
860
- const directory = resolveOutputDir(baseDirectory, options);
861
- const collector = createCollector(emitter, baseDirectory);
862
- const writer = await createWriter(directory);
863
- const [resolved] = await Promise.all([
864
- collector.collect(configuration.collections),
865
- writer.createJavaScriptFile(configuration),
866
- writer.createTypeDefinitionFile(configuration)
867
- ]);
868
- const synchronizer = createSynchronizer(
869
- collector.collectFile,
870
- resolved,
871
- baseDirectory
872
- );
873
- const cacheManager = await createCacheManager(baseDirectory, configuration.checksum);
874
- const transform = createTransformer(emitter, cacheManager);
875
- async function sync(modification, filePath) {
876
- if (modification === "delete") {
877
- return synchronizer.deleted(filePath);
878
- }
879
- return synchronizer.changed(filePath);
880
- }
881
- async function build2() {
882
- const startedAt = Date.now();
883
- emitter.emit("builder:start", {
884
- startedAt
885
- });
886
- const collections = await transform(resolved);
887
- await writer.createDataFiles(collections);
888
- const pendingOnSuccess = collections.filter((collection) => Boolean(collection.onSuccess)).map(
889
- (collection) => collection.onSuccess?.(collection.documents.map((doc) => doc.document))
890
- );
891
- await Promise.all(pendingOnSuccess.filter(isDefined));
892
- emitter.emit("builder:end", {
893
- startedAt,
894
- endedAt: Date.now()
895
- });
896
- }
897
- async function watch() {
898
- const paths = resolved.map(
899
- (collection) => import_node_path6.default.join(baseDirectory, collection.directory)
900
- );
901
- const watcher2 = await createWatcher(emitter, paths, sync, build2);
902
- return watcher2;
903
- }
904
- return {
905
- sync,
906
- build: build2,
907
- watch,
908
- on: emitter.on
909
- };
910
- }
911
- // Annotate the CommonJS export names for ESM import in node:
912
- 0 && (module.exports = {
913
- CollectError,
914
- ConfigurationError,
915
- TransformError,
916
- createBuilder,
917
- defineCollection,
918
- defineConfig
919
- });
package/dist/index.d.cts DELETED
@@ -1,206 +0,0 @@
1
- import z, { ZodRawShape, z as z$1, 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>;
25
-
26
- declare const literalSchema: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull, z.ZodUndefined, z.ZodDate, z.ZodMap<z.ZodUnknown, z.ZodUnknown>, z.ZodSet<z.ZodUnknown>, z.ZodBigInt]>;
27
- type Literal = z.infer<typeof literalSchema>;
28
- type SchemaType = Literal | {
29
- [key: string]: SchemaType;
30
- } | SchemaType[];
31
- type NotSerializableError = `The return type of the transform function must be an object serializable object.
32
- See https://www.content-collections.dev/docs/serialization for more information.
33
-
34
- The following type is not valid:`;
35
- declare const serializableSchema: z.ZodRecord<z.ZodString, z.ZodType<SchemaType, z.ZodTypeDef, SchemaType>>;
36
- type Serializable = z.infer<typeof serializableSchema>;
37
-
38
- type Meta = {
39
- filePath: string;
40
- fileName: string;
41
- directory: string;
42
- path: string;
43
- extension: string;
44
- };
45
- type WithContent = {
46
- content: ZodString;
47
- };
48
- type AddContent<TShape extends ZodRawShape> = TShape extends {
49
- content: ZodTypeAny;
50
- } ? TShape : TShape & WithContent;
51
- type GetParsedShape<TParser extends Parser, TShape extends ZodRawShape> = Parsers[TParser]["hasContent"] extends true ? AddContent<TShape> : TShape;
52
- type GetShape<TParser extends Parser | undefined, TShape extends ZodRawShape> = TParser extends Parser ? GetParsedShape<TParser, TShape> : AddContent<TShape>;
53
- type Schema<TParser extends Parser | undefined, TShape extends ZodRawShape> = z$1.infer<ZodObject<GetShape<TParser, TShape>>> & {
54
- _meta: Meta;
55
- };
56
- type Context = {
57
- documents<TCollection extends AnyCollection>(collection: TCollection): Array<Schema<TCollection["parser"], TCollection["schema"]>>;
58
- cache: CacheFn;
59
- collection: {
60
- name: string;
61
- directory: string;
62
- };
63
- };
64
- type Z = typeof z$1;
65
- type CollectionRequest<TName extends string, TShape extends ZodRawShape, TParser, TSchema, TTransformResult, TDocument> = {
66
- name: TName;
67
- parser?: TParser;
68
- typeName?: string;
69
- schema: (z: Z) => TShape;
70
- transform?: (data: TSchema, context: Context) => TTransformResult;
71
- directory: string;
72
- include: string | string[];
73
- exclude?: string | string[];
74
- onSuccess?: (documents: Array<TDocument>) => void | Promise<void>;
75
- };
76
- type Collection<TName extends string, TShape extends ZodRawShape, TParser extends Parser, TSchema, TTransformResult, TDocument> = Omit<CollectionRequest<TName, TShape, TParser, TSchema, TTransformResult, TDocument>, "schema"> & {
77
- typeName: string;
78
- schema: TShape;
79
- parser: TParser;
80
- };
81
- type AnyCollection = Collection<any, ZodRawShape, Parser, any, any, any>;
82
- declare const InvalidReturnTypeSymbol: unique symbol;
83
- type InvalidReturnType<TMessage extends string, TObject> = {
84
- [InvalidReturnTypeSymbol]: TMessage;
85
- object: TObject;
86
- };
87
- 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>, TResult = TDocument extends Serializable ? Collection<TName, TShape, TParser, TSchema, TTransformResult, TDocument> : InvalidReturnType<NotSerializableError, TDocument>>(collection: CollectionRequest<TName, TShape, TParser, TSchema, TTransformResult, TDocument>): TResult;
88
- type Cache = "memory" | "file" | "none";
89
- type Configuration<TCollections extends Array<AnyCollection>> = {
90
- collections: TCollections;
91
- cache?: Cache;
92
- };
93
- type AnyConfiguration = Configuration<Array<AnyCollection>>;
94
- declare function defineConfig<TConfig extends AnyConfiguration>(config: TConfig): TConfig;
95
-
96
- type Modification = "create" | "update" | "delete";
97
- type Document = {
98
- _meta: Meta;
99
- };
100
- type CollectionFile = {
101
- data: {
102
- content?: string;
103
- [key: string]: unknown;
104
- };
105
- path: string;
106
- };
107
- type CollectionByName<TConfiguration extends AnyConfiguration> = {
108
- [TCollection in TConfiguration["collections"][number] as TCollection["name"]]: TCollection;
109
- };
110
- type GetDocument<TCollection extends AnyCollection> = TCollection extends Collection<any, ZodRawShape, any, any, any, infer TDocument> ? TDocument : never;
111
- type GetTypeByName<TConfiguration extends AnyConfiguration, TName extends keyof CollectionByName<TConfiguration>, TCollection = CollectionByName<TConfiguration>[TName]> = TCollection extends AnyCollection ? GetDocument<TCollection> : never;
112
-
113
- type CollectorEvents = {
114
- "collector:read-error": {
115
- filePath: string;
116
- error: CollectError;
117
- };
118
- "collector:parse-error": {
119
- filePath: string;
120
- error: CollectError;
121
- };
122
- };
123
- type ErrorType$2 = "Parse" | "Read";
124
- declare class CollectError extends Error {
125
- type: ErrorType$2;
126
- constructor(type: ErrorType$2, message: string);
127
- }
128
-
129
- type TransformerEvents = {
130
- "transformer:validation-error": {
131
- collection: AnyCollection;
132
- file: CollectionFile;
133
- error: TransformError;
134
- };
135
- "transformer:result-error": {
136
- collection: AnyCollection;
137
- document: any;
138
- error: TransformError;
139
- };
140
- "transformer:error": {
141
- collection: AnyCollection;
142
- error: TransformError;
143
- };
144
- };
145
- type ErrorType$1 = "Validation" | "Configuration" | "Transform" | "Result";
146
- declare class TransformError extends Error {
147
- type: ErrorType$1;
148
- constructor(type: ErrorType$1, message: string);
149
- }
150
-
151
- type WatcherEvents = {
152
- "watcher:file-changed": {
153
- filePath: string;
154
- modification: Modification;
155
- };
156
- };
157
-
158
- type EventWithError = {
159
- error: Error;
160
- };
161
- type SystemEvent = {
162
- _event: string;
163
- };
164
- type ErrorEvent = EventWithError & SystemEvent;
165
- type Events = BuilderEvents & CollectorEvents & TransformerEvents & WatcherEvents;
166
- type SystemEvents = {
167
- _error: ErrorEvent;
168
- _all: SystemEvent;
169
- };
170
-
171
- type ErrorType = "Read" | "Compile";
172
- declare class ConfigurationError extends Error {
173
- type: ErrorType;
174
- constructor(type: ErrorType, message: string);
175
- }
176
- type Options$1 = {
177
- configName: string;
178
- cacheDir?: string;
179
- };
180
-
181
- type BuilderEvents = {
182
- "builder:start": {
183
- startedAt: number;
184
- };
185
- "builder:end": {
186
- startedAt: number;
187
- endedAt: number;
188
- };
189
- };
190
- type Options = Options$1 & {
191
- outputDir?: string;
192
- };
193
- declare function createBuilder(configurationPath: string, options?: Options): Promise<{
194
- sync: (modification: Modification, filePath: string) => Promise<boolean>;
195
- build: () => Promise<void>;
196
- watch: () => Promise<{
197
- unsubscribe: () => Promise<void>;
198
- }>;
199
- on: {
200
- <TKey extends "builder:start" | "builder:end" | "collector:read-error" | "collector:parse-error" | "transformer:validation-error" | "transformer:result-error" | "transformer:error" | "watcher:file-changed">(key: TKey, listener: (event: Events[TKey]) => void): void;
201
- <TKey_1 extends "_error" | "_all">(key: TKey_1, listener: (event: SystemEvents[TKey_1]) => void): void;
202
- };
203
- }>;
204
- type Builder = Awaited<ReturnType<typeof createBuilder>>;
205
-
206
- export { type AnyCollection, type AnyConfiguration, type Builder, type BuilderEvents, CollectError, type Collection, type CollectionRequest, type Configuration, ConfigurationError, type Context, type Document, type GetTypeByName, type Meta, type Modification, type Schema, TransformError, createBuilder, defineCollection, defineConfig };