@texuli/blocks 0.0.0-stage → 0.1.0-next.0

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.
Files changed (257) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -2
  3. package/dist/code/CodeBlockView.svelte +135 -0
  4. package/dist/code/CodeBlockView.svelte.d.ts +5 -0
  5. package/dist/code/check.d.ts +15 -0
  6. package/dist/code/check.js +14 -0
  7. package/dist/code/code.css +201 -0
  8. package/dist/code/code.css.d.ts +1 -0
  9. package/dist/code/engine-entry.d.ts +10 -0
  10. package/dist/code/engine-entry.js +10 -0
  11. package/dist/code/engine.d.ts +18 -0
  12. package/dist/code/engine.js +18 -0
  13. package/dist/code/family-engine.d.ts +23 -0
  14. package/dist/code/family-engine.js +4 -0
  15. package/dist/code/family.d.ts +7 -0
  16. package/dist/code/family.js +5 -0
  17. package/dist/code/grammars.d.ts +12 -0
  18. package/dist/code/grammars.js +83 -0
  19. package/dist/code/highlight.d.ts +15 -0
  20. package/dist/code/highlight.js +53 -0
  21. package/dist/code/index.d.ts +13 -0
  22. package/dist/code/index.js +12 -0
  23. package/dist/code/labels.d.ts +27 -0
  24. package/dist/code/labels.js +24 -0
  25. package/dist/code/languages/bash.d.ts +3 -0
  26. package/dist/code/languages/bash.js +48 -0
  27. package/dist/code/languages/css.d.ts +10 -0
  28. package/dist/code/languages/css.js +67 -0
  29. package/dist/code/languages/html.d.ts +6 -0
  30. package/dist/code/languages/html.js +35 -0
  31. package/dist/code/languages/javascript.d.ts +3 -0
  32. package/dist/code/languages/javascript.js +113 -0
  33. package/dist/code/languages/json.d.ts +3 -0
  34. package/dist/code/languages/json.js +24 -0
  35. package/dist/code/languages/python.d.ts +3 -0
  36. package/dist/code/languages/python.js +35 -0
  37. package/dist/code/languages/shared.d.ts +22 -0
  38. package/dist/code/languages/shared.js +37 -0
  39. package/dist/code/languages/sql.d.ts +3 -0
  40. package/dist/code/languages/sql.js +32 -0
  41. package/dist/code/languages/yaml.d.ts +7 -0
  42. package/dist/code/languages/yaml.js +36 -0
  43. package/dist/code/renderers.d.ts +5 -0
  44. package/dist/code/renderers.js +5 -0
  45. package/dist/code/token-styles.d.ts +25 -0
  46. package/dist/code/token-styles.js +51 -0
  47. package/dist/code/tokenize-code.d.ts +17 -0
  48. package/dist/code/tokenize-code.js +34 -0
  49. package/dist/code/tokenizer.d.ts +76 -0
  50. package/dist/code/tokenizer.js +171 -0
  51. package/dist/core/catalog/entries.d.ts +10 -0
  52. package/dist/core/catalog/entries.js +589 -0
  53. package/dist/core/catalog/index.d.ts +4 -0
  54. package/dist/core/catalog/index.js +2 -0
  55. package/dist/core/catalog/types.d.ts +36 -0
  56. package/dist/core/catalog/types.js +1 -0
  57. package/dist/core/catalog/validate.d.ts +15 -0
  58. package/dist/core/catalog/validate.js +46 -0
  59. package/dist/core/formula/evaluate.d.ts +14 -0
  60. package/dist/core/formula/evaluate.js +181 -0
  61. package/dist/core/formula/index.d.ts +8 -0
  62. package/dist/core/formula/index.js +6 -0
  63. package/dist/core/formula/parse.d.ts +19 -0
  64. package/dist/core/formula/parse.js +452 -0
  65. package/dist/core/formula/types.d.ts +76 -0
  66. package/dist/core/formula/types.js +7 -0
  67. package/dist/core/index.d.ts +14 -0
  68. package/dist/core/index.js +13 -0
  69. package/dist/core/limits.d.ts +27 -0
  70. package/dist/core/limits.js +26 -0
  71. package/dist/core/safety.d.ts +30 -0
  72. package/dist/core/safety.js +110 -0
  73. package/dist/core/schema/blocks.d.ts +138 -0
  74. package/dist/core/schema/blocks.js +181 -0
  75. package/dist/core/schema/code-family.d.ts +4 -0
  76. package/dist/core/schema/code-family.js +75 -0
  77. package/dist/core/schema/line-spec.d.ts +7 -0
  78. package/dist/core/schema/line-spec.js +19 -0
  79. package/dist/core/schema/media-family.d.ts +4 -0
  80. package/dist/core/schema/media-family.js +260 -0
  81. package/dist/core/schema/parse-family.d.ts +14 -0
  82. package/dist/core/schema/parse-family.js +37 -0
  83. package/dist/core/schema/primitives.d.ts +73 -0
  84. package/dist/core/schema/primitives.js +140 -0
  85. package/dist/core/schema/text-family.d.ts +4 -0
  86. package/dist/core/schema/text-family.js +121 -0
  87. package/dist/core/schema/vocabulary.d.ts +20 -0
  88. package/dist/core/schema/vocabulary.js +33 -0
  89. package/dist/core/text.d.ts +31 -0
  90. package/dist/core/text.js +139 -0
  91. package/dist/core/untrusted.d.ts +20 -0
  92. package/dist/core/untrusted.js +377 -0
  93. package/dist/css-modules.d.ts +1 -0
  94. package/dist/css.d.ts +1 -0
  95. package/dist/data/ChartBlockView.svelte +77 -0
  96. package/dist/data/ChartBlockView.svelte.d.ts +10 -0
  97. package/dist/data/DataBlockView.svelte +109 -0
  98. package/dist/data/DataBlockView.svelte.d.ts +5 -0
  99. package/dist/data/check.d.ts +10 -0
  100. package/dist/data/check.js +9 -0
  101. package/dist/data/engine.d.ts +18 -0
  102. package/dist/data/engine.js +10 -0
  103. package/dist/data/family.d.ts +6 -0
  104. package/dist/data/family.js +4 -0
  105. package/dist/data/index.d.ts +9 -0
  106. package/dist/data/index.js +8 -0
  107. package/dist/data/labels.d.ts +8 -0
  108. package/dist/data/labels.js +8 -0
  109. package/dist/data/renderers.d.ts +2 -0
  110. package/dist/data/renderers.js +2 -0
  111. package/dist/data/schema.d.ts +84 -0
  112. package/dist/data/schema.js +385 -0
  113. package/dist/diagram/BoardDiagram.svelte +48 -0
  114. package/dist/diagram/BoardDiagram.svelte.d.ts +8 -0
  115. package/dist/diagram/DiagramFamily.svelte +46 -0
  116. package/dist/diagram/DiagramFamily.svelte.d.ts +10 -0
  117. package/dist/diagram/FlowDiagram.svelte +108 -0
  118. package/dist/diagram/FlowDiagram.svelte.d.ts +8 -0
  119. package/dist/diagram/TerminalDiagram.svelte +38 -0
  120. package/dist/diagram/TerminalDiagram.svelte.d.ts +8 -0
  121. package/dist/diagram/TreeDiagram.svelte +149 -0
  122. package/dist/diagram/TreeDiagram.svelte.d.ts +8 -0
  123. package/dist/diagram/diagram.css +287 -0
  124. package/dist/diagram/diagram.css.d.ts +1 -0
  125. package/dist/diagram/engine.d.ts +16 -0
  126. package/dist/diagram/engine.js +14 -0
  127. package/dist/diagram/family.d.ts +7 -0
  128. package/dist/diagram/family.js +5 -0
  129. package/dist/diagram/index.d.ts +10 -0
  130. package/dist/diagram/index.js +9 -0
  131. package/dist/diagram/layout.d.ts +26 -0
  132. package/dist/diagram/layout.js +165 -0
  133. package/dist/diagram/schema.d.ts +74 -0
  134. package/dist/diagram/schema.js +358 -0
  135. package/dist/diagram/tones.d.ts +6 -0
  136. package/dist/diagram/tones.js +16 -0
  137. package/dist/embed/EmbedApp.svelte +138 -0
  138. package/dist/embed/EmbedApp.svelte.d.ts +17 -0
  139. package/dist/embed/EmbedBlockView.svelte +32 -0
  140. package/dist/embed/EmbedBlockView.svelte.d.ts +5 -0
  141. package/dist/embed/LinkPreview.svelte +48 -0
  142. package/dist/embed/LinkPreview.svelte.d.ts +10 -0
  143. package/dist/embed/engine.d.ts +30 -0
  144. package/dist/embed/engine.js +17 -0
  145. package/dist/embed/family.d.ts +7 -0
  146. package/dist/embed/family.js +5 -0
  147. package/dist/embed/index.d.ts +5 -0
  148. package/dist/embed/index.js +3 -0
  149. package/dist/embed/renderers.d.ts +3 -0
  150. package/dist/embed/renderers.js +3 -0
  151. package/dist/embed/sandbox.d.ts +86 -0
  152. package/dist/embed/sandbox.js +114 -0
  153. package/dist/embed/schema.d.ts +30 -0
  154. package/dist/embed/schema.js +217 -0
  155. package/dist/index.d.ts +16 -0
  156. package/dist/index.js +15 -0
  157. package/dist/interactive/CalculatorBlock.svelte +61 -0
  158. package/dist/interactive/CalculatorBlock.svelte.d.ts +10 -0
  159. package/dist/interactive/ChecklistBlock.svelte +44 -0
  160. package/dist/interactive/ChecklistBlock.svelte.d.ts +10 -0
  161. package/dist/interactive/InteractiveBlockView.svelte +31 -0
  162. package/dist/interactive/InteractiveBlockView.svelte.d.ts +5 -0
  163. package/dist/interactive/PollBlock.svelte +111 -0
  164. package/dist/interactive/PollBlock.svelte.d.ts +10 -0
  165. package/dist/interactive/QuizBlock.svelte +75 -0
  166. package/dist/interactive/QuizBlock.svelte.d.ts +10 -0
  167. package/dist/interactive/check.d.ts +10 -0
  168. package/dist/interactive/check.js +9 -0
  169. package/dist/interactive/engine.d.ts +19 -0
  170. package/dist/interactive/engine.js +12 -0
  171. package/dist/interactive/family.d.ts +6 -0
  172. package/dist/interactive/family.js +4 -0
  173. package/dist/interactive/index.d.ts +13 -0
  174. package/dist/interactive/index.js +13 -0
  175. package/dist/interactive/interactive.css +97 -0
  176. package/dist/interactive/interactive.css.d.ts +1 -0
  177. package/dist/interactive/labels.d.ts +16 -0
  178. package/dist/interactive/labels.js +16 -0
  179. package/dist/interactive/renderers.d.ts +9 -0
  180. package/dist/interactive/renderers.js +9 -0
  181. package/dist/interactive/schema.d.ts +76 -0
  182. package/dist/interactive/schema.js +324 -0
  183. package/dist/map/MapBlockView.svelte +465 -0
  184. package/dist/map/MapBlockView.svelte.d.ts +5 -0
  185. package/dist/map/check.d.ts +11 -0
  186. package/dist/map/check.js +6 -0
  187. package/dist/map/engine.d.ts +19 -0
  188. package/dist/map/engine.js +8 -0
  189. package/dist/map/family.d.ts +7 -0
  190. package/dist/map/family.js +5 -0
  191. package/dist/map/index.d.ts +11 -0
  192. package/dist/map/index.js +10 -0
  193. package/dist/map/labels.d.ts +27 -0
  194. package/dist/map/labels.js +21 -0
  195. package/dist/map/renderers.d.ts +2 -0
  196. package/dist/map/renderers.js +2 -0
  197. package/dist/map/schema.d.ts +41 -0
  198. package/dist/map/schema.js +176 -0
  199. package/dist/map/view-model.d.ts +55 -0
  200. package/dist/map/view-model.js +168 -0
  201. package/dist/media/MediaBlockView.svelte +258 -0
  202. package/dist/media/MediaBlockView.svelte.d.ts +5 -0
  203. package/dist/media/check.d.ts +14 -0
  204. package/dist/media/check.js +13 -0
  205. package/dist/media/engine.d.ts +18 -0
  206. package/dist/media/engine.js +10 -0
  207. package/dist/media/family.d.ts +7 -0
  208. package/dist/media/family.js +5 -0
  209. package/dist/media/index.d.ts +11 -0
  210. package/dist/media/index.js +10 -0
  211. package/dist/media/labels.d.ts +7 -0
  212. package/dist/media/labels.js +12 -0
  213. package/dist/media/renderers.d.ts +5 -0
  214. package/dist/media/renderers.js +5 -0
  215. package/dist/media/resolve.d.ts +6 -0
  216. package/dist/media/resolve.js +15 -0
  217. package/dist/structure/NestedBlocks.svelte +65 -0
  218. package/dist/structure/NestedBlocks.svelte.d.ts +11 -0
  219. package/dist/structure/SafeBody.svelte +13 -0
  220. package/dist/structure/SafeBody.svelte.d.ts +7 -0
  221. package/dist/structure/StructureFamily.svelte +157 -0
  222. package/dist/structure/StructureFamily.svelte.d.ts +5 -0
  223. package/dist/structure/check.d.ts +14 -0
  224. package/dist/structure/check.js +27 -0
  225. package/dist/structure/engine.d.ts +18 -0
  226. package/dist/structure/engine.js +18 -0
  227. package/dist/structure/family.d.ts +7 -0
  228. package/dist/structure/family.js +5 -0
  229. package/dist/structure/index.d.ts +11 -0
  230. package/dist/structure/index.js +10 -0
  231. package/dist/structure/labels.d.ts +11 -0
  232. package/dist/structure/labels.js +11 -0
  233. package/dist/structure/renderers.d.ts +5 -0
  234. package/dist/structure/renderers.js +5 -0
  235. package/dist/structure/schema.d.ts +71 -0
  236. package/dist/structure/schema.js +327 -0
  237. package/dist/structure/structure.css +182 -0
  238. package/dist/structure/structure.css.d.ts +1 -0
  239. package/dist/text/RichText.svelte +169 -0
  240. package/dist/text/RichText.svelte.d.ts +13 -0
  241. package/dist/text/TextBlockView.svelte +177 -0
  242. package/dist/text/TextBlockView.svelte.d.ts +5 -0
  243. package/dist/text/check.d.ts +14 -0
  244. package/dist/text/check.js +13 -0
  245. package/dist/text/engine.d.ts +17 -0
  246. package/dist/text/engine.js +10 -0
  247. package/dist/text/family.d.ts +7 -0
  248. package/dist/text/family.js +5 -0
  249. package/dist/text/index.d.ts +12 -0
  250. package/dist/text/index.js +11 -0
  251. package/dist/text/labels.d.ts +22 -0
  252. package/dist/text/labels.js +29 -0
  253. package/dist/text/markdown.d.ts +80 -0
  254. package/dist/text/markdown.js +361 -0
  255. package/dist/text/renderers.d.ts +6 -0
  256. package/dist/text/renderers.js +6 -0
  257. package/package.json +167 -4
