diff --git a/.jest/utils.tsx b/.jest/utils.tsx index 9b47a54..f668985 100644 --- a/.jest/utils.tsx +++ b/.jest/utils.tsx @@ -25,10 +25,10 @@ export async function renderStatic( mdx: VFileCompatible, { components, - scope, + scope = {}, mdxOptions, parseFrontmatter, - }: SerializeOptions & Pick = {} + }: Partial> = {} ): Promise { const mdxSource = await serialize(mdx, { mdxOptions, @@ -55,7 +55,7 @@ export async function getPathToPackedPackage() { // Create a temporary directory from one of our fixtures to run isolated tests in // Handles installing the locally-packed next-mdx-remote -export async function createTmpTestDir(fixture) { +export async function createTmpTestDir(fixture: string) { const tmpDir = await fs.promises.mkdtemp( path.join(os.tmpdir(), `next-mdx-remote-${fixture}-`) ) @@ -93,8 +93,8 @@ export function createDescribe( fn: ({ dir }: { dir: () => string; browser: () => Browser }) => void ): void { describe(name, () => { - let tmpDir - let browser + let tmpDir: string + let browser: Browser beforeAll(async () => { tmpDir = await createTmpTestDir(options.fixture) @@ -187,7 +187,7 @@ export function readOutputFile(dir: string, name: string) { // Serves the out directory relative to the provided dir on port 1235 // TODO: we should just use next start -export function serveStatic(dir): Promise { +export function serveStatic(dir: string): Promise { return new Promise((resolve) => { const server = http.createServer((req, res) => handler(req, res, { diff --git a/.npmignore b/.npmignore index 89e6ba5..ab60da5 100644 --- a/.npmignore +++ b/.npmignore @@ -6,3 +6,4 @@ babel.config.js src .circleci *.tgz +global.d.ts diff --git a/__tests__/integration.test.tsx b/__tests__/integration.test.tsx index 49a7451..8d261ac 100644 --- a/__tests__/integration.test.tsx +++ b/__tests__/integration.test.tsx @@ -14,6 +14,7 @@ import { startDevServer, stopDevServer, } from '../.jest/utils' +import { ChildProcess } from 'child_process' jest.setTimeout(30000) @@ -89,7 +90,7 @@ createDescribe( 'hydration - dev server', { fixture: 'basic' }, ({ dir, browser }) => { - let childProcess + let childProcess: ChildProcess beforeAll(async () => { childProcess = await startDevServer(dir()) @@ -121,7 +122,7 @@ createDescribe( 'hydration - dev server - rsc', { fixture: 'rsc' }, ({ dir, browser }) => { - let childProcess + let childProcess: ChildProcess beforeAll(async () => { childProcess = await startDevServer(dir()) diff --git a/__tests__/serialize.test.tsx b/__tests__/serialize.test.tsx index 1be2ce7..6364ac0 100644 --- a/__tests__/serialize.test.tsx +++ b/__tests__/serialize.test.tsx @@ -13,6 +13,10 @@ import { MDXRemote } from '../' import { serialize } from '../serialize' import { renderStatic } from '../.jest/utils' +interface Frontmatter { + hello: string +} + describe('serialize', () => { test('minimal', async () => { const result = await renderStatic('foo **bar**') @@ -22,7 +26,7 @@ describe('serialize', () => { test('with component', async () => { const result = await renderStatic('foo ', { components: { - Test: ({ name }) => hello {name}, + Test: ({ name }: { name: string }) => hello {name}, }, }) expect(result).toMatchInlineSnapshot(`"

foo hello test

"`) @@ -118,7 +122,7 @@ export const bar = 'bar'`) test('fragments', async () => { const components = { - Test: ({ content }) => content, + Test: ({ content }: { content: string }) => <>{content}, } const result = await renderStatic( @@ -129,6 +133,22 @@ export const bar = 'bar'`) }) test('parses frontmatter - serialize result', async () => { + const result = await serialize, Frontmatter>( + `--- +hello: world +--- + +# Hello`, + { parseFrontmatter: true } + ) + + // Validating type correctness here, this should not error + expect().toBeTruthy() + + expect(result.frontmatter?.hello).toEqual('world') + }) + + test('parses frontmatter - serialize result - no types', async () => { const result = await serialize( `--- hello: world @@ -138,6 +158,9 @@ hello: world { parseFrontmatter: true } ) + // Validating type correctness here, this should not error + expect().toBeTruthy() + expect(result.frontmatter?.hello).toEqual('world') }) diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 0000000..f771b24 --- /dev/null +++ b/global.d.ts @@ -0,0 +1 @@ +declare module '@hashicorp/remark-plugins' diff --git a/package-lock.json b/package-lock.json index 0d1957b..7d8614e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "@types/node": "^16.11.6", "@types/puppeteer": "^5.4.4", "@types/react": "^17.0.33", + "@types/react-dom": "^18.0.11", "@types/rmfr": "^2.0.1", "@types/serve-handler": "^6.1.1", "cheerio": "^1.0.0-rc.10", @@ -2760,6 +2761,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -17528,6 +17538,15 @@ "csstype": "^3.0.2" } }, + "@types/react-dom": { + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", diff --git a/package.json b/package.json index 278d38e..4a13b64 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@types/node": "^16.11.6", "@types/puppeteer": "^5.4.4", "@types/react": "^17.0.33", + "@types/react-dom": "^18.0.11", "@types/rmfr": "^2.0.1", "@types/serve-handler": "^6.1.1", "cheerio": "^1.0.0-rc.10", @@ -41,8 +42,8 @@ "prettier": "^2.4.1", "pretty-quick": "^3.1.1", "puppeteer": "^10.4.0", - "react-dom": "^18.2.0", "react": "^18.2.0", + "react-dom": "^18.2.0", "release": "^6.3.0", "rmfr": "^2.0.0", "rollup": "^2.59.0", @@ -86,7 +87,9 @@ "release:patch": "release patch && npm publish", "prepublishOnly": "npm run build", "pretest": "mkdir -p ./dist && npm run build && npm pack --pack-destination ./dist", - "test": "jest" + "test": "npm run test:types && npm run test:js", + "test:js": "jest", + "test:types": "tsc -p . --noEmit" }, "types": "index.d.ts", "type": "module" diff --git a/rollup.config.js b/rollup.config.js index 64544f9..6448d06 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -28,6 +28,7 @@ export default [ tsconfig: './tsconfig.json', declaration: true, declarationDir: './dist', + exclude: ['./__tests__/**/*'], }), resolve(), { @@ -62,6 +63,7 @@ export default [ tsconfig: './tsconfig.json', declaration: true, declarationDir: './dist', + exclude: ['./__tests__/**/*'], }), json(), resolve(), @@ -80,6 +82,7 @@ export default [ tsconfig: './tsconfig.json', declaration: true, declarationDir: './dist', + exclude: ['./__tests__/**/*'], }), json(), resolve(), diff --git a/src/index.tsx b/src/index.tsx index e90d411..e6ec72c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -29,7 +29,10 @@ declare global { } } -export type MDXRemoteProps = MDXRemoteSerializeResult & { +export type MDXRemoteProps< + TScope = Record, + TFrontmatter = Record +> = MDXRemoteSerializeResult & { /** * A object mapping names to React components. * The key used will be the name accessible to MDX. @@ -48,13 +51,13 @@ export { MDXRemoteSerializeResult } /** * Renders compiled source from next-mdx-remote/serialize. */ -export function MDXRemote({ +export function MDXRemote({ compiledSource, frontmatter, scope, components = {}, lazy, -}: MDXRemoteProps) { +}: MDXRemoteProps) { const [isReadyToRender, setIsReadyToRender] = useState( !lazy || typeof window === 'undefined' ) diff --git a/tsconfig.json b/tsconfig.json index da17c26..5a93fb4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,5 @@ "declarationDir": "./dist", "outDir": "./dist" }, - "exclude": ["__tests__"], - "include": ["./src", "types.d.ts"] + "include": ["./src", "types.d.ts", "__tests__", "global.d.ts"] }