@tnotesjs/core 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/config/ConfigManager.ts +137 -0
- package/config/constants.ts +121 -0
- package/config/defaultConfig.ts +33 -4
- package/config/index.ts +31 -0
- package/config/templates.ts +49 -0
- package/core/GitManager.ts +513 -0
- package/core/NoteIndexCache.ts +200 -0
- package/core/NoteManager.ts +395 -0
- package/core/ProcessManager.ts +180 -0
- package/core/ReadmeGenerator.ts +215 -0
- package/core/TocGenerator.ts +212 -0
- package/core/index.ts +11 -0
- package/dist/{chunk-5Y5IYS6C.js → chunk-UJG3UU5X.js} +21 -5
- package/dist/{chunk-5QN44ES5.js → chunk-XCWFZLER.js} +48 -368
- package/dist/cli/index.js +26 -78
- package/dist/index.js +1 -1
- package/dist/vitepress/config/index.js +2 -2
- package/package.json +5 -2
- package/services/file-watcher/configChangeHandler.ts +64 -0
- package/services/file-watcher/eventScheduler.ts +179 -0
- package/services/file-watcher/folderChangeHandler.ts +325 -0
- package/services/file-watcher/fsWatcherAdapter.ts +128 -0
- package/services/file-watcher/globalUpdateCoordinator.ts +60 -0
- package/services/file-watcher/index.ts +7 -0
- package/services/file-watcher/internal.ts +79 -0
- package/services/file-watcher/readmeChangeHandler.ts +28 -0
- package/services/file-watcher/renameDetector.ts +120 -0
- package/services/file-watcher/service.ts +352 -0
- package/services/file-watcher/watchState.ts +194 -0
- package/services/git/index.ts +7 -0
- package/services/git/service.ts +114 -0
- package/services/index.ts +14 -0
- package/services/init-sub-repo/index.ts +2 -0
- package/services/init-sub-repo/initSubRepoLogic.test.ts +162 -0
- package/services/init-sub-repo/initSubRepoLogic.ts +303 -0
- package/services/init-sub-repo/service.ts +101 -0
- package/services/note/index.ts +7 -0
- package/services/note/service.ts +361 -0
- package/services/readme/index.ts +7 -0
- package/services/readme/service.ts +761 -0
- package/services/toc/index.ts +5 -0
- package/services/toc/moveTocInside.test.ts +73 -0
- package/services/toc/service.ts +759 -0
- package/services/vitepress/index.ts +7 -0
- package/services/vitepress/service.ts +339 -0
- package/types/config.ts +0 -3
- package/types/note.ts +0 -2
- package/utils/errorHandler.ts +174 -0
- package/utils/file.ts +17 -0
- package/utils/genHierarchicalSidebar.ts +69 -0
- package/utils/generateAnchor.ts +24 -0
- package/utils/getChangedIds.ts +35 -0
- package/utils/index.ts +71 -0
- package/utils/logger.ts +231 -0
- package/utils/markdown.ts +75 -0
- package/utils/migrateReadmeToToc.test.ts +111 -0
- package/utils/migrateReadmeToToc.ts +135 -0
- package/utils/parseArgs.ts +90 -0
- package/utils/parseReadmeCompletedNotes.test.ts +90 -0
- package/utils/parseReadmeCompletedNotes.ts +108 -0
- package/utils/portUtils.ts +113 -0
- package/utils/readmeHelpers.ts +190 -0
- package/utils/runCommand.ts +29 -0
- package/utils/tocHelpers.test.ts +278 -0
- package/utils/tocHelpers.ts +855 -0
- package/utils/tocNodeId.test.ts +60 -0
- package/utils/tocNodeId.ts +97 -0
- package/utils/validators.ts +102 -0
- package/vitepress/assets/icons/icon__cursor.svg +4 -0
- package/vitepress/assets/icons/index.ts +1 -0
- package/vitepress/components/Layout/AboutPanel.vue +0 -24
- package/vitepress/components/Layout/DocBeforeControls.vue +6 -14
- package/vitepress/components/Layout/DocFooter.vue +3 -3
- package/vitepress/components/Layout/Layout.vue +0 -30
- package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +20 -11
- package/vitepress/components/Layout/homeReadme.data.ts +0 -48
- package/vitepress/components/MarkMap/MarkMap.vue +6 -13
- package/vitepress/components/Settings/Settings.vue +76 -73
- package/vitepress/components/SidebarCard/FolderTreeItems.vue +16 -6
- package/vitepress/components/SidebarCard/SidebarCard.vue +21 -27
- package/vitepress/components/composables/useLocalIde.ts +83 -0
- package/vitepress/components/constants.ts +5 -6
- package/vitepress/components/utils/vscodePaths.test.ts +22 -0
- package/vitepress/components/utils/vscodePaths.ts +24 -2
- package/vitepress/theme/styles/doc-layout.scss +4 -4
package/README.md
CHANGED
|
@@ -69,7 +69,6 @@ export { default } from '@tnotesjs/core/vitepress/theme'
|
|
|
69
69
|
"tn:push": "tnotes --push",
|
|
70
70
|
"tn:pull": "tnotes --pull",
|
|
71
71
|
"tn:create-notes": "tnotes --create-notes",
|
|
72
|
-
"tn:fix-timestamps": "tnotes --fix-timestamps",
|
|
73
72
|
"tn:help": "tnotes --help",
|
|
74
73
|
"tn:init-sub-repo": "tnotes --init-sub-repo"
|
|
75
74
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/ConfigManager.ts
|
|
3
|
+
*
|
|
4
|
+
* 配置管理器 - 统一管理项目配置
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'fs'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
|
|
9
|
+
import { validateAndCompleteConfig } from './defaultConfig'
|
|
10
|
+
|
|
11
|
+
import type { TNotesConfig } from '../types'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 配置管理器(单例模式)
|
|
15
|
+
*/
|
|
16
|
+
export class ConfigManager {
|
|
17
|
+
private static instance: ConfigManager
|
|
18
|
+
private config: TNotesConfig | null = null
|
|
19
|
+
private configPath: string
|
|
20
|
+
private rootPath: string
|
|
21
|
+
|
|
22
|
+
private constructor(rootPath?: string) {
|
|
23
|
+
if (rootPath) {
|
|
24
|
+
// 显式传入根路径
|
|
25
|
+
this.rootPath = rootPath
|
|
26
|
+
} else {
|
|
27
|
+
// 默认使用 process.cwd()(CLI 和 VitePress 均在项目根目录执行)
|
|
28
|
+
this.rootPath = process.cwd()
|
|
29
|
+
}
|
|
30
|
+
this.configPath = path.normalize(
|
|
31
|
+
path.resolve(this.rootPath, '.tnotes.json'),
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 使用指定的根路径初始化配置管理器
|
|
37
|
+
*
|
|
38
|
+
* 必须在 getInstance() 之前调用(如果需要指定 rootPath)。
|
|
39
|
+
* 如果已经初始化,则忽略重复调用。
|
|
40
|
+
*/
|
|
41
|
+
static init({ rootPath }: { rootPath: string }): ConfigManager {
|
|
42
|
+
if (!ConfigManager.instance) {
|
|
43
|
+
ConfigManager.instance = new ConfigManager(rootPath)
|
|
44
|
+
}
|
|
45
|
+
return ConfigManager.instance
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 获取单例实例
|
|
50
|
+
*/
|
|
51
|
+
static getInstance(): ConfigManager {
|
|
52
|
+
if (!ConfigManager.instance) {
|
|
53
|
+
ConfigManager.instance = new ConfigManager()
|
|
54
|
+
}
|
|
55
|
+
return ConfigManager.instance
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 加载配置文件
|
|
60
|
+
*/
|
|
61
|
+
loadConfig(configPath?: string): TNotesConfig {
|
|
62
|
+
if (this.config) return this.config
|
|
63
|
+
|
|
64
|
+
const path = configPath || this.configPath
|
|
65
|
+
|
|
66
|
+
if (!fs.existsSync(path)) {
|
|
67
|
+
throw new Error(`配置文件不存在: ${path}`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const configContent = fs.readFileSync(path, 'utf-8')
|
|
71
|
+
const rawConfig = JSON.parse(configContent)
|
|
72
|
+
|
|
73
|
+
// 验证并补全配置
|
|
74
|
+
const { config: validatedConfig, modified } =
|
|
75
|
+
validateAndCompleteConfig(rawConfig)
|
|
76
|
+
|
|
77
|
+
if (modified) {
|
|
78
|
+
console.warn(`[ConfigManager] 检测到知识库配置缺失字段,已自动补全`)
|
|
79
|
+
// 写回配置文件
|
|
80
|
+
fs.writeFileSync(path, JSON.stringify(validatedConfig, null, 2), 'utf-8')
|
|
81
|
+
console.log(`[ConfigManager] 知识库配置文件已更新`)
|
|
82
|
+
console.log(`[ConfigManager] 知识库配置文件路径: ${path}`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.config = validatedConfig
|
|
86
|
+
|
|
87
|
+
return this.config
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 清除内存中的配置缓存,下次 get/getAll 时重新从磁盘加载
|
|
92
|
+
*/
|
|
93
|
+
clearCache(): void {
|
|
94
|
+
this.config = null
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 获取配置项
|
|
99
|
+
*/
|
|
100
|
+
get<K extends keyof TNotesConfig>(key: K): TNotesConfig[K] {
|
|
101
|
+
if (!this.config) {
|
|
102
|
+
this.loadConfig()
|
|
103
|
+
}
|
|
104
|
+
return this.config![key]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 获取所有配置
|
|
109
|
+
*/
|
|
110
|
+
getAll(): TNotesConfig {
|
|
111
|
+
if (!this.config) {
|
|
112
|
+
this.loadConfig()
|
|
113
|
+
}
|
|
114
|
+
return this.config!
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 获取项目根路径
|
|
119
|
+
*/
|
|
120
|
+
getRootPath(): string {
|
|
121
|
+
return this.rootPath
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @deprecated 使用 getRootPath() 替代
|
|
126
|
+
*/
|
|
127
|
+
getDirname(): string {
|
|
128
|
+
return path.resolve(this.rootPath, '.vitepress', 'tnotes', 'config')
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 获取配置管理器实例(便捷函数)
|
|
134
|
+
*/
|
|
135
|
+
export function getConfigManager(): ConfigManager {
|
|
136
|
+
return ConfigManager.getInstance()
|
|
137
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/constants.ts
|
|
3
|
+
*
|
|
4
|
+
* 常量定义(从配置中派生的路径和URL常量)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { resolve } from 'path'
|
|
8
|
+
|
|
9
|
+
import { getConfigManager } from './ConfigManager'
|
|
10
|
+
import { getDefaultConfig } from './defaultConfig'
|
|
11
|
+
|
|
12
|
+
import type { TNotesConfig } from '../types'
|
|
13
|
+
|
|
14
|
+
function loadConfigOrDefault(): TNotesConfig {
|
|
15
|
+
try {
|
|
16
|
+
return getConfigManager().getAll()
|
|
17
|
+
} catch {
|
|
18
|
+
return getDefaultConfig()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const configManager = getConfigManager()
|
|
23
|
+
const config = loadConfigOrDefault()
|
|
24
|
+
|
|
25
|
+
// 导出配置项(向后兼容)
|
|
26
|
+
export const {
|
|
27
|
+
author,
|
|
28
|
+
ignore_dirs,
|
|
29
|
+
menuItems,
|
|
30
|
+
port,
|
|
31
|
+
repoName,
|
|
32
|
+
sidebarShowNoteId,
|
|
33
|
+
socialLinks,
|
|
34
|
+
root_item,
|
|
35
|
+
} = config
|
|
36
|
+
|
|
37
|
+
// 目录常量 —— 从 ConfigManager.getRootPath() 派生
|
|
38
|
+
const rootPath = configManager.getRootPath()
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* TNotes.* 当前的笔记仓库根路径
|
|
42
|
+
* @example `/Users/huyouda/zm/notes/TNotes.template/`
|
|
43
|
+
*/
|
|
44
|
+
export const ROOT_DIR_PATH = rootPath
|
|
45
|
+
export const ROOT_README_PATH = resolve(ROOT_DIR_PATH, 'README.md')
|
|
46
|
+
export const ROOT_TOC_PATH = resolve(ROOT_DIR_PATH, 'TOC.md')
|
|
47
|
+
export const ROOT_CONFIG_PATH = resolve(ROOT_DIR_PATH, '.tnotes.json')
|
|
48
|
+
export const NOTES_DIR_PATH = resolve(ROOT_DIR_PATH, 'notes')
|
|
49
|
+
export const VP_DIR_PATH = resolve(ROOT_DIR_PATH, '.vitepress')
|
|
50
|
+
export const PUBLIC_PATH = resolve(ROOT_DIR_PATH, 'public')
|
|
51
|
+
export const GITHUB_DIR_PATH = resolve(ROOT_DIR_PATH, '.github')
|
|
52
|
+
export const GITHUB_DEPLOY_YML_PATH = resolve(
|
|
53
|
+
GITHUB_DIR_PATH,
|
|
54
|
+
'workflows',
|
|
55
|
+
'deploy.yml',
|
|
56
|
+
)
|
|
57
|
+
export const VP_SIDEBAR_PATH = resolve(ROOT_DIR_PATH, 'sidebar.json')
|
|
58
|
+
export const ROOT_PKG_PATH = resolve(ROOT_DIR_PATH, 'package.json')
|
|
59
|
+
export const VSCODE_SETTINGS_PATH = resolve(
|
|
60
|
+
ROOT_DIR_PATH,
|
|
61
|
+
'.vscode',
|
|
62
|
+
'settings.json',
|
|
63
|
+
)
|
|
64
|
+
export const VSCODE_TASKS_PATH = resolve(ROOT_DIR_PATH, '.vscode', 'tasks.json')
|
|
65
|
+
|
|
66
|
+
// 文本常量
|
|
67
|
+
export const EOL = '\n'
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* TNotes 常量配置
|
|
71
|
+
*/
|
|
72
|
+
export const CONSTANTS = {
|
|
73
|
+
// 端口配置
|
|
74
|
+
DEFAULT_PORT: 5173,
|
|
75
|
+
|
|
76
|
+
// 笔记索引配置(文件夹前缀的 4 位数字)
|
|
77
|
+
NOTE_INDEX_LENGTH: 4,
|
|
78
|
+
NOTE_INDEX_PATTERN: /^\d{4}\./,
|
|
79
|
+
NOTE_INDEX_PREFIX_PATTERN: /^\d{4}/,
|
|
80
|
+
|
|
81
|
+
// Git 配置
|
|
82
|
+
DEFAULT_BRANCH: 'main',
|
|
83
|
+
|
|
84
|
+
// 缓存配置
|
|
85
|
+
CACHE_TTL: 5000,
|
|
86
|
+
|
|
87
|
+
// 终端输出颜色
|
|
88
|
+
COLORS: {
|
|
89
|
+
RESET: '\x1b[0m',
|
|
90
|
+
BRIGHT: '\x1b[1m',
|
|
91
|
+
DIM: '\x1b[2m',
|
|
92
|
+
RED: '\x1b[31m',
|
|
93
|
+
GREEN: '\x1b[32m',
|
|
94
|
+
YELLOW: '\x1b[33m',
|
|
95
|
+
BLUE: '\x1b[34m',
|
|
96
|
+
MAGENTA: '\x1b[35m',
|
|
97
|
+
CYAN: '\x1b[36m',
|
|
98
|
+
} as const,
|
|
99
|
+
|
|
100
|
+
// Emoji
|
|
101
|
+
EMOJI: {
|
|
102
|
+
SUCCESS: '✅',
|
|
103
|
+
ERROR: '❌',
|
|
104
|
+
WARNING: '⚠️',
|
|
105
|
+
INFO: 'ℹ️',
|
|
106
|
+
PROGRESS: '⏳',
|
|
107
|
+
ROCKET: '🚀',
|
|
108
|
+
STOP: '🛑',
|
|
109
|
+
SPARKLES: '✨',
|
|
110
|
+
LINK: '🔗',
|
|
111
|
+
FILE: '📄',
|
|
112
|
+
GIT: '📦',
|
|
113
|
+
DEBUG: '🐛',
|
|
114
|
+
} as const,
|
|
115
|
+
} as const
|
|
116
|
+
|
|
117
|
+
// 导出路径常量别名(向后兼容)
|
|
118
|
+
export const NOTES_PATH = NOTES_DIR_PATH
|
|
119
|
+
|
|
120
|
+
// GitHub URL 常量
|
|
121
|
+
export const REPO_NOTES_URL = `https://github.com/${author}/${repoName}/tree/main/notes`
|
package/config/defaultConfig.ts
CHANGED
|
@@ -44,9 +44,6 @@ export function getDefaultConfig(repoName?: string): TNotesConfig {
|
|
|
44
44
|
completed_notes_count: {},
|
|
45
45
|
details: `${name} 知识库`,
|
|
46
46
|
link: `https://tnotesjs.github.io/${name}/`,
|
|
47
|
-
created_at: Date.now(),
|
|
48
|
-
updated_at: Date.now(),
|
|
49
|
-
days_since_birth: 0,
|
|
50
47
|
},
|
|
51
48
|
|
|
52
49
|
// 端口配置(根据仓库名生成)
|
|
@@ -120,6 +117,32 @@ export function mergeConfig(
|
|
|
120
117
|
return result
|
|
121
118
|
}
|
|
122
119
|
|
|
120
|
+
/**
|
|
121
|
+
* 根配置 root_item 中已废弃的字段
|
|
122
|
+
*/
|
|
123
|
+
const DEPRECATED_ROOT_ITEM_FIELDS = [
|
|
124
|
+
'created_at',
|
|
125
|
+
'updated_at',
|
|
126
|
+
'days_since_birth',
|
|
127
|
+
] as const
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 剥离 root_item 中的废弃时间戳字段
|
|
131
|
+
* @returns 是否删除了字段
|
|
132
|
+
*/
|
|
133
|
+
export function stripDeprecatedRootItemFields(
|
|
134
|
+
rootItem: Record<string, unknown>,
|
|
135
|
+
): boolean {
|
|
136
|
+
let stripped = false
|
|
137
|
+
for (const key of DEPRECATED_ROOT_ITEM_FIELDS) {
|
|
138
|
+
if (key in rootItem) {
|
|
139
|
+
delete rootItem[key]
|
|
140
|
+
stripped = true
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return stripped
|
|
144
|
+
}
|
|
145
|
+
|
|
123
146
|
/**
|
|
124
147
|
* 验证并补全配置
|
|
125
148
|
* @param config - 现有配置
|
|
@@ -135,8 +158,14 @@ export function validateAndCompleteConfig(config: Record<string, any>): {
|
|
|
135
158
|
// 深度合并配置
|
|
136
159
|
const mergedConfig = mergeConfig(config, defaultConfig as any)
|
|
137
160
|
|
|
161
|
+
// 剥离 root_item 废弃字段
|
|
162
|
+
const rootItem = (mergedConfig.root_item || {}) as Record<string, unknown>
|
|
163
|
+
const stripped = stripDeprecatedRootItemFields(rootItem)
|
|
164
|
+
mergedConfig.root_item = rootItem
|
|
165
|
+
|
|
138
166
|
// 检查是否有修改
|
|
139
|
-
const modified =
|
|
167
|
+
const modified =
|
|
168
|
+
stripped || JSON.stringify(config) !== JSON.stringify(mergedConfig)
|
|
140
169
|
|
|
141
170
|
return {
|
|
142
171
|
config: mergedConfig as TNotesConfig,
|
package/config/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/index.ts
|
|
3
|
+
*
|
|
4
|
+
* 配置层统一导出
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
ConfigManager,
|
|
9
|
+
getConfigManager,
|
|
10
|
+
} from './ConfigManager'
|
|
11
|
+
export {
|
|
12
|
+
getDefaultConfig,
|
|
13
|
+
mergeConfig,
|
|
14
|
+
validateAndCompleteConfig,
|
|
15
|
+
stripDeprecatedRootItemFields,
|
|
16
|
+
} from './defaultConfig'
|
|
17
|
+
export {
|
|
18
|
+
ROOT_DIR_PATH,
|
|
19
|
+
ROOT_README_PATH,
|
|
20
|
+
ROOT_TOC_PATH,
|
|
21
|
+
ROOT_CONFIG_PATH,
|
|
22
|
+
NOTES_DIR_PATH,
|
|
23
|
+
VP_SIDEBAR_PATH,
|
|
24
|
+
EOL,
|
|
25
|
+
CONSTANTS,
|
|
26
|
+
NOTES_PATH,
|
|
27
|
+
REPO_NOTES_URL,
|
|
28
|
+
port,
|
|
29
|
+
repoName,
|
|
30
|
+
} from './constants'
|
|
31
|
+
export * from './templates'
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config/templates.ts
|
|
3
|
+
*
|
|
4
|
+
* 模板定义
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 新增笔记 README.md 正文模板(不含一级标题)
|
|
9
|
+
*/
|
|
10
|
+
export const NEW_NOTES_README_MD_TEMPLATE = `
|
|
11
|
+
<!-- region:toc -->
|
|
12
|
+
|
|
13
|
+
- [1. 本节内容](#1-本节内容)
|
|
14
|
+
- [2. 评价](#2-评价)
|
|
15
|
+
|
|
16
|
+
<!-- endregion:toc -->
|
|
17
|
+
|
|
18
|
+
## 1. 本节内容
|
|
19
|
+
|
|
20
|
+
- todo
|
|
21
|
+
|
|
22
|
+
## 2. 评价
|
|
23
|
+
|
|
24
|
+
- todo
|
|
25
|
+
`
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 获取新增笔记 README.md 正文
|
|
29
|
+
*/
|
|
30
|
+
export function getNewNoteReadmeBody(): string {
|
|
31
|
+
return NEW_NOTES_README_MD_TEMPLATE
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 生成笔记一级标题
|
|
36
|
+
* @param noteIndex - 笔记索引
|
|
37
|
+
* @param title - 笔记标题
|
|
38
|
+
* @param repoUrl - 仓库URL
|
|
39
|
+
* @returns 格式化的一级标题
|
|
40
|
+
*/
|
|
41
|
+
export function generateNoteTitle(
|
|
42
|
+
noteIndex: string,
|
|
43
|
+
title: string,
|
|
44
|
+
repoUrl: string,
|
|
45
|
+
): string {
|
|
46
|
+
const dirName = `${noteIndex}. ${title}`
|
|
47
|
+
const encodedDirName = encodeURIComponent(dirName)
|
|
48
|
+
return `# [${dirName}](${repoUrl}/${encodedDirName})`
|
|
49
|
+
}
|