@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.
- package/commands/BaseCommand.ts +58 -0
- package/commands/build/BuildCommand.ts +25 -0
- package/commands/build/PreviewCommand.ts +29 -0
- package/commands/build/index.ts +8 -0
- package/commands/dev/DevCommand.ts +75 -0
- package/commands/dev/index.ts +7 -0
- package/commands/git/PullCommand.ts +25 -0
- package/commands/git/PushCommand.ts +64 -0
- package/commands/git/index.ts +8 -0
- package/commands/index.ts +11 -0
- package/commands/init-sub-repo/InitSubRepoCommand.ts +206 -0
- package/commands/init-sub-repo/index.ts +1 -0
- package/commands/misc/HelpCommand.ts +104 -0
- package/commands/misc/index.ts +7 -0
- package/commands/models.ts +87 -0
- package/commands/note/CreateNoteCommand.ts +160 -0
- package/commands/note/RenameNoteCommand.ts +147 -0
- package/commands/note/UpdateNoteConfigCommand.ts +78 -0
- package/commands/note/index.ts +9 -0
- package/commands/registry.ts +47 -0
- package/commands/update/UpdateCommand.ts +219 -0
- package/commands/update/index.ts +7 -0
- package/commands/update-completed-count/UpdateCompletedCountCommand.ts +208 -0
- package/commands/update-completed-count/index.ts +5 -0
- package/config/templates.ts +0 -5
- package/dist/{chunk-5F5RJ2HV.cjs → chunk-7FEANCT6.cjs} +16 -7
- package/dist/chunk-AGVER5MX.cjs +1746 -0
- package/dist/{chunk-TJ4527KA.cjs → chunk-BL22KD4V.cjs} +324 -950
- package/dist/{chunk-56PKXCOX.js → chunk-GWG75A5M.js} +13 -4
- package/dist/{chunk-DUTS75WQ.js → chunk-XNO3PCEH.js} +374 -1000
- package/dist/chunk-ZEQS64PE.js +1746 -0
- package/dist/cli/index.cjs +76 -155
- package/dist/cli/index.js +10 -89
- package/dist/markdown/index.cjs +8 -12
- package/dist/markdown/index.d.cts +1 -1
- package/dist/markdown/index.d.ts +1 -1
- package/dist/markdown/index.js +7 -11
- package/dist/{types-CwBWwNVv.d.ts → types-C_d0fFeD.d.ts} +8 -1
- package/dist/{types-CpsEy8lA.d.cts → types-MRBGgJTX.d.cts} +8 -1
- package/dist/vitepress/config/index.cjs +402 -178
- package/dist/vitepress/config/index.js +392 -168
- package/dist/workspace/index.cjs +4 -1202
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.ts +2 -2
- package/dist/workspace/index.js +4 -1202
- package/markdown/components.ts +86 -0
- package/markdown/index.ts +17 -0
- package/markdown/noteFormatter.test.ts +44 -0
- package/markdown/noteFormatter.ts +237 -0
- package/package.json +7 -3
- package/services/file-watcher/folderChangeHandler.ts +19 -15
- package/services/file-watcher/globalUpdateCoordinator.ts +21 -27
- package/services/file-watcher/service.ts +1 -6
- package/services/index.ts +0 -1
- package/services/note/service.ts +4 -6
- package/services/readme/service.ts +11 -18
- package/services/reconcileToc.ts +20 -0
- package/utils/index.ts +0 -9
- package/{services/toc → utils}/moveTocInside.test.ts +1 -1
- package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +9 -18
- package/vitepress/components/EnWordList/EnWordList.vue +16 -662
- package/vitepress/components/Footprints/Footprints.vue +15 -537
- package/vitepress/components/Mermaid/Mermaid.vue +13 -588
- package/vitepress/components/MindmapPreview/MindmapPreview.vue +12 -434
- package/vitepress/components/MindmapPreview/markdown.ts +1 -1
- package/vitepress/components/NotesTable/NotesTable.vue +11 -130
- package/vitepress/components/constants.ts +2 -2
- package/vitepress/components/sidebar.data.ts +8 -5
- package/vitepress/configs/markdown.config.ts +170 -26
- package/vitepress/plugins/sidebarStructurePlugin.ts +242 -145
- package/vitepress/theme/index.ts +9 -13
- package/vitepress/theme/styles/base.scss +15 -0
- package/workspace/atomic.ts +113 -0
- package/workspace/errors.ts +27 -0
- package/workspace/index.ts +40 -0
- package/workspace/mutationQueue.ts +28 -0
- package/workspace/paths.ts +64 -0
- package/workspace/reconcile.test.ts +300 -0
- package/workspace/reconcile.ts +95 -0
- package/workspace/scanner.ts +292 -0
- package/workspace/types.ts +224 -0
- package/workspace/workspace.test.ts +333 -0
- package/workspace/workspace.ts +1020 -0
- package/dist/chunk-3R7QSABB.cjs +0 -502
- package/dist/chunk-CZXRQPFJ.js +0 -11
- package/dist/chunk-HXED7KVT.cjs +0 -11
- package/dist/chunk-U6IBLREL.js +0 -502
- package/services/toc/index.ts +0 -5
- package/services/toc/service.ts +0 -759
- package/utils/migrateReadmeToToc.test.ts +0 -111
- package/utils/migrateReadmeToToc.ts +0 -135
- package/vitepress/components/EnWordList/RightClickMenu.vue +0 -93
package/dist/chunk-U6IBLREL.js
DELETED
|
@@ -1,502 +0,0 @@
|
|
|
1
|
-
// config/templates.ts
|
|
2
|
-
var NEW_NOTES_README_MD_TEMPLATE = `
|
|
3
|
-
<!-- region:toc -->
|
|
4
|
-
|
|
5
|
-
- [1. \u672C\u8282\u5185\u5BB9](#1-\u672C\u8282\u5185\u5BB9)
|
|
6
|
-
- [2. \u8BC4\u4EF7](#2-\u8BC4\u4EF7)
|
|
7
|
-
|
|
8
|
-
<!-- endregion:toc -->
|
|
9
|
-
|
|
10
|
-
## 1. \u672C\u8282\u5185\u5BB9
|
|
11
|
-
|
|
12
|
-
- todo
|
|
13
|
-
|
|
14
|
-
## 2. \u8BC4\u4EF7
|
|
15
|
-
|
|
16
|
-
- todo
|
|
17
|
-
`;
|
|
18
|
-
function getNewNoteReadmeBody() {
|
|
19
|
-
return NEW_NOTES_README_MD_TEMPLATE;
|
|
20
|
-
}
|
|
21
|
-
function generateNoteTitle(noteIndex, title, repoUrl) {
|
|
22
|
-
const dirName = `${noteIndex}. ${title}`;
|
|
23
|
-
const encodedDirName = encodeURIComponent(dirName);
|
|
24
|
-
return `# [${dirName}](${repoUrl}/${encodedDirName})`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// utils/tocNodeId.ts
|
|
28
|
-
function extractNoteIndexFromLink(link) {
|
|
29
|
-
if (!link) return null;
|
|
30
|
-
const match = link.match(/\/notes\/(\d{4})\./);
|
|
31
|
-
return match ? match[1] : null;
|
|
32
|
-
}
|
|
33
|
-
function nodeIdForNote(noteIndex) {
|
|
34
|
-
return `note:${noteIndex}`;
|
|
35
|
-
}
|
|
36
|
-
function nodeIdForFolder(folderPath) {
|
|
37
|
-
return `folder:${folderPath.join("/")}`;
|
|
38
|
-
}
|
|
39
|
-
function nodeIdForLine(tocLineIndex) {
|
|
40
|
-
return `line:${tocLineIndex}`;
|
|
41
|
-
}
|
|
42
|
-
function computeSidebarNodeId(item) {
|
|
43
|
-
if (item.nodeId) return item.nodeId;
|
|
44
|
-
const noteIndex = extractNoteIndexFromLink(item.link);
|
|
45
|
-
if (noteIndex) return nodeIdForNote(noteIndex);
|
|
46
|
-
if (item.tocLineIndex !== void 0 && !item.link) {
|
|
47
|
-
return nodeIdForLine(item.tocLineIndex);
|
|
48
|
-
}
|
|
49
|
-
if (item.folderPath?.length) {
|
|
50
|
-
return nodeIdForFolder(item.folderPath);
|
|
51
|
-
}
|
|
52
|
-
if (item.tocLineIndex !== void 0) {
|
|
53
|
-
return nodeIdForLine(item.tocLineIndex);
|
|
54
|
-
}
|
|
55
|
-
return `text:${item.text}`;
|
|
56
|
-
}
|
|
57
|
-
function parseNodeId(nodeId) {
|
|
58
|
-
if (nodeId.startsWith("note:")) {
|
|
59
|
-
return { kind: "note", noteIndex: nodeId.slice(5) };
|
|
60
|
-
}
|
|
61
|
-
if (nodeId.startsWith("folder:")) {
|
|
62
|
-
const path = nodeId.slice(7);
|
|
63
|
-
return {
|
|
64
|
-
kind: "folder",
|
|
65
|
-
folderPath: path ? path.split("/") : []
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
if (nodeId.startsWith("line:")) {
|
|
69
|
-
return { kind: "line", tocLineIndex: Number(nodeId.slice(5)) };
|
|
70
|
-
}
|
|
71
|
-
return { kind: "text" };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// utils/tocHelpers.ts
|
|
75
|
-
var TOC_INDENT_SPACES = 2;
|
|
76
|
-
var TOC_LEGACY_FULL_REGEX = /^( *)(-\s+\[(x| )\])\s+\[(\d{4}\.[^\]]+)\]\(([^)]+)\)/;
|
|
77
|
-
var TOC_NOTE_LINE_REGEX = /^( *)(-\s+\[(x| )\])\s+(\d{4})(?:\.\s*(.*))?\s*$/;
|
|
78
|
-
var TOC_FOLDER_LINE_REGEX = /^( *)(-\s+(?!\[(?:x| )\]).+?)\s*$/;
|
|
79
|
-
function extractNoteIndexFromTitle(text) {
|
|
80
|
-
const match = text.match(/^(\d{4})\./);
|
|
81
|
-
return match ? match[1] : null;
|
|
82
|
-
}
|
|
83
|
-
function parseIndent(spaces) {
|
|
84
|
-
return Math.floor((spaces?.length ?? 0) / TOC_INDENT_SPACES);
|
|
85
|
-
}
|
|
86
|
-
function parseTocLine(line) {
|
|
87
|
-
const rawLine = line ?? "";
|
|
88
|
-
const empty = {
|
|
89
|
-
kind: "unknown",
|
|
90
|
-
isMatch: false,
|
|
91
|
-
indentLevel: 0,
|
|
92
|
-
noteIndex: null,
|
|
93
|
-
folderTitle: null,
|
|
94
|
-
completed: false,
|
|
95
|
-
rawLine
|
|
96
|
-
};
|
|
97
|
-
if (line == null) return empty;
|
|
98
|
-
const legacyMatch = line.match(TOC_LEGACY_FULL_REGEX);
|
|
99
|
-
if (legacyMatch) {
|
|
100
|
-
const [, spaces, , statusChar, titleText] = legacyMatch;
|
|
101
|
-
const noteIndex = extractNoteIndexFromTitle(titleText);
|
|
102
|
-
if (!noteIndex) return empty;
|
|
103
|
-
return {
|
|
104
|
-
kind: "note",
|
|
105
|
-
isMatch: true,
|
|
106
|
-
indentLevel: parseIndent(spaces),
|
|
107
|
-
noteIndex,
|
|
108
|
-
folderTitle: null,
|
|
109
|
-
completed: statusChar === "x",
|
|
110
|
-
rawLine
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
const noteMatch = line.match(TOC_NOTE_LINE_REGEX);
|
|
114
|
-
if (noteMatch) {
|
|
115
|
-
const [, spaces, , statusChar, noteIndex] = noteMatch;
|
|
116
|
-
return {
|
|
117
|
-
kind: "note",
|
|
118
|
-
isMatch: true,
|
|
119
|
-
indentLevel: parseIndent(spaces),
|
|
120
|
-
noteIndex,
|
|
121
|
-
folderTitle: null,
|
|
122
|
-
completed: statusChar === "x",
|
|
123
|
-
rawLine
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
const folderMatch = line.match(TOC_FOLDER_LINE_REGEX);
|
|
127
|
-
if (folderMatch) {
|
|
128
|
-
const [, spaces, titlePart] = folderMatch;
|
|
129
|
-
const title = titlePart.replace(/^-\s+/, "").trim();
|
|
130
|
-
if (!title) return empty;
|
|
131
|
-
return {
|
|
132
|
-
kind: "folder",
|
|
133
|
-
isMatch: true,
|
|
134
|
-
indentLevel: parseIndent(spaces),
|
|
135
|
-
noteIndex: null,
|
|
136
|
-
folderTitle: title,
|
|
137
|
-
completed: false,
|
|
138
|
-
rawLine
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
return empty;
|
|
142
|
-
}
|
|
143
|
-
function isTocContentLine(line) {
|
|
144
|
-
return parseTocLine(line).isMatch;
|
|
145
|
-
}
|
|
146
|
-
function resolveNoteFromIndex(index, notes) {
|
|
147
|
-
return notes.find((n) => n.index === index);
|
|
148
|
-
}
|
|
149
|
-
function getTocLineCompleted(note, configOverride) {
|
|
150
|
-
const config = configOverride ? { ...note.config, ...configOverride } : note.config;
|
|
151
|
-
return config?.done ?? false;
|
|
152
|
-
}
|
|
153
|
-
function buildFolderTocLine(title, indentLevel) {
|
|
154
|
-
const indent = " ".repeat(indentLevel * TOC_INDENT_SPACES);
|
|
155
|
-
return `${indent}- ${title}`;
|
|
156
|
-
}
|
|
157
|
-
function buildTocLine(note, indentLevel, completed) {
|
|
158
|
-
const indent = " ".repeat(indentLevel * TOC_INDENT_SPACES);
|
|
159
|
-
const status = completed ?? getTocLineCompleted(note) ? "x" : " ";
|
|
160
|
-
return `${indent}- [${status}] ${note.dirName}`;
|
|
161
|
-
}
|
|
162
|
-
function mutableToTreeNode(node) {
|
|
163
|
-
if (node.kind === "folder") {
|
|
164
|
-
return {
|
|
165
|
-
kind: "folder",
|
|
166
|
-
title: node.title,
|
|
167
|
-
indent: node.indent,
|
|
168
|
-
tocLineIndex: node.tocLineIndex,
|
|
169
|
-
children: node.children.map(mutableToTreeNode)
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
kind: "note",
|
|
174
|
-
noteIndex: node.noteIndex,
|
|
175
|
-
indent: node.indent,
|
|
176
|
-
tocLineIndex: node.tocLineIndex,
|
|
177
|
-
children: node.children.map(mutableToTreeNode)
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
function buildMutableTreeFromFlat(flatNodes) {
|
|
181
|
-
const roots = [];
|
|
182
|
-
const stack = [];
|
|
183
|
-
for (const item of flatNodes) {
|
|
184
|
-
while (stack.length > 0 && stack[stack.length - 1].indent >= item.indent) {
|
|
185
|
-
stack.pop();
|
|
186
|
-
}
|
|
187
|
-
const node = {
|
|
188
|
-
kind: item.kind,
|
|
189
|
-
title: item.title,
|
|
190
|
-
noteIndex: item.noteIndex,
|
|
191
|
-
indent: item.indent,
|
|
192
|
-
tocLineIndex: item.tocLineIndex,
|
|
193
|
-
children: []
|
|
194
|
-
};
|
|
195
|
-
if (stack.length === 0) {
|
|
196
|
-
roots.push(node);
|
|
197
|
-
} else {
|
|
198
|
-
stack[stack.length - 1].children.push(node);
|
|
199
|
-
}
|
|
200
|
-
stack.push(node);
|
|
201
|
-
}
|
|
202
|
-
return roots;
|
|
203
|
-
}
|
|
204
|
-
function parseTocToMutableTree(lines, notes) {
|
|
205
|
-
const flatNodes = [];
|
|
206
|
-
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
207
|
-
const line = lines[lineIndex];
|
|
208
|
-
const parsed = parseTocLine(line);
|
|
209
|
-
if (!parsed.isMatch) continue;
|
|
210
|
-
if (parsed.kind === "folder") {
|
|
211
|
-
flatNodes.push({
|
|
212
|
-
kind: "folder",
|
|
213
|
-
title: parsed.folderTitle,
|
|
214
|
-
indent: parsed.indentLevel,
|
|
215
|
-
tocLineIndex: lineIndex
|
|
216
|
-
});
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
if (!parsed.noteIndex) continue;
|
|
220
|
-
if (!resolveNoteFromIndex(parsed.noteIndex, notes)) continue;
|
|
221
|
-
flatNodes.push({
|
|
222
|
-
kind: "note",
|
|
223
|
-
noteIndex: parsed.noteIndex,
|
|
224
|
-
indent: parsed.indentLevel,
|
|
225
|
-
tocLineIndex: lineIndex
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
return buildMutableTreeFromFlat(flatNodes);
|
|
229
|
-
}
|
|
230
|
-
function parseTocToTree(lines, notes) {
|
|
231
|
-
return parseTocToMutableTree(lines, notes).map(mutableToTreeNode);
|
|
232
|
-
}
|
|
233
|
-
function serializeTocTree(tree, notes, configByIndex) {
|
|
234
|
-
const lines = [];
|
|
235
|
-
function walk(nodes) {
|
|
236
|
-
for (const node of nodes) {
|
|
237
|
-
if (node.kind === "folder") {
|
|
238
|
-
lines.push(buildFolderTocLine(node.title, node.indent));
|
|
239
|
-
walk(node.children);
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
const note = resolveNoteFromIndex(node.noteIndex, notes);
|
|
243
|
-
if (!note) continue;
|
|
244
|
-
const override = configByIndex?.get(node.noteIndex);
|
|
245
|
-
const completed = override !== void 0 ? getTocLineCompleted(note, override) : getTocLineCompleted(note);
|
|
246
|
-
lines.push(buildTocLine(note, node.indent, completed));
|
|
247
|
-
walk(node.children);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
walk(tree);
|
|
251
|
-
return lines;
|
|
252
|
-
}
|
|
253
|
-
function parseTocLinesToFlatNodes(lines) {
|
|
254
|
-
const result = [];
|
|
255
|
-
for (const line of lines) {
|
|
256
|
-
const parsed = parseTocLine(line);
|
|
257
|
-
if (parsed.kind !== "note" || !parsed.noteIndex) continue;
|
|
258
|
-
result.push({
|
|
259
|
-
noteIndex: parsed.noteIndex,
|
|
260
|
-
indent: parsed.indentLevel,
|
|
261
|
-
completed: parsed.completed
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
return result;
|
|
265
|
-
}
|
|
266
|
-
function adjustTocLineIndexAfterSubtreeRemoval(lineIndex, removedStart, removedEnd) {
|
|
267
|
-
if (lineIndex >= removedEnd) {
|
|
268
|
-
return lineIndex - (removedEnd - removedStart);
|
|
269
|
-
}
|
|
270
|
-
return lineIndex;
|
|
271
|
-
}
|
|
272
|
-
function getTocEntrySubtreeRange(lines, lineIndex) {
|
|
273
|
-
const parsed = parseTocLine(lines[lineIndex]);
|
|
274
|
-
if (!parsed.isMatch) {
|
|
275
|
-
return { start: lineIndex, end: lineIndex + 1 };
|
|
276
|
-
}
|
|
277
|
-
const baseIndent = parsed.indentLevel;
|
|
278
|
-
let end = lineIndex + 1;
|
|
279
|
-
for (let i = lineIndex + 1; i < lines.length; i++) {
|
|
280
|
-
const next = parseTocLine(lines[i]);
|
|
281
|
-
if (next.isMatch && next.indentLevel <= baseIndent) break;
|
|
282
|
-
end = i + 1;
|
|
283
|
-
}
|
|
284
|
-
return { start: lineIndex, end };
|
|
285
|
-
}
|
|
286
|
-
function collectNoteIndexesInSubtree(lines, lineIndex) {
|
|
287
|
-
const { start, end } = getTocEntrySubtreeRange(lines, lineIndex);
|
|
288
|
-
const indexes = [];
|
|
289
|
-
for (let i = start; i < end; i++) {
|
|
290
|
-
const parsed = parseTocLine(lines[i]);
|
|
291
|
-
if (parsed.noteIndex) {
|
|
292
|
-
indexes.push(parsed.noteIndex);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return indexes;
|
|
296
|
-
}
|
|
297
|
-
function renameFolderLine(lines, lineIndex, newTitle) {
|
|
298
|
-
const parsed = parseTocLine(lines[lineIndex]);
|
|
299
|
-
if (parsed.kind !== "folder") {
|
|
300
|
-
throw new Error(`TOC \u884C ${lineIndex} \u4E0D\u662F\u76EE\u5F55\u884C`);
|
|
301
|
-
}
|
|
302
|
-
const trimmed = newTitle.trim();
|
|
303
|
-
if (!trimmed) {
|
|
304
|
-
throw new Error("\u76EE\u5F55\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A");
|
|
305
|
-
}
|
|
306
|
-
const result = [...lines];
|
|
307
|
-
result[lineIndex] = buildFolderTocLine(trimmed, parsed.indentLevel);
|
|
308
|
-
return result;
|
|
309
|
-
}
|
|
310
|
-
function getPreviousNoteIndexOutsideSubtree(lines, lineIndex) {
|
|
311
|
-
const { start } = getTocEntrySubtreeRange(lines, lineIndex);
|
|
312
|
-
let lastBefore = null;
|
|
313
|
-
for (let i = 0; i < start; i++) {
|
|
314
|
-
const parsed = parseTocLine(lines[i]);
|
|
315
|
-
if (parsed.noteIndex) {
|
|
316
|
-
lastBefore = parsed.noteIndex;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
return lastBefore;
|
|
320
|
-
}
|
|
321
|
-
function isNoteIndexInSubtree(lines, lineIndex, noteIndex) {
|
|
322
|
-
const indexes = collectNoteIndexesInSubtree(lines, lineIndex);
|
|
323
|
-
return indexes.includes(noteIndex);
|
|
324
|
-
}
|
|
325
|
-
function findFolderLineIndex(lines, folderPath) {
|
|
326
|
-
const target = folderPath.join("/");
|
|
327
|
-
const stack = [];
|
|
328
|
-
for (let i = 0; i < lines.length; i++) {
|
|
329
|
-
const parsed = parseTocLine(lines[i]);
|
|
330
|
-
if (!parsed.isMatch) continue;
|
|
331
|
-
while (stack.length > 0 && stack[stack.length - 1].indent >= parsed.indentLevel) {
|
|
332
|
-
stack.pop();
|
|
333
|
-
}
|
|
334
|
-
if (parsed.kind === "folder") {
|
|
335
|
-
const path = [...stack.map((s) => s.title), parsed.folderTitle].join("/");
|
|
336
|
-
if (path === target) return i;
|
|
337
|
-
stack.push({ title: parsed.folderTitle, indent: parsed.indentLevel });
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
throw new Error(`TOC.md \u4E2D\u672A\u627E\u5230\u76EE\u5F55: ${folderPath.join(" > ")}`);
|
|
341
|
-
}
|
|
342
|
-
function findTocLineIndex(lines, noteIndex) {
|
|
343
|
-
for (let i = 0; i < lines.length; i++) {
|
|
344
|
-
const parsed = parseTocLine(lines[i]);
|
|
345
|
-
if (parsed.noteIndex === noteIndex) return i;
|
|
346
|
-
}
|
|
347
|
-
throw new Error(`TOC.md \u4E2D\u672A\u627E\u5230\u7B14\u8BB0: ${noteIndex}`);
|
|
348
|
-
}
|
|
349
|
-
function getPreviousTocNoteIndex(lines, noteIndex) {
|
|
350
|
-
const flat = parseTocLinesToFlatNodes(lines);
|
|
351
|
-
const index = flat.findIndex((node) => node.noteIndex === noteIndex);
|
|
352
|
-
if (index === -1) {
|
|
353
|
-
throw new Error(`TOC.md \u4E2D\u672A\u627E\u5230\u7B14\u8BB0: ${noteIndex}`);
|
|
354
|
-
}
|
|
355
|
-
if (index <= 0) return null;
|
|
356
|
-
return flat[index - 1].noteIndex;
|
|
357
|
-
}
|
|
358
|
-
function processTocEmptyLines(lines) {
|
|
359
|
-
const result = [];
|
|
360
|
-
let previousEmpty = false;
|
|
361
|
-
for (let i = 0; i < lines.length; i++) {
|
|
362
|
-
const line = lines[i];
|
|
363
|
-
if (line === "") {
|
|
364
|
-
const prev = i > 0 ? lines[i - 1] : null;
|
|
365
|
-
const next = i < lines.length - 1 ? lines[i + 1] : null;
|
|
366
|
-
if (prev && next && isTocContentLine(prev) && isTocContentLine(next)) {
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
if (!previousEmpty) {
|
|
370
|
-
result.push(line);
|
|
371
|
-
previousEmpty = true;
|
|
372
|
-
}
|
|
373
|
-
} else {
|
|
374
|
-
result.push(line);
|
|
375
|
-
previousEmpty = false;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
return result;
|
|
379
|
-
}
|
|
380
|
-
function parseTocCompletedNotes(content) {
|
|
381
|
-
const lines = content.split("\n");
|
|
382
|
-
const noteMap = /* @__PURE__ */ new Map();
|
|
383
|
-
for (const line of lines) {
|
|
384
|
-
const parsed = parseTocLine(line);
|
|
385
|
-
if (parsed.kind !== "note" || !parsed.noteIndex) continue;
|
|
386
|
-
const noteIndex = parsed.noteIndex;
|
|
387
|
-
const completed = parsed.completed;
|
|
388
|
-
if (noteMap.has(noteIndex)) {
|
|
389
|
-
const existing = noteMap.get(noteIndex);
|
|
390
|
-
if (existing.completed !== completed) {
|
|
391
|
-
throw new Error(
|
|
392
|
-
`\u53D1\u73B0\u76F8\u540C\u7F16\u53F7 ${noteIndex} \u7684\u7B14\u8BB0\u6709\u4E0D\u540C\u7684\u5B8C\u6210\u72B6\u6001:
|
|
393
|
-
\u7B2C\u4E00\u6B21\u51FA\u73B0: ${existing.line}
|
|
394
|
-
\u7B2C\u4E8C\u6B21\u51FA\u73B0: ${line.trim()}`
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
noteMap.set(noteIndex, {
|
|
400
|
-
noteIndex,
|
|
401
|
-
completed,
|
|
402
|
-
line: line.trim()
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
const notes = Array.from(noteMap.values());
|
|
406
|
-
return {
|
|
407
|
-
completedCount: notes.filter((n) => n.completed).length,
|
|
408
|
-
totalCount: notes.length,
|
|
409
|
-
notes
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
function buildSidebarFromTocTree(tree, notes, options, parentFolderPath = []) {
|
|
413
|
-
const collapsed = options.sidebarIsCollapsed ?? true;
|
|
414
|
-
function mapNote(node, currentFolderPath) {
|
|
415
|
-
const note = resolveNoteFromIndex(node.noteIndex, notes);
|
|
416
|
-
if (!note) return null;
|
|
417
|
-
let statusEmoji = "\u23F0 ";
|
|
418
|
-
if (note.config?.done) {
|
|
419
|
-
statusEmoji = "\u2705 ";
|
|
420
|
-
}
|
|
421
|
-
let displayText = note.dirName;
|
|
422
|
-
if (!options.sidebarShowNoteId) {
|
|
423
|
-
displayText = note.dirName.replace(/^\d{4}\.\s/, "");
|
|
424
|
-
}
|
|
425
|
-
const childItems = node.children.map((child) => mapNode(child, currentFolderPath)).filter((item2) => item2 !== null);
|
|
426
|
-
if (childItems.length > 0) {
|
|
427
|
-
const item2 = {
|
|
428
|
-
text: statusEmoji + displayText,
|
|
429
|
-
link: `/notes/${note.dirName}/README`,
|
|
430
|
-
collapsed,
|
|
431
|
-
items: childItems,
|
|
432
|
-
tocLineIndex: node.tocLineIndex
|
|
433
|
-
};
|
|
434
|
-
item2.nodeId = computeSidebarNodeId(item2);
|
|
435
|
-
return item2;
|
|
436
|
-
}
|
|
437
|
-
const item = {
|
|
438
|
-
text: statusEmoji + displayText,
|
|
439
|
-
link: `/notes/${note.dirName}/README`,
|
|
440
|
-
tocLineIndex: node.tocLineIndex
|
|
441
|
-
};
|
|
442
|
-
item.nodeId = computeSidebarNodeId(item);
|
|
443
|
-
return item;
|
|
444
|
-
}
|
|
445
|
-
function mapFolder(node, folderPath) {
|
|
446
|
-
const childItems = node.children.map((child) => mapNode(child, folderPath)).filter((item2) => item2 !== null);
|
|
447
|
-
if (childItems.length === 0) {
|
|
448
|
-
const item2 = {
|
|
449
|
-
text: node.title,
|
|
450
|
-
collapsed,
|
|
451
|
-
items: [],
|
|
452
|
-
folderPath,
|
|
453
|
-
tocLineIndex: node.tocLineIndex
|
|
454
|
-
};
|
|
455
|
-
item2.nodeId = computeSidebarNodeId(item2);
|
|
456
|
-
return item2;
|
|
457
|
-
}
|
|
458
|
-
const item = {
|
|
459
|
-
text: node.title,
|
|
460
|
-
collapsed,
|
|
461
|
-
items: childItems,
|
|
462
|
-
folderPath,
|
|
463
|
-
tocLineIndex: node.tocLineIndex
|
|
464
|
-
};
|
|
465
|
-
item.nodeId = computeSidebarNodeId(item);
|
|
466
|
-
return item;
|
|
467
|
-
}
|
|
468
|
-
function mapNode(node, currentFolderPath) {
|
|
469
|
-
if (node.kind === "folder") {
|
|
470
|
-
const folderPath = [...currentFolderPath, node.title];
|
|
471
|
-
return mapFolder(node, folderPath);
|
|
472
|
-
}
|
|
473
|
-
return mapNote(node, currentFolderPath);
|
|
474
|
-
}
|
|
475
|
-
return tree.map((node) => mapNode(node, parentFolderPath)).filter((item) => item !== null);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
export {
|
|
479
|
-
getNewNoteReadmeBody,
|
|
480
|
-
generateNoteTitle,
|
|
481
|
-
parseNodeId,
|
|
482
|
-
TOC_INDENT_SPACES,
|
|
483
|
-
parseTocLine,
|
|
484
|
-
resolveNoteFromIndex,
|
|
485
|
-
getTocLineCompleted,
|
|
486
|
-
buildFolderTocLine,
|
|
487
|
-
buildTocLine,
|
|
488
|
-
parseTocToTree,
|
|
489
|
-
serializeTocTree,
|
|
490
|
-
adjustTocLineIndexAfterSubtreeRemoval,
|
|
491
|
-
getTocEntrySubtreeRange,
|
|
492
|
-
collectNoteIndexesInSubtree,
|
|
493
|
-
renameFolderLine,
|
|
494
|
-
getPreviousNoteIndexOutsideSubtree,
|
|
495
|
-
isNoteIndexInSubtree,
|
|
496
|
-
findFolderLineIndex,
|
|
497
|
-
findTocLineIndex,
|
|
498
|
-
getPreviousTocNoteIndex,
|
|
499
|
-
processTocEmptyLines,
|
|
500
|
-
parseTocCompletedNotes,
|
|
501
|
-
buildSidebarFromTocTree
|
|
502
|
-
};
|