harden(html-embed): make stripHtmlEmbedNodes total with a root-type check (#30)
stripHtmlEmbedNodes only filtered children, so a (never-in-practice) bare htmlEmbed root node would be returned as-is. Add a defensive root check that returns an embed-free doc, making the helper total — it can never return a node for which hasHtmlEmbedNode is true. Adds a unit test for the root case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,17 @@ describe('stripHtmlEmbedNodes', () => {
|
||||
const result = stripHtmlEmbedNodes(doc);
|
||||
expect(result).toEqual(doc);
|
||||
});
|
||||
|
||||
it('neutralizes a root node that is itself an htmlEmbed', () => {
|
||||
// Defensive: the PM root is always a `doc`, so this is unreachable in normal
|
||||
// use, but the helper must still never return a bare htmlEmbed.
|
||||
const root = {
|
||||
type: 'htmlEmbed',
|
||||
attrs: { source: '<script>alert(1)</script>' },
|
||||
};
|
||||
const result = stripHtmlEmbedNodes(root);
|
||||
expect(hasHtmlEmbedNode(result)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canAuthorHtmlEmbed', () => {
|
||||
|
||||
@@ -22,6 +22,15 @@ export function stripHtmlEmbedNodes<T = JSONContent>(pmJson: T): T {
|
||||
|
||||
const node = pmJson as unknown as JSONContent;
|
||||
|
||||
// Defensive root-type check: if the ROOT node is itself an htmlEmbed, the
|
||||
// children-filtering below could never drop it, so a bare htmlEmbed would be
|
||||
// returned as-is. This branch is unreachable in normal use (the PM document
|
||||
// root is always a `doc`) and exists only to make the helper total — a bare
|
||||
// htmlEmbed can never be returned by this function.
|
||||
if (node.type === HTML_EMBED_NODE_NAME) {
|
||||
return { type: 'doc', content: [] } as unknown as T;
|
||||
}
|
||||
|
||||
if (Array.isArray(node.content)) {
|
||||
const filtered: JSONContent[] = [];
|
||||
for (const child of node.content) {
|
||||
|
||||
Reference in New Issue
Block a user