safe-mdx 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -5
- package/dist/esm-parser.d.ts.map +1 -1
- package/dist/esm-parser.js +2 -0
- package/dist/esm-parser.js.map +1 -1
- package/dist/esm-parser.test.js +3 -0
- package/dist/esm-parser.test.js.map +1 -1
- package/dist/safe-mdx.d.ts +11 -1
- package/dist/safe-mdx.d.ts.map +1 -1
- package/dist/safe-mdx.js +29 -9
- package/dist/safe-mdx.js.map +1 -1
- package/dist/safe-mdx.test.js +74 -0
- package/dist/safe-mdx.test.js.map +1 -1
- package/package.json +1 -1
- package/src/esm-parser.test.ts +3 -0
- package/src/esm-parser.ts +2 -0
- package/src/safe-mdx.test.tsx +76 -0
- package/src/safe-mdx.tsx +39 -7
package/README.md
CHANGED
|
@@ -181,6 +181,80 @@ subpath, so enabling `allowClientEsmImports` does not need any extra prop.
|
|
|
181
181
|
|
|
182
182
|
**Security Note**: ESM imports are disabled by default. Only enable `allowClientEsmImports` when you trust the MDX source, as it allows loading external code.
|
|
183
183
|
|
|
184
|
+
## Server-side Module Resolution
|
|
185
|
+
|
|
186
|
+
Resolve MDX `import` statements against pre-loaded modules on the server — no client-side `eval` or ESM fetching needed. This is the recommended approach when your MDX files import local components.
|
|
187
|
+
|
|
188
|
+
**Simple case** — use Vite's `import.meta.glob` with `{ eager: true }` to load all modules upfront. The result is already the shape `modules` expects:
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import { SafeMdxRenderer } from 'safe-mdx'
|
|
192
|
+
import { mdxParse } from 'safe-mdx/parse'
|
|
193
|
+
|
|
194
|
+
// { eager: true } returns the modules directly instead of lazy loaders:
|
|
195
|
+
// { './snippets/card.tsx': { Card, default: ... }, './snippets/badge.tsx': { Badge, ... } }
|
|
196
|
+
const modules = import.meta.glob('./snippets/**/*.tsx', { eager: true })
|
|
197
|
+
|
|
198
|
+
const code = `
|
|
199
|
+
import { Card } from '/snippets/card'
|
|
200
|
+
import { Badge } from '/snippets/badge'
|
|
201
|
+
|
|
202
|
+
# Hello
|
|
203
|
+
|
|
204
|
+
<Card title="Welcome">
|
|
205
|
+
Status: <Badge label="new" />
|
|
206
|
+
</Card>
|
|
207
|
+
`
|
|
208
|
+
|
|
209
|
+
export function Page() {
|
|
210
|
+
const mdast = mdxParse(code)
|
|
211
|
+
return (
|
|
212
|
+
<SafeMdxRenderer
|
|
213
|
+
markdown={code}
|
|
214
|
+
mdast={mdast}
|
|
215
|
+
modules={modules}
|
|
216
|
+
baseUrl="./pages/"
|
|
217
|
+
/>
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**With Vite `import.meta.glob`** — use `resolveModules` to lazily load only the modules the MDX actually imports:
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
import { SafeMdxRenderer } from 'safe-mdx'
|
|
226
|
+
import { mdxParse, resolveModules } from 'safe-mdx/parse'
|
|
227
|
+
|
|
228
|
+
const code = `
|
|
229
|
+
import { Card } from '/snippets/card'
|
|
230
|
+
|
|
231
|
+
# Hello
|
|
232
|
+
|
|
233
|
+
<Card title="Welcome">content</Card>
|
|
234
|
+
`
|
|
235
|
+
|
|
236
|
+
export async function Page() {
|
|
237
|
+
const lazyGlob = import.meta.glob('./snippets/**/*.tsx')
|
|
238
|
+
const mdast = mdxParse(code)
|
|
239
|
+
const modules = await resolveModules({
|
|
240
|
+
glob: lazyGlob,
|
|
241
|
+
mdast,
|
|
242
|
+
baseUrl: './pages/',
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
<SafeMdxRenderer
|
|
247
|
+
markdown={code}
|
|
248
|
+
mdast={mdast}
|
|
249
|
+
modules={modules}
|
|
250
|
+
baseUrl="./pages/"
|
|
251
|
+
/>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`baseUrl` is the directory of the MDX file being rendered — it's used to resolve relative imports like `./card` to the correct module key. If omitted it defaults to `'./'`.
|
|
257
|
+
|
|
184
258
|
## Change default MDX parser
|
|
185
259
|
|
|
186
260
|
If you want to use custom MDX plugins, you can pass your own MDX processed ast.
|
|
@@ -280,20 +354,132 @@ Instead you can use `renderNode` to return some JSX for a specific mdast node:
|
|
|
280
354
|
/>
|
|
281
355
|
```
|
|
282
356
|
|
|
357
|
+
## Validating component props
|
|
358
|
+
|
|
359
|
+
Use `componentPropsSchema` to validate component props against a schema. Works with any library that implements [Standard Schema](https://standardschema.dev) (Zod, Valibot, ArkType, etc).
|
|
360
|
+
|
|
361
|
+
Validation errors are collected in `visitor.errors` with line numbers and property paths. The component still renders with the invalid props, so you can show errors alongside the content.
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
import { MdastToJsx, type ComponentPropsSchema } from 'safe-mdx'
|
|
365
|
+
import { mdxParse } from 'safe-mdx/parse'
|
|
366
|
+
import { z } from 'zod'
|
|
367
|
+
|
|
368
|
+
const code = `
|
|
369
|
+
<Heading level={2} title="test">Valid heading</Heading>
|
|
370
|
+
|
|
371
|
+
<Heading level={10}>Invalid - level too high</Heading>
|
|
372
|
+
|
|
373
|
+
<Cards count={-1}>Invalid - negative count</Cards>
|
|
374
|
+
`
|
|
375
|
+
|
|
376
|
+
const componentPropsSchema: ComponentPropsSchema = {
|
|
377
|
+
Heading: z.object({
|
|
378
|
+
level: z.number().min(1).max(6),
|
|
379
|
+
title: z.string().optional(),
|
|
380
|
+
}),
|
|
381
|
+
Cards: z.object({
|
|
382
|
+
count: z.number().positive(),
|
|
383
|
+
variant: z.enum(['default', 'outline']).optional(),
|
|
384
|
+
}),
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export function Page() {
|
|
388
|
+
const mdast = mdxParse(code)
|
|
389
|
+
const visitor = new MdastToJsx({
|
|
390
|
+
markdown: code,
|
|
391
|
+
mdast,
|
|
392
|
+
components: {
|
|
393
|
+
Heading: ({ children, ...props }) => <h1 {...props}>{children}</h1>,
|
|
394
|
+
Cards: ({ children, ...props }) => <div {...props}>{children}</div>,
|
|
395
|
+
},
|
|
396
|
+
componentPropsSchema,
|
|
397
|
+
})
|
|
398
|
+
const jsx = visitor.run()
|
|
399
|
+
|
|
400
|
+
if (visitor.errors.length) {
|
|
401
|
+
// errors include type, line number, component name, property path, and message
|
|
402
|
+
// [
|
|
403
|
+
// { type: 'validation', message: 'Invalid props for component "Heading" at "level": Too big...', line: 3, schemaPath: 'level' },
|
|
404
|
+
// { type: 'validation', message: 'Invalid props for component "Cards" at "count": Too small...', line: 5, schemaPath: 'count' },
|
|
405
|
+
// ]
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return jsx
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
283
412
|
## Handling errors
|
|
284
413
|
|
|
285
|
-
`safe-mdx`
|
|
414
|
+
`safe-mdx` collects errors during rendering and exposes them via the `onError` callback or the `visitor.errors` array. Each error has a `type` field so you can filter by category.
|
|
415
|
+
|
|
416
|
+
### Error types
|
|
417
|
+
|
|
418
|
+
Every error is a `SafeMdxError` object:
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
interface SafeMdxError {
|
|
422
|
+
type: 'validation' | 'missing-component' | 'expression' | 'esm-import'
|
|
423
|
+
message: string
|
|
424
|
+
line?: number // source line in the MDX
|
|
425
|
+
schemaPath?: string // only for validation errors, e.g. "user.age"
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
| Type | When it fires |
|
|
430
|
+
|---|---|
|
|
431
|
+
| `validation` | Component props fail schema validation (via `componentPropsSchema`) |
|
|
432
|
+
| `missing-component` | MDX uses a `<Component>` that wasn't passed in `components` or resolved from `modules` |
|
|
433
|
+
| `expression` | An MDX expression like `{1 + fn()}` or a JSX attribute expression fails to evaluate |
|
|
434
|
+
| `esm-import` | An ESM `import` has an invalid URL or fails to parse (only with `allowClientEsmImports`) |
|
|
435
|
+
|
|
436
|
+
### Using `onError` callback
|
|
437
|
+
|
|
438
|
+
Works with both `SafeMdxRenderer` and `MdastToJsx`. Called for each error during rendering. Throw inside the callback to stop rendering on the first error.
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
import { SafeMdxRenderer } from 'safe-mdx'
|
|
442
|
+
import { mdxParse } from 'safe-mdx/parse'
|
|
443
|
+
|
|
444
|
+
export function Page() {
|
|
445
|
+
const mdast = mdxParse(code)
|
|
446
|
+
return (
|
|
447
|
+
<SafeMdxRenderer
|
|
448
|
+
markdown={code}
|
|
449
|
+
mdast={mdast}
|
|
450
|
+
components={components}
|
|
451
|
+
componentPropsSchema={componentPropsSchema}
|
|
452
|
+
onError={(error) => {
|
|
453
|
+
// only throw on schema validation errors
|
|
454
|
+
if (error.type === 'validation') {
|
|
455
|
+
throw new Error(
|
|
456
|
+
`Invalid props on line ${error.line}: ${error.message}`,
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
// log other errors without stopping rendering
|
|
460
|
+
console.warn(`[safe-mdx] ${error.type}: ${error.message}`)
|
|
461
|
+
}}
|
|
462
|
+
/>
|
|
463
|
+
)
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Using `MdastToJsx` directly
|
|
468
|
+
|
|
469
|
+
Access the full errors array after rendering:
|
|
286
470
|
|
|
287
471
|
```tsx
|
|
288
472
|
import { MdastToJsx } from 'safe-mdx'
|
|
473
|
+
import { mdxParse } from 'safe-mdx/parse'
|
|
289
474
|
|
|
290
475
|
export function Page() {
|
|
476
|
+
const mdast = mdxParse(code)
|
|
291
477
|
const visitor = new MdastToJsx({ markdown: code, mdast, components })
|
|
292
478
|
const jsx = visitor.run()
|
|
293
479
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
480
|
+
// filter by type
|
|
481
|
+
const validationErrors = visitor.errors.filter(e => e.type === 'validation')
|
|
482
|
+
const missingComponents = visitor.errors.filter(e => e.type === 'missing-component')
|
|
297
483
|
|
|
298
484
|
return jsx
|
|
299
485
|
}
|
|
@@ -312,7 +498,7 @@ This is okay if you render your MDX in isolation from each tenant - for example
|
|
|
312
498
|
These features are not supported yet:
|
|
313
499
|
|
|
314
500
|
- Expressions that use methods or functions, currently expressions are evaluated with [eval-estree-expression](https://github.com/jonschlinkert/eval-estree-expression) with the functions option disabled.
|
|
315
|
-
- Importing components or data from other files (unless `
|
|
501
|
+
- Importing components or data from other files (unless using `modules` prop for local imports or `allowClientEsmImports` for `https://` imports).
|
|
316
502
|
- Exporting unresolved components or declaring components inline in the MDX
|
|
317
503
|
|
|
318
504
|
**Note**: JSX components in attributes are now supported! You can use React components inside attributes like `<Card icon={<Icon />}>` without relying on JavaScript evaluation.
|
package/dist/esm-parser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esm-parser.d.ts","sourceRoot":"","sources":["../src/esm-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,MAAM,WAAW,YAAY;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;CACrB;AAcD;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACvC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"esm-parser.d.ts","sourceRoot":"","sources":["../src/esm-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,MAAM,WAAW,YAAY;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;CACrB;AAcD;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GACvC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAoDrB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAMrG"}
|
package/dist/esm-parser.js
CHANGED
|
@@ -29,6 +29,7 @@ export function parseEsmImports(node, onError) {
|
|
|
29
29
|
// Validate URL
|
|
30
30
|
if (!isValidHttpsUrl(importUrl)) {
|
|
31
31
|
onError({
|
|
32
|
+
type: 'esm-import',
|
|
32
33
|
message: `Invalid import URL: "${importUrl}". Only HTTPS URLs are allowed for security reasons.`,
|
|
33
34
|
line: node.position?.start?.line,
|
|
34
35
|
});
|
|
@@ -51,6 +52,7 @@ export function parseEsmImports(node, onError) {
|
|
|
51
52
|
}
|
|
52
53
|
catch (error) {
|
|
53
54
|
onError({
|
|
55
|
+
type: 'esm-import',
|
|
54
56
|
message: `Failed to parse ESM import: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
55
57
|
line: node.position?.start?.line,
|
|
56
58
|
});
|
package/dist/esm-parser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esm-parser.js","sourceRoot":"","sources":["../src/esm-parser.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW;IAChC,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QAC3B,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC3B,IAAS,EACT,OAAsC;IAEtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;IAEzC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACrB,OAAO,OAAO,CAAA;IAClB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA;QAEhC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,SAAS,CAAC,IAAI,KAAK,mBAAmB;gBACtC,SAAS,CAAC,MAAM,CAAC,KAAK;gBACtB,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAE7C,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAA;gBAExC,eAAe;gBACf,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC9B,OAAO,CAAC;wBACJ,OAAO,EAAE,wBAAwB,SAAS,sDAAsD;wBAChG,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI;qBACnC,CAAC,CAAA;oBACF,SAAQ;gBACZ,CAAC;gBAED,4BAA4B;gBAC5B,KAAK,MAAM,SAAS,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;oBAC3C,IAAI,SAAS,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;wBAC9C,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;oBAChD,CAAC;yBAAM,IAAI,SAAS,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;wBAC9C,MAAM,YAAY,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;4BACzD,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI;4BACzB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;wBACtC,OAAO,CAAC,GAAG,CACP,SAAS,CAAC,KAAK,CAAC,IAAI,EACpB,GAAG,SAAS,IAAI,YAAY,EAAE,CACjC,CAAA;oBACL,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC;YACJ,OAAO,EAAE,+BAA+B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE;YAClG,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI;SACnC,CAAC,CAAA;IACN,CAAC;IAED,OAAO,OAAO,CAAA;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAkB;IACnD,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC;QACvD,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;QACvB,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAE7B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AACvC,CAAC"}
|
|
1
|
+
{"version":3,"file":"esm-parser.js","sourceRoot":"","sources":["../src/esm-parser.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW;IAChC,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QAC3B,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC3B,IAAS,EACT,OAAsC;IAEtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;IAEzC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QACrB,OAAO,OAAO,CAAA;IAClB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA;QAEhC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,SAAS,CAAC,IAAI,KAAK,mBAAmB;gBACtC,SAAS,CAAC,MAAM,CAAC,KAAK;gBACtB,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAE7C,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAA;gBAExC,eAAe;gBACf,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC9B,OAAO,CAAC;wBACJ,IAAI,EAAE,YAAY;wBAClB,OAAO,EAAE,wBAAwB,SAAS,sDAAsD;wBAChG,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI;qBACnC,CAAC,CAAA;oBACF,SAAQ;gBACZ,CAAC;gBAED,4BAA4B;gBAC5B,KAAK,MAAM,SAAS,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;oBAC3C,IAAI,SAAS,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;wBAC9C,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;oBAChD,CAAC;yBAAM,IAAI,SAAS,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;wBAC9C,MAAM,YAAY,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;4BACzD,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI;4BACzB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;wBACtC,OAAO,CAAC,GAAG,CACP,SAAS,CAAC,KAAK,CAAC,IAAI,EACpB,GAAG,SAAS,IAAI,YAAY,EAAE,CACjC,CAAA;oBACL,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC;YACJ,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,+BAA+B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE;YAClG,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI;SACnC,CAAC,CAAA;IACN,CAAC;IAED,OAAO,OAAO,CAAA;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAkB;IACnD,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC;QACvD,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;QACvB,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAE7B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AACvC,CAAC"}
|
package/dist/esm-parser.test.js
CHANGED
|
@@ -57,14 +57,17 @@ import Component3 from './relative/path'
|
|
|
57
57
|
{
|
|
58
58
|
"line": 2,
|
|
59
59
|
"message": "Invalid import URL: "http://insecure.com/component". Only HTTPS URLs are allowed for security reasons.",
|
|
60
|
+
"type": "esm-import",
|
|
60
61
|
},
|
|
61
62
|
{
|
|
62
63
|
"line": 2,
|
|
63
64
|
"message": "Invalid import URL: "file:///local/path". Only HTTPS URLs are allowed for security reasons.",
|
|
65
|
+
"type": "esm-import",
|
|
64
66
|
},
|
|
65
67
|
{
|
|
66
68
|
"line": 2,
|
|
67
69
|
"message": "Invalid import URL: "./relative/path". Only HTTPS URLs are allowed for security reasons.",
|
|
70
|
+
"type": "esm-import",
|
|
68
71
|
},
|
|
69
72
|
]
|
|
70
73
|
`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esm-parser.test.js","sourceRoot":"","sources":["../src/esm-parser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACvE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGxE,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,IAAI,GAAG,yDAAyD,CAAA;QACtE,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,MAAM,GAAmB,EAAE,CAAA;QAEjC,yBAAyB;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAS,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAA;QAC5E,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAEnE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;SAO3D,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,IAAI,GAAG,oEAAoE,CAAA;QACjF,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,MAAM,GAAmB,EAAE,CAAA;QAEjC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAS,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAA;QAC5E,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAEnE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;SAW3D,CAAC,CAAA;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,IAAI,GAAG;;;;CAIpB,CAAA;QACO,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5B,MAAM,MAAM,GAAmB,EAAE,CAAA;QAEjC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAS,EAAE,EAAE;YACjC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC3B,eAAe,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;YACpD,CAAC;QACL,CAAC,CAAC,CAAA;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC
|
|
1
|
+
{"version":3,"file":"esm-parser.test.js","sourceRoot":"","sources":["../src/esm-parser.test.ts"],"names":[],"mappings":"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"}
|
package/dist/safe-mdx.d.ts
CHANGED
|
@@ -16,7 +16,9 @@ declare module 'mdast' {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
export type RenderNode = (node: MyRootContent, transform: (node: MyRootContent) => ReactNode) => ReactNode | undefined;
|
|
19
|
+
export type SafeMdxErrorType = 'validation' | 'missing-component' | 'expression' | 'esm-import';
|
|
19
20
|
export interface SafeMdxError {
|
|
21
|
+
type: SafeMdxErrorType;
|
|
20
22
|
message: string;
|
|
21
23
|
line?: number;
|
|
22
24
|
schemaPath?: string;
|
|
@@ -39,6 +41,9 @@ export declare const SafeMdxRenderer: React.NamedExoticComponent<{
|
|
|
39
41
|
/** Directory of the current MDX file, used to resolve relative import
|
|
40
42
|
* sources against `modules` keys. E.g. `'./pages/getting-started/'` */
|
|
41
43
|
baseUrl?: string;
|
|
44
|
+
/** Called for each error during rendering (missing components, invalid props, failed expressions).
|
|
45
|
+
* Throw inside this callback to stop rendering on first error. */
|
|
46
|
+
onError?: (error: SafeMdxError) => void;
|
|
42
47
|
}>;
|
|
43
48
|
export declare class MdastToJsx {
|
|
44
49
|
mdast: MyRootContent;
|
|
@@ -54,7 +59,8 @@ export declare class MdastToJsx {
|
|
|
54
59
|
addMarkdownLineNumbers: boolean;
|
|
55
60
|
modules?: EagerModules;
|
|
56
61
|
baseUrl?: string;
|
|
57
|
-
|
|
62
|
+
onError?: (error: SafeMdxError) => void;
|
|
63
|
+
constructor({ markdown: code, mdast, components, renderNode, componentPropsSchema, createElement, allowClientEsmImports, addMarkdownLineNumbers, modules, baseUrl, onError, }: {
|
|
58
64
|
markdown?: string;
|
|
59
65
|
mdast: MyRootContent;
|
|
60
66
|
components?: ComponentsMap;
|
|
@@ -65,7 +71,11 @@ export declare class MdastToJsx {
|
|
|
65
71
|
addMarkdownLineNumbers?: boolean;
|
|
66
72
|
modules?: EagerModules;
|
|
67
73
|
baseUrl?: string;
|
|
74
|
+
/** Called for each error during rendering (missing components, invalid props, failed expressions).
|
|
75
|
+
* Throw inside this callback to stop rendering on first error. */
|
|
76
|
+
onError?: (error: SafeMdxError) => void;
|
|
68
77
|
});
|
|
78
|
+
pushError(error: SafeMdxError): void;
|
|
69
79
|
/**
|
|
70
80
|
* Resolve import declarations from an mdxjsEsm node against `this.modules`.
|
|
71
81
|
* Resolved components are added directly to `this.c` (the component map)
|
package/dist/safe-mdx.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safe-mdx.d.ts","sourceRoot":"","sources":["../src/safe-mdx.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuB,MAAM,OAAO,CAAA;AAE3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE9E,OAAO,EAAY,SAAS,EAAE,MAAM,OAAO,CAAA;AAG3C,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AAEjE,OAAO,EAAqB,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAE7E,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,IAAI,CAAA;AAE9C,OAAO,QAAQ,OAAO,CAAC;IACnB,UAAiB,WAAW;QACxB,EAAE,CAAC,EAAE,MAAM,CAAA;KACd;IACD,UAAiB,IAAI;QACjB,WAAW,CAAC,EAAE,WAAW,CAAA;KAC5B;CACJ;AAED,MAAM,MAAM,UAAU,GAAG,CACrB,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,SAAS,KAC5C,SAAS,GAAG,SAAS,CAAA;AAE1B,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;AAEnE,MAAM,MAAM,qBAAqB,GAAG,CAChC,IAAI,EAAE,GAAG,EACT,KAAK,CAAC,EAAE,GAAG,EACX,GAAG,QAAQ,EAAE,SAAS,EAAE,KACvB,SAAS,CAAA;AAEd,eAAO,MAAM,eAAe;
|
|
1
|
+
{"version":3,"file":"safe-mdx.d.ts","sourceRoot":"","sources":["../src/safe-mdx.tsx"],"names":[],"mappings":"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"}
|
package/dist/safe-mdx.js
CHANGED
|
@@ -6,7 +6,7 @@ import { extractComponentInfo, parseEsmImports } from './esm-parser.js';
|
|
|
6
6
|
import { resolveModulePath } from './parse.js';
|
|
7
7
|
import { htmlToMdxAst } from './html/html-to-mdx-ast.js';
|
|
8
8
|
import { validHtmlElements, nativeTags } from './html/valid-html-elements.js';
|
|
9
|
-
export const SafeMdxRenderer = React.memo(function SafeMdxRenderer({ components, markdown = '', mdast = null, renderNode, componentPropsSchema, createElement, allowClientEsmImports = false, addMarkdownLineNumbers = false, modules, baseUrl, }) {
|
|
9
|
+
export const SafeMdxRenderer = React.memo(function SafeMdxRenderer({ components, markdown = '', mdast = null, renderNode, componentPropsSchema, createElement, allowClientEsmImports = false, addMarkdownLineNumbers = false, modules, baseUrl, onError, }) {
|
|
10
10
|
const visitor = new MdastToJsx({
|
|
11
11
|
markdown,
|
|
12
12
|
mdast,
|
|
@@ -18,6 +18,7 @@ export const SafeMdxRenderer = React.memo(function SafeMdxRenderer({ components,
|
|
|
18
18
|
addMarkdownLineNumbers,
|
|
19
19
|
modules,
|
|
20
20
|
baseUrl,
|
|
21
|
+
onError,
|
|
21
22
|
});
|
|
22
23
|
const result = visitor.run();
|
|
23
24
|
return result;
|
|
@@ -36,7 +37,8 @@ export class MdastToJsx {
|
|
|
36
37
|
addMarkdownLineNumbers;
|
|
37
38
|
modules;
|
|
38
39
|
baseUrl;
|
|
39
|
-
|
|
40
|
+
onError;
|
|
41
|
+
constructor({ markdown: code = '', mdast, components = {}, renderNode, componentPropsSchema, createElement = React.createElement, allowClientEsmImports = false, addMarkdownLineNumbers = false, modules, baseUrl, onError, }) {
|
|
40
42
|
this.str = code;
|
|
41
43
|
this.mdast = mdast;
|
|
42
44
|
this.renderNode = renderNode;
|
|
@@ -46,6 +48,7 @@ export class MdastToJsx {
|
|
|
46
48
|
this.addMarkdownLineNumbers = addMarkdownLineNumbers;
|
|
47
49
|
this.modules = modules;
|
|
48
50
|
this.baseUrl = baseUrl;
|
|
51
|
+
this.onError = onError;
|
|
49
52
|
this.c = {
|
|
50
53
|
...Object.fromEntries(nativeTags.map((tag) => {
|
|
51
54
|
return [tag, tag];
|
|
@@ -53,6 +56,10 @@ export class MdastToJsx {
|
|
|
53
56
|
...components,
|
|
54
57
|
};
|
|
55
58
|
}
|
|
59
|
+
pushError(error) {
|
|
60
|
+
this.errors.push(error);
|
|
61
|
+
this.onError?.(error);
|
|
62
|
+
}
|
|
56
63
|
/**
|
|
57
64
|
* Resolve import declarations from an mdxjsEsm node against `this.modules`.
|
|
58
65
|
* Resolved components are added directly to `this.c` (the component map)
|
|
@@ -121,7 +128,8 @@ export class MdastToJsx {
|
|
|
121
128
|
if (result.issues) {
|
|
122
129
|
result.issues.forEach((issue) => {
|
|
123
130
|
const propPath = issue.path?.join('.') || 'unknown';
|
|
124
|
-
this.
|
|
131
|
+
this.pushError({
|
|
132
|
+
type: 'validation',
|
|
125
133
|
message: `Invalid props for component "${componentName}" at "${propPath}": ${issue.message}`,
|
|
126
134
|
line,
|
|
127
135
|
schemaPath: issue.path?.join('.'),
|
|
@@ -184,7 +192,7 @@ export class MdastToJsx {
|
|
|
184
192
|
const { importUrl, componentName } = extractComponentInfo(esmImportInfo);
|
|
185
193
|
Component = DynamicEsmComponent;
|
|
186
194
|
let attrsList = this.getJsxAttrs(node, (err) => {
|
|
187
|
-
this.
|
|
195
|
+
this.pushError(err);
|
|
188
196
|
});
|
|
189
197
|
let attrs = Object.fromEntries(attrsList);
|
|
190
198
|
return this.createElement(Component, this.addLineNumberToProps({ ...attrs, importUrl, componentName }, node), this.mapJsxChildren(node));
|
|
@@ -192,7 +200,8 @@ export class MdastToJsx {
|
|
|
192
200
|
else {
|
|
193
201
|
Component = accessWithDot(this.c, node.name);
|
|
194
202
|
if (!Component) {
|
|
195
|
-
this.
|
|
203
|
+
this.pushError({
|
|
204
|
+
type: 'missing-component',
|
|
196
205
|
message: `Unsupported jsx component ${node.name}`,
|
|
197
206
|
line: node.position?.start?.line,
|
|
198
207
|
});
|
|
@@ -200,7 +209,7 @@ export class MdastToJsx {
|
|
|
200
209
|
}
|
|
201
210
|
}
|
|
202
211
|
let attrsList = this.getJsxAttrs(node, (err) => {
|
|
203
|
-
this.
|
|
212
|
+
this.pushError(err);
|
|
204
213
|
});
|
|
205
214
|
let attrs = Object.fromEntries(attrsList);
|
|
206
215
|
// Validate component props with schema if available
|
|
@@ -221,6 +230,7 @@ export class MdastToJsx {
|
|
|
221
230
|
: null;
|
|
222
231
|
if (!tagName) {
|
|
223
232
|
onError?.({
|
|
233
|
+
type: 'expression',
|
|
224
234
|
message: 'JSX element missing component name',
|
|
225
235
|
line: line,
|
|
226
236
|
});
|
|
@@ -241,6 +251,7 @@ export class MdastToJsx {
|
|
|
241
251
|
Component = accessWithDot(this.c, tagName);
|
|
242
252
|
if (!Component) {
|
|
243
253
|
onError?.({
|
|
254
|
+
type: 'missing-component',
|
|
244
255
|
message: `Unsupported jsx component ${tagName} in attribute`,
|
|
245
256
|
line: line,
|
|
246
257
|
});
|
|
@@ -299,6 +310,7 @@ export class MdastToJsx {
|
|
|
299
310
|
catch (error) {
|
|
300
311
|
// Return null if transformation fails
|
|
301
312
|
onError?.({
|
|
313
|
+
type: 'expression',
|
|
302
314
|
message: `Failed to transform JSX element: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
303
315
|
line: line,
|
|
304
316
|
});
|
|
@@ -328,6 +340,7 @@ export class MdastToJsx {
|
|
|
328
340
|
}
|
|
329
341
|
catch (error) {
|
|
330
342
|
onError({
|
|
343
|
+
type: 'expression',
|
|
331
344
|
message: `Failed to evaluate expression attribute: ${attr.value
|
|
332
345
|
.replace(/\n+/g, ' ')
|
|
333
346
|
.replace(/ +/g, ' ')}. ${error instanceof Error
|
|
@@ -340,6 +353,7 @@ export class MdastToJsx {
|
|
|
340
353
|
}
|
|
341
354
|
catch (error) {
|
|
342
355
|
onError({
|
|
356
|
+
type: 'expression',
|
|
343
357
|
message: `Failed to evaluate expression attribute: ${attr.value
|
|
344
358
|
.replace(/\n+/g, ' ')
|
|
345
359
|
.replace(/ +/g, ' ')}. ${error instanceof Error
|
|
@@ -351,6 +365,7 @@ export class MdastToJsx {
|
|
|
351
365
|
}
|
|
352
366
|
else {
|
|
353
367
|
onError({
|
|
368
|
+
type: 'expression',
|
|
354
369
|
message: `Expressions in jsx props are not supported (${attr.value
|
|
355
370
|
.replace(/\n+/g, ' ')
|
|
356
371
|
.replace(/ +/g, ' ')})`,
|
|
@@ -361,6 +376,7 @@ export class MdastToJsx {
|
|
|
361
376
|
}
|
|
362
377
|
if (attr.type !== 'mdxJsxAttribute') {
|
|
363
378
|
onError({
|
|
379
|
+
type: 'expression',
|
|
364
380
|
message: `non mdxJsxAttribute attribute is not supported: ${attr}`,
|
|
365
381
|
line: node.position?.start?.line,
|
|
366
382
|
});
|
|
@@ -417,6 +433,7 @@ export class MdastToJsx {
|
|
|
417
433
|
}
|
|
418
434
|
catch (error) {
|
|
419
435
|
onError({
|
|
436
|
+
type: 'expression',
|
|
420
437
|
message: `Failed to evaluate expression attribute: ${attr.name}={${v.value}}. ${error instanceof Error
|
|
421
438
|
? error.message
|
|
422
439
|
: String(error)}`,
|
|
@@ -430,6 +447,7 @@ export class MdastToJsx {
|
|
|
430
447
|
}
|
|
431
448
|
}
|
|
432
449
|
onError({
|
|
450
|
+
type: 'expression',
|
|
433
451
|
message: `Expressions in jsx prop not evaluated: (${attr.name}={${v.value}})`,
|
|
434
452
|
line: attr.position?.start?.line,
|
|
435
453
|
});
|
|
@@ -463,7 +481,7 @@ export class MdastToJsx {
|
|
|
463
481
|
}
|
|
464
482
|
// Parse ESM imports for client-side dynamic loading (only if allowed)
|
|
465
483
|
if (this.allowClientEsmImports) {
|
|
466
|
-
const parsedImports = parseEsmImports(node, (err) => this.
|
|
484
|
+
const parsedImports = parseEsmImports(node, (err) => this.pushError(err));
|
|
467
485
|
parsedImports.forEach((value, key) => {
|
|
468
486
|
this.esmImports.set(key, value);
|
|
469
487
|
});
|
|
@@ -509,7 +527,8 @@ export class MdastToJsx {
|
|
|
509
527
|
return result;
|
|
510
528
|
}
|
|
511
529
|
catch (error) {
|
|
512
|
-
this.
|
|
530
|
+
this.pushError({
|
|
531
|
+
type: 'expression',
|
|
513
532
|
message: `Failed to evaluate expression: ${node.value}. ${error instanceof Error
|
|
514
533
|
? error.message
|
|
515
534
|
: String(error)}`,
|
|
@@ -519,7 +538,8 @@ export class MdastToJsx {
|
|
|
519
538
|
}
|
|
520
539
|
}
|
|
521
540
|
catch (error) {
|
|
522
|
-
this.
|
|
541
|
+
this.pushError({
|
|
542
|
+
type: 'expression',
|
|
523
543
|
message: `Failed to evaluate expression: ${node.value}. ${error instanceof Error
|
|
524
544
|
? error.message
|
|
525
545
|
: String(error)}`,
|