Added rendering of posts.lexical to posts.html when saving (#15416)

no issue

- added `@tryghost/kg-lexical-html-renderer` dependency
- added `lexical` lib following the same pattern as our `mobiledoc` lib
- updated the Post model's `onSaving` hook to generate the `html` value from `lexical` when present
This commit is contained in:
Kevin Ansfield 2022-09-15 16:49:14 +01:00 committed by GitHub
parent d330c91555
commit c240f7afa4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 383 additions and 108 deletions

View File

@ -0,0 +1,12 @@
let lexicalHtmlRenderer;
module.exports = {
get lexicalHtmlRenderer() {
if (!lexicalHtmlRenderer) {
const LexicalHtmlRenderer = require('@tryghost/kg-lexical-html-renderer');
lexicalHtmlRenderer = new LexicalHtmlRenderer();
}
return lexicalHtmlRenderer;
}
};

View File

@ -13,6 +13,7 @@ const config = require('../../shared/config');
const settingsCache = require('../../shared/settings-cache');
const limitService = require('../services/limits');
const mobiledocLib = require('../lib/mobiledoc');
const lexicalLib = require('../lib/lexical');
const relations = require('./relations');
const urlUtils = require('../../shared/url-utils');
const {Tag} = require('./tag');
@ -610,9 +611,12 @@ Post = ghostBookshelf.Model.extend({
// CASE: ?force_rerender=true passed via Admin API
// CASE: html is null, but mobiledoc exists (only important for migrations & importing)
if (
(this.hasChanged('mobiledoc') && !this.get('lexical'))
|| options.force_rerender
|| (!this.get('html') && (options.migrating || options.importing))
!this.get('lexical') &&
(
this.hasChanged('mobiledoc')
|| options.force_rerender
|| (!this.get('html') && (options.migrating || options.importing))
)
) {
try {
this.set('html', mobiledocLib.mobiledocHtmlRenderer.render(JSON.parse(this.get('mobiledoc'))));
@ -624,6 +628,28 @@ Post = ghostBookshelf.Model.extend({
}
}
// CASE: lexical has changed, generate html
// CASE: ?force_rerender=true passed via Admin API
// CASE: html is null, but lexical exists (only important for migrations & importing)
if (
!this.get('mobiledoc') &&
(
this.hasChanged('lexical')
|| options.force_rerender
|| (!this.get('html') && (options.migrating || options.importing))
)
) {
try {
this.set('html', lexicalLib.lexicalHtmlRenderer.render(this.get('lexical')));
} catch (err) {
throw new errors.ValidationError({
message: 'Invalid lexical structure.',
help: 'https://ghost.org/docs/publishing/',
property: 'lexical'
});
}
}
if (this.hasChanged('html') || !this.get('plaintext')) {
let plaintext;

View File

@ -79,6 +79,7 @@
"@tryghost/kg-card-factory": "3.1.5",
"@tryghost/kg-default-atoms": "3.1.4",
"@tryghost/kg-default-cards": "5.18.0",
"@tryghost/kg-lexical-html-renderer": "0.0.2",
"@tryghost/kg-mobiledoc-html-renderer": "5.3.7",
"@tryghost/limit-service": "1.2.3",
"@tryghost/link-redirects": "0.0.0",

View File

@ -296,14 +296,15 @@ Object {
"email_only": false,
"email_segment": "all",
"email_subject": null,
"excerpt": null,
"excerpt": "Testing post creation with lexical",
"feature_image": null,
"feature_image_alt": null,
"feature_image_caption": null,
"featured": false,
"frontmatter": null,
"html": "<p>Testing post creation with lexical</p>",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"lexical": "{\\"editorState\\":{\\"root\\":{\\"children\\":[{\\"children\\":[{\\"detail\\":0,\\"format\\":0,\\"mode\\":\\"normal\\",\\"style\\":\\"\\",\\"text\\":\\"Testing post creation with lexical\\",\\"type\\":\\"text\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"paragraph\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"root\\",\\"version\\":1}},\\"lastSaved\\":1663081361393,\\"source\\":\\"Playground\\",\\"version\\":\\"0.4.1\\"}",
"lexical": "{\\"root\\":{\\"children\\":[{\\"children\\":[{\\"detail\\":0,\\"format\\":0,\\"mode\\":\\"normal\\",\\"style\\":\\"\\",\\"text\\":\\"Testing post creation with lexical\\",\\"type\\":\\"text\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"paragraph\\",\\"version\\":1}],\\"direction\\":\\"ltr\\",\\"format\\":\\"\\",\\"indent\\":0,\\"type\\":\\"root\\",\\"version\\":1}}",
"meta_description": null,
"meta_title": null,
"mobiledoc": null,
@ -314,6 +315,7 @@ Object {
"primary_author": Any<Object>,
"primary_tag": Any<Object>,
"published_at": null,
"reading_time": 0,
"slug": "lexical-test",
"status": "draft",
"tags": Any<Array>,
@ -335,7 +337,7 @@ exports[`Posts API Create Can create a post with lexical 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "3737",
"content-length": "3743",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -370,6 +372,7 @@ Object {
"feature_image_caption": null,
"featured": false,
"frontmatter": null,
"html": "<p>Testing post creation with mobiledoc</p>",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"lexical": null,
"meta_description": null,
@ -382,6 +385,7 @@ Object {
"primary_author": Any<Object>,
"primary_tag": Any<Object>,
"published_at": null,
"reading_time": 0,
"slug": "mobiledoc-test",
"status": "draft",
"tags": Any<Array>,
@ -403,7 +407,7 @@ exports[`Posts API Create Can create a post with mobiledoc 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "3489",
"content-length": "3559",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/posts\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
@ -442,6 +446,36 @@ Object {
}
`;
exports[`Posts API Create Errors with an invalid lexical state object 1: [body] 1`] = `
Object {
"errors": Array [
Object {
"code": null,
"context": "Invalid lexical structure.",
"details": null,
"ghostErrorCode": null,
"help": "https://ghost.org/docs/publishing/",
"id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"message": "Validation error, cannot save post.",
"property": "lexical",
"type": "ValidationError",
},
],
}
`;
exports[`Posts API Create Errors with an invalid lexical state object 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "284",
"content-type": "application/json; charset=utf-8",
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Posts API Delete Can destroy a post 1: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",

View File

@ -133,42 +133,37 @@ describe('Pages API', function () {
const page = {
title: 'Lexical test',
lexical: JSON.stringify({
editorState: {
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Testing post creation with lexical',
type: 'text',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1
}
},
lastSaved: 1663081361393,
source: 'Playground',
version: '0.4.1'
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Testing page creation with lexical',
type: 'text',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1
}
})
};
const res = await request.post(localUtils.API.getApiQuery('pages/?formats=mobiledoc,lexical'))
const res = await request.post(localUtils.API.getApiQuery('pages/?formats=mobiledoc,lexical,html'))
.set('Origin', config.get('url'))
.send({pages: [page]})
.expect('Content-Type', /json/)
@ -178,11 +173,12 @@ describe('Pages API', function () {
res.body.pages.length.should.eql(1);
const [returnedPage] = res.body.pages;
const additionalProperties = ['lexical'];
const additionalProperties = ['lexical', 'html', 'reading_time'];
localUtils.API.checkResponse(returnedPage, 'page', additionalProperties);
should.equal(returnedPage.mobiledoc, null);
should.equal(returnedPage.lexical, page.lexical);
should.equal(returnedPage.html, '<p>Testing page creation with lexical</p>');
});
it('Can\'t add a page with both mobiledoc and lexical', async function () {

View File

@ -72,7 +72,7 @@ describe('Posts API', function () {
};
await agent
.post('/posts/?formats=mobiledoc,lexical')
.post('/posts/?formats=mobiledoc,lexical,html')
.body({posts: [post]})
.expectStatus(201)
.matchBodySnapshot({
@ -89,43 +89,38 @@ describe('Posts API', function () {
title: 'Lexical test',
mobiledoc: null,
lexical: JSON.stringify({
editorState: {
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Testing post creation with lexical',
type: 'text',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1
}
},
lastSaved: 1663081361393,
source: 'Playground',
version: '0.4.1'
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Testing post creation with lexical',
type: 'text',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1
}
})
};
await agent
.post('/posts/?formats=mobiledoc,lexical')
.post('/posts/?formats=mobiledoc,lexical,html')
.body({posts: [post]})
.expectStatus(201)
.matchBodySnapshot({
@ -153,38 +148,33 @@ describe('Posts API', function () {
]
}),
lexical: JSON.stringify({
editorState: {
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Testing post creation with lexical',
type: 'text',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1
}
},
lastSaved: 1663081361393,
source: 'Playground',
version: '0.4.1'
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Testing post creation with lexical',
type: 'text',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1
}
})
};
@ -201,6 +191,28 @@ describe('Posts API', function () {
etag: anyEtag
});
});
it('Errors with an invalid lexical state object', async function () {
const post = {
title: 'Invalid lexical state',
lexical: JSON.stringify({
notLexical: true
})
};
await agent
.post('/posts/?formats=mobiledoc,lexical,html')
.body({posts: [post]})
.expectStatus(422)
.matchBodySnapshot({
errors: [{
id: anyErrorId
}]
})
.matchHeaderSnapshot({
etag: anyEtag
});
});
});
describe('Delete', function () {

View File

@ -0,0 +1,13 @@
const should = require('should');
const lexicalLib = require('../../../../core/server/lib/lexical');
describe('lib/lexical', function () {
describe('lexicalHtmlRenderer', function () {
it('renders', function () {
const lexical = `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lexical is ","type":"text","version":1},{"detail":0,"format":3,"mode":"normal","style":"","text":"rendering.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`;
lexicalLib.lexicalHtmlRenderer.render(lexical)
.should.eql('<p>Lexical is <strong><em>rendering.</em></strong></p>');
});
});
});

183
yarn.lock
View File

@ -2777,6 +2777,163 @@
"@keyvhq/core" "^1.6.14"
mimic-fn "~3.0.0"
"@lexical/clipboard@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/clipboard/-/clipboard-0.4.1.tgz#67811f940756ba17b52538718db9650b44d433a9"
integrity sha512-/BHeh+LaYhNbBbzNcVPcYgSZtNp6HT5z/iHFKJMfhikE+4KKFf3DbLDO5b92AUDyT3s8QQC04Na5ZeRUbK/Jzw==
dependencies:
"@lexical/html" "0.4.1"
"@lexical/list" "0.4.1"
"@lexical/selection" "0.4.1"
"@lexical/utils" "0.4.1"
"@lexical/code@0.4.1", "@lexical/code@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/code/-/code-0.4.1.tgz#4ba0ec1a471ae4b7cf24ee1a8c87aeabcea01102"
integrity sha512-Bf6MiPrP7rrbYIXOOFKN/+HuZbdSWt0Dy/1gLJ3cLl4CTNiOUPJo2+iKvr3T0LCiSkQLHW+u4ygDs9G0eeDjdg==
dependencies:
"@lexical/utils" "0.4.1"
prismjs "^1.27.0"
"@lexical/dragon@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/dragon/-/dragon-0.4.1.tgz#47de7e45aa059f352dc2b8c1f56b8c385c7bd2ae"
integrity sha512-RDOrxiSQ8c7PQoEiopjxX0z0DudFle8Dn/0Ptb1f8xm8jZFG573NTw9oJPRDg3bhyKdt8Fh4EoPYf0AMdMDJKg==
"@lexical/hashtag@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/hashtag/-/hashtag-0.4.1.tgz#6538d4a1895d10dc252a87c67198a68e4640062e"
integrity sha512-qQQppeW91Kual4+m+KAAX4JgXwxIH9/LHuSpbycaQZiSd29R2PrCYyVx+gb+E3L1dum0r2Uddz2Wa/WLycLeDQ==
dependencies:
"@lexical/utils" "0.4.1"
"@lexical/headless@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/headless/-/headless-0.4.1.tgz#b8d1dc5476c7fcdae672140fe3bdc273c51e3112"
integrity sha512-1US/sub+8YQizmx1JE5U0TbrjmkvIjkNQK3rRzCdkRSuKjfxkvwfOg0R38yGXozMLVJTg6zvaDiNtdt3hXXHTA==
"@lexical/history@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/history/-/history-0.4.1.tgz#7b9991b16841ab082658a1abf898b5ac46b22148"
integrity sha512-n7KUYqCN0jj+NmMrT0bGjbSwn5x7EyDYhw9eghm69/fgHI/qHSJDQUQXa2ep4/0y4kPzYafVZSMrBDYXBxWqmw==
dependencies:
"@lexical/utils" "0.4.1"
"@lexical/html@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/html/-/html-0.4.1.tgz#a99b3b7c2b0ee4a555fe8478c6eef43754de35bb"
integrity sha512-nErgYUtghdrVTPZLB7Ad7U1m3SBxEZvPeW4FH4COFLCeTIVMEG4dg0PhURCk28xNAkEHszd4kQ3XFDRB5muOiQ==
dependencies:
"@lexical/selection" "0.4.1"
"@lexical/link@0.4.1", "@lexical/link@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/link/-/link-0.4.1.tgz#af3744942dd79bc6af34d9502fecd5cd4c635b3b"
integrity sha512-566lQymmuBe3Y7UDyaaTs+VDlElbu1WhnjT9lVDk0BXag7MA8tv/f60XptWnTK1pv/Dobm/CyLmyLae55OuflQ==
dependencies:
"@lexical/utils" "0.4.1"
"@lexical/list@0.4.1", "@lexical/list@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/list/-/list-0.4.1.tgz#5d764d7ed82cd3e710bc42619e1134e1968ec617"
integrity sha512-dP6i18qm1UhUoG6FvqLMn7hoj4htE0jYcmMPYqFyH+f1ir9Ybvr87pV3aFhqH6hdHjQ5tMyM0kURSL1t89GesQ==
dependencies:
"@lexical/utils" "0.4.1"
"@lexical/mark@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/mark/-/mark-0.4.1.tgz#fa20af940d16aabb076c66714e88fef5ca082c91"
integrity sha512-2aW26JvDYPZof8HyZ6WQjIbLSlYYncteJlTYyU5QnFubPjvUwxBps9X2lLf2lJm9CCVGT4T7gdBMkYBeckXSxQ==
dependencies:
"@lexical/utils" "0.4.1"
"@lexical/markdown@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/markdown/-/markdown-0.4.1.tgz#e0f28a585dec51ff51745e46b9d9db5ff49afc4c"
integrity sha512-MEGfQ31WDeb6xGn4zNqHVzG4YH0cpE4zGPHnzE6uNxNolb2md9inaKxziW5/ydpf+E/fur5XfLaDggiEi/ww4A==
dependencies:
"@lexical/code" "0.4.1"
"@lexical/link" "0.4.1"
"@lexical/list" "0.4.1"
"@lexical/rich-text" "0.4.1"
"@lexical/text" "0.4.1"
"@lexical/utils" "0.4.1"
"@lexical/offset@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/offset/-/offset-0.4.1.tgz#6a071a4cf6f6f6dcbafdb8b5b8ef133a82773304"
integrity sha512-MCFoWKsw12fcTuqxUBmC4PEip0ckv6KvrJGx4o6yI1gtkO47r3qb0YGaOShFivE/IQcbJOBXidXBjBk6jZRHEw==
"@lexical/overflow@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/overflow/-/overflow-0.4.1.tgz#38097eb02c4098a8e8b8d7df9bb50616432eb788"
integrity sha512-lOACcyDSIP/HF8ZEMJuz5bTG83WQJGHr+qYIi80giVw/tK8XkFMpCED5YhsOsvWsBqFTP9fxN8rpaF/N+rW4MQ==
"@lexical/plain-text@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/plain-text/-/plain-text-0.4.1.tgz#3b0598ba4f9d9ee5d5852cf0848f4f3f9cd87dbb"
integrity sha512-cNFLXhOfR0coUFGA6aPGcHr6a+Y9ZrkETMM78+XV9J8iVsKij4/katFhsqACQDna4vSfXuqjTitCRtiFaDevDg==
"@lexical/react@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/react/-/react-0.4.1.tgz#d7639c08b3b2c0e003cc1570aceadaa6ca78084d"
integrity sha512-kA9ivSjziYNZILQy8k+l/PmaoPJBkgOQFZ/NTdS5tyM8HVwj5GPwsRKkR+isy2X/C2om7vQ0xYKe+LLiEGzQfg==
dependencies:
"@lexical/clipboard" "0.4.1"
"@lexical/code" "0.4.1"
"@lexical/dragon" "0.4.1"
"@lexical/hashtag" "0.4.1"
"@lexical/history" "0.4.1"
"@lexical/link" "0.4.1"
"@lexical/list" "0.4.1"
"@lexical/mark" "0.4.1"
"@lexical/markdown" "0.4.1"
"@lexical/overflow" "0.4.1"
"@lexical/plain-text" "0.4.1"
"@lexical/rich-text" "0.4.1"
"@lexical/selection" "0.4.1"
"@lexical/table" "0.4.1"
"@lexical/text" "0.4.1"
"@lexical/utils" "0.4.1"
"@lexical/yjs" "0.4.1"
"@lexical/rich-text@0.4.1", "@lexical/rich-text@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/rich-text/-/rich-text-0.4.1.tgz#3a980917f994f31befa40bb50a4f6dd679fe0a36"
integrity sha512-EI4ul3y1hqMp0VS/4D8aOyR41ysz1KaYgkm6PyrRXEMyK8uKmVubJP83RkOU2fWkTVtdrMjM6aeT1qX849LetA==
"@lexical/selection@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/selection/-/selection-0.4.1.tgz#88c709a2b9813077dd91b89990646f1d9b80e16c"
integrity sha512-lrPaBtdWYp5FGpLA/mw8vVxQx8XM/GGVXFGam68B7mgMbY9xxKy3/MtvS94J+oRPtzNHEW3SyhkDEm9356r73g==
"@lexical/table@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/table/-/table-0.4.1.tgz#08545cdfde52a90a5dfd02a16cece699ccdaf6e2"
integrity sha512-1BRLB+cYpqXSk0IHk3uHI1Fa6H4rnQ5pySDm+7HSyShjAzQSMBt0BWoX9B0TW/vXysl3p5+vcnU8mGjGyCA0Lg==
dependencies:
"@lexical/utils" "0.4.1"
"@lexical/text@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/text/-/text-0.4.1.tgz#832ce70f26efc41fdc0041c0b732bb1c99c7d287"
integrity sha512-sfGESzElf8fYSi21+y/OCS00xbBsWUPoRLJ6D2EzvwRByqsPFYR5o9ouYMejQE/UFmkhgzX0Nv+VenFujkGk6Q==
"@lexical/utils@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/utils/-/utils-0.4.1.tgz#caf4cdbb5df0a785685cf7939c774bcb155f38c4"
integrity sha512-OUYS7qpu1oHv9vhUGhL60ow5gbyqLG449XGFZrzaKUGnz1iWU/rXP8nEljoqdtai3rg4t0Ahxcbe9cVIubK3hQ==
dependencies:
"@lexical/list" "0.4.1"
"@lexical/table" "0.4.1"
"@lexical/yjs@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@lexical/yjs/-/yjs-0.4.1.tgz#6db5fbf629518dc0ac6cecb08ccc83f6fc37325e"
integrity sha512-0VSq+rknDaixR7G3HMLYjAQk20EAsg7SaN0Qx/71+TxKKKniUgQSyAbmMw1ZLvW6Xlkqavj827dZCb/E3AbtEw==
dependencies:
"@lexical/offset" "0.4.1"
"@lint-todo/utils@^13.0.3":
version "13.0.3"
resolved "https://registry.yarnpkg.com/@lint-todo/utils/-/utils-13.0.3.tgz#ca222f38738b43eb43384d56e7292ba9cab3e891"
@ -3462,6 +3619,20 @@
lodash "^4.17.21"
luxon "^2.1.1"
"@tryghost/kg-lexical-html-renderer@0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@tryghost/kg-lexical-html-renderer/-/kg-lexical-html-renderer-0.0.2.tgz#4d36225afe75d570f87a0edc2affbc8959a992cc"
integrity sha512-YB6yMP9zZhIeKhKRZ5Rpc1K73w2ZxY8GzxfomWsM087ahdQijOUDGnGzzoKa9vmE452i7f2auNNOK8ryS6nxuw==
dependencies:
"@lexical/code" "^0.4.1"
"@lexical/headless" "^0.4.1"
"@lexical/link" "^0.4.1"
"@lexical/list" "^0.4.1"
"@lexical/react" "^0.4.1"
"@lexical/rich-text" "^0.4.1"
jsdom "^20.0.0"
lexical "^0.4.1"
"@tryghost/kg-markdown-html-renderer@^5.1.7":
version "5.1.7"
resolved "https://registry.yarnpkg.com/@tryghost/kg-markdown-html-renderer/-/kg-markdown-html-renderer-5.1.7.tgz#267654bf72767c0118d26c20f3567dbc7cd4a164"
@ -14693,7 +14864,7 @@ jsdom@^18.0.0:
ws "^8.2.3"
xml-name-validator "^4.0.0"
jsdom@~20.0.0:
jsdom@^20.0.0, jsdom@~20.0.0:
version "20.0.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.0.tgz#882825ac9cc5e5bbee704ba16143e1fa78361ebf"
integrity sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA==
@ -15148,6 +15319,11 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
lexical@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/lexical/-/lexical-0.4.1.tgz#6780f949f8478590b33cc6e8374368bbffbd6180"
integrity sha512-EXcLh/6LbEuwqXlnPkk8MXZXO16yBzznFqklKva91DF+KU8utX2PLoeRSOtWC8P2YbRdiGQewwKjUVeXqxxOaQ==
liftoff@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3"
@ -19062,6 +19238,11 @@ printf@^0.6.1:
resolved "https://registry.yarnpkg.com/printf/-/printf-0.6.1.tgz#b9afa3d3b55b7f2e8b1715272479fc756ed88650"
integrity sha512-is0ctgGdPJ5951KulgfzvHGwJtZ5ck8l042vRkV6jrkpBzTmb/lueTqguWHy2JfVA+RY6gFVlaZgUS0j7S/dsw==
prismjs@^1.27.0:
version "1.29.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
private@^0.1.6, private@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"