@tnotesjs/core 0.2.0 → 0.2.2

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 (67) hide show
  1. package/config/ConfigManager.ts +137 -0
  2. package/config/constants.ts +121 -0
  3. package/config/index.ts +25 -0
  4. package/config/templates.ts +49 -0
  5. package/core/GitManager.ts +513 -0
  6. package/core/NoteIndexCache.ts +194 -0
  7. package/core/NoteManager.ts +407 -0
  8. package/core/ProcessManager.ts +180 -0
  9. package/core/ReadmeGenerator.ts +215 -0
  10. package/core/TocGenerator.ts +212 -0
  11. package/core/index.ts +11 -0
  12. package/dist/chunk-5QN44ES5.js +6050 -0
  13. package/dist/chunk-5Y5IYS6C.js +200 -0
  14. package/dist/cli/index.js +986 -0
  15. package/dist/index.js +8 -0
  16. package/dist/vitepress/config/index.js +1686 -0
  17. package/package.json +6 -2
  18. package/services/file-watcher/configChangeHandler.ts +64 -0
  19. package/services/file-watcher/eventScheduler.ts +179 -0
  20. package/services/file-watcher/folderChangeHandler.ts +325 -0
  21. package/services/file-watcher/fsWatcherAdapter.ts +128 -0
  22. package/services/file-watcher/globalUpdateCoordinator.ts +60 -0
  23. package/services/file-watcher/index.ts +7 -0
  24. package/services/file-watcher/internal.ts +79 -0
  25. package/services/file-watcher/readmeChangeHandler.ts +28 -0
  26. package/services/file-watcher/renameDetector.ts +120 -0
  27. package/services/file-watcher/service.ts +352 -0
  28. package/services/file-watcher/watchState.ts +194 -0
  29. package/services/git/index.ts +7 -0
  30. package/services/git/service.ts +114 -0
  31. package/services/index.ts +15 -0
  32. package/services/init-sub-repo/index.ts +2 -0
  33. package/services/init-sub-repo/initSubRepoLogic.test.ts +162 -0
  34. package/services/init-sub-repo/initSubRepoLogic.ts +304 -0
  35. package/services/init-sub-repo/service.ts +101 -0
  36. package/services/note/index.ts +7 -0
  37. package/services/note/service.ts +362 -0
  38. package/services/readme/index.ts +7 -0
  39. package/services/readme/service.ts +761 -0
  40. package/services/timestamp/index.ts +7 -0
  41. package/services/timestamp/service.ts +465 -0
  42. package/services/toc/index.ts +5 -0
  43. package/services/toc/moveTocInside.test.ts +73 -0
  44. package/services/toc/service.ts +759 -0
  45. package/services/vitepress/index.ts +7 -0
  46. package/services/vitepress/service.ts +339 -0
  47. package/utils/errorHandler.ts +174 -0
  48. package/utils/file.ts +17 -0
  49. package/utils/genHierarchicalSidebar.ts +69 -0
  50. package/utils/generateAnchor.ts +24 -0
  51. package/utils/getChangedIds.ts +35 -0
  52. package/utils/index.ts +71 -0
  53. package/utils/logger.ts +231 -0
  54. package/utils/markdown.ts +75 -0
  55. package/utils/migrateReadmeToToc.test.ts +111 -0
  56. package/utils/migrateReadmeToToc.ts +135 -0
  57. package/utils/parseArgs.ts +90 -0
  58. package/utils/parseReadmeCompletedNotes.test.ts +90 -0
  59. package/utils/parseReadmeCompletedNotes.ts +108 -0
  60. package/utils/portUtils.ts +113 -0
  61. package/utils/readmeHelpers.ts +190 -0
  62. package/utils/runCommand.ts +29 -0
  63. package/utils/tocHelpers.test.ts +278 -0
  64. package/utils/tocHelpers.ts +855 -0
  65. package/utils/tocNodeId.test.ts +60 -0
  66. package/utils/tocNodeId.ts +97 -0
  67. package/utils/validators.ts +102 -0
@@ -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`
@@ -0,0 +1,25 @@
1
+ /**
2
+ * config/index.ts
3
+ *
4
+ * 配置层统一导出
5
+ */
6
+
7
+ export {
8
+ ConfigManager,
9
+ getConfigManager,
10
+ } from './ConfigManager'
11
+ export {
12
+ ROOT_DIR_PATH,
13
+ ROOT_README_PATH,
14
+ ROOT_TOC_PATH,
15
+ ROOT_CONFIG_PATH,
16
+ NOTES_DIR_PATH,
17
+ VP_SIDEBAR_PATH,
18
+ EOL,
19
+ CONSTANTS,
20
+ NOTES_PATH,
21
+ REPO_NOTES_URL,
22
+ port,
23
+ repoName,
24
+ } from './constants'
25
+ 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
+ }