hazo_blog 0.3.0 → 0.3.3
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/CHANGE_LOG.md +20 -0
- package/README.md +8 -3
- package/dist/lib/text.d.ts +27 -7
- package/dist/lib/text.d.ts.map +1 -1
- package/dist/lib/text.js +38 -8
- package/package.json +9 -9
package/CHANGE_LOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
All notable changes are documented here. This project follows
|
|
4
4
|
[Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## 0.3.3 — 2026-07-06
|
|
7
|
+
|
|
8
|
+
**`sanitizeMdx` hardened against raw WordPress HTML**
|
|
9
|
+
|
|
10
|
+
Extends the sanitizer beyond HTML comments to cover three more parser-breaking patterns commonly
|
|
11
|
+
found in imported WordPress post bodies. All run on the code-masked string, so fenced/inline code
|
|
12
|
+
spans stay byte-for-byte untouched, and the transform remains idempotent.
|
|
13
|
+
|
|
14
|
+
- **`<script>` / `<style>` blocks** — dropped entirely. Their bodies (JSON-LD, inline CSS) contain
|
|
15
|
+
raw `{ }` that MDX parses as a JS expression, throwing "Could not parse expression with acorn".
|
|
16
|
+
They carry no visible prose, so removing them never changes rendered output.
|
|
17
|
+
- **HTML void elements** (`<img>`, `<br>`, `<hr>`, `<input>`, …) — normalized to self-closing
|
|
18
|
+
(`<img src="x" />`). Un-self-closed voids throw "Expected a closing tag" in MDX/JSX.
|
|
19
|
+
- **String-valued `style="..."` / `style='...'` attributes** — dropped. Valid HTML but invalid JSX
|
|
20
|
+
(React requires the object form `style={{...}}`), else "The style prop expects a mapping … not a
|
|
21
|
+
string" at render. The JSX object form is deliberately left untouched.
|
|
22
|
+
|
|
23
|
+
No API change — same `sanitizeMdx(mdx: string): string` signature. **Consumer note:** `^0.3.0`
|
|
24
|
+
resolves to `0.3.3` (caret allows patch/minor within the same pre-1.0 minor).
|
|
25
|
+
|
|
6
26
|
## 0.3.0 — 2026-06-12
|
|
7
27
|
|
|
8
28
|
**Build resilience: sanitizer + async try/catch guard against malformed MDX**
|
package/README.md
CHANGED
|
@@ -208,9 +208,14 @@ const nextConfig = {
|
|
|
208
208
|
|
|
209
209
|
`BlogContent` (≥ 0.3.0) is an async server component that catches MDX compilation errors with
|
|
210
210
|
`try/catch`, so a single malformed post renders a graceful fallback instead of failing the whole
|
|
211
|
-
`next build`. It also pre-sanitizes content with `sanitizeMdx`
|
|
212
|
-
|
|
213
|
-
|
|
211
|
+
`next build`. It also pre-sanitizes content with `sanitizeMdx` before passing it to the compiler.
|
|
212
|
+
The sanitizer fixes the common ways raw WordPress HTML trips the MDX/acorn parser: converts HTML
|
|
213
|
+
comments → MDX comments (and escapes stray `<!`), strips `<script>`/`<style>` blocks whose bodies
|
|
214
|
+
break parsing, self-closes HTML void elements (`<img>`, `<br>`, …), and drops string-valued
|
|
215
|
+
`style="..."` attributes (invalid JSX; the object form `style={{...}}` is left untouched). Fenced
|
|
216
|
+
and inline code spans are left byte-for-byte untouched, and the transform is idempotent. The
|
|
217
|
+
sanitizer is also available as a standalone export from `hazo_blog/lib` for custom rendering
|
|
218
|
+
pipelines.
|
|
214
219
|
|
|
215
220
|
## Exports
|
|
216
221
|
|
package/dist/lib/text.d.ts
CHANGED
|
@@ -23,13 +23,33 @@ export interface TocHeading {
|
|
|
23
23
|
}
|
|
24
24
|
export declare function extractToc(mdx: string): TocHeading[];
|
|
25
25
|
/**
|
|
26
|
-
* Make raw MDX safe to compile.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
26
|
+
* Make raw MDX safe to compile. Raw WordPress HTML stored as post content
|
|
27
|
+
* trips the MDX/acorn parser in a handful of unambiguously-fixable ways:
|
|
28
|
+
*
|
|
29
|
+
* 1. HTML comments — MDX has none, so a bare `<!--` makes the parser expect
|
|
30
|
+
* a JSX tag name after `<` and throw "Unexpected character `!` before
|
|
31
|
+
* name". Converted to MDX comments ({/*…*\/}, equally non-rendering).
|
|
32
|
+
* 2. `<script>`/`<style>` blocks — their bodies (JSON-LD, inline CSS)
|
|
33
|
+
* contain raw `{ }` that MDX parses as a JS expression, throwing "Could
|
|
34
|
+
* not parse expression with acorn". They carry no visible prose (SEO
|
|
35
|
+
* metadata / global CSS handle those concerns elsewhere), so dropping the
|
|
36
|
+
* whole block is safe and never changes rendered output.
|
|
37
|
+
* 3. HTML void elements (`<img>`, `<br>`, …) written un-self-closed — MDX/JSX
|
|
38
|
+
* requires them self-closed; `<img src="x">` alone throws "Expected a
|
|
39
|
+
* closing tag". Normalized to `<img src="x" />` regardless of whether a
|
|
40
|
+
* stray slash was already present.
|
|
41
|
+
* 4. String-valued `style="..."` / `style='...'` attributes — valid HTML but
|
|
42
|
+
* invalid JSX/MDX (React requires `style={{...}}`, an object, never a
|
|
43
|
+
* string); left alone, they compile fine but throw "The style prop
|
|
44
|
+
* expects a mapping ... not a string" at render time. Always broken, so
|
|
45
|
+
* the attribute is dropped outright. Only the quoted-string form is
|
|
46
|
+
* matched (`style="`/`style='`) — the legitimate JSX object form
|
|
47
|
+
* (`style={{...}}`) never matches and is left untouched.
|
|
48
|
+
*
|
|
49
|
+
* All four run on the code-MASKED string, so fenced/inline code spans are
|
|
50
|
+
* left byte-for-byte untouched (they are literal in MDX, never error, and
|
|
51
|
+
* may legitimately show a comment, a `<script>` sample, or a bare `<img>` in
|
|
52
|
+
* a code sample). Idempotent: running this twice yields the same output.
|
|
33
53
|
*/
|
|
34
54
|
export declare function sanitizeMdx(mdx: string): string;
|
|
35
55
|
//# sourceMappingURL=text.d.ts.map
|
package/dist/lib/text.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/lib/text.ts"],"names":[],"mappings":"AAGA,6CAA6C;AAC7C,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS7C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAalD;AAED,0CAA0C;AAC1C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,SAAM,GAAG,MAAM,CAG9E;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAMhE;AAED,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAYpD;AAED
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/lib/text.ts"],"names":[],"mappings":"AAGA,6CAA6C;AAC7C,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS7C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAalD;AAED,0CAA0C;AAC1C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,SAAM,GAAG,MAAM,CAG9E;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,MAAM,CAMhE;AAED,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAYpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA+B/C"}
|
package/dist/lib/text.js
CHANGED
|
@@ -68,13 +68,33 @@ export function extractToc(mdx) {
|
|
|
68
68
|
return headings;
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
|
-
* Make raw MDX safe to compile.
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
71
|
+
* Make raw MDX safe to compile. Raw WordPress HTML stored as post content
|
|
72
|
+
* trips the MDX/acorn parser in a handful of unambiguously-fixable ways:
|
|
73
|
+
*
|
|
74
|
+
* 1. HTML comments — MDX has none, so a bare `<!--` makes the parser expect
|
|
75
|
+
* a JSX tag name after `<` and throw "Unexpected character `!` before
|
|
76
|
+
* name". Converted to MDX comments ({/*…*\/}, equally non-rendering).
|
|
77
|
+
* 2. `<script>`/`<style>` blocks — their bodies (JSON-LD, inline CSS)
|
|
78
|
+
* contain raw `{ }` that MDX parses as a JS expression, throwing "Could
|
|
79
|
+
* not parse expression with acorn". They carry no visible prose (SEO
|
|
80
|
+
* metadata / global CSS handle those concerns elsewhere), so dropping the
|
|
81
|
+
* whole block is safe and never changes rendered output.
|
|
82
|
+
* 3. HTML void elements (`<img>`, `<br>`, …) written un-self-closed — MDX/JSX
|
|
83
|
+
* requires them self-closed; `<img src="x">` alone throws "Expected a
|
|
84
|
+
* closing tag". Normalized to `<img src="x" />` regardless of whether a
|
|
85
|
+
* stray slash was already present.
|
|
86
|
+
* 4. String-valued `style="..."` / `style='...'` attributes — valid HTML but
|
|
87
|
+
* invalid JSX/MDX (React requires `style={{...}}`, an object, never a
|
|
88
|
+
* string); left alone, they compile fine but throw "The style prop
|
|
89
|
+
* expects a mapping ... not a string" at render time. Always broken, so
|
|
90
|
+
* the attribute is dropped outright. Only the quoted-string form is
|
|
91
|
+
* matched (`style="`/`style='`) — the legitimate JSX object form
|
|
92
|
+
* (`style={{...}}`) never matches and is left untouched.
|
|
93
|
+
*
|
|
94
|
+
* All four run on the code-MASKED string, so fenced/inline code spans are
|
|
95
|
+
* left byte-for-byte untouched (they are literal in MDX, never error, and
|
|
96
|
+
* may legitimately show a comment, a `<script>` sample, or a bare `<img>` in
|
|
97
|
+
* a code sample). Idempotent: running this twice yields the same output.
|
|
78
98
|
*/
|
|
79
99
|
export function sanitizeMdx(mdx) {
|
|
80
100
|
const stash = [];
|
|
@@ -90,8 +110,18 @@ export function sanitizeMdx(mdx) {
|
|
|
90
110
|
.replace(/~~~[\s\S]*?~~~/g, keep)
|
|
91
111
|
.replace(/`[^`\n]*`/g, keep);
|
|
92
112
|
masked = masked
|
|
113
|
+
// Strip <script>/<style> blocks entirely — see rationale above.
|
|
114
|
+
.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "")
|
|
115
|
+
.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "")
|
|
93
116
|
// Comment body: neutralize any `*/` so it can't close the MDX comment early.
|
|
94
117
|
.replace(/<!--([\s\S]*?)-->/g, (_, body) => `{/*${body.replace(/\*\//g, "* /")}*/}`)
|
|
95
|
-
.replace(/<!(?!--)/g, "<!")
|
|
118
|
+
.replace(/<!(?!--)/g, "<!")
|
|
119
|
+
// Strip string-valued `style="..."` attributes — see rationale above.
|
|
120
|
+
// Deliberately does NOT match `style={` (the valid JSX object form).
|
|
121
|
+
.replace(/\sstyle=("[^"]*"|'[^']*')/gi, "")
|
|
122
|
+
// Self-close HTML void elements — see rationale above. Emits `/>`
|
|
123
|
+
// whether or not a slash was already present, so a second pass is a
|
|
124
|
+
// no-op (idempotent).
|
|
125
|
+
.replace(/<(img|br|hr|input|source|meta|link|col|area|base|embed|param|track|wbr)\b([^>]*?)\s*\/?>/gi, "<$1$2 />");
|
|
96
126
|
return masked.replace(/(\d+)/g, (_, i) => stash[Number(i)]);
|
|
97
127
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_blog",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "SEO-optimized blogging package: posts, categories, tags, MDX content, and GA4/GSC/Bing-ready SEO.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"build:test-app": "npm run build && cd test-app && npm run build"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"hazo_core": "^1.2.
|
|
47
|
+
"hazo_core": "^1.2.1",
|
|
48
48
|
"hazo_connect": "^3.9.0",
|
|
49
|
-
"hazo_api": "^2.
|
|
50
|
-
"hazo_files": "^3.1.
|
|
51
|
-
"hazo_ui": "^4.
|
|
52
|
-
"hazo_images": "^1.
|
|
53
|
-
"hazo_jobs": "^0.
|
|
54
|
-
"hazo_auth": "^10.
|
|
49
|
+
"hazo_api": "^2.5.1",
|
|
50
|
+
"hazo_files": "^3.1.1",
|
|
51
|
+
"hazo_ui": "^4.8.0",
|
|
52
|
+
"hazo_images": "^1.7.0",
|
|
53
|
+
"hazo_jobs": "^0.14.0",
|
|
54
|
+
"hazo_auth": "^10.5.0",
|
|
55
55
|
"react": "^18.0.0 || ^19.0.0",
|
|
56
56
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
57
57
|
"next": "^14.0.0 || ^16.0.0"
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"hazo_connect": "^3.9.0",
|
|
88
88
|
"hazo_api": "^2.5.1",
|
|
89
89
|
"hazo_files": "^3.1.1",
|
|
90
|
-
"hazo_ui": "^4.
|
|
90
|
+
"hazo_ui": "^4.8.0",
|
|
91
91
|
"tailwindcss": "^4.2.4",
|
|
92
92
|
"@tailwindcss/postcss": "^4.2.4",
|
|
93
93
|
"postcss": "^8.4.49"
|