0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00
astro/.changeset/lovely-pianos-breathe.md
Rohan Godha 21b5e806c5
feat: custom file formats in file content loader (#12047)
* add custom file format support

* add tests

* lint/format

* changeset

* nits

* finish tests

* add nested json test

* requested changes

* update changeset with @sarah11918 suggestions

* typos/formatting

* add map<id, data> yaml test

* fix tests and rebase
2024-09-29 19:41:15 +01:00

2.2 KiB

astro
minor

Adds a new optional parser property to the built-in file() loader for content collections to support additional file types such as toml and csv.

The file() loader now accepts a second argument that defines a parser function. This allows you to specify a custom parser (e.g. toml.parse or csv-parse) to create a collection from a file's contents. The file() loader will automatically detect and parse JSON and YAML files (based on their file extension) with no need for a parser.

This works with any type of custom file formats including csv and toml. The following example defines a content collection dogs using a .toml file.

[[dogs]]
id = "..."
age = "..."

[[dogs]]
id = "..."
age = "..."

After importing TOML's parser, you can load the dogs collection into your project by passing both a file path and parser to the file() loader.

import { defineCollection } from "astro:content"
import { file } from "astro/loaders"
import { parse as parseToml } from "toml"

const dogs = defineCollection({
  loader: file("src/data/dogs.toml", { parser: (text) => parseToml(text).dogs }),
  schema: /* ... */
})

// it also works with CSVs!
import { parse as parseCsv } from "csv-parse/sync";

const cats = defineCollection({
  loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })})
});

The parser argument also allows you to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:

{"dogs": [{}], "cats": [{}]}

You can seperate these collections by passing a custom parser to the file() loader like so:

const dogs = defineCollection({
  loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).dogs })
});
const cats = defineCollection({
  loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).cats })
});

And it continues to work with maps of id to data

bubbles:
  breed: "Goldfish"
  age: 2
finn:
  breed: "Betta"
  age: 1
const fish = defineCollection({ 
  loader: file("src/data/fish.yaml"), 
  schema: z.object({ breed: z.string(), age: z.number() }) 
});