Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): #268 add a function to access sibling documents #290

Merged
merged 2 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>;