Skip to content
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
34 changes: 34 additions & 0 deletions .changeset/cozy-masks-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
'astro': minor
---

Adds support for returning a Promise from the `parser()` option of the `file()` loader

This enables you to run asynchronous code such as fetching remote data or using async parsers when loading files with the Content Layer API.

For example:

```js
import { defineCollection } from 'astro:content';
import { file } from 'astro/loaders';

const blog = defineCollection({
loader: file('src/data/blog.json', {
parser: async (text) => {
const data = JSON.parse(text);

// Perform async operations like fetching additional data
const enrichedData = await fetch(`https://api.example.com/enrich`, {
method: 'POST',
body: JSON.stringify(data),
}).then(res => res.json());

return enrichedData;
},
}),
});

export const collections = { blog };
```
Comment thread
Princesseuh marked this conversation as resolved.

See [the `parser()` reference documentation](https://docs.astro.build/en/reference/content-loader-reference/#parser) for more information.
8 changes: 4 additions & 4 deletions packages/astro/src/content/loaders/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { AstroError } from '../../core/errors/index.js';
import { posixRelative } from '../utils.js';
import type { Loader, LoaderContext } from './types.js';

type ParserOutput = Record<string, Record<string, unknown>> | Array<Record<string, unknown>>;

interface FileOptions {
/**
* the parsing function to use for this data
* @default JSON.parse or yaml.load, depending on the extension of the file
* */
parser?: (
text: string,
) => Record<string, Record<string, unknown>> | Array<Record<string, unknown>>;
parser?: (text: string) => Promise<ParserOutput> | ParserOutput;
}

/**
Expand Down Expand Up @@ -54,7 +54,7 @@ export function file(fileName: string, options?: FileOptions): Loader {

try {
const contents = await fs.readFile(filePath, 'utf-8');
data = parse!(contents);
data = await parse!(contents);
} catch (error: any) {
logger.error(`Error reading data from ${fileName}`);
logger.debug(error.message);
Expand Down
8 changes: 8 additions & 0 deletions packages/astro/test/content-layer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ describe('Content Layer', () => {
assert.deepEqual(ids, ['bluejay', 'robin', 'sparrow', 'cardinal', 'goldfinch']);
});

it('can use an async parser in `file()` loader', async () => {
assert.ok(json.hasOwnProperty('loaderWithAsyncParse'));
assert.ok(Array.isArray(json.loaderWithAsyncParse));

const ids = json.loaderWithAsyncParse.map((item) => item.data.id);
assert.deepEqual(ids, ['bluejay', 'robin', 'sparrow', 'cardinal', 'goldfinch']);
});

it('Returns yaml `file()` loader collection', async () => {
assert.ok(json.hasOwnProperty('yamlLoader'));
assert.ok(Array.isArray(json.yamlLoader));
Expand Down
16 changes: 16 additions & 0 deletions packages/astro/test/fixtures/content-layer/src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,21 @@ const birds = defineCollection({
}),
});

const birdsWithAsyncParse = defineCollection({
loader: file('src/data/birds.json', {
parser: async (text) => {
await new Promise((resolve) => setTimeout(resolve, 10));
return JSON.parse(text).birds;
},
}),
schema: z.object({
id: z.string(),
name: z.string(),
breed: z.string(),
age: z.number(),
}),
});

const plants = defineCollection({
loader: file('src/data/plants.csv', {
parser: (text) => {
Expand Down Expand Up @@ -270,6 +285,7 @@ export const collections = {
cats,
fish,
birds,
birdsWithAsyncParse,
plants,
numbers,
numbersToml,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export async function GET() {
const tomlLoader = await getCollection('songs');

const nestedJsonLoader = await getCollection('birds');


const loaderWithAsyncParse = await getCollection('birdsWithAsyncParse');

const csvLoader = await getCollection('plants');

const rockets = await getCollection('rockets');
Expand Down Expand Up @@ -63,6 +65,7 @@ export async function GET() {
yamlLoader,
tomlLoader,
nestedJsonLoader,
loaderWithAsyncParse,
csvLoader,
atlantis,
spacecraft: spacecraft.map(({id}) => id).sort((a, b) => a.localeCompare(b)),
Expand Down
Loading