mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-18 03:26:57 +02:00
refactor: refactor code tab split (#1369)
* refactor: refactor code tab split * Add split tab unit test * Fix code tab list bug
This commit is contained in:
parent
5030952a8f
commit
0813920349
9 changed files with 671 additions and 43 deletions
|
@ -19,20 +19,120 @@ const translateThisDoc = translate(
|
|||
'Translate this Doc|recruitment message asking to translate the docs',
|
||||
);
|
||||
|
||||
const splitTabsToTitleAndContent = content => {
|
||||
const titles = content.match(/<!--(.*?)-->/gms);
|
||||
const tabs = content.split(/<!--.*?-->/gms);
|
||||
if (!titles || !tabs || !titles.length || !tabs.length) {
|
||||
return [];
|
||||
const splitTabsToTitleAndContent = (lines, indents) => {
|
||||
let first = false;
|
||||
let inBlock = false;
|
||||
let whitespace = false;
|
||||
const tc = [];
|
||||
let current = {
|
||||
content: [],
|
||||
};
|
||||
lines.forEach(line => {
|
||||
if (indents) {
|
||||
line = line.replace(new RegExp(`^((\\t|\\s{4}){${indents}})`, 'g'), '');
|
||||
}
|
||||
let pos = 0;
|
||||
const end = line.length;
|
||||
const isToken = (cline, cpos, ...chars) => {
|
||||
for (let i = 0; i < chars.length; i++) {
|
||||
if (cline.charCodeAt(cpos) !== chars[i]) {
|
||||
return false;
|
||||
}
|
||||
cpos++;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
while (pos + 1 < end) {
|
||||
// Skip all the whitespace when we first start the scan.
|
||||
for (let max = end; pos < max; pos++) {
|
||||
if (line.charCodeAt(pos) !== 0x20 && line.charCodeAt(pos) !== 0x0a) {
|
||||
break;
|
||||
}
|
||||
whitespace = true;
|
||||
}
|
||||
// Check for the start of a comment: <!--
|
||||
// If we're in a code block we skip it.
|
||||
if (
|
||||
isToken(
|
||||
line,
|
||||
pos,
|
||||
0x3c /* < */,
|
||||
0x21 /* ! */,
|
||||
0x2d /* - */,
|
||||
0x2d /* - */,
|
||||
) &&
|
||||
!inBlock
|
||||
) {
|
||||
if (current !== null && current.title !== undefined) {
|
||||
tc.push({
|
||||
title: current.title,
|
||||
content: current.content.join('\n'),
|
||||
});
|
||||
current = {
|
||||
content: [],
|
||||
};
|
||||
}
|
||||
first = true;
|
||||
pos += 4;
|
||||
let b0;
|
||||
let b1;
|
||||
const buf = [];
|
||||
// Add all characters to the title buffer until
|
||||
// we reach the end marker: -->
|
||||
for (let max = end; pos < max; pos++) {
|
||||
const b = line.charCodeAt(pos);
|
||||
if (b0 === 0x2d /* - */ && b1 === 0x2d /* - */) {
|
||||
if (b !== 0x3e /* > */) {
|
||||
throw new Error(`Invalid comment sequence "--"`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
buf.push(b);
|
||||
b0 = b1;
|
||||
b1 = b;
|
||||
}
|
||||
// Clear the line out before we add it to content.
|
||||
// This also means tabs can only be defined on a line by itself.
|
||||
line = '\n';
|
||||
// Trim the last 2 characters: --
|
||||
current.title = String.fromCharCode(...buf)
|
||||
.substring(0, buf.length - 2)
|
||||
.trim();
|
||||
}
|
||||
// If the first thing in a code tab is not a title it's invalid.
|
||||
if (!first) {
|
||||
throw new Error(`Invalid code tab markdown`);
|
||||
}
|
||||
// Check for code block: ```
|
||||
// If the line begins with whitespace we don't consider it a code block.
|
||||
if (
|
||||
isToken(line, pos, 0x60 /* ` */, 0x60 /* ` */, 0x60 /* ` */) &&
|
||||
!whitespace
|
||||
) {
|
||||
pos += 3;
|
||||
inBlock = !inBlock;
|
||||
}
|
||||
pos++;
|
||||
whitespace = false;
|
||||
}
|
||||
current.content.push(line);
|
||||
});
|
||||
if (current !== null && current.title !== undefined) {
|
||||
tc.push({
|
||||
title: current.title,
|
||||
content: current.content.join('\n'),
|
||||
});
|
||||
}
|
||||
tabs.shift();
|
||||
return titles.map((title, idx) => ({
|
||||
title: title.substring(4, title.length - 3).trim(),
|
||||
content: tabs[idx],
|
||||
}));
|
||||
return tc;
|
||||
};
|
||||
|
||||
const cleanTheCodeTag = content => {
|
||||
const cleanTheCodeTag = (content, indents) => {
|
||||
const prepend = (line, indent) => {
|
||||
if (indent) {
|
||||
return ' '.repeat(indent) + line;
|
||||
}
|
||||
return line;
|
||||
};
|
||||
const contents = content.split(/(<pre>)(.*?)(<\/pre>)/gms);
|
||||
let inCodeBlock = false;
|
||||
const cleanContents = contents.map(c => {
|
||||
|
@ -47,7 +147,7 @@ const cleanTheCodeTag = content => {
|
|||
if (inCodeBlock) {
|
||||
return c.replace(/\n/g, '<br />');
|
||||
}
|
||||
return c;
|
||||
return prepend(c, indents);
|
||||
});
|
||||
return cleanContents.join('');
|
||||
};
|
||||
|
@ -56,32 +156,43 @@ const cleanTheCodeTag = content => {
|
|||
class Doc extends React.Component {
|
||||
renderContent() {
|
||||
const {content} = this.props;
|
||||
let inCodeTabs = false;
|
||||
const contents = content.split(
|
||||
/(<!--DOCUSAURUS_CODE_TABS-->\n)(.*?)(\n<!--END_DOCUSAURUS_CODE_TABS-->)/gms,
|
||||
);
|
||||
|
||||
const renderResult = contents.map(c => {
|
||||
if (c === '<!--DOCUSAURUS_CODE_TABS-->\n') {
|
||||
inCodeTabs = true;
|
||||
return '';
|
||||
}
|
||||
if (c === '\n<!--END_DOCUSAURUS_CODE_TABS-->') {
|
||||
inCodeTabs = false;
|
||||
return '';
|
||||
}
|
||||
if (inCodeTabs) {
|
||||
let indents = 0;
|
||||
return content.replace(
|
||||
/(\t|\s{4})*?(<!--DOCUSAURUS_CODE_TABS-->\n)(.*?)((\n|\t|\s{4})<!--END_DOCUSAURUS_CODE_TABS-->)/gms,
|
||||
m => {
|
||||
const contents = m.split('\n').filter(c => {
|
||||
if (!indents) {
|
||||
indents = (
|
||||
c.match(/((\t|\s{4})+)<!--DOCUSAURUS_CODE_TABS-->/) || []
|
||||
).length;
|
||||
}
|
||||
if (c.match(/(\t|\s{4})+<!--DOCUSAURUS_CODE_TABS-->/)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
c.match(
|
||||
/<!--END_DOCUSAURUS_CODE_TABS-->|<!--DOCUSAURUS_CODE_TABS-->/,
|
||||
) ||
|
||||
(indents > 0 &&
|
||||
c.match(
|
||||
/(\t|\s{4})+(<!--END_DOCUSAURUS_CODE_TABS-->|<!--DOCUSAURUS_CODE_TABS-->)/,
|
||||
))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (indents) {
|
||||
indents -= 1;
|
||||
}
|
||||
const codeTabsMarkdownBlock = renderToStaticMarkup(
|
||||
<CodeTabsMarkdownBlock>
|
||||
{splitTabsToTitleAndContent(c)}
|
||||
{splitTabsToTitleAndContent(contents, indents)}
|
||||
</CodeTabsMarkdownBlock>,
|
||||
);
|
||||
return cleanTheCodeTag(codeTabsMarkdownBlock);
|
||||
}
|
||||
return c;
|
||||
});
|
||||
|
||||
return renderResult.join('');
|
||||
return cleanTheCodeTag(codeTabsMarkdownBlock, indents);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue