docnest 0.1.23 → 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/README.md +3 -0
- package/dist/server.js +19 -13
- package/package.json +1 -1
- package/server/views/doc.ejs +9 -0
package/README.md
CHANGED
|
@@ -58,6 +58,8 @@ export default defineConfig({
|
|
|
58
58
|
|
|
59
59
|
### 文档搜索
|
|
60
60
|
|
|
61
|
+
整理目录时可以把文档移动到原目录下的分类文件夹。旧地址会在原目录子树中按完全相同的文件名查找,只有唯一匹配时才跳转;重名、目录不存在或读取失败时保留 404,避免打开错误的文档。直接访问现有路径始终优先。
|
|
62
|
+
|
|
61
63
|
普通阅读模式下,页面顶部提供文档搜索入口,也可以使用 `⌘K`(macOS)或
|
|
62
64
|
`Ctrl K`(Windows/Linux)打开。搜索索引在首次打开搜索时才加载,覆盖文档标题、目录路径、标题层级、正文和代码块;中文按连续字符匹配,英文和带空格的查询按多个词匹配。结果按标题、目录和正文命中位置综合排序,并显示安全的文本摘要。
|
|
63
65
|
|
|
@@ -147,6 +149,7 @@ startServer(3000)
|
|
|
147
149
|
Markdown 或 HTML 中明确引用的本地附件,不按文件扩展名设置业务白名单;外链、文档链接、隐藏路径、路径穿越和代码块中的伪引用会被忽略,缺失的附件默认会让构建失败。
|
|
148
150
|
常见凭据文件(如 `.env`、私钥和证书容器)属于公共安全阻断项,即使被误写进文档链接也不会进入静态产物。
|
|
149
151
|
静态生成 HTML 时,可再调用 `rewriteDocumentAttachmentUrls`,将正文中的附件链接统一改写到 `/doc-asset/` 端点。
|
|
152
|
+
正文中的附件链接使用浏览器完整导航;独立 HTML 页面保持自己的样式和脚本,不进入 Markdown 局部刷新流程,挂载在子路径时也遵循这一规则。
|
|
150
153
|
|
|
151
154
|
## 开发
|
|
152
155
|
|
package/dist/server.js
CHANGED
|
@@ -719,7 +719,10 @@ async function resolveDocPath(requestedPath) {
|
|
|
719
719
|
if (await storageFileExists(resolvedPath)) {
|
|
720
720
|
return { resolvedPath };
|
|
721
721
|
}
|
|
722
|
-
|
|
722
|
+
// A document may have moved into a subdirectory during catalog cleanup.
|
|
723
|
+
// Resolve only an unambiguous filename inside its original directory.
|
|
724
|
+
const movedPath = await findFileInTree(resolvedDirPath, fileName);
|
|
725
|
+
return movedPath ? { resolvedPath: movedPath } : null;
|
|
723
726
|
}
|
|
724
727
|
// 如果只是文件名,尝试在整个文档目录中查找
|
|
725
728
|
try {
|
|
@@ -733,29 +736,32 @@ async function resolveDocPath(requestedPath) {
|
|
|
733
736
|
}
|
|
734
737
|
return null;
|
|
735
738
|
}
|
|
736
|
-
//
|
|
737
|
-
async function findFileInTree(dir, fileName
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
const entries = await storageReadDir(
|
|
739
|
+
// Find one exact filename; ambiguity or an unreadable subtree must not redirect.
|
|
740
|
+
async function findFileInTree(dir, fileName) {
|
|
741
|
+
const matches = [];
|
|
742
|
+
async function visit(basePath) {
|
|
743
|
+
const entries = await storageReadDir(basePath);
|
|
741
744
|
for (const entry of entries) {
|
|
742
745
|
if (entry.name.startsWith('.'))
|
|
743
746
|
continue;
|
|
744
|
-
const relativePath = joinDocPath(
|
|
747
|
+
const relativePath = joinDocPath(basePath, entry.name);
|
|
745
748
|
if (entry.isDirectory) {
|
|
746
|
-
|
|
747
|
-
if (found)
|
|
748
|
-
return found;
|
|
749
|
+
await visit(relativePath);
|
|
749
750
|
}
|
|
750
751
|
else if (entry.isFile && entry.name === fileName && entry.name.endsWith('.md')) {
|
|
751
|
-
|
|
752
|
+
matches.push(relativePath);
|
|
752
753
|
}
|
|
754
|
+
if (matches.length > 1)
|
|
755
|
+
return;
|
|
753
756
|
}
|
|
754
757
|
}
|
|
758
|
+
try {
|
|
759
|
+
await visit(dir || '');
|
|
760
|
+
}
|
|
755
761
|
catch (e) {
|
|
756
|
-
|
|
762
|
+
return null;
|
|
757
763
|
}
|
|
758
|
-
return null;
|
|
764
|
+
return matches.length === 1 ? matches[0] : null;
|
|
759
765
|
}
|
|
760
766
|
// 构建面包屑:基于文档路径
|
|
761
767
|
async function buildBreadcrumbs(docPath) {
|
package/package.json
CHANGED
package/server/views/doc.ejs
CHANGED
|
@@ -294,6 +294,15 @@
|
|
|
294
294
|
// 检查是否是文档系统内的链接
|
|
295
295
|
const href = link.getAttribute('href');
|
|
296
296
|
if (!href) return;
|
|
297
|
+
|
|
298
|
+
// Assets, including standalone HTML pages, need full browser navigation;
|
|
299
|
+
// they do not contain the Markdown article expected by navigateToDoc.
|
|
300
|
+
try {
|
|
301
|
+
const linkUrl = new URL(href, document.baseURI || window.location.href);
|
|
302
|
+
if (/(^|\/)doc-asset\//.test(linkUrl.pathname)) return;
|
|
303
|
+
} catch (_) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
297
306
|
|
|
298
307
|
// 判断是否是文档系统内的链接(排除外部链接、锚点、目录页链接)
|
|
299
308
|
const isDocLink = (href.startsWith('/doc?') ||
|