Skip to content

Commit 433a6be

Browse files
committed
fix(parser): Protect inline code from formatting while allowing spans
1 parent f0237f0 commit 433a6be

8 files changed

Lines changed: 205 additions & 7 deletions

File tree

dist/overtype.esm.js

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/overtype.esm.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/overtype.js

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/overtype.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/overtype.min.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* @author Demo User
66
* https://github.com/demo/overtype
77
*/
8-
var OverType=(()=>{var _=Object.defineProperty;var He=Object.getOwnPropertyDescriptor;var Ie=Object.getOwnPropertyNames;var Me=Object.prototype.hasOwnProperty;var Oe=(n,e,t)=>e in n?_(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var je=(n,e)=>{for(var t in e)_(n,t,{get:e[t],enumerable:!0})},Ne=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Ie(e))!Me.call(n,r)&&r!==t&&_(n,r,{get:()=>e[r],enumerable:!(o=He(e,r))||o.enumerable});return n};var _e=n=>Ne(_({},"__esModule",{value:!0}),n);var I=(n,e,t)=>(Oe(n,typeof e!="symbol"?e+"":e,t),t);var Ge={};je(Ge,{OverType:()=>A,default:()=>Qe});var M=class{static escapeHtml(e){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return e.replace(/[&<>"']/g,o=>t[o])}static preserveIndentation(e,t){let r=t.match(/^(\s*)/)[1].replace(/ /g,"&nbsp;");return e.replace(/^\s*/,r)}static parseHeader(e){return e.replace(/^(#{1,3})\s(.+)$/,(t,o,r)=>{let i=o.length;return`<span class="header ${["h1","h2","h3"][i-1]}"><span class="syntax-marker">${o}</span> ${r}</span>`})}static parseHorizontalRule(e){return e.match(/^(-{3,}|\*{3,}|_{3,})$/)?`<div><span class="hr-marker">${e}</span></div>`:null}static parseBlockquote(e){return e.replace(/^&gt; (.+)$/,(t,o)=>`<span class="blockquote"><span class="syntax-marker">&gt;</span> ${o}</span>`)}static parseBulletList(e){return e.replace(/^((?:&nbsp;)*)([-*])\s(.+)$/,(t,o,r,i)=>`${o}<span class="syntax-marker">${r}</span> ${i}`)}static parseNumberedList(e){return e.replace(/^((?:&nbsp;)*)(\d+\.)\s(.+)$/,(t,o,r,i)=>`${o}<span class="syntax-marker">${r}</span> ${i}`)}static parseCodeBlock(e){return e.startsWith("```")?`<div><span class="code-fence">${e}</span></div>`:null}static parseBold(e){return e=e.replace(/\*\*(.+?)\*\*/g,'<strong><span class="syntax-marker">**</span>$1<span class="syntax-marker">**</span></strong>'),e=e.replace(/__(.+?)__/g,'<strong><span class="syntax-marker">__</span>$1<span class="syntax-marker">__</span></strong>'),e}static parseItalic(e){return e=e.replace(new RegExp("(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)","g"),'<em><span class="syntax-marker">*</span>$1<span class="syntax-marker">*</span></em>'),e=e.replace(new RegExp("(?<!_)_(?!_)(.+?)(?<!_)_(?!_)","g"),'<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>'),e}static parseInlineCode(e){return e.replace(/`(.+?)`/g,'<code><span class="syntax-marker">`</span>$1<span class="syntax-marker">`</span></code>')}static parseLinks(e){return e.replace(/\[(.+?)\]\((.+?)\)/g,'<a href="$2"><span class="syntax-marker">[</span>$1<span class="syntax-marker">](</span><span class="syntax-marker">$2</span><span class="syntax-marker">)</span></a>')}static parseInlineElements(e){let t=e;return t=this.parseInlineCode(t),t=this.parseLinks(t),t=this.parseBold(t),t=this.parseItalic(t),t}static parseLine(e){let t=this.escapeHtml(e);t=this.preserveIndentation(t,e);let o=this.parseHorizontalRule(t);if(o)return o;let r=this.parseCodeBlock(t);return r||(t=this.parseHeader(t),t=this.parseBlockquote(t),t=this.parseBulletList(t),t=this.parseNumberedList(t),t=this.parseInlineElements(t),t.trim()===""?"<div>&nbsp;</div>":`<div>${t}</div>`)}static parse(e,t=-1,o=!1){return e.split(`
8+
var OverType=(()=>{var _=Object.defineProperty;var He=Object.getOwnPropertyDescriptor;var Ie=Object.getOwnPropertyNames;var Me=Object.prototype.hasOwnProperty;var Oe=(n,e,t)=>e in n?_(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var je=(n,e)=>{for(var t in e)_(n,t,{get:e[t],enumerable:!0})},Ne=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Ie(e))!Me.call(n,r)&&r!==t&&_(n,r,{get:()=>e[r],enumerable:!(o=He(e,r))||o.enumerable});return n};var _e=n=>Ne(_({},"__esModule",{value:!0}),n);var I=(n,e,t)=>(Oe(n,typeof e!="symbol"?e+"":e,t),t);var Ge={};je(Ge,{OverType:()=>A,default:()=>Qe});var M=class{static escapeHtml(e){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return e.replace(/[&<>"']/g,o=>t[o])}static preserveIndentation(e,t){let r=t.match(/^(\s*)/)[1].replace(/ /g,"&nbsp;");return e.replace(/^\s*/,r)}static parseHeader(e){return e.replace(/^(#{1,3})\s(.+)$/,(t,o,r)=>{let i=o.length;return`<span class="header ${["h1","h2","h3"][i-1]}"><span class="syntax-marker">${o}</span> ${r}</span>`})}static parseHorizontalRule(e){return e.match(/^(-{3,}|\*{3,}|_{3,})$/)?`<div><span class="hr-marker">${e}</span></div>`:null}static parseBlockquote(e){return e.replace(/^&gt; (.+)$/,(t,o)=>`<span class="blockquote"><span class="syntax-marker">&gt;</span> ${o}</span>`)}static parseBulletList(e){return e.replace(/^((?:&nbsp;)*)([-*])\s(.+)$/,(t,o,r,i)=>`${o}<span class="syntax-marker">${r}</span> ${i}`)}static parseNumberedList(e){return e.replace(/^((?:&nbsp;)*)(\d+\.)\s(.+)$/,(t,o,r,i)=>`${o}<span class="syntax-marker">${r}</span> ${i}`)}static parseCodeBlock(e){return e.startsWith("```")?`<div><span class="code-fence">${e}</span></div>`:null}static parseBold(e){return e=e.replace(/\*\*(.+?)\*\*/g,'<strong><span class="syntax-marker">**</span>$1<span class="syntax-marker">**</span></strong>'),e=e.replace(/__(.+?)__/g,'<strong><span class="syntax-marker">__</span>$1<span class="syntax-marker">__</span></strong>'),e}static parseItalic(e){return e=e.replace(new RegExp("(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)","g"),'<em><span class="syntax-marker">*</span>$1<span class="syntax-marker">*</span></em>'),e=e.replace(new RegExp("(?<!_)_(?!_)(.+?)(?<!_)_(?!_)","g"),'<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>'),e}static parseInlineCode(e){return e.replace(/`(.+?)`/g,'<code><span class="syntax-marker">`</span>$1<span class="syntax-marker">`</span></code>')}static parseLinks(e){return e.replace(/\[(.+?)\]\((.+?)\)/g,'<a href="$2"><span class="syntax-marker">[</span>$1<span class="syntax-marker">](</span><span class="syntax-marker">$2</span><span class="syntax-marker">)</span></a>')}static parseInlineElements(e){let t=e;t=this.parseInlineCode(t);let o=new Map;return t=t.replace(/(<code>.*?<\/code>)/g,r=>{let i=`\uE000${o.size}\uE001`;return o.set(i,r),i}),t=this.parseLinks(t),t=this.parseBold(t),t=this.parseItalic(t),o.forEach((r,i)=>{t=t.replace(i,r)}),t}static parseLine(e){let t=this.escapeHtml(e);t=this.preserveIndentation(t,e);let o=this.parseHorizontalRule(t);if(o)return o;let r=this.parseCodeBlock(t);return r||(t=this.parseHeader(t),t=this.parseBlockquote(t),t=this.parseBulletList(t),t=this.parseNumberedList(t),t=this.parseInlineElements(t),t.trim()===""?"<div>&nbsp;</div>":`<div>${t}</div>`)}static parse(e,t=-1,o=!1){return e.split(`
99
`).map((s,a)=>o&&a===t?`<div class="raw-line">${this.escapeHtml(s)||"&nbsp;"}</div>`:this.parseLine(s)).join("")}};var Pe=Object.defineProperty,X=Object.getOwnPropertySymbols,Fe=Object.prototype.hasOwnProperty,Ve=Object.prototype.propertyIsEnumerable,Y=(n,e,t)=>e in n?Pe(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,ee=(n,e)=>{for(var t in e||(e={}))Fe.call(e,t)&&Y(n,t,e[t]);if(X)for(var t of X(e))Ve.call(e,t)&&Y(n,t,e[t]);return n},S={bold:{prefix:"**",suffix:"**",trimFirst:!0},italic:{prefix:"_",suffix:"_",trimFirst:!0},code:{prefix:"`",suffix:"`",blockPrefix:"```",blockSuffix:"```"},link:{prefix:"[",suffix:"](url)",replaceNext:"url",scanFor:"https?://"},bulletList:{prefix:"- ",multiline:!0,unorderedList:!0},numberedList:{prefix:"1. ",multiline:!0,orderedList:!0},quote:{prefix:"> ",multiline:!0,surroundWithNewlines:!0},taskList:{prefix:"- [ ] ",multiline:!0,surroundWithNewlines:!0},header1:{prefix:"# "},header2:{prefix:"## "},header3:{prefix:"### "},header4:{prefix:"#### "},header5:{prefix:"##### "},header6:{prefix:"###### "}};function ze(){return{prefix:"",suffix:"",blockPrefix:"",blockSuffix:"",multiline:!1,replaceNext:"",prefixSpace:!1,scanFor:"",surroundWithNewlines:!1,orderedList:!1,unorderedList:!1,trimFirst:!1}}function E(n){return ee(ee({},ze()),n)}var F=!1;function Re(){return F}function g(n,e,t){F&&(console.group(`\u{1F50D} ${n}`),console.log(e),t&&console.log("Data:",t),console.groupEnd())}function P(n,e){if(!F)return;let t=n.value.slice(n.selectionStart,n.selectionEnd);console.group(`\u{1F4CD} Selection: ${e}`),console.log("Position:",`${n.selectionStart}-${n.selectionEnd}`),console.log("Selected text:",JSON.stringify(t)),console.log("Length:",t.length);let o=n.value.slice(Math.max(0,n.selectionStart-10),n.selectionStart),r=n.value.slice(n.selectionEnd,Math.min(n.value.length,n.selectionEnd+10));console.log("Context:",JSON.stringify(o)+"[SELECTION]"+JSON.stringify(r)),console.groupEnd()}function re(n){F&&(console.group("\u{1F4DD} Result"),console.log("Text to insert:",JSON.stringify(n.text)),console.log("New selection:",`${n.selectionStart}-${n.selectionEnd}`),console.groupEnd())}var C=null;function $(n,{text:e,selectionStart:t,selectionEnd:o}){let r=Re();r&&(console.group("\u{1F527} insertText"),console.log("Current selection:",`${n.selectionStart}-${n.selectionEnd}`),console.log("Text to insert:",JSON.stringify(e)),console.log("New selection to set:",t,"-",o)),n.focus();let i=n.selectionStart,s=n.selectionEnd,a=n.value.slice(0,i),l=n.value.slice(s);r&&(console.log("Before text (last 20):",JSON.stringify(a.slice(-20))),console.log("After text (first 20):",JSON.stringify(l.slice(0,20))),console.log("Selected text being replaced:",JSON.stringify(n.value.slice(i,s))));let u=n.value,p=i!==s;if(C===null||C===!0){n.contentEditable="true";try{C=document.execCommand("insertText",!1,e),r&&console.log("execCommand returned:",C,"for text with",e.split(`
1010
`).length,"lines")}catch(c){C=!1,r&&console.log("execCommand threw error:",c)}n.contentEditable="false"}if(r&&(console.log("canInsertText before:",C),console.log("execCommand result:",C)),C){let c=a+e+l,f=n.value;r&&(console.log("Expected length:",c.length),console.log("Actual length:",f.length)),f!==c&&r&&(console.log("execCommand changed the value but not as expected"),console.log("Expected:",JSON.stringify(c.slice(0,100))),console.log("Actual:",JSON.stringify(f.slice(0,100))))}if(!C)if(r&&console.log("Using manual insertion"),n.value===u){r&&console.log("Value unchanged, doing manual replacement");try{document.execCommand("ms-beginUndoUnit")}catch(c){}n.value=a+e+l;try{document.execCommand("ms-endUndoUnit")}catch(c){}n.dispatchEvent(new CustomEvent("input",{bubbles:!0,cancelable:!0}))}else r&&console.log("Value was changed by execCommand, skipping manual insertion");r&&console.log("Setting selection range:",t,o),t!=null&&o!=null?n.setSelectionRange(t,o):n.setSelectionRange(i,n.selectionEnd),r&&(console.log("Final value length:",n.value.length),console.groupEnd())}function te(n){return n.trim().split(`
1111
`).length>1}function qe(n,e){let t=e;for(;n[t]&&n[t-1]!=null&&!n[t-1].match(/\s/);)t--;return t}function De(n,e,t){let o=e,r=t?/\n/:/\s/;for(;n[o]&&!n[o].match(r);)o++;return o}function ie(n){let e=n.value.split(`

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/parser.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,31 @@ export class MarkdownParser {
153153
*/
154154
static parseInlineElements(text) {
155155
let html = text;
156+
156157
// Order matters: parse code first to avoid conflicts
157158
html = this.parseInlineCode(html);
159+
160+
// Use placeholders to protect code content while preserving formatting spans
161+
const codeBlocks = new Map();
162+
163+
// Replace code blocks with placeholders using a unique token
164+
html = html.replace(/(<code>.*?<\/code>)/g, (match) => {
165+
// Prevent conflicts with private use area Unicode chars
166+
const placeholder = `\uE000${codeBlocks.size}\uE001`;
167+
codeBlocks.set(placeholder, match);
168+
return placeholder;
169+
});
170+
171+
// Process other inline elements on text with placeholders
158172
html = this.parseLinks(html);
159173
html = this.parseBold(html);
160174
html = this.parseItalic(html);
175+
176+
// Restore code blocks
177+
codeBlocks.forEach((codeBlock, placeholder) => {
178+
html = html.replace(placeholder, codeBlock);
179+
});
180+
161181
return html;
162182
}
163183

0 commit comments

Comments
 (0)