diff --git a/.changeset/twelve-cooks-flow.md b/.changeset/twelve-cooks-flow.md new file mode 100644 index 0000000..16f9128 --- /dev/null +++ b/.changeset/twelve-cooks-flow.md @@ -0,0 +1,5 @@ +--- +"vite-plugin-doctest": major +--- + +Use `@example` tag instead of `@import.meta.vitest` diff --git a/packages/vite-plugin-doctest/README.md b/packages/vite-plugin-doctest/README.md index 4495a20..f4e1d61 100644 --- a/packages/vite-plugin-doctest/README.md +++ b/packages/vite-plugin-doctest/README.md @@ -7,8 +7,8 @@ You can write test in your source code with documentation. ```ts /** - * @import.meta.vitest - * ```ts + * @example + * ```ts @import.meta.vitest * expect(add(1, 2)).toBe(3); * assert(add(3, 4) === 7); * ``` @@ -23,8 +23,7 @@ You can also test code in markdown. ````markdown # Test - -```ts +```ts:filename.ts@import.meta.vitest const { add } = await import('./add'); expect(add(1, 2)).toBe(3); ``` @@ -42,7 +41,12 @@ import { defineConfig } from 'vitest/config'; // or `import { defineConfig } fro import { doctest } from 'vite-plugin-doctest'; export default defineConfig({ plugins: [doctest({ /* options */ })], - test: { includeSource: ['./src/**/*.[jt]s?(x)', './**/*.md'] }, + test: { + includeSource: [ + './src/**/*.[jt]s?(x)', + './**/*.md', // You can disable markdown test by removing this line + ], + }, }); ``` @@ -67,8 +71,8 @@ So, you don't need to worry about the performance of your production code. ```ts /** - * @import.meta.vitest - * ```ts + * @example + * ```ts @import.meta.vitest * expect(add(1, 2)).toBe(3); * ``` */ @@ -81,8 +85,8 @@ export function add(a: number, b: number) { ```ts /** - * @import.meta.vitest - * ```ts:1+2=3 + * @example + * ```ts @import.meta.vitest * expect(add(1, 2)).toBe(3); * ``` */ diff --git a/packages/vite-plugin-doctest/src/transformers/markdown.ts b/packages/vite-plugin-doctest/src/transformers/markdown.ts index 1591fc7..427fa85 100644 --- a/packages/vite-plugin-doctest/src/transformers/markdown.ts +++ b/packages/vite-plugin-doctest/src/transformers/markdown.ts @@ -10,18 +10,15 @@ export const transform = async (code: string, id: string) => { let testCount = 0; const tests = await Promise.all( - ast.children.map(async (node, i, arr) => { + ast.children.map(async (node) => { // skip if not code block - if (node.type !== "code") return; - const [lang, name] = (node.lang || "ts").split(":", 2); - const prevNode = arr[i - 1]; - // skip if not test target if ( - !lang.match(/^([jt]sx?|javascript|typescript)$/i) || - prevNode?.type !== "html" || - !prevNode.value.match(/^$/) + node.type !== "code" || + (!node.meta?.includes("@import.meta.vitest") && + !node.lang?.includes("@import.meta.vitest")) ) return; + const [lang, name] = (node.lang || "ts").split(":", 2); const testNumber = testCount++; const transformResult = await transformWithEsbuild( node.value, diff --git a/packages/vite-plugin-doctest/src/transformers/typescript.ts b/packages/vite-plugin-doctest/src/transformers/typescript.ts index 1472ff5..4a104f2 100644 --- a/packages/vite-plugin-doctest/src/transformers/typescript.ts +++ b/packages/vite-plugin-doctest/src/transformers/typescript.ts @@ -51,21 +51,16 @@ function findJSDoc(node: typescript.Node): typescript.JSDoc[] { } function extractTestComment(jsDoc: typescript.JSDoc): string[] { - return ( - jsDoc.tags?.flatMap((tag) => { - if (tag.comment == null) return []; - const commentText = - typeof tag.comment === "string" - ? tag.comment - : tag.comment.map((c) => c.text).join("\n"); - // tagName should be `import.meta.vitest`. But it splits into `import` and `.meta.vitest`. - if ( - tag.tagName.text === "import" && - commentText.startsWith(".meta.vitest") - ) { - return [commentText]; - } - return []; - }) ?? [] - ); + if (jsDoc.tags == null) return []; + return jsDoc.tags.flatMap((tag) => { + if (tag.comment == null) return []; + const commentText = + typeof tag.comment === "string" + ? tag.comment + : tag.comment.map((c) => c.text).join("\n"); + if (tag.tagName.text === "example") { + return [commentText]; + } + return []; + }); } diff --git a/packages/vite-plugin-doctest/src/transformers/utils.ts b/packages/vite-plugin-doctest/src/transformers/utils.ts index ee2f917..8ce28e9 100644 --- a/packages/vite-plugin-doctest/src/transformers/utils.ts +++ b/packages/vite-plugin-doctest/src/transformers/utils.ts @@ -30,14 +30,14 @@ type TestCode = { }; export function extractCode(md: string): TestCode[] { - const matched = md.match(/```.*?\n.+?\n```/gs); + const matched = md.match(/```.+?\n.+?\n```/gs); if (matched == null) return []; - return matched.map((suggestion) => { - const matched = suggestion.match(/```(.*?)\n(.+?)\n```/s) ?? []; + return matched.flatMap((suggestion) => { + const matched = suggestion.match(/```(.+?)\n(.+?)\n```/s) ?? []; const [, lang, code] = matched; if (!code) throw new Error("Unexpected blank code block"); - if (lang == null) return { code }; - const name = lang.split(":")[1]?.trim(); + if (lang == null || !lang.includes("@import.meta.vitest")) return []; + const name = lang.split(":", 2)[1]?.trim(); return { name, code }; }); } diff --git a/test/src/add.ts b/test/src/add.ts index 88b9e68..386ca5c 100644 --- a/test/src/add.ts +++ b/test/src/add.ts @@ -1,6 +1,6 @@ /** - * @import.meta.vitest - * ```ts + * @example + * ```ts @import.meta.vitest * assert(add(1, 2) === 3); * ``` */ diff --git a/test/src/class.ts b/test/src/class.ts index 05c398f..01ff8dc 100644 --- a/test/src/class.ts +++ b/test/src/class.ts @@ -3,8 +3,8 @@ export class Foo { private readonly bar: number = 3; /** - * @import.meta.vitest - * ```ts + * @example + * ```ts @import.meta.vitest * assert(true); * ``` */ diff --git a/test/src/mul.js b/test/src/mul.js index c6933aa..2190075 100644 --- a/test/src/mul.js +++ b/test/src/mul.js @@ -1,6 +1,6 @@ /** - * @import.meta.vitest - * ```ts + * @example + * ```ts:test@import.meta.vitest * expect(mul(2, 3)).toBe(6); * ``` */ diff --git a/test/src/sub.ts b/test/src/sub.ts index 1b09dd8..b063b6f 100644 --- a/test/src/sub.ts +++ b/test/src/sub.ts @@ -1,14 +1,14 @@ /** - * @import.meta.vitest - * ```ts + * @example + * ```ts @import.meta.vitest * const { add } = await import('./add'); * expect(add(1, 2)).toBe(3); * ``` */ export const sub = (a: number, b: number) => { /** - * @import.meta.vitest - * ```ts + * @example + * ```ts @import.meta.vitest * expect(sub(1, 2)).toBe(-1); * ``` */ diff --git a/test/src/test.md b/test/src/test.md index 2778496..10b4be6 100644 --- a/test/src/test.md +++ b/test/src/test.md @@ -2,10 +2,9 @@ ## @import.meta.vitest -`@import.meta.vitest` is a special comment that will be tested. +`@import.meta.vitest` is a special marker that will be tested. - -```js +```js @import.meta.vitest const add = (a, b) => a + b; assert(add(1, 2) === 3); assert(add(0, 0) === 0); @@ -27,8 +26,7 @@ The plugin supports the following languages: - JavaScript (includes js,jsx) - TypeScript (includes ts,tsx) - -```ts +```ts:add@import.meta.vitest const add = (a: number, b: number) => a + b; expect(add(1, 2)).toBe(3); ``` @@ -37,13 +35,11 @@ expect(add(1, 2)).toBe(3); You can also import external files via dynamic import. - -```js +```js @import.meta.vitest const { add } = await import("./add"); assert(add(1, 2) === 3); ``` ## Constraints - `inline code` is not supported.