@tnotesjs/core 0.6.1 → 0.7.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 (42) hide show
  1. package/config/templates.ts +0 -5
  2. package/dist/{chunk-5F5RJ2HV.cjs → chunk-7FEANCT6.cjs} +16 -7
  3. package/dist/chunk-AGVER5MX.cjs +1746 -0
  4. package/dist/{chunk-TJ4527KA.cjs → chunk-BL22KD4V.cjs} +324 -950
  5. package/dist/{chunk-56PKXCOX.js → chunk-GWG75A5M.js} +13 -4
  6. package/dist/{chunk-DUTS75WQ.js → chunk-XNO3PCEH.js} +374 -1000
  7. package/dist/chunk-ZEQS64PE.js +1746 -0
  8. package/dist/cli/index.cjs +76 -155
  9. package/dist/cli/index.js +10 -89
  10. package/dist/markdown/index.cjs +2 -3
  11. package/dist/markdown/index.d.cts +1 -1
  12. package/dist/markdown/index.d.ts +1 -1
  13. package/dist/markdown/index.js +1 -2
  14. package/dist/{types-CwBWwNVv.d.ts → types-C_d0fFeD.d.ts} +8 -1
  15. package/dist/{types-CpsEy8lA.d.cts → types-MRBGgJTX.d.cts} +8 -1
  16. package/dist/vitepress/config/index.cjs +200 -132
  17. package/dist/vitepress/config/index.js +187 -119
  18. package/dist/workspace/index.cjs +4 -1202
  19. package/dist/workspace/index.d.cts +2 -2
  20. package/dist/workspace/index.d.ts +2 -2
  21. package/dist/workspace/index.js +4 -1202
  22. package/package.json +1 -1
  23. package/services/file-watcher/folderChangeHandler.ts +19 -15
  24. package/services/file-watcher/globalUpdateCoordinator.ts +21 -27
  25. package/services/file-watcher/service.ts +1 -6
  26. package/services/index.ts +0 -1
  27. package/services/note/service.ts +4 -6
  28. package/services/readme/service.ts +11 -18
  29. package/services/reconcileToc.ts +20 -0
  30. package/utils/index.ts +0 -9
  31. package/{services/toc → utils}/moveTocInside.test.ts +1 -1
  32. package/vitepress/components/constants.ts +2 -2
  33. package/vitepress/components/sidebar.data.ts +8 -5
  34. package/vitepress/plugins/sidebarStructurePlugin.ts +242 -145
  35. package/dist/chunk-3R7QSABB.cjs +0 -502
  36. package/dist/chunk-CZXRQPFJ.js +0 -11
  37. package/dist/chunk-HXED7KVT.cjs +0 -11
  38. package/dist/chunk-U6IBLREL.js +0 -502
  39. package/services/toc/index.ts +0 -5
  40. package/services/toc/service.ts +0 -759
  41. package/utils/migrateReadmeToToc.test.ts +0 -111
  42. package/utils/migrateReadmeToToc.ts +0 -135
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tnotesjs/core",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "TNotes 知识库核心框架 —— 基于 VitePress 的笔记管理系统",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.17.1",
@@ -5,11 +5,12 @@
5
5
  */
6
6
 
7
7
  import { existsSync, promises as fsPromises } from 'fs'
8
- import { join } from 'path'
8
+ import { dirname, join } from 'path'
9
9
 
10
10
  import { safeExecute } from './internal'
11
11
  import { REPO_NOTES_URL } from '../../config/constants'
12
12
  import { generateNoteTitle } from '../../config/templates'
13
+ import { reconcileTocFromFiles } from '../reconcileToc'
13
14
 
14
15
  import type { EventScheduler } from './eventScheduler'
15
16
  import type { WatchState } from './watchState'
@@ -17,7 +18,6 @@ import type { NoteIndexCache } from '../../core/NoteIndexCache'
17
18
  import type { Logger } from '../../utils'
18
19
  import type { NoteService } from '../note/service'
19
20
  import type { ReadmeService } from '../readme/service'
20
- import type { TocService } from '../toc/service'
21
21
 
22
22
  const RENAME_REVERT_DELAY_MS = 2000
