overtype 1.2.4 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverType v1.2.4
2
+ * OverType v1.2.5
3
3
  * A lightweight markdown editor library with perfect WYSIWYG alignment
4
4
  * @license MIT
5
5
  * @author Demo User
@@ -128,7 +128,7 @@ var MarkdownParser = class {
128
128
  */
129
129
  static parseItalic(html) {
130
130
  html = html.replace(new RegExp("(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)", "g"), '<em><span class="syntax-marker">*</span>$1<span class="syntax-marker">*</span></em>');
131
- html = html.replace(new RegExp("(?<!_)_(?!_)(.+?)(?<!_)_(?!_)", "g"), '<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>');
131
+ html = html.replace(new RegExp("(?<=^|\\s)_(?!_)(.+?)(?<!_)_(?!_)(?=\\s|$)", "g"), '<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>');
132
132
  return html;
133
133
  }
134
134
  /**
@@ -185,31 +185,116 @@ var MarkdownParser = class {
185
185
  });
186
186
  }
187
187
  /**
188
- * Parse all inline elements in correct order
189
- * @param {string} text - Text with potential inline markdown
190
- * @returns {string} HTML with all inline styling
188
+ * Identify and protect sanctuaries (code and links) before parsing
189
+ * @param {string} text - Text with potential markdown
190
+ * @returns {Object} Object with protected text and sanctuary map
191
191
  */
192
- static parseInlineElements(text) {
193
- let html = text;
194
- html = this.parseInlineCode(html);
192
+ static identifyAndProtectSanctuaries(text) {
195
193
  const sanctuaries = /* @__PURE__ */ new Map();
196
- html = html.replace(/(<code>.*?<\/code>)/g, (match) => {
197
- const placeholder = `\uE000${sanctuaries.size}\uE001`;
198
- sanctuaries.set(placeholder, match);
199
- return placeholder;
194
+ let sanctuaryCounter = 0;
195
+ let protectedText = text;
196
+ const protectedRegions = [];
197
+ const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
198
+ let linkMatch;
199
+ while ((linkMatch = linkRegex.exec(text)) !== null) {
200
+ const bracketPos = linkMatch.index + linkMatch[0].indexOf("](");
201
+ const urlStart = bracketPos + 2;
202
+ const urlEnd = urlStart + linkMatch[2].length;
203
+ protectedRegions.push({ start: urlStart, end: urlEnd });
204
+ }
205
+ const codeRegex = new RegExp("(?<!`)(`+)(?!`)((?:(?!\\1).)+?)(\\1)(?!`)", "g");
206
+ let codeMatch;
207
+ const codeMatches = [];
208
+ while ((codeMatch = codeRegex.exec(text)) !== null) {
209
+ const codeStart = codeMatch.index;
210
+ const codeEnd = codeMatch.index + codeMatch[0].length;
211
+ const inProtectedRegion = protectedRegions.some(
212
+ (region) => codeStart >= region.start && codeEnd <= region.end
213
+ );
214
+ if (!inProtectedRegion) {
215
+ codeMatches.push({
216
+ match: codeMatch[0],
217
+ index: codeMatch.index,
218
+ openTicks: codeMatch[1],
219
+ content: codeMatch[2],
220
+ closeTicks: codeMatch[3]
221
+ });
222
+ }
223
+ }
224
+ codeMatches.sort((a, b) => b.index - a.index);
225
+ codeMatches.forEach((codeInfo) => {
226
+ const placeholder = `\uE000${sanctuaryCounter++}\uE001`;
227
+ sanctuaries.set(placeholder, {
228
+ type: "code",
229
+ original: codeInfo.match,
230
+ openTicks: codeInfo.openTicks,
231
+ content: codeInfo.content,
232
+ closeTicks: codeInfo.closeTicks
233
+ });
234
+ protectedText = protectedText.substring(0, codeInfo.index) + placeholder + protectedText.substring(codeInfo.index + codeInfo.match.length);
200
235
  });
201
- html = this.parseLinks(html);
202
- html = html.replace(/(<a[^>]*>.*?<\/a>)/g, (match) => {
203
- const placeholder = `\uE000${sanctuaries.size}\uE001`;
204
- sanctuaries.set(placeholder, match);
236
+ protectedText = protectedText.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, linkText, url) => {
237
+ const placeholder = `\uE000${sanctuaryCounter++}\uE001`;
238
+ sanctuaries.set(placeholder, {
239
+ type: "link",
240
+ original: match,
241
+ linkText,
242
+ url
243
+ });
205
244
  return placeholder;
206
245
  });
246
+ return { protectedText, sanctuaries };
247
+ }
248
+ /**
249
+ * Restore and transform sanctuaries back to HTML
250
+ * @param {string} html - HTML with sanctuary placeholders
251
+ * @param {Map} sanctuaries - Map of sanctuaries to restore
252
+ * @returns {string} HTML with sanctuaries restored and transformed
253
+ */
254
+ static restoreAndTransformSanctuaries(html, sanctuaries) {
255
+ const placeholders = Array.from(sanctuaries.keys()).sort((a, b) => {
256
+ const indexA = html.indexOf(a);
257
+ const indexB = html.indexOf(b);
258
+ return indexA - indexB;
259
+ });
260
+ placeholders.forEach((placeholder) => {
261
+ const sanctuary = sanctuaries.get(placeholder);
262
+ let replacement;
263
+ if (sanctuary.type === "code") {
264
+ replacement = `<code><span class="syntax-marker">${sanctuary.openTicks}</span>${this.escapeHtml(sanctuary.content)}<span class="syntax-marker">${sanctuary.closeTicks}</span></code>`;
265
+ } else if (sanctuary.type === "link") {
266
+ let processedLinkText = sanctuary.linkText;
267
+ sanctuaries.forEach((innerSanctuary, innerPlaceholder) => {
268
+ if (processedLinkText.includes(innerPlaceholder)) {
269
+ if (innerSanctuary.type === "code") {
270
+ const codeHtml = `<code><span class="syntax-marker">${innerSanctuary.openTicks}</span>${this.escapeHtml(innerSanctuary.content)}<span class="syntax-marker">${innerSanctuary.closeTicks}</span></code>`;
271
+ processedLinkText = processedLinkText.replace(innerPlaceholder, codeHtml);
272
+ }
273
+ }
274
+ });
275
+ processedLinkText = this.parseStrikethrough(processedLinkText);
276
+ processedLinkText = this.parseBold(processedLinkText);
277
+ processedLinkText = this.parseItalic(processedLinkText);
278
+ const anchorName = `--link-${this.linkIndex++}`;
279
+ const safeUrl = this.sanitizeUrl(sanctuary.url);
280
+ replacement = `<a href="${safeUrl}" style="anchor-name: ${anchorName}"><span class="syntax-marker">[</span>${processedLinkText}<span class="syntax-marker url-part">](${this.escapeHtml(sanctuary.url)})</span></a>`;
281
+ }
282
+ html = html.replace(placeholder, replacement);
283
+ });
284
+ return html;
285
+ }
286
+ /**
287
+ * Parse all inline elements in correct order
288
+ * @param {string} text - Text with potential inline markdown
289
+ * @returns {string} HTML with all inline styling
290
+ */
291
+ static parseInlineElements(text) {
292
+ const { protectedText, sanctuaries } = this.identifyAndProtectSanctuaries(text);
293
+ let html = protectedText;
207
294
  html = this.parseStrikethrough(html);
208
295
  html = this.parseBold(html);
209
296
  html = this.parseItalic(html);
210
- sanctuaries.forEach((content, placeholder) => {
211
- html = html.replace(placeholder, content);
212
- });
297
+ html = this.restoreAndTransformSanctuaries(html, sanctuaries);
213
298
  return html;
214
299
  }
215
300
  /**