Skip to content

Commit

Permalink
Merge pull request #240 from yandex-cloud/@v8tenko/term
Browse files Browse the repository at this point in the history
diplodoc/terms
  • Loading branch information
v8tenko authored Jul 27, 2023
2 parents feef516 + 9bf89ef commit 5a43e26
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 96 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions src/transform/md.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,11 @@ function initParser(md: MarkdownIt, options: OptionsType, env: EnvType) {
};
}

function initCompiler(md: MarkdownIt, options: OptionsType, env: EnvType<{termTokens?: Token[]}>) {
function initCompiler(md: MarkdownIt, options: OptionsType, env: EnvType) {
const {needToSanitizeHtml = false, sanitizeOptions} = options;

return (tokens: Token[]) => {
// TODO: define postprocess step on term plugin
const {termTokens = []} = env;
delete env.termTokens;

const html = md.renderer.render([...tokens, ...termTokens], md.options, env);
const html = md.renderer.render(tokens, md.options, env);

return needToSanitizeHtml ? sanitizeHtml(html, sanitizeOptions) : html;
};
Expand Down
55 changes: 40 additions & 15 deletions src/transform/plugins/term/termDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export function termDefinitions(md: MarkdownIt, options: MarkdownItPluginOpts) {

const newLineReg = new RegExp(/^(\r\n|\r|\n)/);
const termReg = new RegExp(/^\[\*(\w+)\]:/);

let currentLine = startLine;

// Allow multiline term definition
Expand Down Expand Up @@ -74,7 +73,16 @@ export function termDefinitions(md: MarkdownIt, options: MarkdownItPluginOpts) {
return false;
}

return processTermDefinition(md, options, state, currentLine, endLine, label, title);
return processTermDefinition(
md,
options,
state,
currentLine,
startLine,
endLine,
label,
title,
);
};
}

Expand All @@ -83,6 +91,7 @@ function processTermDefinition(
options: MarkdownItPluginOpts,
state: StateBlock,
currentLine: number,
startLine: number,
endLine: number,
label: string,
title: string,
Expand Down Expand Up @@ -121,32 +130,48 @@ function processTermDefinition(
state.env.terms[':' + label] = title;
}

const termNodes = [];

token = new state.Token('template_open', 'template', 1);
token.map = [startLine, currentLine + 1];
token.attrSet('id', ':' + label + '_template');
termNodes.push(token);
token.attrSet('label', label);

token = new state.Token('term_open', 'dfn', 1);
state.tokens.push(token);

token = new state.Token('dfn_open', 'dfn', 1);
token.attrSet('class', 'yfm yfm-term_dfn');
token.attrSet('id', ':' + label + '_element');
token.attrSet('role', 'tooltip');
termNodes.push(token);

termNodes.push(...md.parse(title, {}));
state.tokens.push(token);

token = new state.Token('term_close', 'dfn', -1);
termNodes.push(token);
const titleTokens = md.parse(title, state.env);

token = new state.Token('template_close', 'template', -1);
termNodes.push(token);
for (const titleToken of titleTokens) {
if (titleToken.children?.length) {
titleToken.content = '';
}

if (!titleToken.map) {
state.tokens.push(titleToken);
continue;
}

if (!state.env.termTokens) {
state.env.termTokens = [];
const [start, end] = titleToken.map;

titleToken.map = [start + startLine, end + startLine];
state.tokens.push(titleToken);
}

state.env.termTokens.push(...termNodes);
token = new state.Token('dfn_close', 'dfn', -1);

state.tokens.push(token);

token = new state.Token('template_close', 'template', -1);

state.tokens.push(token);

/** current line links to end of term definition */
state.line = currentLine + 1;

return true;
}
144 changes: 70 additions & 74 deletions test/term.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,100 +32,96 @@ describe('Terms', () => {
const input = readFileSync(inputPath, 'utf8');
const result = transformYfm(input, inputPath);

expect(clearRandomId(result)).toEqual(
'<h1>Web</h1>\n' +
'<p>The <i class="yfm yfm-term_title" term-key=":html" aria-describedby=":html_element" id="">HTML</i> specification</p>\n' +
'<template id=":html_template"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>\n' +
'</dfn></template>',
);
expect(clearRandomId(result)).toEqual(`\
<template id=":html_template" label="html"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>
</dfn></template><h1>Web</h1>
<p>The <i class="yfm yfm-term_title" term-key=":html" aria-describedby=":html_element" id="">HTML</i> specification</p>
`);
});

test('Should create term in table with definition template', () => {
const inputPath = resolve(__dirname, './mocks/term/table.md');
const input = readFileSync(inputPath, 'utf8');
const result = transformYfm(input, inputPath);

expect(clearRandomId(result)).toEqual(
'<h1>Web</h1>\n' +
'<table>\n' +
'<thead>\n' +
'<tr>\n' +
'<th>Language</th>\n' +
'<th style="text-align:center">Initial release</th>\n' +
'</tr>\n' +
'</thead>\n' +
'<tbody>\n' +
'<tr>\n' +
'<td><i class="yfm yfm-term_title" term-key=":html" aria-describedby=":html_element" id="">HTML</i></td>\n' +
'<td style="text-align:center">1993</td>\n' +
'</tr>\n' +
'</tbody>\n' +
'</table>\n' +
'<template id=":html_template"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>\n' +
'</dfn></template>',
);
expect(clearRandomId(result)).toEqual(`\
<template id=":html_template" label="html"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>
</dfn></template><h1>Web</h1>
<table>
<thead>
<tr>
<th>Language</th>
<th style="text-align:center">Initial release</th>
</tr>
</thead>
<tbody>
<tr>
<td><i class="yfm yfm-term_title" term-key=":html" aria-describedby=":html_element" id="">HTML</i></td>
<td style="text-align:center">1993</td>
</tr>
</tbody>
</table>
`);
});

test('Should create term in code with definition template', () => {
const inputPath = resolve(__dirname, './mocks/term/code.md');
const input = readFileSync(inputPath, 'utf8');
const result = transformYfm(input, inputPath);

expect(clearRandomId(result)).toEqual(
'<h1>Web</h1>\n' +
'\n' +
' <div class="yfm-clipboard">\n' +
' <pre><code class="hljs"><i class="yfm yfm-term_title" term-key=":html" id="">HTML</i>: Lorem\n' +
'</code></pre>\n' +
'\n' +
' <svg width="16" height="16" viewBox="0 0 24 24" class="yfm-clipboard-button" data-animation="3">\n' +
' <path\n' +
' fill="currentColor"\n' +
' d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"\n' +
' />\n' +
' <path\n' +
' stroke="currentColor"\n' +
' fill="transparent"\n' +
' strokeWidth="1.5"\n' +
' d="M9.5 13l3 3l5 -5"\n' +
' visibility="hidden"\n' +
' >\n' +
' <animate\n' +
' id="visibileAnimation-3"\n' +
' attributeName="visibility"\n' +
' from="hidden"\n' +
' to="visible"\n' +
' dur="0.2s"\n' +
' fill="freeze"\n' +
' begin=""\n' +
' />\n' +
' <animate\n' +
' id="hideAnimation-3"\n' +
' attributeName="visibility"\n' +
' from="visible"\n' +
' to="hidden"\n' +
' dur="1s"\n' +
' begin="visibileAnimation-3.end+1"\n' +
' fill="freeze"\n' +
' />\n' +
' </path>\n' +
' </svg>\n' +
' </div>\n' +
'<template id=":html_template"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>\n' +
'</dfn></template>',
);
expect(clearRandomId(result)).toEqual(`\
<template id=":html_template" label="html"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>
</dfn></template><h1>Web</h1>
<div class="yfm-clipboard">
<pre><code class="hljs"><i class="yfm yfm-term_title" term-key=":html" id="">HTML</i>: Lorem
</code></pre>
<svg width="16" height="16" viewBox="0 0 24 24" class="yfm-clipboard-button" data-animation="10">
<path
fill="currentColor"
d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"
/>
<path
stroke="currentColor"
fill="transparent"
strokeWidth="1.5"
d="M9.5 13l3 3l5 -5"
visibility="hidden"
>
<animate
id="visibileAnimation-10"
attributeName="visibility"
from="hidden"
to="visible"
dur="0.2s"
fill="freeze"
begin=""
/>
<animate
id="hideAnimation-10"
attributeName="visibility"
from="visible"
to="hidden"
dur="1s"
begin="visibileAnimation-10.end+1"
fill="freeze"
/>
</path>
</svg>
</div>
`);
});

test('Term should use content from include', () => {
const inputPath = resolve(__dirname, './mocks/term/includeContent.md');
const input = readFileSync(inputPath, 'utf8');
const result = transformYfm(input, inputPath);

expect(clearRandomId(result)).toEqual(
'<h1>Web</h1>\n' +
'<p>The <i class="yfm yfm-term_title" term-key=":html" aria-describedby=":html_element" id="">HTML</i> specification</p>\n' +
'<template id=":html_template"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>\n' +
'</dfn></template>',
);
expect(clearRandomId(result)).toEqual(`\
<template id=":html_template" label="html"><dfn class="yfm yfm-term_dfn" id=":html_element" role="tooltip"><p>The HyperText Markup Language or <strong>HTML</strong> is the standard markup language for documents designed to be displayed in a web browser.</p>
</dfn></template><h1>Web</h1>
<p>The <i class="yfm yfm-term_title" term-key=":html" aria-describedby=":html_element" id="">HTML</i> specification</p>
`);
});
});

0 comments on commit 5a43e26

Please sign in to comment.