Skip to content

Commit

Permalink
feat(core): #290 add a function to access sibling documents
Browse files Browse the repository at this point in the history
Extend the context collection with a documents function,
which returns all documents of the current collection.

Closes: #268
  • Loading branch information
sdorra authored Sep 4, 2024
1 parent 426a6ac commit 486584b
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-pandas-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@content-collections/core": minor
---

Add a function to access sibling documents during transformation
25 changes: 25 additions & 0 deletions docs/transform.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,27 @@ In this example, the `markdownToHtml` function is only called if the content has

**Note**: Caching the compilation steps of `@content-collections/markdown` or `@content-collections/mdx` is unnecessary as they already utilize the same caching mechanism.

## Access sibling documents

Since version 0.7.0, it is possible to access other documents of the same collection by using the `documents` function of the `collection` object, which is part of the `context` object. The function is asynchronous, requires no parameters, and returns an array of all documents of the collection. The documents are not transformed; they have the shape as defined in the schema of the collection.

Example:

```ts
const posts = defineCollection({
// ...
transform: async (doc, {collection}) => {
const docs = await collection.documents();
const idx = docs.findIndex(d => doc._meta.filePath === d._meta.filePath);
return {
...doc,
prev: idx > 0 ? docs[idx - 1] : null,
next: idx < docs.length - 1 ? docs[idx + 1] : null,
};
},
});
```

## Access other collections

The `transform` function can access other collections using the `documents` function of the `context` object. The function requires a collection reference as parameter and returns an array of documents for that collection. But keep in mind the returned document are not transformed, they have the shape as defined in the schema of the referenced collection.
Expand Down Expand Up @@ -66,6 +87,10 @@ const posts = defineCollection({
For a complete example have a look at the [Join collections](#join-collections) example.
<Callout type="warn">
It is not possible to access documents of the same collection with the `documents` function. Use the `collection.documents` function instead. Please refer to [Access sibling documents](#access-sibling-documents) for more information.
</Callout>
## Examples
Here are some common use cases of the `transform` function:
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/__tests__/config.005.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { defineCollection, defineConfig } from "@content-collections/core";

const posts = defineCollection({
name: "posts",
directory: "sources/posts",
include: "**/*.md(x)?",
schema: (z) => ({
title: z.string(),
}),
transform: async (doc, {collection}) => {
const docs = await collection.documents();
const idx = docs.findIndex(d => doc._meta.filePath === d._meta.filePath);
return {
...doc,
prev: idx > 0 ? docs[idx - 1] : null,
next: idx < docs.length - 1 ? docs[idx + 1] : null,
};
},
});

export default defineConfig({
collections: [posts],
});
5 changes: 3 additions & 2 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ export type Schema<
_meta: Meta;
};

export type Context = {
export type Context<TSchema = unknown> = {
documents<TCollection extends AnyCollection>(
collection: TCollection
): Array<Schema<TCollection["parser"], TCollection["schema"]>>;
cache: CacheFn;
collection: {
name: string;
directory: string;
documents: () => Promise<Array<TSchema>>;
};
};

Expand All @@ -71,7 +72,7 @@ export type CollectionRequest<
parser?: TParser;
typeName?: string;
schema: (z: Z) => TShape;
transform?: (data: TSchema, context: Context) => TTransformResult;
transform?: (data: TSchema, context: Context<TSchema>) => TTransformResult;
directory: string;
include: string | string[];
exclude?: string | string[];
Expand Down
32 changes: 32 additions & 0 deletions packages/core/src/transformer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,4 +659,36 @@ describe("transform", () => {

expect(collection?.documents[0].document.collectionDirectory).toBe("tests");
});

it("should access documents of the same collection", async () => {
const posts = defineCollection({
name: "posts",
schema: (z) => ({
name: z.string(),
}),
directory: "tests",
include: "*.md",
transform: async (doc, context) => {
const docs = await context.collection.documents();
return {
...doc,
docs
};
},
});

const [collection] = await createTransformer(
emitter,
noopCacheManager
)([
{
...posts,
files: [sampleOne, sampleTwo],
},
]);

expect(collection?.documents[0].document.docs).toHaveLength(2);
expect(collection?.documents[0].document.docs[0].name).toBe("One");
expect(collection?.documents[0].document.docs[1].name).toBe("Two");
});
});
9 changes: 6 additions & 3 deletions packages/core/src/transformer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CollectionFile, MakeRequired } from "./types";
import { CollectionFile } from "./types";
import { AnyCollection, Context } from "./config";
import { isDefined } from "./utils";
import { Emitter } from "./events";
Expand Down Expand Up @@ -129,7 +129,7 @@ export function createTransformer(
collections: Array<TransformedCollection>,
collection: TransformedCollection,
cache: Cache
): Context {
): Context<unknown> {
return {
documents: (collection) => {
const resolved = collections.find((c) => c.name === collection.name);
Expand All @@ -144,6 +144,9 @@ export function createTransformer(
collection: {
name: collection.name,
directory: collection.directory,
documents: async () => {
return collection.documents.map((doc) => doc.document);
},
},
cache: cache.cacheFn,
};
Expand All @@ -152,7 +155,7 @@ export function createTransformer(
async function transformDocument(
collections: Array<TransformedCollection>,
collection: TransformedCollection,
transform: (data: any, context: Context) => any,
transform: (data: any, context: Context<unknown>) => any,
doc: any
) {
const cache = cacheManager.cache(collection.name, doc.document._meta.path);
Expand Down
5 changes: 0 additions & 5 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,3 @@ export type GetTypeByName<
TName extends keyof CollectionByName<TConfiguration>,
TCollection = CollectionByName<TConfiguration>[TName],
> = TCollection extends AnyCollection ? GetDocument<TCollection> : never;


export type MakeRequired<T, K extends keyof T> = {
[P in K]-?: T[P];
} & Omit<T, K>;

0 comments on commit 486584b

Please sign in to comment.