@content-collections/core 0.3.1 → 0.4.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/README.md +12 -0
- package/dist/index.d.ts +25 -6
- package/dist/index.js +97 -47
- 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.1",
|
|
48
49
|
type: "module",
|
|
49
50
|
main: "dist/index.js",
|
|
50
51
|
types: "./dist/index.d.ts",
|
|
@@ -314,11 +315,18 @@ async function createJavaScriptFile(directory, configuration) {
|
|
|
314
315
|
content += "export { " + collections.join(", ") + " };\n";
|
|
315
316
|
await fs2.writeFile(path3.join(directory, "index.js"), content, "utf-8");
|
|
316
317
|
}
|
|
318
|
+
function createImportPath(directory, target) {
|
|
319
|
+
let importPath = path3.posix.join(...path3.relative(directory, target).split(path3.sep));
|
|
320
|
+
if (!importPath.startsWith(".")) {
|
|
321
|
+
importPath = "./" + importPath;
|
|
322
|
+
}
|
|
323
|
+
return importPath;
|
|
324
|
+
}
|
|
317
325
|
async function createTypeDefinitionFile(directory, configuration) {
|
|
318
326
|
if (!configuration.generateTypes) {
|
|
319
327
|
return;
|
|
320
328
|
}
|
|
321
|
-
const importPath =
|
|
329
|
+
const importPath = createImportPath(directory, configuration.path);
|
|
322
330
|
let content = `import configuration from "${importPath}";
|
|
323
331
|
import { GetTypeByName } from "@content-collections/core";
|
|
324
332
|
`;
|
|
@@ -348,7 +356,23 @@ async function createWriter(directory) {
|
|
|
348
356
|
|
|
349
357
|
// src/transformer.ts
|
|
350
358
|
import { basename, dirname, extname } from "path";
|
|
351
|
-
import { z as
|
|
359
|
+
import { z as z3 } from "zod";
|
|
360
|
+
|
|
361
|
+
// src/json.ts
|
|
362
|
+
import z2 from "zod";
|
|
363
|
+
var literalSchema = z2.union([
|
|
364
|
+
z2.string(),
|
|
365
|
+
z2.number(),
|
|
366
|
+
z2.boolean(),
|
|
367
|
+
z2.null(),
|
|
368
|
+
z2.undefined()
|
|
369
|
+
]);
|
|
370
|
+
var jsonSchema = z2.lazy(
|
|
371
|
+
() => z2.union([literalSchema, z2.array(jsonSchema), z2.record(jsonSchema)])
|
|
372
|
+
);
|
|
373
|
+
var jsonObjectScheme = z2.record(jsonSchema);
|
|
374
|
+
|
|
375
|
+
// src/transformer.ts
|
|
352
376
|
var TransformError = class extends Error {
|
|
353
377
|
type;
|
|
354
378
|
constructor(type, message) {
|
|
@@ -367,10 +391,10 @@ function createTransformer(emitter, cacheManager) {
|
|
|
367
391
|
function createSchema(parserName, schema) {
|
|
368
392
|
const parser = parsers[parserName];
|
|
369
393
|
if (!parser.hasContent) {
|
|
370
|
-
return
|
|
394
|
+
return z3.object(schema);
|
|
371
395
|
}
|
|
372
|
-
return
|
|
373
|
-
content:
|
|
396
|
+
return z3.object({
|
|
397
|
+
content: z3.string(),
|
|
374
398
|
...schema
|
|
375
399
|
});
|
|
376
400
|
}
|
|
@@ -433,12 +457,16 @@ function createTransformer(emitter, cacheManager) {
|
|
|
433
457
|
if (collection.transform) {
|
|
434
458
|
const docs = [];
|
|
435
459
|
for (const doc of collection.documents) {
|
|
436
|
-
const cache = cacheManager.cache(
|
|
460
|
+
const cache = cacheManager.cache(
|
|
461
|
+
collection.name,
|
|
462
|
+
doc.document._meta.path
|
|
463
|
+
);
|
|
437
464
|
const context = createContext(collections, cache);
|
|
438
465
|
try {
|
|
466
|
+
const document = await collection.transform(doc.document, context);
|
|
439
467
|
docs.push({
|
|
440
468
|
...doc,
|
|
441
|
-
document
|
|
469
|
+
document
|
|
442
470
|
});
|
|
443
471
|
await cache.tidyUp();
|
|
444
472
|
} catch (error) {
|
|
@@ -460,13 +488,30 @@ function createTransformer(emitter, cacheManager) {
|
|
|
460
488
|
}
|
|
461
489
|
return collection.documents;
|
|
462
490
|
}
|
|
491
|
+
async function validateDocuments(collection, documents) {
|
|
492
|
+
const docs = [];
|
|
493
|
+
for (const doc of documents) {
|
|
494
|
+
let parsedData = await jsonObjectScheme.safeParseAsync(doc.document);
|
|
495
|
+
if (parsedData.success) {
|
|
496
|
+
docs.push(doc);
|
|
497
|
+
} else {
|
|
498
|
+
emitter.emit("transformer:result-error", {
|
|
499
|
+
collection,
|
|
500
|
+
document: doc.document,
|
|
501
|
+
error: new TransformError("Result", parsedData.error.message)
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return docs;
|
|
506
|
+
}
|
|
463
507
|
return async (untransformedCollections) => {
|
|
464
508
|
const promises = untransformedCollections.map(
|
|
465
509
|
(collection) => parseCollection(collection)
|
|
466
510
|
);
|
|
467
511
|
const collections = await Promise.all(promises);
|
|
468
512
|
for (const collection of collections) {
|
|
469
|
-
|
|
513
|
+
const documents = await transformCollection(collections, collection);
|
|
514
|
+
collection.documents = await validateDocuments(collection, documents);
|
|
470
515
|
}
|
|
471
516
|
return collections;
|
|
472
517
|
};
|
|
@@ -476,9 +521,9 @@ function createTransformer(emitter, cacheManager) {
|
|
|
476
521
|
import micromatch from "micromatch";
|
|
477
522
|
import path4 from "path";
|
|
478
523
|
function createSynchronizer(readCollectionFile, collections, baseDirectory = ".") {
|
|
479
|
-
function
|
|
524
|
+
function findCollections(filePath) {
|
|
480
525
|
const resolvedFilePath = path4.resolve(filePath);
|
|
481
|
-
return collections.
|
|
526
|
+
return collections.filter((collection) => {
|
|
482
527
|
return resolvedFilePath.startsWith(
|
|
483
528
|
path4.resolve(baseDirectory, collection.directory)
|
|
484
529
|
);
|
|
@@ -494,51 +539,56 @@ function createSynchronizer(readCollectionFile, collections, baseDirectory = "."
|
|
|
494
539
|
return relativePath;
|
|
495
540
|
}
|
|
496
541
|
function resolve(filePath) {
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
relativePath
|
|
508
|
-
};
|
|
542
|
+
const collections2 = findCollections(filePath);
|
|
543
|
+
return collections2.map((collection) => {
|
|
544
|
+
const relativePath = createRelativePath(collection.directory, filePath);
|
|
545
|
+
return {
|
|
546
|
+
collection,
|
|
547
|
+
relativePath
|
|
548
|
+
};
|
|
549
|
+
}).filter(({ collection, relativePath }) => {
|
|
550
|
+
return micromatch.isMatch(relativePath, collection.include);
|
|
551
|
+
});
|
|
509
552
|
}
|
|
510
553
|
function deleted(filePath) {
|
|
511
|
-
const
|
|
512
|
-
if (
|
|
554
|
+
const resolvedCollections = resolve(filePath);
|
|
555
|
+
if (resolvedCollections.length === 0) {
|
|
513
556
|
return false;
|
|
514
557
|
}
|
|
515
|
-
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
558
|
+
let changed2 = false;
|
|
559
|
+
for (const { collection, relativePath } of resolvedCollections) {
|
|
560
|
+
const index = collection.files.findIndex(
|
|
561
|
+
(file) => file.path === relativePath
|
|
562
|
+
);
|
|
563
|
+
const deleted2 = collection.files.splice(index, 1);
|
|
564
|
+
if (deleted2.length > 0) {
|
|
565
|
+
changed2 = true;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return changed2;
|
|
521
569
|
}
|
|
522
570
|
async function changed(filePath) {
|
|
523
|
-
const
|
|
524
|
-
if (
|
|
571
|
+
const resolvedCollections = resolve(filePath);
|
|
572
|
+
if (resolvedCollections.length === 0) {
|
|
525
573
|
return false;
|
|
526
574
|
}
|
|
527
|
-
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
575
|
+
let changed2 = false;
|
|
576
|
+
for (const { collection, relativePath } of resolvedCollections) {
|
|
577
|
+
const index = collection.files.findIndex(
|
|
578
|
+
(file2) => file2.path === relativePath
|
|
579
|
+
);
|
|
580
|
+
const file = await readCollectionFile(collection, relativePath);
|
|
581
|
+
if (file) {
|
|
582
|
+
changed2 = true;
|
|
583
|
+
if (index === -1) {
|
|
584
|
+
collection.files.push(file);
|
|
585
|
+
collection.files.sort(orderByPath);
|
|
586
|
+
} else {
|
|
587
|
+
collection.files[index] = file;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
540
590
|
}
|
|
541
|
-
return
|
|
591
|
+
return changed2;
|
|
542
592
|
}
|
|
543
593
|
return {
|
|
544
594
|
deleted,
|