mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-14 22:32:24 +08:00
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
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:
parent
d1b7dd238d
commit
8c619c6f96
5
.changeset/violet-foxes-fetch.md
Normal file
5
.changeset/violet-foxes-fetch.md
Normal 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
|
@ -46,5 +46,6 @@ export * from './isNodeSelection.js'
|
|||||||
export * from './isTextSelection.js'
|
export * from './isTextSelection.js'
|
||||||
export * from './posToDOMRect.js'
|
export * from './posToDOMRect.js'
|
||||||
export * from './resolveFocusPosition.js'
|
export * from './resolveFocusPosition.js'
|
||||||
|
export * from './rewriteUnknownContent.js'
|
||||||
export * from './selectionToInsertionEnd.js'
|
export * from './selectionToInsertionEnd.js'
|
||||||
export * from './splitExtensions.js'
|
export * from './splitExtensions.js'
|
||||||
|
148
packages/core/src/helpers/rewriteUnknownContent.ts
Normal file
148
packages/core/src/helpers/rewriteUnknownContent.ts
Normal 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,
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user