rapier-markdown-kit 1.1.51 → 1.1.54
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.
- package/dist/spec/md-marks.mjs +218 -0
- package/package.json +1 -1
- package/style.css +6 -0
package/dist/spec/md-marks.mjs
CHANGED
|
@@ -258,6 +258,224 @@ export function pairMarkers(source, kind, markers = null) {
|
|
|
258
258
|
return { runs, strays, arrows };
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
// Where a Will marker may stand (docs/will.md, Conversion). A pair inside a fence, a raw block
|
|
262
|
+
// (`<pre>`, `<div>`, a raw table cell) or the opening front matter is text: the line is quoted,
|
|
263
|
+
// and a Word or PDF writer that met it as a marker would govern the wrong region. The same frame
|
|
264
|
+
// as spec/frontmatter.mjs, copied here so this grammar stays inside the MIT kit's closure.
|
|
265
|
+
const WILL_BLOCK_TAGS = new Set('address article aside base basefont blockquote body caption center col colgroup dd details dialog dir div dl dt fieldset figcaption figure footer form frame frameset h1 h2 h3 h4 h5 h6 head header hr html iframe legend li link main menu menuitem nav noframes ol optgroup option p param search section summary table tbody td tfoot th thead title tr track ul'.split(' '));
|
|
266
|
+
const WILL_VOID_TAGS = new Set('area base br col embed hr img input link meta param source track wbr'.split(' '));
|
|
267
|
+
|
|
268
|
+
function willLineAt(text, start) {
|
|
269
|
+
let end = start;
|
|
270
|
+
while (end < text.length && text.charCodeAt(end) !== 13 && text.charCodeAt(end) !== 10) end++;
|
|
271
|
+
const eol = text.charCodeAt(end) === 13 && text.charCodeAt(end + 1) === 10 ? 2 : end < text.length ? 1 : 0;
|
|
272
|
+
return {start, end, next: end + eol, text: text.slice(start, end)};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function willOpeningFrame(text) {
|
|
276
|
+
const bom = text.charCodeAt(0) === 0xfeff ? 1 : 0;
|
|
277
|
+
const opening = willLineAt(text, bom);
|
|
278
|
+
if (!/^--- *$/.test(opening.text) || opening.next === opening.end) return null;
|
|
279
|
+
for (let at = opening.next; at < text.length;) {
|
|
280
|
+
const line = willLineAt(text, at);
|
|
281
|
+
if (/^(?:---|\.\.\.) *$/.test(line.text)) return {contentStart: opening.next, contentEnd: line.start, bodyStart: line.next};
|
|
282
|
+
if (line.next <= at) break;
|
|
283
|
+
at = line.next;
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function willColumns(line) {
|
|
289
|
+
let col = 0;
|
|
290
|
+
for (let i = 0; i < line.length; i++) {
|
|
291
|
+
const code = line.charCodeAt(i);
|
|
292
|
+
if (code === 32) col++;
|
|
293
|
+
else if (code === 9) col += 4 - (col % 4);
|
|
294
|
+
else return {col, index: i};
|
|
295
|
+
}
|
|
296
|
+
return {col, index: line.length};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function willQuoteInner(line) {
|
|
300
|
+
let i = 0, depth = 0;
|
|
301
|
+
while (i < line.length) {
|
|
302
|
+
let col = 0, j = i;
|
|
303
|
+
while (j < line.length && col < 3) {
|
|
304
|
+
const code = line.charCodeAt(j);
|
|
305
|
+
if (code === 32) { col++; j++; }
|
|
306
|
+
else if (code === 9) {
|
|
307
|
+
const adv = 4 - (col % 4);
|
|
308
|
+
if (col + adv > 3) break;
|
|
309
|
+
col += adv; j++;
|
|
310
|
+
} else break;
|
|
311
|
+
}
|
|
312
|
+
if (line.charCodeAt(j) !== 62) break;
|
|
313
|
+
depth++;
|
|
314
|
+
j++;
|
|
315
|
+
if (line.charCodeAt(j) === 32 || line.charCodeAt(j) === 9) j++;
|
|
316
|
+
i = j;
|
|
317
|
+
}
|
|
318
|
+
return depth ? line.slice(i) : null;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function willListItem(line) {
|
|
322
|
+
const {col, index} = willColumns(line);
|
|
323
|
+
if (col >= 4) return null;
|
|
324
|
+
const rest = line.slice(index);
|
|
325
|
+
const marked = /^([-*+]|\d{1,9}[.)])([ \t]*)/.exec(rest);
|
|
326
|
+
if (!marked || (marked[2].length === 0 && index + marked[1].length < line.length)) return null;
|
|
327
|
+
let content = col + marked[1].length, padding = 0;
|
|
328
|
+
for (const ch of marked[2]) {
|
|
329
|
+
if (padding >= 4) break;
|
|
330
|
+
if (ch === ' ') { content++; padding++; }
|
|
331
|
+
else { const adv = 4 - (content % 4); content += adv; padding += adv; }
|
|
332
|
+
}
|
|
333
|
+
if (marked[2].length === 0) content++;
|
|
334
|
+
return {content};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function willFenceOpen(line) {
|
|
338
|
+
const {col, index} = willColumns(line);
|
|
339
|
+
if (col >= 4) return null;
|
|
340
|
+
const match = /^(`{3,}|~{3,})(.*)$/.exec(line.slice(index));
|
|
341
|
+
if (!match || (match[1].charCodeAt(0) === 96 && match[2].includes('`'))) return null;
|
|
342
|
+
return {ch: match[1][0], len: match[1].length};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function willFenceCloses(line, fence) {
|
|
346
|
+
const raw = fence.inQuote ? willQuoteInner(line) : line;
|
|
347
|
+
if (raw == null) return false;
|
|
348
|
+
const {col, index} = willColumns(raw);
|
|
349
|
+
if (col >= 4) return false;
|
|
350
|
+
const rest = raw.slice(index);
|
|
351
|
+
let i = 0;
|
|
352
|
+
while (i < rest.length && rest[i] === fence.ch) i++;
|
|
353
|
+
if (i < fence.len) return false;
|
|
354
|
+
for (let k = i; k < rest.length; k++) if (rest.charCodeAt(k) !== 32 && rest.charCodeAt(k) !== 9) return false;
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function willUpdateTags(item, line) {
|
|
359
|
+
const re = /<!--[\s\S]*?-->|<\/?([A-Za-z][A-Za-z0-9]*)\b[^>]*?>/g;
|
|
360
|
+
let match;
|
|
361
|
+
while ((match = re.exec(line))) {
|
|
362
|
+
if (match[0].charCodeAt(1) === 33) continue;
|
|
363
|
+
const name = match[1].toLowerCase();
|
|
364
|
+
const close = match[0].charCodeAt(1) === 47;
|
|
365
|
+
if (WILL_VOID_TAGS.has(name) || /\/\s*>$/.test(match[0])) continue;
|
|
366
|
+
if (close) {
|
|
367
|
+
const at = item.tags.lastIndexOf(name);
|
|
368
|
+
if (at >= 0) item.tags.splice(at, 1);
|
|
369
|
+
} else item.tags.push(name);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function willHtmlOpen(line) {
|
|
374
|
+
const {col, index} = willColumns(line);
|
|
375
|
+
if (col >= 4) return null;
|
|
376
|
+
const rest = line.slice(index);
|
|
377
|
+
const leaf = /^<(pre|script|style|textarea)(?:[ \t]|\/?>|$)/i.exec(rest);
|
|
378
|
+
if (leaf) return {kind: leaf[1].toLowerCase() === 'pre' ? 'pre' : 'raw', tag: leaf[1].toLowerCase()};
|
|
379
|
+
const block = /^<\/?([A-Za-z][A-Za-z0-9]*)(?:[ \t]|\/?>|$)/.exec(rest);
|
|
380
|
+
if (!block || !WILL_BLOCK_TAGS.has(block[1].toLowerCase())) return null;
|
|
381
|
+
const item = {kind: 'html', tags: []};
|
|
382
|
+
willUpdateTags(item, rest);
|
|
383
|
+
return item;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function willRawCloses(item, line) {
|
|
387
|
+
const close = new RegExp('</' + item.tag + '(?:[\\t\\n\\f />]|$)', 'i');
|
|
388
|
+
return close.test(line);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function willQuotedWhere(stack) {
|
|
392
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
393
|
+
const item = stack[i];
|
|
394
|
+
if (item.kind === 'fence') return 'fence';
|
|
395
|
+
if (item.kind === 'pre') return 'raw-pre';
|
|
396
|
+
if (item.kind === 'html') {
|
|
397
|
+
if (item.tags.includes('pre')) return 'raw-pre';
|
|
398
|
+
if (item.tags.includes('td') || item.tags.includes('th')) return 'raw-table';
|
|
399
|
+
if (item.tags.includes('div')) return 'raw-div';
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function willLeaf(stack) {
|
|
407
|
+
const kind = stack[stack.length - 1]?.kind;
|
|
408
|
+
return kind === 'fence' || kind === 'pre' || kind === 'html' || kind === 'raw';
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// `spans` are [start, end) of marker lines in `source` (the Will reader's own offsets).
|
|
412
|
+
// Returns the first quoted span, {start, end, where}, or null when every span may stand.
|
|
413
|
+
// `where` is `fence`, `raw-pre`, `raw-div`, `raw-table` or `frontmatter`.
|
|
414
|
+
export function quotedWillSpan(source, spans) {
|
|
415
|
+
const text = String(source ?? '');
|
|
416
|
+
const marks = Array.isArray(spans) ? spans : [];
|
|
417
|
+
if (!marks.length) return null;
|
|
418
|
+
const places = new Map();
|
|
419
|
+
const frame = willOpeningFrame(text);
|
|
420
|
+
if (frame) {
|
|
421
|
+
for (const span of marks) {
|
|
422
|
+
const start = span[0];
|
|
423
|
+
if (start >= frame.contentStart && start < frame.contentEnd) places.set(start, 'frontmatter');
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const stack = [];
|
|
427
|
+
for (let pos = frame ? frame.bodyStart : text.charCodeAt(0) === 0xfeff ? 1 : 0; pos < text.length;) {
|
|
428
|
+
const line = willLineAt(text, pos);
|
|
429
|
+
const blank = /^[ \t]*$/.test(line.text);
|
|
430
|
+
let closedHere = false;
|
|
431
|
+
while (stack.length) {
|
|
432
|
+
const top = stack[stack.length - 1];
|
|
433
|
+
if (top.kind === 'html' && blank) { stack.pop(); continue; }
|
|
434
|
+
if (top.kind === 'fence' && willFenceCloses(line.text, top)) { stack.pop(); closedHere = true; continue; }
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
let cut = -1;
|
|
438
|
+
for (let i = 0; i < stack.length; i++) {
|
|
439
|
+
const item = stack[i];
|
|
440
|
+
if (item.kind === 'list' && !blank && willColumns(line.text).col < item.content && !willListItem(line.text)) { cut = i; break; }
|
|
441
|
+
if (item.kind === 'quote' && !blank && willQuoteInner(line.text) == null) { cut = i; break; }
|
|
442
|
+
}
|
|
443
|
+
if (cut >= 0) stack.length = cut;
|
|
444
|
+
if (!places.has(line.start)) {
|
|
445
|
+
const where = willQuotedWhere(stack);
|
|
446
|
+
if (where) places.set(line.start, where);
|
|
447
|
+
}
|
|
448
|
+
const top = stack[stack.length - 1];
|
|
449
|
+
if (top?.kind === 'pre' && willRawCloses({tag: 'pre'}, line.text)) stack.pop();
|
|
450
|
+
else if (top?.kind === 'raw' && willRawCloses(top, line.text)) stack.pop();
|
|
451
|
+
else if (top?.kind === 'html' && !blank) willUpdateTags(top, line.text);
|
|
452
|
+
else if (!closedHere && !willLeaf(stack) && !blank) {
|
|
453
|
+
const inner = willQuoteInner(line.text);
|
|
454
|
+
const body = inner == null ? line.text : inner;
|
|
455
|
+
const inQuote = inner != null;
|
|
456
|
+
if (inQuote && stack[stack.length - 1]?.kind !== 'quote') stack.push({kind: 'quote'});
|
|
457
|
+
const fence = willFenceOpen(body);
|
|
458
|
+
if (fence) stack.push({kind: 'fence', ...fence, inQuote});
|
|
459
|
+
else {
|
|
460
|
+
const html = willHtmlOpen(body);
|
|
461
|
+
if (html) stack.push({...html, inQuote});
|
|
462
|
+
else if (!inQuote) {
|
|
463
|
+
const item = willListItem(line.text);
|
|
464
|
+
if (item && stack[stack.length - 1]?.kind !== 'list') stack.push({kind: 'list', content: item.content});
|
|
465
|
+
else if (item && stack[stack.length - 1]?.kind === 'list' && item.content > stack[stack.length - 1].content) stack.push({kind: 'list', content: item.content});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (line.next <= pos) break;
|
|
470
|
+
pos = line.next;
|
|
471
|
+
}
|
|
472
|
+
for (const span of marks) {
|
|
473
|
+
const where = places.get(span[0]);
|
|
474
|
+
if (where) return {start: span[0], end: span[1], where};
|
|
475
|
+
}
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
|
|
261
479
|
function pairSpanMarkers(source, kind, markers = null) {
|
|
262
480
|
if (kind !== 'ink' && kind !== 'color') throw new TypeError('Unknown paired marker kind');
|
|
263
481
|
const color = kind === 'color';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rapier-markdown-kit",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.54",
|
|
4
4
|
"description": "Read, write and style Self-contained Markdown: the universal stylesheet, picture layout, text marks, picture appendix, line planner and Will/1 markers. MIT, no dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
package/style.css
CHANGED
|
@@ -732,6 +732,12 @@
|
|
|
732
732
|
font-size: var(--md-text-sm);
|
|
733
733
|
color: var(--md-color-text-secondary);
|
|
734
734
|
}
|
|
735
|
+
:where(.md-render) .rapier-figure-caption {
|
|
736
|
+
margin-top: calc(var(--md-space-1) - var(--md-line));
|
|
737
|
+
font-style: italic;
|
|
738
|
+
font-size: var(--md-text-sm);
|
|
739
|
+
color: var(--md-color-text-secondary);
|
|
740
|
+
}
|
|
735
741
|
.md-render img{
|
|
736
742
|
max-width:100%;height:auto;
|
|
737
743
|
border:0;
|