@lexical/code
Version:
This package contains the functionality for the code blocks and code highlighting for Lexical.
10 lines (8 loc) • 15.2 kB
JavaScript
/**
* 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{isHTMLElement as t,addClassNamesToElement as e,removeClassNamesFromElement as n,$getAdjacentCaret as r,mergeRegister as o}from"@lexical/utils";import{ElementNode as i,$createParagraphNode as s,$isTextNode as l,$isTabNode as u,$createTabNode as c,$createLineBreakNode as a,$applyNodeReplacement as g,TextNode as p,$getSiblingCaret as f,$isLineBreakNode as h,$createTextNode as d,$getNodeByKey as m,$getSelection as x,$isRangeSelection as y,$createPoint as S,INDENT_CONTENT_COMMAND as _,OUTDENT_CONTENT_COMMAND as v,INSERT_TAB_COMMAND as T,$setSelectionFromCaretRange as C,$getCaretRangeInDirection as N,$getCaretRange as j,$getTextPointCaret as b,$normalizeCaret as w,KEY_ARROW_UP_COMMAND as P,MOVE_TO_START as k,KEY_TAB_COMMAND as O,COMMAND_PRIORITY_LOW as L,$insertNodes as A,KEY_ARROW_DOWN_COMMAND as H,MOVE_TO_END as B}from"lexical";import"prismjs";import"prismjs/components/prism-clike.js";import"prismjs/components/prism-javascript.js";import"prismjs/components/prism-markup.js";import"prismjs/components/prism-markdown.js";import"prismjs/components/prism-c.js";import"prismjs/components/prism-css.js";import"prismjs/components/prism-objectivec.js";import"prismjs/components/prism-sql.js";import"prismjs/components/prism-powershell.js";import"prismjs/components/prism-python.js";import"prismjs/components/prism-rust.js";import"prismjs/components/prism-swift.js";import"prismjs/components/prism-typescript.js";import"prismjs/components/prism-java.js";import"prismjs/components/prism-cpp.js";function D(t,...e){const n=new URL("https://lexical.dev/docs/error"),r=new URLSearchParams;r.append("code",t);for(const t of e)r.append("v",t);throw n.search=r.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 M=globalThis.Prism||window.Prism,z=t=>{try{return!!t&&M.languages.hasOwnProperty(t)}catch(t){return!1}};function J(e,n){for(const r of e.childNodes){if(t(r)&&r.tagName===n)return!0;J(r,n)}return!1}const E="data-language",F="data-highlight-language";class K extends i{static getType(){return"code"}static clone(t){return new K(t.__language,t.__key)}constructor(t,e){super(e),this.__language=t||void 0,this.__isSyntaxHighlightSupported=z(t)}createDOM(t){const n=document.createElement("code");e(n,t.theme.code),n.setAttribute("spellcheck","false");const r=this.getLanguage();return r&&(n.setAttribute(E,r),this.getIsSyntaxHighlightSupported()&&n.setAttribute(F,r)),n}updateDOM(t,e,n){const r=this.__language,o=t.__language;return r?r!==o&&(e.setAttribute(E,r),this.__isSyntaxHighlightSupported&&e.setAttribute(F,r)):o&&(e.removeAttribute(E),t.__isSyntaxHighlightSupported&&e.removeAttribute(F)),!1}exportDOM(t){const n=document.createElement("pre");e(n,t._config.theme.code),n.setAttribute("spellcheck","false");const r=this.getLanguage();return r&&(n.setAttribute(E,r),this.getIsSyntaxHighlightSupported()&&n.setAttribute(F,r)),{element:n}}static importDOM(){return{code:t=>null!=t.textContent&&(/\r?\n/.test(t.textContent)||J(t,"BR"))?{conversion:q,priority:1}:null,div:()=>({conversion:U,priority:1}),pre:()=>({conversion:q,priority:0}),table:t=>X(t)?{conversion:W,priority:3}:null,td:t=>{const e=t,n=e.closest("table");return e.classList.contains("js-file-line")||n&&X(n)?{conversion:$,priority:3}:null},tr:t=>{const e=t.closest("table");return e&&X(e)?{conversion:$,priority:3}:null}}}static importJSON(t){return R().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setLanguage(t.language)}exportJSON(){return{...super.exportJSON(),language:this.getLanguage()}}insertNewAfter(t,e=!0){const n=this.getChildren(),r=n.length;if(r>=2&&"\n"===n[r-1].getTextContent()&&"\n"===n[r-2].getTextContent()&&t.isCollapsed()&&t.anchor.key===this.__key&&t.anchor.offset===r){n[r-1].remove(),n[r-2].remove();const t=s();return this.insertAfter(t,e),t}const{anchor:o,focus:i}=t,g=(o.isBefore(i)?o:i).getNode();if(l(g)){let t=ut(g);const e=[];for(;;)if(u(t))e.push(c()),t=t.getNextSibling();else{if(!st(t))break;{let n=0;const r=t.getTextContent(),o=t.getTextContentSize();for(;n<o&&" "===r[n];)n++;if(0!==n&&e.push(it(" ".repeat(n))),n!==o)break;t=t.getNextSibling()}}const n=g.splitText(o.offset)[0],r=0===o.offset?0:1,i=n.getIndexWithinParent()+r,s=g.getParentOrThrow(),l=[a(),...e];s.splice(i,0,l);const p=e[e.length-1];p?p.select():0===o.offset?n.selectPrevious():n.getNextSibling().selectNext(0,0)}if(I(g)){const{offset:e}=t.anchor;g.splice(e,0,[a()]),g.select(e+1,e+1)}return null}canIndent(){return!1}collapseAtStart(){const t=s();return this.getChildren().forEach((e=>t.append(e))),this.replace(t),!0}setLanguage(t){const e=this.getWritable();return e.__language=t||void 0,e.__isSyntaxHighlightSupported=z(t),e}getLanguage(){return this.getLatest().__language}getIsSyntaxHighlightSupported(){return this.getLatest().__isSyntaxHighlightSupported}}function R(t){return g(new K(t))}function I(t){return t instanceof K}function q(t){return{node:R(t.getAttribute(E))}}function U(t){const e=t,n=Q(e);return n||function(t){let e=t.parentElement;for(;null!==e;){if(Q(e))return!0;e=e.parentElement}return!1}(e)?{node:n?R():null}:{node:null}}function W(){return{node:R()}}function $(){return{node:null}}function Q(t){return null!==t.style.fontFamily.match("monospace")}function X(t){return t.classList.contains("js-file-line-container")}const G="javascript",V={c:"C",clike:"C-like",cpp:"C++",css:"CSS",html:"HTML",java:"Java",js:"JavaScript",markdown:"Markdown",objc:"Objective-C",plain:"Plain Text",powershell:"PowerShell",py:"Python",rust:"Rust",sql:"SQL",swift:"Swift",typescript:"TypeScript",xml:"XML"},Y={cpp:"cpp",java:"java",javascript:"js",md:"markdown",plaintext:"plain",python:"py",text:"plain",ts:"typescript"};function Z(t){return Y[t]||t}function tt(t){const e=Z(t);return V[e]||e}const et=()=>G,nt=()=>Object.keys(M.languages).filter((t=>"function"!=typeof M.languages[t])).sort();class rt extends p{constructor(t="",e,n){super(t,n),this.__highlightType=e}static getType(){return"code-highlight"}static clone(t){return new rt(t.__text,t.__highlightType||void 0,t.__key)}getHighlightType(){return this.getLatest().__highlightType}setHighlightType(t){const e=this.getWritable();return e.__highlightType=t||void 0,e}canHaveFormat(){return!1}createDOM(t){const n=super.createDOM(t),r=ot(t.theme,this.__highlightType);return e(n,r),n}updateDOM(t,r,o){const i=super.updateDOM(t,r,o),s=ot(o.theme,t.__highlightType),l=ot(o.theme,this.__highlightType);return s!==l&&(s&&n(r,s),l&&e(r,l)),i}static importJSON(t){return it().updateFromJSON(t)}updateFromJSON(t){return super.updateFromJSON(t).setHighlightType(t.highlightType)}exportJSON(){return{...super.exportJSON(),highlightType:this.getHighlightType()}}setFormat(t){return this}isParentRequired(){return!0}createParentElementNode(){return R()}}function ot(t,e){return e&&t&&t.codeHighlight&&t.codeHighlight[e]}function it(t="",e){return g(new rt(t,e))}function st(t){return t instanceof rt}function lt(t,e){let n=t;for(let o=f(t,e);o&&(st(o.origin)||u(o.origin));o=r(o))n=o.origin;return n}function ut(t){return lt(t,"previous")}function ct(t){return lt(t,"next")}const at={defaultLanguage:G,tokenize(t,e){return M.tokenize(t,M.languages[e||""]||M.languages[this.defaultLanguage])}};function gt(t,e){let n=null,r=null,o=t,i=e,s=t.getTextContent();for(;;){if(0===i){if(o=o.getPreviousSibling(),null===o)break;if(st(o)||u(o)||h(o)||D(167),h(o)){n={node:o,offset:1};break}i=Math.max(0,o.getTextContentSize()-1),s=o.getTextContent()}else i--;const t=s[i];st(o)&&" "!==t&&(r={node:o,offset:i})}if(null!==r)return r;let l=null;if(e<t.getTextContentSize())st(t)&&(l=t.getTextContent()[e]);else{const e=t.getNextSibling();st(e)&&(l=e.getTextContent()[0])}if(null!==l&&" "!==l)return n;{const r=function(t,e){let n=t,r=e,o=t.getTextContent(),i=t.getTextContentSize();for(;;){if(!st(n)||r===i){if(n=n.getNextSibling(),null===n||h(n))return null;st(n)&&(r=0,o=n.getTextContent(),i=n.getTextContentSize())}if(st(n)){if(" "!==o[r])return{node:n,offset:r};r++}}}(t,e);return null!==r?r:n}}function pt(t){const e=ct(t);return h(e)&&D(168),e}function ft(t,e,n){const r=t.getParent();I(r)?mt(r,e,n):st(t)&&t.replace(d(t.__text))}function ht(t,e){const n=e.getElementByKey(t.getKey());if(null===n)return;const r=t.getChildren(),o=r.length;if(o===n.__cachedChildrenLength)return;n.__cachedChildrenLength=o;let i="1",s=1;for(let t=0;t<o;t++)h(r[t])&&(i+="\n"+ ++s);n.setAttribute("data-gutter",i)}const dt=new Set;function mt(t,e,n){const r=t.getKey();dt.has(r)||(dt.add(r),void 0===t.getLanguage()&&t.setLanguage(n.defaultLanguage),e.update((()=>{!function(t,e){const n=m(t);if(!I(n)||!n.isAttached())return;const r=x();if(!y(r))return void e();const o=r.anchor,i=o.offset,s="element"===o.type&&h(n.getChildAtIndex(o.offset-1));let u=0;if(!s){const t=o.getNode();u=i+t.getPreviousSiblings().reduce(((t,e)=>t+e.getTextContentSize()),0)}if(!e())return;if(s)return void o.getNode().select(i,i);n.getChildren().some((t=>{const e=l(t);if(e||h(t)){const n=t.getTextContentSize();if(e&&n>=u)return t.select(u,u),!0;u-=n}return!1}))}(r,(()=>{const e=m(r);if(!I(e)||!e.isAttached())return!1;const o=e.getTextContent(),i=xt(n.tokenize(o,e.getLanguage()||n.defaultLanguage)),s=function(t,e){let n=0;for(;n<t.length&&yt(t[n],e[n]);)n++;const r=t.length,o=e.length,i=Math.min(r,o)-n;let s=0;for(;s<i;)if(s++,!yt(t[r-s],e[o-s])){s--;break}const l=n,u=r-s,c=e.slice(n,o-s);return{from:l,nodesForReplacement:c,to:u}}(e.getChildren(),i),{from:l,to:u,nodesForReplacement:c}=s;return!(l===u&&!c.length)&&(t.splice(l,u-l,c),!0)}))}),{onUpdate:()=>{dt.delete(r)},skipTransforms:!0}))}function xt(t,e){const n=[];for(const r of t)if("string"==typeof r){const t=r.split(/(\n|\t)/),o=t.length;for(let r=0;r<o;r++){const o=t[r];"\n"===o||"\r\n"===o?n.push(a()):"\t"===o?n.push(c()):o.length>0&&n.push(it(o,e))}}else{const{content:t}=r;"string"==typeof t?n.push(...xt([t],r.type)):Array.isArray(t)&&n.push(...xt(t,r.type))}return n}function yt(t,e){return st(t)&&st(e)&&t.__text===e.__text&&t.__highlightType===e.__highlightType||u(t)&&u(e)||h(t)&&h(e)}function St(t){if(!y(t))return!1;const e=t.anchor.getNode(),n=I(e)?e:e.getParent(),r=t.focus.getNode(),o=I(r)?r:r.getParent();return I(n)&&n.is(o)}function _t(t){const e=t.getNodes(),n=[];if(1===e.length&&I(e[0]))return n;let r=[];for(let t=0;t<e.length;t++){const o=e[t];st(o)||u(o)||h(o)||D(169),h(o)?r.length>0&&(n.push(r),r=[]):r.push(o)}if(r.length>0){const e=t.isBackward()?t.anchor:t.focus,o=S(r[0].getKey(),0,"text");e.is(o)||n.push(r)}return n}function vt(t){const e=x();if(!y(e)||!St(e))return!1;const n=_t(e),r=n.length;if(0===r&&e.isCollapsed())return t===_&&e.insertNodes([c()]),!0;if(0===r&&t===_&&"\n"===e.getTextContent()){const t=c(),n=a(),r=e.isBackward()?"previous":"next";return e.insertNodes([t,n]),C(N(j(b(t,"next",0),w(f(n,"next"))),r)),!0}for(let o=0;o<r;o++){const r=n[o];if(r.length>0){let n=r[0];if(0===o&&(n=ut(n)),t===_){const t=c();if(n.insertBefore(t),0===o){const r=e.isBackward()?"focus":"anchor",o=S(n.getKey(),0,"text");e[r].is(o)&&e[r].set(t.getKey(),0,"text")}}else u(n)&&n.remove()}}return!0}function Tt(t,e){const n=x();if(!y(n))return!1;const{anchor:r,focus:o}=n,i=r.offset,s=o.offset,l=r.getNode(),c=o.getNode(),a=t===P;if(!St(n)||!st(l)&&!u(l)||!st(c)&&!u(c))return!1;if(!e.altKey){if(n.isCollapsed()){const t=l.getParentOrThrow();if(a&&0===i&&null===l.getPreviousSibling()){if(null===t.getPreviousSibling())return t.selectPrevious(),e.preventDefault(),!0}else if(!a&&i===l.getTextContentSize()&&null===l.getNextSibling()){if(null===t.getNextSibling())return t.selectNext(),e.preventDefault(),!0}}return!1}let g,p;if(l.isBefore(c)?(g=ut(l),p=ct(c)):(g=ut(c),p=ct(l)),null==g||null==p)return!1;const f=g.getNodesBetween(p);for(let t=0;t<f.length;t++){const e=f[t];if(!st(e)&&!u(e)&&!h(e))return!1}e.preventDefault(),e.stopPropagation();const d=a?g.getPreviousSibling():p.getNextSibling();if(!h(d))return!0;const m=a?d.getPreviousSibling():d.getNextSibling();if(null==m)return!0;const S=st(m)||u(m)||h(m)?a?ut(m):ct(m):null;let _=null!=S?S:m;return d.remove(),f.forEach((t=>t.remove())),t===P?(f.forEach((t=>_.insertBefore(t))),_.insertBefore(d)):(_.insertAfter(d),_=d,f.forEach((t=>{_.insertAfter(t),_=t}))),n.setTextNodeRange(l,i,c,s),!0}function Ct(t,e){const n=x();if(!y(n))return!1;const{anchor:r,focus:o}=n,i=r.getNode(),s=o.getNode(),l=t===k;if(!St(n)||!st(i)&&!u(i)||!st(s)&&!u(s))return!1;if(l){const t=gt(s,o.offset);if(null!==t){const{node:e,offset:r}=t;h(e)?e.selectNext(0,0):n.setTextNodeRange(e,r,e,r)}else s.getParentOrThrow().selectStart()}else{pt(s).select()}return e.preventDefault(),e.stopPropagation(),!0}function Nt(t,e){if(!t.hasNodes([K,rt]))throw new Error("CodeHighlightPlugin: CodeNode or CodeHighlightNode not registered on editor");null==e&&(e=at);const n=[];return!0!==t._headless&&n.push(t.registerMutationListener(K,(e=>{t.update((()=>{for(const[n,r]of e)if("destroyed"!==r){const e=m(n);null!==e&&ht(e,t)}}))}),{skipInitialization:!1})),n.push(t.registerNodeTransform(K,(n=>mt(n,t,e))),t.registerNodeTransform(p,(n=>ft(n,t,e))),t.registerNodeTransform(rt,(n=>ft(n,t,e))),t.registerCommand(O,(e=>{const n=function(t){const e=x();if(!y(e)||!St(e))return null;const n=t?v:_,r=t?v:T,o=e.anchor,i=e.focus;if(o.is(i))return r;const s=_t(e);if(1!==s.length)return n;const l=s[0];let u,c;0===l.length&&D(285),e.isBackward()?(u=i,c=o):(u=o,c=i);const a=ut(l[0]),g=ct(l[0]),p=S(a.getKey(),0,"text"),f=S(g.getKey(),g.getTextContentSize(),"text");return u.isBefore(p)||f.isBefore(c)?n:p.isBefore(u)||c.isBefore(f)?r:n}(e.shiftKey);return null!==n&&(e.preventDefault(),t.dispatchCommand(n,void 0),!0)}),L),t.registerCommand(T,(()=>!!St(x())&&(A([c()]),!0)),L),t.registerCommand(_,(t=>vt(_)),L),t.registerCommand(v,(t=>vt(v)),L),t.registerCommand(P,(t=>{const e=x();if(!y(e))return!1;const{anchor:n}=e,r=n.getNode();return!!St(e)&&(e.isCollapsed()&&0===n.offset&&null===r.getPreviousSibling()&&I(r.getParentOrThrow())?(t.preventDefault(),!0):Tt(P,t))}),L),t.registerCommand(H,(t=>{const e=x();if(!y(e))return!1;const{anchor:n}=e,r=n.getNode();return!!St(e)&&(e.isCollapsed()&&n.offset===r.getTextContentSize()&&null===r.getNextSibling()&&I(r.getParentOrThrow())?(t.preventDefault(),!0):Tt(H,t))}),L),t.registerCommand(k,(t=>Ct(k,t)),L),t.registerCommand(B,(t=>Ct(B,t)),L)),o(...n)}const jt=ut,bt=ct,wt=pt,Pt=gt;export{it as $createCodeHighlightNode,R as $createCodeNode,pt as $getEndOfCodeInLine,ut as $getFirstCodeNodeOfLine,ct as $getLastCodeNodeOfLine,gt as $getStartOfCodeInLine,st as $isCodeHighlightNode,I as $isCodeNode,V as CODE_LANGUAGE_FRIENDLY_NAME_MAP,Y as CODE_LANGUAGE_MAP,rt as CodeHighlightNode,K as CodeNode,G as DEFAULT_CODE_LANGUAGE,at as PrismTokenizer,nt as getCodeLanguages,et as getDefaultCodeLanguage,wt as getEndOfCodeInLine,jt as getFirstCodeNodeOfLine,tt as getLanguageFriendlyName,bt as getLastCodeNodeOfLine,Pt as getStartOfCodeInLine,Z as normalizeCodeLang,Nt as registerCodeHighlighting};