@owomark/core 0.1.4 → 0.1.6

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.
@@ -11,185 +11,233 @@ import {
11
11
  } from "./chunk-MPIWZLI3.js";
12
12
 
13
13
  // src/parser/inline-tokens.ts
14
- function overlaps(segs, start, end) {
15
- return segs.some((s) => start < s.end && end > s.start);
16
- }
14
+ var HTML_TAG_RE = /<\/?[A-Za-z][\w:-]*(?:\s+[A-Za-z_:][\w:.-]*(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)*\s*\/?>/y;
17
15
  function tok(type, text, start) {
18
16
  return { type, text, start, end: start + text.length };
19
17
  }
20
18
  function isEscaped(raw, index) {
21
19
  let backslashCount = 0;
22
- for (let cursor = index - 1; cursor >= 0 && raw[cursor] === "\\"; cursor--) {
20
+ for (let cursor = index - 1; cursor >= 0 && raw[cursor] === "\\"; cursor -= 1) {
23
21
  backslashCount += 1;
24
22
  }
25
23
  return backslashCount % 2 === 1;
26
24
  }
27
- function findInlineMathRanges(raw) {
28
- const ranges = [];
29
- for (let start = 0; start < raw.length; start++) {
30
- if (raw[start] !== "$" || isEscaped(raw, start)) continue;
31
- if (raw[start + 1] === "$") {
32
- start += 1;
33
- continue;
34
- }
35
- for (let end = start + 1; end < raw.length; end++) {
36
- if (raw[end] !== "$" || isEscaped(raw, end)) continue;
37
- if (raw[end - 1] === "$" || raw[end + 1] === "$") continue;
38
- ranges.push({ start, end: end + 1 });
39
- start = end;
40
- break;
41
- }
25
+ function isAsciiWordChar(value) {
26
+ return value != null && /[A-Za-z0-9]/.test(value);
27
+ }
28
+ function countRun(raw, start, char) {
29
+ let length = 0;
30
+ while (raw[start + length] === char) {
31
+ length += 1;
42
32
  }
43
- return ranges;
33
+ return length;
44
34
  }
45
- function tokenizeInline(raw, baseOffset = 0) {
46
- if (!raw) return [{ type: "text", text: "", start: baseOffset, end: baseOffset }];
47
- const segs = [];
48
- for (const m of raw.matchAll(/`([^`]+)`/g)) {
49
- const s = m.index;
50
- segs.push({
51
- start: s,
52
- end: s + m[0].length,
53
- tokens: [
54
- tok("code-marker", "`", baseOffset + s),
55
- tok("code", m[1], baseOffset + s + 1),
56
- tok("code-marker", "`", baseOffset + s + m[0].length - 1)
57
- ]
58
- });
35
+ function findClosingDelimiter(raw, from, delimiter) {
36
+ for (let index = from; index <= raw.length - delimiter.length; index += 1) {
37
+ if (raw.slice(index, index + delimiter.length) !== delimiter) continue;
38
+ if (isEscaped(raw, index)) continue;
39
+ return index;
59
40
  }
60
- for (const m of raw.matchAll(/!\[([^\]]*)\]\(([^)]*)\)/g)) {
61
- const s = m.index;
62
- if (!overlaps(segs, s, s + m[0].length)) {
63
- const tokens = [];
64
- let pos2 = s;
65
- tokens.push(tok("image-marker", "![", baseOffset + pos2));
66
- pos2 += 2;
67
- tokens.push(tok("image-alt", m[1], baseOffset + pos2));
68
- pos2 += m[1].length;
69
- tokens.push(tok("link-bracket", "](", baseOffset + pos2));
70
- pos2 += 2;
71
- tokens.push(tok("image-url", m[2], baseOffset + pos2));
72
- pos2 += m[2].length;
73
- tokens.push(tok("link-bracket", ")", baseOffset + pos2));
74
- segs.push({ start: s, end: s + m[0].length, tokens });
75
- }
76
- }
77
- for (const m of raw.matchAll(/\[([^\]]*)\]\(([^)]*)\)/g)) {
78
- const s = m.index;
79
- if (!overlaps(segs, s, s + m[0].length)) {
80
- const tokens = [];
81
- let pos2 = s;
82
- tokens.push(tok("link-bracket", "[", baseOffset + pos2));
83
- pos2 += 1;
84
- tokens.push(tok("link-text", m[1], baseOffset + pos2));
85
- pos2 += m[1].length;
86
- tokens.push(tok("link-bracket", "](", baseOffset + pos2));
87
- pos2 += 2;
88
- tokens.push(tok("link-url", m[2], baseOffset + pos2));
89
- pos2 += m[2].length;
90
- tokens.push(tok("link-bracket", ")", baseOffset + pos2));
91
- segs.push({ start: s, end: s + m[0].length, tokens });
92
- }
93
- }
94
- for (const m of raw.matchAll(/~~(.+?)~~/g)) {
95
- const s = m.index;
96
- if (!overlaps(segs, s, s + m[0].length)) {
97
- segs.push({
98
- start: s,
99
- end: s + m[0].length,
100
- tokens: [
101
- tok("strikethrough-marker", "~~", baseOffset + s),
102
- tok("strikethrough", m[1], baseOffset + s + 2),
103
- tok("strikethrough-marker", "~~", baseOffset + s + m[0].length - 2)
104
- ]
105
- });
41
+ return -1;
42
+ }
43
+ function findClosingCodeDelimiter(raw, from, delimiterLength) {
44
+ for (let index = from; index < raw.length; index += 1) {
45
+ if (raw[index] !== "`" || isEscaped(raw, index)) continue;
46
+ const runLength = countRun(raw, index, "`");
47
+ if (runLength === delimiterLength) {
48
+ return index;
106
49
  }
50
+ index += runLength - 1;
107
51
  }
108
- for (const range of findInlineMathRanges(raw)) {
109
- if (!overlaps(segs, range.start, range.end)) {
110
- const innerStart = range.start + 1;
111
- const innerEnd = range.end - 1;
112
- segs.push({
113
- start: range.start,
114
- end: range.end,
115
- tokens: [
116
- tok("math-marker", "$", baseOffset + range.start),
117
- tok("math-text", raw.slice(innerStart, innerEnd), baseOffset + innerStart),
118
- tok("math-marker", "$", baseOffset + innerEnd)
119
- ]
120
- });
121
- }
52
+ return -1;
53
+ }
54
+ function matchCodeSpan(raw, index, baseOffset) {
55
+ if (raw[index] !== "`") return null;
56
+ const delimiterLength = countRun(raw, index, "`");
57
+ const delimiter = "`".repeat(delimiterLength);
58
+ const closeIndex = findClosingCodeDelimiter(raw, index + delimiterLength, delimiterLength);
59
+ if (closeIndex === -1 || closeIndex === index + delimiterLength) {
60
+ return null;
122
61
  }
123
- for (const m of raw.matchAll(/\*\*(.+?)\*\*/g)) {
124
- const s = m.index;
125
- if (!overlaps(segs, s, s + m[0].length)) {
126
- segs.push({
127
- start: s,
128
- end: s + m[0].length,
129
- tokens: [
130
- tok("strong-marker", "**", baseOffset + s),
131
- tok("strong", m[1], baseOffset + s + 2),
132
- tok("strong-marker", "**", baseOffset + s + m[0].length - 2)
133
- ]
134
- });
62
+ const innerStart = index + delimiterLength;
63
+ const innerText = raw.slice(innerStart, closeIndex);
64
+ return {
65
+ end: closeIndex + delimiterLength,
66
+ tokens: [
67
+ tok("code-marker", delimiter, baseOffset + index),
68
+ tok("code", innerText, baseOffset + innerStart),
69
+ tok("code-marker", delimiter, baseOffset + closeIndex)
70
+ ]
71
+ };
72
+ }
73
+ function findClosingBracket(raw, from) {
74
+ for (let index = from; index < raw.length; index += 1) {
75
+ if (raw[index] === "]" && !isEscaped(raw, index)) {
76
+ return index;
135
77
  }
136
78
  }
137
- for (const m of raw.matchAll(/(?<![a-zA-Z0-9])__(.+?)__(?![a-zA-Z0-9])/g)) {
138
- const s = m.index;
139
- if (!overlaps(segs, s, s + m[0].length)) {
140
- segs.push({
141
- start: s,
142
- end: s + m[0].length,
143
- tokens: [
144
- tok("strong-marker", "__", baseOffset + s),
145
- tok("strong", m[1], baseOffset + s + 2),
146
- tok("strong-marker", "__", baseOffset + s + m[0].length - 2)
147
- ]
148
- });
79
+ return -1;
80
+ }
81
+ function findClosingParen(raw, from) {
82
+ for (let index = from; index < raw.length; index += 1) {
83
+ if (raw[index] === ")" && !isEscaped(raw, index)) {
84
+ return index;
149
85
  }
150
86
  }
151
- for (const m of raw.matchAll(/(?<!\*)\*([^*]+)\*(?!\*)/g)) {
152
- const s = m.index;
153
- if (!overlaps(segs, s, s + m[0].length)) {
154
- segs.push({
155
- start: s,
156
- end: s + m[0].length,
157
- tokens: [
158
- tok("emphasis-marker", "*", baseOffset + s),
159
- tok("emphasis", m[1], baseOffset + s + 1),
160
- tok("emphasis-marker", "*", baseOffset + s + m[0].length - 1)
161
- ]
162
- });
87
+ return -1;
88
+ }
89
+ function matchLinkLike(raw, index, baseOffset, image2) {
90
+ const marker = image2 ? "![" : "[";
91
+ if (!raw.startsWith(marker, index)) return null;
92
+ const labelStart = index + marker.length;
93
+ const labelEnd = findClosingBracket(raw, labelStart);
94
+ if (labelEnd === -1 || raw[labelEnd + 1] !== "(") return null;
95
+ const urlStart = labelEnd + 2;
96
+ const urlEnd = findClosingParen(raw, urlStart);
97
+ if (urlEnd === -1) return null;
98
+ const label = raw.slice(labelStart, labelEnd);
99
+ const url = raw.slice(urlStart, urlEnd);
100
+ const tokens = [];
101
+ let cursor = index;
102
+ if (image2) {
103
+ tokens.push(tok("image-marker", "![", baseOffset + cursor));
104
+ cursor += 2;
105
+ tokens.push(tok("image-alt", label, baseOffset + cursor));
106
+ cursor += label.length;
107
+ tokens.push(tok("link-bracket", "](", baseOffset + cursor));
108
+ cursor += 2;
109
+ tokens.push(tok("image-url", url, baseOffset + cursor));
110
+ cursor += url.length;
111
+ tokens.push(tok("link-bracket", ")", baseOffset + cursor));
112
+ } else {
113
+ tokens.push(tok("link-bracket", "[", baseOffset + cursor));
114
+ cursor += 1;
115
+ tokens.push(tok("link-text", label, baseOffset + cursor));
116
+ cursor += label.length;
117
+ tokens.push(tok("link-bracket", "](", baseOffset + cursor));
118
+ cursor += 2;
119
+ tokens.push(tok("link-url", url, baseOffset + cursor));
120
+ cursor += url.length;
121
+ tokens.push(tok("link-bracket", ")", baseOffset + cursor));
122
+ }
123
+ return {
124
+ end: urlEnd + 1,
125
+ tokens
126
+ };
127
+ }
128
+ function matchDelimitedRange(raw, index, baseOffset, delimiter, markerType, contentType) {
129
+ if (!raw.startsWith(delimiter, index) || isEscaped(raw, index)) return null;
130
+ const contentStart = index + delimiter.length;
131
+ const closeIndex = findClosingDelimiter(raw, contentStart, delimiter);
132
+ if (closeIndex === -1 || closeIndex === contentStart) return null;
133
+ return {
134
+ end: closeIndex + delimiter.length,
135
+ tokens: [
136
+ tok(markerType, delimiter, baseOffset + index),
137
+ tok(contentType, raw.slice(contentStart, closeIndex), baseOffset + contentStart),
138
+ tok(markerType, delimiter, baseOffset + closeIndex)
139
+ ]
140
+ };
141
+ }
142
+ function matchInlineMath(raw, index, baseOffset) {
143
+ if (raw[index] !== "$" || isEscaped(raw, index)) return null;
144
+ if (raw[index + 1] === "$") return null;
145
+ for (let cursor = index + 1; cursor < raw.length; cursor += 1) {
146
+ if (raw[cursor] !== "$" || isEscaped(raw, cursor)) continue;
147
+ if (raw[cursor - 1] === "$" || raw[cursor + 1] === "$") continue;
148
+ if (cursor === index + 1) return null;
149
+ return {
150
+ end: cursor + 1,
151
+ tokens: [
152
+ tok("math-marker", "$", baseOffset + index),
153
+ tok("math-text", raw.slice(index + 1, cursor), baseOffset + index + 1),
154
+ tok("math-marker", "$", baseOffset + cursor)
155
+ ]
156
+ };
157
+ }
158
+ return null;
159
+ }
160
+ function matchHtml(raw, index, baseOffset) {
161
+ if (raw[index] !== "<") return null;
162
+ HTML_TAG_RE.lastIndex = index;
163
+ const match = HTML_TAG_RE.exec(raw);
164
+ if (!match || match.index !== index) return null;
165
+ return {
166
+ end: index + match[0].length,
167
+ tokens: [tok("html", match[0], baseOffset + index)]
168
+ };
169
+ }
170
+ function underscoreBoundaryAllows(raw, start, end) {
171
+ return !isAsciiWordChar(raw[start - 1]) && !isAsciiWordChar(raw[end]);
172
+ }
173
+ function matchStrong(raw, index, baseOffset) {
174
+ if (raw.startsWith("**", index)) {
175
+ return matchDelimitedRange(raw, index, baseOffset, "**", "strong-marker", "strong");
176
+ }
177
+ if (!raw.startsWith("__", index)) return null;
178
+ const match = matchDelimitedRange(raw, index, baseOffset, "__", "strong-marker", "strong");
179
+ if (!match) return null;
180
+ if (!underscoreBoundaryAllows(raw, index, match.end)) return null;
181
+ return match;
182
+ }
183
+ function matchEmphasis(raw, index, baseOffset) {
184
+ if (raw[index] === "*") {
185
+ if (raw[index - 1] === "*" || raw[index + 1] === "*") return null;
186
+ return matchDelimitedRange(raw, index, baseOffset, "*", "emphasis-marker", "emphasis");
187
+ }
188
+ if (raw[index] !== "_" || raw[index + 1] === "_") return null;
189
+ const match = matchDelimitedRange(raw, index, baseOffset, "_", "emphasis-marker", "emphasis");
190
+ if (!match) return null;
191
+ if (!underscoreBoundaryAllows(raw, index, match.end)) return null;
192
+ return match;
193
+ }
194
+ function tryMatch(raw, index, baseOffset, customMatchers) {
195
+ for (const matcher of customMatchers) {
196
+ const match = matcher(raw, index, baseOffset);
197
+ if (match) {
198
+ return match;
163
199
  }
164
200
  }
165
- for (const m of raw.matchAll(/(?<![a-zA-Z0-9])_([^_]+)_(?![a-zA-Z0-9])/g)) {
166
- const s = m.index;
167
- if (!overlaps(segs, s, s + m[0].length)) {
168
- segs.push({
169
- start: s,
170
- end: s + m[0].length,
171
- tokens: [
172
- tok("emphasis-marker", "_", baseOffset + s),
173
- tok("emphasis", m[1], baseOffset + s + 1),
174
- tok("emphasis-marker", "_", baseOffset + s + m[0].length - 1)
175
- ]
176
- });
201
+ return matchCodeSpan(raw, index, baseOffset) ?? matchLinkLike(raw, index, baseOffset, true) ?? matchLinkLike(raw, index, baseOffset, false) ?? matchDelimitedRange(raw, index, baseOffset, "~~", "strikethrough-marker", "strikethrough") ?? matchInlineMath(raw, index, baseOffset) ?? matchHtml(raw, index, baseOffset) ?? matchStrong(raw, index, baseOffset) ?? matchEmphasis(raw, index, baseOffset);
202
+ }
203
+ function createLiteralTokenMatcher(literal, tokenType) {
204
+ return (raw, index, baseOffset) => {
205
+ if (!raw.startsWith(literal, index) || isEscaped(raw, index)) {
206
+ return null;
177
207
  }
208
+ return {
209
+ end: index + literal.length,
210
+ tokens: [tok(tokenType, literal, baseOffset + index)]
211
+ };
212
+ };
213
+ }
214
+ function tokenizeInlineWithMatchers(raw, baseOffset = 0, customMatchers = []) {
215
+ if (!raw) {
216
+ return [{ type: "text", text: "", start: baseOffset, end: baseOffset }];
178
217
  }
179
- segs.sort((a, b) => a.start - b.start);
180
- const result = [];
181
- let pos = 0;
182
- for (const seg of segs) {
183
- if (seg.start > pos) {
184
- result.push(tok("text", raw.slice(pos, seg.start), baseOffset + pos));
218
+ const tokens = [];
219
+ let textStart = 0;
220
+ let index = 0;
221
+ while (index < raw.length) {
222
+ const match = tryMatch(raw, index, baseOffset, customMatchers);
223
+ if (!match) {
224
+ index += 1;
225
+ continue;
226
+ }
227
+ if (index > textStart) {
228
+ tokens.push(tok("text", raw.slice(textStart, index), baseOffset + textStart));
185
229
  }
186
- result.push(...seg.tokens);
187
- pos = seg.end;
230
+ tokens.push(...match.tokens);
231
+ index = match.end;
232
+ textStart = index;
188
233
  }
189
- if (pos < raw.length) {
190
- result.push(tok("text", raw.slice(pos), baseOffset + pos));
234
+ if (textStart < raw.length) {
235
+ tokens.push(tok("text", raw.slice(textStart), baseOffset + textStart));
191
236
  }
192
- return result;
237
+ return tokens;
238
+ }
239
+ function tokenizeInline(raw, baseOffset = 0) {
240
+ return tokenizeInlineWithMatchers(raw, baseOffset);
193
241
  }
194
242
 
195
243
  // src/parser/blocks.ts
@@ -229,7 +277,7 @@ function tokenizeBlock(raw, blockType, baseOffset = 0) {
229
277
  }
230
278
  if (blockType === "table") {
231
279
  return tokenizeMultiLineBlock(raw, baseOffset, (line) => {
232
- return tokenizeInline(line, -1);
280
+ return tokenizeTableLine(line, -1);
233
281
  });
234
282
  }
235
283
  if (blockType === "thematic-break") {
@@ -251,13 +299,55 @@ function tokenizeBlock(raw, blockType, baseOffset = 0) {
251
299
  }
252
300
  const listMatch = raw.match(/^(\s*(?:[-*+]|\d+\.)\s)(.*)/);
253
301
  if (listMatch && (blockType === "unordered-list" || blockType === "ordered-list")) {
254
- return [
255
- { type: "list-marker", text: listMatch[1], start: baseOffset, end: baseOffset + listMatch[1].length },
256
- ...tokenizeInline(listMatch[2], baseOffset + listMatch[1].length)
257
- ];
302
+ return tokenizeListItem(listMatch[1], listMatch[2], baseOffset);
258
303
  }
259
304
  return tokenizeInline(raw, baseOffset);
260
305
  }
306
+ function tokenizeListItem(marker, content, baseOffset) {
307
+ const tokens = [
308
+ { type: "list-marker", text: marker, start: baseOffset, end: baseOffset + marker.length }
309
+ ];
310
+ const contentOffset = baseOffset + marker.length;
311
+ const leadingWhitespace = content.match(/^\s+/)?.[0] ?? "";
312
+ const taskCandidate = content.slice(leadingWhitespace.length);
313
+ const taskMatch = taskCandidate.match(/^(\[(?: |x|X)\])(\s*)(.*)$/);
314
+ let cursor = contentOffset;
315
+ if (leadingWhitespace) {
316
+ tokens.push({
317
+ type: "text",
318
+ text: leadingWhitespace,
319
+ start: cursor,
320
+ end: cursor + leadingWhitespace.length
321
+ });
322
+ cursor += leadingWhitespace.length;
323
+ }
324
+ if (!taskMatch) {
325
+ tokens.push(...tokenizeInline(taskCandidate, cursor));
326
+ return tokens;
327
+ }
328
+ const taskTokenType = /^[xX]$/.test(taskMatch[1][1]) ? "task-marker-checked" : "task-marker";
329
+ tokens.push({
330
+ type: taskTokenType,
331
+ text: taskMatch[1],
332
+ start: cursor,
333
+ end: cursor + taskMatch[1].length
334
+ });
335
+ cursor += taskMatch[1].length;
336
+ if (taskMatch[2]) {
337
+ tokens.push({
338
+ type: "text",
339
+ text: taskMatch[2],
340
+ start: cursor,
341
+ end: cursor + taskMatch[2].length
342
+ });
343
+ cursor += taskMatch[2].length;
344
+ }
345
+ tokens.push(...tokenizeInline(taskMatch[3], cursor));
346
+ return tokens;
347
+ }
348
+ function tokenizeTableLine(line, baseOffset) {
349
+ return tokenizeInlineWithMatchers(line, baseOffset, [TABLE_SEPARATOR_MATCHER]);
350
+ }
261
351
  function tokenizeMultiLineBlock(raw, baseOffset, classifyLine) {
262
352
  const lines = raw.split("\n");
263
353
  const tokens = [];
@@ -269,13 +359,27 @@ function tokenizeMultiLineBlock(raw, baseOffset, classifyLine) {
269
359
  offset += 1;
270
360
  }
271
361
  const lineTokens = classifyLine(line, i, i === 0, i === lines.length - 1);
272
- let pos = offset;
273
- for (const t of lineTokens) {
274
- if (t.start === -1) {
275
- t.start = pos;
276
- t.end = pos + t.text.length;
362
+ if (lineTokens.length > 0 && lineTokens[0].start < 0) {
363
+ let pos = offset;
364
+ for (const token of lineTokens) {
365
+ if (token.start === -1 && token.end === -1) {
366
+ token.start = pos;
367
+ token.end = pos + token.text.length;
368
+ } else {
369
+ token.start = offset + token.start + 1;
370
+ token.end = offset + token.end + 1;
371
+ }
372
+ pos = token.end;
373
+ }
374
+ } else {
375
+ let pos = offset;
376
+ for (const token of lineTokens) {
377
+ if (token.start === -1) {
378
+ token.start = pos;
379
+ token.end = pos + token.text.length;
380
+ }
381
+ pos = token.end;
277
382
  }
278
- pos = t.end;
279
383
  }
280
384
  tokens.push(...lineTokens);
281
385
  offset += line.length;
@@ -311,6 +415,7 @@ function tokenizeCodeFence(raw, baseOffset) {
311
415
  }
312
416
  return tokens;
313
417
  }
418
+ var TABLE_SEPARATOR_MATCHER = createLiteralTokenMatcher("|", "table-separator");
314
419
 
315
420
  // src/model/document.ts
316
421
  function createBlockIdGenerator() {
@@ -2996,6 +3101,7 @@ function buildBlockquoteBarsBoxShadow(depth) {
2996
3101
  }
2997
3102
 
2998
3103
  // src/render/block-render.ts
3104
+ var TOKEN_CLASS_EXEMPTIONS = /* @__PURE__ */ new Set(["text"]);
2999
3105
  function applyBlockquoteBarsStyle(el, depth) {
3000
3106
  const shadow = buildBlockquoteBarsBoxShadow(depth);
3001
3107
  if (!shadow) return;
@@ -3018,6 +3124,9 @@ var TOKEN_TO_CLASS = {
3018
3124
  "image-url": "owo-syntax-link-url",
3019
3125
  "heading-marker": "owo-syntax-heading-marker",
3020
3126
  "list-marker": "owo-syntax-list-marker",
3127
+ "task-marker": "owo-syntax-task-marker",
3128
+ "task-marker-checked": "owo-syntax-task-marker-checked",
3129
+ "table-separator": "owo-syntax-table-separator",
3021
3130
  "blockquote-marker": "owo-syntax-blockquote-marker",
3022
3131
  "fence-marker": "owo-syntax-fence",
3023
3132
  "fence-lang": "owo-syntax-fence-lang",
@@ -3217,6 +3326,7 @@ export {
3217
3326
  expandWithContext,
3218
3327
  BQ_STEP,
3219
3328
  buildBlockquoteBarsBoxShadow,
3329
+ TOKEN_CLASS_EXEMPTIONS,
3220
3330
  TOKEN_TO_CLASS,
3221
3331
  BLOCK_TYPE_TO_CLASS,
3222
3332
  createBlockElement,
@@ -68,7 +68,9 @@ type CompositionState = {
68
68
  active: boolean;
69
69
  range: VirtualSelection | null;
70
70
  };
71
- type InlineTokenType = 'text' | 'strong-marker' | 'strong' | 'emphasis-marker' | 'emphasis' | 'code-marker' | 'code' | 'link-bracket' | 'link-text' | 'link-url' | 'image-marker' | 'image-alt' | 'image-url' | 'heading-marker' | 'list-marker' | 'blockquote-marker' | 'fence-marker' | 'fence-lang' | 'code-block-text' | 'strikethrough-marker' | 'strikethrough' | 'math-marker' | 'math-text' | 'hr' | 'html';
71
+ declare const INLINE_TOKEN_TYPES: readonly ["text", "strong-marker", "strong", "emphasis-marker", "emphasis", "code-marker", "code", "link-bracket", "link-text", "link-url", "image-marker", "image-alt", "image-url", "heading-marker", "list-marker", "task-marker", "task-marker-checked", "table-separator", "blockquote-marker", "fence-marker", "fence-lang", "code-block-text", "strikethrough-marker", "strikethrough", "math-marker", "math-text", "hr", "html"];
72
+ type InlineTokenType = (typeof INLINE_TOKEN_TYPES)[number];
73
+ declare const CLASSLESS_INLINE_TOKEN_TYPES: readonly ["text"];
72
74
  type InlineToken = {
73
75
  type: InlineTokenType;
74
76
  text: string;
@@ -466,4 +468,4 @@ type DomAdapterInstance = OwoMarkEditorInstance & {
466
468
  };
467
469
  declare function createDomAdapter(): DomAdapterInstance;
468
470
 
469
- export { isVirtualSelectionCollapsed as $, type JsonValue as A, type BlockNode as B, type CoreStateSnapshot as C, type DirtyRange as D, type OwoMarkCommands as E, type OwoMarkCore as F, type OwoMarkEditorInstance as G, type HeadingLevel as H, type InlineToken as I, type JsonPrimitive as J, type KeyDownIntent as K, type Leaf as L, type OwoMarkEditorLike as M, type OwoMarkSharedState as N, type OwoMarkSelection as O, type PreviewBlockKind as P, type OwoMarkSharedStateStore as Q, type PasteIntent as R, type SlashState as S, type PreviewDirtyReason as T, type SlashStateListener as U, type SlashTriggerInfo as V, type VirtualPosition as W, type VirtualSelection as X, applyMarkdownIndent as Y, createOwoMarkCore as Z, getBlockIndexForPosition as _, type BlockContextType as a, linearToVirtual as a0, linearToVirtualPosition as a1, resolveIndentSize as a2, virtualPositionToLinear as a3, virtualPositionsEqual as a4, virtualToLinear as a5, createDomAdapter as a6, type CommandRegistry as b, type OwoMarkDocument as c, type PreviewBlock as d, type BlockTransform as e, type OwoMarkSharedStateController as f, type InlineTokenType as g, type BeforeInputIntent as h, type BlockContext as i, type BlockContextListener as j, type BlockInsertType as k, type BlockType as l, type CommandContext as m, type CommandDefinition as n, type CompositionState as o, type CoreApplyAction as p, type CoreApplyResult as q, type CoreSelectionSnapshot as r, type CreateOwoMarkCoreOptions as s, type Decorator as t, type DecoratorType as u, type DocumentChangeCallback as v, type DomAdapterInstance as w, type HistoryEntry as x, type IndentMode as y, type IndentResult as z };
471
+ export { createOwoMarkCore as $, type IndentMode as A, type BlockNode as B, type CoreStateSnapshot as C, type DirtyRange as D, type IndentResult as E, type JsonValue as F, type OwoMarkCommands as G, type HeadingLevel as H, type InlineToken as I, type JsonPrimitive as J, type KeyDownIntent as K, type Leaf as L, type OwoMarkCore as M, type OwoMarkEditorInstance as N, type OwoMarkSelection as O, type PreviewBlockKind as P, type OwoMarkEditorLike as Q, type OwoMarkSharedState as R, type SlashState as S, type OwoMarkSharedStateStore as T, type PasteIntent as U, type PreviewDirtyReason as V, type SlashStateListener as W, type SlashTriggerInfo as X, type VirtualPosition as Y, type VirtualSelection as Z, applyMarkdownIndent as _, type BlockContextType as a, getBlockIndexForPosition as a0, isVirtualSelectionCollapsed as a1, linearToVirtual as a2, linearToVirtualPosition as a3, resolveIndentSize as a4, virtualPositionToLinear as a5, virtualPositionsEqual as a6, virtualToLinear as a7, createDomAdapter as a8, type CommandRegistry as b, type OwoMarkDocument as c, type PreviewBlock as d, type BlockTransform as e, type OwoMarkSharedStateController as f, type InlineTokenType as g, type BeforeInputIntent as h, type BlockContext as i, type BlockContextListener as j, type BlockInsertType as k, type BlockType as l, CLASSLESS_INLINE_TOKEN_TYPES as m, type CommandContext as n, type CommandDefinition as o, type CompositionState as p, type CoreApplyAction as q, type CoreApplyResult as r, type CoreSelectionSnapshot as s, type CreateOwoMarkCoreOptions as t, type Decorator as u, type DecoratorType as v, type DocumentChangeCallback as w, type DomAdapterInstance as x, type HistoryEntry as y, INLINE_TOKEN_TYPES as z };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BlockNode, a as BlockContextType, O as OwoMarkSelection, C as CoreStateSnapshot, S as SlashState, b as CommandRegistry, c as OwoMarkDocument, D as DirtyRange, P as PreviewBlockKind, d as PreviewBlock, e as BlockTransform, f as OwoMarkSharedStateController, I as InlineToken, g as InlineTokenType } from './dom-adapter-CTSJe5Uo.js';
2
- export { h as BeforeInputIntent, i as BlockContext, j as BlockContextListener, k as BlockInsertType, l as BlockType, m as CommandContext, n as CommandDefinition, o as CompositionState, p as CoreApplyAction, q as CoreApplyResult, r as CoreSelectionSnapshot, s as CreateOwoMarkCoreOptions, t as Decorator, u as DecoratorType, v as DocumentChangeCallback, w as DomAdapterInstance, H as HeadingLevel, x as HistoryEntry, y as IndentMode, z as IndentResult, J as JsonPrimitive, A as JsonValue, K as KeyDownIntent, L as Leaf, E as OwoMarkCommands, F as OwoMarkCore, G as OwoMarkEditorInstance, M as OwoMarkEditorLike, N as OwoMarkSharedState, Q as OwoMarkSharedStateStore, R as PasteIntent, T as PreviewDirtyReason, U as SlashStateListener, V as SlashTriggerInfo, W as VirtualPosition, X as VirtualSelection, Y as applyMarkdownIndent, Z as createOwoMarkCore, _ as getBlockIndexForPosition, $ as isVirtualSelectionCollapsed, a0 as linearToVirtual, a1 as linearToVirtualPosition, a2 as resolveIndentSize, a3 as virtualPositionToLinear, a4 as virtualPositionsEqual, a5 as virtualToLinear } from './dom-adapter-CTSJe5Uo.js';
1
+ import { B as BlockNode, a as BlockContextType, O as OwoMarkSelection, C as CoreStateSnapshot, S as SlashState, b as CommandRegistry, c as OwoMarkDocument, D as DirtyRange, P as PreviewBlockKind, d as PreviewBlock, e as BlockTransform, f as OwoMarkSharedStateController, I as InlineToken, g as InlineTokenType } from './dom-adapter-C8wuoffZ.js';
2
+ export { h as BeforeInputIntent, i as BlockContext, j as BlockContextListener, k as BlockInsertType, l as BlockType, m as CLASSLESS_INLINE_TOKEN_TYPES, n as CommandContext, o as CommandDefinition, p as CompositionState, q as CoreApplyAction, r as CoreApplyResult, s as CoreSelectionSnapshot, t as CreateOwoMarkCoreOptions, u as Decorator, v as DecoratorType, w as DocumentChangeCallback, x as DomAdapterInstance, H as HeadingLevel, y as HistoryEntry, z as INLINE_TOKEN_TYPES, A as IndentMode, E as IndentResult, J as JsonPrimitive, F as JsonValue, K as KeyDownIntent, L as Leaf, G as OwoMarkCommands, M as OwoMarkCore, N as OwoMarkEditorInstance, Q as OwoMarkEditorLike, R as OwoMarkSharedState, T as OwoMarkSharedStateStore, U as PasteIntent, V as PreviewDirtyReason, W as SlashStateListener, X as SlashTriggerInfo, Y as VirtualPosition, Z as VirtualSelection, _ as applyMarkdownIndent, $ as createOwoMarkCore, a0 as getBlockIndexForPosition, a1 as isVirtualSelectionCollapsed, a2 as linearToVirtual, a3 as linearToVirtualPosition, a4 as resolveIndentSize, a5 as virtualPositionToLinear, a6 as virtualPositionsEqual, a7 as virtualToLinear } from './dom-adapter-C8wuoffZ.js';
3
3
  export { WordBoundaryResult, deleteToLineEnd, deleteToLineStart, deleteWordBackward, deleteWordForward } from './internal/commands/word-boundary.js';
4
4
  export { normalizeMarkdownPaste } from './internal/clipboard/paste.js';
5
5
  export { enableMapSet, produce } from 'immer';
@@ -158,7 +158,7 @@ declare function createSharedStateStore(options?: CreateSharedStateOptions): Owo
158
158
 
159
159
  /**
160
160
  * Tokenize inline Markdown content into decoration tokens.
161
- * Pure function, no DOM dependency.
161
+ * Single-pass scanner with explicit priority and stable offsets.
162
162
  */
163
163
  declare function tokenizeInline(raw: string, baseOffset?: number): InlineToken[];
164
164
 
@@ -324,6 +324,7 @@ declare function detectAndRenderDirty(root: HTMLElement, oldDoc: OwoMarkDocument
324
324
  * Each block is a <div data-owo-block="index"> containing text/span nodes.
325
325
  */
326
326
 
327
+ declare const TOKEN_CLASS_EXEMPTIONS: Set<"text" | "strong-marker" | "strong" | "emphasis-marker" | "emphasis" | "code-marker" | "code" | "link-bracket" | "link-text" | "link-url" | "image-marker" | "image-alt" | "image-url" | "heading-marker" | "list-marker" | "task-marker" | "task-marker-checked" | "table-separator" | "blockquote-marker" | "fence-marker" | "fence-lang" | "code-block-text" | "strikethrough-marker" | "strikethrough" | "math-marker" | "math-text" | "hr" | "html">;
327
328
  declare const TOKEN_TO_CLASS: Record<InlineTokenType, string>;
328
329
  declare const BLOCK_TYPE_TO_CLASS: Record<string, string>;
329
330
  declare function createBlockElement(doc: Document, tokens: InlineToken[], blockIndex: number, blockType: string, headingLevel?: number, depth?: number): HTMLDivElement;
@@ -362,4 +363,4 @@ declare function buildVirtualRows(blocks: readonly BlockNode[], heightCache: Map
362
363
  /** Compute the visible range given scroll state. */
363
364
  declare function computeVisibleRange(rows: VirtualRow[], scrollTop: number, viewportHeight: number, overscan?: number): VisibleRange;
364
365
 
365
- export { BLOCK_TYPE_TO_CLASS, BQ_STEP, BlockContextType, type BlockIdGenerator, BlockNode, BlockTransform, CommandRegistry, type CommandResult, type CoreEventHub, type CoreSlashStateListener, CoreStateSnapshot, type CreateSharedStateOptions, DirtyRange, type ImageSizeSyntax, InlineToken, InlineTokenType, NOT_HANDLED, OwoMarkDocument, OwoMarkSelection, OwoMarkSharedStateController, PreviewBlock, PreviewBlockKind, SlashState, TOKEN_TO_CLASS, type VirtualRow, type VisibleRange, buildBlockquoteBarsBoxShadow, buildVirtualRows, computePreviewDirtyRange, computeVisibleRange, createBlockElement, createBlockIdGenerator, createCommandRegistry, createImageSizeTransform, createSharedStateStore, deriveBlockId, deriveRenderKey, deriveSourceKey, detectAndRenderDirty, domRangeToOffset, estimateEditorBlockHeight, expandDirtyRange, expandWithContext, fullRender, getBlockAtOffset, getBlockById, getBlockIndexById, getBlockStartOffset, handleCharInput, handleMarkdownEnter, handleSmartBackspace, handleSmartDelete, insertCodeFence, insertImage, insertLink, insertMathBlock, insertSideAnnotation, insertTable, invalidateBlockCache, offsetToDomRange, parseMarkdownToDocument, patchDirtyBlocks, projectToPreviewBlocks, readSelection, reconcileBlocks, resetBlockIdCounter, resolveBlockContextType, restoreSelection, serializeDocument, toggleBold, toggleItalic, tokenizeBlock, tokenizeInline, updateBlockElement };
366
+ export { BLOCK_TYPE_TO_CLASS, BQ_STEP, BlockContextType, type BlockIdGenerator, BlockNode, BlockTransform, CommandRegistry, type CommandResult, type CoreEventHub, type CoreSlashStateListener, CoreStateSnapshot, type CreateSharedStateOptions, DirtyRange, type ImageSizeSyntax, InlineToken, InlineTokenType, NOT_HANDLED, OwoMarkDocument, OwoMarkSelection, OwoMarkSharedStateController, PreviewBlock, PreviewBlockKind, SlashState, TOKEN_CLASS_EXEMPTIONS, TOKEN_TO_CLASS, type VirtualRow, type VisibleRange, buildBlockquoteBarsBoxShadow, buildVirtualRows, computePreviewDirtyRange, computeVisibleRange, createBlockElement, createBlockIdGenerator, createCommandRegistry, createImageSizeTransform, createSharedStateStore, deriveBlockId, deriveRenderKey, deriveSourceKey, detectAndRenderDirty, domRangeToOffset, estimateEditorBlockHeight, expandDirtyRange, expandWithContext, fullRender, getBlockAtOffset, getBlockById, getBlockIndexById, getBlockStartOffset, handleCharInput, handleMarkdownEnter, handleSmartBackspace, handleSmartDelete, insertCodeFence, insertImage, insertLink, insertMathBlock, insertSideAnnotation, insertTable, invalidateBlockCache, offsetToDomRange, parseMarkdownToDocument, patchDirtyBlocks, projectToPreviewBlocks, readSelection, reconcileBlocks, resetBlockIdCounter, resolveBlockContextType, restoreSelection, serializeDocument, toggleBold, toggleItalic, tokenizeBlock, tokenizeInline, updateBlockElement };
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  NOT_HANDLED,
5
5
  SIDE_ANNOTATION_TAIL_RE,
6
6
  SIDE_CONTINUATION_TAIL_RE,
7
+ TOKEN_CLASS_EXEMPTIONS,
7
8
  TOKEN_TO_CLASS,
8
9
  applyMarkdownIndent,
9
10
  buildBlockquoteBarsBoxShadow,
@@ -53,7 +54,7 @@ import {
53
54
  virtualPositionToLinear,
54
55
  virtualPositionsEqual,
55
56
  virtualToLinear
56
- } from "./chunk-TRLKIMRD.js";
57
+ } from "./chunk-6CBUAORJ.js";
57
58
  import {
58
59
  normalizeMarkdownPaste
59
60
  } from "./chunk-BGXCXQZP.js";
@@ -64,6 +65,39 @@ import {
64
65
  deleteWordForward
65
66
  } from "./chunk-MPIWZLI3.js";
66
67
 
68
+ // src/types/public.ts
69
+ var INLINE_TOKEN_TYPES = [
70
+ "text",
71
+ "strong-marker",
72
+ "strong",
73
+ "emphasis-marker",
74
+ "emphasis",
75
+ "code-marker",
76
+ "code",
77
+ "link-bracket",
78
+ "link-text",
79
+ "link-url",
80
+ "image-marker",
81
+ "image-alt",
82
+ "image-url",
83
+ "heading-marker",
84
+ "list-marker",
85
+ "task-marker",
86
+ "task-marker-checked",
87
+ "table-separator",
88
+ "blockquote-marker",
89
+ "fence-marker",
90
+ "fence-lang",
91
+ "code-block-text",
92
+ "strikethrough-marker",
93
+ "strikethrough",
94
+ "math-marker",
95
+ "math-text",
96
+ "hr",
97
+ "html"
98
+ ];
99
+ var CLASSLESS_INLINE_TOKEN_TYPES = ["text"];
100
+
67
101
  // src/preview/block-id.ts
68
102
  function deriveBlockId(renderKey, occurrenceIndex) {
69
103
  return `${renderKey}#${occurrenceIndex}`;
@@ -590,7 +624,10 @@ function computeVisibleRange(rows, scrollTop, viewportHeight, overscan = 5) {
590
624
  export {
591
625
  BLOCK_TYPE_TO_CLASS,
592
626
  BQ_STEP,
627
+ CLASSLESS_INLINE_TOKEN_TYPES,
628
+ INLINE_TOKEN_TYPES,
593
629
  NOT_HANDLED,
630
+ TOKEN_CLASS_EXEMPTIONS,
594
631
  TOKEN_TO_CLASS,
595
632
  applyMarkdownIndent,
596
633
  buildBlockquoteBarsBoxShadow,
@@ -1 +1 @@
1
- export { v as DocumentChangeCallback, w as DomAdapterInstance, a6 as createDomAdapter } from '../dom-adapter-CTSJe5Uo.js';
1
+ export { w as DocumentChangeCallback, x as DomAdapterInstance, a8 as createDomAdapter } from '../dom-adapter-C8wuoffZ.js';
@@ -4,7 +4,7 @@ import {
4
4
  fullRender,
5
5
  readSelection,
6
6
  restoreSelection
7
- } from "../chunk-TRLKIMRD.js";
7
+ } from "../chunk-6CBUAORJ.js";
8
8
  import "../chunk-BGXCXQZP.js";
9
9
  import "../chunk-MPIWZLI3.js";
10
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owomark/core",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Framework-agnostic core engine for the OwoMark editor.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",