diff --git a/packages/@contentlayer/cli/package.json b/packages/@contentlayer/cli/package.json index 216bb0d0..576a0107 100644 --- a/packages/@contentlayer/cli/package.json +++ b/packages/@contentlayer/cli/package.json @@ -1,6 +1,6 @@ { "name": "@contentlayer/cli", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "exports": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/@contentlayer/client/package.json b/packages/@contentlayer/client/package.json index 9cd81bf1..d3a483de 100644 --- a/packages/@contentlayer/client/package.json +++ b/packages/@contentlayer/client/package.json @@ -1,6 +1,6 @@ { "name": "@contentlayer/client", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "exports": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/@contentlayer/core/package.json b/packages/@contentlayer/core/package.json index e8ae7080..16ce7131 100644 --- a/packages/@contentlayer/core/package.json +++ b/packages/@contentlayer/core/package.json @@ -1,6 +1,6 @@ { "name": "@contentlayer/core", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "exports": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/@contentlayer/source-contentful/package.json b/packages/@contentlayer/source-contentful/package.json index f23976d9..79a208fd 100644 --- a/packages/@contentlayer/source-contentful/package.json +++ b/packages/@contentlayer/source-contentful/package.json @@ -1,6 +1,6 @@ { "name": "@contentlayer/source-contentful", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "exports": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/@contentlayer/source-files/package.json b/packages/@contentlayer/source-files/package.json index 3db90f3a..3ae6ade2 100644 --- a/packages/@contentlayer/source-files/package.json +++ b/packages/@contentlayer/source-files/package.json @@ -1,6 +1,6 @@ { "name": "@contentlayer/source-files", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "exports": { ".": { diff --git a/packages/@contentlayer/source-files/src/errors/index.ts b/packages/@contentlayer/source-files/src/errors/index.ts index 6acd66f0..ff52355e 100644 --- a/packages/@contentlayer/source-files/src/errors/index.ts +++ b/packages/@contentlayer/source-files/src/errors/index.ts @@ -6,6 +6,10 @@ import { handleFetchDataErrors } from './aggregate.js' export namespace FetchDataError { export type FetchDataError = + | InvalidFrontmatterError + | InvalidMarkdownFileError + | InvalidYamlFileError + | InvalidJsonFileError | ComputedValueError | UnsupportedFileExtension | NoSuchDocumentTypeError @@ -26,6 +30,63 @@ export namespace FetchDataError { type InvalidDataErrorKind = 'UnknownDocument' | 'ExtraFieldData' | 'MissingOrIncompatibleData' | 'Unexpected' + export class InvalidFrontmatterError + extends Tagged('InvalidFrontmatterError')<{ + readonly error: unknown + readonly documentFilePath: string + }> + implements AggregatableError + { + kind: InvalidDataErrorKind = 'MissingOrIncompatibleData' + + renderHeadline: RenderHeadline = ({ documentCount }) => + `Invalid frontmatter data found for ${documentCount} documents.` + + renderLine = () => `"${this.documentFilePath}" failed with ${errorToString(this.error)}` + } + + export class InvalidMarkdownFileError + extends Tagged('InvalidMarkdownFileError')<{ + readonly error: unknown + readonly documentFilePath: string + }> + implements AggregatableError + { + kind: InvalidDataErrorKind = 'MissingOrIncompatibleData' + + renderHeadline: RenderHeadline = ({ documentCount }) => `Invalid markdown in ${documentCount} documents.` + + renderLine = () => `"${this.documentFilePath}" failed with ${errorToString(this.error)}` + } + + export class InvalidYamlFileError + extends Tagged('InvalidYamlFileError')<{ + readonly error: unknown + readonly documentFilePath: string + }> + implements AggregatableError + { + kind: InvalidDataErrorKind = 'MissingOrIncompatibleData' + + renderHeadline: RenderHeadline = ({ documentCount }) => `Invalid YAML data in ${documentCount} documents.` + + renderLine = () => `"${this.documentFilePath}" failed with ${errorToString(this.error)}` + } + + export class InvalidJsonFileError + extends Tagged('InvalidJsonFileError')<{ + readonly error: unknown + readonly documentFilePath: string + }> + implements AggregatableError + { + kind: InvalidDataErrorKind = 'MissingOrIncompatibleData' + + renderHeadline: RenderHeadline = ({ documentCount }) => `Invalid JSON data in ${documentCount} documents.` + + renderLine = () => `"${this.documentFilePath}" failed with ${errorToString(this.error)}` + } + export class ComputedValueError extends Tagged('ComputedValueError')<{ readonly error: unknown diff --git a/packages/@contentlayer/source-files/src/fetchData/fetchAllDocuments.ts b/packages/@contentlayer/source-files/src/fetchData/fetchAllDocuments.ts index c6ff2236..3cbe6e44 100644 --- a/packages/@contentlayer/source-files/src/fetchData/fetchAllDocuments.ts +++ b/packages/@contentlayer/source-files/src/fetchData/fetchAllDocuments.ts @@ -110,9 +110,7 @@ export const makeCacheItemFromFilePath = ({ const rawContent = yield* $(processRawContent({ fullFilePath, relativeFilePath })) - const { - tuple: [{ documentTypeDef }, warnings], - } = yield* $( + const [{ documentTypeDef }, warnings] = yield* $( pipe( validateDocumentData({ rawContent, @@ -122,6 +120,7 @@ export const makeCacheItemFromFilePath = ({ options, }), These.toEffect, + T.map((_) => _.tuple), ), ) @@ -169,7 +168,13 @@ const processRawContent = ({ relativeFilePath: string }): T.Effect< OT.HasTracer, - FetchDataError.UnsupportedFileExtension | fs.FileNotFoundError | fs.ReadFileError, + | FetchDataError.UnsupportedFileExtension + | FetchDataError.InvalidFrontmatterError + | FetchDataError.InvalidMarkdownFileError + | FetchDataError.InvalidJsonFileError + | FetchDataError.InvalidYamlFileError + | fs.FileNotFoundError + | fs.ReadFileError, RawContent > => pipe( @@ -179,18 +184,22 @@ const processRawContent = ({ switch (filePathExtension) { case 'md': { - const markdown = matter(fileContent) + const markdown = yield* $(parseMarkdown({ markdownString: fileContent, documentFilePath: relativeFilePath })) return { kind: 'markdown' as const, fields: markdown.data, body: markdown.content } } case 'mdx': { - const markdown = matter(fileContent) + const markdown = yield* $(parseMarkdown({ markdownString: fileContent, documentFilePath: relativeFilePath })) return { kind: 'mdx' as const, fields: markdown.data, body: markdown.content } } - case 'json': - return { kind: 'json' as const, fields: JSON.parse(fileContent) } + case 'json': { + const fields = yield* $(parseJson({ jsonString: fileContent, documentFilePath: relativeFilePath })) + return { kind: 'json' as const, fields } + } case 'yaml': - case 'yml': - return { kind: 'yaml' as const, fields: yaml.parse(fileContent) } + case 'yml': { + const fields = yield* $(parseYaml({ yamlString: fileContent, documentFilePath: relativeFilePath })) + return { kind: 'yaml' as const, fields } + } default: return yield* $( T.fail( @@ -239,3 +248,49 @@ const getAllRelativeFilePaths = ({ (error) => new fs.UnknownFSError({ error }), ) } + +const parseMarkdown = ({ + markdownString, + documentFilePath, +}: { + markdownString: string + documentFilePath: string +}): T.Effect< + unknown, + FetchDataError.InvalidMarkdownFileError | FetchDataError.InvalidFrontmatterError, + matter.GrayMatterFile +> => + T.tryCatch( + () => matter(markdownString), + (error: any) => { + if (error.name === 'YAMLException') { + return new FetchDataError.InvalidFrontmatterError({ error, documentFilePath }) + } else { + return new FetchDataError.InvalidMarkdownFileError({ error, documentFilePath }) + } + }, + ) + +const parseJson = ({ + jsonString, + documentFilePath, +}: { + jsonString: string + documentFilePath: string +}): T.Effect> => + T.tryCatch( + () => JSON.parse(jsonString), + (error) => new FetchDataError.InvalidJsonFileError({ error, documentFilePath }), + ) + +const parseYaml = ({ + yamlString, + documentFilePath, +}: { + yamlString: string + documentFilePath: string +}): T.Effect> => + T.tryCatch( + () => yaml.parse(yamlString), + (error) => new FetchDataError.InvalidYamlFileError({ error, documentFilePath }), + ) diff --git a/packages/@contentlayer/source-sanity/package.json b/packages/@contentlayer/source-sanity/package.json index ab380eae..36f81bd1 100644 --- a/packages/@contentlayer/source-sanity/package.json +++ b/packages/@contentlayer/source-sanity/package.json @@ -1,6 +1,6 @@ { "name": "@contentlayer/source-sanity", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "exports": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/@contentlayer/utils/package.json b/packages/@contentlayer/utils/package.json index b25dce92..71a3bb0f 100644 --- a/packages/@contentlayer/utils/package.json +++ b/packages/@contentlayer/utils/package.json @@ -1,6 +1,6 @@ { "name": "@contentlayer/utils", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "exports": { "./package.json": { diff --git a/packages/contentlayer-stackbit-yaml-generator/package.json b/packages/contentlayer-stackbit-yaml-generator/package.json index 07db7afd..422a33ca 100644 --- a/packages/contentlayer-stackbit-yaml-generator/package.json +++ b/packages/contentlayer-stackbit-yaml-generator/package.json @@ -1,6 +1,6 @@ { "name": "contentlayer-stackbit-yaml-generator", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "bin": "./dist/cli/index.js", "exports": "./dist/lib/index.js", diff --git a/packages/contentlayer/package.json b/packages/contentlayer/package.json index ce0c9782..f229cc1b 100644 --- a/packages/contentlayer/package.json +++ b/packages/contentlayer/package.json @@ -1,6 +1,6 @@ { "name": "contentlayer", - "version": "0.0.26", + "version": "0.0.27", "bin": "./bin/cli.cjs", "type": "module", "exports": { diff --git a/packages/next-contentlayer/package.json b/packages/next-contentlayer/package.json index 43140108..1a123922 100644 --- a/packages/next-contentlayer/package.json +++ b/packages/next-contentlayer/package.json @@ -1,6 +1,6 @@ { "name": "next-contentlayer", - "version": "0.0.26", + "version": "0.0.27", "type": "module", "main": "./dist/cjs/index.cjs", "exports": {