diff --git a/.changeset/big-masks-care.md b/.changeset/big-masks-care.md new file mode 100644 index 00000000000..8b3a17254e6 --- /dev/null +++ b/.changeset/big-masks-care.md @@ -0,0 +1,5 @@ +--- +"@effect/doctest": patch +--- + +Support `.mdx` files diff --git a/packages/tools/doctest/README.md b/packages/tools/doctest/README.md index e4d75e3383c..ad90bafd39a 100644 --- a/packages/tools/doctest/README.md +++ b/packages/tools/doctest/README.md @@ -1,6 +1,6 @@ # `@effect/doctest` -`@effect/doctest` extracts marked TypeScript examples from JSDoc comments and Markdown files, then runs each example as an isolated Vitest module. +`@effect/doctest` extracts marked TypeScript examples from JSDoc comments, Markdown, and MDX files, then runs each example as an isolated Vitest module. Mark runnable fences with `import.meta.vitest`: @@ -51,7 +51,7 @@ export const value = 1 Markers must trail a complete expression statement or supported `const` declaration on the same line. Standalone markers, destructuring declarations, multiple declarations, and `let` or `var` declarations are not supported. The transform does not implicitly await promises, run Effects, or consume iterators; write those operations explicitly. Ordinary comments are ignored. Await asynchronous work so all assertions and cleanup occur before the snippet module finishes evaluating. -Regular tests can use `include` in the same project. Documentation sources use `includeSource`, which lets Vitest discard files without the marker before collection. The plugin resolves imports relative to each example's original TypeScript or Markdown file: +Regular tests can use `include` in the same project. Documentation sources use `includeSource`, which lets Vitest discard files without the marker before collection. The plugin resolves imports relative to each example's original TypeScript, Markdown, or MDX file: ```ts import * as Doctest from "@effect/doctest/Plugin" @@ -61,7 +61,7 @@ export default defineConfig({ plugins: [Doctest.plugin()], test: { include: ["test/**/*.test.ts"], - includeSource: ["src/**/*.ts", "docs/**/*.md"] + includeSource: ["src/**/*.ts", "docs/**/*.{md,mdx}"] } }) ``` diff --git a/packages/tools/doctest/src/Source.ts b/packages/tools/doctest/src/Source.ts index 2c8e2b33f86..9185b2ed5a4 100644 --- a/packages/tools/doctest/src/Source.ts +++ b/packages/tools/doctest/src/Source.ts @@ -98,4 +98,6 @@ export const extract = (source: string, format: SourceFormat = "jsdoc"): Readonl * @since 4.0.0 */ export const extractFile = (file: string): Promise> => - readFile(file, "utf8").then((source) => extract(source, file.endsWith(".md") ? "markdown" : "jsdoc")) + readFile(file, "utf8").then((source) => + extract(source, file.endsWith(".md") || file.endsWith(".mdx") ? "markdown" : "jsdoc") + ) diff --git a/packages/tools/doctest/test/Source.test.ts b/packages/tools/doctest/test/Source.test.ts index 18f108a212c..57508e6ec8a 100644 --- a/packages/tools/doctest/test/Source.test.ts +++ b/packages/tools/doctest/test/Source.test.ts @@ -116,4 +116,24 @@ describe("Source", () => { ]) }) }) + + describe("MDX", () => { + it("extracts marked TypeScript fences from mdx content", () => { + const source = [ + "import { SomeComponent } from './component'", + "", + "## Example", + "", + "", + "", + "```ts import.meta.vitest", + "const result = 42", + "```" + ].join("\n") + + assert.deepStrictEqual(Source.extract(source, "markdown"), [ + { source: "const result = 42", line: 7, name: undefined } + ]) + }) + }) })