@tnotesjs/core 0.6.1 → 0.8.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.
Files changed (92) hide show
  1. package/commands/BaseCommand.ts +58 -0
  2. package/commands/build/BuildCommand.ts +25 -0
  3. package/commands/build/PreviewCommand.ts +29 -0
  4. package/commands/build/index.ts +8 -0
  5. package/commands/dev/DevCommand.ts +75 -0
  6. package/commands/dev/index.ts +7 -0
  7. package/commands/git/PullCommand.ts +25 -0
  8. package/commands/git/PushCommand.ts +64 -0
  9. package/commands/git/index.ts +8 -0
  10. package/commands/index.ts +11 -0
  11. package/commands/init-sub-repo/InitSubRepoCommand.ts +206 -0
  12. package/commands/init-sub-repo/index.ts +1 -0
  13. package/commands/misc/HelpCommand.ts +104 -0
  14. package/commands/misc/index.ts +7 -0
  15. package/commands/models.ts +87 -0
  16. package/commands/note/CreateNoteCommand.ts +160 -0
  17. package/commands/note/RenameNoteCommand.ts +147 -0
  18. package/commands/note/UpdateNoteConfigCommand.ts +78 -0
  19. package/commands/note/index.ts +9 -0
  20. package/commands/registry.ts +47 -0
  21. package/commands/update/UpdateCommand.ts +219 -0
  22. package/commands/update/index.ts +7 -0
  23. package/commands/update-completed-count/UpdateCompletedCountCommand.ts +208 -0
  24. package/commands/update-completed-count/index.ts +5 -0
  25. package/config/templates.ts +0 -5
  26. package/dist/{chunk-5F5RJ2HV.cjs → chunk-7FEANCT6.cjs} +16 -7
  27. package/dist/chunk-AGVER5MX.cjs +1746 -0
  28. package/dist/{chunk-TJ4527KA.cjs → chunk-BL22KD4V.cjs} +324 -950
  29. package/dist/{chunk-56PKXCOX.js → chunk-GWG75A5M.js} +13 -4
  30. package/dist/{chunk-DUTS75WQ.js → chunk-XNO3PCEH.js} +374 -1000
  31. package/dist/chunk-ZEQS64PE.js +1746 -0
  32. package/dist/cli/index.cjs +76 -155
  33. package/dist/cli/index.js +10 -89
  34. package/dist/markdown/index.cjs +8 -12
  35. package/dist/markdown/index.d.cts +1 -1
  36. package/dist/markdown/index.d.ts +1 -1
  37. package/dist/markdown/index.js +7 -11
  38. package/dist/{types-CwBWwNVv.d.ts → types-C_d0fFeD.d.ts} +8 -1
  39. package/dist/{types-CpsEy8lA.d.cts → types-MRBGgJTX.d.cts} +8 -1
  40. package/dist/vitepress/config/index.cjs +402 -178
  41. package/dist/vitepress/config/index.js +392 -168
  42. package/dist/workspace/index.cjs +4 -1202
  43. package/dist/workspace/index.d.cts +2 -2
  44. package/dist/workspace/index.d.ts +2 -2
  45. package/dist/workspace/index.js +4 -1202
  46. package/markdown/components.ts +86 -0
  47. package/markdown/index.ts +17 -0
  48. package/markdown/noteFormatter.test.ts +44 -0
  49. package/markdown/noteFormatter.ts +237 -0
  50. package/package.json +7 -3
  51. package/services/file-watcher/folderChangeHandler.ts +19 -15
  52. package/services/file-watcher/globalUpdateCoordinator.ts +21 -27
  53. package/services/file-watcher/service.ts +1 -6
  54. package/services/index.ts +0 -1
  55. package/services/note/service.ts +4 -6
  56. package/services/readme/service.ts +11 -18
  57. package/services/reconcileToc.ts +20 -0
  58. package/utils/index.ts +0 -9
  59. package/{services/toc → utils}/moveTocInside.test.ts +1 -1
  60. package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +9 -18
  61. package/vitepress/components/EnWordList/EnWordList.vue +16 -662
  62. package/vitepress/components/Footprints/Footprints.vue +15 -537
  63. package/vitepress/components/Mermaid/Mermaid.vue +13 -588
  64. package/vitepress/components/MindmapPreview/MindmapPreview.vue +12 -434
  65. package/vitepress/components/MindmapPreview/markdown.ts +1 -1
  66. package/vitepress/components/NotesTable/NotesTable.vue +11 -130
  67. package/vitepress/components/constants.ts +2 -2
  68. package/vitepress/components/sidebar.data.ts +8 -5
  69. package/vitepress/configs/markdown.config.ts +170 -26
  70. package/vitepress/plugins/sidebarStructurePlugin.ts +242 -145
  71. package/vitepress/theme/index.ts +9 -13
  72. package/vitepress/theme/styles/base.scss +15 -0
  73. package/workspace/atomic.ts +113 -0
  74. package/workspace/errors.ts +27 -0
  75. package/workspace/index.ts +40 -0
  76. package/workspace/mutationQueue.ts +28 -0
  77. package/workspace/paths.ts +64 -0
  78. package/workspace/reconcile.test.ts +300 -0
  79. package/workspace/reconcile.ts +95 -0
  80. package/workspace/scanner.ts +292 -0
  81. package/workspace/types.ts +224 -0
  82. package/workspace/workspace.test.ts +333 -0
  83. package/workspace/workspace.ts +1020 -0
  84. package/dist/chunk-3R7QSABB.cjs +0 -502
  85. package/dist/chunk-CZXRQPFJ.js +0 -11
  86. package/dist/chunk-HXED7KVT.cjs +0 -11
  87. package/dist/chunk-U6IBLREL.js +0 -502
  88. package/services/toc/index.ts +0 -5
  89. package/services/toc/service.ts +0 -759
  90. package/utils/migrateReadmeToToc.test.ts +0 -111
  91. package/utils/migrateReadmeToToc.ts +0 -135
  92. package/vitepress/components/EnWordList/RightClickMenu.vue +0 -93
