@content-collections/core 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/index.d.ts +25 -6
- package/dist/index.js +89 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,6 +110,18 @@ Transform your content into type-safe data collections. Eliminate the need for m
|
|
|
110
110
|
|
|
111
111
|
For a more detailed guide, please refer to the [documentation](https://content-collections.dev/docs/guides/getting-started).
|
|
112
112
|
|
|
113
|
+
## Sponsors
|
|
114
|
+
|
|
115
|
+
<a href="https://supastarter.dev">
|
|
116
|
+
<picture>
|
|
117
|
+
<source media="(prefers-color-scheme: dark)" srcset="./assets/sponsors/supastarter/dark.svg">
|
|
118
|
+
<source media="(prefers-color-scheme: light)" srcset="./assets/sponsors/supastarter/light.svg">
|
|
119
|
+
<img alt="supastarter" src="./assets/sponsors/supastarter/light.svg" height="64">
|
|
120
|
+
</picture>
|
|
121
|
+
</a>
|
|
122
|
+
|
|
123
|
+
### [Become a sponsor](https://github.com/sponsors/sdorra)
|
|
124
|
+
|
|
113
125
|
## License
|
|
114
126
|
|
|
115
127
|
Content Collections is licensed under the [MIT License](./LICENSE).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ZodRawShape, z, ZodObject, ZodTypeAny, ZodString } from 'zod';
|
|
1
|
+
import z, { ZodRawShape, z as z$1, ZodObject, ZodTypeAny, ZodString } from 'zod';
|
|
2
2
|
import { parse } from 'yaml';
|
|
3
3
|
|
|
4
4
|
type Parsers = typeof parsers;
|
|
@@ -23,6 +23,14 @@ declare const parsers: {
|
|
|
23
23
|
|
|
24
24
|
type CacheFn = <TInput, TOutput>(input: TInput, compute: (input: TInput) => Promise<TOutput> | TOutput) => Promise<TOutput>;
|
|
25
25
|
|
|
26
|
+
declare const literalSchema: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull, z.ZodUndefined]>;
|
|
27
|
+
type Literal = z.infer<typeof literalSchema>;
|
|
28
|
+
type Json = Literal | {
|
|
29
|
+
[key: string]: Json;
|
|
30
|
+
} | Json[];
|
|
31
|
+
declare const jsonObjectScheme: z.ZodRecord<z.ZodString, z.ZodType<Json, z.ZodTypeDef, Json>>;
|
|
32
|
+
type JSONObject = z.infer<typeof jsonObjectScheme>;
|
|
33
|
+
|
|
26
34
|
type Meta = {
|
|
27
35
|
filePath: string;
|
|
28
36
|
fileName: string;
|
|
@@ -38,14 +46,14 @@ type AddContent<TShape extends ZodRawShape> = TShape extends {
|
|
|
38
46
|
} ? TShape : TShape & WithContent;
|
|
39
47
|
type GetParsedShape<TParser extends Parser, TShape extends ZodRawShape> = Parsers[TParser]["hasContent"] extends true ? AddContent<TShape> : TShape;
|
|
40
48
|
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>>> & {
|
|
49
|
+
type Schema<TParser extends Parser | undefined, TShape extends ZodRawShape> = z$1.infer<ZodObject<GetShape<TParser, TShape>>> & {
|
|
42
50
|
_meta: Meta;
|
|
43
51
|
};
|
|
44
52
|
type Context = {
|
|
45
53
|
documents<TCollection extends AnyCollection>(collection: TCollection): Array<Schema<TCollection["parser"], TCollection["schema"]>>;
|
|
46
54
|
cache: CacheFn;
|
|
47
55
|
};
|
|
48
|
-
type Z = typeof z;
|
|
56
|
+
type Z = typeof z$1;
|
|
49
57
|
type CollectionRequest<TName extends string, TShape extends ZodRawShape, TParser, TSchema, TTransformResult, TDocument> = {
|
|
50
58
|
name: TName;
|
|
51
59
|
parser?: TParser;
|
|
@@ -62,7 +70,13 @@ type Collection<TName extends string, TShape extends ZodRawShape, TParser extend
|
|
|
62
70
|
parser: TParser;
|
|
63
71
|
};
|
|
64
72
|
type AnyCollection = Collection<any, ZodRawShape, Parser, any, any, any>;
|
|
65
|
-
|
|
73
|
+
type NonJSONObjectError = "The return type of the transform function must be an valid JSONObject, the following type is not valid:";
|
|
74
|
+
declare const InvalidReturnTypeSymbol: unique symbol;
|
|
75
|
+
type InvalidReturnType<TMessage extends string, TObject> = {
|
|
76
|
+
[InvalidReturnTypeSymbol]: TMessage;
|
|
77
|
+
object: TObject;
|
|
78
|
+
};
|
|
79
|
+
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 JSONObject ? Collection<TName, TShape, TParser, TSchema, TTransformResult, TDocument> : InvalidReturnType<NonJSONObjectError, TDocument>>(collection: CollectionRequest<TName, TShape, TParser, TSchema, TTransformResult, TDocument>): TResult;
|
|
66
80
|
type Cache = "memory" | "file" | "none";
|
|
67
81
|
type Configuration<TCollections extends Array<AnyCollection>> = {
|
|
68
82
|
collections: TCollections;
|
|
@@ -107,12 +121,17 @@ type TransformerEvents = {
|
|
|
107
121
|
file: CollectionFile;
|
|
108
122
|
error: TransformError;
|
|
109
123
|
};
|
|
124
|
+
"transformer:result-error": {
|
|
125
|
+
collection: AnyCollection;
|
|
126
|
+
document: any;
|
|
127
|
+
error: TransformError;
|
|
128
|
+
};
|
|
110
129
|
"transformer:error": {
|
|
111
130
|
collection: AnyCollection;
|
|
112
131
|
error: TransformError;
|
|
113
132
|
};
|
|
114
133
|
};
|
|
115
|
-
type ErrorType$1 = "Validation" | "Configuration" | "Transform";
|
|
134
|
+
type ErrorType$1 = "Validation" | "Configuration" | "Transform" | "Result";
|
|
116
135
|
declare class TransformError extends Error {
|
|
117
136
|
type: ErrorType$1;
|
|
118
137
|
constructor(type: ErrorType$1, message: string);
|
|
@@ -167,7 +186,7 @@ declare function createBuilder(configurationPath: string, options?: Options): Pr
|
|
|
167
186
|
unsubscribe: () => Promise<void>;
|
|
168
187
|
}>;
|
|
169
188
|
on: {
|
|
170
|
-
<TKey extends "builder:start" | "builder:end" | "collector:read-error" | "collector:parse-error" | "transformer:validation-error" | "transformer:error" | "watcher:file-changed">(key: TKey, listener: (event: Events[TKey]) => void): void;
|
|
189
|
+
<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;
|
|
171
190
|
<TKey_1 extends "_error" | "_all">(key: TKey_1, listener: (event: SystemEvents[TKey_1]) => void): void;
|
|
172
191
|
};
|
|
173
192
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ function orderByPath(a, b) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// src/config.ts
|
|
19
|
+
var InvalidReturnTypeSymbol = Symbol(`InvalidReturnType`);
|
|
19
20
|
function defineCollection(collection) {
|
|
20
21
|
let typeName = collection.typeName;
|
|
21
22
|
if (!typeName) {
|
|
@@ -44,7 +45,7 @@ import path from "path";
|
|
|
44
45
|
// package.json
|
|
45
46
|
var package_default = {
|
|
46
47
|
name: "@content-collections/core",
|
|
47
|
-
version: "0.
|
|
48
|
+
version: "0.4.0",
|
|
48
49
|
type: "module",
|
|
49
50
|
main: "dist/index.js",
|
|
50
51
|
types: "./dist/index.d.ts",
|
|
@@ -348,7 +349,23 @@ async function createWriter(directory) {
|
|
|
348
349
|
|
|
349
350
|
// src/transformer.ts
|
|
350
351
|
import { basename, dirname, extname } from "path";
|
|
351
|
-
import { z as
|
|
352
|
+
import { z as z3 } from "zod";
|
|
353
|
+
|
|
354
|
+
// src/json.ts
|
|
355
|
+
import z2 from "zod";
|
|
356
|
+
var literalSchema = z2.union([
|
|
357
|
+
z2.string(),
|
|
358
|
+
z2.number(),
|
|
359
|
+
z2.boolean(),
|
|
360
|
+
z2.null(),
|
|
361
|
+
z2.undefined()
|
|
362
|
+
]);
|
|
363
|
+
var jsonSchema = z2.lazy(
|
|
364
|
+
() => z2.union([literalSchema, z2.array(jsonSchema), z2.record(jsonSchema)])
|
|
365
|
+
);
|
|
366
|
+
var jsonObjectScheme = z2.record(jsonSchema);
|
|
367
|
+
|
|
368
|
+
// src/transformer.ts
|
|
352
369
|
var TransformError = class extends Error {
|
|
353
370
|
type;
|
|
354
371
|
constructor(type, message) {
|
|
@@ -367,10 +384,10 @@ function createTransformer(emitter, cacheManager) {
|
|
|
367
384
|
function createSchema(parserName, schema) {
|
|
368
385
|
const parser = parsers[parserName];
|
|
369
386
|
if (!parser.hasContent) {
|
|
370
|
-
return
|
|
387
|
+
return z3.object(schema);
|
|
371
388
|
}
|
|
372
|
-
return
|
|
373
|
-
content:
|
|
389
|
+
return z3.object({
|
|
390
|
+
content: z3.string(),
|
|
374
391
|
...schema
|
|
375
392
|
});
|
|
376
393
|
}
|
|
@@ -433,12 +450,16 @@ function createTransformer(emitter, cacheManager) {
|
|
|
433
450
|
if (collection.transform) {
|
|
434
451
|
const docs = [];
|
|
435
452
|
for (const doc of collection.documents) {
|
|
436
|
-
const cache = cacheManager.cache(
|
|
453
|
+
const cache = cacheManager.cache(
|
|
454
|
+
collection.name,
|
|
455
|
+
doc.document._meta.path
|
|
456
|
+
);
|
|
437
457
|
const context = createContext(collections, cache);
|
|
438
458
|
try {
|
|
459
|
+
const document = await collection.transform(doc.document, context);
|
|
439
460
|
docs.push({
|
|
440
461
|
...doc,
|
|
441
|
-
document
|
|
462
|
+
document
|
|
442
463
|
});
|
|
443
464
|
await cache.tidyUp();
|
|
444
465
|
} catch (error) {
|
|
@@ -460,13 +481,30 @@ function createTransformer(emitter, cacheManager) {
|
|
|
460
481
|
}
|
|
461
482
|
return collection.documents;
|
|
462
483
|
}
|
|
484
|
+
async function validateDocuments(collection, documents) {
|
|
485
|
+
const docs = [];
|
|
486
|
+
for (const doc of documents) {
|
|
487
|
+
let parsedData = await jsonObjectScheme.safeParseAsync(doc.document);
|
|
488
|
+
if (parsedData.success) {
|
|
489
|
+
docs.push(doc);
|
|
490
|
+
} else {
|
|
491
|
+
emitter.emit("transformer:result-error", {
|
|
492
|
+
collection,
|
|
493
|
+
document: doc.document,
|
|
494
|
+
error: new TransformError("Result", parsedData.error.message)
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return docs;
|
|
499
|
+
}
|
|
463
500
|
return async (untransformedCollections) => {
|
|
464
501
|
const promises = untransformedCollections.map(
|
|
465
502
|
(collection) => parseCollection(collection)
|
|
466
503
|
);
|
|
467
504
|
const collections = await Promise.all(promises);
|
|
468
505
|
for (const collection of collections) {
|
|
469
|
-
|
|
506
|
+
const documents = await transformCollection(collections, collection);
|
|
507
|
+
collection.documents = await validateDocuments(collection, documents);
|
|
470
508
|
}
|
|
471
509
|
return collections;
|
|
472
510
|
};
|
|
@@ -476,9 +514,9 @@ function createTransformer(emitter, cacheManager) {
|
|
|
476
514
|
import micromatch from "micromatch";
|
|
477
515
|
import path4 from "path";
|
|
478
516
|
function createSynchronizer(readCollectionFile, collections, baseDirectory = ".") {
|
|
479
|
-
function
|
|
517
|
+
function findCollections(filePath) {
|
|
480
518
|
const resolvedFilePath = path4.resolve(filePath);
|
|
481
|
-
return collections.
|
|
519
|
+
return collections.filter((collection) => {
|
|
482
520
|
return resolvedFilePath.startsWith(
|
|
483
521
|
path4.resolve(baseDirectory, collection.directory)
|
|
484
522
|
);
|
|
@@ -494,51 +532,56 @@ function createSynchronizer(readCollectionFile, collections, baseDirectory = "."
|
|
|
494
532
|
return relativePath;
|
|
495
533
|
}
|
|
496
534
|
function resolve(filePath) {
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
relativePath
|
|
508
|
-
};
|
|
535
|
+
const collections2 = findCollections(filePath);
|
|
536
|
+
return collections2.map((collection) => {
|
|
537
|
+
const relativePath = createRelativePath(collection.directory, filePath);
|
|
538
|
+
return {
|
|
539
|
+
collection,
|
|
540
|
+
relativePath
|
|
541
|
+
};
|
|
542
|
+
}).filter(({ collection, relativePath }) => {
|
|
543
|
+
return micromatch.isMatch(relativePath, collection.include);
|
|
544
|
+
});
|
|
509
545
|
}
|
|
510
546
|
function deleted(filePath) {
|
|
511
|
-
const
|
|
512
|
-
if (
|
|
547
|
+
const resolvedCollections = resolve(filePath);
|
|
548
|
+
if (resolvedCollections.length === 0) {
|
|
513
549
|
return false;
|
|
514
550
|
}
|
|
515
|
-
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
551
|
+
let changed2 = false;
|
|
552
|
+
for (const { collection, relativePath } of resolvedCollections) {
|
|
553
|
+
const index = collection.files.findIndex(
|
|
554
|
+
(file) => file.path === relativePath
|
|
555
|
+
);
|
|
556
|
+
const deleted2 = collection.files.splice(index, 1);
|
|
557
|
+
if (deleted2.length > 0) {
|
|
558
|
+
changed2 = true;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return changed2;
|
|
521
562
|
}
|
|
522
563
|
async function changed(filePath) {
|
|
523
|
-
const
|
|
524
|
-
if (
|
|
564
|
+
const resolvedCollections = resolve(filePath);
|
|
565
|
+
if (resolvedCollections.length === 0) {
|
|
525
566
|
return false;
|
|
526
567
|
}
|
|
527
|
-
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
568
|
+
let changed2 = false;
|
|
569
|
+
for (const { collection, relativePath } of resolvedCollections) {
|
|
570
|
+
const index = collection.files.findIndex(
|
|
571
|
+
(file2) => file2.path === relativePath
|
|
572
|
+
);
|
|
573
|
+
const file = await readCollectionFile(collection, relativePath);
|
|
574
|
+
if (file) {
|
|
575
|
+
changed2 = true;
|
|
576
|
+
if (index === -1) {
|
|
577
|
+
collection.files.push(file);
|
|
578
|
+
collection.files.sort(orderByPath);
|
|
579
|
+
} else {
|
|
580
|
+
collection.files[index] = file;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
540
583
|
}
|
|
541
|
-
return
|
|
584
|
+
return changed2;
|
|
542
585
|
}
|
|
543
586
|
return {
|
|
544
587
|
deleted,
|