diff --git a/apps/docs/components/docs/components/helper.ts b/apps/docs/components/docs/components/helper.ts index f9c46f0db2..862e39a490 100644 --- a/apps/docs/components/docs/components/helper.ts +++ b/apps/docs/components/docs/components/helper.ts @@ -12,10 +12,8 @@ export type TransformTokensTypes = TransformTokens[0][0] & { const startFlag = ["{", "["]; const endFlag = ["}", "]"]; -const specialStartFlag = ["("]; -const specialEndFlag = [")"]; -const defaultFoldFlagList = ["cn", "HTMLAttributes"]; -const defaultShowFlagList = ["Component", "forwardRef", "App", "Example", "AddForm", "SignupForm"]; +const isElementStartRegex = /^\s* { if (index < lastIndex) { return; } + token.forEach((t) => { + (t as TransformTokensTypes).index = index; + }); + result.push(token); - let startToken: TransformTokens[0][0] = null as any; - let mergedStartFlagList = [...startFlag]; + const lineContent = getLineContent(token); + const {isStartTag, isEndTag} = checkIsElement(lineContent); - token.forEach((t) => { - if (defaultFoldFlagList.some((text) => t.content.includes(text))) { - // If cn then need to judge whether it is import token - if (t.content.includes("cn") && token.some((t) => t.content === "import")) { - return; - } + // If it has startElementName means it is within the element range + if (startElementName) { + if (isEndTag) { + // Judge whether it is the end tag of the element then reset startElementName + const {endElementName} = getElementName(lineContent); - // If HTMLAttributes then need to judge whether it have start flag - if ( - t.content.includes("HTMLAttributes") && - !token.some((t) => startFlag.includes(t.content)) - ) { - return; + if (endElementName === startElementName) { + startElementName = ""; } - - fold = true; - mergedStartFlagList.push(...specialStartFlag); } - if (mergedStartFlagList.includes(t.content)) { - startToken = t; + return; + } else if (isStartTag) { + const {startElementName: elementName, endElementName} = getElementName(lineContent); + + if (!endElementName) { + startElementName = elementName; + + return; } + } - if (defaultShowFlagList.some((text) => t.content.includes(text))) { - isShowFolder = true; + let startToken: TransformTokens[0][0] = null as any; + + token.forEach((t) => { + if (startFlag.includes(t.content)) { + startToken = t; } }); - const mergedOptions = fold - ? { - specialEndFlag, - specialStartFlag, - } - : undefined; - const isFolder = checkIsFolder(token, mergedOptions); + const isFolder = checkIsFolder(token); if (isFolder && startToken) { - const endIndex = findEndIndex(tokens, index + 1, mergedOptions); - - // Greater than or equal to folderLine then will folder otherwise it will show directly - if (endIndex !== -1 && (endIndex - index >= folderLine || isShowFolder || fold)) { - lastIndex = endIndex; - const folder = tokens.slice(index + 1, endIndex); - const endToken = tokens[endIndex]; - const ellipsisToken: TransformTokensTypes = { - types: ["ellipsis"], - content: "", - class: "custom-folder ellipsis-token", - }; - const copyContent: TransformTokensTypes = { - types: ["copy"], - content: "", - folderContent: folder, - class: "custom-folder copy-token", - }; - - endToken.forEach((t, _, arr) => { - let className = ""; - - className += "custom-folder"; - if (t.content.trim() === "" && (arr.length === 3 || arr.length === 4)) { - // Add length check to sure it's added to } token - className += " empty-token"; - } - (t as TransformTokensTypes).class = className; - }); - - startToken.types = ["folderStart"]; - (startToken as TransformTokensTypes).folderContent = folder; - (startToken as TransformTokensTypes).summaryContent = [ - ...token, - ellipsisToken, - copyContent, - ...endToken, - ]; - (startToken as TransformTokensTypes).index = index; - if (isShowFolder && !fold) { - (startToken as TransformTokensTypes).open = true; - } - - result.push([startToken]); - - isShowFolder = false; - fold = false; + const nextLineContent = tokens.slice(index + 1, index + 2).reduce((acc, line) => { + return acc + getLineContent(line); + }, ""); + const isNextLineObjectFolder = checkIsObjectContent(nextLineContent); + const isArrayFolder = lineContent.trim().endsWith("["); + + if (isNextLineObjectFolder || isArrayFolder) { + const endIndex = findEndIndex(tokens, index + 1); + + // Greater than or equal to folderLine then will folder otherwise it will show directly + if (endIndex !== -1 && endIndex - index >= folderLine) { + lastIndex = endIndex; + const folder = tokens.slice(index + 1, endIndex); + const endToken = tokens[endIndex]; + + (endToken[0] as TransformTokensTypes).class = "first-custom-folder"; + + const ellipsisToken: TransformTokensTypes = { + types: ["ellipsis"], + content: "", + class: "custom-folder ellipsis-token", + }; + const copyContent: TransformTokensTypes = { + types: ["copy"], + content: "", + folderContent: folder, + class: "custom-folder copy-token", + }; + + endToken.forEach((t, _, arr) => { + let className = (t as TransformTokensTypes).class || ""; + + className += " custom-folder"; + if (t.content.trim() === "" && (arr.length === 3 || arr.length === 4)) { + // Add length check to sure it's added to } token + className += " empty-token"; + } + (t as TransformTokensTypes).class = className; + }); + + startToken.types = ["folderStart"]; + (startToken as TransformTokensTypes).folderContent = folder; + (startToken as TransformTokensTypes).summaryContent = [ + ...token, + ellipsisToken, + copyContent, + ...endToken, + ]; + (startToken as TransformTokensTypes).index = index; + // isShowFolder && ((startToken as TransformTokensTypes).open = true); + + result.splice(result.length - 1, 1, [startToken]); - return; + return; + } } } - token.forEach((t) => { - (t as TransformTokensTypes).index = index; - }); - result.push(token); }); return result; } -interface SpecialOptions { - specialStartFlag?: string[]; - specialEndFlag?: string[]; -} - -function checkIsFolder( - token: TransformTokens[0], - {specialStartFlag, specialEndFlag}: SpecialOptions = {}, -) { +function checkIsFolder(token: TransformTokens[0]) { const stack: string[] = []; - const mergedStartFlagList = specialStartFlag ? [...startFlag, ...specialStartFlag] : startFlag; - const mergedEndFlagList = specialEndFlag ? [...endFlag, ...specialEndFlag] : endFlag; for (const t of token) { - if (mergedStartFlagList.includes(t.content)) { + if (startFlag.includes(t.content)) { stack.push(t.content); - } else if (mergedEndFlagList.includes(t.content)) { + } else if (endFlag.includes(t.content)) { stack.pop(); } } @@ -158,14 +147,8 @@ function checkIsFolder( return stack.length !== 0; } -function findEndIndex( - tokens: TransformTokens, - startIndex: number, - {specialStartFlag, specialEndFlag}: SpecialOptions = {}, -) { +function findEndIndex(tokens: TransformTokens, startIndex: number) { const stack: string[] = ["flag"]; - const mergedStartFlagList = specialStartFlag ? [...startFlag, ...specialStartFlag] : startFlag; - const mergedEndFlagList = specialEndFlag ? [...endFlag, ...specialEndFlag] : endFlag; for (let i = startIndex; i < tokens.length; i++) { const token = tokens[i]; @@ -173,9 +156,9 @@ function findEndIndex( for (const line of token) { const transformLine = line.content.replace(/\$/g, ""); - if (mergedStartFlagList.includes(transformLine)) { + if (startFlag.includes(transformLine)) { stack.push("flag"); - } else if (mergedEndFlagList.includes(transformLine)) { + } else if (endFlag.includes(transformLine)) { stack.pop(); } @@ -187,3 +170,40 @@ function findEndIndex( return -1; } + +function checkIsElement(lineContent: string) { + return { + isStartTag: isElementStartRegex.test(lineContent), + isEndTag: isElementEndRegex.test(lineContent), + }; +} + +function getElementName(lineContent: string) { + const startElementName = lineContent.match(/^\s*<([a-zA-Z.]+)/); + const endElementName = lineContent.match(/^\s*<\/([a-zA-Z.]+)>/); + + return { + startElementName: startElementName?.[1] || (lineContent.includes("<>") ? "<>" : ""), + endElementName: endElementName?.[1] || (lineContent.includes("") ? "" : ""), + }; +} + +function getLineContent(token: TransformTokens[0]) { + return token.reduce((acc, t) => acc + t.content, ""); +} + +function checkIsObjectContent(lineContent: string) { + lineContent = lineContent.trim(); + // first: match { a } + // second: match { a: b } + // third: match { a (b) } + // fourth: match /** */ + const isObjectContent = /^([\w]+,?$)|([\w\[.\]]+:)|([\w]+\s?\(.*?\)$)|(^\/\*\*)/.test( + lineContent, + ); + const hasEqual = /\s=\s/.test(lineContent); + const hasFunction = lineContent.includes("function"); + const hasVariable = /var|let|const/.test(lineContent); + + return isObjectContent && !hasEqual && !hasFunction && !hasVariable; +}