@@ -0,0 +1,87 @@
1
+ /**
2
+ * commands/models.ts
3
+ *
4
+ * commands 层对外暴露的类型和常量
5
+ * 注意:此文件不应导入任何命令类,以避免循环引用
6
+ */
7
+
8
+ /**
9
+ * TNotes 内置命令名称常量
10
+ */
11
+ export const COMMAND_NAMES = {
12
+ BUILD: 'build',
13
+ CREATE_NOTES: 'create-notes',
14
+ DEV: 'dev',
15
+ HELP: 'help',
16
+ PREVIEW: 'preview',
17
+ PULL: 'pull',
18
+ PUSH: 'push',
19
+ RENAME_NOTE: 'rename-note',
20
+ INIT_SUB_REPO: 'init-sub-repo',
21
+ UPDATE: 'update',
22
+ UPDATE_COMPLETED_COUNT: 'update-completed-count',
23
+ UPDATE_NOTE_CONFIG: 'update-note-config',
24
+ } as const
25
+
26
+ /**
27
+ * TNotes 内置命令名称类型
28
+ */
29
+ export type CommandName = (typeof COMMAND_NAMES)[keyof typeof COMMAND_NAMES]
30
+
31
+ /**
32
+ * 命令描述映射(静态配置,无需实例化即可读取)
33
+ */
34
+ export const COMMAND_DESCRIPTIONS: Record<CommandName, string> = {
35
+ [COMMAND_NAMES.DEV]: '启动知识库开发服务',
36
+ [COMMAND_NAMES.BUILD]: '构建知识库',
37
+ [COMMAND_NAMES.PREVIEW]: '预览构建后的知识库',
38
+ [COMMAND_NAMES.INIT_SUB_REPO]: '初始化 TNotes 子知识库(一次性脚手架)',
39
+ [COMMAND_NAMES.UPDATE]: '根据笔记内容更新知识库',
40
+ [COMMAND_NAMES.UPDATE_COMPLETED_COUNT]:
41
+ '更新完成笔记数量历史记录(近 1 年,最近 12 个月)',
42
+ [COMMAND_NAMES.CREATE_NOTES]: '新建笔记(支持批量创建)',
43
+ [COMMAND_NAMES.PUSH]: '将知识库推送到 GitHub',
44
+ [COMMAND_NAMES.PULL]: '将 GitHub 的知识库拉下来',
45
+ [COMMAND_NAMES.UPDATE_NOTE_CONFIG]: '更新笔记配置文件',
46
+ [COMMAND_NAMES.RENAME_NOTE]: '重命名笔记',
47
+ [COMMAND_NAMES.HELP]: '显示帮助信息',
48
+ }
49
+
50
+ /**
51
+ * 命令参数选项常量
52
+ */
53
+ export const COMMAND_OPTIONS = {
54
+ QUIET: 'quiet',
55
+ FORCE: 'force',
56
+ } as const
57
+
58
+ export type CommandOption =
59
+ (typeof COMMAND_OPTIONS)[keyof typeof COMMAND_OPTIONS]
60
+
61
+ /**
62
+ * 命令选项类型(传递给 BaseCommand.setOptions 的参数类型)
63
+ */
64
+ export interface CommandOptions {
65
+ force?: boolean
66
+ quiet?: boolean
67
+ [key: string]: unknown
68
+ }
69
+
70
+ /**
71
+ * 命令参数类型
72
+ */
73
+ export type CommandArgs = {
74
+ [K in CommandName]?: boolean
75
+ } & {
76
+ [COMMAND_OPTIONS.QUIET]?: boolean
77
+ [COMMAND_OPTIONS.FORCE]?: boolean
78
+ }
79
+
80
+ /**
81
+ * 命令接口
82
+ */
83
+ export interface Command {
84
+ name: CommandName
85
+ description: string
86
+ execute(): Promise<void>
87
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * commands/note/CreateNoteCommand.ts
3
+ *
4
+ * 新建笔记命令 - 使用 NoteService(支持批量创建,生成全局唯一 ID)
5
+ */
6
+
7
+ import { createInterface } from 'readline'
8
+ import { v4 as uuidv4 } from 'uuid'
9
+
10
+ import { NoteService, ReadmeService } from '../../services'
11
+ import { BaseCommand } from '../BaseCommand'
12
+
13
+ export class CreateNoteCommand extends BaseCommand {
14
+ private noteService: NoteService
15
+ private readmeService: ReadmeService
16
+
17
+ constructor() {
18
+ super('create-notes')
19
+
20
+ this.noteService = NoteService.getInstance()
21
+ this.readmeService = ReadmeService.getInstance()
22
+ }
23
+
24
+ protected async run(): Promise<void> {
25
+ this.logger.info('创建新笔记...')
26
+
27
+ // 提示用户输入要创建的笔记数量
28
+ const count = await this.promptForCount()
29
+
30
+ // 批量创建笔记
31
+ let successCount = 0
32
+ let failCount = 0
33
+ const createdNotes: string[] = []
34
+
35
+ // 预先扫描一次,构建已使用编号集合,避免循环内重复扫描
36
+ const existingNotes = this.noteService.getAllNotes()
37
+ const usedIndexes = new Set<number>()
38
+ for (const note of existingNotes) {
39
+ const index = parseInt(note.index, 10)
40
+ if (!isNaN(index) && index >= 1 && index <= 9999) {
41
+ usedIndexes.add(index)
42
+ }
43
+ }
44
+
45
+ for (let i = 1; i <= count; i++) {
46
+ try {
47
+ // 为每篇笔记提示标题(如果是批量创建,使用默认标题)
48
+ let title: string
49
+ if (count === 1) {
50
+ title = await this.promptForTitle()
51
+ } else {
52
+ title = `new`
53
+ this.logger.info(`[${i}/${count}] 创建笔记: ${title}`)
54
+ }
55
+
56
+ // 生成全局唯一的 UUID 作为配置文件中的 id
57
+ const configId = uuidv4()
58
+
59
+ const note = await this.noteService.createNote({
60
+ title: title || `new`,
61
+ enableDiscussions: false,
62
+ configId, // 传递 UUID 作为配置 ID(跨知识库唯一)
63
+ usedIndexes, // 传入已使用编号集合,避免重复扫描
64
+ })
65
+
66
+ // 将新创建的笔记编号加入集合,确保后续创建不会冲突
67
+ const newIndex = parseInt(note.index, 10)
68
+ if (!isNaN(newIndex)) {
69
+ usedIndexes.add(newIndex)
70
+ }
71
+
72
+ createdNotes.push(note.dirName)
73
+ successCount++
74
+
75
+ if (count === 1) {
76
+ this.logger.success(`笔记创建成功: ${note.dirName}`)
77
+ this.logger.info(`笔记路径: ${note.path}`)
78
+ this.logger.info(`笔记编号: ${note.index}`)
79
+ this.logger.info(`配置ID: ${configId}`)
80
+ } else {
81
+ this.logger.success(`[${i}/${count}] 创建成功: ${note.dirName}`)
82
+ }
83
+ } catch (error) {
84
+ failCount++
85
+ this.logger.error(`[${i}/${count}] 创建失败`, error)
86
+ }
87
+ }
88
+
89
+ // 显示统计信息
90
+ if (count > 1) {
91
+ console.log('')
92
+ this.logger.info(
93
+ `📊 创建完成: 成功 ${successCount} 篇, 失败 ${failCount} 篇`,
94
+ )
95
+ }
96
+
97
+ // 自动更新索引文件(TOC.md、sidebar.json)
98
+ if (successCount > 0) {
99
+ this.logger.info('正在更新知识库索引...')
100
+ await this.readmeService.updateAllReadmes()
101
+ this.logger.success('知识库索引更新完成')
102
+ }
103
+ }
104
+
105
+ /**
106
+ * 提示用户输入要创建的笔记数量
107
+ */
108
+ private async promptForCount(): Promise<number> {
109
+ const rl = createInterface({
110
+ input: process.stdin,
111
+ output: process.stdout,
112
+ })
113
+
114
+ return new Promise((resolve) => {
115
+ rl.question('\n📝 请输入要创建的笔记数量(默认为 1): ', (answer) => {
116
+ rl.close()
117
+
118
+ // 解析输入
119
+ const trimmed = answer.trim()
120
+
121
+ // 如果输入为空,默认为 1
122
+ if (!trimmed) {
123
+ this.logger.info('使用默认数量: 1')
124
+ resolve(1)
125
+ return
126
+ }
127
+
128
+ // 尝试解析为数字
129
+ const num = parseInt(trimmed, 10)
130
+
131
+ // 如果不是正整数,视为 1
132
+ if (isNaN(num) || num < 1 || !Number.isInteger(num)) {
133
+ this.logger.warn(`输入 "${trimmed}" 不是有效的正整数,使用默认值: 1`)
134
+ resolve(1)
135
+ return
136
+ }
137
+
138
+ this.logger.info(`将创建 ${num} 篇笔记`)
139
+ resolve(num)
140
+ })
141
+ })
142
+ }
143
+
144
+ /**
145
+ * 提示用户输入笔记标题
146
+ */
147
+ private async promptForTitle(): Promise<string> {
148
+ const rl = createInterface({
149
+ input: process.stdin,
150
+ output: process.stdout,
151
+ })
152
+
153
+ return new Promise((resolve) => {
154
+ rl.question('请输入笔记标题: ', (answer) => {
155
+ rl.close()
156
+ resolve(answer.trim())
157
+ })
158
+ })
159
+ }
160
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * commands/note/RenameNoteCommand.ts
3
+ *
4
+ * 重命名笔记命令 - 用于在开发环境中重命名笔记文件夹
5
+ */
6
+
7
+ import { existsSync, renameSync, readFileSync, writeFileSync } from 'fs'
8
+ import { join } from 'path'
9
+
10
+ import { NOTES_PATH, REPO_NOTES_URL } from '../../config/constants'
11
+ import { ROOT_DIR_PATH } from '../../config/constants'
12
+ import { generateNoteTitle } from '../../config/templates'
13
+ import { NoteService, FileWatcherService } from '../../services'
14
+ import { reconcileTocFromFiles } from '../../services/reconcileToc'
15
+ import { validateNoteTitle } from '../../utils'
16
+ import { BaseCommand } from '../BaseCommand'
17
+
18
+ interface RenameNoteParams {
19
+ noteIndex: string
20
+ newTitle: string
21
+ }
22
+
23
+ export class RenameNoteCommand extends BaseCommand {
24
+ private noteService: NoteService
25
+
26
+ constructor() {
27
+ super('rename-note')
28
+ this.noteService = NoteService.getInstance()
29
+ }
30
+
31
+ protected async run(): Promise<void> {
32
+ // 从命令行参数读取
33
+ const noteIndex = process.env.NOTE_ID
34
+ const newTitle = process.env.NOTE_TITLE
35
+
36
+ if (!noteIndex || !newTitle) {
37
+ throw new Error('缺少 NOTE_ID 或 NOTE_TITLE 参数')
38
+ }
39
+
40
+ try {
41
+ await this.renameNote({ noteIndex, newTitle })
42
+ this.logger.success(`笔记 ${noteIndex} 已重命名为: ${newTitle}`)
43
+ } catch (error) {
44
+ this.logger.error('重命名失败', error)
45
+ throw error
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 重命名笔记(可被外部调用)
51
+ */
52
+ async renameNote(params: RenameNoteParams): Promise<void> {
53
+ const { noteIndex, newTitle } = params
54
+
55
+ // 验证笔记是否存在
56
+ const note = this.noteService.getNoteByIndex(noteIndex)
57
+ if (!note) {
58
+ throw new Error(`笔记未找到: ${noteIndex}`)
59
+ }
60
+
61
+ // 验证新标题
62
+ const validation = validateNoteTitle(newTitle)
63
+ if (!validation.valid) {
64
+ throw new Error(validation.error || '标题格式无效')
65
+ }
66
+
67
+ // 构建新的文件夹名称
68
+ const newDirName = `${noteIndex}. ${newTitle.trim()}`
69
+ const newPath = join(NOTES_PATH, newDirName)
70
+
71
+ // 检查新路径是否已存在
72
+ if (existsSync(newPath)) {
73
+ throw new Error(`目标文件夹已存在: ${newDirName}`)
74
+ }
75
+
76
+ // 重命名文件夹
77
+ // Windows 上 fs.watch 会锁住文件夹句柄,需要先挂起监听
78
+ const watcher = FileWatcherService.getInstance()
79
+ try {
80
+ if (watcher) watcher.suspend()
81
+ renameSync(note.path, newPath)
82
+ this.logger.info(`✅ 文件夹已重命名:`)
83
+ this.logger.info(` 原名称: ${note.dirName}`)
84
+ this.logger.info(` 新名称: ${newDirName}`)
85
+ } catch (error) {
86
+ throw new Error(
87
+ `重命名文件夹失败: ${
88
+ error instanceof Error ? error.message : String(error)
89
+ }`,
90
+ )
91
+ } finally {
92
+ if (watcher) watcher.unsuspend()
93
+ }
94
+
95
+ // 更新笔记内部的标题(README.md 第一行)
96
+ try {
97
+ this.logger.info('正在更新笔记内部标题...')
98
+ const readmePath = join(newPath, 'README.md')
99
+
100
+ if (existsSync(readmePath)) {
101
+ const content = readFileSync(readmePath, 'utf-8')
102
+ const lines = content.split('\n')
103
+
104
+ // 查找第一个一级标题
105
+ let h1Index = -1
106
+ for (let i = 0; i < lines.length; i++) {
107
+ if (lines[i].trim().startsWith('# ')) {
108
+ h1Index = i
109
+ break
110
+ }
111
+ }
112
+
113
+ if (h1Index !== -1) {
114
+ // 生成新的标题
115
+ const newH1 = generateNoteTitle(
116
+ noteIndex,
117
+ newTitle.trim(),
118
+ REPO_NOTES_URL,
119
+ )
120
+ lines[h1Index] = newH1
121
+
122
+ // 写回文件
123
+ writeFileSync(readmePath, lines.join('\n'), 'utf-8')
124
+ this.logger.success('✅ 笔记标题已更新')
125
+ } else {
126
+ this.logger.warn(
127
+ `⚠️ 笔记标题格式不符合规范,未找到一级标题,请手动检查修正: ${readmePath}`,
128
+ )
129
+ }
130
+ }
131
+ } catch (error) {
132
+ this.logger.warn('⚠️ 更新笔记标题时出错:', error)
133
+ }
134
+
135
+ // 重命名成功后,更新 TOC.md 和 sidebar.json
136
+ try {
137
+ this.logger.info('正在更新 TOC.md 和 sidebar.json...')
138
+
139
+ await reconcileTocFromFiles(ROOT_DIR_PATH)
140
+
141
+ this.logger.success('✅ 全局文件已更新')
142
+ } catch (error) {
143
+ this.logger.warn('⚠️ 文件夹重命名成功,但更新全局文件时出错:', error)
144
+ // 不抛出错误,因为主要任务(重命名)已完成
145
+ }
146
+ }
147
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * commands/note/UpdateNoteConfigCommand.ts
3
+ *
4
+ * 更新笔记配置命令 - 用于在开发环境中更新笔记配置
5
+ */
6
+
7
+ import { NoteService } from '../../services'
8
+ import { BaseCommand } from '../BaseCommand'
9
+
10
+ import type { NoteConfig } from '../../types'
11
+
12
+ interface UpdateConfigParams {
13
+ noteIndex: string
14
+ config: Partial<
15
+ Pick<NoteConfig, 'done' | 'enableDiscussions' | 'description'>
16
+ >
17
+ }
18
+
19
+ export class UpdateNoteConfigCommand extends BaseCommand {
20
+ private noteService: NoteService
21
+
22
+ constructor() {
23
+ super('update-note-config')
24
+ this.noteService = NoteService.getInstance()
25
+ }
26
+
27
+ protected async run(): Promise<void> {
28
+ // 从命令行参数读取配置(用于 CLI 调用)
29
+ const noteIndex = process.env.NOTE_ID
30
+ const done = process.env.NOTE_DONE === 'true'
31
+ const enableDiscussions = process.env.NOTE_DISCUSSIONS === 'true'
32
+ const description = process.env.NOTE_DESCRIPTION || ''
33
+
34
+ if (!noteIndex) {
35
+ throw new Error('缺少 NOTE_ID 参数')
36
+ }
37
+
38
+ try {
39
+ await this.updateConfig({
40
+ noteIndex,
41
+ config: {
42
+ done,
43
+ enableDiscussions,
44
+ description,
45
+ },
46
+ })
47
+
48
+ this.logger.success(`笔记 ${noteIndex} 配置已更新`)
49
+ } catch (error) {
50
+ this.logger.error('更新配置失败', error)
51
+ throw error
52
+ }
53
+ }
54
+
55
+ /**
56
+ * 更新笔记配置(可被外部调用)
57
+ */
58
+ async updateConfig(params: UpdateConfigParams): Promise<void> {
59
+ const { noteIndex, config } = params
60
+
61
+ // 验证笔记是否存在
62
+ const note = this.noteService.getNoteByIndex(noteIndex)
63
+ if (!note) {
64
+ throw new Error(`笔记未找到: ${noteIndex}`)
65
+ }
66
+
67
+ // 更新配置
68
+ await this.noteService.updateNoteConfig(noteIndex, config)
69
+
70
+ this.logger.info(`✅ 笔记 ${noteIndex} 配置已更新:`)
71
+ if (config.done !== undefined)
72
+ this.logger.info(` - 完成状态: ${config.done}`)
73
+ if (config.enableDiscussions !== undefined)
74
+ this.logger.info(` - 评论状态: ${config.enableDiscussions}`)
75
+ if (config.description !== undefined)
76
+ this.logger.info(` - 笔记简介: ${config.description || '(空)'}`)
77
+ }
78
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * commands/note/index.ts
3
+ *
4
+ * Note 命令统一导出
5
+ */
6
+
7
+ export { CreateNoteCommand } from './CreateNoteCommand'
8
+ export { UpdateNoteConfigCommand } from './UpdateNoteConfigCommand'
9
+ export { RenameNoteCommand } from './RenameNoteCommand'
@@ -0,0 +1,47 @@
1
+ /**
2
+ * commands/registry.ts
3
+ *
4
+ * 命令注册表 - 管理命令的注册、实例化和获取
5
+ */
6
+
7
+ import { BuildCommand, PreviewCommand } from './build'
8
+ import { DevCommand } from './dev'
9
+ import { PushCommand, PullCommand } from './git'
10
+ import { InitSubRepoCommand } from './init-sub-repo'
11
+ import { HelpCommand } from './misc'
12
+ import { type Command, type CommandName } from './models'
13
+ import {
14
+ CreateNoteCommand,
15
+ UpdateNoteConfigCommand,
16
+ RenameNoteCommand,
17
+ } from './note'
18
+ import { UpdateCommand } from './update'
19
+ import { UpdateCompletedCountCommand } from './update-completed-count'
20
+
21
+ /** 命令注册表(懒加载) */
22
+ const commandFactories: Record<CommandName, () => Command> = {
23
+ 'build': () => new BuildCommand(),
24
+ 'create-notes': () => new CreateNoteCommand(),
25
+ 'dev': () => new DevCommand(),
26
+ 'init-sub-repo': () => new InitSubRepoCommand(),
27
+ 'help': () => new HelpCommand(),
28
+ 'preview': () => new PreviewCommand(),
29
+ 'pull': () => new PullCommand(),
30
+ 'push': () => new PushCommand(),
31
+ 'rename-note': () => new RenameNoteCommand(),
32
+ 'update-completed-count': () => new UpdateCompletedCountCommand(),
33
+ 'update-note-config': () => new UpdateNoteConfigCommand(),
34
+ 'update': () => new UpdateCommand(),
35
+ }
36
+
37
+ /** 命令实例缓存 */
38
+ const commandCache = new Map<CommandName, Command>()
39
+
40
+ /** 获取命令(懒加载,首次调用时才实例化) */
41
+ export function getCommand(name: CommandName): Command | undefined {
42
+ if (!commandFactories[name]) return undefined
43
+
44
+ if (!commandCache.has(name)) commandCache.set(name, commandFactories[name]())
45
+
46
+ return commandCache.get(name)
47
+ }