1+ const fs = require ( 'fs' ) . promises ;
2+ const path = require ( 'path' ) ;
3+
4+ // 命令行参数处理:获取要扫描的文件夹路径,默认是当前目录
5+ const targetDir = process . argv [ 2 ] || process . cwd ( ) ;
6+
7+ /**
8+ * 递归扫描目录,收集符合条件的Markdown文件
9+ * @param {string } dir - 要扫描的目录
10+ * @param {string } baseDir - 基础目录,用于计算相对路径
11+ * @returns {Promise<Array> } - 文件结构数组
12+ */
13+ async function scanDirectory ( dir , baseDir = dir ) {
14+ const results = [ ] ;
15+ const entries = await fs . readdir ( dir , { withFileTypes : true } ) ;
16+
17+ for ( const entry of entries ) {
18+ const fullPath = path . join ( dir , entry . name ) ;
19+ const relativePath = path . relative ( baseDir , fullPath ) ;
20+
21+ // 忽略以_开头的文件和目录
22+ if ( entry . name . startsWith ( '_' ) || entry . name . startsWith ( 'README' ) ) {
23+ continue ;
24+ }
25+
26+ if ( entry . isDirectory ( ) ) {
27+ // 递归处理子目录
28+ const subDirFiles = await scanDirectory ( fullPath , baseDir ) ;
29+ if ( subDirFiles . length > 0 ) {
30+ results . push ( {
31+ type : 'directory' ,
32+ name : entry . name ,
33+ path : relativePath ,
34+ children : subDirFiles
35+ } ) ;
36+ }
37+ } else if ( entry . isFile ( ) && path . extname ( entry . name ) === '.md' ) {
38+ // 处理Markdown文件
39+ results . push ( {
40+ type : 'file' ,
41+ name : path . basename ( entry . name , '.md' ) , // 去除.md扩展名
42+ path : relativePath
43+ } ) ;
44+ }
45+ }
46+
47+ // 排序逻辑:
48+ // 1. 文件夹(directory)排在文件(file)前面
49+ // 2. 同一类型的按名称首字母顺序排序(支持国际化)
50+ return results . sort ( ( a , b ) => {
51+ // 先按类型排序:文件夹在前,文件在后
52+ if ( a . type !== b . type ) {
53+ return a . type === 'directory' ? - 1 : 1 ;
54+ }
55+
56+ // 再按名称首字母排序,使用localeCompare确保正确的字母顺序
57+ return a . name . localeCompare ( b . name , undefined , {
58+ sensitivity : 'base' , // 不区分大小写
59+ numeric : true // 正确处理包含数字的名称
60+ } ) ;
61+ } ) ;
62+ }
63+
64+ /**
65+ * 将文件结构转换为docsify侧边栏格式的Markdown
66+ * @param {Array } items - 文件结构数组
67+ * @param {number } level - 层级,用于生成缩进
68+ * @returns {string } - 侧边栏Markdown内容
69+ */
70+ function generateSidebarMarkdown ( items , level = 0 ) {
71+ const indent = ' ' . repeat ( level ) ;
72+ let markdown = '' ;
73+
74+ for ( const item of items ) {
75+ if ( item . type === 'directory' ) {
76+ // 目录项
77+ markdown += `${ indent } - [${ item . name } ](${ item . path } /)\n` ;
78+ // 递归处理子项,层级+1
79+ markdown += generateSidebarMarkdown ( item . children , level + 1 ) ;
80+ } else if ( item . type === 'file' ) {
81+ // 文件项
82+ markdown += `${ indent } - [${ item . name } ](${ item . path } )\n` ;
83+ }
84+ }
85+
86+ return markdown ;
87+ }
88+
89+ /**
90+ * 主函数:扫描目录并生成侧边栏文件
91+ */
92+ async function main ( ) {
93+ try {
94+ console . log ( `开始扫描目录: ${ targetDir } ` ) ;
95+
96+ // 扫描目录获取文件结构
97+ const fileStructure = await scanDirectory ( targetDir ) ;
98+
99+ // 生成侧边栏Markdown内容
100+ const sidebarContent = generateSidebarMarkdown ( fileStructure ) ;
101+
102+ // 输出文件路径
103+ const outputPath = path . join ( process . cwd ( ) , '_sidebar.md' ) ;
104+
105+ // 写入文件
106+ await fs . writeFile ( outputPath , sidebarContent ) ;
107+
108+ console . log ( `侧边栏已生成: ${ outputPath } ` ) ;
109+ console . log ( '生成完成!' ) ;
110+ } catch ( error ) {
111+ console . error ( '生成侧边栏时出错:' , error . message ) ;
112+ process . exit ( 1 ) ;
113+ }
114+ }
115+
116+ // 执行主函数
117+ main ( ) ;
118+
0 commit comments