UNPKG

@lexical/markdown

Version:

This package contains Markdown helpers and functionality for Lexical.

10 lines (8 loc) 16.7 kB
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import{$isParagraphNode as t,$isTextNode as e,$getRoot as n,$isElementNode as o,$isDecoratorNode as r,$isLineBreakNode as i,$getSelection as s,$createTextNode as l,$createParagraphNode as c,$createLineBreakNode as f,createState as a,$setState as u,$getState as g,COLLABORATION_TAG as p,HISTORIC_TAG as d,$isRangeSelection as m,$isRootOrShadowRoot as h,$createRangeSelection as x,$setSelection as T}from"lexical";import{$isListNode as E,$isListItemNode as C,ListNode as y,ListItemNode as $,$createListItemNode as v,$createListNode as S}from"@lexical/list";import{$isQuoteNode as b,HeadingNode as F,QuoteNode as I,$createHeadingNode as w,$isHeadingNode as N,$createQuoteNode as k}from"@lexical/rich-text";import{$findMatchingParent as R}from"@lexical/utils";import{CodeNode as L,$createCodeNode as _,$isCodeNode as P}from"@lexical/code";import{LinkNode as B,$createLinkNode as M,$isLinkNode as j,$isAutoLinkNode as A}from"@lexical/link";function z(t,e){const n={};for(const o of t){const t=e(o);t&&(n[t]?n[t].push(o):n[t]=[o])}return n}function U(t){const e=z(t,t=>t.type);return{element:e.element||[],multilineElement:e["multiline-element"]||[],textFormat:e["text-format"]||[],textMatch:e["text-match"]||[]}}const W=/[!-/:-@[-`{-~\s]/,D=/^\s{0,3}$/;function O(n){if(!t(n))return!1;const o=n.getFirstChild();return null==o||1===n.getChildrenSize()&&e(o)&&D.test(o.getTextContent())}function q(t,e,n,i){for(const o of e){if(!o.export)continue;const e=o.export(t,t=>G(t,n,i));if(null!=e)return e}return o(t)?G(t,n,i):r(t)?t.getTextContent():null}function G(t,n,s,l,c){const f=[],a=t.getChildren();l||(l=[]),c||(c=[]);t:for(const t of a){for(const e of s){if(!e.export)continue;const o=e.export(t,t=>G(t,n,s,l,[...c,...l]),(t,e)=>H(t,e,n,l,c));if(null!=o){f.push(o);continue t}}i(t)?f.push("\n"):e(t)?f.push(H(t,t.getTextContent(),n,l,c)):o(t)?f.push(G(t,n,s,l,c)):r(t)&&f.push(t.getTextContent())}return f.join("")}function H(t,e,n,o,r){let i=0===t.getFormat()?e:function(t){return t.replace(/^\s+|\s+$/g,t=>[...t].map(t=>"&#"+t.codePointAt(0)+";").join(""))}(e);t.hasFormat("code")||(i=i.replace(/([*_`~\\])/g,"\\$1"));let s="",l="",c="";const f=J(t,!0),a=J(t,!1),u=new Set;for(const e of n){const n=e.format[0],r=e.tag;K(t,n)&&!u.has(n)&&(u.add(n),K(f,n)&&o.find(t=>t.tag===r)||(o.push({format:n,tag:r}),s+=r))}for(let e=0;e<o.length;e++){const n=K(t,o[e].format),i=K(a,o[e].format);if(n&&i)continue;const s=[...o];for(;s.length>e;){const t=s.pop();r&&t&&r.find(e=>e.tag===t.tag)||(t&&"string"==typeof t.tag&&(n?i||(c+=t.tag):l+=t.tag),o.pop())}break}return i=s+i+c,l+i}function J(t,n){let r=n?t.getPreviousSibling():t.getNextSibling();if(!r){const e=t.getParentOrThrow();e.isInline()&&(r=n?e.getPreviousSibling():e.getNextSibling())}for(;r;){if(o(r)){if(!r.isInline())break;const t=n?r.getLastDescendant():r.getFirstDescendant();if(e(t))return t;r=n?r.getPreviousSibling():r.getNextSibling()}if(e(r))return r;if(!o(r))return null}return null}function K(t,n){return e(t)&&t.hasFormat(n)}function Q(t,e){const n=function(t,e){const n=t.match(e.openTagsRegExp);if(null==n)return null;for(const o of n){const n=o.replace(/^\s/,""),r=e.fullMatchRegExpByTag[n];if(null==r)continue;const i=t.match(r),s=e.transformersByTag[n];if(null!=i&&null!=s){if(!1!==s.intraword)return i;const{index:e=0}=i,n=t[e-1],o=t[e+i[0].length];if((!n||W.test(n))&&(!o||W.test(o)))return i}}return null}(t.getTextContent(),e);if(!n)return null;const o=n.index||0;return{endIndex:o+n[0].length,match:n,startIndex:o,transformer:e.transformersByTag[n[1]]}}function V(t){return e(t)&&!t.hasFormat("code")}function X(t,e,n){let o=Q(t,e),r=function(t,e){const n=t;let o,r,i,s;for(const t of e){if(!t.replace||!t.importRegExp)continue;const e=n.getTextContent().match(t.importRegExp);if(!e)continue;const l=e.index||0,c=t.getEndIndex?t.getEndIndex(n,e):l+e[0].length;!1!==c&&(void 0===o||void 0===r||l<o&&(c>r||c<=o))&&(o=l,r=c,i=t,s=e)}return void 0===o||void 0===r||void 0===i||void 0===s?null:{endIndex:r,match:s,startIndex:o,transformer:i}}(t,n);if(o&&r&&(o.startIndex<=r.startIndex&&o.endIndex>=r.endIndex||r.startIndex>o.endIndex?r=null:o=null),o){const r=function(t,e,n,o,r){const i=t.getTextContent();let s,l,c;if(r[0]===i?s=t:0===e?[s,l]=t.splitText(n):[c,s,l]=t.splitText(e,n),s.setTextContent(r[2]),o)for(const t of o.format)s.hasFormat(t)||s.toggleFormat(t);return{nodeAfter:l,nodeBefore:c,transformedNode:s}}(t,o.startIndex,o.endIndex,o.transformer,o.match);V(r.nodeAfter)&&X(r.nodeAfter,e,n),V(r.nodeBefore)&&X(r.nodeBefore,e,n),V(r.transformedNode)&&X(r.transformedNode,e,n)}else if(r){const o=function(t,e,n,o,r){let i,s,l;return 0===e?[i,s]=t.splitText(n):[l,i,s]=t.splitText(e,n),o.replace?{nodeAfter:s,nodeBefore:l,transformedNode:o.replace(i,r)||void 0}:null}(t,r.startIndex,r.endIndex,r.transformer,r.match);if(!o)return;V(o.nodeAfter)&&X(o.nodeAfter,e,n),V(o.nodeBefore)&&X(o.nodeBefore,e,n),V(o.transformedNode)&&X(o.transformedNode,e,n)}const i=t.getTextContent().replace(/\\([*_`~\\])/g,"$1").replace(/&#(\d+);/g,(t,e)=>String.fromCodePoint(e));t.setTextContent(i)}function Y(t,e=!1){const o=U(t),r=function(t){const e={},n={},o=[],r="(?<![\\\\])";for(const r of t){const{tag:t}=r;e[t]=r;const i=t.replace(/(\*|\^|\+)/g,"\\$1");o.push(i),1===t.length?n[t]="`"===t?new RegExp("(?<![\\\\`])(`)((?:\\\\`|[^`])+?)(`)(?!`)"):new RegExp(`(?<![\\\\${i}])(${i})((\\\\${i})?.*?[^${i}\\s](\\\\${i})?)((?<!\\\\)|(?<=\\\\\\\\))(${i})(?![\\\\${i}])`):n[t]=new RegExp(`(?<!\\\\)(${i})((\\\\${i})?.*?[^\\s](\\\\${i})?)((?<!\\\\)|(?<=\\\\\\\\))(${i})(?!\\\\)`)}return{fullMatchRegExpByTag:n,openTagsRegExp:new RegExp(`${r}(${o.join("|")})`,"g"),transformersByTag:e}}(o.textFormat);return(t,i)=>{const l=t.split("\n"),c=l.length,f=i||n();f.clear();for(let t=0;t<c;t++){const n=l[t],[i,s]=Z(l,t,o.multilineElement,f);i?t=s:tt(n,f,o.element,r,o.textMatch,e)}const a=f.getChildren();for(const t of a)!e&&O(t)&&f.getChildrenSize()>1&&t.remove();null!==s()&&f.selectStart()}}function Z(t,e,n,o){for(const r of n){const{handleImportAfterStartMatch:n,regExpEnd:i,regExpStart:s,replace:l}=r,c=t[e].match(s);if(!c)continue;if(n){const i=n({lines:t,rootNode:o,startLineIndex:e,startMatch:c,transformer:r});if(null===i)continue;if(i)return i}const f="object"==typeof i&&"regExp"in i?i.regExp:i,a=i&&"object"==typeof i&&"optional"in i?i.optional:!i;let u=e;const g=t.length;for(;u<g;){const n=f?t[u].match(f):null;if(!n&&(!a||a&&u<g-1)){u++;continue}if(n&&e===u&&n.index===c.index){u++;continue}const r=[];if(n&&e===u)r.push(t[e].slice(c[0].length,-n[0].length));else for(let o=e;o<=u;o++)if(o===e){const e=t[o].slice(c[0].length);r.push(e)}else if(o===u&&n){const e=t[o].slice(0,-n[0].length);r.push(e)}else r.push(t[o]);if(!1!==l(o,null,c,n,r,!0))return[!0,u];break}}return[!1,e]}function tt(e,n,o,r,i,s){const a=l(e),u=c();u.append(a),n.append(u);for(const{regExp:t,replace:n}of o){const o=e.match(t);if(o&&(a.setTextContent(e.slice(o[0].length)),!1!==n(u,[a],o,!0)))break}if(X(a,r,i),u.isAttached()&&e.length>0){const e=u.getPreviousSibling();if(!s&&(t(e)||b(e)||E(e))){let t=e;if(E(e)){const n=e.getLastDescendant();t=null==n?null:R(n,C)}null!=t&&t.getTextContentSize()>0&&(t.splice(t.getChildrenSize(),0,[f(),...u.getChildren()]),u.remove())}}}function et(t,...e){const n=new URL("https://lexical.dev/docs/error"),o=new URLSearchParams;o.append("code",t);for(const t of e)o.append("v",t);throw n.search=o.toString(),Error(`Minified Lexical error #${t}; visit ${n.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}const nt=/^(\s*)(\d{1,})\.\s/,ot=/^(\s*)[-*+]\s/,rt=/^(\s*)(?:[-*+]\s)?\s?(\[(\s|x)?\])\s/i,it=/^(#{1,6})\s/,st=/^>\s/,lt=/^[ \t]*```([\w-]+)?/,ct=/[ \t]*```$/,ft=/^[ \t]*```[^`]+(?:(?:`{1,2}|`{4,})[^`]+)*```(?:[^`]|$)/,at=/^(?:\|)(.+)(?:\|)\s?$/,ut=/^(\| ?:?-*:? ?)+\|\s?$/,gt=/^<[a-z_][\w-]*(?:\s[^<>]*)?\/?>/i,pt=/^<\/[a-z_][\w-]*\s*>/i,dt=t=>new RegExp(`(?:${t.source})$`,t.flags),mt=a("mdListMarker",{parse:t=>"string"==typeof t&&/^[-*+]$/.test(t)?t:"-"}),ht=t=>(e,n,o,r)=>{const i=t(o);i.append(...n),e.replace(i),r||i.select(0,0)};const xt=t=>(e,n,o,r)=>{const i=e.getPreviousSibling(),s=e.getNextSibling(),l=v("check"===t?"x"===o[3]:void 0),c=o[0].trim()[0],f="bullet"!==t&&"check"!==t||c!==mt.parse(c)?void 0:c;if(E(s)&&s.getListType()===t){f&&u(s,mt,f);const t=s.getFirstChild();null!==t?t.insertBefore(l):s.append(l),e.remove()}else if(E(i)&&i.getListType()===t)f&&u(i,mt,f),i.append(l),e.remove();else{const n=S(t,"number"===t?Number(o[2]):void 0);f&&u(n,mt,f),n.append(l),e.replace(n)}l.append(...n),r||l.select(0,0);const a=function(t){const e=t.match(/\t/g),n=t.match(/ /g);let o=0;return e&&(o+=e.length),n&&(o+=Math.floor(n.length/4)),o}(o[1]);a&&l.setIndent(a)},Tt=(t,e,n)=>{const o=[],r=t.getChildren();let i=0;for(const s of r)if(C(s)){if(1===s.getChildrenSize()){const t=s.getFirstChild();if(E(t)){o.push(Tt(t,e,n+1));continue}}const r=" ".repeat(4*n),l=t.getListType(),c=g(t,mt),f="number"===l?`${t.getStart()+i}. `:"check"===l?`${c} [${s.getChecked()?"x":" "}] `:c+" ";o.push(r+f+e(s)),i++}return o.join("\n")},Et={dependencies:[F],export:(t,e)=>{if(!N(t))return null;const n=Number(t.getTag().slice(1));return"#".repeat(n)+" "+e(t)},regExp:it,replace:ht(t=>{const e="h"+t[1].length;return w(e)}),type:"element"},Ct={dependencies:[I],export:(t,e)=>{if(!b(t))return null;const n=e(t).split("\n"),o=[];for(const t of n)o.push("> "+t);return o.join("\n")},regExp:st,replace:(t,e,n,o)=>{if(o){const n=t.getPreviousSibling();if(b(n))return n.splice(n.getChildrenSize(),0,[f(),...e]),void t.remove()}const r=k();r.append(...e),t.replace(r),o||r.select(0,0)},type:"element"},yt={dependencies:[L],export:t=>{if(!P(t))return null;const e=t.getTextContent();return"```"+(t.getLanguage()||"")+(e?"\n"+e:"")+"\n```"},regExpEnd:{optional:!0,regExp:ct},regExpStart:lt,replace:(t,e,n,o,r,i)=>{let s,c;if(!e&&r){if(1===r.length)o?(s=_(),c=n[1]+r[0]):(s=_(n[1]),c=r[0].startsWith(" ")?r[0].slice(1):r[0]);else{if(s=_(n[1]),0===r[0].trim().length)for(;r.length>0&&!r[0].length;)r.shift();else r[0]=r[0].startsWith(" ")?r[0].slice(1):r[0];for(;r.length>0&&!r[r.length-1].length;)r.pop();c=r.join("\n")}const e=l(c);s.append(e),t.append(s)}else e&&ht(t=>_(t?t[1]:void 0))(t,e,n,i)},type:"multiline-element"},$t={dependencies:[y,$],export:(t,e)=>E(t)?Tt(t,e,0):null,regExp:ot,replace:xt("bullet"),type:"element"},vt={dependencies:[y,$],export:(t,e)=>E(t)?Tt(t,e,0):null,regExp:rt,replace:xt("check"),type:"element"},St={dependencies:[y,$],export:(t,e)=>E(t)?Tt(t,e,0):null,regExp:nt,replace:xt("number"),type:"element"},bt={format:["code"],tag:"`",type:"text-format"},Ft={format:["highlight"],tag:"==",type:"text-format"},It={format:["bold","italic"],tag:"***",type:"text-format"},wt={format:["bold","italic"],intraword:!1,tag:"___",type:"text-format"},Nt={format:["bold"],tag:"**",type:"text-format"},kt={format:["bold"],intraword:!1,tag:"__",type:"text-format"},Rt={format:["strikethrough"],tag:"~~",type:"text-format"},Lt={format:["italic"],tag:"*",type:"text-format"},_t={format:["italic"],intraword:!1,tag:"_",type:"text-format"},Pt={dependencies:[B],export:(t,e,n)=>{if(!j(t)||A(t))return null;const o=t.getTitle(),r=e(t);return o?`[${r}](${t.getURL()} "${o}")`:`[${r}](${t.getURL()})`},importRegExp:/(?:\[(.+?)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))/,regExp:/(?:\[(.+?)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/,replace:(t,e)=>{const[,n,o,r]=e,i=M(o,{title:r}),s=n.split("[").length-1,c=n.split("]").length-1;let f=n,a="";if(s<c)return;if(s>c){const t=n.split("[");a="["+t[0],f=t.slice(1).join("[")}const u=l(f);return u.setFormat(t.getFormat()),i.append(u),t.replace(i),a&&i.insertBefore(l(a)),u},trigger:")",type:"text-match"},Bt=[Et,Ct,$t,St],Mt=[yt],jt=[bt,It,wt,Nt,kt,Ft,Lt,_t,Rt],At=[Pt],zt=[...Bt,...Mt,...jt,...At];function Ut(t,e,n){const o=n.length;for(let r=e;r>=o;r--){const e=r-o;if(Wt(t,e,n,0,o)&&" "!==t[e+o])return e}return-1}function Wt(t,e,n,o,r){for(let i=0;i<r;i++)if(t[e+i]!==n[o+i])return!1;return!0}function Dt(t,n=zt){const o=U(n),r=z(o.textFormat,({tag:t})=>t[t.length-1]),l=z(o.textMatch,({trigger:t})=>t);for(const e of n){const n=e.type;if("element"===n||"text-match"===n||"multiline-element"===n){const n=e.dependencies;for(const e of n)t.hasNode(e)||et(173,e.getType())}}const c=(t,n,c)=>{(function(t,e,n,o){const r=t.getParent();if(!h(r)||t.getFirstChild()!==e)return!1;const i=e.getTextContent();if(" "!==i[n-1])return!1;for(const{regExp:r,replace:s}of o){const o=i.match(r);if(o&&o[0].length===(o[0].endsWith(" ")?n:n-1)){const r=e.getNextSiblings(),[i,l]=e.splitText(n);if(!1!==s(t,l?[l,...r]:r,o,!1))return i.remove(),!0}}return!1})(t,n,c,o.element)||function(t,e,n,o){const r=t.getParent();if(!h(r)||t.getFirstChild()!==e)return!1;const i=e.getTextContent();if(" "!==i[n-1])return!1;for(const{regExpStart:r,replace:s,regExpEnd:l}of o){if(l&&!("optional"in l)||l&&"optional"in l&&!l.optional)continue;const o=i.match(r);if(o&&o[0].length===(o[0].endsWith(" ")?n:n-1)){const r=e.getNextSiblings(),[i,l]=e.splitText(n);if(!1!==s(t,l?[l,...r]:r,o,null,null,!1))return i.remove(),!0}}return!1}(t,n,c,o.multilineElement)||function(t,e,n){let o=t.getTextContent();const r=n[o[e-1]];if(null==r)return!1;e<o.length&&(o=o.slice(0,e));for(const e of r){if(!e.replace||!e.regExp)continue;const n=o.match(e.regExp);if(null===n)continue;const r=n.index||0,i=r+n[0].length;let s;return 0===r?[s]=t.splitText(i):[,s]=t.splitText(r,i),s.selectNext(0,0),e.replace(s,n),!0}return!1}(n,c,l)||function(t,n,o){const r=t.getTextContent(),l=n-1,c=r[l],f=o[c];if(!f)return!1;for(const n of f){const{tag:o}=n,f=o.length,a=l-f+1;if(f>1&&!Wt(r,a,o,0,f))continue;if(" "===r[a-1])continue;const u=r[l+1];if(!1===n.intraword&&u&&!W.test(u))continue;const g=t;let p=g,d=Ut(r,a,o),h=p;for(;d<0&&(h=h.getPreviousSibling())&&!i(h);)if(e(h)){if(h.hasFormat("code"))continue;const t=h.getTextContent();p=h,d=Ut(t,t.length,o)}if(d<0)continue;if(p===g&&d+f===a)continue;const E=p.getTextContent();if(d>0&&E[d-1]===c)continue;const C=E[d-1];if(!1===n.intraword&&C&&!W.test(C))continue;const y=g.getTextContent(),$=y.slice(0,a)+y.slice(l+1);g.setTextContent($);const v=p===g?$:E;p.setTextContent(v.slice(0,d)+v.slice(d+f));const S=s(),b=x();T(b);const F=l-f*(p===g?2:1)+1;b.anchor.set(p.__key,d,"text"),b.focus.set(g.__key,F,"text");for(const t of n.format)b.hasFormat(t)||b.formatText(t);b.anchor.set(b.focus.key,b.focus.offset,b.focus.type);for(const t of n.format)b.hasFormat(t)&&b.toggleFormat(t);return m(S)&&(b.format=S.format),!0}}(n,c,r)};return t.registerUpdateListener(({tags:n,dirtyLeaves:o,editorState:r,prevEditorState:i})=>{if(n.has(p)||n.has(d))return;if(t.isComposing())return;const l=r.read(s),f=i.read(s);if(!m(f)||!m(l)||!l.isCollapsed()||l.is(f))return;const a=l.anchor.key,u=l.anchor.offset,g=r._nodeMap.get(a);!e(g)||!o.has(a)||1!==u&&u>f.anchor.offset+1||t.update(()=>{if(!V(g))return;const t=g.getParent();null===t||P(t)||c(t,g,l.anchor.offset)})})}function Ot(t,e=zt,n,o=!1,r=!1){const i=o?t:function(t,e=!1){const n=t.split("\n");let o=!1;const r=[];for(let t=0;t<n.length;t++){const i=n[t].trimEnd(),s=r[r.length-1];ft.test(i)?r.push(i):lt.test(i)||ct.test(i)?(o=!o,r.push(i)):o||""===i||""===s||!s||it.test(s)||it.test(i)||st.test(i)||nt.test(i)||ot.test(i)||rt.test(i)||at.test(i)||ut.test(i)||!e||gt.test(i)||pt.test(i)||dt(pt).test(s)||dt(gt).test(s)||ct.test(s)?r.push(i):r[r.length-1]=s+" "+i.trimStart()}return r.join("\n")}(t,r);return Y(e,o)(i,n)}function qt(t=zt,e,o=!1){const r=function(t,e=!1){const o=U(t),r=[...o.multilineElement,...o.element],i=!e,s=o.textFormat.filter(t=>1===t.format.length).sort((t,e)=>Number(t.format.includes("code"))-Number(e.format.includes("code")));return t=>{const e=[],l=(t||n()).getChildren();for(let t=0;t<l.length;t++){const n=l[t],c=q(n,r,s,o.textMatch);null!=c&&e.push(i&&t>0&&!O(n)&&!O(l[t-1])?"\n".concat(c):c)}return e.join("\n")}}(t,o);return r(e)}export{Ot as $convertFromMarkdownString,qt as $convertToMarkdownString,It as BOLD_ITALIC_STAR,wt as BOLD_ITALIC_UNDERSCORE,Nt as BOLD_STAR,kt as BOLD_UNDERSCORE,vt as CHECK_LIST,yt as CODE,Bt as ELEMENT_TRANSFORMERS,Et as HEADING,Ft as HIGHLIGHT,bt as INLINE_CODE,Lt as ITALIC_STAR,_t as ITALIC_UNDERSCORE,Pt as LINK,Mt as MULTILINE_ELEMENT_TRANSFORMERS,St as ORDERED_LIST,Ct as QUOTE,Rt as STRIKETHROUGH,jt as TEXT_FORMAT_TRANSFORMERS,At as TEXT_MATCH_TRANSFORMERS,zt as TRANSFORMERS,$t as UNORDERED_LIST,Dt as registerMarkdownShortcuts};