feat(core): add rewriteUnknownContent utility for cleaning JSON (#5915)
Some checks are pending
build / lint (20) (push) Waiting to run
build / test (20, map[name:Demos/Examples spec:./demos/src/Examples/**/*.spec.{js,ts}]) (push) Waiting to run
build / test (20, map[name:Demos/Experiments spec:./demos/src/Experiments/**/*.spec.{js,ts}]) (push) Waiting to run
build / test (20, map[name:Demos/Extensions spec:./demos/src/Extensions/**/*.spec.{js,ts}]) (push) Waiting to run
build / test (20, map[name:Demos/GuideContent spec:./demos/src/GuideContent/**/*.spec.{js,ts}]) (push) Waiting to run
build / test (20, map[name:Demos/GuideGettingStarted spec:./demos/src/GuideGettingStarted/**/*.spec.{js,ts}]) (push) Waiting to run
build / test (20, map[name:Demos/Marks spec:./demos/src/Marks/**/*.spec.{js,ts}]) (push) Waiting to run
build / test (20, map[name:Demos/Nodes spec:./demos/src/Nodes/**/*.spec.{js,ts}]) (push) Waiting to run
build / test (20, map[name:Integration spec:./tests/cypress/integration/**/*.spec.{js,ts}]) (push) Waiting to run
build / build (20) (push) Blocked by required conditions
Publish / Release (20) (push) Waiting to run

This commit is contained in:
Nick Perez 2024-12-30 13:24:24 +01:00 committed by GitHub
parent d1b7dd238d
commit 8c619c6f96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 154 additions and 0 deletions

View File

@ -0,0 +1,5 @@
---
"@tiptap/core": patch
---
Add `rewriteUnknownContent` helper, which can strip your editor JSON of content which is invalid within the current editor's schema

View File

@ -46,5 +46,6 @@ export * from './isNodeSelection.js'
export * from './isTextSelection.js'
export * from './posToDOMRect.js'
export * from './resolveFocusPosition.js'
export * from './rewriteUnknownContent.js'
export * from './selectionToInsertionEnd.js'
export * from './splitExtensions.js'

View File

@ -0,0 +1,148 @@
import type { Schema } from '@tiptap/pm/model'
import type { JSONContent } from '../types.js'
type RewriteUnknownContentOptions = {
/**
* If true, unknown nodes will be treated as paragraphs
* @default true
*/
fallbackToParagraph?: boolean;
};
type RewrittenContent = {
/**
* The original JSON content that was rewritten
*/
original: JSONContent;
/**
* The name of the node or mark that was unsupported
*/
unsupported: string;
}[];
/**
* The actual implementation of the rewriteUnknownContent function
*/
function rewriteUnknownContentInner({
json,
validMarks,
validNodes,
options,
rewrittenContent = [],
}: {
json: JSONContent;
validMarks: Set<string>;
validNodes: Set<string>;
options?: RewriteUnknownContentOptions;
rewrittenContent?: RewrittenContent;
}): {
/**
* The cleaned JSON content
*/
json: JSONContent | null;
/**
* The array of nodes and marks that were rewritten
*/
rewrittenContent: RewrittenContent;
} {
if (json.marks && Array.isArray(json.marks)) {
json.marks = json.marks.filter(mark => {
const name = typeof mark === 'string' ? mark : mark.type
if (validMarks.has(name)) {
return true
}
rewrittenContent.push({
original: JSON.parse(JSON.stringify(mark)),
unsupported: name,
})
// Just ignore any unknown marks
return false
})
}
if (json.content && Array.isArray(json.content)) {
json.content = json.content
.map(
value => rewriteUnknownContentInner({
json: value,
validMarks,
validNodes,
options,
rewrittenContent,
}).json,
)
.filter(a => a !== null && a !== undefined)
}
if (json.type && !validNodes.has(json.type)) {
rewrittenContent.push({
original: JSON.parse(JSON.stringify(json)),
unsupported: json.type,
})
if (json.content && Array.isArray(json.content) && (options?.fallbackToParagraph !== false)) {
// Just treat it like a paragraph and hope for the best
json.type = 'paragraph'
return {
json,
rewrittenContent,
}
}
// or just omit it entirely
return {
json: null,
rewrittenContent,
}
}
return { json, rewrittenContent }
}
/**
* Rewrite unknown nodes and marks within JSON content
* Allowing for user within the editor
*/
export function rewriteUnknownContent(
/**
* The JSON content to clean of unknown nodes and marks
*/
json: JSONContent,
/**
* The schema to use for validation
*/
schema: Schema,
/**
* Options for the cleaning process
*/
options?: RewriteUnknownContentOptions,
): {
/**
* The cleaned JSON content
*/
json: JSONContent | null;
/**
* The array of nodes and marks that were rewritten
*/
rewrittenContent: {
/**
* The original JSON content that was rewritten
*/
original: JSONContent;
/**
* The name of the node or mark that was unsupported
*/
unsupported: string;
}[];
} {
return rewriteUnknownContentInner({
json,
validNodes: new Set(Object.keys(schema.nodes)),
validMarks: new Set(Object.keys(schema.marks)),
options,
})
}