safe-mdx 1.5.0 → 1.7.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.
Files changed (42) hide show
  1. package/README.md +94 -8
  2. package/dist/dynamic-esm-component.d.ts +1 -1
  3. package/dist/dynamic-esm-component.d.ts.map +1 -1
  4. package/dist/dynamic-esm-component.js +9 -1
  5. package/dist/dynamic-esm-component.js.map +1 -1
  6. package/dist/esm-parser.d.ts +1 -1
  7. package/dist/esm-parser.d.ts.map +1 -1
  8. package/dist/esm-parser.js +3 -3
  9. package/dist/esm-parser.js.map +1 -1
  10. package/dist/esm-parser.test.js +2 -2
  11. package/dist/html/html-and-md.test.js.map +1 -1
  12. package/dist/html/html-to-mdx-ast.d.ts +1 -1
  13. package/dist/html/html-to-mdx-ast.js +4 -4
  14. package/dist/html/html-to-mdx-ast.js.map +1 -1
  15. package/dist/html/html-to-mdx-ast.test.js +3 -3
  16. package/dist/html/html-to-mdx-ast.test.js.map +1 -1
  17. package/dist/parse.d.ts +1 -1
  18. package/dist/parse.d.ts.map +1 -1
  19. package/dist/parse.js +5 -1
  20. package/dist/parse.js.map +1 -1
  21. package/dist/safe-mdx.bench.js +2 -2
  22. package/dist/safe-mdx.bench.js.map +1 -1
  23. package/dist/safe-mdx.d.ts +48 -3
  24. package/dist/safe-mdx.d.ts.map +1 -1
  25. package/dist/safe-mdx.js +219 -26
  26. package/dist/safe-mdx.js.map +1 -1
  27. package/dist/safe-mdx.test.js +420 -5
  28. package/dist/safe-mdx.test.js.map +1 -1
  29. package/dist/streaming.d.ts.map +1 -1
  30. package/dist/streaming.js +3 -1
  31. package/dist/streaming.js.map +1 -1
  32. package/package.json +30 -7
  33. package/src/esm-parser.test.ts +3 -3
  34. package/src/esm-parser.ts +4 -4
  35. package/src/html/html-and-md.test.ts +2 -2
  36. package/src/html/html-to-mdx-ast.test.ts +3 -3
  37. package/src/html/html-to-mdx-ast.ts +4 -4
  38. package/src/parse.ts +3 -1
  39. package/src/safe-mdx.bench.tsx +2 -2
  40. package/src/safe-mdx.test.tsx +519 -11
  41. package/src/safe-mdx.tsx +315 -28
  42. package/src/streaming.tsx +2 -1
package/package.json CHANGED
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "name": "safe-mdx",
3
- "version": "1.5.0",
4
- "private": false,
5
- "description": "Render MDX in React without eval",
6
- "repository": "https://github.com/holocron-hq/safe-mdx",
3
+ "version": "1.7.0",
4
+ "description": "Render MDX in React without eval, works in Cloudflare Workers and Vercel Edge",
7
5
  "type": "module",
6
+ "main": "./dist/safe-mdx.js",
8
7
  "types": "./dist/safe-mdx.d.ts",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/holocron-hq/safe-mdx"
11
+ },
12
+ "homepage": "https://github.com/holocron-hq/safe-mdx",
13
+ "bugs": "https://github.com/holocron-hq/safe-mdx/issues",
9
14
  "exports": {
15
+ "./package.json": "./package.json",
10
16
  ".": {
11
17
  "types": "./dist/safe-mdx.d.ts",
12
18
  "default": "./dist/safe-mdx.js"
@@ -24,15 +30,29 @@
24
30
  "browser": "./dist/html/domparser-browser.js",
25
31
  "default": "./dist/html/domparser.js"
26
32
  },
27
- "./src/*": "./src/*.tsx",
28
- "./package.json": "./package.json"
33
+ "./src": {
34
+ "types": "./src/safe-mdx.tsx",
35
+ "default": "./src/safe-mdx.tsx"
36
+ },
37
+ "./src/*": {
38
+ "types": "./src/*.tsx",
39
+ "default": "./src/*.tsx"
40
+ }
29
41
  },