23
23
 
@@ -41,8 +41,6 @@ interface FolderChangeHandlerConfig {
41
41
  noteService: NoteService
42
42
  /** README 服务实例 */
43
43
  readmeService: ReadmeService
44
- /** TOC 服务实例 */
45
- tocService: TocService
46
44
  /** 笔记索引缓存实例 */
47
45
  noteIndexCache: NoteIndexCache
48
46
  /** 日志记录器 */
@@ -89,7 +87,7 @@ export class FolderChangeHandler {
89
87
  }
90
88
 
91
89
  async handleFolderDeletion(deletedFolderName: string): Promise<void> {
92
- const { scheduler, watchState, noteIndexCache, tocService, logger } =
90
+ const { scheduler, watchState, noteIndexCache, logger, notesDir } =
93
91
  this.config
94
92
 
95
93
  if (scheduler.getUpdating()) return
@@ -106,12 +104,11 @@ export class FolderChangeHandler {
106
104
  watchState.clearNoteCaches(deletedFolderName)
107
105
  noteIndexCache.delete(noteIndex)
108
106
 
109
- // 更新根 README.md、sidebar.json
107
+ // files→TOC 对齐(Workspace):TOC 行随目录消失而移除
110
108
  await safeExecute(
111
109
  `删除笔记 ${noteIndex}`,
112
110
  async () => {
113
- await tocService.deleteNoteFromToc(noteIndex)
114
- await tocService.regenerateSidebar()
111
+ await reconcileTocFromFiles(dirname(notesDir))
115
112
  this.config.onNoteStructureChanged?.(`watcher:delete:${noteIndex}`)
116
113
  },
117
114
  logger,
@@ -202,7 +199,7 @@ export class FolderChangeHandler {
202
199
  noteIndex: string,
203
200
  newName: string,
204
201
  ): Promise<void> {
205
- const { noteIndexCache, tocService, logger, notesDir } = this.config
202
+ const { noteIndexCache, logger, notesDir } = this.config
206
203
 
207
204
  logger.info(`笔记索引未变 (${noteIndex}),只更新标题`)
208
205
  noteIndexCache.updateFolderName(noteIndex, newName)
@@ -214,8 +211,12 @@ export class FolderChangeHandler {
214
211
  logger,
215
212
  )
216
213
 
217
- await tocService.renameNoteInToc(noteIndex, newName)
218
- await tocService.regenerateSidebar()
214
+ // files→TOC 对齐(Workspace):标题以目录名为准,行位置/完成标记保留
215
+ await safeExecute(
216
+ `标题重命名同步目录 ${noteIndex}`,
217
+ () => reconcileTocFromFiles(dirname(notesDir)),
218
+ logger,
219
+ )
219
220
  this.config.onNoteStructureChanged?.(`watcher:rename-title:${noteIndex}`)
220
221
  logger.success(`标题更新完成`)
221
222
  }
@@ -266,11 +267,16 @@ export class FolderChangeHandler {
266
267
  oldNoteIndex: string,
267
268
  newNoteIndex: string,
268
269
  ): Promise<void> {
269
- const { noteService, noteIndexCache, tocService, logger } = this.config
270
+ const { noteService, noteIndexCache, logger, notesDir } = this.config
270
271
 
271
272
  logger.info(`笔记索引变更: ${oldNoteIndex} → ${newNoteIndex}`)
272
273
 
273
- await tocService.deleteNoteFromToc(oldNoteIndex)
274
+ // files→TOC 对齐(Workspace):旧索引行随目录消失移除,新索引行按编号追加
275
+ await safeExecute(
276
+ `索引变更同步目录 ${oldNoteIndex}→${newNoteIndex}`,
277
+ () => reconcileTocFromFiles(dirname(notesDir)),
278
+ logger,
279
+ )
274
280
 
275
281
  const newNote = noteService.getNoteByIndex(newNoteIndex)
276
282
 
@@ -278,8 +284,6 @@ export class FolderChangeHandler {
278
284
  noteIndexCache.delete(oldNoteIndex)
279
285
  noteIndexCache.add(newNote)
280
286
 
281
- await tocService.appendNoteToToc(newNoteIndex)
282
- await tocService.regenerateSidebar()
283
287
  this.config.onNoteStructureChanged?.(
284
288
  `watcher:rename-index:${oldNoteIndex}->${newNoteIndex}`,
285
289
  )
@@ -1,25 +1,26 @@
1
1
  /**
2
2
  * services/file-watcher/globalUpdateCoordinator.ts
3
3
  *
4
- * 全局更新协调:应用配置更新、更新 README 列表
4
+ * 全局更新协调:应用配置更新、更新 README 列表。
5
+ * TOC/sidebar 的写入统一走 Workspace 的 `toc.reconcileFromFiles()`
6
+ * (0004 方案 B),不再直接操作 TocService。
5
7
  */
6
8
 
9
+ import { dirname } from 'path'
10
+
7
11
  import { safeExecute } from './internal'
12
+ import { reconcileTocFromFiles } from '../reconcileToc'
8
13
 
9
14
  import type { WatchEvent } from './internal'
10
- import type { NoteIndexCache } from '../../core/NoteIndexCache'
11
15
  import type { Logger } from '../../utils'
12
16
  import type { ReadmeService } from '../readme/service'
13
- import type { TocService } from '../toc/service'
14
17
 
15
18
 
16
19
  interface GlobalUpdateCoordinatorConfig {
20
+ /** 笔记目录路径 */
21
+ notesDir: string
17
22
  /** README 服务实例,用于更新笔记 README */
18
23
  readmeService: ReadmeService
19
- /** TOC 服务实例,用于更新 TOC.md 与 sidebar */
20
- tocService: TocService
21
- /** 笔记索引缓存实例 */
22
- noteIndexCache: NoteIndexCache
23
24
  /** 日志记录器 */
24
25
  logger: Logger
25
26
  }
@@ -30,26 +31,19 @@ export class GlobalUpdateCoordinator {
30
31
  async applyConfigUpdates(changedNoteIndexes: string[]): Promise<void> {
31
32
  if (changedNoteIndexes.length === 0) return
32
33
 
33
- const { tocService, noteIndexCache, logger } = this.config
34
-
35
- logger.info('检测到笔记状态变化,增量更新全局文件...')
36
-
37
- for (const noteIndex of changedNoteIndexes) {
38
- await safeExecute(
39
- `增量更新 ${noteIndex}`,
40
- async () => {
41
- const item = noteIndexCache.getByNoteIndex(noteIndex)
42
- await tocService.updateNoteInToc(
43
- noteIndex,
44
- item?.noteConfig || {},
45
- )
46
- logger.info(`增量更新 TOC.md 中的笔记: ${noteIndex}`)
47
- },
48
- logger,
49
- )
50
- }
51
-
52
- await tocService.regenerateSidebar()
34
+ const { logger, notesDir } = this.config
35
+
36
+ logger.info('检测到笔记状态变化,同步全局文件...')
37
+
38
+ // files→TOC 对齐(Workspace):config.done 等以文件为真值,
39
+ // 同步到 TOC 行标记与 sidebar。
40
+ await safeExecute(
41
+ '配置变更同步目录',
42
+ () => reconcileTocFromFiles(dirname(notesDir)),
43
+ logger,
44
+ )
45
+
46
+ logger.info(`已同步配置变更的笔记: ${changedNoteIndexes.join(', ')}`)
53
47
  }
54
48
 
55
49
  async updateNoteReadmesOnly(events: WatchEvent[]): Promise<void> {
@@ -24,7 +24,6 @@ import { NoteIndexCache } from '../../core/NoteIndexCache'
24
24
  import { logger } from '../../utils'
25
25
  import { NoteService } from '../note/service'
26
26
  import { ReadmeService } from '../readme/service'
27
- import { TocService } from '../toc/service'
28
27
 
29
28
  import type { WatchEvent } from './internal'
30
29
 
@@ -49,7 +48,6 @@ export class FileWatcherService {
49
48
  private adapter!: FsWatcherAdapter
50
49
  private noteService!: NoteService
51
50
  private readmeService!: ReadmeService
52
- private tocService!: TocService
53
51
  private noteIndexCache!: NoteIndexCache
54
52
  private unlockTimer: NodeJS.Timeout | null = null
55
53
 
@@ -68,7 +66,6 @@ export class FileWatcherService {
68
66
  private init(): void {
69
67
  this.noteService = NoteService.getInstance()
70
68
  this.readmeService = ReadmeService.getInstance()
71
- this.tocService = TocService.getInstance()
72
69
  this.noteIndexCache = NoteIndexCache.getInstance()
73
70
 
74
71
  this.watchState = this.initWatchState()
@@ -103,7 +100,6 @@ export class FileWatcherService {
103
100
  scheduler: this.scheduler,
104
101
  noteService: this.noteService,
105
102
  readmeService: this.readmeService,
106
- tocService: this.tocService,
107
103
  noteIndexCache: this.noteIndexCache,
108
104
  logger,
109
105
  onRenameSuccess: (payload) => {
@@ -228,9 +224,8 @@ export class FileWatcherService {
228
224
 
229
225
  private initCoordinator(): GlobalUpdateCoordinator {
230
226
  return new GlobalUpdateCoordinator({
227
+ notesDir: this.notesDir,
231
228
  readmeService: this.readmeService,
232
- tocService: this.tocService,
233
- noteIndexCache: this.noteIndexCache,
234
229
  logger,
235
230
  })
236
231
  }
package/services/index.ts CHANGED
@@ -8,7 +8,6 @@ export { FileWatcherService } from './file-watcher'
8
8
  export { GitService } from './git'
9
9
  export { NoteService } from './note'
10
10
  export { ReadmeService } from './readme'
11
- export { TocService } from './toc'
12
11
  export { VitepressService } from './vitepress'
13
12
  export { InitSubRepoService } from './init-sub-repo'
14
13
  export * from './init-sub-repo/initSubRepoLogic'
@@ -8,7 +8,7 @@ import { writeFileSync, readFileSync, promises as fsPromises } from 'fs'
8
8
  import { join } from 'path'
9
9
  import { v4 as uuidv4 } from 'uuid'
10
10
 
11
- import { NOTES_PATH, CONSTANTS, REPO_NOTES_URL } from '../../config/constants'
11
+ import { NOTES_PATH, CONSTANTS, REPO_NOTES_URL, ROOT_DIR_PATH } from '../../config/constants'
12
12
  import {
13
13
  generateNoteTitle,
14
14
  getNewNoteReadmeBody,
@@ -16,7 +16,7 @@ import {
16
16
  import { NoteIndexCache } from '../../core/NoteIndexCache'
17
17
  import { NoteManager } from '../../core/NoteManager'
18
18
  import { ensureDirectory, logger } from '../../utils'
19
- import { TocService } from '../toc/service'
19
+ import { reconcileTocFromFiles } from '../reconcileToc'
20
20
 
21
21
  import type { NoteInfo, NoteConfig } from '../../types'
22
22
 
@@ -247,10 +247,8 @@ export class NoteService {
247
247
  logger.info(`检测到全局字段变更 (${noteIndex}),正在增量更新全局文件...`)
248
248
 
249
249
  // 使用增量更新
250
- const tocService = TocService.getInstance()
251
-
252
- await tocService.updateNoteInToc(noteIndex, updates)
253
- await tocService.regenerateSidebar()
250
+ // files→TOC 对齐(Workspace):config 已写盘,同步 TOC 行标记与 sidebar
251
+ await reconcileTocFromFiles(ROOT_DIR_PATH)
254
252
 
255
253
  logger.info(`全局文件增量更新完成 (${noteIndex})`)
256
254
  } else {
@@ -12,7 +12,7 @@ import {
12
12
  } from 'fs'
13
13
 
14
14
  import { ConfigManager } from '../../config/ConfigManager'
15
- import { ROOT_README_PATH, VP_SIDEBAR_PATH } from '../../config/constants'
15
+ import { ROOT_DIR_PATH, ROOT_README_PATH, VP_SIDEBAR_PATH } from '../../config/constants'
16
16
  import { NoteIndexCache } from '../../core/NoteIndexCache'
17
17
  import { NoteManager } from '../../core/NoteManager'
18
18
  import { ReadmeGenerator } from '../../core/ReadmeGenerator'
@@ -24,7 +24,8 @@ import {
24
24
  genHierarchicalSidebar,
25
25
  processEmptyLines,
26
26
  } from '../../utils'
27
- import { TocService } from '../toc/service'
27
+ import { reconcileTocFromFiles } from '../reconcileToc'
28
+
28
29
 
29
30
  import type { NoteInfo, NoteConfig } from '../../types'
30
31
 
@@ -60,14 +61,12 @@ export class ReadmeService {
60
61
  private readmeGenerator: ReadmeGenerator
61
62
  private configManager: ConfigManager
62
63
  private noteIndexCache: NoteIndexCache
63
- private tocService: TocService
64
64
 
65
65
  private constructor() {
66
66
  this.noteManager = NoteManager.getInstance()
67
67
  this.readmeGenerator = new ReadmeGenerator()
68
68
  this.configManager = ConfigManager.getInstance()
69
69
  this.noteIndexCache = NoteIndexCache.getInstance()
70
- this.tocService = TocService.getInstance()
71
70
  }
72
71
 
73
72
  static getInstance(): ReadmeService {
@@ -121,10 +120,9 @@ export class ReadmeService {
121
120
  await this.updateHomeReadme(notes)
122
121
  }
123
122
 
124
- // 规范化 TOC.md 并更新 sidebar.json
123
+ // files→TOC 对齐(Workspace):规范化 TOC.md 并重建 sidebar.json
125
124
  if (updateSidebar) {
126
- await this.tocService.normalizeToc(notes)
127
- await this.tocService.regenerateSidebar(notes)
125
+ await reconcileTocFromFiles(ROOT_DIR_PATH)
128
126
  }
129
127
 
130
128
  logger.info('知识库更新完成!')
@@ -618,23 +616,18 @@ export class ReadmeService {
618
616
  /**
619
617
  * 更新 TOC.md 和 sidebar,不重写每篇笔记 README
620
618
  */
621
- async refreshHomeReadmeAndSidebar(notes?: NoteInfo[]): Promise<void> {
622
- const allNotes =
623
- notes ??
624
- (this.noteIndexCache.isInitialized()
625
- ? this.noteIndexCache.toNoteInfoList()
626
- : this.noteManager.scanNotes())
627
-
628
- await this.tocService.normalizeToc(allNotes)
629
- await this.tocService.regenerateSidebar(allNotes)
619
+ async refreshHomeReadmeAndSidebar(_notes?: NoteInfo[]): Promise<void> {
620
+ // files→TOC 对齐(Workspace):TOC.md 规范化 + sidebar 重建
621
+ await reconcileTocFromFiles(ROOT_DIR_PATH)
630
622
  }
631
623
 
632
624
  /**
633
625
  * 重新生成 sidebar.json(基于当前 TOC.md)
634
626
  * @param notes - 可选的笔记列表,不传则内部扫描
635
627
  */
636
- async regenerateSidebar(notes?: NoteInfo[]): Promise<void> {
637
- await this.tocService.regenerateSidebar(notes)
628
+ async regenerateSidebar(_notes?: NoteInfo[]): Promise<void> {
629
+ // files→TOC 对齐(Workspace):sidebar 由重建的 TOC 派生
630
+ await reconcileTocFromFiles(ROOT_DIR_PATH)
638
631
  logger.info('重新生成 sidebar.json')
639
632
  }
640
633
 
@@ -0,0 +1,20 @@
1
+ /**
2
+ * services/reconcileToc.ts
3
+ *
4
+ * CLI / 服务侧的「files→TOC 对齐」入口(0004 方案 B):
5
+ * 统一的 TOC/sidebar 写入都收敛到 Core Workspace 的
6
+ * `toc.reconcileFromFiles()`,不再直接操作 TocService。
7
+ */
8
+ import { createWorkspace, type TNotesWorkspace } from '../workspace'
9
+
10
+ const workspaces = new Map<string, TNotesWorkspace>()
11
+
12
+ /** 知识库根目录 → 常驻 Workspace 实例(幂等,可重复调用)。 */
13
+ export async function reconcileTocFromFiles(repoRoot: string): Promise<void> {
14
+ let workspace = workspaces.get(repoRoot)
15
+ if (!workspace) {
16
+ workspace = createWorkspace({ rootPath: repoRoot })
17
+ workspaces.set(repoRoot, workspace)
18
+ }
19
+ await workspace.toc.reconcileFromFiles()
20
+ }
package/utils/index.ts CHANGED
@@ -52,15 +52,6 @@ export type {
52
52
  TocSidebarItem,
53
53
  TocLineKind,
54
54
  } from './tocHelpers'
55
- export {
56
- migrateReadmeToToc,
57
- extractReadmeBodyAfterToc,
58
- README_TOC_END_TAG,
59
- } from './migrateReadmeToToc'
60
- export type {
61
- MigratedTocEntry,
62
- MigrateReadmeToTocResult,
63
- } from './migrateReadmeToToc'
64
55
  export { isPortInUse, killPortProcess, waitForPort } from './portUtils'
65
56
  export {
66
57
  parseNoteLine,
@@ -11,7 +11,7 @@ import {
11
11
  getTocEntrySubtreeRange,
12
12
  parseTocLine,
13
13
  TOC_INDENT_SPACES,
14
- } from '../../utils/tocHelpers'
14
+ } from './tocHelpers'
15
15
 
16
16
  function adjustSubtreeIndent(lines: string[], delta: number): string[] {
17
17
  if (delta === 0) return lines
@@ -108,11 +108,11 @@ export const TOC_MD: string = TOC + '.md'
108
108
  * https://github.com/tnotesjs/en-words/blob/main/{word}.md
109
109
  */
110
110
  export const EN_WORDS_REPO_BASE_URL: string =
111
- 'https://github.com/tnotesjs/TNotes.en-words/blob/main/'
111
+ 'https://github.com/tnotesjs/en-words/blob/main/'
112
112
 
113
113
  /**
114
114
  * 英语单词仓库 raw 地址
115
115
  * https://raw.githubusercontent.com/tnotesjs/TNotes.en-words/refs/heads/main/{word}.md
116
116
  */
117
117
  export const EN_WORDS_REPO_BASE_RAW_URL: string =
118
- 'https://raw.githubusercontent.com/tnotesjs/TNotes.en-words/refs/heads/main/'
118
+ 'https://raw.githubusercontent.com/tnotesjs/en-words/refs/heads/main/'
@@ -5,15 +5,19 @@
5
5
  import fs from 'node:fs'
6
6
  import path from 'node:path'
7
7
 
8
- import { TocService } from '../../services/toc/service'
8
+ import { ROOT_DIR_PATH } from '../../config/constants'
9
+ import { createWorkspace } from '../../workspace'
9
10
 
10
- const rootPath = process.cwd()
11
+ const rootPath = ROOT_DIR_PATH
11
12
  const sidebarFilePath = path.resolve(rootPath, 'sidebar.json')
12
13
  const tocFilePath = path.resolve(rootPath, 'TOC.md')
13
14
 
15
+ const workspace = createWorkspace({ rootPath })
16
+
14
17
  /**
15
18
  * VitePress Data Loader for Sidebar
16
- * 以 TOC.md 为唯一数据源,加载前重建 sidebar.json,并监听 TOC/sidebar 变化做 HMR
19
+ * 以 TOC.md 为唯一数据源,加载前用 Workspace 对齐(files→TOC)重建 sidebar.json
20
+ * 并监听 TOC/sidebar 变化做 HMR
17
21
  */
18
22
 
19
23
  interface SidebarItem {
@@ -37,8 +41,7 @@ export default {
37
41
 
38
42
  async load(): Promise<SidebarConfig> {
39
43
  try {
40
- const tocService = TocService.getInstance()
41
- await tocService.regenerateSidebar()
44
+ await workspace.toc.reconcileFromFiles()
42
45
 
43
46
  const fileContent = fs.readFileSync(sidebarFilePath, 'utf-8')
44
47
  const sidebarArray = JSON.parse(fileContent) as SidebarGroup[]