UNPKG

next-mdx-remote-client

Version:

A wrapper of the `@mdx-js/mdx` for the `nextjs` applications in order to load MDX content. It is a fork of `next-mdx-remote`.

134 lines (116 loc) 3.87 kB
/** * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 * * reference to https://github.com/hashicorp/next-mdx-remote/blob/main/src/format-mdx-error.ts * * improved the types */ import { codeFrameColumns } from "@babel/code-frame"; type Position = { start: { line: number; column: number; }; }; /** * Attempt to parse position information from an error message originating from the MDX compiler. * * @param message error message * @returns the position of the error indicator */ function parsePositionInformationFromErrorMessage(message: string): Position | undefined { const positionInfoPattern = /\d+:\d+(-\d+:\d+)/g; const match = message.match(positionInfoPattern); if (!match) return; // take the last match, that seems to be the most reliable source of the error. const lastMatch = match.slice(-1)[0]; const [line, column] = lastMatch.split("-")[0].split(":"); return { start: { line: Number.parseInt(line, 10), column: Number.parseInt(column, 10), }, }; } type PositionedError = Error & { position?: Position; }; /** * prints a nicely formatted error message from an error caught during MDX compilation. * * @param error Error caught from the mdx compiler * @param source Raw MDX string * @returns Error */ export function createFormattedMDXError(error: PositionedError, source: string): Error { const position = error.position ?? parsePositionInformationFromErrorMessage(error.message); const codeFrames = position ? codeFrameColumns( source, { start: { line: position.start.line, column: position.start.column, }, }, { linesAbove: 2, linesBelow: 2 }, ) : ""; const formattedError = new Error(`[next-mdx-remote-client] error compiling MDX: ${error?.message} ${codeFrames ? "\n" + codeFrames + "\n" : ""} More information: https://mdxjs.com/docs/troubleshooting-mdx`); formattedError.stack = ""; return formattedError; } /** * Copyright (c) @talatkuyuk AKA @ipikuka * SPDX-License-Identifier: MPL-2.0 */ export type VfileDataIntoScope = | true // all fields | string // one specific field | { name: string; as: string } // one specific field but change the key as | Array<string | { name: string; as: string }>; // more than one field /** * copies some fields of vfile.data into scope by mutating the scope * pay attention that it provides reference copy for objects (including arrays) * * @param data vfile.data from copied * @param vfileDataIntoScope refers the fields of vfile.data, some or all (if true) * @param scope an object to copied in a mutable way */ export function passVfileDataIntoScope( data: Record<string, unknown>, vfileDataIntoScope: VfileDataIntoScope, scope: Record<string, unknown>, ): undefined { if (typeof vfileDataIntoScope === "boolean") { Object.entries(data).forEach(([key, value]) => { scope[key] = value; }); } else if (typeof vfileDataIntoScope === "string") { scope[vfileDataIntoScope] = data[vfileDataIntoScope]; } else if (Array.isArray(vfileDataIntoScope)) { vfileDataIntoScope.forEach((field) => { if (typeof field === "string") { scope[field] = data[field]; } else if ( // type-coverage:ignore-next-line Object.prototype.hasOwnProperty.call(field, "name") && // type-coverage:ignore-next-line Object.prototype.hasOwnProperty.call(field, "as") ) { scope[field.as] = data[field.name]; } }); } else if ( // type-coverage:ignore-next-line Object.prototype.hasOwnProperty.call(vfileDataIntoScope, "name") && // type-coverage:ignore-next-line Object.prototype.hasOwnProperty.call(vfileDataIntoScope, "as") ) { scope[vfileDataIntoScope.as] = data[vfileDataIntoScope.name]; } }