mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 02:49:18 +08:00
docs(dumi-plugin):Improved changelog detail processing logic (#55302)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { UnifiedTransformer } from 'dumi';
|
||||
import { unistUtilVisit } from 'dumi';
|
||||
import semver from 'semver';
|
||||
import set from 'lodash/set';
|
||||
|
||||
let hastToString: typeof import('hast-util-to-string').toString;
|
||||
@@ -9,6 +10,24 @@ let hastToString: typeof import('hast-util-to-string').toString;
|
||||
({ toString: hastToString } = await import('hast-util-to-string'));
|
||||
})();
|
||||
|
||||
function isValidStrictVer(ver: string): boolean {
|
||||
if (!semver.valid(ver)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parts = ver.split('.');
|
||||
if (parts.length !== 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parts.every((part) => /^\d+$/.test(part));
|
||||
}
|
||||
|
||||
function isValidDate(dateStr: string): boolean {
|
||||
// (YYYY-MM-DD)
|
||||
return /^\d{4}-\d{2}-\d{2}$/.test(dateStr);
|
||||
}
|
||||
|
||||
const COMPONENT_NAME = 'RefinedChangelog';
|
||||
|
||||
function rehypeChangelog(): UnifiedTransformer<any> {
|
||||
@@ -23,32 +42,69 @@ function rehypeChangelog(): UnifiedTransformer<any> {
|
||||
const nodesToWrap: { parent: any; startIdx: number }[] = [];
|
||||
const WRAPPER_FLAG = 'data-changelog-wrapped'; // 包裹容器唯一标识
|
||||
|
||||
function checkLogSegment(node: any, strict = true) {
|
||||
if (node && node.type === 'element' && node.tagName === 'h2') {
|
||||
if (strict) {
|
||||
const ver = hastToString(node);
|
||||
return isValidStrictVer(ver) && semver.major(ver) >= 5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unistUtilVisit.visit(tree, 'element', (node, idx, parent) => {
|
||||
if (node.properties?.[WRAPPER_FLAG]) {
|
||||
return unistUtilVisit.SKIP;
|
||||
}
|
||||
if (
|
||||
idx !== undefined &&
|
||||
parent &&
|
||||
idx! + 2 < parent.children.length &&
|
||||
node.tagName === 'h2' &&
|
||||
parent.children[idx! + 1].tagName === 'p' &&
|
||||
parent.children[idx! + 2].tagName === 'ul'
|
||||
) {
|
||||
|
||||
if (idx !== undefined && parent && checkLogSegment(node)) {
|
||||
nodesToWrap.push({ parent, startIdx: idx! });
|
||||
}
|
||||
});
|
||||
|
||||
nodesToWrap.reverse().forEach(({ parent, startIdx }) => {
|
||||
const [heading, date, list] = parent.children.splice(startIdx, 3);
|
||||
const totalNodesToWrap = nodesToWrap.length;
|
||||
for (let i = totalNodesToWrap - 1; i >= 0; i--) {
|
||||
const { parent, startIdx } = nodesToWrap[i];
|
||||
|
||||
let endIdx = -1;
|
||||
const isEndOfWrap = i === totalNodesToWrap - 1;
|
||||
for (let j = startIdx + 1; j < parent.children.length; j++) {
|
||||
const nextNode = parent.children[j];
|
||||
if (
|
||||
(isEndOfWrap && checkLogSegment(nextNode, false)) || // 日志页通常还存在历史 major 版本
|
||||
nextNode.properties?.[WRAPPER_FLAG] || // 已经被处理
|
||||
checkLogSegment(nextNode) // 下一段日志
|
||||
) {
|
||||
endIdx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (endIdx === -1) continue;
|
||||
|
||||
// Version
|
||||
const heading = parent.children[startIdx];
|
||||
|
||||
// Find Date
|
||||
let dateIdx = -1;
|
||||
for (let j = startIdx + 1; j < endIdx; j++) {
|
||||
const node = parent.children[j];
|
||||
if (node.type === 'element' && isValidDate(hastToString(node))) {
|
||||
dateIdx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dateIdx === -1) continue;
|
||||
|
||||
// Collect list nodes between dateIdx and endIdx
|
||||
const version = hastToString(heading);
|
||||
const date = parent.children[dateIdx];
|
||||
const dateStr = hastToString(date);
|
||||
const details = parent.children.slice(dateIdx + 1, endIdx);
|
||||
|
||||
const headingWrap = {
|
||||
type: 'element',
|
||||
tagName: `${COMPONENT_NAME}.Version`,
|
||||
// 为标签添加语义化 className (下面同理)
|
||||
children: [set(heading, 'properties.className', 'changelog-version')],
|
||||
};
|
||||
|
||||
@@ -58,10 +114,13 @@ function rehypeChangelog(): UnifiedTransformer<any> {
|
||||
children: [set(date, 'properties.className', 'changelog-date')],
|
||||
};
|
||||
|
||||
const listWrap = {
|
||||
const detailWrap = {
|
||||
type: 'element',
|
||||
tagName: `${COMPONENT_NAME}.Details`,
|
||||
children: [set(list, 'properties.className', 'changelog-details')],
|
||||
properties: {
|
||||
className: 'changelog-details',
|
||||
},
|
||||
children: details,
|
||||
};
|
||||
|
||||
const wrapper = {
|
||||
@@ -82,11 +141,11 @@ function rehypeChangelog(): UnifiedTransformer<any> {
|
||||
value: JSON.stringify(dateStr),
|
||||
},
|
||||
],
|
||||
children: [headingWrap, dateWrap, listWrap],
|
||||
children: [headingWrap, dateWrap, detailWrap],
|
||||
};
|
||||
|
||||
parent.children.splice(startIdx, 0, wrapper);
|
||||
});
|
||||
parent.children.splice(startIdx, endIdx - startIdx, wrapper);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,10 @@ const Version: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||
|
||||
const DateComp: React.FC<React.PropsWithChildren> = (props) => props.children;
|
||||
|
||||
const DetailsComp: React.FC<React.PropsWithChildren> = (props) => props.children;
|
||||
const DetailsComp: React.FC<React.PropsWithChildren<HTMLDivElement>> = (props) => {
|
||||
const { children, className } = props;
|
||||
return <div className={className}>{children}</div>;
|
||||
};
|
||||
|
||||
export default Object.assign(RefinedChangelog, {
|
||||
Version,
|
||||
|
||||
Reference in New Issue
Block a user