From 5163674cc56b2200a459798ad08bc9c2a1464a7d Mon Sep 17 00:00:00 2001 From: DCloud_LXH <283700113@qq.com> Date: Tue, 5 Mar 2024 17:22:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E8=A1=A8=E6=A0=BC?= =?UTF-8?q?=E8=A1=8C=E5=B1=95=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vuepress/config.js | 3 + .../markdown/markdown-it-subtable.js | 146 ++++++++++++++++++ package.json | 2 +- yarn.lock | 8 +- 4 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 docs/.vuepress/markdown/markdown-it-subtable.js diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 2e62b3e..c7e1646 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -114,6 +114,9 @@ const config = { .end() .plugin('add-base-to-md') .use(require('./markdown/add-base-to-md'), [{ base }]) + .end() + .plugin('subtable') + .use(require('./markdown/markdown-it-subtable').markdownIt, [{ flags: ['->'] }]) } }, chainWebpack (config, isServer) { diff --git a/docs/.vuepress/markdown/markdown-it-subtable.js b/docs/.vuepress/markdown/markdown-it-subtable.js new file mode 100644 index 0000000..50a0332 --- /dev/null +++ b/docs/.vuepress/markdown/markdown-it-subtable.js @@ -0,0 +1,146 @@ +function normalizeMD (md) { + if (typeof md === 'string') { + return md + .replace(/(? { + if (Array.isArray(tokenIndex) && tokenIndex.length > 2) { + const tableOpenIndex = tokenIndex.shift(); + const tableCloseIndex = tokenIndex.pop(); + let deleteOffset = 0; + + tokenIndex.forEach(subtableIndexes => { + const subtableOpenIndex = subtableIndexes.shift() + deleteOffset; + const subtableColumnCount = (subtableIndexes[0] + deleteOffset - subtableOpenIndex - 2) / 3 - 1; + const subtableCloseIndex = subtableIndexes.pop() + deleteOffset + subtableColumnCount * 3; + const subtableTokens = tokens.slice(subtableOpenIndex - 1, subtableCloseIndex + 1); + + // 2 table token 新行开始时固定的 tr_open td_open 数量 + // 3 每个 inline 都会伴随一个 td_close、td_open(行最后一列 inline 会伴随 td_close tr_close) + // 1 为 flag ->(标识符) 的列,需要去掉 + let tableColumnCount = 0; + for (let i = 0; i < tableCloseIndex; i++) { + const token = tokens[i]; + if (i < subtableOpenIndex) { + if (token.type === 'th_open') { + tableColumnCount++; + } else if (token.type === 'thead_close') { + break; + } + } + } + + let subtableMD = subtableTokens + .map(token => { + if (token.type === 'inline' && !flags.includes(token.content)) { + return normalizeMD(token.content); + } else if (token.type === 'tr_close') { + return '\n'; + } + }) + .filter(Boolean); + const subtableLevel = subtableTokens[0].level; + const newTokens = md.parse(`|${subtableMD.join('|')}|`); + newTokens.forEach(token => { + token.content = ''; // 和 children 内容重复 + token.level = token.level + subtableLevel; + }); + newTokens[0].attrJoin('style', 'overflow-x: visible;margin: auto;'); + const childrenTableTokenIndex = subtableOpenIndex - 2; + const subtablePrevTrOpenIndex = childrenTableTokenIndex - tableColumnCount * 3 - 2; + tokens[tableOpenIndex].attrJoin('class', 'have-children-table'); // table + tokens[subtablePrevTrOpenIndex].attrJoin('class', 'have-children-tr'); // table tr_open + + // table td_open + const haveChildrenTrTdToken = tokens[subtablePrevTrOpenIndex + 1]; + haveChildrenTrTdToken.attrJoin('class', 'have-children-tr-td'); + haveChildrenTrTdToken.attrJoin('style', ';text-wrap: nowrap'); + + tokens[childrenTableTokenIndex].attrJoin('class', 'children-table'); // subtable tr_open + tokens[childrenTableTokenIndex].attrJoin('hidden', ''); // subtable tr_open + + tokens[subtableOpenIndex - 1].attrJoin('colspan', tableColumnCount); // subtable td_open + const deleteCount = subtableCloseIndex - subtableOpenIndex + 1; + tokens.splice(subtableOpenIndex, deleteCount, ...newTokens); + deleteOffset = deleteOffset + newTokens.length - deleteCount; + }); + } + }); + } +} + +function process(md, tokens, flags = ['->']) { + const subtableMinTokenCount = 3; + if ( + Array.isArray(tokens) && + tokens.length && + tokens.some(token => token.content.includes('->') && token.type === 'inline') + ) { + const tableOpenTokenIndex = tokens.findIndex(token => token.type === 'table_open'); + if (tableOpenTokenIndex > -1) { + /** + * [ + * table_open index, + * [] // subtable indexes, + * table_close index + * ] + */ + let tableTokensIndexes = [[]]; + let tableIndex = 0; + let subtableIndex = 1; + tokens.forEach((token, index) => { + if (token.type === 'table_open' && tableTokensIndexes[tableIndex].length === 0) { + tableTokensIndexes[tableIndex].push(index); + } + if (tableTokensIndexes[tableIndex] && typeof tableTokensIndexes[tableIndex][0] !== 'undefined') { + if (token.type === 'inline') { + if (flags.find(flag => new RegExp(`^\\s*${flag}\\s*$`).test(token.content))) { + ( + tableTokensIndexes[tableIndex][subtableIndex] || (tableTokensIndexes[tableIndex][subtableIndex] = []) + ).push(index); + } else if (tokens[index - 2].type === 'tr_open') { + tableTokensIndexes[tableIndex][++subtableIndex] = []; + } + } + } + if (token.type === 'table_close') { + subtableIndex = 1; + tableTokensIndexes[tableIndex].push(index); + tableTokensIndexes[++tableIndex] = []; + } + }); + tableTokensIndexes.forEach((subtableTokensIndex, index) => { + tableTokensIndexes[index] = subtableTokensIndex.filter( + i => typeof i === 'number' || (Array.isArray(i) && i.length >= subtableMinTokenCount) + ); + }); + tableTokensIndexes = tableTokensIndexes.filter(i => i.length); + if (tableTokensIndexes.length) { + resolveSubtable(md, tokens, tableTokensIndexes, flags); + } + } + } +} + +module.exports = { + process, + markdownIt: function subTablePlugin(md, { flags = ['->'] } = {}) { + md.core.ruler.after( + 'inline', + 'subtable', + (state, startLine, endLine, silent) => { + process(md, state.tokens, flags); + }, + { + alt: ['paragraph', 'reference'], + } + ); + }, +}; diff --git a/package.json b/package.json index 0cef209..31435e0 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "markdown-it-attrs": "^4.1.6", "markdown-it-raw-table": "^1.0.0", "markdown-it-task-lists": "^2.1.1", - "vuepress-theme-uni-app-test": "^1.4.5" + "vuepress-theme-uni-app-test": "^1.4.7" }, "dependencies": { "@docsearch/js": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index eaceae9..5d78e6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9288,10 +9288,10 @@ vuepress-plugin-zooming@^1.1.8: dependencies: zooming "^2.1.1" -vuepress-theme-uni-app-test@^1.4.5: - version "1.4.5" - resolved "https://registry.npmmirror.com/vuepress-theme-uni-app-test/-/vuepress-theme-uni-app-test-1.4.5.tgz#c996fcf2baef6e6610e065671d6f0d29328ce97f" - integrity sha512-Zo8T2lH6d3TCf9Dghkz0NrzWbdOB0czisdbFqnB0P4H9K/qkM7SBDJCxeF9tVvS+p4GB49jwHAH24CTfDKYY9Q== +vuepress-theme-uni-app-test@^1.4.7: + version "1.4.7" + resolved "https://registry.npmmirror.com/vuepress-theme-uni-app-test/-/vuepress-theme-uni-app-test-1.4.7.tgz#566be747f080f551a0f65ac306ccc09dab2ab623" + integrity sha512-O+4FGNetUqEHBpz/EE7KJlwNP3LrU2iz7W1WEq2vHnowPyOxwB2DiSA1aHaHhX1zDAG4n/HILQXhjH48r4uGhw== dependencies: "@vuepress/plugin-back-to-top" "^1.9.5" "@vuepress/theme-default" "^1.8.2" -- GitLab