30
42
  "files": [
31
43
  "dist",
32
44
  "src"
33
45
  ],
34
46
  "keywords": [
35
- "mdx"
47
+ "mdx",
48
+ "react",
49
+ "server-components",
50
+ "rsc",
51
+ "safe",
52
+ "no-eval",
53
+ "cloudflare-workers",
54
+ "edge",
55
+ "markdown"
36
56
  ],
37
57
  "author": "remorses <beats.by.morse@gmail.com>",
38
58
  "license": "MIT",
@@ -59,6 +79,7 @@
59
79
  "@changesets/cli": "^2.28.1",
60
80
  "@tailwindcss/typography": "^0.5.16",
61
81
  "@tailwindcss/vite": "^4.1.11",
82
+ "@types/escodegen": "^0.0.10",
62
83
  "@types/estree-jsx": "^1.0.5",
63
84
  "@types/mdast": "^4.0.0",
64
85
  "@types/node": "^22.15.17",
@@ -68,12 +89,14 @@
68
89
  "@vitejs/plugin-react": "^4.7.0",
69
90
  "@vitest/coverage-v8": "^1.6.0",
70
91
  "dedent": "^1.5.1",
92
+ "escodegen": "^2.1.0",
71
93
  "importmap-vite-plugin": "^0.0.0",
72
94
  "mdast-util-mdx-jsx": "^3.2.0",
73
95
  "react": "^19.2.1",
74
96
  "react-dom": "^19.2.1",
75
97
  "remark-parse": "^11.0.0",
76
98
  "remark-stringify": "^11.0.0",
99
+ "rimraf": "^6.0.1",
77
100
  "tailwindcss": "^4.1.11",
78
101
  "typescript": "5.8.3",
79
102
  "vite": "^6.2.6",
@@ -1,7 +1,7 @@
1
1
  import { expect, test, describe } from 'vitest'
2
- import { parseEsmImports, extractComponentInfo } from './esm-parser.js'
3
- import { mdxParse, extractImports, resolveModulePath } from './parse.js'
4
- import type { SafeMdxError } from './safe-mdx.js'
2
+ import { parseEsmImports, extractComponentInfo } from './esm-parser.ts'
3
+ import { mdxParse, extractImports, resolveModulePath } from './parse.ts'
4
+ import type { SafeMdxError } from './safe-mdx.tsx'
5
5
 
6
6
  describe('parseEsmImports', () => {
7
7
  test('parses default imports from HTTPS URLs', () => {
package/src/esm-parser.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { SafeMdxError } from './safe-mdx.js'
1
+ import type { SafeMdxError } from './safe-mdx.tsx'
2
2
 
3
3
  export interface ParsedImport {
4
4
  componentName: string
@@ -83,9 +83,9 @@ export function parseEsmImports(
83
83
  * Extracts component info from an import map entry
84
84
  */
85
85
  export function extractComponentInfo(importInfo: string): { importUrl: string; componentName: string } {
86
- const [importUrl, componentName] = importInfo.includes('#')
87
- ? importInfo.split('#')
88
- : [importInfo, 'default']
86
+ const parts = importInfo.split('#')
87
+ const importUrl = parts[0] ?? importInfo
88
+ const componentName = importInfo.includes('#') ? (parts[1] ?? 'default') : 'default'
89
89
 
90
90
  return { importUrl, componentName }
91
91
  }
@@ -55,7 +55,7 @@ async function htmlToMdxString({
55
55
  parent &&
56
56
  typeof index === 'number'
57
57
  ) {
58
- const htmlValue = node.value as string
58
+ const htmlValue = node.value
59
59
 
60
60
  // Parse HTML to MDX AST with processor for markdown parsing
61
61
  const mdxNodes = parseHtmlToMdxAst({
@@ -77,7 +77,7 @@ async function htmlToMdxString({
77
77
 
78
78
  // Replace the HTML node with the MDX nodes
79
79
  if (mdxNodes.length === 1) {
80
- parent.children[index] = mdxNodes[0]
80
+ parent.children[index] = mdxNodes[0]!
81
81
  } else if (mdxNodes.length > 1) {
82
82
  parent.children.splice(index, 1, ...mdxNodes)
83
83
  } else {
@@ -5,14 +5,14 @@ import {
5
5
  parseHtmlToMdxAst,
6
6
  htmlToMdxAst,
7
7
  remarkMdxJsxNormalize,
8
- } from './html-to-mdx-ast.js'
8
+ } from './html-to-mdx-ast.ts'
9
9
  import { unified } from 'unified'
10
10
  import remarkMdx from 'remark-mdx'
11
11
  import remarkStringify from 'remark-stringify'
12
12
  import remarkParse from 'remark-parse'
13
13
  import type { RootContent } from 'mdast'
14
- import { mdxParse } from '../parse.js'
15
- import { MdastToJsx } from '../safe-mdx.js'
14
+ import { mdxParse } from '../parse.ts'
15
+ import { MdastToJsx } from '../safe-mdx.tsx'
16
16
 
17
17
  // Default components for testing
18
18
  const components = {
@@ -6,9 +6,9 @@ import type {
6
6
  } from 'mdast-util-mdx-jsx'
7
7
  import type { Processor } from 'unified'
8
8
  import { unified } from 'unified'
9
- import { convertAttributeNameToJSX } from './convert-attributes.js'
10
- import { parseHTML } from './domparser.js'
11
- import { remarkMdxJsxNormalize } from './remark-mdx-jsx-normalize.js'
9
+ import { convertAttributeNameToJSX } from './convert-attributes.ts'
10
+ import { parseHTML } from './domparser.ts'
11
+ import { remarkMdxJsxNormalize } from './remark-mdx-jsx-normalize.ts'
12
12
 
13
13
  // Re-export the normalize plugin
14
14
  export { remarkMdxJsxNormalize }
@@ -77,7 +77,7 @@ function deindent(text: string): string {
77
77
  for (const line of lines) {
78
78
  if (line.trim()) {
79
79
  const match = line.match(/^(\s*)/)
80
- if (match) {
80
+ if (match?.[1] != null) {
81
81
  minIndent = Math.min(minIndent, match[1].length)
82
82
  }
83
83
  }
package/src/parse.ts CHANGED
@@ -5,7 +5,7 @@ import { Root, RootContent } from 'mdast'
5
5
  import { remark } from 'remark'
6
6
  import remarkGfm from 'remark-gfm'
7
7
  import remarkMdx from 'remark-mdx'
8
- import { parseHtmlToMdxAst, remarkMdxJsxNormalize } from './html/html-to-mdx-ast.js'
8
+ import { parseHtmlToMdxAst, remarkMdxJsxNormalize } from './html/html-to-mdx-ast.ts'
9
9
 
10
10
  export { parseHtmlToMdxAst, remarkMdxJsxNormalize }
11
11
 
@@ -95,6 +95,7 @@ export function remarkMarkAndUnravel() {
95
95
 
96
96
  while (++offset < children.length) {
97
97
  const child = children[offset]
98
+ if (!child) continue
98
99
 
99
100
  if (
100
101
  child.type === 'mdxJsxTextElement' ||
@@ -122,6 +123,7 @@ export function remarkMarkAndUnravel() {
122
123
 
123
124
  while (++offset < children.length) {
124
125
  const child = children[offset]
126
+ if (!child) continue
125
127
 
126
128
  if (child.type === 'mdxJsxTextElement') {
127
129
  // @ts-expect-error: mutate because it is faster; content model is fine.
@@ -1,6 +1,6 @@
1
1
  import { bench, describe } from 'vitest'
2
- import { mdxParse } from './parse.js'
3
- import { MdastToJsx } from './safe-mdx.js'
2
+ import { mdxParse } from './parse.ts'
3
+ import { MdastToJsx } from './safe-mdx.tsx'
4
4
 
5
5
  let longMdxContent = await fetch(
6
6
  'https://raw.githubusercontent.com/colinhacks/zod/0a49fa39348b7c72b19ddedc3b0f879bd395304b/packages/docs/content/packages/v3.mdx',