916a568e9fd45b2298aad1064cbaea3ac9b8a47c
Four issues from adversarial review of the block-scoped <style> feature: 1. (Critical) transformBlock() recursed once per @media/@supports/@container nesting level with no cap -- ~7000 nested rules blew the call stack, and nothing between a Custom HTML block's toHtml() and the publish pipeline catches exceptions, so this took down the whole page's publish and crashed the live editor on every keystroke. Added MAX_NESTING_DEPTH=20 (pass the body through unscoped beyond it) and wrapped scopeCss() so it never throws on any input, matching repairOrphanNodes's existing contract. Caught and fixed a variable-shadowing bug in my own first pass at this: the new depth parameter was silently shadowed by a pre-existing `let depth` used for brace-matching in the same block, which would have defeated the cap with no type error. 2. (Important) FORCE_BODY: true was unconditional, but it isn't a no-op for style-free input: it also changes how the parser preserves whitespace after a LEADING html comment, which this repo's own fixture starts with. Verified via a raw byte-diff against HtmlBlock.tsx@6a9b227 (extracted verbatim, run standalone against real dompurify+jsdom) that the fixture gained bytes. Fixed by applying FORCE_BODY only when the input has a real (non-comment) <style> tag to rescue -- confirmed empirically that this is a true no-op for every other input. Pinned the old output as a checked-in regression fixture and added a raw toBe() diff test. 3. (Important) scopeStyleBlocks() wasn't idempotent -- pasting previously published/exported output into a fresh block nested a second wrapper and re-prefixed every selector. Added isAlreadyScoped(), which detects a lone root wrapper whose <style> content is already a no-op under scopeCss for that wrapper's own class (reusing scopeCss's own idempotency guarantee) and leaves it untouched. 4. (Minor) Documented, not fixed: the 32-bit scope-id hash is brute-forceable (CSS-only impact, same trust tier as other accepted risks here), and DOMPurify's SAFE_FOR_XML silently drops an entire <style> block when its content merely looks tag-like (e.g. content: "<Read More>"). 1155/1155 tests passing (was 1141), tsc clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Description
Visual drag-and-drop website builder using GrapesJS
3.5 MiB
Languages
TypeScript
64.8%
HTML
16.1%
JavaScript
14.9%
CSS
3.2%
PHP
0.7%
Other
0.3%