JSON Plugin

Handle `.json` files as data documents to query with `content.get`, `content.list`, and SQL.

The json plugin lets your sources serve plain JSON files alongside Markdown. Each .json file becomes a ContentFile whose data is the parsed JSON object and whose nodes are empty.

Usage

content.ts
import { comarkContent } from 'comark-content'
import json from 'comark-content/plugins/json'

const content = comarkContent({
  source: fs('./content'),
  plugins: [json()],
})

Given content/teams/engineering.json:

engineering.json
{
  "name": "Engineering",
  "lead": "Ada Lovelace",
  "members": 42
}
query.ts
const team = await content.get('/teams/engineering')
//    ^? ContentFile
team.data  // { name: 'Engineering', lead: 'Ada Lovelace', members: 42 }

API

json(options?)

Returns a ContentPlugin that registers a parser for .json files. Each file becomes a kind: 'document' ContentFile whose data is the parsed JSON object and whose nodes are empty. Files that fail to parse, or that parse to an array (rather than an object), are handled according to onError — by default they are dropped with a warning.

Parameters:

Returns: ContentPlugin


Options

OptionTypeDefaultDescription
listingFieldsstring[]undefineddata fields kept in listings for .json entries.
onError'throw' | 'warn' | 'ignore'Content onErrorHow to react to a malformed or non-object .json file.

listingFields

By default a listing keeps a document's whole data object. Pass listingFields to limit which data keys are retained in content.list() results for .json entries, forwarded to content.addListingFields():

listing-fields.ts
import json from 'comark-content/plugins/json'

json({
  listingFields: ['name', 'members'],
})

Default: undefined

onError

How the parser reacts when a .json file can't be parsed or isn't an object: 'warn' logs and drops it, 'ignore' drops it silently, 'throw' aborts. Defaults to the Content-level onError (which defaults to 'warn').

json({ onError: 'throw' }) // fail fast on malformed JSON

Default: the Content instance onError option


Read data

Each .json file resolves to a regular kind: 'document' ContentFile whose data is the parsed object, so the core content methods (content.get(), content.list(), content.stat(), and content.navigation()) treat them like any other document, and content.query() indexes their flattened data.

await content.list(['default'])
//    → includes engineering.json alongside .md files

await content.query('default').where('data.members', '>', 10).all()
//    → SQL queries against JSON data work too
content.search() is the only method that skips JSON files. It only indexes parsed nodes, which data files don't have.
Markdown files give you content + structure. JSON files give you data. The Content instance treats both as ContentFile so navigation, queries, and snapshots include them uniformly.

Trim listing payloads

When a source serves large JSON records, restrict listings to the fields you actually render:

content.ts
const content = comarkContent({
  source: fs('./content'),
  plugins: [json({ listingFields: ['name', 'members'] })],
})

await content.list(['default'])
//    → each JSON entry's data is trimmed to { name, members }