@tnotesjs/core 0.1.24 → 0.1.25
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/dist/{chunk-BSTQOJVE.js → chunk-4KG6RXFS.js} +113 -130
- package/dist/{chunk-O4DCXHOV.js → chunk-AGSL3VZE.js} +1 -4
- package/dist/cli/index.js +162 -173
- package/dist/index.js +1 -1
- package/dist/vitepress/config/index.js +6 -8
- package/package.json +4 -1
- package/types/config.ts +1 -1
- package/types/index.ts +1 -1
- package/types/note.ts +1 -1
- package/vitepress/assets/icons/index.ts +1 -1
- package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +4 -0
- package/vitepress/components/CodeBlockFullscreen/CodeBlockFullscreen.vue +4 -0
- package/vitepress/components/CodeBlockFullscreen/index.ts +8 -0
- package/vitepress/components/CodeBlockFullscreen/styles.css +4 -0
- package/vitepress/components/Discussions/Discussions.vue +4 -0
- package/vitepress/components/EnWordList/EnWordList.vue +4 -0
- package/vitepress/components/EnWordList/RightClickMenu.vue +4 -0
- package/vitepress/components/Footprints/Footprints.vue +4 -0
- package/vitepress/components/Layout/AboutModal.vue +4 -0
- package/vitepress/components/Layout/AboutPanel.vue +4 -0
- package/vitepress/components/Layout/ContentCollapse.vue +4 -0
- package/vitepress/components/Layout/CustomSidebar.vue +4 -0
- package/vitepress/components/Layout/DocBeforeControls.vue +4 -0
- package/vitepress/components/Layout/DocFooter.vue +4 -0
- package/vitepress/components/Layout/ImagePreview.vue +4 -0
- package/vitepress/components/Layout/Layout.vue +4 -0
- package/vitepress/components/Layout/NavBarSettingsTrigger.vue +4 -0
- package/vitepress/components/Layout/NoteStatus.vue +4 -0
- package/vitepress/components/Layout/SidebarItems.vue +4 -0
- package/vitepress/components/Layout/SidebarNavBefore.vue +4 -0
- package/vitepress/components/Layout/SidebarResizeHandle.vue +5 -1
- package/vitepress/components/Layout/Swiper.vue +4 -0
- package/vitepress/components/Layout/ToggleFullContent.vue +4 -0
- package/vitepress/components/Layout/ToggleSidebar.vue +4 -1
- package/vitepress/components/Layout/composables/useCollapseControl.ts +6 -0
- package/vitepress/components/Layout/composables/useNoteConfig.ts +7 -0
- package/vitepress/components/Layout/composables/useNoteSave.ts +4 -0
- package/vitepress/components/Layout/composables/useNoteValidation.ts +8 -0
- package/vitepress/components/Layout/composables/useRedirect.ts +7 -0
- package/vitepress/components/Layout/composables/useRenameOverlay.ts +3 -0
- package/vitepress/components/Layout/composables/useRenameRedirect.ts +3 -0
- package/vitepress/components/Layout/composables/useSidebarLayout.ts +6 -0
- package/vitepress/components/Layout/composables/useVSCodeIntegration.ts +6 -0
- package/vitepress/components/Layout/homeReadme.data.ts +3 -1
- package/vitepress/components/LoadingPage/LoadingPage.vue +4 -0
- package/vitepress/components/MarkMap/MarkMap.vue +4 -0
- package/vitepress/components/Mermaid/Mermaid.vue +6 -0
- package/vitepress/components/NotesTable/NotesTable.vue +4 -0
- package/vitepress/components/Settings/Settings.vue +6 -0
- package/vitepress/components/Settings/SettingsDialog.vue +6 -0
- package/vitepress/components/Settings/composables/useSettingsDialog.ts +3 -0
- package/vitepress/components/SidebarCard/MindMapView.vue +4 -0
- package/vitepress/components/SidebarCard/NotesTrendChart.vue +4 -0
- package/vitepress/components/SidebarCard/SidebarCard.vue +4 -0
- package/vitepress/components/Tooltip/Tooltip.vue +6 -0
- package/vitepress/components/constants.ts +3 -0
- package/vitepress/components/notesConfig.data.ts +7 -1
- package/vitepress/components/sidebar.data.ts +1 -1
- package/vitepress/components/tnotes-config.data.ts +13 -8
- package/vitepress/components/utils.ts +6 -0
- package/vitepress/config/index.ts +5 -13
- package/vitepress/configs/constants.ts +1 -0
- package/vitepress/configs/head.config.ts +1 -0
- package/vitepress/configs/index.ts +1 -0
- package/vitepress/configs/markdown.config.ts +1 -0
- package/vitepress/configs/theme.config.ts +1 -0
- package/vitepress/plugins/buildProgressPlugin.ts +1 -1
- package/vitepress/plugins/fileWatcherBridgePlugin.ts +2 -1
- package/vitepress/plugins/getNoteByConfigIdPlugin.ts +2 -1
- package/vitepress/plugins/renameNotePlugin.ts +2 -1
- package/vitepress/plugins/sidebarStructurePlugin.ts +3 -2
- package/vitepress/plugins/updateConfigPlugin.ts +2 -1
- package/vitepress/theme/index.ts +1 -4
package/dist/cli/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
COMMAND_NAMES,
|
|
6
6
|
COMMAND_OPTIONS,
|
|
7
7
|
FileWatcherService,
|
|
8
|
+
GitManager,
|
|
8
9
|
GitService,
|
|
9
10
|
NoteIndexCache,
|
|
10
11
|
NoteManager,
|
|
@@ -22,20 +23,18 @@ import {
|
|
|
22
23
|
parseArgs,
|
|
23
24
|
parseReadmeCompletedNotes,
|
|
24
25
|
runCommand
|
|
25
|
-
} from "../chunk-
|
|
26
|
+
} from "../chunk-4KG6RXFS.js";
|
|
26
27
|
import {
|
|
27
28
|
ConfigManager
|
|
28
|
-
} from "../chunk-
|
|
29
|
+
} from "../chunk-AGSL3VZE.js";
|
|
29
30
|
|
|
30
31
|
// commands/update/UpdateCommand.ts
|
|
31
32
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
32
33
|
import { resolve } from "path";
|
|
33
34
|
var UpdateCommand = class extends BaseCommand {
|
|
34
|
-
readmeService;
|
|
35
|
-
noteService;
|
|
36
|
-
quiet = false;
|
|
37
35
|
constructor() {
|
|
38
36
|
super("update");
|
|
37
|
+
this.quiet = false;
|
|
39
38
|
this.readmeService = ReadmeService.getInstance();
|
|
40
39
|
this.noteService = NoteService.getInstance();
|
|
41
40
|
}
|
|
@@ -121,158 +120,18 @@ var UpdateCommand = class extends BaseCommand {
|
|
|
121
120
|
}
|
|
122
121
|
};
|
|
123
122
|
|
|
124
|
-
// commands/update-completed-count/UpdateCompletedCountCommand.ts
|
|
125
|
-
import { execSync } from "child_process";
|
|
126
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
127
|
-
var UpdateCompletedCountCommand = class extends BaseCommand {
|
|
128
|
-
constructor() {
|
|
129
|
-
super("update-completed-count");
|
|
130
|
-
}
|
|
131
|
-
async run() {
|
|
132
|
-
await this.updateCurrentRepo();
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* 更新当前知识库
|
|
136
|
-
*/
|
|
137
|
-
async updateCurrentRepo() {
|
|
138
|
-
const startTime = Date.now();
|
|
139
|
-
try {
|
|
140
|
-
const configContent = readFileSync2(ROOT_CONFIG_PATH, "utf-8");
|
|
141
|
-
const config = JSON.parse(configContent);
|
|
142
|
-
this.logger.info("\u5F00\u59CB\u66F4\u65B0\u5B8C\u6210\u7B14\u8BB0\u6570\u91CF\u5386\u53F2\u8BB0\u5F55...");
|
|
143
|
-
const completedNotesCountHistory = await this.getCompletedNotesCountHistory(
|
|
144
|
-
config.root_item.created_at ?? Date.now()
|
|
145
|
-
);
|
|
146
|
-
config.root_item = {
|
|
147
|
-
...config.root_item,
|
|
148
|
-
completed_notes_count: completedNotesCountHistory
|
|
149
|
-
};
|
|
150
|
-
writeFileSync2(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
151
|
-
const duration = Date.now() - startTime;
|
|
152
|
-
const monthKeys = Object.keys(completedNotesCountHistory);
|
|
153
|
-
const currentKey = monthKeys[monthKeys.length - 1];
|
|
154
|
-
const currentCount = completedNotesCountHistory[currentKey] || 0;
|
|
155
|
-
this.logger.success(
|
|
156
|
-
`\u5386\u53F2\u6570\u636E\u66F4\u65B0\u5B8C\u6210: \u5171 ${monthKeys.length} \u4E2A\u6708, \u5F53\u524D ${currentKey} \u6708\u5B8C\u6210 ${currentCount} \u7BC7\u7B14\u8BB0 (${duration}ms)`
|
|
157
|
-
);
|
|
158
|
-
} catch (error) {
|
|
159
|
-
this.logger.error(
|
|
160
|
-
`\u66F4\u65B0\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
161
|
-
);
|
|
162
|
-
throw error;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* 获取历史每个月的 completed_notes_count(最近12个月)
|
|
167
|
-
*
|
|
168
|
-
* 逻辑:
|
|
169
|
-
* 1. 计算最近12个月的范围(当前月份往前推11个月)
|
|
170
|
-
* 2. 遍历这12个月,从 Git 历史中读取 README.md
|
|
171
|
-
* 3. 解析 README.md 获取完成笔记数量
|
|
172
|
-
* 4. 如果知识库创建时间在这12个月内,之前的月份补0
|
|
173
|
-
* 5. 返回对象 { '25.01': 0, '25.02': 1, ..., '25.12': 15 }
|
|
174
|
-
*/
|
|
175
|
-
async getCompletedNotesCountHistory(createdAt) {
|
|
176
|
-
try {
|
|
177
|
-
const now = /* @__PURE__ */ new Date();
|
|
178
|
-
const currentYear = now.getFullYear();
|
|
179
|
-
const currentMonth = now.getMonth();
|
|
180
|
-
let firstYear = currentYear;
|
|
181
|
-
let firstMonth = currentMonth - 11;
|
|
182
|
-
if (firstMonth < 0) {
|
|
183
|
-
firstYear = currentYear - 1;
|
|
184
|
-
firstMonth = 12 + firstMonth;
|
|
185
|
-
}
|
|
186
|
-
const createdDate = new Date(createdAt);
|
|
187
|
-
const createdYear = createdDate.getFullYear();
|
|
188
|
-
const createdMonth = createdDate.getMonth();
|
|
189
|
-
const result = {};
|
|
190
|
-
let prevCount = 0;
|
|
191
|
-
for (let i = 0; i < 12; i++) {
|
|
192
|
-
const targetYear = firstYear + Math.floor((firstMonth + i) / 12);
|
|
193
|
-
const targetMonth = (firstMonth + i) % 12;
|
|
194
|
-
const yearShort = String(targetYear).slice(-2);
|
|
195
|
-
const monthStr = String(targetMonth + 1).padStart(2, "0");
|
|
196
|
-
const key = `${yearShort}.${monthStr}`;
|
|
197
|
-
const isBeforeCreation = targetYear < createdYear || targetYear === createdYear && targetMonth < createdMonth;
|
|
198
|
-
if (isBeforeCreation) {
|
|
199
|
-
result[key] = 0;
|
|
200
|
-
prevCount = 0;
|
|
201
|
-
this.logger.info(`\u2713 ${key}: 0 \u7BC7\uFF08\u65E9\u4E8E\u521B\u5EFA\u65F6\u95F4\uFF09`);
|
|
202
|
-
} else {
|
|
203
|
-
try {
|
|
204
|
-
const count = await this.getMonthCompletedCount(
|
|
205
|
-
targetYear,
|
|
206
|
-
targetMonth,
|
|
207
|
-
prevCount
|
|
208
|
-
);
|
|
209
|
-
result[key] = count;
|
|
210
|
-
prevCount = count;
|
|
211
|
-
this.logger.info(`\u2713 ${key}: ${count} \u7BC7`);
|
|
212
|
-
} catch (error) {
|
|
213
|
-
result[key] = prevCount;
|
|
214
|
-
this.logger.warn(`${key}: \u65E0\u6570\u636E\uFF0C\u4F7F\u7528 ${prevCount}\uFF08\u4E0A\u6708\u503C\uFF09`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return result;
|
|
219
|
-
} catch (error) {
|
|
220
|
-
this.logger.error(
|
|
221
|
-
`\u83B7\u53D6\u5386\u53F2\u6570\u636E\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
222
|
-
);
|
|
223
|
-
return {};
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* 获取指定月份的完成笔记数量
|
|
228
|
-
* @param year - 年份
|
|
229
|
-
* @param month - 月份 (0-11)
|
|
230
|
-
* @param fallbackCount - 回退值(如果该月没有数据)
|
|
231
|
-
* @returns 完成笔记数量
|
|
232
|
-
*/
|
|
233
|
-
async getMonthCompletedCount(year, month, fallbackCount = 0) {
|
|
234
|
-
const lastDayOfMonth = new Date(year, month + 1, 0, 23, 59, 59);
|
|
235
|
-
const yearStr = lastDayOfMonth.getFullYear();
|
|
236
|
-
const monthStr = String(lastDayOfMonth.getMonth() + 1).padStart(2, "0");
|
|
237
|
-
const dayStr = String(lastDayOfMonth.getDate()).padStart(2, "0");
|
|
238
|
-
const untilDate = `${yearStr}-${monthStr}-${dayStr} 23:59:59 +0800`;
|
|
239
|
-
const commitHash = execSync(
|
|
240
|
-
`git log --until="${untilDate}" --format=%H -1 -- README.md`,
|
|
241
|
-
{
|
|
242
|
-
cwd: ROOT_DIR_PATH,
|
|
243
|
-
encoding: "utf-8"
|
|
244
|
-
}
|
|
245
|
-
).trim();
|
|
246
|
-
if (!commitHash) {
|
|
247
|
-
return fallbackCount;
|
|
248
|
-
}
|
|
249
|
-
let readmeContent;
|
|
250
|
-
try {
|
|
251
|
-
readmeContent = execSync(`git show ${commitHash}:README.md`, {
|
|
252
|
-
cwd: ROOT_DIR_PATH,
|
|
253
|
-
encoding: "utf-8"
|
|
254
|
-
});
|
|
255
|
-
} catch (error) {
|
|
256
|
-
return fallbackCount;
|
|
257
|
-
}
|
|
258
|
-
const { completedCount } = parseReadmeCompletedNotes(readmeContent);
|
|
259
|
-
return completedCount;
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
|
|
263
123
|
// commands/git/PushCommand.ts
|
|
264
124
|
var PushCommand = class extends BaseCommand {
|
|
265
|
-
gitService;
|
|
266
|
-
timestampService;
|
|
267
125
|
constructor() {
|
|
268
126
|
super("push");
|
|
127
|
+
this.gitManager = new GitManager(ROOT_DIR_PATH);
|
|
269
128
|
this.gitService = new GitService();
|
|
270
129
|
this.timestampService = new TimestampService();
|
|
271
130
|
}
|
|
272
131
|
async run() {
|
|
273
132
|
try {
|
|
274
133
|
this.logger.info("\u68C0\u67E5\u662F\u5426\u6709\u66F4\u6539...");
|
|
275
|
-
const status = await this.
|
|
134
|
+
const status = await this.gitManager.getStatus();
|
|
276
135
|
const hasPendingCommits = (status.ahead ?? 0) > 0;
|
|
277
136
|
if (!status.hasChanges && !hasPendingCommits) {
|
|
278
137
|
this.logger.info("\u6CA1\u6709\u66F4\u6539\u9700\u8981\u63A8\u9001");
|
|
@@ -317,7 +176,6 @@ var PushCommand = class extends BaseCommand {
|
|
|
317
176
|
|
|
318
177
|
// commands/git/PullCommand.ts
|
|
319
178
|
var PullCommand = class extends BaseCommand {
|
|
320
|
-
gitService;
|
|
321
179
|
constructor() {
|
|
322
180
|
super("pull");
|
|
323
181
|
this.gitService = new GitService();
|
|
@@ -331,7 +189,6 @@ var PullCommand = class extends BaseCommand {
|
|
|
331
189
|
|
|
332
190
|
// commands/build/BuildCommand.ts
|
|
333
191
|
var BuildCommand = class extends BaseCommand {
|
|
334
|
-
vitepressService;
|
|
335
192
|
constructor() {
|
|
336
193
|
super("build");
|
|
337
194
|
this.vitepressService = new VitepressService();
|
|
@@ -345,7 +202,6 @@ var BuildCommand = class extends BaseCommand {
|
|
|
345
202
|
|
|
346
203
|
// commands/build/PreviewCommand.ts
|
|
347
204
|
var PreviewCommand = class extends BaseCommand {
|
|
348
|
-
vitepressService;
|
|
349
205
|
constructor() {
|
|
350
206
|
super("preview");
|
|
351
207
|
this.vitepressService = new VitepressService();
|
|
@@ -363,23 +219,20 @@ var PreviewCommand = class extends BaseCommand {
|
|
|
363
219
|
|
|
364
220
|
// commands/dev/DevCommand.ts
|
|
365
221
|
var DevCommand = class extends BaseCommand {
|
|
366
|
-
fileWatcherService;
|
|
367
|
-
vitepressService;
|
|
368
|
-
noteManager;
|
|
369
|
-
noteIndexCache;
|
|
370
|
-
configManager;
|
|
371
222
|
constructor() {
|
|
372
223
|
super("dev");
|
|
224
|
+
this.configManager = ConfigManager.getInstance();
|
|
373
225
|
this.fileWatcherService = new FileWatcherService();
|
|
374
|
-
this.vitepressService = new VitepressService();
|
|
375
|
-
this.noteManager = NoteManager.getInstance();
|
|
376
226
|
this.noteIndexCache = NoteIndexCache.getInstance();
|
|
377
|
-
this.
|
|
227
|
+
this.noteManager = NoteManager.getInstance();
|
|
228
|
+
this.readmeService = ReadmeService.getInstance();
|
|
229
|
+
this.vitepressService = new VitepressService();
|
|
378
230
|
}
|
|
379
231
|
async run() {
|
|
380
232
|
const notes = this.noteManager.scanNotes();
|
|
381
233
|
this.logger.info(`\u626B\u63CF\u5230 ${notes.length} \u7BC7\u7B14\u8BB0`);
|
|
382
234
|
this.noteIndexCache.initialize(notes);
|
|
235
|
+
await this.readmeService.regenerateSidebar(notes);
|
|
383
236
|
const result = await this.vitepressService.startServer();
|
|
384
237
|
if (result) {
|
|
385
238
|
const versionInfo = result.version ? `\uFF08v${result.version}\uFF09` : "";
|
|
@@ -390,10 +243,10 @@ var DevCommand = class extends BaseCommand {
|
|
|
390
243
|
this.fileWatcherService.start();
|
|
391
244
|
const watcherElapsed = Date.now() - watcherStart;
|
|
392
245
|
this.logger.success(`\u6587\u4EF6\u76D1\u542C\u670D\u52A1\u5DF2\u5C31\u7EEA\uFF0C\u8017\u65F6\uFF1A${watcherElapsed} ms`);
|
|
393
|
-
const
|
|
394
|
-
const
|
|
246
|
+
const port2 = this.configManager.get("port") || VitepressService.DEFAULT_DEV_PORT;
|
|
247
|
+
const repoName2 = this.configManager.get("repoName");
|
|
395
248
|
this.logger.info(
|
|
396
|
-
`\u672C\u5730\u5F00\u53D1\u670D\u52A1\u5730\u5740\uFF1Ahttp://localhost:${
|
|
249
|
+
`\u672C\u5730\u5F00\u53D1\u670D\u52A1\u5730\u5740\uFF1Ahttp://localhost:${port2}/${repoName2}/`
|
|
397
250
|
);
|
|
398
251
|
} else {
|
|
399
252
|
this.logger.error("\u542F\u52A8\u670D\u52A1\u5668\u5931\u8D25");
|
|
@@ -403,7 +256,6 @@ var DevCommand = class extends BaseCommand {
|
|
|
403
256
|
|
|
404
257
|
// commands/maintenance/FixTimestampsCommand.ts
|
|
405
258
|
var FixTimestampsCommand = class extends BaseCommand {
|
|
406
|
-
timestampService;
|
|
407
259
|
constructor() {
|
|
408
260
|
super("fix-timestamps");
|
|
409
261
|
this.timestampService = new TimestampService();
|
|
@@ -509,8 +361,6 @@ var HelpCommand = class extends BaseCommand {
|
|
|
509
361
|
import { createInterface } from "readline";
|
|
510
362
|
import { v4 as uuidv4 } from "uuid";
|
|
511
363
|
var CreateNoteCommand = class extends BaseCommand {
|
|
512
|
-
noteService;
|
|
513
|
-
readmeService;
|
|
514
364
|
constructor() {
|
|
515
365
|
super("create-notes");
|
|
516
366
|
this.noteService = NoteService.getInstance();
|
|
@@ -624,20 +474,159 @@ var CreateNoteCommand = class extends BaseCommand {
|
|
|
624
474
|
}
|
|
625
475
|
};
|
|
626
476
|
|
|
477
|
+
// commands/update-completed-count/UpdateCompletedCountCommand.ts
|
|
478
|
+
import { execSync } from "child_process";
|
|
479
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
480
|
+
var UpdateCompletedCountCommand = class extends BaseCommand {
|
|
481
|
+
constructor() {
|
|
482
|
+
super("update-completed-count");
|
|
483
|
+
}
|
|
484
|
+
async run() {
|
|
485
|
+
await this.updateCurrentRepo();
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* 更新当前知识库
|
|
489
|
+
*/
|
|
490
|
+
async updateCurrentRepo() {
|
|
491
|
+
const startTime = Date.now();
|
|
492
|
+
try {
|
|
493
|
+
const configContent = readFileSync2(ROOT_CONFIG_PATH, "utf-8");
|
|
494
|
+
const config = JSON.parse(configContent);
|
|
495
|
+
this.logger.info("\u5F00\u59CB\u66F4\u65B0\u5B8C\u6210\u7B14\u8BB0\u6570\u91CF\u5386\u53F2\u8BB0\u5F55...");
|
|
496
|
+
const completedNotesCountHistory = await this.getCompletedNotesCountHistory(
|
|
497
|
+
config.root_item.created_at ?? Date.now()
|
|
498
|
+
);
|
|
499
|
+
config.root_item = {
|
|
500
|
+
...config.root_item,
|
|
501
|
+
completed_notes_count: completedNotesCountHistory
|
|
502
|
+
};
|
|
503
|
+
writeFileSync2(ROOT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
504
|
+
const duration = Date.now() - startTime;
|
|
505
|
+
const monthKeys = Object.keys(completedNotesCountHistory);
|
|
506
|
+
const currentKey = monthKeys[monthKeys.length - 1];
|
|
507
|
+
const currentCount = completedNotesCountHistory[currentKey] || 0;
|
|
508
|
+
this.logger.success(
|
|
509
|
+
`\u5386\u53F2\u6570\u636E\u66F4\u65B0\u5B8C\u6210: \u5171 ${monthKeys.length} \u4E2A\u6708, \u5F53\u524D ${currentKey} \u6708\u5B8C\u6210 ${currentCount} \u7BC7\u7B14\u8BB0 (${duration}ms)`
|
|
510
|
+
);
|
|
511
|
+
} catch (error) {
|
|
512
|
+
this.logger.error(
|
|
513
|
+
`\u66F4\u65B0\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
514
|
+
);
|
|
515
|
+
throw error;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* 获取历史每个月的 completed_notes_count(最近12个月)
|
|
520
|
+
*
|
|
521
|
+
* 逻辑:
|
|
522
|
+
* 1. 计算最近12个月的范围(当前月份往前推11个月)
|
|
523
|
+
* 2. 遍历这12个月,从 Git 历史中读取 README.md
|
|
524
|
+
* 3. 解析 README.md 获取完成笔记数量
|
|
525
|
+
* 4. 如果知识库创建时间在这12个月内,之前的月份补0
|
|
526
|
+
* 5. 返回对象 { '25.01': 0, '25.02': 1, ..., '25.12': 15 }
|
|
527
|
+
*/
|
|
528
|
+
async getCompletedNotesCountHistory(createdAt) {
|
|
529
|
+
try {
|
|
530
|
+
const now = /* @__PURE__ */ new Date();
|
|
531
|
+
const currentYear = now.getFullYear();
|
|
532
|
+
const currentMonth = now.getMonth();
|
|
533
|
+
let firstYear = currentYear;
|
|
534
|
+
let firstMonth = currentMonth - 11;
|
|
535
|
+
if (firstMonth < 0) {
|
|
536
|
+
firstYear = currentYear - 1;
|
|
537
|
+
firstMonth = 12 + firstMonth;
|
|
538
|
+
}
|
|
539
|
+
const createdDate = new Date(createdAt);
|
|
540
|
+
const createdYear = createdDate.getFullYear();
|
|
541
|
+
const createdMonth = createdDate.getMonth();
|
|
542
|
+
const result = {};
|
|
543
|
+
let prevCount = 0;
|
|
544
|
+
for (let i = 0; i < 12; i++) {
|
|
545
|
+
const targetYear = firstYear + Math.floor((firstMonth + i) / 12);
|
|
546
|
+
const targetMonth = (firstMonth + i) % 12;
|
|
547
|
+
const yearShort = String(targetYear).slice(-2);
|
|
548
|
+
const monthStr = String(targetMonth + 1).padStart(2, "0");
|
|
549
|
+
const key = `${yearShort}.${monthStr}`;
|
|
550
|
+
const isBeforeCreation = targetYear < createdYear || targetYear === createdYear && targetMonth < createdMonth;
|
|
551
|
+
if (isBeforeCreation) {
|
|
552
|
+
result[key] = 0;
|
|
553
|
+
prevCount = 0;
|
|
554
|
+
this.logger.info(`\u2713 ${key}: 0 \u7BC7\uFF08\u65E9\u4E8E\u521B\u5EFA\u65F6\u95F4\uFF09`);
|
|
555
|
+
} else {
|
|
556
|
+
try {
|
|
557
|
+
const count = await this.getMonthCompletedCount(
|
|
558
|
+
targetYear,
|
|
559
|
+
targetMonth,
|
|
560
|
+
prevCount
|
|
561
|
+
);
|
|
562
|
+
result[key] = count;
|
|
563
|
+
prevCount = count;
|
|
564
|
+
this.logger.info(`\u2713 ${key}: ${count} \u7BC7`);
|
|
565
|
+
} catch (error) {
|
|
566
|
+
result[key] = prevCount;
|
|
567
|
+
this.logger.warn(`${key}: \u65E0\u6570\u636E\uFF0C\u4F7F\u7528 ${prevCount}\uFF08\u4E0A\u6708\u503C\uFF09`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return result;
|
|
572
|
+
} catch (error) {
|
|
573
|
+
this.logger.error(
|
|
574
|
+
`\u83B7\u53D6\u5386\u53F2\u6570\u636E\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
575
|
+
);
|
|
576
|
+
return {};
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* 获取指定月份的完成笔记数量
|
|
581
|
+
* @param year - 年份
|
|
582
|
+
* @param month - 月份 (0-11)
|
|
583
|
+
* @param fallbackCount - 回退值(如果该月没有数据)
|
|
584
|
+
* @returns 完成笔记数量
|
|
585
|
+
*/
|
|
586
|
+
async getMonthCompletedCount(year, month, fallbackCount = 0) {
|
|
587
|
+
const lastDayOfMonth = new Date(year, month + 1, 0, 23, 59, 59);
|
|
588
|
+
const yearStr = lastDayOfMonth.getFullYear();
|
|
589
|
+
const monthStr = String(lastDayOfMonth.getMonth() + 1).padStart(2, "0");
|
|
590
|
+
const dayStr = String(lastDayOfMonth.getDate()).padStart(2, "0");
|
|
591
|
+
const untilDate = `${yearStr}-${monthStr}-${dayStr} 23:59:59 +0800`;
|
|
592
|
+
const commitHash = execSync(
|
|
593
|
+
`git log --until="${untilDate}" --format=%H -1 -- README.md`,
|
|
594
|
+
{
|
|
595
|
+
cwd: ROOT_DIR_PATH,
|
|
596
|
+
encoding: "utf-8"
|
|
597
|
+
}
|
|
598
|
+
).trim();
|
|
599
|
+
if (!commitHash) {
|
|
600
|
+
return fallbackCount;
|
|
601
|
+
}
|
|
602
|
+
let readmeContent;
|
|
603
|
+
try {
|
|
604
|
+
readmeContent = execSync(`git show ${commitHash}:README.md`, {
|
|
605
|
+
cwd: ROOT_DIR_PATH,
|
|
606
|
+
encoding: "utf-8"
|
|
607
|
+
});
|
|
608
|
+
} catch (error) {
|
|
609
|
+
return fallbackCount;
|
|
610
|
+
}
|
|
611
|
+
const { completedCount } = parseReadmeCompletedNotes(readmeContent);
|
|
612
|
+
return completedCount;
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
627
616
|
// commands/registry.ts
|
|
628
617
|
var commandFactories = {
|
|
629
|
-
|
|
630
|
-
build: () => new BuildCommand(),
|
|
631
|
-
preview: () => new PreviewCommand(),
|
|
632
|
-
update: () => new UpdateCommand(),
|
|
633
|
-
"update-completed-count": () => new UpdateCompletedCountCommand(),
|
|
634
|
-
push: () => new PushCommand(),
|
|
635
|
-
pull: () => new PullCommand(),
|
|
618
|
+
"build": () => new BuildCommand(),
|
|
636
619
|
"create-notes": () => new CreateNoteCommand(),
|
|
620
|
+
"dev": () => new DevCommand(),
|
|
637
621
|
"fix-timestamps": () => new FixTimestampsCommand(),
|
|
638
|
-
"
|
|
622
|
+
"help": () => new HelpCommand(),
|
|
623
|
+
"preview": () => new PreviewCommand(),
|
|
624
|
+
"pull": () => new PullCommand(),
|
|
625
|
+
"push": () => new PushCommand(),
|
|
639
626
|
"rename-note": () => new RenameNoteCommand(),
|
|
640
|
-
|
|
627
|
+
"update-completed-count": () => new UpdateCompletedCountCommand(),
|
|
628
|
+
"update-note-config": () => new UpdateNoteConfigCommand(),
|
|
629
|
+
"update": () => new UpdateCommand()
|
|
641
630
|
};
|
|
642
631
|
var commandCache = /* @__PURE__ */ new Map();
|
|
643
632
|
function getCommand(name) {
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,10 @@ import {
|
|
|
7
7
|
UpdateNoteConfigCommand,
|
|
8
8
|
generateAnchor,
|
|
9
9
|
logger
|
|
10
|
-
} from "../../chunk-
|
|
11
|
-
import
|
|
10
|
+
} from "../../chunk-4KG6RXFS.js";
|
|
11
|
+
import {
|
|
12
|
+
ConfigManager
|
|
13
|
+
} from "../../chunk-AGSL3VZE.js";
|
|
12
14
|
|
|
13
15
|
// vitepress/config/index.ts
|
|
14
16
|
import fs2 from "fs";
|
|
@@ -1066,14 +1068,10 @@ function updateConfigPlugin() {
|
|
|
1066
1068
|
}
|
|
1067
1069
|
|
|
1068
1070
|
// vitepress/config/index.ts
|
|
1069
|
-
function loadTNotesConfig(rootPath) {
|
|
1070
|
-
const configPath = path2.resolve(rootPath, ".tnotes.json");
|
|
1071
|
-
const configContent = fs2.readFileSync(configPath, "utf-8");
|
|
1072
|
-
return JSON.parse(configContent);
|
|
1073
|
-
}
|
|
1074
1071
|
function defineNotesConfig(overrides = {}) {
|
|
1075
1072
|
const rootPath = process.cwd();
|
|
1076
|
-
|
|
1073
|
+
ConfigManager.init({ rootPath });
|
|
1074
|
+
const config = ConfigManager.getInstance().getAll();
|
|
1077
1075
|
const { repoName } = config;
|
|
1078
1076
|
const IGNORE_LIST = getIgnoreList(config);
|
|
1079
1077
|
const GITHUB_PAGE_URL = getGithubPageUrl(config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tnotesjs/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "TNotes 知识库核心框架 —— 基于 VitePress 的笔记管理系统",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.17.1",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
"typecheck": "vue-tsc --noEmit -p tsconfig.build.json",
|
|
33
33
|
"dev": "tsup --watch",
|
|
34
34
|
"release": "node scripts/release.mjs",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"test:watch": "vitest",
|
|
35
37
|
"lint": "eslint . --max-warnings=0",
|
|
36
38
|
"lint:fix": "eslint . --fix"
|
|
37
39
|
},
|
|
@@ -69,6 +71,7 @@
|
|
|
69
71
|
"tsup": "^8.5.1",
|
|
70
72
|
"typescript": "^5.9.3",
|
|
71
73
|
"typescript-eslint": "^8.59.1",
|
|
74
|
+
"vitest": "^4.1.6",
|
|
72
75
|
"vue-eslint-parser": "^10.4.0",
|
|
73
76
|
"vue-tsc": "^3.2.7"
|
|
74
77
|
},
|
package/types/config.ts
CHANGED
package/types/index.ts
CHANGED
package/types/note.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vitepress/components/CodeBlockFullscreen/index.ts
|
|
3
|
+
*
|
|
4
|
+
* 代码块全屏功能的组合式函数
|
|
5
|
+
* 负责在代码块上添加全屏和复制按钮,处理相关事件
|
|
6
|
+
* 使用 Vue 3 的 Composition API 实现,增强用户体验
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { createApp, onMounted, onUnmounted } from 'vue'
|
|
2
10
|
|
|
3
11
|
import CodeBlockFullscreen from './CodeBlockFullscreen.vue'
|