Repository: contentlayerdev/contentlayer

Issue #123: Simplify document type resolution
Created: 2022-02-10T13:36:01Z
Context
In the contentlayer/source-files plugin there are currently two mechanisms to tell Contentlayer how map a given document (e.g. a .md file) to one of many document definitions (e.g. a BlogPost, Page, ...). The two mechanisms are:

Explicitly via the filePathPattern option provided for defineDocumentType
Implicitly by looking up a "type" field in a given document (configurable via fieldOptions.typeFieldName)

Problem
I'm seeing two problems with the current design:
A: Technical problems/limitations
When using mechanism (1) there can be situations where the provided filePathPattern can overlap between document definitions and there currently is no way to explicitly configure the "precedence" document matching behaviour of Contentlayer.
B: Hard to understand / learn
Additionally to the technical problems (A) having two different ways to do the same thing (especially when they overlap) makes things much harder to understand - especially for new Contentlayer users who e.g. might ask themselves "which approach should I use?" or "which approach is better?".
I think that providing less ways to do the same thing is the right approach in most cases as it reduces cognitive overload.
Additionally there's also the complexity resulting of the possibility of combining both mechanisms (1) + (2).
Solution
As an alternative to the current mechanisms (1) + (2) I'm proposing a single unified approach to let users specify how to map document files to document type definitions by simply implementing a resolveDocumentType function as a property in makeSource like the following:
As replacement for mechanism (1)
Assuming a content file structure like:
.
├── about.md
├── index.md
└── posts
    ├── post-1.md
    ├── post-2.md
    └── post-3.md

const Post = defineDocumentType(() => ({
  name: 'Post',
  fields: {
    // ...
  }
}))

const Page = defineDocumentType(() => ({
  name: 'Page',
  fields: {
    // ...
  }
}))

export default makeSource({
  contentDirPath: 'posts',
  documentTypes: [Post, Page],
  resolveDocumentType: (frontmatter, raw) => raw.sourceFilePath.startsWith('posts/') ? 'Post' : 'Page'
})
As replacement for mechanism (2)
Assuming each document as a frontmatter field called type
const Post = defineDocumentType(() => ({
  name: 'Post',
  fields: {
    // ...
  }
}))

const Page = defineDocumentType(() => ({
  name: 'Page',
  fields: {
    // ...
  }
}))

export default makeSource({
  contentDirPath: 'posts',
  documentTypes: [Post, Page],
  resolveDocumentType: (frontmatter, raw) => frontmatter.type
})
Feedback wanted
We'd love to hear your feedback on the proposed API change. 🙏

Duplicate issue #122: Add `include` / `exclude` configuration option for `contentlayer/source-files`
Created: 2022-02-10T12:52:22Z
Sometimes the directory structure provided via contentDirPath can contain files that Contentlayer should ignore while processing the "relevant" document files. In order to allow the user to configure with files Contentlayer should consider vs ignore we could introduce an include and/or exclude option in makeSource of contentlayer/source-files.

Closing comment (2022-03-29T14:43:55Z): How about just watching the files specified by filePathPattern across all defined local defineDocumentType?

Interesting idea. This is very related to #123. Need to think more about this.