@quarto/jupyterlab-quarto 0.1.44 → 0.2.3
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/LICENSE +1 -1
- package/README.md +48 -15
- package/lib/__tests__/jupyterlab_quarto.spec.d.ts +3 -0
- package/lib/__tests__/jupyterlab_quarto.spec.js +9 -0
- package/lib/ast/ast.d.ts +2 -0
- package/lib/ast/ast.js +40 -0
- package/lib/const.d.ts +4 -0
- package/lib/const.js +11 -0
- package/lib/hooks/codemirror.d.ts +5 -0
- package/lib/hooks/codemirror.js +77 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +61 -0
- package/lib/manager.d.ts +8 -0
- package/lib/manager.js +115 -0
- package/lib/plugins/callouts.d.ts +2 -0
- package/lib/plugins/callouts.js +210 -0
- package/lib/plugins/cites.d.ts +2 -0
- package/lib/plugins/cites.js +166 -0
- package/lib/plugins/decorator.d.ts +2 -0
- package/lib/plugins/decorator.js +58 -0
- package/lib/plugins/divs.d.ts +5 -0
- package/lib/plugins/divs.js +111 -0
- package/lib/plugins/figure-divs.d.ts +2 -0
- package/lib/plugins/figure-divs.js +54 -0
- package/lib/plugins/figures.d.ts +16 -0
- package/lib/plugins/figures.js +98 -0
- package/lib/plugins/gridtables/common/gridtables/GetCells.d.ts +7 -0
- package/lib/plugins/gridtables/common/gridtables/GetCells.js +43 -0
- package/lib/plugins/gridtables/common/gridtables/GetColumnWidths.d.ts +7 -0
- package/lib/plugins/gridtables/common/gridtables/GetColumnWidths.js +22 -0
- package/lib/plugins/gridtables/common/markdown-it/ColumnAlignments.d.ts +7 -0
- package/lib/plugins/gridtables/common/markdown-it/ColumnAlignments.js +12 -0
- package/lib/plugins/gridtables/common/markdown-it/EmitTable.d.ts +4 -0
- package/lib/plugins/gridtables/common/markdown-it/EmitTable.js +64 -0
- package/lib/plugins/gridtables/common/markdown-it/GetCharCodeAtStartOfLine.d.ts +8 -0
- package/lib/plugins/gridtables/common/markdown-it/GetCharCodeAtStartOfLine.js +17 -0
- package/lib/plugins/gridtables/common/markdown-it/GetLine.d.ts +2 -0
- package/lib/plugins/gridtables/common/markdown-it/GetLine.js +9 -0
- package/lib/plugins/gridtables/common/markdown-it/ParseTable.d.ts +3 -0
- package/lib/plugins/gridtables/common/markdown-it/ParseTable.js +152 -0
- package/lib/plugins/gridtables/common/markdown-it/ParseTableResult.d.ts +12 -0
- package/lib/plugins/gridtables/common/markdown-it/ParseTableResult.js +17 -0
- package/lib/plugins/gridtables/index.d.ts +1 -0
- package/lib/plugins/gridtables/index.js +10 -0
- package/lib/plugins/gridtables/interfaces/markdown-it/IState.d.ts +10 -0
- package/lib/plugins/gridtables/interfaces/markdown-it/IState.js +5 -0
- package/lib/plugins/gridtables/interfaces/markdown-it/IToken.d.ts +6 -0
- package/lib/plugins/gridtables/interfaces/markdown-it/IToken.js +5 -0
- package/lib/plugins/gridtables/interfaces/markdown-it/TRuleFunction.d.ts +3 -0
- package/lib/plugins/gridtables/interfaces/markdown-it/TRuleFunction.js +5 -0
- package/lib/plugins/gridtables/rules/gridtable.d.ts +3 -0
- package/lib/plugins/gridtables/rules/gridtable.js +25 -0
- package/lib/plugins/index.d.ts +15 -0
- package/lib/plugins/index.js +21 -0
- package/lib/plugins/math.d.ts +6 -0
- package/lib/plugins/math.js +179 -0
- package/lib/plugins/mermaid/index.d.ts +4 -0
- package/lib/plugins/mermaid/index.js +60 -0
- package/lib/plugins/shortcodes.d.ts +3 -0
- package/lib/plugins/shortcodes.js +32 -0
- package/lib/plugins/spans.d.ts +2 -0
- package/lib/plugins/spans.js +37 -0
- package/lib/plugins/table-captions.d.ts +2 -0
- package/lib/plugins/table-captions.js +72 -0
- package/lib/plugins/utils/html.d.ts +11 -0
- package/lib/plugins/utils/html.js +50 -0
- package/lib/plugins/utils/markdownit.d.ts +15 -0
- package/lib/plugins/utils/markdownit.js +46 -0
- package/lib/plugins/utils/tok.d.ts +7 -0
- package/lib/plugins/utils/tok.js +13 -0
- package/lib/plugins/yaml.d.ts +2 -0
- package/lib/plugins/yaml.js +330 -0
- package/lib/providers/attrs.d.ts +1 -0
- package/lib/providers/attrs.js +15 -0
- package/lib/providers/callouts.d.ts +1 -0
- package/lib/providers/callouts.js +15 -0
- package/lib/providers/cites.d.ts +1 -0
- package/lib/providers/cites.js +15 -0
- package/lib/providers/decorator.d.ts +1 -0
- package/lib/providers/decorator.js +15 -0
- package/lib/providers/deflist.d.ts +1 -0
- package/lib/providers/deflist.js +15 -0
- package/lib/providers/divs.d.ts +1 -0
- package/lib/providers/divs.js +27 -0
- package/lib/providers/figure-divs.d.ts +1 -0
- package/lib/providers/figure-divs.js +15 -0
- package/lib/providers/figures.d.ts +1 -0
- package/lib/providers/figures.js +15 -0
- package/lib/providers/footnotes.d.ts +1 -0
- package/lib/providers/footnotes.js +15 -0
- package/lib/providers/gridtables.d.ts +1 -0
- package/lib/providers/gridtables.js +15 -0
- package/lib/providers/math.d.ts +1 -0
- package/lib/providers/math.js +104 -0
- package/lib/providers/mermaid.d.ts +1 -0
- package/lib/providers/mermaid.js +17 -0
- package/lib/providers/provider.d.ts +3 -0
- package/lib/providers/provider.js +12 -0
- package/lib/providers/shortcodes.d.ts +1 -0
- package/lib/providers/shortcodes.js +15 -0
- package/lib/providers/spans.d.ts +1 -0
- package/lib/providers/spans.js +15 -0
- package/lib/providers/sub.d.ts +1 -0
- package/lib/providers/sub.js +15 -0
- package/lib/providers/sup.d.ts +1 -0
- package/lib/providers/sup.js +15 -0
- package/lib/providers/table-captions.d.ts +1 -0
- package/lib/providers/table-captions.js +15 -0
- package/lib/providers/tasklists.d.ts +1 -0
- package/lib/providers/tasklists.js +15 -0
- package/lib/providers/yaml.d.ts +1 -0
- package/lib/providers/yaml.js +15 -0
- package/lib/types.d.ts +43 -0
- package/lib/types.js +1 -0
- package/lib/widgets.d.ts +14 -0
- package/lib/widgets.js +57 -0
- package/package.json +105 -39
- package/style/base.css +34 -33
- package/style/index.css +1 -1
- package/schema/plugin.json +0 -8
- package/src/@types/markdown-it-deflist.d.ts +0 -10
- package/src/@types/markdown-it-footnote.d.ts +0 -10
- package/src/@types/markdown-it-gridtables.d.ts +0 -10
- package/src/@types/markdown-it-implicit-figures.d.ts +0 -10
- package/src/@types/markdown-it-sub.d.ts +0 -10
- package/src/@types/markdown-it-sup.d.ts +0 -10
- package/src/@types/markdown-it-task-lists.d.ts +0 -10
@@ -0,0 +1,179 @@
|
|
1
|
+
/*
|
2
|
+
* math.ts
|
3
|
+
*
|
4
|
+
* Copyright (C) 2020-2023 Posit Software, PBC
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
export const kTokMathBlock = 'math_block';
|
8
|
+
export const kTokMathInline = 'math_inline';
|
9
|
+
function renderMath(content, convertOptions) {
|
10
|
+
if (convertOptions.display) {
|
11
|
+
return `<div class='quarto-display-math'>\\[${content}\\]</div>`;
|
12
|
+
}
|
13
|
+
else {
|
14
|
+
return `<span class='quarto-inline-math'>\\(${content}\\)</span>`;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
// Test if potential opening or closing delimieter
|
18
|
+
// Assumes that there is a "$" at state.src[pos]
|
19
|
+
function isValidDelim(state, pos) {
|
20
|
+
const max = state.posMax;
|
21
|
+
let can_open = true;
|
22
|
+
let can_close = true;
|
23
|
+
const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1, nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
|
24
|
+
// Check non-whitespace conditions for opening and closing, and
|
25
|
+
// check that closing delimeter isn't followed by a number
|
26
|
+
if (prevChar === 0x20 /* " " */ ||
|
27
|
+
prevChar === 0x09 /* \t */ ||
|
28
|
+
(nextChar >= 0x30 /* "0" */ && nextChar <= 0x39) /* "9" */) {
|
29
|
+
can_close = false;
|
30
|
+
}
|
31
|
+
if (nextChar === 0x20 /* " " */ || nextChar === 0x09 /* \t */) {
|
32
|
+
can_open = false;
|
33
|
+
}
|
34
|
+
return {
|
35
|
+
can_open: can_open,
|
36
|
+
can_close: can_close
|
37
|
+
};
|
38
|
+
}
|
39
|
+
function math_inline(state, silent) {
|
40
|
+
if (state.src[state.pos] !== '$') {
|
41
|
+
return false;
|
42
|
+
}
|
43
|
+
let res = isValidDelim(state, state.pos);
|
44
|
+
if (!res.can_open) {
|
45
|
+
if (!silent) {
|
46
|
+
state.pending += '$';
|
47
|
+
}
|
48
|
+
state.pos += 1;
|
49
|
+
return true;
|
50
|
+
}
|
51
|
+
// First check for and bypass all properly escaped delimieters
|
52
|
+
// This loop will assume that the first leading backtick can not
|
53
|
+
// be the first character in state.src, which is known since
|
54
|
+
// we have found an opening delimieter already.
|
55
|
+
const start = state.pos + 1;
|
56
|
+
let match = start;
|
57
|
+
while ((match = state.src.indexOf('$', match)) !== -1) {
|
58
|
+
// Found potential $, look for escapes, pos will point to
|
59
|
+
// first non escape when complete
|
60
|
+
let pos = match - 1;
|
61
|
+
while (state.src[pos] === '\\') {
|
62
|
+
pos -= 1;
|
63
|
+
}
|
64
|
+
// Even number of escapes, potential closing delimiter found
|
65
|
+
if ((match - pos) % 2 === 1) {
|
66
|
+
break;
|
67
|
+
}
|
68
|
+
match += 1;
|
69
|
+
}
|
70
|
+
// No closing delimter found. Consume $ and continue.
|
71
|
+
if (match === -1) {
|
72
|
+
if (!silent) {
|
73
|
+
state.pending += '$';
|
74
|
+
}
|
75
|
+
state.pos = start;
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
// Check if we have empty content, ie: $$. Do not parse.
|
79
|
+
if (match - start === 0) {
|
80
|
+
if (!silent) {
|
81
|
+
state.pending += '$$';
|
82
|
+
}
|
83
|
+
state.pos = start + 1;
|
84
|
+
return true;
|
85
|
+
}
|
86
|
+
// Check for valid closing delimiter
|
87
|
+
res = isValidDelim(state, match);
|
88
|
+
if (!res.can_close) {
|
89
|
+
if (!silent) {
|
90
|
+
state.pending += '$';
|
91
|
+
}
|
92
|
+
state.pos = start;
|
93
|
+
return true;
|
94
|
+
}
|
95
|
+
if (!silent) {
|
96
|
+
const token = state.push('math_inline', 'math', 0);
|
97
|
+
token.markup = '$';
|
98
|
+
token.content = state.src.slice(start, match);
|
99
|
+
}
|
100
|
+
state.pos = match + 1;
|
101
|
+
return true;
|
102
|
+
}
|
103
|
+
function math_block(state, start, end, silent) {
|
104
|
+
let next, lastPos;
|
105
|
+
let found = false, pos = state.bMarks[start] + state.tShift[start], max = state.eMarks[start], lastLine = '';
|
106
|
+
if (pos + 2 > max) {
|
107
|
+
return false;
|
108
|
+
}
|
109
|
+
if (state.src.slice(pos, pos + 2) !== '$$') {
|
110
|
+
return false;
|
111
|
+
}
|
112
|
+
pos += 2;
|
113
|
+
let firstLine = state.src.slice(pos, max);
|
114
|
+
if (silent) {
|
115
|
+
return true;
|
116
|
+
}
|
117
|
+
if (firstLine.trim().slice(-2) === '$$') {
|
118
|
+
// Single line expression
|
119
|
+
firstLine = firstLine.trim().slice(0, -2);
|
120
|
+
found = true;
|
121
|
+
}
|
122
|
+
let attrStr = undefined;
|
123
|
+
for (next = start; !found;) {
|
124
|
+
next++;
|
125
|
+
if (next >= end) {
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
pos = state.bMarks[next] + state.tShift[next];
|
129
|
+
max = state.eMarks[next];
|
130
|
+
if (pos < max && state.tShift[next] < state.blkIndent) {
|
131
|
+
// non-empty line with negative indent should stop the list:
|
132
|
+
break;
|
133
|
+
}
|
134
|
+
const line = state.src.slice(pos, max).trim();
|
135
|
+
const match = line.match(/^\$\$\s*(\{.*\})?\s*$/);
|
136
|
+
if (match) {
|
137
|
+
lastPos = state.src.slice(0, max).lastIndexOf('$$');
|
138
|
+
lastLine = state.src.slice(pos, lastPos);
|
139
|
+
attrStr = match[1];
|
140
|
+
found = true;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
state.line = next + 1;
|
144
|
+
const token = state.push(kTokMathBlock, 'math', 0);
|
145
|
+
token.block = true;
|
146
|
+
if (attrStr) {
|
147
|
+
token.info = attrStr;
|
148
|
+
}
|
149
|
+
token.content =
|
150
|
+
(firstLine && firstLine.trim() ? firstLine + '\n' : '') +
|
151
|
+
state.getLines(start + 1, next, state.tShift[start], true) +
|
152
|
+
(lastLine && lastLine.trim() ? lastLine : '');
|
153
|
+
token.map = [start, state.line];
|
154
|
+
token.markup = '$$';
|
155
|
+
return true;
|
156
|
+
}
|
157
|
+
export function mathjaxPlugin(md, options) {
|
158
|
+
// Default options
|
159
|
+
options = options || {};
|
160
|
+
const enableInlines = options.enableInlines !== undefined ? options.enableInlines : true;
|
161
|
+
const convertOptions = {
|
162
|
+
display: false
|
163
|
+
};
|
164
|
+
// set MathJax as the renderer for markdown-it-simplemath
|
165
|
+
md.inline.ruler.after('escape', kTokMathInline, math_inline);
|
166
|
+
md.block.ruler.after('blockquote', kTokMathBlock, math_block, {
|
167
|
+
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
168
|
+
});
|
169
|
+
if (enableInlines) {
|
170
|
+
md.renderer.rules.math_inline = function (tokens, idx) {
|
171
|
+
convertOptions.display = false;
|
172
|
+
return renderMath(tokens[idx].content, convertOptions);
|
173
|
+
};
|
174
|
+
}
|
175
|
+
md.renderer.rules.math_block = function (tokens, idx) {
|
176
|
+
convertOptions.display = true;
|
177
|
+
return renderMath(tokens[idx].content, convertOptions);
|
178
|
+
};
|
179
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import Mermaid from 'mermaid';
|
2
|
+
export default function mermaidPlugin(md, options) {
|
3
|
+
const kLang = 'mermaid';
|
4
|
+
const kContainer = 'quarto-mermaid';
|
5
|
+
Mermaid.initialize({
|
6
|
+
securityLevel: 'loose',
|
7
|
+
theme: options.dark ? 'dark' : 'default',
|
8
|
+
...options
|
9
|
+
});
|
10
|
+
const defaultFenceRenderer = md.renderer.rules.fence;
|
11
|
+
// Render custom code types as SVGs, letting the fence parser do all the heavy lifting.
|
12
|
+
function mermaidFenceRenderer(tokens, idx, options, env, slf) {
|
13
|
+
const token = tokens[idx];
|
14
|
+
if (token.info === kLang ||
|
15
|
+
(token.attrs !== null &&
|
16
|
+
token.attrs.length === 1 &&
|
17
|
+
token.attrs[0][0] === kLang)) {
|
18
|
+
let imageHTML = '';
|
19
|
+
const imageAttrs = [];
|
20
|
+
// Create element to render into
|
21
|
+
const element = document.createElement('div');
|
22
|
+
document.body.appendChild(element);
|
23
|
+
// Render with Mermaid
|
24
|
+
try {
|
25
|
+
Mermaid.mermaidAPI.render(kContainer, token.content, (html) => {
|
26
|
+
// We need to forcibly extract the max-width/height attributes to set on img tag
|
27
|
+
const mermaidEl = document.getElementById(kContainer);
|
28
|
+
if (mermaidEl !== null) {
|
29
|
+
imageAttrs.push([
|
30
|
+
'style',
|
31
|
+
`max-width:${mermaidEl.style.maxWidth};max-height:${mermaidEl.style.maxHeight}`
|
32
|
+
]);
|
33
|
+
}
|
34
|
+
// Store HTML
|
35
|
+
imageHTML = html;
|
36
|
+
}, element);
|
37
|
+
}
|
38
|
+
catch (e) {
|
39
|
+
return `<pre>Failed to render mermaid diagram.${e}</pre>`;
|
40
|
+
}
|
41
|
+
finally {
|
42
|
+
element.remove();
|
43
|
+
}
|
44
|
+
// Store encoded image data
|
45
|
+
imageAttrs.push([
|
46
|
+
'src',
|
47
|
+
`data:image/svg+xml,${encodeURIComponent(imageHTML)}`
|
48
|
+
]);
|
49
|
+
return `<img ${slf.renderAttrs({ attrs: imageAttrs })}>`;
|
50
|
+
}
|
51
|
+
else {
|
52
|
+
if (defaultFenceRenderer !== undefined) {
|
53
|
+
return defaultFenceRenderer(tokens, idx, options, env, slf);
|
54
|
+
}
|
55
|
+
// Missing fence renderer!
|
56
|
+
return '';
|
57
|
+
}
|
58
|
+
}
|
59
|
+
md.renderer.rules.fence = mermaidFenceRenderer;
|
60
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { escapeHtml } from 'markdown-it/lib/common/utils';
|
2
|
+
export const kShortcode = 'shortcode';
|
3
|
+
export const shortcodePlugin = (md) => {
|
4
|
+
const shortcode = (state, silent) => {
|
5
|
+
// {{< shortcode >}}
|
6
|
+
if (state.src.slice(state.pos, state.pos + 3) !== '{{<') {
|
7
|
+
return false;
|
8
|
+
}
|
9
|
+
const shortcodeEndRegex = />}}/g;
|
10
|
+
// ignore if shortcode doesn't end
|
11
|
+
const end = state.src.slice(state.pos).search(shortcodeEndRegex);
|
12
|
+
if (end === -1) {
|
13
|
+
return false;
|
14
|
+
}
|
15
|
+
const shortcodeContent = state.src.slice(state.pos + 3, state.pos + end);
|
16
|
+
if (!silent) {
|
17
|
+
const token = state.push('shortcode', 'shortcode', 0);
|
18
|
+
token.markup = '';
|
19
|
+
token.content = shortcodeContent;
|
20
|
+
}
|
21
|
+
state.pos += end + 3;
|
22
|
+
return true;
|
23
|
+
};
|
24
|
+
md.inline.ruler.after('escape', kShortcode, shortcode);
|
25
|
+
const renderShortcode = (tokens, idx) => {
|
26
|
+
const token = tokens[idx];
|
27
|
+
const content = token.content;
|
28
|
+
// insert shortcode braces and escape content's html entities
|
29
|
+
return `<span class="shortcode">${escapeHtml(`{{<${content}>}}`)}</span>`;
|
30
|
+
};
|
31
|
+
md.renderer.rules[kShortcode] = renderShortcode;
|
32
|
+
};
|
@@ -0,0 +1,37 @@
|
|
1
|
+
/*
|
2
|
+
* span.ts
|
3
|
+
*
|
4
|
+
* Copyright (C) 2020-2023 Posit Software, PBC
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
export function spansPlugin(md) {
|
8
|
+
function span(state) {
|
9
|
+
const max = state.posMax;
|
10
|
+
if (state.src.charCodeAt(state.pos) !== 0x5b) {
|
11
|
+
// opening [
|
12
|
+
return false;
|
13
|
+
}
|
14
|
+
const labelStart = state.pos + 1;
|
15
|
+
const labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);
|
16
|
+
if (labelEnd < 0) {
|
17
|
+
// parser failed to find closing ]
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
const pos = labelEnd + 1;
|
21
|
+
if (pos < max && state.src.charCodeAt(pos) === 0x7b /* { */) {
|
22
|
+
// probably found span
|
23
|
+
state.pos = labelStart;
|
24
|
+
state.posMax = labelEnd;
|
25
|
+
state.push('span_open', 'span', 1);
|
26
|
+
state.md.inline.tokenize(state);
|
27
|
+
state.push('span_close', 'span', -1);
|
28
|
+
state.pos = pos;
|
29
|
+
state.posMax = max;
|
30
|
+
return true;
|
31
|
+
}
|
32
|
+
else {
|
33
|
+
return false;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
md.inline.ruler.push('quarto-spans', span);
|
37
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
/*
|
2
|
+
* table-captions.ts
|
3
|
+
*
|
4
|
+
* Copyright (C) 2020-2023 Posit Software, PBC
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
import { kTokInline, kTokParaClose, kTokParaOpen, kTokTableClose, kTokTableOpen, kTokText } from './utils/tok';
|
8
|
+
const kTableCaptionRule = 'quarto-table-captions';
|
9
|
+
export const tableCaptionPlugin = (md) => {
|
10
|
+
md.core.ruler.push(kTableCaptionRule, state => {
|
11
|
+
const tableIdxs = [];
|
12
|
+
const tablePoss = [];
|
13
|
+
// Identify tables that we'd like to process
|
14
|
+
// The tables must be the bottom first (we will process them bottom to
|
15
|
+
// top to ensure that the positions remain accurate as the tokens
|
16
|
+
// are mutated
|
17
|
+
for (let i = 0; i < state.tokens.length; i++) {
|
18
|
+
const token = state.tokens[i];
|
19
|
+
if (token.type === kTokTableOpen) {
|
20
|
+
tableIdxs.push(i);
|
21
|
+
}
|
22
|
+
else if (token.type === kTokTableClose) {
|
23
|
+
const start = tableIdxs.pop();
|
24
|
+
if (start) {
|
25
|
+
tablePoss.unshift({
|
26
|
+
start,
|
27
|
+
end: i
|
28
|
+
});
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
// Look just past the tables and if there is a paragraph that is
|
33
|
+
// a table caption, extract that and place it in the table
|
34
|
+
for (const tablePos of tablePoss) {
|
35
|
+
resolveTableCaption(state.tokens, tablePos.start, tablePos.end);
|
36
|
+
}
|
37
|
+
});
|
38
|
+
};
|
39
|
+
function resolveTableCaption(tokens, tblStartPos, tblEndPos) {
|
40
|
+
// Must have at least three tokens past the table end
|
41
|
+
if (tokens.length > tblEndPos + 3) {
|
42
|
+
if (tokens[tblEndPos + 1].type === kTokParaOpen &&
|
43
|
+
tokens[tblEndPos + 2].type === kTokInline &&
|
44
|
+
tokens[tblEndPos + 3].type === kTokParaClose) {
|
45
|
+
const maybeCaption = tokens[tblEndPos + 2];
|
46
|
+
const isText = maybeCaption.children !== null &&
|
47
|
+
maybeCaption.children.length > 0 &&
|
48
|
+
maybeCaption.children[0].type === kTokText;
|
49
|
+
const maybeCaptionText = isText && maybeCaption.children ? maybeCaption.children[0].content : '';
|
50
|
+
const match = maybeCaptionText.match(/^:\s([^{}]*)(?:\{.*\}){0,1}$/);
|
51
|
+
if (match && match[1]) {
|
52
|
+
// Carve out the existing tokens
|
53
|
+
const capTokens = tokens.splice(tblEndPos + 1, 3);
|
54
|
+
// We have the caption, remove the paragraph and return
|
55
|
+
// the caption
|
56
|
+
capTokens[0].type = 'table_caption';
|
57
|
+
capTokens[0].tag = 'caption';
|
58
|
+
// Forward any attributes from the caption up to the table
|
59
|
+
tokens[tblStartPos].attrs = capTokens[0].attrs;
|
60
|
+
capTokens[0].attrs = [];
|
61
|
+
// Trim the content
|
62
|
+
if (capTokens[1].children && capTokens[1].children.length > 0) {
|
63
|
+
capTokens[1].children[0].content = match[1];
|
64
|
+
}
|
65
|
+
// Close the caption
|
66
|
+
capTokens[2].type = 'table_caption';
|
67
|
+
capTokens[2].tag = 'caption';
|
68
|
+
tokens.splice(tblStartPos + 1, 0, ...capTokens);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import Token from 'markdown-it/lib/token';
|
2
|
+
export interface DecoratorOptions {
|
3
|
+
customClass?: string;
|
4
|
+
hide: {
|
5
|
+
id?: boolean;
|
6
|
+
classes?: boolean;
|
7
|
+
attributes?: boolean;
|
8
|
+
};
|
9
|
+
}
|
10
|
+
export declare const decorator: (contents: string[], customClass?: string) => string;
|
11
|
+
export declare const attributeDecorator: (token: Token, options?: DecoratorOptions) => string;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
/*
|
2
|
+
* html.ts
|
3
|
+
*
|
4
|
+
* Copyright (C) 2020-2023 Posit Software, PBC
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
import { readAttrValue } from './markdownit';
|
8
|
+
export const decorator = (contents, customClass) => {
|
9
|
+
if (contents.length > 0) {
|
10
|
+
// Provide a decorator with the attributes
|
11
|
+
return `<div class="quarto-attribute-decorator${customClass ? ' ' + customClass : ''}">${contents.map(decoratorSpan).join('')}</div>`;
|
12
|
+
}
|
13
|
+
else {
|
14
|
+
// There is no decorator - no attributes
|
15
|
+
return '';
|
16
|
+
}
|
17
|
+
};
|
18
|
+
export const attributeDecorator = (token, options) => {
|
19
|
+
var _a;
|
20
|
+
// id
|
21
|
+
const id = readAttrValue('id', token.attrs);
|
22
|
+
// classes
|
23
|
+
const clz = readAttrValue('class', token.attrs);
|
24
|
+
// other attributes
|
25
|
+
const otherAttrs = (_a = token.attrs) === null || _a === void 0 ? void 0 : _a.filter(attr => {
|
26
|
+
return attr[0] !== 'id' && attr[0] !== 'class';
|
27
|
+
});
|
28
|
+
// Create a decorator for the div
|
29
|
+
const contents = [];
|
30
|
+
if (id && !(options === null || options === void 0 ? void 0 : options.hide.id)) {
|
31
|
+
contents.push(`#${id}`);
|
32
|
+
}
|
33
|
+
if (clz && !(options === null || options === void 0 ? void 0 : options.hide.classes)) {
|
34
|
+
const clzStr = clz
|
35
|
+
.split(' ')
|
36
|
+
.map(cls => `.${cls}`)
|
37
|
+
.join(' ');
|
38
|
+
contents.push(clzStr);
|
39
|
+
}
|
40
|
+
if (otherAttrs && otherAttrs.length > 0 && !(options === null || options === void 0 ? void 0 : options.hide.attributes)) {
|
41
|
+
const otherAttrStr = otherAttrs === null || otherAttrs === void 0 ? void 0 : otherAttrs.map(attr => {
|
42
|
+
return `${attr[0]}="${attr[1]}"`;
|
43
|
+
}).join(' ');
|
44
|
+
contents.push(otherAttrStr);
|
45
|
+
}
|
46
|
+
return decorator(contents, options === null || options === void 0 ? void 0 : options.customClass);
|
47
|
+
};
|
48
|
+
const decoratorSpan = (contents) => {
|
49
|
+
return `<span class="quarto-attribute-decorator-content">${contents}</span>`;
|
50
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
export declare const hasClass: (clz: string, attrs: null | [
|
2
|
+
string,
|
3
|
+
string
|
4
|
+
][]) => boolean | undefined;
|
5
|
+
export declare const readAttrValue: (name: string, attrs: null | [
|
6
|
+
string,
|
7
|
+
string
|
8
|
+
][]) => string | undefined;
|
9
|
+
export declare const addClass: (clz: string, attrs: null | [
|
10
|
+
string,
|
11
|
+
string
|
12
|
+
][]) => [
|
13
|
+
string,
|
14
|
+
string
|
15
|
+
][];
|
@@ -0,0 +1,46 @@
|
|
1
|
+
/*
|
2
|
+
* markdownit.ts
|
3
|
+
*
|
4
|
+
* Copyright (C) 2020-2023 Posit Software, PBC
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
export const hasClass = (clz, attrs) => {
|
8
|
+
if (attrs === null) {
|
9
|
+
return false;
|
10
|
+
}
|
11
|
+
const classes = readAttrValue('class', attrs);
|
12
|
+
if (classes === null) {
|
13
|
+
return false;
|
14
|
+
}
|
15
|
+
else {
|
16
|
+
return classes === null || classes === void 0 ? void 0 : classes.split(' ').includes(clz);
|
17
|
+
}
|
18
|
+
};
|
19
|
+
export const readAttrValue = (name, attrs) => {
|
20
|
+
if (attrs === null) {
|
21
|
+
return undefined;
|
22
|
+
}
|
23
|
+
const attr = attrs.find(attr => {
|
24
|
+
return attr[0] === name;
|
25
|
+
});
|
26
|
+
return attr ? attr[1] : undefined;
|
27
|
+
};
|
28
|
+
export const addClass = (clz, attrs) => {
|
29
|
+
if (attrs === null) {
|
30
|
+
attrs = [];
|
31
|
+
attrs.push(['class', clz]);
|
32
|
+
return attrs;
|
33
|
+
}
|
34
|
+
else {
|
35
|
+
const clzIdx = attrs.findIndex(attr => attr[0] === 'class');
|
36
|
+
if (clzIdx >= 0) {
|
37
|
+
const currentClz = attrs[clzIdx];
|
38
|
+
attrs[clzIdx] = ['class', `${currentClz[1]} ${clz}`.trim()];
|
39
|
+
return attrs;
|
40
|
+
}
|
41
|
+
else {
|
42
|
+
attrs.push(['class', clz]);
|
43
|
+
return attrs;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
};
|
@@ -0,0 +1,7 @@
|
|
1
|
+
export declare const kTokParaOpen = "paragraph_open";
|
2
|
+
export declare const kTokParaClose = "paragraph_close";
|
3
|
+
export declare const kTokInline = "inline";
|
4
|
+
export declare const kTokTableOpen = "table_open";
|
5
|
+
export declare const kTokTableClose = "table_close";
|
6
|
+
export declare const kTokText = "text";
|
7
|
+
export declare const kTokHeadingOpen = "heading_open";
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* tok.ts
|
3
|
+
*
|
4
|
+
* Copyright (C) 2020-2023 Posit Software, PBC
|
5
|
+
*
|
6
|
+
*/
|
7
|
+
export const kTokParaOpen = 'paragraph_open';
|
8
|
+
export const kTokParaClose = 'paragraph_close';
|
9
|
+
export const kTokInline = 'inline';
|
10
|
+
export const kTokTableOpen = 'table_open';
|
11
|
+
export const kTokTableClose = 'table_close';
|
12
|
+
export const kTokText = 'text';
|
13
|
+
export const kTokHeadingOpen = 'heading_open';
|