@@ -0,0 +1,361 @@
1
+ import { safeHref } from '@texuli/core';
2
+ /** Nesting and size caps: hostile input degrades to literal text, never recursion blowups. */
3
+ export const MARKDOWN_LIMITS = /* @__PURE__ */ Object.freeze({
4
+ /**
5
+ * Longest source parsed, equal to the schema's markdown cap. Pathological
6
+ * inline input stays under ~50 ms at this size.
7
+ */
8
+ source: 4_000,
9
+ /** Nested quotes and lists. */
10
+ blockDepth: 4,
11
+ /** Nested emphasis and links. */
12
+ inlineDepth: 6,
13
+ });
14
+ const FENCE = /^ {0,3}(`{3,}|~{3,})\s*([a-z][a-z0-9+-]{0,31})?\s*$/i;
15
+ const HEADING = /^ {0,3}(#{1,6})(?:[ \t]+(.*?))?[ \t]*#*[ \t]*$/;
16
+ const RULE = /^ {0,3}([-*_])(?:[ \t]*\1){2,}[ \t]*$/;
17
+ const QUOTE = /^ {0,3}> ?(.*)$/;
18
+ const BULLET = /^( {0,3})([-*+])[ \t]+(.*)$/;
19
+ const ORDERED = /^( {0,3})(\d{1,9})[.)][ \t]+(.*)$/;
20
+ const TASK = /^\[([ xX])\][ \t]+/;
21
+ /** Parses validated block text into the closed Markdown tree. */
22
+ export function parseMarkdown(source) {
23
+ const text = String(source).slice(0, MARKDOWN_LIMITS.source).replace(/\r\n?/g, '\n');
24
+ return { blocks: parseBlocks(text.split('\n'), 0) };
25
+ }
26
+ function isBlank(line) {
27
+ return line.trim() === '';
28
+ }
29
+ function listMarker(line) {
30
+ const bullet = BULLET.exec(line);
31
+ if (bullet)
32
+ return { ordered: false, start: 1, content: bullet[3] ?? '' };
33
+ const ordered = ORDERED.exec(line);
34
+ if (ordered)
35
+ return { ordered: true, start: Number(ordered[2]), content: ordered[3] ?? '' };
36
+ return null;
37
+ }
38
+ /** True when `line` starts a block other than a paragraph continuation. */
39
+ function startsBlock(line) {
40
+ return (FENCE.test(line) ||
41
+ HEADING.test(line) ||
42
+ RULE.test(line) ||
43
+ QUOTE.test(line) ||
44
+ listMarker(line) !== null);
45
+ }
46
+ function parseBlocks(lines, depth) {
47
+ const blocks = [];
48
+ let i = 0;
49
+ while (i < lines.length) {
50
+ const line = lines[i] ?? '';
51
+ if (isBlank(line)) {
52
+ i += 1;
53
+ continue;
54
+ }
55
+ const fence = FENCE.exec(line);
56
+ if (fence) {
57
+ const marker = fence[1] ?? '```';
58
+ const body = [];
59
+ i += 1;
60
+ while (i < lines.length && !(lines[i] ?? '').trim().startsWith(marker)) {
61
+ body.push(lines[i] ?? '');
62
+ i += 1;
63
+ }
64
+ i += 1; // closing fence (or end of input)
65
+ blocks.push({ type: 'code', lang: fence[2]?.toLowerCase(), text: body.join('\n') });
66
+ continue;
67
+ }
68
+ const heading = HEADING.exec(line);
69
+ if (heading) {
70
+ const level = (heading[1] ?? '#').length;
71
+ blocks.push({ type: 'heading', level, children: parseInline(heading[2] ?? '', 0) });
72
+ i += 1;
73
+ continue;
74
+ }
75
+ if (RULE.test(line)) {
76
+ blocks.push({ type: 'rule' });
77
+ i += 1;
78
+ continue;
79
+ }
80
+ if (QUOTE.test(line)) {
81
+ const inner = [];
82
+ while (i < lines.length && QUOTE.test(lines[i] ?? '')) {
83
+ inner.push(QUOTE.exec(lines[i] ?? '')?.[1] ?? '');
84
+ i += 1;
85
+ }
86
+ blocks.push(depth < MARKDOWN_LIMITS.blockDepth
87
+ ? { type: 'quote', children: parseBlocks(inner, depth + 1) }
88
+ : { type: 'paragraph', children: parseInline(inner.join('\n'), 0) });
89
+ continue;
90
+ }
91
+ const marker = listMarker(line);
92
+ if (marker) {
93
+ const parsed = parseList(lines, i, marker.ordered, marker.start, depth);
94
+ blocks.push(parsed.block);
95
+ i = parsed.next;
96
+ continue;
97
+ }
98
+ const paragraph = [line];
99
+ i += 1;
100
+ while (i < lines.length && !isBlank(lines[i] ?? '') && !startsBlock(lines[i] ?? '')) {
101
+ paragraph.push(lines[i] ?? '');
102
+ i += 1;
103
+ }
104
+ blocks.push({ type: 'paragraph', children: parseInline(paragraph.join('\n'), 0) });
105
+ }
106
+ return blocks;
107
+ }
108
+ function parseList(lines, from, ordered, start, depth) {
109
+ const items = [];
110
+ let i = from;
111
+ while (i < lines.length) {
112
+ const marker = listMarker(lines[i] ?? '');
113
+ if (!marker || marker.ordered !== ordered)
114
+ break;
115
+ const body = [marker.content];
116
+ i += 1;
117
+ // Continuation: indented lines (nested lists, wrapped text) and lazy
118
+ // paragraph lines that do not start another block.
119
+ while (i < lines.length) {
120
+ const next = lines[i] ?? '';
121
+ if (isBlank(next)) {
122
+ const after = lines[i + 1] ?? '';
123
+ if (/^ {2,}\S/.test(after)) {
124
+ body.push('');
125
+ i += 1;
126
+ continue;
127
+ }
128
+ break;
129
+ }
130
+ if (/^ {2,}\S/.test(next)) {
131
+ body.push(next.replace(/^ {2,4}/, ''));
132
+ i += 1;
133
+ continue;
134
+ }
135
+ if (startsBlock(next))
136
+ break;
137
+ body.push(next);
138
+ i += 1;
139
+ }
140
+ let checked = null;
141
+ const task = TASK.exec(body[0] ?? '');
142
+ if (task) {
143
+ checked = task[1] !== ' ';
144
+ body[0] = (body[0] ?? '').slice(task[0].length);
145
+ }
146
+ const children = depth < MARKDOWN_LIMITS.blockDepth
147
+ ? parseBlocks(body, depth + 1)
148
+ : [{ type: 'paragraph', children: parseInline(body.join('\n'), 0) }];
149
+ items.push({ checked, children });
150
+ }
151
+ return { block: { type: 'list', ordered, start, items }, next: i };
152
+ }
153
+ const ESCAPABLE = /[\\`*_{}[\]()#+\-.!~<>|]/;
154
+ /** Parses inline Markdown; `depth` caps nested emphasis and links. */
155
+ export function parseInline(source, depth, inLink = false) {
156
+ const out = [];
157
+ let buffer = '';
158
+ const flush = () => {
159
+ if (buffer)
160
+ out.push({ type: 'text', text: buffer });
161
+ buffer = '';
162
+ };
163
+ let i = 0;
164
+ while (i < source.length) {
165
+ const ch = source[i] ?? '';
166
+ if (ch === '\\') {
167
+ const next = source[i + 1] ?? '';
168
+ if (next === '\n') {
169
+ flush();
170
+ out.push({ type: 'break' });
171
+ i += 2;
172
+ continue;
173
+ }
174
+ if (ESCAPABLE.test(next)) {
175
+ buffer += next;
176
+ i += 2;
177
+ continue;
178
+ }
179
+ }
180
+ if (ch === '\n') {
181
+ if (/ {2,}$/.test(buffer)) {
182
+ buffer = buffer.replace(/ +$/, '');
183
+ flush();
184
+ out.push({ type: 'break' });
185
+ }
186
+ else {
187
+ buffer += '\n';
188
+ }
189
+ i += 1;
190
+ continue;
191
+ }
192
+ if (ch === '`') {
193
+ const run = /^`+/.exec(source.slice(i))?.[0] ?? '`';
194
+ const close = source.indexOf(run, i + run.length);
195
+ if (close !== -1) {
196
+ flush();
197
+ const code = source.slice(i + run.length, close).replace(/\n/g, ' ');
198
+ out.push({
199
+ type: 'code',
200
+ text: code.length > 2 && /^ .* $/.test(code) ? code.slice(1, -1) : code,
201
+ });
202
+ i = close + run.length;
203
+ continue;
204
+ }
205
+ buffer += run;
206
+ i += run.length;
207
+ continue;
208
+ }
209
+ if (depth < MARKDOWN_LIMITS.inlineDepth) {
210
+ const emphasis = matchEmphasis(source, i);
211
+ if (emphasis) {
212
+ flush();
213
+ out.push({
214
+ type: emphasis.type,
215
+ children: parseInline(source.slice(emphasis.innerStart, emphasis.innerEnd), depth + 1, inLink),
216
+ });
217
+ i = emphasis.end;
218
+ continue;
219
+ }
220
+ if (ch === '!' && source[i + 1] === '[') {
221
+ const image = matchLink(source, i + 1);
222
+ if (image) {
223
+ // Images are not loaded from text blocks: keep the alt text only.
224
+ buffer += source.slice(image.labelStart, image.labelEnd);
225
+ i = image.end;
226
+ continue;
227
+ }
228
+ }
229
+ if (ch === '[' && !inLink) {
230
+ const link = matchLink(source, i);
231
+ if (link) {
232
+ flush();
233
+ out.push({
234
+ type: 'link',
235
+ href: safeHref(link.href),
236
+ children: parseInline(source.slice(link.labelStart, link.labelEnd), depth + 1, true),
237
+ });
238
+ i = link.end;
239
+ continue;
240
+ }
241
+ }
242
+ if (ch === '<' && !inLink) {
243
+ const auto = /^<((?:https?:\/\/|mailto:)[^\s<>]+)>/i.exec(source.slice(i));
244
+ if (auto?.[1]) {
245
+ flush();
246
+ out.push({
247
+ type: 'link',
248
+ href: safeHref(auto[1]),
249
+ children: [{ type: 'text', text: auto[1] }],
250
+ });
251
+ i += auto[0].length;
252
+ continue;
253
+ }
254
+ }
255
+ }
256
+ buffer += ch;
257
+ i += 1;
258
+ }
259
+ flush();
260
+ return out;
261
+ }
262
+ function matchEmphasis(source, at) {
263
+ const candidates = [
264
+ { marker: '**', type: 'strong' },
265
+ { marker: '__', type: 'strong' },
266
+ { marker: '~~', type: 'del' },
267
+ { marker: '*', type: 'em' },
268
+ { marker: '_', type: 'em' },
269
+ ];
270
+ for (const { marker, type } of candidates) {
271
+ if (!source.startsWith(marker, at))
272
+ continue;
273
+ const innerStart = at + marker.length;
274
+ const first = source[innerStart] ?? '';
275
+ if (first === '' || /\s/.test(first))
276
+ continue;
277
+ // `_` inside a word (snake_case) is literal.
278
+ if (marker[0] === '_' && /[\p{L}\p{N}]/u.test(source[at - 1] ?? ''))
279
+ continue;
280
+ let close = source.indexOf(marker, innerStart + 1);
281
+ while (close !== -1) {
282
+ const before = source[close - 1] ?? '';
283
+ const after = source[close + marker.length] ?? '';
284
+ const doubled = marker.length === 1 && after === marker;
285
+ const midWord = marker[0] === '_' && /[\p{L}\p{N}]/u.test(after);
286
+ if (!/\s/.test(before) && before !== '\\' && !doubled && !midWord)
287
+ break;
288
+ close = source.indexOf(marker, close + (doubled ? 2 : 1));
289
+ }
290
+ if (close === -1)
291
+ continue;
292
+ return { type, innerStart, innerEnd: close, end: close + marker.length };
293
+ }
294
+ return null;
295
+ }
296
+ function matchLink(source, at) {
297
+ let level = 0;
298
+ let labelEnd = -1;
299
+ for (let j = at; j < source.length; j += 1) {
300
+ const c = source[j];
301
+ if (c === '\\') {
302
+ j += 1;
303
+ continue;
304
+ }
305
+ if (c === '[')
306
+ level += 1;
307
+ else if (c === ']') {
308
+ level -= 1;
309
+ if (level === 0) {
310
+ labelEnd = j;
311
+ break;
312
+ }
313
+ }
314
+ else if (c === '\n' && source[j + 1] === '\n')
315
+ return null;
316
+ }
317
+ if (labelEnd === -1 || source[labelEnd + 1] !== '(')
318
+ return null;
319
+ const target = /^\(\s*<?((?:[^\s()<>]|\([^\s()<>]*\))*)>?(?:\s+"[^"\n]*")?\s*\)/.exec(source.slice(labelEnd + 1));
320
+ if (!target)
321
+ return null;
322
+ return {
323
+ labelStart: at + 1,
324
+ labelEnd,
325
+ href: target[1] ?? '',
326
+ end: labelEnd + 1 + target[0].length,
327
+ };
328
+ }
329
+ /** Plain text of an inline tree (for accessible names and summaries). */
330
+ export function inlineText(nodes) {
331
+ let text = '';
332
+ for (const node of nodes) {
333
+ if (node.type === 'text' || node.type === 'code')
334
+ text += node.text;
335
+ else if (node.type === 'break')
336
+ text += '\n';
337
+ else
338
+ text += inlineText(node.children);
339
+ }
340
+ return text;
341
+ }
342
+ /**
343
+ * Distinct heading levels used anywhere in the tree, ascending. Renderers map
344
+ * them onto consecutive outline levels (`##` then `####` become h3 then h4).
345
+ */
346
+ export function headingLevels(blocks) {
347
+ const found = new Set();
348
+ const visit = (items) => {
349
+ for (const block of items) {
350
+ if (block.type === 'heading')
351
+ found.add(block.level);
352
+ else if (block.type === 'quote')
353
+ visit(block.children);
354
+ else if (block.type === 'list')
355
+ for (const item of block.items)
356
+ visit(item.children);
357
+ }
358
+ };
359
+ visit(blocks);
360
+ return [...found].sort((a, b) => a - b);
361
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Eager entry for hosts that render text blocks on first paint. Most hosts
3
+ * should prefer `loadTextFamily()` from `@texuli/blocks` (lazy chunk).
4
+ */
5
+ export { default as RichText } from './RichText.svelte';
6
+ export { default as TextBlockView } from './TextBlockView.svelte';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Eager entry for hosts that render text blocks on first paint. Most hosts
3
+ * should prefer `loadTextFamily()` from `@texuli/blocks` (lazy chunk).
4
+ */
5
+ export { default as RichText } from './RichText.svelte';
6
+ export { default as TextBlockView } from './TextBlockView.svelte';
package/package.json CHANGED
@@ -1,6 +1,169 @@
1
1
  {
2
2
  "name": "@texuli/blocks",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0-next.0",
4
+ "description": "Content blocks: closed vocabulary, untrusted guard, formula AST and catalog metadata for pages, documents and slides.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": [
8
+ "**/*.css"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "svelte": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./code": {
17
+ "types": "./dist/code/index.d.ts",
18
+ "default": "./dist/code/index.js"
19
+ },
20
+ "./code/engine": {
21
+ "types": "./dist/code/engine-entry.d.ts",
22
+ "default": "./dist/code/engine-entry.js"
23
+ },
24
+ "./code/renderers": {
25
+ "types": "./dist/code/renderers.d.ts",
26
+ "svelte": "./dist/code/renderers.js",
27
+ "default": "./dist/code/renderers.js"
28
+ },
29
+ "./code/tokenizer": {
30
+ "types": "./dist/code/engine.d.ts",
31
+ "default": "./dist/code/engine.js"
32
+ },
33
+ "./core": {
34
+ "types": "./dist/core/index.d.ts",
35
+ "default": "./dist/core/index.js"
36
+ },
37
+ "./data": {
38
+ "types": "./dist/data/index.d.ts",
39
+ "default": "./dist/data/index.js"
40
+ },
41
+ "./data/engine": {
42
+ "types": "./dist/data/engine.d.ts",
43
+ "default": "./dist/data/engine.js"
44
+ },
45
+ "./data/renderers": {
46
+ "types": "./dist/data/renderers.d.ts",
47
+ "svelte": "./dist/data/renderers.js",
48
+ "default": "./dist/data/renderers.js"
49
+ },
50
+ "./diagram": {
51
+ "types": "./dist/diagram/index.d.ts",
52
+ "default": "./dist/diagram/index.js"
53
+ },
54
+ "./diagram/engine": {
55
+ "types": "./dist/diagram/engine.d.ts",
56
+ "default": "./dist/diagram/engine.js"
57
+ },
58
+ "./diagram/renderers": {
59
+ "types": "./dist/diagram/DiagramFamily.svelte.d.ts",
60
+ "svelte": "./dist/diagram/DiagramFamily.svelte",
61
+ "default": "./dist/diagram/DiagramFamily.svelte"
62
+ },
63
+ "./embed": {
64
+ "types": "./dist/embed/index.d.ts",
65
+ "svelte": "./dist/embed/index.js",
66
+ "default": "./dist/embed/index.js"
67
+ },
68
+ "./embed/engine": {
69
+ "types": "./dist/embed/engine.d.ts",
70
+ "default": "./dist/embed/engine.js"
71
+ },
72
+ "./embed/renderers": {
73
+ "types": "./dist/embed/renderers.d.ts",
74
+ "svelte": "./dist/embed/renderers.js",
75
+ "default": "./dist/embed/renderers.js"
76
+ },
77
+ "./formula": {
78
+ "types": "./dist/core/formula/index.d.ts",
79
+ "default": "./dist/core/formula/index.js"
80
+ },
81
+ "./interactive": {
82
+ "types": "./dist/interactive/index.d.ts",
83
+ "default": "./dist/interactive/index.js"
84
+ },
85
+ "./interactive/engine": {
86
+ "types": "./dist/interactive/engine.d.ts",
87
+ "default": "./dist/interactive/engine.js"
88
+ },
89
+ "./interactive/renderers": {
90
+ "types": "./dist/interactive/renderers.d.ts",
91
+ "svelte": "./dist/interactive/renderers.js",
92
+ "default": "./dist/interactive/renderers.js"
93
+ },
94
+ "./map": {
95
+ "types": "./dist/map/index.d.ts",
96
+ "default": "./dist/map/index.js"
97
+ },
98
+ "./map/engine": {
99
+ "types": "./dist/map/engine.d.ts",
100
+ "default": "./dist/map/engine.js"
101
+ },
102
+ "./map/renderers": {
103
+ "types": "./dist/map/renderers.d.ts",
104
+ "svelte": "./dist/map/renderers.js",
105
+ "default": "./dist/map/renderers.js"
106
+ },
107
+ "./media": {
108
+ "types": "./dist/media/index.d.ts",
109
+ "default": "./dist/media/index.js"
110
+ },
111
+ "./media/engine": {
112
+ "types": "./dist/media/engine.d.ts",
113
+ "default": "./dist/media/engine.js"
114
+ },
115
+ "./media/renderers": {
116
+ "types": "./dist/media/renderers.d.ts",
117
+ "svelte": "./dist/media/renderers.js",
118
+ "default": "./dist/media/renderers.js"
119
+ },
120
+ "./structure": {
121
+ "types": "./dist/structure/index.d.ts",
122
+ "default": "./dist/structure/index.js"
123
+ },
124
+ "./structure/engine": {
125
+ "types": "./dist/structure/engine.d.ts",
126
+ "default": "./dist/structure/engine.js"
127
+ },
128
+ "./structure/renderers": {
129
+ "types": "./dist/structure/renderers.d.ts",
130
+ "svelte": "./dist/structure/renderers.js",
131
+ "default": "./dist/structure/renderers.js"
132
+ },
133
+ "./text": {
134
+ "types": "./dist/text/index.d.ts",
135
+ "default": "./dist/text/index.js"
136
+ },
137
+ "./text/engine": {
138
+ "types": "./dist/text/engine.d.ts",
139
+ "default": "./dist/text/engine.js"
140
+ },
141
+ "./text/markdown": {
142
+ "types": "./dist/text/markdown.d.ts",
143
+ "default": "./dist/text/markdown.js"
144
+ },
145
+ "./text/renderers": {
146
+ "types": "./dist/text/renderers.d.ts",
147
+ "svelte": "./dist/text/renderers.js",
148
+ "default": "./dist/text/renderers.js"
149
+ }
150
+ },
151
+ "files": [
152
+ "dist"
153
+ ],
154
+ "dependencies": {
155
+ "@texuli/core": "0.1.0-next.0",
156
+ "@texuli/tokens": "0.1.0-next.0",
157
+ "texuli": "0.1.0-next.0",
158
+ "@texuli/charts": "0.1.0-next.0",
159
+ "@texuli/data": "0.1.0-next.0",
160
+ "@texuli/media": "0.1.0-next.0"
161
+ },
162
+ "peerDependencies": {
163
+ "svelte": "^5.57.2"
164
+ },
165
+ "publishConfig": {
166
+ "access": "public",
167
+ "tag": "next"
168
+ }
169
+ }