oceanpress 1.0.10 → 1.0.12

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 CHANGED
@@ -81,3 +81,8 @@ OceanPress 使用 JSON 格式的配置文件来定义站点的基本信息和构
81
81
  - Hono
82
82
  - Effect
83
83
  - Commander.js
84
+
85
+
86
+ ## 开发相关
87
+
88
+ 可以使用 claude 执行 /full-release 命令自动更新依赖并推送npm
package/dist-cli/cli.js CHANGED
@@ -77,7 +77,7 @@ import { computed, reactive, watch } from "vue";
77
77
  // package.json
78
78
  var package_default = {
79
79
  name: "oceanpress",
80
- version: "1.0.9",
80
+ version: "1.0.10",
81
81
  type: "module",
82
82
  scripts: {
83
83
  dev: "vite",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/deploy.ts","../../rpc/src/createRPC.ts","../src/core/config.ts","../package.json","../src/util/deep_assign.ts","../src/core/EffectDep.ts","../src/core/genZip.ts","../src/plugins/meilisearch_plugin/meilisearch_upload.ts","../src/plugins/publish/OceanPressServer.ts","../src/plugins/publish/s3.ts","../src/core/build.ts","../src/components/data_promise/index.ts","../src/core/siyuan_api.ts","../src/core/siyuan_type.ts","../src/core/cache.ts","../src/core/genRssXml.ts","../src/core/seo.ts","../src/core/htmlTemplate.ts","../src/core/render.ts","../src/util/escaping.ts","../src/core/renderDocTree.ts","../src/core/plugin.ts","../src/core/ocean_press.ts","../src/core/render.api.dep.ts","../src/util/store.node.dep.ts","../src/cli/common.ts","../src/cli/build.ts","../src/cli/server.ts","../src/server.ts","../src/core/hono_server.ts","../src/cli.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { createRPC } from 'oceanpress-rpc'\nimport type { API } from 'oceanpress-server'\nimport { stringify } from 'superjson'\nimport { currentConfig, loadConfigFile } from '~/core/config.ts'\nimport { genZIP } from '~/core/genZip.ts'\nimport { OceanPress } from '~/core/ocean_press.ts'\nimport { program } from './common.ts'\nimport { Context, Effect } from 'effect'\nimport {\n EffectRender,\n EffectLocalStorageDep,\n EffectLogDep,\n EffectConfigDep,\n} from '~/core/EffectDep.ts'\nimport { renderApiDep } from '~/core/render.api.dep.ts'\nimport { nodeApiDep } from '~/util/store.node.dep.ts'\n\nprogram\n .command('deploy')\n .description('部署站点')\n .option('-c, --config <string>', '指定配置文件的位置')\n .option('-h, --apiBase <string>', 'OceanPress server 地址')\n .option('-k, --apiKey <string>', 'OceanPress server Api 密钥')\n .action(async (opt: { config: string; apiBase: string; apiKey: string }) => {\n if (!opt.apiBase || !opt.apiKey) {\n return console.error(`请配置 apiBase 和 apiKey`)\n }\n const config = await readFile(opt.config, 'utf-8')\n\n const client = await createRPC<API>('apiConsumer', {\n remoteCall(method, data) {\n let body: ReadableStream | string\n // 如果第一参数是 ReadableStream 的时候,直接使用 ReadableStream 作为 body,不用考虑其他参数,因为这种情况只支持一个参数\n let content_type\n if (data[0] instanceof ReadableStream) {\n body = data[0]\n content_type = 'application/octet-stream'\n } else {\n body = stringify(data)\n console.log('[body]', body)\n content_type = 'application/json'\n }\n return fetch(`${opt.apiBase}/api/${method}`, {\n method: 'POST',\n body,\n headers: {\n 'x-api-key': opt.apiKey,\n 'Content-Type': content_type,\n },\n // @ts-expect-error 在 node 运行的时候需要声明双工模式才能正确发送 ReadableStream,TODO 需要验证浏览器端可以这样运行吗\n duplex: 'half', // 关键:显式声明半双工模式\n })\n .then((res) => res.json())\n .then((r) => {\n if (r.error) {\n console.log('[r]', r)\n throw new Error()\n }\n return r.result\n })\n },\n })\n\n const context = Context.empty().pipe(\n Context.add(EffectRender, renderApiDep),\n Context.add(EffectLocalStorageDep, nodeApiDep),\n Context.add(EffectConfigDep, currentConfig.value),\n Context.add(EffectLogDep, {\n log: (msg) => {\n if (msg.startsWith('渲染:')) {\n process.stdout.write(`\\r\\x1b[K${msg}`)\n } else {\n process.stdout.write(`\\n${msg}`)\n }\n },\n percentage: (n) => {\n process.stdout.write(`\\r\\x1b[K进度:${n}%`)\n },\n }),\n )\n const p = Effect.provide(\n Effect.gen(function* () {\n yield* loadConfigFile(JSON.parse(config))\n const ocean_press = new OceanPress(currentConfig.value)\n\n ocean_press.pluginCenter.registerPlugin({\n async build_onFileTree([tree], next) {\n const zip = await genZIP(tree, { withoutZip: true })\n const sizeInMB = zip.size / (1024 * 1024)\n console.log('[zip.size in MB]', sizeInMB.toFixed(2))\n // 将 Blob 转换为 ReadableStream\n const readableStream = zip.stream()\n const { chunkCount, fileId } = await client.API.upload(\n readableStream,\n )\n\n console.log('[res]', { chunkCount, fileId })\n const res = await client.API.deploy({ zipFileId: fileId })\n console.log('[deploy res]', res)\n },\n })\n\n return yield* ocean_press.build()\n }),\n context,\n )\n\n await Effect.runPromise(p)\n })\n","/** ═════════🏳‍🌈 超轻量级的远程调用,完备的类型提示! 🏳‍🌈═════════ */\n\ninterface commonOptions {\n middleware?: ((method: string, data: any[], next: () => Promise<any>) => Promise<any>)[]; // 统一的中间件\n}\n\nexport async function createRPC<API_TYPE>(\n ...[type, options]:\n | [\n 'apiProvider',\n commonOptions & {\n genApiModule: () => Promise<API_TYPE>;\n },\n ]\n | [\n 'apiConsumer',\n commonOptions & {\n /** 配置此选项替换默认的远程调用函数,默认逻辑采用 fetch 实现。 */\n remoteCall: (method: string, data: any[]) => Promise<any>; // 远程调用函数\n },\n ]\n) {\n const apiModule = type === 'apiProvider' ? await options.genApiModule() : undefined;\n\n const remoteCall = type === 'apiConsumer' ? options.remoteCall : undefined;\n\n async function RC<K extends string>(method: K, data: any[]): Promise<any> {\n // 洋葱路由的核心逻辑\n async function executeMiddleware(index: number): Promise<any> {\n if (options.middleware && index < options.middleware.length) {\n return options.middleware[index](method, data, () => executeMiddleware(index + 1));\n } else {\n return executeCall();\n }\n }\n\n async function executeCall(): Promise<any> {\n try {\n if (type === 'apiProvider') {\n const methodParts = method.split('.');\n let currentObj: any = apiModule;\n for (const part of methodParts) {\n if (currentObj && typeof currentObj === 'object' && part in currentObj) {\n currentObj = currentObj[part];\n } else {\n throw new Error(`Method ${method} not found`);\n }\n }\n if (typeof currentObj === 'function') {\n return await currentObj(...data);\n } else {\n throw new Error(`${method} is not a function`);\n }\n } else {\n return await remoteCall!(method, data);\n }\n } catch (error) {\n console.error('API call failed:', error);\n throw error;\n }\n }\n\n return await executeMiddleware(0);\n }\n\n /** Remote call , 会就近的选择是远程调用还是使用本地函数 */\n\n /** 创建嵌套的Proxy处理器 */\n function createNestedProxy(path: string[] = []): ProxyHandler<object> {\n return {\n get(target, prop: string) {\n if (prop === 'then') {\n // Handle the case when the proxy is accidentally treated as a Promise\n return undefined;\n }\n const newPath = [...path, prop];\n return new Proxy(function (...args: any[]) {\n const method = newPath.join('.');\n return RC(method, args);\n }, createNestedProxy(newPath));\n },\n apply(target, thisArg, args) {\n const method = path.join('.');\n return RC(method, args);\n },\n };\n }\n /** 包装了一次的 RC 方便跳转到函数定义 */\n const API = new Proxy(function () {}, createNestedProxy()) as unknown as NestedAsyncAPI<API_TYPE>;\n return { API, RC };\n}\n\ntype AsyncifyReturnType<T> = T extends (...args: any[]) => infer R\n ? R extends Promise<any>\n ? T\n : (...args: Parameters<T>) => Promise<Awaited<R>>\n : T;\n\ntype DeepAsyncify<T> = T extends (...args: any[]) => any\n ? AsyncifyReturnType<T>\n : T extends object\n ? { [K in keyof T]: DeepAsyncify<T[K]> }\n : T;\n/** 因为如果是客户端调用,那么返回值必须要是 promise 风格的,所以使用这个类型来将所有返回值的类型包裹一层promise */\ntype NestedAsyncAPI<T> = {\n [K in keyof T]: DeepAsyncify<T[K]>;\n};\n","import { Effect } from 'effect';\r\nimport { computed, reactive, watch } from 'vue';\r\nimport packageJson from '~/../package.json' with { type: 'json' };\r\nimport { deepAssign } from '~/util/deep_assign.ts';\r\nimport { EffectLocalStorageDep } from './EffectDep.ts';\r\nimport { notebook } from './siyuan_type.ts';\r\nconst version = packageJson.version\r\nconsole.log('[version]',version);\r\n/** 不要在运行时修改这个对象,他只应该在代码中配置 */\r\nconst defaultConfig = {\r\n name: 'default',\r\n /** 需要编译的笔记本 */\r\n notebook: {} as notebook,\r\n /** 思源的鉴权key */\r\n authorized: '',\r\n /** 思源的api服务地址 */\r\n apiPrefix: 'http://127.0.0.1:6806',\r\n /** 打包成 zip */\r\n compressedZip: true,\r\n /** 不将 publicZip 打包到 zip 包中 */\r\n // withoutPublicZip: true,\r\n /** 不复制 assets/ ,勾选此选项则需要自行处理资源文件 */\r\n excludeAssetsCopy: false,\r\n /** 输出站点地图相关 */\r\n sitemap: {\r\n /** 控制是否输出 sitemap.xml,不影响 rss 选项 */\r\n enable: true,\r\n /** 默认为 \".\" 生成路径例如 \"./record/思源笔记.html\"\r\n * 但 sitemap 并不建议采用相对路径所以应该替换成例如 \"https://shenzilong.cn\"\r\n * 则会生成 \"https://shenzilong.cn/record/思源笔记.html\" 这样的绝对路径\r\n * 参见 https://www.sitemaps.org/protocol.html#escaping\r\n */\r\n sitePrefix: '.',\r\n /** 站点地址 */\r\n siteLink: '',\r\n /** 站点描述 */\r\n description: '',\r\n /** 站点标题 */\r\n title: '',\r\n /** 开启 rss 生成,对于文件名为 .rss.xml 结尾的文档生效 */\r\n rss: true,\r\n },\r\n /** 开启增量编译,当开启增量编译时,\r\n * 在编译过程中会依据 __skipBuilds__ 的内容来跳过一些没有变化不需要重新输出的内容\r\n */\r\n enableIncrementalCompilation: false,\r\n /**\r\n * 要全量编译文档时将此选项设置为false,当OceanPress版本和上次编译时不同时会忽略此属性全量编译文档\r\n */\r\n enableIncrementalCompilation_doc: true,\r\n /** 跳过编译的资源 */\r\n __skipBuilds__: {} as {\r\n [id: string]:\r\n | {\r\n hash?: string\r\n /** 此文档正向引用的其他文档的id */ refs?: string[]\r\n /** 挂件快照的更新时间 */ updated?: string\r\n }\r\n | undefined\r\n },\r\n\r\n // cdn: {\r\n // /** 思源 js、css等文件的前缀 */\r\n // siyuanPrefix:\r\n // 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@v0.0.7/apps/frontend/public/notebook/',\r\n // /** 思源 js、css等文件zip包地址 */\r\n // publicZip:\r\n // 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@v0.0.7/apps/frontend/public/public.zip',\r\n // },\r\n /** 部署到 s3 上传配置\r\n * https://help.aliyun.com/zh/oss/developer-reference/use-amazon-s3-sdks-to-access-oss#section-2ri-suq-pb3\r\n */\r\n s3: {\r\n enable: false,\r\n bucket: '',\r\n region: '',\r\n pathPrefix: '',\r\n endpoint: '',\r\n accessKeyId: '',\r\n secretAccessKey: '',\r\n },\r\n /** 部署到 oceanPressServer 的配置 */\r\n oceanPressServer:{\r\n enable: false,\r\n apiBase:'',\r\n apiKey:'',\r\n },\r\n meilisearch: {\r\n enable: false,\r\n host: '',\r\n apiKey: '',\r\n indexName: '',\r\n },\r\n /** html模板嵌入代码块,会将此处配置中的代码嵌入到生成的html所对应的位置 */\r\n embedCode: {\r\n head: '',\r\n beforeBody: '',\r\n afterBody: `<footer>\r\n<p style=\"text-align:center;margin:15px 0;\">\r\n 技术支持:\r\n <a target=\"_blank\" href=\"https://github.com/2234839/oceanPress_js\">OceanPress</a> |\r\n 开发者:\r\n <a target=\"_blank\" href=\"https://shenzilong.cn\">崮生(子虚)</a>\r\n</p>\r\n</footer>`,\r\n },\r\n /** 侧边栏配置 */\r\n sidebarCode:{\r\n /** 启用文档树,则 leftCode 将插入在文档树上方 */\r\n enableDocTree:true,\r\n /** 将插入主文档的左侧div中的html代码 */\r\n leftCode: '',\r\n /** 将插入主文档的右侧div中的html代码 */\r\n rightCode: '',\r\n },\r\n OceanPress: {\r\n /** 此配置文件编译时的版本 */\r\n version: version,\r\n },\r\n}\r\nexport type Config = typeof defaultConfig\r\nexport const configs = reactive({\r\n /** 当前所使用的配置项的 key */\r\n __current__: 'default' as const,\r\n /** 为true是表示是代码中设置的默认值,不会保存到本地,避免覆盖之前保存的数据,在加载本地配置后会自动修改为false */\r\n __init__: true,\r\n default: deepAssign<typeof defaultConfig>({}, defaultConfig),\r\n})\r\n\r\nexport function addConfig(name: string, value?: typeof defaultConfig) {\r\n configs[name as 'default'] = deepAssign<typeof defaultConfig>(\r\n {},\r\n value ?? defaultConfig,\r\n )\r\n}\r\n/** 加载配置文件到全局 config 单例中 */\r\nexport const loadConfigFile = (c?: typeof configs) => {\r\n return Effect.gen(function*(){\r\n const effectDep = yield* EffectLocalStorageDep\r\n if (c) {\r\n deepAssign(configs, c)\r\n\r\n } else {\r\n const localConfig = effectDep.getItem('configs')\r\n if (localConfig) {\r\n /** 从本地存储加载配置 */\r\n deepAssign(configs, JSON.parse(localConfig))\r\n }\r\n }\r\n\r\n Object.entries(configs)\r\n .filter(([key]) => key.startsWith('__') === false)\r\n .forEach(([_key, obj]) => {\r\n /** 将新增配置项更新到旧配置上 */\r\n deepAssign(obj, defaultConfig, { update: false, add: true })\r\n })\r\n\r\n // 自动更新配置文件到本地存储\r\n const saveConfig = () => {\r\n if (configs.__init__ === false)\r\n effectDep.setItem('configs', JSON.stringify(configs, null, 2))\r\n }\r\n\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n /** 防抖的保存配置 */\r\n const debounceSaveConfig = () => {\r\n if (timer) {\r\n clearTimeout(timer)\r\n }\r\n timer = setTimeout(() => {\r\n saveConfig()\r\n timer = null\r\n }, 700)\r\n }\r\n watch(configs, debounceSaveConfig, { deep: true })\r\n\r\n return configs\r\n })\r\n\r\n}\r\nexport const currentConfig = computed(() => configs[configs.__current__])\r\n\r\n/** 应该要给用户配置的,但目前没有什么好方法,所以暂时不给配置 */\r\nexport const tempConfig = {\r\n cdn: {\r\n /** 思源 js、css等文件的前缀 */\r\n siyuanPrefix:\r\n `https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@${version}/apps/frontend/public/notebook/`,\r\n // 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@latest/apps/frontend/public/notebook/',\r\n /** 思源 js、css等文件zip包地址 */\r\n publicZip:\r\n 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@v0.0.7/apps/frontend/public/public.zip',\r\n },\r\n withoutPublicZip:true,\r\n}\r\n\r\n\r\nconfigs.__init__ = false\r\n","{\n \"name\": \"oceanpress\",\n \"version\": \"1.0.9\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"cli\": \"tsx ./src/cli.ts\",\n \"cli-w\": \"tsx watch ./src/cli.ts\",\n \"build\": \"vite build && npm run build_lib\",\n \"build_lib\": \"vite build --config vite.sw.config.ts\",\n \"build_app\": \"vite build --mode library\",\n \"build_cli\": \"tsup\",\n \"build_plugin_ui\": \"vite build --config vite.plugin.config.ts\",\n \"dev_plugin_ui\": \"vite build --watch --config vite.plugin.config.ts\",\n \"preview\": \"vite preview\"\n },\n \"bin\": {\n \"oceanpress\": \"./dist-cli/cli.js\"\n },\n \"files\": [\n \"dist/assets\",\n \"dist/dev\",\n \"dist/index.html\",\n \"dist/ocean_press-log.png\",\n \"dist-app/assets\",\n \"dist-app/dev\",\n \"dist-app/app.*\",\n \"dist-cli\",\n \"*.md\"\n ],\n \"dependencies\": {\n \"@aws-sdk/client-s3\": \"^3.873.0\",\n \"@hono/node-server\": \"^1.19.0\",\n \"cheerio\": \"1.1.2\",\n \"commander\": \"^14.0.0\",\n \"effect\": \"^3.17.8\",\n \"fzstd\": \"^0.1.1\",\n \"hono\": \"^4.9.4\",\n \"jszip\": \"^3.10.1\",\n \"meilisearch\": \"^0.52.0\",\n \"naive-ui\": \"^2.42.0\",\n \"octokit\": \"^5.0.3\",\n \"superjson\": \"^2.2.2\",\n \"tsx\": \"^4.20.4\",\n \"vditor\": \"^3.11.1\",\n \"vue\": \"^3.5.19\",\n \"vue-router\": \"^4.5.1\",\n \"zstd-codec\": \"^0.1.5\"\n },\n \"devDependencies\": {\n \"@vitejs/plugin-vue\": \"^6.0.1\",\n \"@vitejs/plugin-vue-jsx\": \"^5.0.1\",\n \"dependency-cruiser\": \"^17.0.1\",\n \"oceanpress-rpc\": \"workspace:*\",\n \"oceanpress-server\": \"workspace:*\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.2\",\n \"vite\": \"^7.1.3\",\n \"vite-plugin-vue-devtools\": \"^8.0.0\",\n \"vue-tsc\": \"^3.0.6\"\n }\n}","export function deepAssign<T>(target: any, source: any, config = { add: true, update: true }): T {\r\n for (let key in source) {\r\n if (source.hasOwnProperty(key)) {\r\n if (source[key] instanceof Object && !Array.isArray(source[key])) {\r\n // 如果属性是对象且不是数组,则递归执行深度合并\r\n if (!target.hasOwnProperty(key)) {\r\n // 目标对象不存在该属性则创建空对象\r\n target[key] = {};\r\n }\r\n deepAssign(target[key], source[key], config);\r\n } else {\r\n // 如果属性不是对象或者是数组,则直接赋值\r\n if (!target.hasOwnProperty(key) && config.add) {\r\n // 目标属性不存在属于新增\r\n target[key] = source[key];\r\n } else if (config.update) {\r\n // 更新\r\n target[key] = source[key];\r\n }\r\n }\r\n }\r\n }\r\n return target;\r\n }\r\n","import { Context } from 'effect'\nimport type { S_Node } from './siyuan_type.ts'\nimport type { Config } from './config.ts'\n\nexport type EffectRenderApi = {\n // 渲染相关\n getNodeByID: (id?: string) => Promise<S_Node | undefined>\n getDocPathBySY: (sy?: S_Node) => Promise<string | undefined>\n getDocByChildID: (id: string) => Promise<S_Node | undefined>\n getHPathByID_Node: (id_node: string | S_Node) => Promise<string>\n}\nexport class EffectRender extends Context.Tag('EffectDep')<\n EffectRender,\n EffectRenderApi\n>() {}\n\n// 读写配置文件所依赖的副作用\nexport type effectLocalStorage = {\n setItem: (key: string, value: string) => void\n getItem: (key: string) => string | undefined\n}\n\nexport class EffectLocalStorageDep extends Context.Tag('EffectLocalStorageDep')<\n EffectLocalStorageDep,\n effectLocalStorage\n>() {}\n\n// 读写配置文件所依赖的副作用\nexport type effectLog = {\n // 进度输出相关\n log: (msg: string) => void\n percentage: (_n: number) => void\n}\n\nexport class EffectLogDep extends Context.Tag('EffectLogDep')<\n EffectLogDep,\n effectLog\n>() {}\n\nexport class EffectConfigDep extends Context.Tag('EffectConfigDep')<\n EffectConfigDep,\n Config\n>() {}\n","import JSZip from 'jszip'\n\n/** 下载zip */\nexport async function downloadZIP(\n docTree: { [htmlPath: string]: string | ArrayBuffer },\n config?: { publicZip?: string; withoutZip?: boolean },\n) {\n const content = await genZIP(docTree, config)\n if (globalThis.document) {\n // 将ZIP文件保存为下载\n const link = document.createElement('a')\n link.href = URL.createObjectURL(content)\n link.download = `notebook.zip`\n link.click()\n } else {\n //TODO node 环境下需要写文件\n }\n}\n\nexport async function genZIP(\n docTree: { [htmlPath: string]: string | ArrayBuffer },\n config?: {\n /** 默认的public.zip压缩包内容路径,默认为/public.zip */\n publicZip?: string\n /** 是否不包含默认的public.zip压缩包内容,设置为 true 则会不下载 public.zip 内容合并使用 */\n withoutZip?: boolean\n },\n) {\n const zip = new JSZip()\n if (config?.withoutZip !== true) {\n const presetZip = await (\n await fetch(config?.publicZip ?? '/public.zip')\n ).arrayBuffer()\n await zip.loadAsync(presetZip)\n }\n for (const [path, html] of Object.entries(docTree)) {\n const newPath = path.startsWith('/') ? path.slice(1) : path\n zip.file(newPath, html)\n }\n return await zip.generateAsync({ type: 'blob' })\n}\n","import { Meilisearch, Index } from 'meilisearch'\r\nimport { OceanPressPlugin } from '~/core/ocean_press.ts'\r\nimport { load } from 'cheerio'\r\ntype doc = {\r\n id: string\r\n title?: string\r\n content: string\r\n url: string\r\n lvl0?: string\r\n lvl1?: string\r\n lvl2?: string\r\n lvl3?: string\r\n lvl4?: string\r\n lvl5?: string\r\n lvl6?: string\r\n}\r\nexport class MeilisearchPlugin implements OceanPressPlugin {\r\n _melisearch: Meilisearch | undefined\r\n _index: Index | undefined\r\n _indexName: string\r\n host: string\r\n apiKey: string\r\n constructor(option: { host: string; apiKey: string; indexName: string }) {\r\n this.host = option.host\r\n this.apiKey = option.apiKey\r\n this._indexName = option.indexName\r\n }\r\n async _getMeliSearch() {\r\n if (this._melisearch === undefined) {\r\n this._melisearch = new Meilisearch({\r\n host: this.host,\r\n apiKey: this.apiKey,\r\n })\r\n }\r\n return this._melisearch!\r\n }\r\n async _getIndex() {\r\n if (this._index === undefined) {\r\n const meilisearch = await this._getMeliSearch()\r\n this._index = meilisearch.index(this._indexName)\r\n }\r\n return this._index!\r\n }\r\n docs: { [id: string]: doc } = {}\r\n async addDocument(doc: doc) {\r\n this.docs[doc.id] = doc\r\n }\r\n async updateDocument() {\r\n console.log(`开始上传数据到 ${this.host}`)\r\n const index = await this._getIndex()\r\n const res = await index.addDocuments(Object.values(this.docs))\r\n console.log(`上传结果`, res)\r\n }\r\n build_onFileTree: OceanPressPlugin['build_onFileTree'] = (c, next) => {\r\n const [tree] = c\r\n console.log('开始生成 meilisearch 所需数据结构')\r\n\r\n const htmlTree = Object.keys(tree)\r\n .filter((path) => path.endsWith('.html'))\r\n .map((path) => [path, tree[path]] as const)\r\n for (const [path, html] of htmlTree) {\r\n const $ = load(html.toString())\r\n const entries = $('.h1,.h2,.h3,.h4,.h5,.h6,.p').toArray()\r\n const level: Record<string, string> = { lvl0: $('title').text() }\r\n for (const el of entries) {\r\n /** h1~h6、p */\r\n const c = el.attribs.class\r\n if (c !== 'p') {\r\n Object.keys(level).forEach((lv) => {\r\n if (lv.substring(3, 4) > c.substring(1, 2)) {\r\n /** 跳出层级 */\r\n delete level[lv]\r\n }\r\n })\r\n /** 进入层级 */\r\n level[`lvl${c.substring(1, 2)}`] = $(el).text()\r\n }\r\n this.addDocument({\r\n id: el.attribs.id,\r\n content: $(el).text(),\r\n url: `${path}#${el.attribs.id}`,\r\n ...level,\r\n })\r\n }\r\n\r\n if (path.endsWith('index.html')) break\r\n }\r\n this.updateDocument()\r\n return next(...c)\r\n }\r\n}\r\n","import { createRPC } from 'oceanpress-rpc'\r\nimport type { API } from 'oceanpress-server'\r\nimport { stringify } from 'superjson'\r\nimport { type Config } from '~/core/config.ts'\r\nimport { genZIP } from '~/core/genZip.ts'\r\nimport type { OceanPressPlugin } from '~/core/ocean_press.ts'\r\n\r\n/** 上传数据到 OceanPressServer 适配云端 */\r\nexport function deployOceanPressServer_plugin(config: Config) {\r\n const plugin: OceanPressPlugin = {\r\n async build_onFileTree([tree,effectApi], next) {\r\n next(tree,effectApi)\r\n const client = await createRPC<API>('apiConsumer', {\r\n async remoteCall(method, data) {\r\n let body: ReadableStream | string | Blob\r\n // 如果第一参数是 ReadableStream 的时候,直接使用 ReadableStream 作为 body,不用考虑其他参数,因为这种情况只支持一个参数\r\n let content_type\r\n if (data[0] instanceof ReadableStream) {\r\n // body = data[0] //会遇到一些兼容性问题, http 1.1 不支持使用流作为 body,需要转换为 blob 或者 arraybuffer\r\n\r\n body = await new Response(data[0]).blob()\r\n content_type = 'application/octet-stream'\r\n } else {\r\n body = stringify(data)\r\n console.log('[body]', body)\r\n content_type = 'application/json'\r\n }\r\n return fetch(`${config.oceanPressServer.apiBase}/api/${method}`, {\r\n method: 'POST',\r\n body,\r\n headers: {\r\n 'x-api-key': config.oceanPressServer.apiKey,\r\n 'Content-Type': content_type,\r\n },\r\n // @ts-expect-error 在 node 运行的时候需要声明双工模式才能正确发送 ReadableStream,TODO 需要验证浏览器端可以这样运行吗\r\n duplex: 'half', // 关键:显式声明半双工模式\r\n })\r\n .then((res) => res.json())\r\n .then((r) => {\r\n if (r.error) {\r\n console.log('[r]', r)\r\n throw new Error()\r\n }\r\n return r.result\r\n })\r\n },\r\n })\r\n const zip = await genZIP(tree, { withoutZip: true })\r\n const sizeInMB = zip.size / (1024 * 1024)\r\n console.log('[zip.size in MB]', sizeInMB.toFixed(2))\r\n // 将 Blob 转换为 ReadableStream\r\n const readableStream = zip.stream()\r\n const { chunkCount, fileId } = await client.API.upload(readableStream)\r\n\r\n console.log('[res]', { chunkCount, fileId })\r\n const res = await client.API.deploy({ zipFileId: fileId })\r\n console.log('[deploy res]', res)\r\n },\r\n }\r\n return plugin\r\n}\r\n","import { S3 } from '@aws-sdk/client-s3'\r\nimport type { OceanPressPlugin } from '~/core/ocean_press.ts'\r\nimport type { uploadFiles } from './interface.ts'\r\n\r\n/** 上传数据到 s3 适配云端 */\r\nexport const s3Upload_plugin: OceanPressPlugin = {\r\n build: function ([config, otherConfig], next) {\r\n return next(config, {\r\n ...otherConfig,\r\n\r\n onFileTree: async (tree, effectApi) => {\r\n if (otherConfig?.onFileTree) {\r\n // 维持原有其他监听程序\r\n await otherConfig.onFileTree(tree, effectApi)\r\n }\r\n for await (const [fileName, ETag] of s3_uploads(tree, config)) {\r\n effectApi.log(`上传: ${fileName} ${ETag}`)\r\n }\r\n effectApi.log(`s3 上传完毕`)\r\n },\r\n })\r\n },\r\n}\r\nconst s3_uploads: uploadFiles = async function* (tree, config) {\r\n // https://help.aliyun.com/zh/oss/developer-reference/use-amazon-s3-sdks-to-access-oss#section-2ri-suq-pb3\r\n\r\n const s3 = new S3({\r\n region: config.s3.region,\r\n endpoint: config.s3.endpoint,\r\n credentials: {\r\n accessKeyId: config.s3.accessKeyId,\r\n secretAccessKey: config.s3.secretAccessKey,\r\n },\r\n })\r\n // 将文件逐个上传至 s3\r\n // TODO 可改成并发上传,以缩短时间\r\n const encoder = new TextEncoder()\r\n for (const [path, value] of Object.entries(tree)) {\r\n let buffer: Uint8Array\r\n if (typeof value === 'string') {\r\n buffer = encoder.encode(value)\r\n } else {\r\n buffer = new Uint8Array(value)\r\n }\r\n const r = await s3.putObject({\r\n Bucket: config.s3.bucket,\r\n Key: (config.s3.pathPrefix + path).replace(/\\/\\//g, '/'),\r\n Body: buffer,\r\n })\r\n yield [path, r.ETag] as const\r\n }\r\n}\r\n","import { Effect } from 'effect'\r\nimport packageJson from '~/../package.json' with { type: 'json' }\r\nimport { Config, currentConfig, tempConfig } from '~/core/config.ts'\r\nimport { deepAssign } from '~/util/deep_assign.ts'\r\nimport {\r\n allDocBlock_by_bookId,\r\n get_doc_by_SyPath,\r\n get_node_by_id,\r\n} from './cache.ts'\r\nimport { EffectLogDep, EffectRender, type effectLog } from './EffectDep.ts'\r\nimport { generateRSSXML, sitemap_xml } from './genRssXml.ts'\r\nimport { downloadZIP } from './genZip.ts'\r\nimport { htmlTemplate } from './htmlTemplate.ts'\r\nimport { getRender, renderHTML } from './render.ts'\r\nimport { API } from './siyuan_api.ts'\r\nimport { DB_block, DB_block_path, S_Node } from './siyuan_type.ts'\r\nimport { renderDocTree, renderDocTreeJsPath } from './renderDocTree.ts'\r\n\r\n/**\r\n * 生成面包屑导航数据\r\n */\r\nfunction generateBreadcrumbs(path: string, config: any): Array<{ name: string; url: string }> {\r\n const breadcrumbs: Array<{ name: string; url: string }> = []\r\n \r\n // 添加首页\r\n if (config.sitemap?.siteLink) {\r\n breadcrumbs.push({\r\n name: config.sitemap?.title || '首页',\r\n url: config.sitemap.siteLink\r\n })\r\n }\r\n \r\n // 解析路径\r\n const pathSegments = path.split('/').filter(segment => segment.length > 0)\r\n \r\n let currentPath = ''\r\n for (const segment of pathSegments) {\r\n currentPath += '/' + segment\r\n breadcrumbs.push({\r\n name: segment,\r\n url: `${config.sitemap?.siteLink || ''}${currentPath}.html`\r\n })\r\n }\r\n \r\n return breadcrumbs\r\n}\r\n\r\nexport interface DocTree {\r\n [/** \"/计算机基础课/自述\" */ docPath: string]: {\r\n sy: S_Node\r\n docBlock: DB_block\r\n }\r\n}\r\nexport interface FileTree {\r\n [path: string]: string | ArrayBuffer\r\n}\r\nexport type Build = typeof build\r\n/** 根据配置文件进行编译\r\n * TODO 将浏览器写文件的部分抽离出去,也改成使用 onFileTree\r\n */\r\nexport function build (config:Config,otherConfig?: {\r\n // 监听文件准备完毕 TODO:应该修改实现,而非目前直接全量加载到内存\r\n onFileTree?: (tree: FileTree,effectApi:effectLog) => void\r\n renderHtmlFn?: typeof renderHTML\r\n},){\r\n return Effect.gen(function*(){\r\n const effectApi = yield* EffectRender\r\n const effectLog = yield* EffectLogDep\r\n\r\n const _renderHTML = otherConfig?.renderHtmlFn ?? renderHTML\r\n const book = config.notebook\r\n const docTree: DocTree = {}\r\n const skipBuilds = useSkipBuilds()\r\n\r\n let oldPercentage = 0\r\n let total = 0\r\n /** 较为精准的估计进度 */\r\n function processPercentage(\r\n /** 0~1 的小数 表示这个数占整体百分之多少 */ percentage: number,\r\n ) {\r\n total += oldPercentage\r\n return (/** 0~1 的小数 */ process: number) => {\r\n oldPercentage = process * percentage\r\n effectLog.percentage((total + oldPercentage) * 100)\r\n }\r\n }\r\n effectLog.log( `=== 开始编译 ${book.name} ===`)\r\n let process = processPercentage(0.4)\r\n /** 查询所有文档级block\r\n * TODO 增量编译时不应该全部获取\r\n */\r\n const Doc_blocks: DB_block[] = yield* Effect.tryPromise(()=>allDocBlock_by_bookId(book.id))\r\n /** docBlock 的引用没有更新:true */\r\n function refsNotUpdated(docBlock: DB_block): boolean {\r\n const refs = config.__skipBuilds__[docBlock.id]?.refs ?? []\r\n for (const ref_id of refs) {\r\n const new_doc_hash = Doc_blocks.find(\r\n (docBlock) => docBlock.id === ref_id,\r\n )?.hash\r\n const old_doc_hash = config.__skipBuilds__[ref_id]?.hash\r\n if (new_doc_hash === undefined || old_doc_hash === undefined) {\r\n /** 不应该进入此分支的,如果进来了就重新编译吧 */\r\n return false\r\n } else if (new_doc_hash === old_doc_hash) {\r\n continue\r\n } else {\r\n return false\r\n }\r\n }\r\n /** 引用的都没有更新 */\r\n return true\r\n }\r\n effectLog.log (`=== 查询文档级block完成 ===`)\r\n let i = 0\r\n yield* Effect.tryPromise(()=>Promise.all(\r\n Doc_blocks.map(async (docBlock) => {\r\n const sy = await get_doc_by_SyPath(DB_block_path(docBlock))\r\n docTree[docBlock.hpath] = { sy, docBlock }\r\n i++\r\n process(i / Doc_blocks.length)\r\n }),\r\n ))\r\n const fileTree: FileTree = {}\r\n\r\n process = processPercentage(0.4)\r\n\r\n const enableIncrementalCompilation_doc = (() => {\r\n if (packageJson.version !== config.OceanPress.version) {\r\n effectLog.log(\r\n `配置文件版本号[${config.OceanPress.version}]与OceanPress版本[${packageJson.version}]不一致,将进行文档全量编译`,\r\n )\r\n return false\r\n }\r\n return config.enableIncrementalCompilation_doc\r\n })()\r\n effectLog.log (`=== 开始渲染文档 ===`)\r\n\r\n yield* Effect.forEach(Object.entries(docTree), ([path, { sy, docBlock }]) => {\r\n return Effect.gen(function*(){\r\n if (\r\n config.enableIncrementalCompilation &&\r\n enableIncrementalCompilation_doc &&\r\n /** 文档本身没有发生变化 */\r\n config.__skipBuilds__[docBlock.id]?.hash === docBlock.hash &&\r\n /** docBlock所引用的文档也没有更新 */\r\n refsNotUpdated(docBlock)\r\n ){\r\n return '/** skip */'\r\n }\r\n const renderInstance = yield* getRender\r\n try {\r\n const rootLevel = path.split('/').length - 2 /** 最开头有一个 / 还有一个 data 目录所以减二 */\r\n const htmlContent = yield* _renderHTML(sy, renderInstance)\r\n\r\n const pageUrl = config.sitemap.siteLink \r\n ? `${config.sitemap.siteLink}${path}.html`\r\n : `${path}.html`\r\n \r\n fileTree[path + '.html'] = yield* Effect.tryPromise( ()=>htmlTemplate(\r\n {\r\n title: sy.Properties?.title || '',\r\n htmlContent,\r\n level: rootLevel,\r\n seoData: {\r\n doc: sy,\r\n config: config,\r\n pageUrl: pageUrl,\r\n breadcrumbs: generateBreadcrumbs(path, config)\r\n },\r\n },\r\n {\r\n ...tempConfig.cdn,\r\n embedCode: config.embedCode,\r\n },\r\n ))\r\n /** rss.xml 生成 */\r\n if (config.sitemap.rss && path.endsWith('.rss.xml')) {\r\n const rssPath = path\r\n fileTree[rssPath] =yield* Effect.tryPromise(()=> generateRSSXML(rssPath, renderInstance, config,effectApi.getHPathByID_Node))\r\n effectLog.log(`渲染 rss.xml:${rssPath} 完毕`)\r\n }\r\n if (\r\n config.enableIncrementalCompilation &&\r\n config.enableIncrementalCompilation_doc\r\n ) {\r\n /** 更新为当前hash */\r\n skipBuilds.add(docBlock.id, {\r\n hash: docBlock.hash,\r\n })\r\n }\r\n /** 无论是否配置增量更新都要更新正向引用,不然开启增量更新后没有引用数据可用 */\r\n skipBuilds.add(docBlock.id, {\r\n refs: /** 保存引用 */ [...renderInstance.refs.values()],\r\n })\r\n effectLog.log(`渲染完毕:${path}`)\r\n } catch (error) {\r\n effectLog.log(`${path} 渲染失败:${error}`)\r\n console.log(error)\r\n }\r\n process(i / Doc_blocks.length)\r\n return `渲染完毕:${path}`\r\n })\r\n\r\n\r\n\r\n })\r\n\r\n effectLog.log( `=== 渲染文档完成 ===`)\r\n effectLog.log( `=== 开始生成 sitemap.xml ===`)\r\n if (config.sitemap.enable) {\r\n fileTree['sitemap.xml'] = sitemap_xml(Doc_blocks, config.sitemap)\r\n }\r\n if (config.excludeAssetsCopy === false) {\r\n effectLog.log( `=== 开始复制资源文件 ===`)\r\n const assets: {\r\n box: string\r\n docpath: string\r\n path: string\r\n hash: string\r\n id: string\r\n }[] = yield* Effect.tryPromise( ()=>API.query_sql({\r\n stmt: `SELECT * from assets\r\n WHERE box = '${book.id}'\r\n limit 150000 OFFSET 0`,\r\n }))\r\n yield* Effect.tryPromise(()=> Promise.all(\r\n assets.map(async (item) => {\r\n if (\r\n config.enableIncrementalCompilation &&\r\n /** 资源没有变化,直接跳过 */\r\n config.__skipBuilds__[item.id]?.hash === item.hash\r\n ) {\r\n return /** skip */\r\n } else {\r\n fileTree[item.path] = await API.get_assets({\r\n path: item.path,\r\n })\r\n if (config.enableIncrementalCompilation) {\r\n skipBuilds.add(item.id, { hash: item.hash })\r\n }\r\n }\r\n }),\r\n ))\r\n effectLog.log( `=== 开始复制挂件资源文件 ===`)\r\n const widgetList: DB_block[] =yield* Effect.tryPromise( ()=>API.query_sql({\r\n stmt: `\r\n SELECT *\r\n from blocks\r\n WHERE box = '${book.id}'\r\n AND type = 'widget'\r\n limit 150000 OFFSET 0\r\n `,\r\n }))\r\n const widgetNode = (\r\n yield* Effect.tryPromise( ()=>Promise.all(\r\n widgetList.map(async (el) => await get_node_by_id(el.id)),\r\n ))\r\n )\r\n .filter(\r\n (widget) =>\r\n (widget?.Properties as any)?.['custom-oceanpress-widget-update'],\r\n )\r\n .map(async (widget) => {\r\n if (!widget || !widget?.ID) return\r\n const update = (widget?.Properties as any)?.[\r\n 'custom-oceanpress-widget-update'\r\n ] as string\r\n if (\r\n config.enableIncrementalCompilation &&\r\n config.__skipBuilds__[widget.ID]?.updated === update\r\n ) {\r\n return /** 资源没有变化,直接跳过 */\r\n } else {\r\n const id = widget.ID\r\n // 快照保存的位置 `/data/storage/oceanpress/widget_img/${id}.jpg`\r\n fileTree[`assets/widget/${id}.jpg`] = (await API.file_getFile({\r\n path: `data/storage/oceanpress/widget_img/${id}.jpg`,\r\n })) as ArrayBuffer\r\n if (config.enableIncrementalCompilation) {\r\n skipBuilds.add(id, { updated: update })\r\n }\r\n }\r\n })\r\n yield* Effect.tryPromise( ()=> Promise.all(widgetNode))\r\n }\r\n if(config.sidebarCode.enableDocTree){\r\n effectLog.log( `=== 开始生成文档树 ===`)\r\n fileTree[renderDocTreeJsPath]=yield* renderDocTree()\r\n effectLog.log( `=== 文档树生成完成 ===`)\r\n }\r\n // === 输出编译成果 ===\r\n if (otherConfig?.onFileTree) {\r\n otherConfig.onFileTree(fileTree,effectLog)\r\n }\r\n if (config.compressedZip) {\r\n effectLog.log( `=== 开始生成压缩包 ===`)\r\n yield* Effect.tryPromise(() =>\r\n downloadZIP(fileTree, {\r\n // TODO 这里应该移出来成为全局的写选项\r\n withoutZip: tempConfig.withoutPublicZip,\r\n publicZip: tempConfig.cdn.publicZip,\r\n })\r\n )\r\n }\r\n\r\n config.OceanPress.version = packageJson.version\r\n /** 更新跳过编译的资源 */\r\n skipBuilds.write()\r\n effectLog.percentage(100)\r\n effectLog.log( '编译完毕')\r\n\r\n return {fileTree}\r\n })\r\n}\r\n\r\nfunction useSkipBuilds() {\r\n const obj: { [k: string]: { hash?: string } } = {}\r\n return {\r\n add(\r\n id: string,\r\n value: { hash?: string; refs?: string[]; updated?: string },\r\n ) {\r\n if (obj[id] === undefined) {\r\n obj[id] = {}\r\n }\r\n deepAssign(obj[id], value)\r\n },\r\n /** 将缓存的写入到配置文件 */\r\n write() {\r\n deepAssign(currentConfig.value.__skipBuilds__, obj)\r\n },\r\n }\r\n}\r\n","/** ════════════════════════🏳‍🌈 实用功能 🏳‍🌈════════════════════════\r\n * 利用 composition-api 实现的一些实用功能\r\n ** ════════════════════════🚧 实用功能 🚧════════════════════════ */\r\nimport { customRef, nextTick, watch, watchEffect, WatchSource } from \"vue\";\r\n\r\nexport class PromiseObj<T, Err = Error> {\r\n pending = false;\r\n fulfilled = false;\r\n rejected = false;\r\n data = {} as T;\r\n error = {} as Err;\r\n _p = Promise.resolve() as Promise<unknown>;\r\n setP(p: Promise<unknown>) {\r\n this._p = p;\r\n }\r\n equalP(p: Promise<unknown>) {\r\n return this._p === p;\r\n }\r\n reLoad() {}\r\n setValue(_data: T) {}\r\n}\r\nexport const continueLoading = Symbol();\r\n\r\nexport interface usePromiseComputedOptions<T> {\r\n /** 函数内的依赖变更的时候就重新计算,指定了 deps 则不会依赖于 getter 内的 ref 了\r\n * tips: 可以将其设置为 `()=>[]` 从而不主动执行 getter(), 可以通过调用返回的 reLoad 来调用 getter()\r\n */\r\n deps?: WatchSource<any>;\r\n /** data 的默认值 */\r\n defaultData?: T;\r\n /** 如果这个参数没有输入的话,应该自行调用 PromiseObj.setValue */\r\n getter?: () => Promise<T> | typeof continueLoading;\r\n /** 处理数据是否要和之前的数据进行合并 */\r\n dataMergeFun?: (oldData: T, newData: T) => T;\r\n}\r\n\r\nexport function usePromiseComputed<T, Err = Error>({\r\n deps,\r\n getter,\r\n dataMergeFun = (_oldData, newData) => newData,\r\n defaultData,\r\n}: usePromiseComputedOptions<T>) {\r\n const r = new PromiseObj<T, Err>();\r\n if (defaultData !== undefined) {\r\n r.data = defaultData;\r\n }\r\n return customRef<PromiseObj<T, Err>>((track, trigger) => {\r\n if (!deps && getter) {\r\n watchEffect(() => update(getter()));\r\n } else if (deps && getter) {\r\n if (deps instanceof Function) {\r\n const depsSource = deps();\r\n if (Array.isArray(depsSource) && depsSource.length === 0) {\r\n // 特性,传递空数组则先不执行 getter ,由用户自己决定时机执行 reload\r\n } else {\r\n watch(deps, () => update(getter()), { immediate: true });\r\n }\r\n } else {\r\n watch(deps, () => update(getter()), { immediate: true });\r\n }\r\n }\r\n function update(p: Promise<T> | typeof continueLoading) {\r\n r.pending = true;\r\n r.fulfilled = false;\r\n r.rejected = false;\r\n /** 返回值为继续加载则,getter函数中有特殊的判断逻辑,依据当前的 deps 还无法得出值,需要继续 loading */\r\n if (p === continueLoading) {\r\n nextTick(trigger);\r\n return;\r\n }\r\n r.setP(p);\r\n // 立即触发会导致死循环,所以包裹一层\r\n nextTick(trigger);\r\n p.then((res) => {\r\n // 避免 「求值fun」 第一次执行产生的 promise 比 第二次产生的后结束 导致 数据错误的采用了第一次的\r\n if (r.equalP(p)) {\r\n r.pending = false;\r\n r.fulfilled = true;\r\n r.data = dataMergeFun(r.data, res);\r\n }\r\n })\r\n .catch((e) => {\r\n if (r.equalP(p)) {\r\n r.pending = false;\r\n r.rejected = true;\r\n r.error = e;\r\n }\r\n })\r\n .finally(() => {\r\n if (r.equalP(p)) {\r\n trigger();\r\n }\r\n });\r\n }\r\n r.reLoad = () => {\r\n if (getter) update(getter());\r\n // 否则是用户通过 setValue 设定的值,是无法reLoad的\r\n };\r\n r.setValue = (data) => {\r\n r.pending = false;\r\n r.fulfilled = true;\r\n r.data = dataMergeFun(r.data, data);\r\n trigger();\r\n };\r\n return {\r\n get() {\r\n track();\r\n return r;\r\n },\r\n set(_newValue) {\r\n console.warn(\"不可设置值\");\r\n },\r\n };\r\n });\r\n}\r\n\r\nexport namespace usePromiseComputed {\r\n /** 辅助方法,返回一个deps为 `()=>{}` 的 PromiseObj */\r\n export function nullDeps<T>(getter: usePromiseComputedOptions<T>[\"getter\"]) {\r\n return usePromiseComputed({\r\n deps: () => [],\r\n getter,\r\n });\r\n }\r\n export function fn<T>(fn: () => Promise<T> | typeof continueLoading) {\r\n const p = usePromiseComputed({\r\n getter() {\r\n return fn();\r\n },\r\n });\r\n return p;\r\n }\r\n}\r\n\r\n/** 防抖的 ref */\r\nexport function useDebouncedRef<T>(value: T, delay = 200) {\r\n let timeout = 0;\r\n return customRef<T>((track, trigger) => {\r\n return {\r\n get() {\r\n track();\r\n return value;\r\n },\r\n set(newValue) {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => {\r\n value = newValue;\r\n trigger();\r\n }, delay) as unknown as number;\r\n },\r\n };\r\n });\r\n}\r\n","import { Ref } from 'vue'\r\nimport { currentConfig } from '~/core/config.ts'\r\nimport {\r\n PromiseObj,\r\n usePromiseComputed,\r\n} from '../components/data_promise/index.ts'\r\nimport { S_Node, file, notebook } from './siyuan_type.ts'\r\n\r\n/** oceanpress 所依赖的相关 api https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md */\r\nexport interface api {\r\n /**\r\n * 列出笔记本\r\n */\r\n notebook_lsNotebooks(): {\r\n notebooks: notebook[]\r\n }\r\n filetree_listDocsByPath(p: { notebook: notebook['id']; path: '/' }): {\r\n box: '20210816161940-zo21go1'\r\n files: file[]\r\n path: '/'\r\n }\r\n /** 执行 SQL 查询 https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md#执行-sql-查询 */\r\n query_sql(p: {\r\n /** SELECT * FROM blocks WHERE content LIKE'%content%' LIMIT 7 */ stmt: string\r\n }): any[]\r\n /** 获取文件 https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md#获取文件 */\r\n file_getFile(p: { path: string }): S_Node | ArrayBuffer\r\n get_assets(p: { path: string }): ArrayBuffer\r\n /** 根据人类可读路径获取 IDs https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md#根据人类可读路径获取-ids */\r\n filetree_getIDsByHPath(p: {\r\n /** /foo/bar */\r\n path: string\r\n /** 20210808180117-czj9bvb */\r\n notebook: string\r\n }): string[]\r\n}\r\ntype apiPromisify = {\r\n readonly [K in keyof api]: (\r\n ...arg: Parameters<api[K]>\r\n ) => Promise<unPromise<ReturnType<api[K]>>>\r\n}\r\n\r\n/** 解开 promise 类型包装 */\r\ndeclare type unPromise<T> = T extends Promise<infer R> ? R : T\r\nlet rpcCount = 0\r\nasync function rpc(method: string, arg: any) {\r\n const apiPrefix = currentConfig.value.apiPrefix\r\n const Authorization = currentConfig.value.authorized\r\n rpcCount++\r\n\r\n if (method === 'get_assets') {\r\n return fetch(`${apiPrefix}/${arg[0].path}`, {\r\n headers: {\r\n Authorization: `Token ${Authorization}`,\r\n },\r\n body: null,\r\n method: 'GET',\r\n mode: 'cors',\r\n }).then((r) => r.arrayBuffer())\r\n }\r\n const res = await fetch(`${apiPrefix}/api/${method.replace(/_/g, '/')}`, {\r\n headers: {\r\n Authorization: `Token ${Authorization}`,\r\n },\r\n body: JSON.stringify(arg[0]),\r\n method: 'POST',\r\n }).catch((err: Error) => {\r\n err.message = `访问思源接口时出错了,请检查思源服务是否启动以及配置接口地址是否正确。`\r\n throw err\r\n })\r\n if (method === 'file_getFile') {\r\n const path = arg[0].path as string\r\n if (path.endsWith('.sy')) {\r\n return await res.json()\r\n } else {\r\n const buffer = await res.arrayBuffer()\r\n if (buffer.byteLength < 200) {\r\n const decoder = new TextDecoder()\r\n const text = decoder.decode(buffer)\r\n if (JSON.parse(text).code === 404) {\r\n throw new Error(`文件不存在: ${path}`)\r\n }\r\n }\r\n return buffer\r\n }\r\n }\r\n const json = await res.json()\r\n\r\n if (json.code !== 0) {\r\n throw new Error(json.msg)\r\n }\r\n return json.data\r\n}\r\n\r\n/** 包装了一次的 RC 方便跳转到函数定义 */\r\nexport const API = new Proxy(\r\n {},\r\n {\r\n get(_, method: string) {\r\n return (...arg: any) => rpc(method, arg)\r\n },\r\n },\r\n) as apiPromisify\r\n\r\ntype vApi = {\r\n readonly [K in keyof api]: (\r\n ...arg: Parameters<api[K]>\r\n ) => Ref<PromiseObj<unPromise<ReturnType<api[K]>>, Error>>\r\n}\r\n/** 使用 usePromiseComputed 包装的方法,便于使用 */\r\nexport const vApi = new Proxy(\r\n {},\r\n {\r\n get(_, method: string) {\r\n return (...arg: any) => usePromiseComputed.fn(() => rpc(method, arg))\r\n },\r\n },\r\n) as vApi\r\n","export interface notebook {\r\n id: \"20210808180117-czj9bvb\";\r\n name: \"思源笔记用户指南\";\r\n icon: \"1f4d4\";\r\n sort: 1;\r\n closed: false;\r\n}\r\nexport interface file {\r\n /** \"/20210816161946-cktc4gf.sy\" */\r\n path: string;\r\n name: \"关于.sy\";\r\n icon: \"\";\r\n name1: \"\";\r\n alias: \"\";\r\n memo: \"\";\r\n bookmark: \"\";\r\n /** \"20210816161946-cktc4gf\" */\r\n id: string;\r\n count: 0;\r\n size: 362;\r\n hSize: \"362 B\";\r\n mtime: 1629101986;\r\n ctime: 1629101986;\r\n hMtime: \"2 年以前\";\r\n hCtime: \"2021-08-16 16:19:46\";\r\n sort: 0;\r\n subFileCount: 9;\r\n newFlashcardCount: 0;\r\n dueFlashcardCount: 0;\r\n flashcardCount: 0;\r\n}\r\nexport interface NodeDocument {\r\n blockCount: 2;\r\n box: \"20210808180117-czj9bvb\";\r\n content: \"<html>\";\r\n eof: false;\r\n id: \"20230519105228-hm0y74i\";\r\n isBacklinkExpand: false;\r\n isSyncing: false;\r\n mode: 0;\r\n parent2ID: \"20230519105228-hm0y74i\";\r\n parentID: \"20230519105228-hm0y74i\";\r\n path: \"/20230519105228-hm0y74i.sy\";\r\n rootID: \"20230519105228-hm0y74i\";\r\n scroll: false;\r\n type: \"NodeDocument\";\r\n}\r\n\r\nexport function DB_block_path(p: DB_block) {\r\n return `data/${p.box}${p.path}`;\r\n}\r\nexport interface DB_block {\r\n alias: \"\";\r\n box: \"20210816161940-3mfvumm\";\r\n content: \"自述\";\r\n created: \"20201125202944\";\r\n fcontent: \"自述\";\r\n hash: \"922ee83\";\r\n hpath: \"/计算机基础课/自述\";\r\n ial: '{: id=\"20201125202944-01mdxqn\" title=\"自述\" type=\"doc\" updated=\"20201125202944\"}';\r\n id: \"20201125202944-01mdxqn\";\r\n length: 2;\r\n markdown: \"\";\r\n memo: \"\";\r\n name: \"\";\r\n parent_id: \"\";\r\n path: \"/20210816161944-io0cgn6/20201125202944-01mdxqn.sy\";\r\n root_id: \"20201125202944-01mdxqn\";\r\n sort: 0;\r\n subtype: \"\";\r\n tag: \"\";\r\n type: \"d\";\r\n updated: \"20201125202944\";\r\n}\r\nexport interface S_Node {\r\n ID?: string; // 节点的唯一标识\r\n Box?: string; // 容器\r\n Path?: string; // 路径\r\n Spec?: string; // 规范版本号\r\n Type: NodeType; // 节点类型\r\n Parent: S_Node; // 父节点 在 node.ts 中被重建了,所以这个引用关系是可用的\r\n Previous?: S_Node; // 前一个兄弟节点\r\n Next?: S_Node; // 后一个兄弟节点\r\n FirstChild?: S_Node; // 第一个子节点\r\n LastChild?: S_Node; // 最后一个子节点\r\n Children?: S_Node[]; // 所有子节点\r\n Tokens?: number[]; // 词法分析结果 Tokens,语法分析阶段会继续操作这些 Tokens\r\n TypeStr: string; // 类型字符串\r\n Data?: string; // Tokens 字符串\r\n Close?: boolean; // 标识是否关闭\r\n LastLineBlank?: boolean; // 标识最后一行是否是空行\r\n LastLineChecked?: boolean; // 标识最后一行是否检查过\r\n CodeMarkerLen?: number; // ` 个数,1 或 2\r\n IsFencedCodeBlock?: boolean;\r\n CodeBlockFenceChar?: number;\r\n CodeBlockFenceLen?: number;\r\n CodeBlockFenceOffset?: number;\r\n CodeBlockOpenFence?: number[];\r\n CodeBlockInfo?: string; // Z28= | atob = 'go'\r\n CodeBlockCloseFence?: number[];\r\n HtmlBlockType?: number;\r\n ListData?: ListData;\r\n TaskListItemChecked?: boolean;\r\n TableAligns?: number[];\r\n TableCellAlign?: number;\r\n TableCellContentWidth?: number;\r\n TableCellContentMaxWidth?: number;\r\n LinkType?: number;\r\n LinkRefLabel?: number[];\r\n HeadingLevel?: number;\r\n HeadingSetext?: boolean;\r\n HeadingNormalizedID?: string;\r\n MathBlockDollarOffset?: number;\r\n FootnotesRefLabel?: number[];\r\n FootnotesRefId?: string;\r\n FootnotesRefs?: Node[];\r\n HtmlEntityTokens?: number[];\r\n KramdownIAL?: string[][];\r\n Properties?: {\r\n icon: \"1f4f0\";\r\n id: \"20200825162036-4dx365o\";\r\n title: \"排版元素\";\r\n \"title-img\": \"background-color: hsl(2, 57%, 40%);background-image: repeating-linear-gradient(transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(270deg, transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(125deg, transparent, transparent 2px, rgba(0,0,0,.2) 2px, rgba(0,0,0,.2) 3px, transparent 3px, transparent 5px, rgba(0,0,0,.2) 5px);\";\r\n type: \"doc\";\r\n updated: \"20230820185054\";\r\n \"parent-style\"?: \"max-width: 137px;\";\r\n style?: \"display: block;\";\r\n };\r\n TextMarkType?: \"block-ref\" | \"a\" | \"tag\" | \"inline-math\" | \"inline-memo\";\r\n TextMarkAHref?: string;\r\n TextMarkATitle?: string;\r\n TextMarkInlineMathContent?: string;\r\n TextMarkInlineMemoContent?: string;\r\n TextMarkBlockRefID?: string;\r\n TextMarkBlockRefSubtype?: string;\r\n TextMarkFileAnnotationRefID?: string;\r\n TextMarkTextContent?: string;\r\n AttributeViewID?: string;\r\n AttributeViewType?: string;\r\n CustomBlockFenceOffset?: number;\r\n CustomBlockInfo?: string;\r\n}\r\ntype NodeType = ValueKeys<typeof NodeType>;\r\ntype ValueKeys<T> = keyof { [K in keyof T]: T[K] extends string ? K : never };\r\ninterface ListData {\r\n Typ?: number; // 0:无序列表,1:有序列表,3:任务列表\r\n Tight?: boolean; // 是否是紧凑模式\r\n BulletChar?: number; // 无序列表标识,* - 或者 +\r\n Start?: number; // 有序列表起始序号\r\n Delimiter?: number; // 有序列表分隔符,. 或者 )\r\n Padding?: number; // 列表内部缩进空格数(包含标识符长度,即规范中的 W+N)\r\n MarkerOffset?: number; // 标识符(* - + 或者 1 2 3)相对缩进空格数\r\n Checked?: boolean; // 任务列表项是否勾选\r\n Marker?: string; // 列表标识符\r\n Num?: number; // 有序列表项修正过的序号\r\n}\r\n\r\nexport const NodeType = {\r\n NodeDocument: 0, // 根\r\n NodeParagraph: 1, // 段落\r\n NodeHeading: 2, // 标题\r\n NodeHeadingC8hMarker: 3, // ATX 标题标记符 #\r\n NodeThematicBreak: 4, // 分隔线\r\n NodeBlockquote: 5, // 块引用\r\n NodeBlockquoteMarker: 6, // 块引用标记符 >\r\n NodeList: 7, // 列表\r\n NodeListItem: 8, // 列表项\r\n NodeHTMLBlock: 9, // HTML 块\r\n NodeInlineHTML: 10, // 内联 HTML\r\n NodeCodeBlock: 11, // 代码块\r\n NodeCodeBlockFenceOpenMarker: 12, // 开始围栏代码块标记符 ```\r\n NodeCodeBlockFenceCloseMarker: 13, // 结束围栏代码块标记符 ```\r\n NodeCodeBlockFenceInfoMarker: 14, // 围栏代码块信息标记符 info string\r\n NodeCodeBlockCode: 15, // 围栏代码块代码\r\n NodeText: 16, // 文本\r\n NodeEmphasis: 17, // 强调\r\n NodeEmA6kOpenMarker: 18, // 开始强调标记符 *\r\n NodeEmA6kCloseMarker: 19, // 结束强调标记符 *\r\n NodeEmU8eOpenMarker: 20, // 开始强调标记符 _\r\n NodeEmU8eCloseMarker: 21, // 结束强调标记符 _\r\n NodeStrong: 22, // 加粗\r\n NodeStrongA6kOpenMarker: 23, // 开始加粗标记符 **\r\n NodeStrongA6kCloseMarker: 24, // 结束加粗标记符 **\r\n NodeStrongU8eOpenMarker: 25, // 开始加粗标记符 __\r\n NodeStrongU8eCloseMarker: 26, // 结束加粗标记符 __\r\n NodeCodeSpan: 27, // 代码\r\n NodeCodeSpanOpenMarker: 28, // 开始代码标记符 `\r\n NodeCodeSpanContent: 29, // 代码内容\r\n NodeCodeSpanCloseMarker: 30, // 结束代码标记符 `\r\n NodeHardBreak: 31, // 硬换行\r\n NodeSoftBreak: 32, // 软换行\r\n NodeLink: 33, // 链接\r\n NodeImage: 34, // 图片\r\n NodeBang: 35, // !\r\n NodeOpenBracket: 36, // [\r\n NodeCloseBracket: 37, // ]\r\n NodeOpenParen: 38, // (\r\n NodeCloseParen: 39, // )\r\n NodeLinkText: 40, // 链接文本\r\n NodeLinkDest: 41, // 链接地址\r\n NodeLinkTitle: 42, // 链接标题\r\n NodeLinkSpace: 43, // 链接地址和链接标题之间的空格\r\n NodeHTMLEntity: 44, // HTML 实体\r\n NodeLinkRefDefBlock: 45, // 链接引用定义块\r\n NodeLinkRefDef: 46, // 链接引用定义 [label]:\r\n NodeLess: 47, // <\r\n NodeGreater: 48, // >\r\n\r\n // GFM\r\n\r\n NodeTaskListItemMarker: 100, // 任务列表项标记符\r\n NodeStrikethrough: 101, // 删除线\r\n NodeStrikethrough1OpenMarker: 102, // 开始删除线标记符 ~\r\n NodeStrikethrough1CloseMarker: 103, // 结束删除线标记符 ~\r\n NodeStrikethrough2OpenMarker: 104, // 开始删除线标记符 ~~\r\n NodeStrikethrough2CloseMarker: 105, // 结束删除线标记符 ~~\r\n NodeTable: 106, // 表\r\n NodeTableHead: 107, // 表头\r\n NodeTableRow: 108, // 表行\r\n NodeTableCell: 109, // 表格\r\n\r\n // Emoji\r\n\r\n NodeEmoji: 200, // Emoji\r\n NodeEmojiUnicode: 201, // Emoji Unicode\r\n NodeEmojiImg: 202, // Emoji 图片\r\n NodeEmojiAlias: 203, // Emoji ASCII\r\n\r\n // 数学公式\r\n\r\n NodeMathBlock: 300, // 数学公式块\r\n NodeMathBlockOpenMarker: 301, // 开始数学公式块标记符 $$\r\n NodeMathBlockContent: 302, // 数学公式块内容\r\n NodeMathBlockCloseMarker: 303, // 结束数学公式块标记符 $$\r\n NodeInlineMath: 304, // 内联数学公式\r\n NodeInlineMathOpenMarker: 305, // 开始内联数学公式标记符 $\r\n NodeInlineMathContent: 306, // 内联数学公式内容\r\n NodeInlineMathCloseMarker: 307, // 结束内联数学公式标记符 $\r\n\r\n // 转义\r\n\r\n NodeBackslash: 400, // 转义反斜杠标记符 \\\r\n NodeBackslashContent: 401, // 转义反斜杠后的内容\r\n\r\n // Vditor 支持\r\n\r\n NodeVditorCaret: 405, // 插入符,某些情况下需要使用该节点进行插入符位置调整\r\n\r\n // 脚注\r\n\r\n NodeFootnotesDefBlock: 410, // 脚注定义块\r\n NodeFootnotesDef: 411, // 脚注定义 [^label]:\r\n NodeFootnotesRef: 412, // 脚注引用 [^label]\r\n\r\n // 目录\r\n\r\n NodeToC: 415, // 目录 [toc]\r\n\r\n // 标题\r\n\r\n NodeHeadingID: 420, // 标题 ID # foo {id}\r\n\r\n // YAML Front Matter\r\n\r\n NodeYamlFrontMatter: 425, // https://,jekyllrb.com/docs/front-matter/\r\n NodeYamlFrontMatterOpenMarker: 426, // 开始 YAML Front Matter 标记符 ---\r\n NodeYamlFrontMatterContent: 427, // YAML Front Matter 内容\r\n NodeYamlFrontMatterCloseMarker: 428, // 结束 YAML Front Matter 标记符 ---\r\n\r\n // 内容块引用(Block Reference) https://,github.com/88250/lute/issues/82\r\n\r\n NodeBlockRef: 430, // 内容块引用节点\r\n NodeBlockRefID: 431, // 被引用的内容块(定义块)ID\r\n NodeBlockRefSpace: 432, // 被引用的内容块 ID 和内容块引用锚文本之间的空格\r\n NodeBlockRefText: 433, // 内容块引用锚文本\r\n NodeBlockRefDynamicText: 434, // 内容块引用动态锚文本\r\n\r\n // ==Mark== 标记语法 https://,github.com/88250/lute/issues/84\r\n\r\n NodeMark: 450, // 标记\r\n NodeMark1OpenMarker: 451, // 开始标记标记符 =\r\n NodeMark1CloseMarker: 452, // 结束标记标记符 =\r\n NodeMark2OpenMarker: 453, // 开始标记标记符 ==\r\n NodeMark2CloseMarker: 454, // 结束标记标记符 ==\r\n\r\n // kramdown 内联属性列表 https://,github.com/88250/lute/issues/89 and https://,github.com/88250/lute/issues/118\r\n\r\n NodeKramdownBlockIAL: 455, // 块级内联属性列表 {: name,=\"value\"}\r\n NodeKramdownSpanIAL: 456, // 行级内联属性列表 *foo*{: name,=\"value\"}bar\r\n\r\n // #Tag# 标签语法 https://,github.com/88250/lute/issues/92\r\n\r\n NodeTag: 460, // 标签\r\n NodeTagOpenMarker: 461, // 开始标签标记符 #\r\n NodeTagCloseMarker: 462, // 结束标签标记符 #\r\n\r\n // 内容块查询嵌入(Block Query Embed)语法 https://,github.com/88250/lute/issues/96\r\n\r\n NodeBlockQueryEmbed: 465, // 内容块查询嵌入\r\n NodeOpenBrace: 466, // {\r\n NodeCloseBrace: 467, // }\r\n NodeBlockQueryEmbedScript: 468, // 内容块查询嵌入脚本\r\n\r\n // 超级块语法 https://,github.com/88250/lute/issues/111\r\n\r\n NodeSuperBlock: 475, // 超级块节点\r\n NodeSuperBlockOpenMarker: 476, // 开始超级块标记符 {{{\r\n NodeSuperBlockLayoutMarker: 477, // 超级块布局 row/col\r\n NodeSuperBlockCloseMarker: 478, // 结束超级块标记符 }}}\r\n\r\n // 上标下标语法 https://,github.com/88250/lute/issues/113\r\n\r\n NodeSup: 485, // 上标\r\n NodeSupOpenMarker: 486, // 开始上标标记符 ^\r\n NodeSupCloseMarker: 487, // 结束上标标记符 ^\r\n NodeSub: 490, // 下标\r\n NodeSubOpenMarker: 491, // 开始下标标记符 ~\r\n NodeSubCloseMarker: 492, // 结束下标标记符 ~\r\n\r\n // Git 冲突标记 https://,github.com/88250/lute/issues/131\r\n\r\n NodeGitConflict: 495, // Git 冲突标记\r\n NodeGitConflictOpenMarker: 496, // 开始 Git 冲突标记标记符 <<<<<<<\r\n NodeGitConflictContent: 497, // Git 冲突标记内容\r\n NodeGitConflictCloseMarker: 498, // 结束 Git 冲突标记标记符 >>>>>>>\r\n\r\n // <iframe> 标签\r\n\r\n NodeIFrame: 500, // <iframe> 标签\r\n\r\n // <audio> 标签\r\n\r\n NodeAudio: 505, // <audio> 标签\r\n\r\n // <video> 标签\r\n\r\n NodeVideo: 510, // <video> 标签\r\n\r\n // <kbd> 标签\r\n\r\n NodeKbd: 515, // 键盘\r\n NodeKbdOpenMarker: 516, // 开始 kbd 标记符 <kbd>\r\n NodeKbdCloseMarker: 517, // 结束 kbd 标记符 </kbd>\r\n\r\n // <u> 标签\r\n\r\n NodeUnderline: 520, // 下划线\r\n NodeUnderlineOpenMarker: 521, // 开始下划线标记符 <u>\r\n NodeUnderlineCloseMarker: 522, // 结束下划线标记符 </u>\r\n\r\n // <br> 标签\r\n\r\n NodeBr: 525, // <br> 换行\r\n\r\n // <span data-type=\"mark\">foo</span> 通用的行级文本标记,不能嵌套\r\n\r\n NodeTextMark: 530, // 文本标记,该节点因为不存在嵌套,所以不使用 Open/Close 标记符\r\n\r\n // Protyle 挂件,<iframe data-type=\"NodeWidget\">\r\n\r\n NodeWidget: 535, // <iframe data-type=\"NodeWidget\" data-subtype=\"widget\"></iframe>\r\n\r\n // 文件注解引用 https://,github.com/88250/lute/issues/155\r\n\r\n NodeFileAnnotationRef: 540, // 文件注解引用节点\r\n NodeFileAnnotationRefID: 541, // 被引用的文件注解 ID(file/annotation)\r\n NodeFileAnnotationRefSpace: 542, // 被引用的文件注解 ID 和文件注解引用锚文本之间的空格\r\n NodeFileAnnotationRefText: 543, // 文件注解引用锚文本(不能为空,如果为空的话会自动使用 ID 渲染)\r\n\r\n // 属性视图 https://,github.com/siyuan-note/siyuan/issues/7535 <div data-type=\"NodeAttributeView\" data-av-type=\"table\" data-av-id=\"xxx\"></div>\r\n\r\n NodeAttributeView: 550, // 属性视图\r\n\r\n // 自定义块 https://,github.com/siyuan-note/siyuan/issues/8418 ;;;info\r\n\r\n NodeCustomBlock: 560, // 自定义块\r\n\r\n NodeTypeMaxVal: 1024, // 节点类型最大值\r\n};\r\n","/** ════════════════════════🏳‍🌈 cache 🏳‍🌈════════════════════════\r\n * 对于思源内核 api 的调用存到内存,通过快取技术避免重复请求和没有必要的请求,加速程序运行速度,但这可能会导致数据不是最新的\r\n ** ════════════════════════🚧 cache 🚧════════════════════════ */\r\n\r\nimport { API } from './siyuan_api.ts'\r\nimport { DB_block, DB_block_path, S_Node } from './siyuan_type.ts'\r\n\r\nlet cache = true\r\n/** 控制是否启用快取功能 */\r\nexport function setCache(b: boolean) {\r\n cache = b\r\n}\r\n\r\n/** sql->查询结果 */\r\nconst sqlCacheMap = new Map<string, any>()\r\n/** hpath->S_Node文档节点 */\r\nconst hpathCacheMap = new Map<string, S_Node>()\r\n/** id->S_Node */\r\nconst idCacheMap = new Map<string, S_Node>()\r\n/** id->DB_block */\r\nconst blockCacheMap = new Map<string, DB_block>()\r\n\r\nexport async function getIDsByHPath(p: {\r\n path: string\r\n notebook: string\r\n}): Promise<string[]> {\r\n if (cache && hpathCacheMap.has(p.path)) {\r\n const id = hpathCacheMap.get(p.path)?.ID\r\n // TODO 也许会有重复hpath这里暂不考虑\r\n return id ? [id] : []\r\n }\r\n const ids = await API.filetree_getIDsByHPath(p)\r\n return ids\r\n}\r\n\r\n/** 设置快取 sqlCacheMap */\r\nexport async function query_sql(stmt: string): Promise<any> {\r\n if (cache && sqlCacheMap.has(stmt)) {\r\n return sqlCacheMap.get(stmt)\r\n }\r\n const res = await API.query_sql({\r\n stmt,\r\n })\r\n if (cache) {\r\n sqlCacheMap.set(stmt, res)\r\n }\r\n return res\r\n}\r\n\r\n/** 设置快取 hpathCacheMap idCacheMap */\r\nexport async function get_doc_by_hpath(hpath: string): Promise<S_Node> {\r\n if (cache) {\r\n const c = hpathCacheMap.get(hpath)\r\n if (c) return c\r\n }\r\n const docBlock = (\r\n (await query_sql(\r\n `SELECT * FROM blocks WHERE hpath = '${hpath}'`,\r\n )) as DB_block[]\r\n )[0]\r\n if (docBlock === undefined) throw new Error(`not doc by:${hpath}`)\r\n const res = await get_doc_by_SyPath(DB_block_path(docBlock))\r\n if (cache) {\r\n hpathCacheMap.set(hpath, res)\r\n }\r\n return res\r\n}\r\n/** 设置快取 idCacheMap */\r\nexport async function get_doc_by_SyPath(path: string): Promise<S_Node> {\r\n const res = parentRef(\r\n (await API.file_getFile({\r\n path,\r\n })) as S_Node,\r\n )\r\n if (cache) {\r\n idCache(res)\r\n }\r\n return res\r\n}\r\n\r\nexport async function get_block_by_id(id: string) {\r\n if (cache) {\r\n const block = blockCacheMap.get(id)\r\n if (block) return block\r\n }\r\n const blocks = (await query_sql(`\r\n SELECT * from blocks\r\n WHERE id = '${id}'\r\n `)) as DB_block[]\r\n if (blocks.length === 0) {\r\n return\r\n }\r\n if (cache) blockCacheMap.set(id, blocks[0])\r\n return blocks[0]\r\n}\r\nexport async function get_node_by_id(id?: string) {\r\n if (id === undefined) return\r\n if (cache) {\r\n const node = idCacheMap.get(id)\r\n if (node) return node\r\n }\r\n const doc = await get_doc_by_child_id(id)\r\n if (doc === undefined) return\r\n return findNode(doc)\r\n\r\n function findNode(node: S_Node): S_Node | undefined {\r\n if (node.ID === id) return node\r\n if (node.Children) {\r\n return node.Children.find((child) => findNode(child))\r\n }\r\n }\r\n}\r\n/** set blockCacheMap*/\r\n// TODO 需要更换成能够完全遍历一个笔记本的写法\r\nexport async function allDocBlock_by_bookId(id: string) {\r\n const res = (await query_sql(`\r\n SELECT * from blocks\r\n WHERE box = '${id}'\r\n AND type = 'd'\r\n limit 150000 OFFSET 0\r\n `)) as DB_block[]\r\n if (cache) {\r\n res.forEach((block) => blockCacheMap.set(block.id, block))\r\n }\r\n return res\r\n}\r\n\r\nexport async function get_doc_by_child_id(\r\n id: string,\r\n): Promise<S_Node | undefined> {\r\n if (cache) {\r\n const child = idCacheMap.get(id)\r\n if (child) {\r\n let node = child\r\n while (true) {\r\n if (node.Type === 'NodeDocument') {\r\n return node\r\n } else if (node === undefined) {\r\n break\r\n }\r\n node = node.Parent\r\n }\r\n }\r\n }\r\n const block = await get_block_by_id(id)\r\n if (block === undefined) return\r\n return await get_doc_by_hpath(block.hpath)\r\n}\r\n\r\nfunction idCache(node: S_Node) {\r\n if (node.ID) {\r\n idCacheMap.set(node.ID, node)\r\n }\r\n if (node.Children) {\r\n node.Children.forEach(idCache)\r\n }\r\n}\r\n\r\n/** 为 children 节点附加 Parent 引用 */\r\nexport function parentRef(sy: S_Node) {\r\n for (const child of sy?.Children ?? []) {\r\n child.Parent = sy\r\n parentRef(child)\r\n }\r\n return sy\r\n}\r\n","import { get_node_by_id } from './cache.ts'\nimport type { Config } from './config.ts'\nimport type { Render } from './render.ts'\nimport type { DB_block, S_Node } from './siyuan_type.ts'\n\n/** 生成当前实例所有引用文档的RSS XML */\nexport async function generateRSSXML(\n path: string,\n renderInstance: Render,\n config: Config,\n getHPathByID_Node: (id_node: string | S_Node) => Promise<string>,\n): Promise<string> {\n const refNode = (\n await Promise.all([...renderInstance.refs.values()].map(get_node_by_id))\n ).filter((el) => el)\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n <channel>\n <title>${config.sitemap.title}</title>\n <link>${config.sitemap.siteLink}</link>\n <description>${config.sitemap.description}</description>\n <atom:link href=\"${\n config.sitemap.sitePrefix\n }${path}\" rel=\"self\" type=\"application/rss+xml\"/>\n <lastBuildDate>${new Date().toISOString()}</lastBuildDate>\n ${(\n await Promise.all(\n refNode.map(\n async (node) => `<item>\n <title>${node?.Properties?.title}</title>\n <link>${config.sitemap.sitePrefix}${\n node?.ID ? (await getHPathByID_Node(node?.ID)) + '.html' : ''\n }</link>\n <description>${'' /** TODO 或许可以加入ai 进行摘要 */}</description>\n <pubDate>${\n node?.Properties?.updated\n ? new Date(\n node.Properties.updated.replace(\n /(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/,\n '$1/$2/$3 $4:$5:$6',\n ),\n ).toISOString()\n : ''\n }</pubDate>\n </item>`,\n ),\n )\n ).join('\\n')}\n </channel>\n </rss>`\n}\n\n/** 生成 sitemap.xml 文件内容 */\nexport function sitemap_xml(\n docArr: DB_block[],\n config: {\n sitePrefix: string\n },\n) {\n const urlList: string = docArr\n .map((doc) => {\n let lastmod = ''\n const time = doc.ial.match(/updated=\\\"(\\d+)\\\"/)?.[1] ?? doc.created\n if (time) {\n lastmod = `\\n<lastmod>${time.slice(0, 4)}-${time.slice(\n 4,\n 6,\n )}-${time.slice(6, 8)}</lastmod>`\n }\n return `<url>\n <loc>${config.sitePrefix}${doc.hpath}.html</loc>${lastmod}\n </url>\\n`\n })\n .join('')\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n ${urlList}\n </urlset>`\n}\n","/**\r\n * SEO 优化和结构化数据生成工具\r\n * 为 OceanPress 生成的 HTML 页面添加 JSON-LD 结构化数据和其他 SEO 优化\r\n */\r\n\r\nimport { Config } from './config.ts'\r\nimport { S_Node } from './siyuan_type.ts'\r\n\r\n\r\n/**\r\n * 从思源文档ID中提取日期时间并格式化为 ISO 8601\r\n * 思源ID格式: 20250801084546-uvfteud -> 2025-08-01T08:45:46Z\r\n */\r\nfunction extractDateFromId(id?: string): string {\r\n if (!id || id.length < 14) return new Date().toISOString()\r\n\r\n try {\r\n const datePart = id.slice(0, 14) // 取前14位: 20250801084546\r\n if (datePart.length === 14) {\r\n const year = datePart.slice(0, 4)\r\n const month = datePart.slice(4, 6)\r\n const day = datePart.slice(6, 8)\r\n const hour = datePart.slice(8, 10)\r\n const minute = datePart.slice(10, 12)\r\n const second = datePart.slice(12, 14)\r\n return `${year}-${month}-${day}T${hour}:${minute}:${second}Z`\r\n }\r\n } catch {\r\n // 忽略解析错误,使用默认值\r\n }\r\n return new Date().toISOString()\r\n}\r\n\r\n/**\r\n * 格式化日期为 ISO 8601 格式\r\n */\r\nfunction formatDate(dateString?: string): string {\r\n if (!dateString) return new Date().toISOString()\r\n try {\r\n // 思源笔记的日期格式通常是 YYYYMMDDHHMMSS 或时间戳\r\n if (dateString.length === 14) {\r\n // YYYYMMDDHHMMSS 格式\r\n const year = dateString.slice(0, 4)\r\n const month = dateString.slice(4, 6)\r\n const day = dateString.slice(6, 8)\r\n const hour = dateString.slice(8, 10)\r\n const minute = dateString.slice(10, 12)\r\n const second = dateString.slice(12, 14)\r\n return `${year}-${month}-${day}T${hour}:${minute}:${second}Z`\r\n }\r\n // 尝试解析为时间戳\r\n const timestamp = parseInt(dateString)\r\n if (!isNaN(timestamp)) {\r\n return new Date(timestamp).toISOString()\r\n }\r\n // 尝试直接解析\r\n return new Date(dateString).toISOString()\r\n } catch {\r\n return new Date().toISOString()\r\n }\r\n}\r\n\r\n/**\r\n * TF-IDF 关键词提取算法\r\n */\r\nclass TFIDFKeywordExtractor {\r\n private stopWords = new Set([\r\n // 中文停用词\r\n '的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这', '那', '现在', '可以', '但是', '还是', '因为', '什么', '如果', '所以', '对于', '关于', '通过', '进行', '基于', '以及', '或者', '而且', '然后', '只是', '已经', '正在', '应该', '能够', '需要', '可能', '一定', '这样', '那样', '怎么', '为什么', '哪里', '哪个', '多少', '几个', '什么', '怎么', '如何', '为什么',\r\n // 英文停用词\r\n 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'must', 'can', 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they', 'me', 'him', 'her', 'us', 'them', 'my', 'your', 'his', 'its', 'our', 'their', 'not', 'no', 'yes', 'so', 'if', 'when', 'where', 'how', 'why', 'what', 'which', 'who', 'whom', 'there', 'here'\r\n ])\r\n\r\n /**\r\n * 计算词频 (TF)\r\n */\r\n private calculateTermFrequency(text: string): Map<string, number> {\r\n const words = this.tokenize(text)\r\n const tf = new Map<string, number>()\r\n const totalWords = words.length\r\n\r\n for (const word of words) {\r\n tf.set(word, (tf.get(word) || 0) + 1)\r\n }\r\n\r\n // 标准化词频\r\n for (const [word, count] of tf) {\r\n tf.set(word, count / totalWords)\r\n }\r\n\r\n return tf\r\n }\r\n\r\n /**\r\n * 分词处理(针对中文和英文优化)\r\n */\r\n private tokenize(text: string): string[] {\r\n const tokens: string[] = []\r\n\r\n // 首先彻底清理HTML标签和属性,只保留纯文本内容\r\n const plainText = text\r\n .replace(/<[^>]*>/g, ' ') // 移除所有HTML标签\r\n .replace(/&[^;]+;/g, ' ') // 移除HTML实体\r\n .replace(/\\s+/g, ' ') // 合并多个空格\r\n .trim()\r\n\r\n // 1. 提取英文单词和技术术语(优先处理)\r\n const englishWords = plainText.match(/[a-zA-Z]{3,}/g) || []\r\n tokens.push(...englishWords.map(word => word.toLowerCase()).filter(word => !this.stopWords.has(word)))\r\n\r\n // 2. 提取驼峰命名(如 useState, useEffect)\r\n const camelCaseWords = plainText.match(/[a-z]+[A-Z][a-zA-Z0-9]*|[A-Z][a-z0-9]+[A-Z][a-zA-Z0-9]*/g) || []\r\n tokens.push(...camelCaseWords.map(word => word.toLowerCase()))\r\n\r\n // 3. 智能中文分词 - 基于文本特征分析\r\n const chineseTokens = this.extractChineseTokens(plainText)\r\n tokens.push(...chineseTokens)\r\n\r\n // 4. 后处理:过滤掉无意义的词汇\r\n const filteredTokens = tokens.filter(token => {\r\n // 过滤掉长度小于2的词汇\r\n if (token.length < 2) return false\r\n\r\n // 过滤掉HTML相关的无意义词汇\r\n const htmlRelatedWords = ['div', 'span', 'class', 'id', 'type', 'data', 'href', 'src', 'alt', 'title', 'style', 'width', 'height', 'rootid', 'endid', 'nodedocument', 'ezcqbj', 'cktc', 'quot']\r\n if (htmlRelatedWords.includes(token.toLowerCase())) {\r\n return false\r\n }\r\n\r\n // 过滤掉看起来像属性名或ID的词汇\r\n if (token.match(/^[a-f0-9]{6,}$/)) return false // 过滤掉十六进制ID\r\n\r\n // 过滤掉看起来不像是完整词汇的中文词汇\r\n if (/[\\u4e00-\\u9fa5]/.test(token) && token.length < 2) {\r\n return false\r\n }\r\n\r\n return true\r\n })\r\n\r\n return filteredTokens\r\n }\r\n\r\n /**\r\n * 智能中文分词 - 基于文本特征分析\r\n */\r\n private extractChineseTokens(text: string): string[] {\r\n const tokens: string[] = []\r\n\r\n // 提取中文文本\r\n const chineseText = text.replace(/[^\\u4e00-\\u9fa5\\s]/g, ' ')\r\n\r\n // 基于常见中文词汇模式进行提取\r\n // 2-4字的中文词汇通常是完整的词汇\r\n const wordPatterns = [\r\n /[\\u4e00-\\u9fa5]{4}/g, // 4字词汇\r\n /[\\u4e00-\\u9fa5]{3}/g, // 3字词汇\r\n /[\\u4e00-\\u9fa5]{2}/g, // 2字词汇\r\n ]\r\n\r\n for (const pattern of wordPatterns) {\r\n const matches = chineseText.match(pattern) || []\r\n for (const word of matches) {\r\n if (!this.stopWords.has(word) && this.isMeaningfulChineseWord(word)) {\r\n tokens.push(word.toLowerCase())\r\n }\r\n }\r\n }\r\n\r\n return tokens\r\n }\r\n\r\n /**\r\n * 判断是否为有意义的中文词汇\r\n */\r\n private isMeaningfulChineseWord(word: string): boolean {\r\n // 过滤掉常见的无意义组合\r\n const meaninglessPatterns = [\r\n /^的.*$/, /^.*的$/, /^了.*$/, /^.*了$/,\r\n /^在.*$/, /^.*在$/, /^是.*$/, /^.*是$/,\r\n /^我.*$/, /^.*我$/, /^有.*$/, /^.*有$/,\r\n /^和.*$/, /^.*和$/, /^就.*$/, /^.*就$/,\r\n /^不.*$/, /^.*不$/, /^人.*$/, /^.*人$/\r\n ]\r\n\r\n for (const pattern of meaninglessPatterns) {\r\n if (pattern.test(word)) {\r\n return false\r\n }\r\n }\r\n\r\n // 检查是否包含重复字符\r\n if (/(.)\\1{2,}/.test(word)) {\r\n return false\r\n }\r\n\r\n return true\r\n }\r\n\r\n /**\r\n * 计算逆文档频率 (IDF) - 简化版本\r\n */\r\n private calculateInverseDocumentFrequency(term: string): number {\r\n // 简化的IDF计算,基于常见词汇频率\r\n const commonTerms = new Set([\r\n '技术', '开发', '代码', '系统', '数据', '功能', '应用', '实现', '方法', '问题',\r\n 'time', 'data', 'system', 'code', 'development', 'application', 'function', 'method', 'problem', 'solution'\r\n ])\r\n\r\n if (commonTerms.has(term.toLowerCase())) {\r\n return Math.log(1000 / 500) // 常见词汇权重较低\r\n }\r\n\r\n return Math.log(1000 / 10) // 稀有词汇权重较高\r\n }\r\n\r\n /**\r\n * 提取关键词\r\n */\r\n extractKeywords(content: string, maxKeywords: number = 10): string[] {\r\n const tf = this.calculateTermFrequency(content)\r\n const keywordScores = new Map<string, number>()\r\n\r\n // 计算 TF-IDF 分数\r\n for (const [term, frequency] of tf) {\r\n const idf = this.calculateInverseDocumentFrequency(term)\r\n const tfidf = frequency * idf\r\n\r\n // 额外的权重规则\r\n let bonus = 1\r\n\r\n // 标题中的词汇权重更高\r\n if (content.toLowerCase().includes(term.toLowerCase()) &&\r\n (content.match(new RegExp(`^${term}`, 'mi')) || content.match(new RegExp(`${term}$`, 'mi')))) {\r\n bonus *= 1.5\r\n }\r\n\r\n // 长度适中的词汇权重更高\r\n if (term.length >= 2 && term.length <= 6) {\r\n bonus *= 1.2\r\n }\r\n\r\n keywordScores.set(term, tfidf * bonus)\r\n }\r\n\r\n // 排序并返回前N个关键词\r\n return Array.from(keywordScores.entries())\r\n .sort((a, b) => b[1] - a[1])\r\n .slice(0, maxKeywords)\r\n .map(([term]) => term)\r\n }\r\n}\r\n\r\n/**\r\n * 从文档内容中提取描述文本\r\n */\r\nfunction extractDescription(content: string, maxLength = 160): string {\r\n // 移除 HTML 标签\r\n const plainText = content\r\n .replace(/<[^>]*>/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim()\r\n\r\n if (plainText.length <= maxLength) return plainText\r\n\r\n // 尝试在句子边界截断\r\n const truncated = plainText.substring(0, maxLength)\r\n const lastSentenceEnd = Math.max(\r\n truncated.lastIndexOf('。'),\r\n truncated.lastIndexOf('!'),\r\n truncated.lastIndexOf('?'),\r\n truncated.lastIndexOf('.'),\r\n truncated.lastIndexOf('!'),\r\n truncated.lastIndexOf('?')\r\n )\r\n\r\n if (lastSentenceEnd > maxLength * 0.7) {\r\n return truncated.substring(0, lastSentenceEnd + 1)\r\n }\r\n\r\n return truncated + '...'\r\n}\r\n\r\n/**\r\n * 从内容中提取关键词(使用TF-IDF算法)\r\n */\r\nfunction extractKeywords(content: string): string[] {\r\n const tfidfExtractor = new TFIDFKeywordExtractor()\r\n return tfidfExtractor.extractKeywords(content, 8)\r\n}\r\n\r\n/**\r\n * 生成文章的 JSON-LD 结构化数据\r\n */\r\nexport function generateArticleJsonLd(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n content: string\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const description = extractDescription(content)\r\n const keywords = extractKeywords(content)\r\n // 从ID中提取创建时间,如果没有则使用updated时间\r\n const datePublished = extractDateFromId(doc.ID)\r\n const dateModified = formatDate(doc.Properties?.updated)\r\n\r\n const jsonLd = {\r\n '@context': 'https://schema.org',\r\n '@type': 'Article',\r\n headline: title,\r\n description: description,\r\n keywords: keywords.join(', '),\r\n datePublished: datePublished,\r\n dateModified: dateModified,\r\n author: {\r\n '@type': 'Person',\r\n name: config.sitemap?.title || '崮生',\r\n url: config.sitemap?.siteLink || ''\r\n },\r\n publisher: {\r\n '@type': 'Organization',\r\n name: config.sitemap?.title || 'OceanPress',\r\n logo: {\r\n '@type': 'ImageObject',\r\n url: `${config.sitemap?.siteLink || ''}/assets/logo.png`\r\n }\r\n },\r\n mainEntityOfPage: {\r\n '@type': 'WebPage',\r\n '@id': pageUrl\r\n },\r\n image: doc.Properties?.['title-img'] ? {\r\n '@type': 'ImageObject',\r\n url: `${config.sitemap?.siteLink || ''}${doc.Properties['title-img'].replace('assets', '/assets')}`,\r\n width: 1200,\r\n height: 630\r\n } : undefined,\r\n wordCount: content.replace(/<[^>]*>/g, '').length,\r\n articleSection: '技术文档',\r\n inLanguage: 'zh-CN'\r\n }\r\n\r\n return `<script type=\"application/ld+json\">\r\n${JSON.stringify(jsonLd, null, 2)}\r\n</script>`\r\n}\r\n\r\n/**\r\n * 生成面包屑导航的 JSON-LD\r\n */\r\nexport function generateBreadcrumbJsonLd(\r\n breadcrumbs: Array<{ name: string; url: string }>\r\n): string {\r\n const itemListElement = breadcrumbs.map((crumb, index) => ({\r\n '@type': 'ListItem',\r\n position: index + 1,\r\n name: crumb.name,\r\n item: crumb.url\r\n }))\r\n\r\n const jsonLd = {\r\n '@context': 'https://schema.org',\r\n '@type': 'BreadcrumbList',\r\n itemListElement: itemListElement\r\n }\r\n\r\n return `<script type=\"application/ld+json\">\r\n${JSON.stringify(jsonLd, null, 2)}\r\n</script>`\r\n}\r\n\r\n/**\r\n * 生成网站的 JSON-LD\r\n */\r\nexport function generateWebsiteJsonLd(config: Config): string {\r\n const jsonLd = {\r\n '@context': 'https://schema.org',\r\n '@type': 'WebSite',\r\n name: config.sitemap?.title || 'OceanPress 站点',\r\n description: config.sitemap?.description || '基于思源笔记的静态站点',\r\n url: config.sitemap?.siteLink || '',\r\n author: {\r\n '@type': 'Person',\r\n name: '崮生'\r\n },\r\n potentialAction: {\r\n '@type': 'SearchAction',\r\n target: {\r\n '@type': 'EntryPoint',\r\n urlTemplate: `${config.sitemap?.siteLink || ''}/search?q={search_term_string}`\r\n },\r\n 'query-input': 'required name=search_term_string'\r\n },\r\n inLanguage: 'zh-CN'\r\n }\r\n\r\n return `<script type=\"application/ld+json\">\r\n${JSON.stringify(jsonLd, null, 2)}\r\n</script>`\r\n}\r\n\r\n/**\r\n * 生成完整的 SEO meta 标签\r\n */\r\nexport function generateSeoMetaTags(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n content: string\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const description = extractDescription(content)\r\n const keywords = extractKeywords(content)\r\n\r\n let metaTags = ''\r\n\r\n // 基础 meta 标签\r\n metaTags += ` <meta name=\"description\" content=\"${description.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta name=\"keywords\" content=\"${keywords.join(', ')}\" />\\n`\r\n metaTags += ` <meta name=\"author\" content=\"${config.sitemap?.title || '崮生'}\" />\\n`\r\n\r\n // Open Graph 标签\r\n metaTags += ` <meta property=\"og:title\" content=\"${title.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta property=\"og:description\" content=\"${description.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta property=\"og:type\" content=\"article\" />\\n`\r\n metaTags += ` <meta property=\"og:url\" content=\"${pageUrl}\" />\\n`\r\n metaTags += ` <meta property=\"og:site_name\" content=\"${config.sitemap?.title || 'OceanPress'}\" />\\n`\r\n\r\n if (doc.Properties?.['title-img']) {\r\n const imageUrl = `${config.sitemap?.siteLink || ''}${doc.Properties['title-img'].replace('assets', '/assets')}`\r\n metaTags += ` <meta property=\"og:image\" content=\"${imageUrl}\" />\\n`\r\n metaTags += ` <meta property=\"og:image:width\" content=\"1200\" />\\n`\r\n metaTags += ` <meta property=\"og:image:height\" content=\"630\" />\\n`\r\n }\r\n\r\n // 从ID中提取创建时间\r\n const datePublished = extractDateFromId(doc.ID)\r\n const dateModified = formatDate(doc.Properties?.updated)\r\n\r\n metaTags += ` <meta property=\"article:published_time\" content=\"${datePublished}\" />\\n`\r\n metaTags += ` <meta property=\"article:modified_time\" content=\"${dateModified}\" />\\n`\r\n\r\n // Twitter Card 标签\r\n metaTags += ` <meta name=\"twitter:card\" content=\"summary_large_image\" />\\n`\r\n metaTags += ` <meta name=\"twitter:title\" content=\"${title.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta name=\"twitter:description\" content=\"${description.replace(/\"/g, '&quot;')}\" />\\n`\r\n\r\n if (doc.Properties?.['title-img']) {\r\n const imageUrl = `${config.sitemap?.siteLink || ''}${doc.Properties['title-img'].replace('assets', '/assets')}`\r\n metaTags += ` <meta name=\"twitter:image\" content=\"${imageUrl}\" />\\n`\r\n }\r\n\r\n // 其他 SEO 标签\r\n metaTags += ` <meta name=\"robots\" content=\"index, follow\" />\\n`\r\n metaTags += ` <link rel=\"canonical\" href=\"${pageUrl}\" />\\n`\r\n\r\n return metaTags\r\n}\r\n\r\n/**\r\n * SEO 数据接口\r\n */\r\nexport interface SeoData {\r\n doc: S_Node\r\n config: Config\r\n pageUrl: string\r\n content: string\r\n breadcrumbs?: Array<{ name: string; url: string }>\r\n}\r\n\r\n/**\r\n * 生成完整的 SEO 优化代码\r\n */\r\nexport function generateSeoContent(data: SeoData): {\r\n metaTags: string\r\n jsonLd: string\r\n} {\r\n const metaTags = generateSeoMetaTags(data.doc, data.config, data.pageUrl, data.content)\r\n\r\n let jsonLd = generateArticleJsonLd(data.doc, data.config, data.pageUrl, data.content)\r\n\r\n if (data.breadcrumbs && data.breadcrumbs.length > 0) {\r\n jsonLd += '\\n' + generateBreadcrumbJsonLd(data.breadcrumbs)\r\n }\r\n\r\n return {\r\n metaTags,\r\n jsonLd\r\n }\r\n}","import { generateSeoContent } from './seo.ts'\r\n\r\n/** 添加对应的 html 模板 */\r\nexport async function htmlTemplate(\r\n p: {\r\n htmlContent: string\r\n title: string\r\n level: number\r\n seoData?: {\r\n doc: any\r\n config: any\r\n pageUrl: string\r\n breadcrumbs?: Array<{ name: string; url: string }>\r\n }\r\n },\r\n config?: {\r\n siyuanPrefix: string\r\n embedCode?: { head?: string; beforeBody?: string; afterBody?: string }\r\n },\r\n) {\r\n /** 根据level有几级返回多少个 '../' ,用于解决 file协议打开html文档无法正常加载资源 */\r\n let prePath = ''\r\n if (config?.siyuanPrefix) {\r\n prePath = config.siyuanPrefix\r\n } else {\r\n for (let i = 0; i < p.level; i++) {\r\n prePath += '../'\r\n }\r\n }\r\n const version = '2.10.5'\r\n /** 思源中导出 html 代码: https://github1s.com/siyuan-note/siyuan/blob/HEAD/app/src/protyle/export/index.ts#L652 */\r\n //data-theme-mode=\"dark\" data-light-theme=\"daylight\" data-dark-theme=\"midnight\"\r\n return `<!DOCTYPE html>\r\n<html lang=\"zh_CN\" data-theme-mode=\"light\" data-light-theme=\"daylight\" data-dark-theme=\"midnight\">\r\n<head>\r\n ${config?.embedCode?.head ?? ''}\r\n <meta charset=\"utf-8\" />\r\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"/>\r\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\r\n <meta name=\"mobile-web-app-capable\" content=\"yes\" />\r\n <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black\" />\r\n ${\r\n p.seoData\r\n ? generateSeoContent({\r\n doc: p.seoData.doc,\r\n config: p.seoData.config,\r\n pageUrl: p.seoData.pageUrl,\r\n content: p.htmlContent,\r\n breadcrumbs: p.seoData.breadcrumbs,\r\n }).metaTags\r\n : ''\r\n }\r\n <link rel=\"stylesheet\" type=\"text/css\" id=\"baseStyle\" href=\"${prePath}stage/build/export/base.css?${version}\"/>\r\n <script>\r\n // 更好的主题切换方案\r\n (function() {\r\n // 主题配置\r\n const themes = {\r\n light: {\r\n name: 'daylight',\r\n mode: 'light',\r\n icon: '☀️'\r\n },\r\n dark: {\r\n name: 'midnight',\r\n mode: 'dark',\r\n icon: '🌙'\r\n },\r\n auto: {\r\n name: 'auto',\r\n mode: 'auto',\r\n icon: '🌗',\r\n getTheme: function() {\r\n const currentHour = new Date().getHours();\r\n return currentHour >= 18 || currentHour < 6 ? 'dark' : 'light';\r\n }\r\n }\r\n };\r\n\r\n // 获取当前主题设置\r\n function getCurrentTheme() {\r\n // 优先级:localStorage > 系统偏好 > auto\r\n const savedTheme = localStorage.getItem('oceanpress-theme');\r\n if (savedTheme && themes[savedTheme]) {\r\n return savedTheme;\r\n }\r\n\r\n // 检测系统偏好\r\n if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {\r\n return 'dark';\r\n }\r\n if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {\r\n return 'light';\r\n }\r\n\r\n return 'auto';\r\n }\r\n\r\n // 应用主题\r\n function applyTheme(themeName) {\r\n const theme = themes[themeName] || themes.auto;\r\n const actualTheme = themeName === 'auto' ? theme.getTheme() : themeName;\r\n const themeConfig = themes[actualTheme];\r\n\r\n // 设置 CSS 变量\r\n document.documentElement.setAttribute('data-theme-mode', themeConfig.mode);\r\n document.documentElement.setAttribute('data-light-theme', 'daylight');\r\n document.documentElement.setAttribute('data-dark-theme', 'midnight');\r\n\r\n // 加载对应的 CSS\r\n const themeStyle = document.getElementById('themeDefaultStyle');\r\n if (themeStyle) {\r\n themeStyle.href = '${prePath}appearance/themes/' + themeConfig.name + '/theme.css?${version}';\r\n } else {\r\n // 如果元素不存在,创建它\r\n const link = document.createElement('link');\r\n link.id = 'themeDefaultStyle';\r\n link.rel = 'stylesheet';\r\n link.type = 'text/css';\r\n link.href = '${prePath}appearance/themes/' + themeConfig.name + '/theme.css?${version}';\r\n document.head.appendChild(link);\r\n }\r\n\r\n // 更新主题切换按钮\r\n updateThemeToggle(themeName);\r\n\r\n // 保存到 localStorage\r\n localStorage.setItem('oceanpress-theme', themeName);\r\n\r\n // 触发自定义事件\r\n window.dispatchEvent(new CustomEvent('oceanpress-theme-changed', {\r\n detail: { theme: themeName, actualTheme: actualTheme }\r\n }));\r\n }\r\n\r\n // 创建主题切换按钮\r\n function createThemeToggle() {\r\n const toggle = document.createElement('div');\r\n toggle.id = 'oceanpress-theme-toggle';\r\n toggle.innerHTML = '<span class=\"theme-icon\">🌗</span><span class=\"theme-text\">自动</span>';\r\n toggle.addEventListener('click', toggleTheme);\r\n (document.querySelector('[data-type=\"NodeDocument\"]')||document.body).appendChild(toggle);\r\n }\r\n\r\n // 更新主题切换按钮\r\n function updateThemeToggle(themeName) {\r\n const toggle = document.getElementById('oceanpress-theme-toggle');\r\n if (!toggle) return;\r\n\r\n const theme = themes[themeName] || themes.auto;\r\n toggle.innerHTML = '<span class=\"theme-icon\">' + theme.icon + '</span><span class=\"theme-text\">' +\r\n (themeName === 'auto' ? '自动' : (themeName === 'dark' ? '深色' : '浅色')) + '</span>';\r\n }\r\n\r\n // 切换主题\r\n function toggleTheme() {\r\n const currentTheme = getCurrentTheme();\r\n const themeOrder = ['auto', 'light', 'dark'];\r\n const currentIndex = themeOrder.indexOf(currentTheme);\r\n const nextIndex = (currentIndex + 1) % themeOrder.length;\r\n const nextTheme = themeOrder[nextIndex];\r\n\r\n applyTheme(nextTheme);\r\n }\r\n\r\n // 监听系统主题变化\r\n if (window.matchMedia) {\r\n window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme === 'auto') {\r\n applyTheme('auto');\r\n }\r\n });\r\n }\r\n\r\n // 监听自定义主题变化事件(用于侧边栏等组件)\r\n window.addEventListener('oceanpress-theme-changed', function(e) {\r\n // 这里可以添加其他组件需要响应主题变化的逻辑\r\n console.log('Theme changed to:', e.detail);\r\n });\r\n\r\n // 初始化主题\r\n function initTheme() {\r\n const themeName = getCurrentTheme();\r\n const theme = themes[themeName] || themes.auto;\r\n const actualTheme = themeName === 'auto' ? theme.getTheme() : themeName;\r\n const themeConfig = themes[actualTheme];\r\n\r\n // 立即设置基础主题,避免闪烁\r\n document.documentElement.setAttribute('data-theme-mode', themeConfig.mode);\r\n document.documentElement.setAttribute('data-light-theme', 'daylight');\r\n document.documentElement.setAttribute('data-dark-theme', 'midnight');\r\n\r\n // 创建主题切换按钮\r\n createThemeToggle();\r\n\r\n // 应用完整主题\r\n applyTheme(themeName);\r\n }\r\n\r\n // 页面加载完成后初始化\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', initTheme);\r\n } else {\r\n initTheme();\r\n }\r\n })();\r\n </script>\r\n <link rel=\"stylesheet\" type=\"text/css\" href=\"${prePath}appearance/oceanpress.css\"/>\r\n <title>${p.title}</title>\r\n ${\r\n p.seoData\r\n ? generateSeoContent({\r\n doc: p.seoData.doc,\r\n config: p.seoData.config,\r\n pageUrl: p.seoData.pageUrl,\r\n content: p.htmlContent,\r\n breadcrumbs: p.seoData.breadcrumbs,\r\n }).jsonLd\r\n : ''\r\n }\r\n</head>\r\n<body>\r\n ${config?.embedCode?.beforeBody ?? ''}\r\n ${p.htmlContent}\r\n <script src=\"${prePath}appearance/icons/material/icon.js?${version}\"></script>\r\n <script src=\"${prePath}stage/build/export/protyle-method.js?${version}\"></script>\r\n <script src=\"${prePath}stage/protyle/js/lute/lute.min.js?${version}\"></script>\r\n <script>\r\n window.siyuan = {\r\n config: {\r\n appearance: {\r\n mode: document.documentElement.getAttribute('data-theme-mode') === 'dark' ? 1 : 0,//主题 明亮=0 暗黑=1\r\n codeBlockThemeDark: \"base16/dracula\",\r\n codeBlockThemeLight: \"github\",\r\n },\r\n editor: {\r\n codeLineWrap: true,\r\n codeLigatures: false,\r\n plantUMLServePath: \"https://www.plantuml.com/plantuml/svg/~1\",\r\n codeSyntaxHighlightLineNum: true,\r\n katexMacros: JSON.stringify({}),\r\n },\r\n },\r\n languages: { copy: \"复制\" },\r\n };\r\n const cdn = \"${prePath}stage/protyle\";\r\n const previewElement = document.getElementById(\"preview\");\r\n\r\n Protyle.highlightRender(previewElement, cdn);\r\n Protyle.mathRender(previewElement, cdn, false);\r\n Protyle.mermaidRender(previewElement, cdn);\r\n Protyle.flowchartRender(previewElement, cdn);\r\n Protyle.graphvizRender(previewElement, cdn);\r\n Protyle.chartRender(previewElement, cdn);\r\n Protyle.mindmapRender(previewElement, cdn);\r\n Protyle.abcRender(previewElement, cdn);\r\n Protyle.htmlRender(previewElement);\r\n Protyle.plantumlRender(previewElement, cdn);\r\n document.querySelectorAll(\".protyle-action__copy\").forEach((item) => {\r\n item.addEventListener(\"click\", (event) => {\r\n navigator.clipboard.writeText(\r\n item.parentElement.nextElementSibling.textContent.trimEnd(),\r\n );\r\n event.preventDefault();\r\n event.stopPropagation();\r\n });\r\n });\r\n </script>\r\n ${config?.embedCode?.afterBody ?? ''}\r\n</body>\r\n</html>`\r\n}\r\n","import { Context, Effect } from 'effect'\r\nimport { escaping, unescaping } from '~/util/escaping.ts'\r\nimport { EffectConfigDep, EffectRender } from './EffectDep.ts'\r\nimport { API } from './siyuan_api.ts'\r\nimport { DB_block, NodeType, S_Node } from './siyuan_type.ts'\r\nimport { renderDocTreeJsPath } from './renderDocTree.ts'\r\n\r\nexport type RenderHTML = typeof renderHTML\r\nexport type Render = Effect.Effect.Success<typeof renderProgram>\r\n\r\n/** 将指定 S_Node 渲染成对应的 html 代码 */\r\nexport const renderHTML = (\r\n sy: S_Node | undefined,\r\n /**\r\n * renderHTML 内部会创建一个 renderInstance 的浅克隆\r\n * 用来维护 renderHTML.nodeStack 的正常运转\r\n */\r\n render?: Render,\r\n) =>\r\n Effect.gen(function* () {\r\n if (sy === undefined) return ''\r\n const defaultRender = yield* getRender\r\n const renderInstance = render ?? defaultRender\r\n const renderObj: Render = {\r\n ...renderInstance,\r\n nodeStack: [\r\n /** 避免让所有的 renderInstance.nodeStack 是同一个对象 ,所以这里复制一个新的 */ ...renderInstance.nodeStack,\r\n ],\r\n }\r\n if (\r\n renderInstance.nodeStack.find(\r\n (node) => node.ID && sy.ID && node.ID === sy.ID,\r\n )\r\n ) {\r\n return warnDiv(\r\n '循环引用',\r\n [...renderInstance.nodeStack, sy].map((el) => el.ID),\r\n )\r\n }\r\n if (renderObj[sy.Type] === undefined) {\r\n return warnDiv(\r\n `没有找到对应的渲染方法 ${sy.Type} ${renderObj.nodeStack[0].Properties?.title}`,\r\n )\r\n } else {\r\n /** 入栈 */\r\n renderObj.nodeStack.push(sy)\r\n /** 维护引用关系 */\r\n if (sy.ID && renderInstance.nodeStack[0]?.ID) {\r\n const storeDep = yield* EffectRender\r\n const id = sy.ID\r\n const targetDoc = yield* Effect.tryPromise(() =>\r\n storeDep.getDocByChildID(id),\r\n )\r\n const currentDoc = renderInstance.nodeStack[0]\r\n if (\r\n targetDoc?.ID !== undefined &&\r\n targetDoc.ID !== currentDoc.ID &&\r\n currentDoc.ID\r\n ) {\r\n /** 代表这个节点不在当前文档中,却在编译currentDoc时出现了,所以 currentDoc依赖(正向引用)targetDoc */\r\n // 记录引用 TODO 不应该在 render中之直接记录,该上报\r\n renderObj.refs.add(targetDoc.ID)\r\n }\r\n }\r\n const r = yield* Effect.tryPromise(() => renderObj[sy.Type]!(sy))\r\n /** 出栈 */\r\n renderObj.nodeStack.pop()\r\n return r\r\n }\r\n })\r\n\r\nfunction warnDiv(msg: string, ...args: any[]) {\r\n warn(msg, ...args)\r\n return `<div class=\"ft__smaller ft__secondary b3-form__space--small\">${msg}</div>`\r\n}\r\nfunction isRenderCode(sy: S_Node) {\r\n const mark = atob(\r\n sy.CodeBlockInfo ??\r\n sy.Children?.find((el) => el.Type === 'NodeCodeBlockFenceInfoMarker')\r\n ?.CodeBlockInfo ??\r\n '',\r\n )\r\n return [\r\n [\r\n 'mindmap',\r\n 'mermaid',\r\n 'echarts',\r\n 'abc',\r\n 'graphviz',\r\n 'flowchart',\r\n 'plantuml',\r\n ].includes(mark),\r\n mark,\r\n ] as const\r\n}\r\nconst html = String.raw\r\n\r\nfunction strAttr(\r\n sy: S_Node,\r\n config: {\r\n subtype_class?: string | [string, string]\r\n data_type?: string\r\n } = {},\r\n) {\r\n if (config?.subtype_class === undefined) {\r\n config.subtype_class = (() => {\r\n const typ_subtype =\r\n sy.ListData?.Typ === 1\r\n ? /** 有序列表 */ 'o'\r\n : sy.ListData?.Typ === 3\r\n ? /** 任务列表 */ 't'\r\n : /** 无序列表 */ 'u'\r\n\r\n if (sy.Type === 'NodeDocument') return ''\r\n else if (sy.Type === 'NodeHeading') return `h${sy.HeadingLevel}`\r\n else if (sy.Type === 'NodeList') return [typ_subtype, 'list']\r\n else if (sy.Type === 'NodeListItem') return [typ_subtype, 'li']\r\n else if (sy.Type === 'NodeParagraph') return ['', 'p']\r\n else if (sy.Type === 'NodeImage') return ['', 'img']\r\n else if (sy.Type === 'NodeBlockquote') return ['', 'bq']\r\n else if (sy.Type === 'NodeSuperBlock') return ['', 'sb']\r\n else if (sy.Type === 'NodeCodeBlock') {\r\n const [yes, mark] = isRenderCode(sy)\r\n if (yes) {\r\n /** 脑图等需要渲染的块 */\r\n return [mark, 'render-node']\r\n } else {\r\n return ['', 'code-block']\r\n }\r\n } else if (sy.Type === 'NodeTable') return ['', 'table']\r\n else if (sy.Type === 'NodeThematicBreak') return ['', 'hr']\r\n else if (sy.Type === 'NodeMathBlock') return ['math', 'render-node']\r\n else if (sy.Type === 'NodeIFrame') return ['', 'iframe']\r\n else if (sy.Type === 'NodeVideo') return ['', 'iframe']\r\n else return ''\r\n })()\r\n }\r\n const attrObj = {} as { [k: string]: string }\r\n function addAttr(key: string, value: string) {\r\n attrObj[key] = value\r\n }\r\n if (sy.ID) {\r\n addAttr('id', sy.ID)\r\n addAttr('data-node-id', sy.ID)\r\n }\r\n\r\n if (sy?.TextMarkType === 'tag') {\r\n addAttr(`data-type`, sy.TextMarkType ?? '')\r\n } else {\r\n addAttr(`data-type`, config?.data_type ?? sy.Type)\r\n }\r\n if (sy.Properties?.updated) addAttr('updated', sy.Properties.updated)\r\n if (config?.subtype_class) {\r\n if (typeof config.subtype_class === 'string') {\r\n addAttr('data-subtype', config.subtype_class)\r\n addAttr('class', config.subtype_class)\r\n } else {\r\n if (config.subtype_class[0] !== '')\r\n addAttr('data-subtype', config.subtype_class[0])\r\n if (config.subtype_class[1] !== '')\r\n addAttr('class', config.subtype_class[1])\r\n }\r\n }\r\n if (sy.Properties) {\r\n Object.entries(sy.Properties).forEach(([k, v]) => addAttr(k, v))\r\n }\r\n if (sy.ListData?.Marker) addAttr('data-marker', atob(sy.ListData.Marker))\r\n if (\r\n /** 任务列表 */ sy.ListData?.Typ === 3 &&\r\n /** 该项被选中 */ sy.Children?.find(\r\n (el) => el.Type === 'NodeTaskListItemMarker',\r\n )?.TaskListItemChecked\r\n ) {\r\n attrObj['class'] = (attrObj['class'] ?? '') + ' protyle-task--done '\r\n }\r\n /** 不折叠任何项目 */ delete attrObj['fold']\r\n /** 避免任意元素上悬停都显示文档标题 */\r\n if (sy.Type === 'NodeDocument') delete attrObj['title']\r\n return Object.entries(attrObj)\r\n .map(([k, v]) => `${k}=\"${v}\"`)\r\n .join(' ')\r\n}\r\n/** 返回空字符串,一般用于不用解析的节点 */\r\nconst _emptyString = async (_sy: S_Node) => ''\r\nconst _dataString = async (sy: S_Node) => sy.Data ?? ''\r\n\r\n/** 对一些数据常量进行处理 */\r\nexport const getRender = Effect.gen(function* () {\r\n const render = yield* renderProgram\r\n return {\r\n ...render,\r\n nodeStack: [],\r\n refs: new Set(),\r\n } as Render\r\n})\r\n\r\nconst renderProgram = Effect.gen(function* () {\r\n const storeDep = yield* EffectRender\r\n const config = yield* EffectConfigDep\r\n const context = Context.empty().pipe(\r\n Context.add(EffectRender, storeDep),\r\n Context.add(EffectConfigDep, config),\r\n )\r\n async function callChildRender(sy: S_Node, renderInstance: Render) {\r\n const children = sy?.Children ?? []\r\n\r\n // 1. 创建所有子节点的渲染任务(并发启动)\r\n const promises = children.map((el) =>\r\n Effect.runPromise(\r\n Effect.provide(renderHTML(el, renderInstance), context),\r\n ),\r\n )\r\n\r\n // 2. 等待所有任务完成,保持原顺序\r\n const results = await Promise.all(promises)\r\n\r\n // 3. 按顺序拼接结果\r\n return results.join('')\r\n }\r\n async function callRenderHTML(sy: S_Node | undefined, render?: Render) {\r\n return Effect.runPromise(Effect.provide(renderHTML(sy, render), context))\r\n }\r\n\r\n const render: {\r\n [key in keyof typeof NodeType]?: (sy: S_Node) => Promise<string>\r\n } & {\r\n /**\r\n * 用于保存调用栈,即从根节点到当前节点。\r\n * 例如在渲染 文档A中引用了文档B中的节点 时调用栈如下\r\n * ```\r\n * nodeStack ~= [A_NodeDocument,A_NodeList,...,A_block-ref,B_Node]\r\n * ```\r\n * 对render中的函数意味着 `this.nodeStack[0]===需要生成的文档`\r\n * 这样就方便解决 block-ref 等链接问题\r\n * */\r\n nodeStack: S_Node[]\r\n /** 当前实例所引用的其他文档id,在渲染中计算 */\r\n refs: Set<string>\r\n /** 返回当前文档到顶层文档的路径前缀,例如: ./../.. */\r\n getTopPathPrefix: (sy_doc?: S_Node) => Promise<string>\r\n } = {\r\n nodeStack: [] as S_Node[],\r\n refs: new Set(),\r\n async getTopPathPrefix() {\r\n const sy = this.nodeStack[0]\r\n let prefix = '.'\r\n if (sy.Type === 'NodeDocument' && sy.ID) {\r\n /** 基于当前文档路径将 href ../ 到顶层 */\r\n const path = await storeDep.getDocPathBySY(sy)\r\n if (path) {\r\n /** path data/box_id/doc_id/doc_id/doc_id.sy `data/box_id/` 这一节是多出来的,所以要减3 */\r\n const level = path.split('/').length - 3\r\n for (let i = 0; i < level; i++) {\r\n prefix += '/..'\r\n }\r\n }\r\n return prefix\r\n } else {\r\n console.log('未定义顶层元素非 NodeDocument 时的处理方式', sy)\r\n return ''\r\n }\r\n },\r\n async NodeDocument(sy) {\r\n /** 对于顶层文档,也就是当前html的主要内容,渲染题头图和标题等其他信息,相比被嵌入的 doc 块需要做一些特殊处理 */\r\n const isTopDoc = this.nodeStack.length === 1\r\n\r\n let html = `<div style=\"min-height: 150px;\" ${strAttr(sy)}>\\n${\r\n /** 题头图 */\r\n isTopDoc && sy.Properties?.['title-img']\r\n ? `<div class=\"protyle-background__img\" style=\"margin-bottom: 30px;position: relative;height: 16vh;${sy.Properties?.[\r\n 'title-img'\r\n ].replace(\r\n /assets/,\r\n // 修改为相对路径\r\n (await this.getTopPathPrefix()) + '/assets',\r\n )}\"/>${\r\n sy.Properties?.['icon']\r\n ? `<div style=\"position: absolute;bottom:-10px;left:15px;height: 80px;width: 80px;transition: var(--b3-transition);cursor: pointer;font-size: 68px;line-height: 80px;text-align: center;font-family: var(--b3-font-family-emoji);margin-right: 16px;\"> &#x${sy.Properties?.['icon']} </div>`\r\n : ''\r\n }</div>`\r\n : ''\r\n }\\n${\r\n /** h1 文档标题 */ isTopDoc\r\n ? `<h1 ${strAttr(sy)} data-type=\"NodeHeading\" class=\"h1\">${\r\n sy.Properties?.title\r\n }</h1>`\r\n : ''\r\n }\\n${await callChildRender(sy, this)}</div>`\r\n /** 添加 protyle-wysiwyg 容器和侧边栏,这里面的才会得到对应的样式效果 */\r\n if (isTopDoc) {\r\n html = `<div class=\"protyle-wysiwyg protyle-wysiwyg--attr\" id=\"preview\">\r\n <div id=\"oceanpress-left-sidebar\">\r\n ${config.sidebarCode.leftCode}\r\n ${\r\n config.sidebarCode.enableDocTree\r\n ? `<div id=\"oceanpress-doctree\"></div>\r\n <script src=\"${await this.getTopPathPrefix()}${renderDocTreeJsPath}\" async></script>`\r\n : ''\r\n }\r\n </div>\r\n ${html}\r\n <div id=\"oceanpress-right-sidebar\">${config.sidebarCode.rightCode}</div>\r\n</div>`\r\n }\r\n return html\r\n },\r\n async NodeHeading(sy) {\r\n const tagName = `h${sy.HeadingLevel}`\r\n let html = `<${tagName} ${strAttr(sy)}>${await callChildRender(\r\n sy,\r\n this,\r\n )}</${tagName}>`\r\n\r\n // 在被嵌入查询块的情况下需要查询渲染其后面的非标题块\r\n const parentNode =\r\n this.nodeStack[\r\n this.nodeStack.length -\r\n 2 /** 最后一个元素是 sy本身(NodeHeading)还得要往前一个,所以是2 */\r\n ]\r\n\r\n if (parentNode?.Type === 'NodeBlockQueryEmbedScript') {\r\n let afterFlag = false\r\n for (const node of sy.Parent.Children ?? []) {\r\n if (node === sy) {\r\n afterFlag = true\r\n } else if (node !== sy && node.Type === 'NodeHeading') {\r\n afterFlag = false\r\n } else if (afterFlag) {\r\n html += '\\n' + (await callRenderHTML(node, this))\r\n }\r\n }\r\n }\r\n return html\r\n },\r\n NodeText: _dataString,\r\n async NodeList(sy) {\r\n return html`<div ${strAttr(sy)}>${await callChildRender(sy, this)}</div>`\r\n },\r\n async NodeListItem(sy) {\r\n return html`<div ${await strAttr(sy)}>\r\n <div class=\"protyle-action\">\r\n ${\r\n sy.ListData?.Typ === 1\r\n ? /** 有序列表 */ atob(sy.ListData?.Marker ?? '')\r\n : sy.ListData?.Typ === 3\r\n ? /** 任务列表 */ `<svg><use xlink:href=\"#${\r\n sy.Children?.find(\r\n (el) => el.Type === 'NodeTaskListItemMarker',\r\n )?.TaskListItemChecked\r\n ? 'iconCheck'\r\n : 'iconUncheck'\r\n }\"></use></svg>`\r\n : /** 无序列表 */ `<svg><use xlink:href=\"#iconDot\"></use></svg>`\r\n }\r\n </div>\r\n ${await callChildRender(sy, this)}\r\n </div>`\r\n },\r\n NodeTaskListItemMarker: _emptyString,\r\n\r\n async NodeParagraph(sy) {\r\n /** .protyle-wysiwyg [data-node-id] [spellcheck] 定义了换行样式 */\r\n return `<div ${strAttr(\r\n sy,\r\n )}><div spellcheck=\"false\">${await callChildRender(sy, this)}</div></div>`\r\n },\r\n async NodeTextMark(sy) {\r\n const that = this\r\n let r: string = ''\r\n /** 从后向前渲染每一层mark ,TextMarkType有可能是 `a sub` |`sub a` | `a` |`code`等 */\r\n for (const type of (\r\n sy.TextMarkType?.split(' ') ?? []\r\n ).reverse() as S_Node['TextMarkType'][]) {\r\n if (r === '') {\r\n r = await TextMarkRender(sy, type, sy.TextMarkTextContent ?? '')\r\n } else {\r\n r = await TextMarkRender(sy, type, r)\r\n }\r\n }\r\n return r\r\n async function TextMarkRender(\r\n sy: S_Node,\r\n type: S_Node['TextMarkType'],\r\n content: string,\r\n ): Promise<string> {\r\n if (type === 'inline-math') {\r\n return `<span data-type=\"inline-math\" data-subtype=\"math\" data-content=\"${sy.TextMarkInlineMathContent}\" class=\"render-node\"></span>`\r\n } else if (type === 'inline-memo' /** 备注 */) {\r\n return `${content}<sup>(${sy.TextMarkInlineMemoContent})</sup>`\r\n } else if (type === 'block-ref' /** 引用块 */) {\r\n let href = ''\r\n if (sy.TextMarkBlockRefID) {\r\n const doc = await storeDep.getDocByChildID(sy.TextMarkBlockRefID)\r\n if (doc?.ID) {\r\n href = `${await that.getTopPathPrefix()}${await storeDep.getHPathByID_Node(\r\n doc /** 要先定位到文档,再通过下面的hash(#)定位到具体元素 */,\r\n )}.html#${sy.TextMarkBlockRefID}`\r\n that.refs.add(doc.ID)\r\n } else {\r\n warn(`未查找到${sy.ID}所指向的文档节点 ${sy.TextMarkBlockRefID}`)\r\n }\r\n } else {\r\n warn(`${sy.ID} 块引用没有设定 ref id`)\r\n }\r\n\r\n return `<span data-type=\"${sy.TextMarkType}\" \\\r\n data-subtype=\"${/** \"s\" */ sy.TextMarkBlockRefSubtype}\" \\\r\n data-id=\"${\r\n /** 被引用块的id */ sy.TextMarkBlockRefID\r\n }\"><a href=\"${href}\">${content}</a></span>`\r\n } else if (type === 'a') {\r\n let href = sy.TextMarkAHref\r\n if (href?.startsWith('assets/')) {\r\n /** TODO 应该有一个统一处理资源的方案 */\r\n href = `${await that.getTopPathPrefix()}/${href}`\r\n }\r\n return `<a href=\"${href}\">${content}</a>`\r\n } else if (\r\n `strong em u s mark sup sub kbd tag code strong code text`.includes(\r\n type ?? '',\r\n )\r\n ) {\r\n return `<span ${strAttr(sy, { data_type: type })}>${content}</span>`\r\n } else {\r\n return warnDiv(\r\n `没有找到对应的渲染器 ${sy.TextMarkType} ${that.nodeStack[0].Properties?.title}`,\r\n )\r\n }\r\n }\r\n },\r\n async NodeImage(sy) {\r\n let link = ''\r\n const LinkDest = sy.Children?.filter((c) => c.Type === 'NodeLinkDest')\r\n if (LinkDest?.length === 1) {\r\n link = await callRenderHTML(LinkDest[0], this)\r\n } else if (LinkDest?.length && LinkDest.length > 1) {\r\n warn('NodeImage 存在多个 LinkDest', sy)\r\n }\r\n\r\n let title = ''\r\n const LinkTitle = sy.Children?.filter((c) => c.Type === 'NodeLinkTitle')\r\n if (LinkTitle?.length === 1) {\r\n title = await callRenderHTML(LinkTitle[0], this)\r\n } else if (LinkTitle?.length && LinkTitle.length > 1) {\r\n warn('NodeImage 存在多个 LinkTitle', sy)\r\n }\r\n return `<span ${await strAttr(sy)} style=\"${\r\n sy.Properties?.['parent-style'] ?? ''\r\n }\">\r\n <img\r\n src=\"${link}\"\r\n data-src=\"${link}\"\r\n title=\"${title}\"\r\n style=\"${sy.Properties?.style ?? ''}\"\r\n loading=\"lazy\"\r\n />\r\n <span class=\"protyle-action__title\">${title}</span></span>`\r\n },\r\n async NodeLinkDest(sy) {\r\n /** 绝对路径 */\r\n if (/^(?:[a-z]+:)?\\/\\/|^(?:\\/)/.test(sy.Data ?? '')) {\r\n return sy.Data ?? ''\r\n }\r\n /** 为相对路径添加正确的前缀 */\r\n return `${await this.getTopPathPrefix()}/${sy.Data}`\r\n },\r\n NodeLinkTitle: _dataString,\r\n NodeKramdownSpanIAL: _emptyString,\r\n async NodeSuperBlock(sy) {\r\n return `<div ${strAttr(sy)} data-sb-layout=\"${childDateByType(\r\n sy,\r\n 'NodeSuperBlockLayoutMarker',\r\n )}\">${await callChildRender(sy, this)}</div>`\r\n },\r\n NodeSuperBlockOpenMarker: _emptyString,\r\n NodeSuperBlockCloseMarker: _emptyString,\r\n NodeSuperBlockLayoutMarker: _emptyString,\r\n async NodeBlockQueryEmbed(sy) {\r\n return `<div ${strAttr(sy)} data-type=\"NodeBlockquote\" class=\"bq\">\\\r\n ${await callChildRender(sy, this)}\\\r\n </div>`\r\n },\r\n NodeOpenBrace: _emptyString,\r\n NodeCloseBrace: _emptyString,\r\n async NodeBlockQueryEmbedScript(sy) {\r\n const sql = sy.Data\r\n if (!sql) {\r\n console.log('no sql', sy)\r\n return html`<pre>${sql}</pre>`\r\n }\r\n let htmlStr = ''\r\n const blocks: DB_block[] = await API.query_sql({\r\n stmt: /** sql 被思源转义了,类似 :SELECT * FROM blocks WHERE id = &#39;20201227174241-nxny1tq&#39;\r\n 所以这里将它转义回来\r\n TODO 当用户确实使用了包含转义的字符串时,这个实现是错误的 */ unescaping(\r\n sql,\r\n ).replace(\r\n /** 我不理解lute为什么这样实现 https://github.com/88250/lute/blob/HEAD/editor/const.go#L38\r\n * https://ld246.com/article/1696750832289\r\n */\r\n /_esc_newline_/g,\r\n '\\n',\r\n ),\r\n }).catch((err) => {\r\n throw new Error(\r\n `sql error: ${err.message}\\nrawSql:${sql}\\nunescapingSql:${unescaping(\r\n sql,\r\n )}`,\r\n )\r\n })\r\n for (const block of blocks) {\r\n const node = await storeDep.getNodeByID(block.id)\r\n if (node === undefined) {\r\n return warnDiv('未找到此块,可能为跨笔记引用', block.id, sql)\r\n }\r\n htmlStr += await callRenderHTML(node, this)\r\n }\r\n\r\n return htmlStr\r\n },\r\n async NodeBlockquote(sy) {\r\n return html`<div ${strAttr(sy)}>${await callChildRender(sy, this)}</div>`\r\n },\r\n NodeBlockquoteMarker: _emptyString,\r\n NodeCodeBlock: async function (sy) {\r\n const [yes, _] = isRenderCode(sy)\r\n if (yes) {\r\n return `<div ${strAttr(sy)} data-content=\"${escaping(\r\n sy.Children?.find((el) => el.Type === 'NodeCodeBlockCode')?.Data ??\r\n '',\r\n )}\">\r\n <div spin=\"1\"></div>\r\n <div class=\"protyle-attr\" contenteditable=\"false\"></div>\r\n </div>`\r\n }\r\n return `<div ${strAttr(sy)}>\r\n <div class=\"protyle-action\">\r\n <span class=\"protyle-action--first protyle-action__language\">${await callRenderHTML(\r\n sy.Children?.find(\r\n (el) => el.Type === 'NodeCodeBlockFenceInfoMarker',\r\n ),\r\n this,\r\n )}</span>\r\n <span class=\"fn__flex-1\"></span><span class=\"protyle-icon protyle-icon--only protyle-action__copy\"><svg><use xlink:href=\"#iconCopy\"></use></svg></span>\r\n </div>\r\n ${await callRenderHTML(\r\n sy.Children?.find((el) => el.Type === 'NodeCodeBlockCode'),\r\n this,\r\n )}\r\n </div>`\r\n },\r\n NodeCodeBlockFenceInfoMarker: async (sy) => atob(sy.CodeBlockInfo ?? ''),\r\n NodeCodeBlockCode: async (sy) =>\r\n `<div class=\"hljs\" spellcheck=\"false\">${sy.Data}</div>`,\r\n NodeCodeBlockFenceOpenMarker: _emptyString,\r\n NodeCodeBlockFenceCloseMarker: _emptyString,\r\n async NodeTable(sy) {\r\n return `<div ${strAttr(sy)}>\r\n <div>\r\n <table spellcheck=\"false\">\r\n <colgroup>\r\n ${sy.TableAligns?.map(() => '<col />').join('')}\r\n </colgroup>\r\n ${await callRenderHTML(\r\n sy.Children?.find((el) => el.Type === 'NodeTableHead'),\r\n this,\r\n )}\r\n <tbody>\r\n ${(\r\n await Promise.all(\r\n sy.Children?.filter((el) => el.Type === 'NodeTableRow').map(\r\n (el) => callRenderHTML(el, this),\r\n ) ?? [],\r\n )\r\n ).join('\\n')}\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>`\r\n },\r\n async NodeTableHead(sy) {\r\n return `<${sy.Data}>${await callChildRender(sy, this)}</${sy.Data}>`\r\n },\r\n async NodeTableRow(sy) {\r\n return `<tr>${await callChildRender(sy, this)}</tr>`\r\n },\r\n async NodeTableCell(sy) {\r\n return `<td>${await callChildRender(sy, this)}</td>`\r\n },\r\n NodeHTMLBlock: async (sy) => `<div ${strAttr(sy)}>${sy.Data}</div>`,\r\n NodeThematicBreak: async (sy) => `<div ${strAttr(sy)}><div></div></div>`,\r\n NodeMathBlock: async (sy) => `<div ${strAttr(\r\n sy,\r\n )} data-content=\"${childDateByType(sy, 'NodeMathBlockContent')}\">\r\n <div spin=\"1\"></div>\r\n </div>`,\r\n NodeMathBlockOpenMarker: _emptyString,\r\n NodeMathBlockCloseMarker: _emptyString,\r\n async NodeIFrame(sy) {\r\n return ` <div ${strAttr(sy)}>\r\n <div class=\"iframe-content\">\r\n ${\r\n /** 资源总是被复制到顶层目录,所以直接跳到顶层即可 */\r\n /** TODO 应该有一个统一处理资源的方案 */\r\n sy.Data?.replace(\r\n /src=\"assets\\//,\r\n `src=\"${await this.getTopPathPrefix()}/assets\\/`,\r\n )\r\n }\r\n </div>\r\n </div>`\r\n },\r\n async NodeVideo(sy) {\r\n return await this.NodeIFrame!(sy)\r\n },\r\n async NodeAudio(sy) {\r\n return await this.NodeIFrame!(sy)\r\n },\r\n /** 虚拟链接 */\r\n NodeHeadingC8hMarker: _emptyString,\r\n async NodeSoftBreak(_sy) {\r\n //TODO 此处实现应该有问题\r\n /** https://zh.wikipedia.org/wiki/零宽空格 */\r\n return '\\u200B'\r\n },\r\n async NodeBr(sy) {\r\n return `<${sy.Data}>`\r\n },\r\n async NodeWidget(sy) {\r\n return `<div ${strAttr(\r\n sy,\r\n )}><img src=\"${await this.getTopPathPrefix()}/assets/widget/${\r\n sy.ID\r\n }.jpg\"/></div>`\r\n },\r\n async NodeBackslash(sy) {\r\n if (sy.Data === undefined || sy.Data === 'span') {\r\n return `${await callChildRender(sy, this)}`\r\n } else {\r\n return warnDiv(\r\n `未定义的 NodeBackslash 处理 ${sy.Data}`,\r\n this.nodeStack[0].Properties?.title,\r\n )\r\n }\r\n },\r\n NodeBackslashContent: _dataString,\r\n }\r\n\r\n return render\r\n})\r\n\r\n/** 获取sy节点的child中第一个type类型节点的data */\r\nfunction childDateByType(sy: S_Node, type: S_Node['Type']) {\r\n return sy.Children?.find((el) => el.Type === type)?.Data\r\n}\r\n\r\nfunction warn(...arg: any[]) {\r\n console.warn('\\n', ...arg)\r\n}\r\n","/** html 实体转义 https://www.sitemaps.org/protocol.html#escaping */\r\nexport function escaping(s: string) {\r\n return s\r\n .replace(/&/g, \"&amp;\")\r\n .replace(/</g, \"&lt;\")\r\n .replace(/>/g, \"&gt;\")\r\n .replace(/\"/g, \"&quot;\")\r\n .replace(/'/g, \"&apos\");\r\n}\r\nexport function unescaping(s: string) {\r\n return s\r\n .replace(/&amp;/g, \"&\")\r\n .replace(/&lt;/g, \"<\")\r\n .replace(/&gt;/g, \">\")\r\n .replace(/&quot;/g, '\"')\r\n .replace(/&apos;/g, \"'\")\r\n .replace(/&#(\\d+);/g, (_sub,code) => {\r\n return String.fromCharCode(Number(code));\r\n });\r\n}\r\n","import { Effect } from 'effect'\nimport { EffectConfigDep } from './EffectDep.ts'\nimport type { DB_block } from './siyuan_type.ts'\nimport { allDocBlock_by_bookId } from './cache.ts'\nimport { API } from './siyuan_api.ts'\nimport { tempConfig } from './config.ts'\n\nexport const renderDocTreeJsPath = `/__oceanpress/docTree.js`\n/** 生成文档树 JS 文件 */\nexport function renderDocTree() {\n return Effect.gen(function* () {\n const config = yield* EffectConfigDep\n const Doc_blocks: DB_block[] = yield* Effect.tryPromise(() =>\n allDocBlock_by_bookId(config.notebook.id),\n )\n /** 获取文档树排序信息 */\n const sortJSON: { [id: string]: number | undefined } =\n yield* Effect.tryPromise(() =>\n API.file_getFile({\n path: `/data/${config.notebook.id}/.siyuan/sort.json`,\n }).then((r) => {\n // 1. 将 ArrayBuffer 转为字符串\n const decoder = new TextDecoder('utf-8')\n const jsonString = decoder.decode(r as ArrayBuffer)\n // 2. 解析字符串为 JSON 对象\n return JSON.parse(jsonString)\n }),\n )\n const docs = Doc_blocks.map((el) => ({\n id: el.id,\n /** 类似 '/record/cssFlex' */\n hpath: el.hpath,\n title: el.content,\n sort: sortJSON[el.id],\n }))\n const tree = buildTree(docs)\n \n // 生成 JS 代码\n const jsCode = generateJSTree(tree)\n return `\n// OceanPress DocTree - 动态加载的文档树\n(function() {\n 'use strict';\n \n // 文档树数据\n const docTreeData = ${jsCode};\n \n // 渲染函数\n function renderDocTree(containerId, options = {}) {\n const container = document.getElementById(containerId);\n if (!container) {\n console.error('Container not found:', containerId);\n return;\n }\n \n const currentPath = options.currentPath || window.location.pathname.replace(/\\\\.html$/, '');\n \n // 生成 HTML\n const html = generateHTMLTree(docTreeData, currentPath);\n container.innerHTML = html;\n \n // 加载样式\n loadStyles();\n \n // 初始化交互\n initInteractions(container, currentPath);\n }\n \n // 检查是否为单一路径(只有单个子节点的文件夹)\n function isSinglePath(node) {\n if (!node.children || node.children.length !== 1) {\n return false;\n }\n \n let current = node;\n while (current.children && current.children.length === 1) {\n current = current.children[0];\n }\n \n // 如果最终节点没有子节点,说明是单一路径\n return !current.children || current.children.length === 0;\n }\n\n // 获取单一路径的所有节点\n function getSinglePathNodes(node) {\n const pathNodes = [node];\n let current = node;\n \n while (current.children && current.children.length === 1) {\n current = current.children[0];\n pathNodes.push(current);\n }\n \n return pathNodes;\n }\n\n // 生成面包屑路径\n function generateBreadcrumb(pathNodes, currentPath) {\n const lastNode = pathNodes[pathNodes.length - 1];\n const isCurrent = lastNode.hpath === currentPath;\n \n let breadcrumbHtml = '<div class=\"breadcrumb-path\">';\n \n pathNodes.forEach((node, index) => {\n if (index > 0) {\n breadcrumbHtml += '<span class=\"breadcrumb-separator\">/</span>';\n }\n \n const isLast = index === pathNodes.length - 1;\n const nodeCurrent = node.hpath === currentPath;\n \n breadcrumbHtml += \\`\n <a href=\"\\${node.hpath}.html\" class=\"breadcrumb-part \\${(isLast && isCurrent) ? 'current' : ''}\" target=\"_top\">\\${node.title}</a>\n \\`;\n });\n \n breadcrumbHtml += '</div>';\n return breadcrumbHtml;\n }\n\n // 生成 HTML 树\n function generateHTMLTree(nodes, currentPath, level = 0) {\n let html = '';\n for (const node of nodes) {\n const isCurrent = node.hpath === currentPath;\n const isActive = isCurrent || (currentPath && node.hpath && currentPath.startsWith(node.hpath));\n \n // 检查是否为单一路径,如果是则显示为面包屑\n if (isSinglePath(node)) {\n const pathNodes = getSinglePathNodes(node);\n html += generateBreadcrumb(pathNodes, currentPath);\n continue;\n }\n \n if (node.children && node.children.length > 0) {\n // 有子节点时使用 details/summary\n const isExpanded = isActive ? 'open' : '';\n html += \\`\n <details class=\"folder\" \\${isExpanded}>\n <summary class=\"folder-summary\">\n <a href=\"\\${node.hpath}.html\" class=\"folder-link \\${isCurrent ? 'current' : ''}\" target=\"_top\">\\${node.title}</a>\n </summary>\n <div class=\"folder-children\" style=\"padding:0 0 0 10px;\">\n \\${generateHTMLTree(node.children, currentPath, level + 1)}\n </div>\n </details>\n \\`;\n } else {\n // 没有子节点的普通项目\n html += \\`\n <div class=\"file \\${isCurrent ? 'current' : ''}\">\n <a href=\"\\${node.hpath}.html\" class=\"file-link\" target=\"_top\">\\${node.title}</a>\n </div>\n \\`;\n }\n }\n return html;\n }\n \n // 加载样式\n function loadStyles() {\n if (document.getElementById('oceanpress-doctree-styles')) return;\n \n const link = document.createElement('link');\n link.id = 'oceanpress-doctree-styles';\n link.rel = 'stylesheet';\n link.type = 'text/css';\n link.href = '${tempConfig.cdn.siyuanPrefix}appearance/docTree.css';\n document.head.appendChild(link);\n }\n \n // 初始化交互\n function initInteractions(container, currentPath) {\n // 为当前页面项添加高亮样式\n const currentItems = container.querySelectorAll('.current');\n currentItems.forEach(item => {\n // 如果是面包屑路径中的当前项,需要特殊处理\n if (item.classList.contains('breadcrumb-part')) {\n item.style.fontWeight = 'bold';\n item.style.color = 'var(--oceanpress-sidebar-current-border)';\n } else {\n // 使用 CSS 变量而不是硬编码颜色\n item.style.backgroundColor = 'var(--oceanpress-sidebar-current-bg)';\n item.style.borderLeft = '3px solid var(--oceanpress-sidebar-current-border)';\n item.style.paddingLeft = '7px';\n }\n });\n \n // 确保当前页面的所有父文件夹都展开\n const currentElements = container.querySelectorAll('.current');\n currentElements.forEach(currentElement => {\n // 向上遍历所有父级 details 元素并展开\n let parent = currentElement.parentElement;\n while (parent) {\n if (parent.tagName === 'DETAILS') {\n parent.setAttribute('open', 'open');\n }\n parent = parent.parentElement;\n }\n });\n \n // 自动滚动到当前页面\n const firstCurrent = container.querySelector('.current');\n if (firstCurrent) {\n setTimeout(() => {\n firstCurrent.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 100);\n }\n \n // 监听主题变化事件,更新高亮样式\n window.addEventListener('oceanpress-theme-changed', function(e) {\n currentItems.forEach(item => {\n if (item.classList.contains('breadcrumb-part')) {\n item.style.fontWeight = 'bold';\n item.style.color = 'var(--oceanpress-sidebar-current-border)';\n } else {\n item.style.backgroundColor = 'var(--oceanpress-sidebar-current-bg)';\n item.style.borderLeft = '3px solid var(--oceanpress-sidebar-current-border)';\n }\n });\n });\n }\n \n // 暴露到全局\n window.OceanPressDocTree = {\n render: renderDocTree,\n data: docTreeData\n };\n \n // 自动渲染(如果容器存在)\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n if (document.getElementById('oceanpress-doctree')) {\n renderDocTree('oceanpress-doctree');\n }\n });\n } else {\n if (document.getElementById('oceanpress-doctree')) {\n renderDocTree('oceanpress-doctree');\n }\n }\n})();\n `\n })\n}\n\n/** 生成 JavaScript 格式的文档树数据 */\nfunction generateJSTree(nodes: DocNode[]): string {\n return JSON.stringify(nodes, null, 2);\n}\n\n\ninterface DocNode {\n id: string\n hpath: string\n title: string\n sort: number | undefined\n children?: DocNode[]\n}\n\nfunction buildTree(docs: DocNode[]): DocNode[] {\n // 1. 创建根节点和路径映射\n const root: DocNode[] = []\n const pathMap: Record<string, DocNode> = {}\n\n // 2. 先按 hpath 排序,确保父节点先处理\n docs.sort((a, b) => a.hpath.localeCompare(b.hpath))\n\n // 3. 构建树结构\n for (const doc of docs) {\n const pathParts = doc.hpath.split('/').filter((part) => part !== '')\n let currentPath = ''\n let parentNode: DocNode | undefined = undefined\n\n // 逐级查找或创建父节点\n for (let i = 0; i < pathParts.length - 1; i++) {\n currentPath += '/' + pathParts[i]\n if (!pathMap[currentPath]) {\n // 创建虚拟父节点\n pathMap[currentPath] = {\n id: 'virtual_' + currentPath,\n hpath: currentPath,\n title: pathParts[i],\n sort: undefined,\n children: [],\n }\n // 添加到父节点的children中\n if (parentNode) {\n parentNode.children = parentNode.children || []\n parentNode.children.push(pathMap[currentPath])\n } else {\n root.push(pathMap[currentPath])\n }\n }\n parentNode = pathMap[currentPath]\n }\n\n // 添加当前节点\n if (parentNode) {\n parentNode.children = parentNode.children || []\n parentNode.children.push(doc)\n } else {\n root.push(doc)\n }\n pathMap[doc.hpath] = doc\n }\n\n // 4. 递归排序\n function sortNodes(nodes: DocNode[]): DocNode[] {\n return nodes\n .map((node) => {\n if (node.children) {\n node.children = sortNodes(node.children)\n }\n return node\n })\n .sort((a, b) => {\n // 有sort值的优先按sort排序,没有sort值的按title排序\n if (a.sort !== undefined && b.sort !== undefined) {\n return a.sort - b.sort\n } else if (a.sort !== undefined) {\n return -1\n } else if (b.sort !== undefined) {\n return 1\n } else {\n return (a.title || '').localeCompare(b.title || '')\n }\n })\n }\n\n return sortNodes(root)\n}\n","/** 基于洋葱 HOOk 机制的插件管理器\r\n * 我感觉这个手搓的插件机制还可以,类型完备,可拓展性强,\r\n */\r\nexport class PluginCenter<T extends Record<string, (...args: any[]) => any>> {\r\n plugins: PluginCenter<T>['pluginType'][] = []\r\n registerPlugin(plugin: PluginCenter<T>['pluginType']) {\r\n this.plugins.push(plugin)\r\n }\r\n removePlugin(plugin: PluginCenter<T>['pluginType']) {\r\n this.plugins = this.plugins.filter((p) => p !== plugin)\r\n }\r\n /** 洋葱hook调用机制的实现 */\r\n callFn<R extends keyof PluginCenter<T>['pluginType']>(\r\n name: R,\r\n fn: GetMiddlewareFunc<Required<PluginCenter<T>['pluginType']>[R]>,\r\n ) {\r\n return ((...arg: any) => {\r\n // 此处可优化,不必每次都重新生成 middlewareRunner\r\n const m = new middlewareRunner(fn)\r\n // 注入 plugins 中的对应中间件\r\n for (const plugin of this.plugins) {\r\n const middleware = plugin[name]\r\n if (middleware) {\r\n m.use(middleware)\r\n }\r\n }\r\n return m.runMiddlewareHandel(...arg)\r\n }) as GetMiddlewareFunc<Required<PluginCenter<T>['pluginType']>[R]>\r\n }\r\n /** 辅助类型,不可调用! */\r\n pluginType: {\r\n [key in keyof PluginCenter<T>['_funMap']]?: FuncMiddlewares<\r\n PluginCenter<T>['_funMap'][key]\r\n >\r\n } = 0 as any\r\n /** 对需要调用的函数进行代理,完成插件hook介入。 */\r\n fun: PluginCenter<T>['_funMap']\r\n constructor(\r\n /** 原始函数映射表,这里的函数全部可以被插件处理 */\r\n public _funMap: T,\r\n ) {\r\n const that = this\r\n // 可以改成生成对象 {} 的方式,比 proxy 开销要小\r\n this.fun = new Proxy({} as T, {\r\n get(_target, propertyKey, receiver) {\r\n const method = Reflect.get(that._funMap, propertyKey, receiver)\r\n if (typeof method === 'function') {\r\n return (...args: any) => {\r\n return that.callFn(\r\n propertyKey as keyof T,\r\n //@ts-ignore 懒得推类型了。属于内部实现,就直接忽略掉吧\r\n method,\r\n )(...args)\r\n }\r\n }\r\n return method\r\n },\r\n })\r\n }\r\n}\r\n\r\ntype GetMiddlewareFunc<T> = T extends FuncMiddlewares<infer R> ? R : never\r\n\r\n// 小中间件实现,接收一个函数 handel 作为最终执行的函数,当执行 runMiddlewareHandel 时等价于执行 Handel\r\n// 通过 use 注册中间件,类似于洋葱路由,先注册的先执行\r\ntype FuncMiddlewares<Handel extends (...args: any[]) => any> = (\r\n ctx: Parameters<Handel>,\r\n next: Handel,\r\n) => ReturnType<Handel>\r\nclass middlewareRunner<Handel extends (...args: any[]) => any> {\r\n middlewares: FuncMiddlewares<Handel>[] = []\r\n constructor(public handel: Handel) {}\r\n use(middleware: FuncMiddlewares<Handel>) {\r\n this.middlewares.push(middleware)\r\n }\r\n runMiddlewareHandel(...ctx: Parameters<typeof this.handel>) {\r\n let index = 0\r\n const next = ((...ctx2: Parameters<Handel>) => {\r\n const middleware = this.middlewares[index]\r\n index++\r\n if (middleware === undefined) {\r\n return this.handel.call(this, ...ctx2)\r\n }\r\n return middleware(ctx2, next)\r\n }) as Handel\r\n return next.call(this, ...ctx)\r\n }\r\n}\r\n","import { MeilisearchPlugin } from '~/plugins/meilisearch_plugin/meilisearch_upload.ts'\r\nimport { deployOceanPressServer_plugin } from '~/plugins/publish/OceanPressServer.ts'\r\nimport { s3Upload_plugin } from '~/plugins/publish/s3.ts'\r\nimport { FileTree, build } from './build.ts'\r\nimport { Config } from './config.ts'\r\nimport type { effectLog } from './EffectDep.ts'\r\nimport { PluginCenter } from './plugin.ts'\r\nimport { renderHTML } from './render.ts'\r\n\r\nexport type OceanPressPlugin = PluginCenter<OceanPress['funMap']>['pluginType']\r\n\r\n/** OceanPress 核心类,用于管理插件和配置,执行构建过程。 */\r\nexport class OceanPress {\r\n build() {\r\n const build_res = this.pluginCenter.fun.build(this.config, {\r\n renderHtmlFn: this.pluginCenter.fun.build_renderHTML,\r\n onFileTree: this.pluginCenter.fun.build_onFileTree,\r\n })\r\n return build_res\r\n }\r\n funMap = {\r\n /** 开始整体编译 */\r\n build,\r\n /** 用于渲染文档的函数 */\r\n build_renderHTML: renderHTML,\r\n /** 编译完成后文件树的处理回调函数 */\r\n build_onFileTree: (_tree: FileTree, _effectApi: effectLog) => {},\r\n }\r\n pluginCenter: PluginCenter<OceanPress['funMap']> = new PluginCenter(\r\n this.funMap,\r\n )\r\n constructor(public config: Config) {\r\n // TODO 内置插件,以后应该改成由用户配置\r\n if (config.meilisearch.enable) {\r\n this.pluginCenter.registerPlugin(\r\n new MeilisearchPlugin(config.meilisearch),\r\n )\r\n }\r\n if (config.s3.enable) {\r\n this.pluginCenter.registerPlugin(s3Upload_plugin)\r\n }\r\n if (config.oceanPressServer.enable) {\r\n this.pluginCenter.registerPlugin(\r\n deployOceanPressServer_plugin(this.config),\r\n )\r\n }\r\n }\r\n}\r\n","import { get_block_by_id, get_doc_by_child_id } from './cache.ts'\r\nimport { DB_block_path, type S_Node } from './siyuan_type.ts'\r\n\r\n/** 通过 fetch 实现的平台无关 api 依赖 */\r\nexport const renderApiDep = {\r\n getDocByChildID: async (id: string) => {\r\n return await get_doc_by_child_id(id)\r\n },\r\n\r\n getDocPathBySY: async (sy?: S_Node) => {\r\n if (sy?.ID) {\r\n const block = await get_block_by_id(sy.ID)\r\n if (block) {\r\n return DB_block_path(block)\r\n }\r\n }\r\n },\r\n\r\n /** TODO 应该可以从cache中获取,而不需要查询 */\r\n getHPathByID_Node: async (id_node: string | S_Node): Promise<string> => {\r\n const id = typeof id_node === 'string' ? id_node : id_node.ID\r\n if (id === undefined) throw new Error('id is undefined')\r\n const docNode = await get_doc_by_child_id(id)\r\n if (docNode === undefined) throw new Error('docNode is undefined')\r\n const docBlock = await get_block_by_id(id)\r\n if (docBlock === undefined) throw new Error('docBlock is undefined')\r\n return docBlock.hpath\r\n },\r\n\r\n getNodeByID: async (id?: string): Promise<S_Node | undefined> => {\r\n if (id === undefined) return\r\n const doc = await renderApiDep.getDocByChildID(id)\r\n if (doc === undefined) return\r\n return getNode(doc)\r\n function getNode(node: S_Node): S_Node | undefined {\r\n if (node.ID === id) return node\r\n if (node.Children === undefined) return\r\n for (const child of node.Children) {\r\n const n = getNode(child)\r\n if (n) return n\r\n }\r\n }\r\n },\r\n log(msg: string) {\r\n console.log(msg)\r\n },\r\n percentage: (n: number) => {\r\n console.log(n)\r\n },\r\n}\r\n","import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'node:fs'\r\n\r\nexport function setItem(key: string, value: string) {\r\n if (!existsSync('./store/')) {\r\n // 目录不存在,递归创建目录\r\n mkdirSync('./store/', { recursive: true })\r\n }\r\n return writeFileSync(`./store/${key}`, value, {\r\n encoding: 'utf-8',\r\n })\r\n}\r\n\r\nexport function getItem(key: string): string | undefined {\r\n try {\r\n return readFileSync(`./store/${key}`, 'utf-8')\r\n } catch (_) {\r\n return undefined\r\n }\r\n}\r\nexport const nodeApiDep = {\r\n setItem,\r\n getItem,\r\n}\r\n","import '~/core/render.api.dep.ts'\nimport '~/util/store.node.dep.ts'\nimport { Command } from 'commander'\n\nexport const program = new Command()\n\nprogram\n .name('OceanPress')\n .description('这是一款从思源笔记本生成一个静态站点的工具')\n","import { mkdir, readFile, writeFile } from 'fs/promises'\nimport { resolve } from 'path'\nimport { join } from 'path/posix'\nimport { currentConfig, loadConfigFile } from '~/core/config.ts'\nimport { OceanPress } from '~/core/ocean_press.ts'\nimport { program } from './common.ts'\nimport { Context, Effect } from 'effect'\nimport {\n EffectRender,\n EffectLocalStorageDep,\n EffectLogDep,\n EffectConfigDep,\n} from '~/core/EffectDep.ts'\nimport { renderApiDep } from '~/core/render.api.dep.ts'\nimport { nodeApiDep } from '~/util/store.node.dep.ts'\n\nprogram\n .command('build')\n .description('输出静态站点源码')\n .option('-c, --config <string>', '指定配置文件的位置')\n .option('-o, --output <string>', '指定输出目录位置')\n .action(async (opt: { config: string; output: string }) => {\n if (!opt.config || !opt.output) {\n console.log(`请设置配置文件位置和输出目录位置`)\n throw new Error('请设置配置文件位置和输出目录位置')\n }\n const config = await readFile(opt.config, 'utf-8')\n const filePath = resolve(opt.output)\n\n /** 先加载配置 */\n await Effect.runPromise(\n Effect.provideService(\n loadConfigFile(JSON.parse(config)),\n EffectLocalStorageDep,\n nodeApiDep,\n ),\n )\n const context = Context.empty().pipe(\n Context.add(EffectRender, renderApiDep),\n Context.add(EffectLocalStorageDep, nodeApiDep),\n Context.add(EffectConfigDep, currentConfig.value),\n Context.add(EffectLogDep, {\n log: (msg) => {\n if (msg.startsWith('渲染:')) {\n process.stdout.write(`\\r\\x1b[K${msg}`)\n } else {\n process.stdout.write(`\\n${msg}`)\n }\n },\n percentage: (n) => {\n process.stdout.write(`\\r\\x1b[K进度:${n}%`)\n },\n }),\n )\n\n const p = Effect.provide(\n Effect.gen(function* () {\n const ocean_press = new OceanPress(currentConfig.value)\n\n // node 端写磁盘插件\n ocean_press.pluginCenter.registerPlugin({\n async build_onFileTree([tree]) {\n for (const [path, data] of Object.entries(tree)) {\n const fullPath = join(filePath, './', path)\n const pathArray = fullPath.split('/').slice(0, -1)\n const dirPath = pathArray.join('/')\n mkdir(dirPath, { recursive: true })\n try {\n if (typeof data === 'string') {\n await writeFile(fullPath, data, 'utf-8')\n } else {\n await writeFile(fullPath, new DataView(data))\n }\n } catch (error) {\n console.log(`${fullPath} 无法写入`)\n }\n }\n },\n })\n\n console.log('[config.__current__]', JSON.parse(config).__current__)\n console.log('[currentConfig.value.name]', currentConfig.value.name)\n return yield* ocean_press.build()\n }),\n context,\n )\n await Effect.runPromise(p)\n })\n","import { readFile } from 'fs/promises'\nimport { setCache } from '~/core/cache.ts'\nimport { loadConfigFile, tempConfig } from '~/core/config.ts'\nimport { server } from '~/server.ts'\nimport { program } from './common.ts'\nimport { Context, Effect } from 'effect'\nimport {\n EffectRender,\n EffectLocalStorageDep,\n EffectLogDep,\n} from '~/core/EffectDep.ts'\nimport { renderApiDep } from '~/core/render.api.dep.ts'\nimport { nodeApiDep } from '~/util/store.node.dep.ts'\nprogram\n .command('server')\n .description('启动动态代理')\n .option('-c, --config <string>', '指定配置文件的位置')\n .option('-h, --host <string>', 'web服务绑定到的地址', '127.0.0.1')\n .option('-p, --port <number>', 'web服务绑定到的端口', '80')\n .option(\n '--cache <boolean>',\n '配置为 true 时开启缓存,默认为 false 不开启缓存',\n 'false',\n )\n .action(\n async (opt: {\n config: string\n host: string\n port: string\n cache: 'false'\n }) => {\n if (!opt.config) {\n console.log(`请设置配置文件位置`)\n }\n const config = await readFile(opt.config, 'utf-8')\n setCache(opt.cache !== 'false')\n\n const context = Context.empty().pipe(\n Context.add(EffectRender, renderApiDep),\n Context.add(EffectLocalStorageDep, nodeApiDep),\n Context.add(EffectLogDep, {\n log: (msg) => {\n if (msg.startsWith('渲染:')) {\n process.stdout.write(`\\r\\x1b[K${msg}`)\n } else {\n process.stdout.write(`\\n${msg}`)\n }\n },\n percentage: (n) => {\n process.stdout.write(`\\r\\x1b[K进度:${n}%`)\n },\n }),\n )\n\n const p = Effect.provide(\n Effect.gen(function* () {\n yield* loadConfigFile(JSON.parse(config))\n /** 使用本地的文件,方便调试 */\n tempConfig.cdn.siyuanPrefix = '/notebook/'\n return yield* server({\n hostname: opt.host,\n port: Number(opt.port),\n })\n }),\n context,\n )\n\n await Effect.runPromise(p)\n },\n )\n","import { serve } from '@hono/node-server'\r\nimport { serveStatic } from '@hono/node-server/serve-static'\r\nimport { Effect } from 'effect'\r\nimport { Hono } from 'hono'\r\nimport { EffectRender } from './core/EffectDep.ts'\r\nimport { createHonoApp } from './core/hono_server.ts'\r\n\r\nexport function server(config = { port: 80, hostname: '0.0.0.0' }) {\r\n return Effect.gen(function* () {\r\n const app = new Hono()\r\n // 方便开发调试样式\r\n app.use(\r\n '/notebook/*',\r\n serveStatic({\r\n root: './public/',\r\n onNotFound(path, c) {\r\n console.log('[onNotFound notebook path]', path)\r\n // ./public/notebook/appearance/fonts/JetBrainsMono-2.304/JetBrainsMono-Regular.woff2\r\n // ./public/notebook/appearance/fonts\\JetBrainsMono-2.304/JetBrainsMono-Regular.woff2\r\n },\r\n }),\r\n )\r\n const effectDep = yield* EffectRender\r\n createHonoApp(app, effectDep)\r\n return new Promise((resolve, _reject) => {\r\n serve(\r\n {\r\n fetch: app.fetch,\r\n port: config.port,\r\n hostname: config.hostname,\r\n },\r\n (info) => {\r\n resolve({ info, app })\r\n console.log(`Listening on http://${info.address}:${info.port}`)\r\n },\r\n )\r\n })\r\n })\r\n}\r\n","import { Context as HonoContext, Hono } from 'hono'\r\nimport { currentConfig, tempConfig } from './config.ts'\r\nimport { get_doc_by_hpath } from './cache.ts'\r\nimport { htmlTemplate } from './htmlTemplate.ts'\r\nimport { renderHTML } from './render.ts'\r\nimport { stream } from 'hono/streaming'\r\nimport type { StatusCode } from 'hono/utils/http-status'\r\nimport { Effect, Context } from 'effect'\r\nimport {\r\n EffectConfigDep,\r\n EffectRender,\r\n type EffectRenderApi,\r\n} from './EffectDep.ts'\r\nimport { renderDocTree, renderDocTreeJsPath } from './renderDocTree.ts'\r\n\r\nexport function createHonoApp(\r\n app: Hono = new Hono(),\r\n renderapi: EffectRenderApi,\r\n) {\r\n const context = Context.empty().pipe(\r\n Context.add(EffectRender, renderapi),\r\n Context.add(EffectConfigDep, currentConfig.value),\r\n )\r\n /** 处理文档树的接口 */\r\n app.get(renderDocTreeJsPath, async (c) => {\r\n const p = Effect.provide(renderDocTree(), context)\r\n const r = await Effect.runPromise(p)\r\n return c.text(r, 200, {\r\n 'Content-Type': 'application/javascript',\r\n 'Cache-Control': 'public, max-age=3600'\r\n })\r\n })\r\n app.get('/', (c) => c.redirect('/index.html'))\r\n\r\n app.get('/assets/*', assetsHandle)\r\n app.get('/favicon.ico', assetsHandle)\r\n app.get('*', async (c) => {\r\n const path = decodeURIComponent(c.req.path)\r\n\r\n const p = Effect.provide(renderHtmlByUriPath(path), context)\r\n const r = await Effect.runPromise(p)\r\n return c.html(r)\r\n })\r\n return app\r\n}\r\nasync function assetsHandle(c: HonoContext) {\r\n // TODO 处于安全考虑应该防范 file 跳出 assets\r\n const file = c.req.path\r\n const widgetPrefix = '/assets/widget/'\r\n const isWidget = file.startsWith(widgetPrefix)\r\n const apiPath = `${currentConfig.value.apiPrefix}${\r\n isWidget ? '/api/file/getFile' : file\r\n }`\r\n const r = await fetch(apiPath, {\r\n headers: {\r\n Authorization: `Token ${currentConfig.value.authorized}`,\r\n },\r\n method: isWidget ? 'POST' : 'GET',\r\n body: isWidget\r\n ? JSON.stringify({\r\n path: `/data/storage/oceanpress/widget_img/${file.substring(\r\n widgetPrefix.length,\r\n )}`,\r\n })\r\n : undefined,\r\n })\r\n const body = r.body\r\n if (!body) {\r\n return c.text('响应体为 null', 500, { 'Content-Type': 'text/plain' })\r\n }\r\n c.status(r.status as StatusCode)\r\n return stream(c, async (writeStream) => {\r\n const reader = body.getReader()\r\n while (true) {\r\n const r = await reader.read()\r\n if (r.done) {\r\n writeStream.close()\r\n break\r\n } else {\r\n writeStream.write(r.value)\r\n }\r\n }\r\n })\r\n}\r\n/** 渲染文档,通过 path 路径 */\r\nfunction renderHtmlByUriPath(path: string) {\r\n\r\n return Effect.gen(function* () {\r\n const hpath = decodeURIComponent(path)\r\n .replace(/\\#(.*)?$/, '')\r\n .replace(/\\.html$/, '')\r\n\r\n const doc = yield* Effect.tryPromise(() => get_doc_by_hpath(hpath))\r\n const htmlContent = yield* renderHTML(doc)\r\n return yield* Effect.tryPromise(() =>\r\n htmlTemplate(\r\n {\r\n title: doc.Properties?.title || '',\r\n htmlContent,\r\n level: path.split('/').length - 1 /** 最开头有一个 / */,\r\n },\r\n {\r\n ...tempConfig.cdn,\r\n embedCode: currentConfig.value.embedCode,\r\n },\r\n ),\r\n )\r\n })\r\n}\r\n","\r\n\r\nimport './cli/deploy.ts'\r\nimport './cli/build.ts'\r\nimport './cli/server.ts'\r\nimport { program } from './cli/common.ts'\r\n\r\nprogram.parse(process.argv)\r\n"],"mappings":"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","names":["API","stringify","html","html","c","res","Effect","watch","watch","usePromiseComputed","fn","version","Context","Effect","Effect","Effect","Effect","Context","render","html","sy","Effect","process","docBlock","Context","Effect","stringify","Context","Effect","readFile","Context","Effect","readFile","Effect","Context","readFile","Effect","Hono","Effect","Context","Context","Effect","r","Effect","Hono","resolve","Context","Effect","readFile","Context","Effect"]}
1
+ {"version":3,"sources":["../src/cli/deploy.ts","../../rpc/src/createRPC.ts","../src/core/config.ts","../package.json","../src/util/deep_assign.ts","../src/core/EffectDep.ts","../src/core/genZip.ts","../src/plugins/meilisearch_plugin/meilisearch_upload.ts","../src/plugins/publish/OceanPressServer.ts","../src/plugins/publish/s3.ts","../src/core/build.ts","../src/components/data_promise/index.ts","../src/core/siyuan_api.ts","../src/core/siyuan_type.ts","../src/core/cache.ts","../src/core/genRssXml.ts","../src/core/seo.ts","../src/core/htmlTemplate.ts","../src/core/render.ts","../src/util/escaping.ts","../src/core/renderDocTree.ts","../src/core/plugin.ts","../src/core/ocean_press.ts","../src/core/render.api.dep.ts","../src/util/store.node.dep.ts","../src/cli/common.ts","../src/cli/build.ts","../src/cli/server.ts","../src/server.ts","../src/core/hono_server.ts","../src/cli.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { createRPC } from 'oceanpress-rpc'\nimport type { API } from 'oceanpress-server'\nimport { stringify } from 'superjson'\nimport { currentConfig, loadConfigFile } from '~/core/config.ts'\nimport { genZIP } from '~/core/genZip.ts'\nimport { OceanPress } from '~/core/ocean_press.ts'\nimport { program } from './common.ts'\nimport { Context, Effect } from 'effect'\nimport {\n EffectRender,\n EffectLocalStorageDep,\n EffectLogDep,\n EffectConfigDep,\n} from '~/core/EffectDep.ts'\nimport { renderApiDep } from '~/core/render.api.dep.ts'\nimport { nodeApiDep } from '~/util/store.node.dep.ts'\n\nprogram\n .command('deploy')\n .description('部署站点')\n .option('-c, --config <string>', '指定配置文件的位置')\n .option('-h, --apiBase <string>', 'OceanPress server 地址')\n .option('-k, --apiKey <string>', 'OceanPress server Api 密钥')\n .action(async (opt: { config: string; apiBase: string; apiKey: string }) => {\n if (!opt.apiBase || !opt.apiKey) {\n return console.error(`请配置 apiBase 和 apiKey`)\n }\n const config = await readFile(opt.config, 'utf-8')\n\n const client = await createRPC<API>('apiConsumer', {\n remoteCall(method, data) {\n let body: ReadableStream | string\n // 如果第一参数是 ReadableStream 的时候,直接使用 ReadableStream 作为 body,不用考虑其他参数,因为这种情况只支持一个参数\n let content_type\n if (data[0] instanceof ReadableStream) {\n body = data[0]\n content_type = 'application/octet-stream'\n } else {\n body = stringify(data)\n console.log('[body]', body)\n content_type = 'application/json'\n }\n return fetch(`${opt.apiBase}/api/${method}`, {\n method: 'POST',\n body,\n headers: {\n 'x-api-key': opt.apiKey,\n 'Content-Type': content_type,\n },\n // @ts-expect-error 在 node 运行的时候需要声明双工模式才能正确发送 ReadableStream,TODO 需要验证浏览器端可以这样运行吗\n duplex: 'half', // 关键:显式声明半双工模式\n })\n .then((res) => res.json())\n .then((r) => {\n if (r.error) {\n console.log('[r]', r)\n throw new Error()\n }\n return r.result\n })\n },\n })\n\n const context = Context.empty().pipe(\n Context.add(EffectRender, renderApiDep),\n Context.add(EffectLocalStorageDep, nodeApiDep),\n Context.add(EffectConfigDep, currentConfig.value),\n Context.add(EffectLogDep, {\n log: (msg) => {\n if (msg.startsWith('渲染:')) {\n process.stdout.write(`\\r\\x1b[K${msg}`)\n } else {\n process.stdout.write(`\\n${msg}`)\n }\n },\n percentage: (n) => {\n process.stdout.write(`\\r\\x1b[K进度:${n}%`)\n },\n }),\n )\n const p = Effect.provide(\n Effect.gen(function* () {\n yield* loadConfigFile(JSON.parse(config))\n const ocean_press = new OceanPress(currentConfig.value)\n\n ocean_press.pluginCenter.registerPlugin({\n async build_onFileTree([tree], next) {\n const zip = await genZIP(tree, { withoutZip: true })\n const sizeInMB = zip.size / (1024 * 1024)\n console.log('[zip.size in MB]', sizeInMB.toFixed(2))\n // 将 Blob 转换为 ReadableStream\n const readableStream = zip.stream()\n const { chunkCount, fileId } = await client.API.upload(\n readableStream,\n )\n\n console.log('[res]', { chunkCount, fileId })\n const res = await client.API.deploy({ zipFileId: fileId })\n console.log('[deploy res]', res)\n },\n })\n\n return yield* ocean_press.build()\n }),\n context,\n )\n\n await Effect.runPromise(p)\n })\n","/** ═════════🏳‍🌈 超轻量级的远程调用,完备的类型提示! 🏳‍🌈═════════ */\n\ninterface commonOptions {\n middleware?: ((method: string, data: any[], next: () => Promise<any>) => Promise<any>)[]; // 统一的中间件\n}\n\nexport async function createRPC<API_TYPE>(\n ...[type, options]:\n | [\n 'apiProvider',\n commonOptions & {\n genApiModule: () => Promise<API_TYPE>;\n },\n ]\n | [\n 'apiConsumer',\n commonOptions & {\n /** 配置此选项替换默认的远程调用函数,默认逻辑采用 fetch 实现。 */\n remoteCall: (method: string, data: any[]) => Promise<any>; // 远程调用函数\n },\n ]\n) {\n const apiModule = type === 'apiProvider' ? await options.genApiModule() : undefined;\n\n const remoteCall = type === 'apiConsumer' ? options.remoteCall : undefined;\n\n async function RC<K extends string>(method: K, data: any[]): Promise<any> {\n // 洋葱路由的核心逻辑\n async function executeMiddleware(index: number): Promise<any> {\n if (options.middleware && index < options.middleware.length) {\n return options.middleware[index](method, data, () => executeMiddleware(index + 1));\n } else {\n return executeCall();\n }\n }\n\n async function executeCall(): Promise<any> {\n try {\n if (type === 'apiProvider') {\n const methodParts = method.split('.');\n let currentObj: any = apiModule;\n for (const part of methodParts) {\n if (currentObj && typeof currentObj === 'object' && part in currentObj) {\n currentObj = currentObj[part];\n } else {\n throw new Error(`Method ${method} not found`);\n }\n }\n if (typeof currentObj === 'function') {\n return await currentObj(...data);\n } else {\n throw new Error(`${method} is not a function`);\n }\n } else {\n return await remoteCall!(method, data);\n }\n } catch (error) {\n console.error('API call failed:', error);\n throw error;\n }\n }\n\n return await executeMiddleware(0);\n }\n\n /** Remote call , 会就近的选择是远程调用还是使用本地函数 */\n\n /** 创建嵌套的Proxy处理器 */\n function createNestedProxy(path: string[] = []): ProxyHandler<object> {\n return {\n get(target, prop: string) {\n if (prop === 'then') {\n // Handle the case when the proxy is accidentally treated as a Promise\n return undefined;\n }\n const newPath = [...path, prop];\n return new Proxy(function (...args: any[]) {\n const method = newPath.join('.');\n return RC(method, args);\n }, createNestedProxy(newPath));\n },\n apply(target, thisArg, args) {\n const method = path.join('.');\n return RC(method, args);\n },\n };\n }\n /** 包装了一次的 RC 方便跳转到函数定义 */\n const API = new Proxy(function () {}, createNestedProxy()) as unknown as NestedAsyncAPI<API_TYPE>;\n return { API, RC };\n}\n\ntype AsyncifyReturnType<T> = T extends (...args: any[]) => infer R\n ? R extends Promise<any>\n ? T\n : (...args: Parameters<T>) => Promise<Awaited<R>>\n : T;\n\ntype DeepAsyncify<T> = T extends (...args: any[]) => any\n ? AsyncifyReturnType<T>\n : T extends object\n ? { [K in keyof T]: DeepAsyncify<T[K]> }\n : T;\n/** 因为如果是客户端调用,那么返回值必须要是 promise 风格的,所以使用这个类型来将所有返回值的类型包裹一层promise */\ntype NestedAsyncAPI<T> = {\n [K in keyof T]: DeepAsyncify<T[K]>;\n};\n","import { Effect } from 'effect';\r\nimport { computed, reactive, watch } from 'vue';\r\nimport packageJson from '~/../package.json' with { type: 'json' };\r\nimport { deepAssign } from '~/util/deep_assign.ts';\r\nimport { EffectLocalStorageDep } from './EffectDep.ts';\r\nimport { notebook } from './siyuan_type.ts';\r\nconst version = packageJson.version\r\nconsole.log('[version]',version);\r\n/** 不要在运行时修改这个对象,他只应该在代码中配置 */\r\nconst defaultConfig = {\r\n name: 'default',\r\n /** 需要编译的笔记本 */\r\n notebook: {} as notebook,\r\n /** 思源的鉴权key */\r\n authorized: '',\r\n /** 思源的api服务地址 */\r\n apiPrefix: 'http://127.0.0.1:6806',\r\n /** 打包成 zip */\r\n compressedZip: true,\r\n /** 不将 publicZip 打包到 zip 包中 */\r\n // withoutPublicZip: true,\r\n /** 不复制 assets/ ,勾选此选项则需要自行处理资源文件 */\r\n excludeAssetsCopy: false,\r\n /** 输出站点地图相关 */\r\n sitemap: {\r\n /** 控制是否输出 sitemap.xml,不影响 rss 选项 */\r\n enable: true,\r\n /** 默认为 \".\" 生成路径例如 \"./record/思源笔记.html\"\r\n * 但 sitemap 并不建议采用相对路径所以应该替换成例如 \"https://shenzilong.cn\"\r\n * 则会生成 \"https://shenzilong.cn/record/思源笔记.html\" 这样的绝对路径\r\n * 参见 https://www.sitemaps.org/protocol.html#escaping\r\n */\r\n sitePrefix: '.',\r\n /** 站点地址 */\r\n siteLink: '',\r\n /** 站点描述 */\r\n description: '',\r\n /** 站点标题 */\r\n title: '',\r\n /** 开启 rss 生成,对于文件名为 .rss.xml 结尾的文档生效 */\r\n rss: true,\r\n },\r\n /** 开启增量编译,当开启增量编译时,\r\n * 在编译过程中会依据 __skipBuilds__ 的内容来跳过一些没有变化不需要重新输出的内容\r\n */\r\n enableIncrementalCompilation: false,\r\n /**\r\n * 要全量编译文档时将此选项设置为false,当OceanPress版本和上次编译时不同时会忽略此属性全量编译文档\r\n */\r\n enableIncrementalCompilation_doc: true,\r\n /** 跳过编译的资源 */\r\n __skipBuilds__: {} as {\r\n [id: string]:\r\n | {\r\n hash?: string\r\n /** 此文档正向引用的其他文档的id */ refs?: string[]\r\n /** 挂件快照的更新时间 */ updated?: string\r\n }\r\n | undefined\r\n },\r\n\r\n // cdn: {\r\n // /** 思源 js、css等文件的前缀 */\r\n // siyuanPrefix:\r\n // 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@v0.0.7/apps/frontend/public/notebook/',\r\n // /** 思源 js、css等文件zip包地址 */\r\n // publicZip:\r\n // 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@v0.0.7/apps/frontend/public/public.zip',\r\n // },\r\n /** 部署到 s3 上传配置\r\n * https://help.aliyun.com/zh/oss/developer-reference/use-amazon-s3-sdks-to-access-oss#section-2ri-suq-pb3\r\n */\r\n s3: {\r\n enable: false,\r\n bucket: '',\r\n region: '',\r\n pathPrefix: '',\r\n endpoint: '',\r\n accessKeyId: '',\r\n secretAccessKey: '',\r\n },\r\n /** 部署到 oceanPressServer 的配置 */\r\n oceanPressServer:{\r\n enable: false,\r\n apiBase:'',\r\n apiKey:'',\r\n },\r\n meilisearch: {\r\n enable: false,\r\n host: '',\r\n apiKey: '',\r\n indexName: '',\r\n },\r\n /** html模板嵌入代码块,会将此处配置中的代码嵌入到生成的html所对应的位置 */\r\n embedCode: {\r\n head: '',\r\n beforeBody: '',\r\n afterBody: `<footer>\r\n<p style=\"text-align:center;margin:15px 0;\">\r\n 技术支持:\r\n <a target=\"_blank\" href=\"https://github.com/2234839/oceanPress_js\">OceanPress</a> |\r\n 开发者:\r\n <a target=\"_blank\" href=\"https://shenzilong.cn\">崮生(子虚)</a>\r\n</p>\r\n</footer>`,\r\n },\r\n /** 侧边栏配置 */\r\n sidebarCode:{\r\n /** 启用文档树,则 leftCode 将插入在文档树上方 */\r\n enableDocTree:true,\r\n /** 将插入主文档的左侧div中的html代码 */\r\n leftCode: '',\r\n /** 将插入主文档的右侧div中的html代码 */\r\n rightCode: '',\r\n },\r\n OceanPress: {\r\n /** 此配置文件编译时的版本 */\r\n version: version,\r\n },\r\n}\r\nexport type Config = typeof defaultConfig\r\nexport const configs = reactive({\r\n /** 当前所使用的配置项的 key */\r\n __current__: 'default' as const,\r\n /** 为true是表示是代码中设置的默认值,不会保存到本地,避免覆盖之前保存的数据,在加载本地配置后会自动修改为false */\r\n __init__: true,\r\n default: deepAssign<typeof defaultConfig>({}, defaultConfig),\r\n})\r\n\r\nexport function addConfig(name: string, value?: typeof defaultConfig) {\r\n configs[name as 'default'] = deepAssign<typeof defaultConfig>(\r\n {},\r\n value ?? defaultConfig,\r\n )\r\n}\r\n/** 加载配置文件到全局 config 单例中 */\r\nexport const loadConfigFile = (c?: typeof configs) => {\r\n return Effect.gen(function*(){\r\n const effectDep = yield* EffectLocalStorageDep\r\n if (c) {\r\n deepAssign(configs, c)\r\n\r\n } else {\r\n const localConfig = effectDep.getItem('configs')\r\n if (localConfig) {\r\n /** 从本地存储加载配置 */\r\n deepAssign(configs, JSON.parse(localConfig))\r\n }\r\n }\r\n\r\n Object.entries(configs)\r\n .filter(([key]) => key.startsWith('__') === false)\r\n .forEach(([_key, obj]) => {\r\n /** 将新增配置项更新到旧配置上 */\r\n deepAssign(obj, defaultConfig, { update: false, add: true })\r\n })\r\n\r\n // 自动更新配置文件到本地存储\r\n const saveConfig = () => {\r\n if (configs.__init__ === false)\r\n effectDep.setItem('configs', JSON.stringify(configs, null, 2))\r\n }\r\n\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n /** 防抖的保存配置 */\r\n const debounceSaveConfig = () => {\r\n if (timer) {\r\n clearTimeout(timer)\r\n }\r\n timer = setTimeout(() => {\r\n saveConfig()\r\n timer = null\r\n }, 700)\r\n }\r\n watch(configs, debounceSaveConfig, { deep: true })\r\n\r\n return configs\r\n })\r\n\r\n}\r\nexport const currentConfig = computed(() => configs[configs.__current__])\r\n\r\n/** 应该要给用户配置的,但目前没有什么好方法,所以暂时不给配置 */\r\nexport const tempConfig = {\r\n cdn: {\r\n /** 思源 js、css等文件的前缀 */\r\n siyuanPrefix:\r\n `https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@${version}/apps/frontend/public/notebook/`,\r\n // 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@latest/apps/frontend/public/notebook/',\r\n /** 思源 js、css等文件zip包地址 */\r\n publicZip:\r\n 'https://fastly.jsdelivr.net/gh/siyuan-note/oceanpress@v0.0.7/apps/frontend/public/public.zip',\r\n },\r\n withoutPublicZip:true,\r\n}\r\n\r\n\r\nconfigs.__init__ = false\r\n","{\n \"name\": \"oceanpress\",\n \"version\": \"1.0.10\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"cli\": \"tsx ./src/cli.ts\",\n \"cli-w\": \"tsx watch ./src/cli.ts\",\n \"build\": \"vite build && npm run build_lib\",\n \"build_lib\": \"vite build --config vite.sw.config.ts\",\n \"build_app\": \"vite build --mode library\",\n \"build_cli\": \"tsup\",\n \"build_plugin_ui\": \"vite build --config vite.plugin.config.ts\",\n \"dev_plugin_ui\": \"vite build --watch --config vite.plugin.config.ts\",\n \"preview\": \"vite preview\"\n },\n \"bin\": {\n \"oceanpress\": \"./dist-cli/cli.js\"\n },\n \"files\": [\n \"dist/assets\",\n \"dist/dev\",\n \"dist/index.html\",\n \"dist/ocean_press-log.png\",\n \"dist-app/assets\",\n \"dist-app/dev\",\n \"dist-app/app.*\",\n \"dist-cli\",\n \"*.md\"\n ],\n \"dependencies\": {\n \"@aws-sdk/client-s3\": \"^3.873.0\",\n \"@hono/node-server\": \"^1.19.0\",\n \"cheerio\": \"1.1.2\",\n \"commander\": \"^14.0.0\",\n \"effect\": \"^3.17.8\",\n \"fzstd\": \"^0.1.1\",\n \"hono\": \"^4.9.4\",\n \"jszip\": \"^3.10.1\",\n \"meilisearch\": \"^0.52.0\",\n \"naive-ui\": \"^2.42.0\",\n \"octokit\": \"^5.0.3\",\n \"superjson\": \"^2.2.2\",\n \"tsx\": \"^4.20.4\",\n \"vditor\": \"^3.11.1\",\n \"vue\": \"^3.5.19\",\n \"vue-router\": \"^4.5.1\",\n \"zstd-codec\": \"^0.1.5\"\n },\n \"devDependencies\": {\n \"@vitejs/plugin-vue\": \"^6.0.1\",\n \"@vitejs/plugin-vue-jsx\": \"^5.0.1\",\n \"dependency-cruiser\": \"^17.0.1\",\n \"oceanpress-rpc\": \"workspace:*\",\n \"oceanpress-server\": \"workspace:*\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.2\",\n \"vite\": \"^7.1.3\",\n \"vite-plugin-vue-devtools\": \"^8.0.0\",\n \"vue-tsc\": \"^3.0.6\"\n }\n}\n","export function deepAssign<T>(target: any, source: any, config = { add: true, update: true }): T {\r\n for (let key in source) {\r\n if (source.hasOwnProperty(key)) {\r\n if (source[key] instanceof Object && !Array.isArray(source[key])) {\r\n // 如果属性是对象且不是数组,则递归执行深度合并\r\n if (!target.hasOwnProperty(key)) {\r\n // 目标对象不存在该属性则创建空对象\r\n target[key] = {};\r\n }\r\n deepAssign(target[key], source[key], config);\r\n } else {\r\n // 如果属性不是对象或者是数组,则直接赋值\r\n if (!target.hasOwnProperty(key) && config.add) {\r\n // 目标属性不存在属于新增\r\n target[key] = source[key];\r\n } else if (config.update) {\r\n // 更新\r\n target[key] = source[key];\r\n }\r\n }\r\n }\r\n }\r\n return target;\r\n }\r\n","import { Context } from 'effect'\nimport type { S_Node } from './siyuan_type.ts'\nimport type { Config } from './config.ts'\n\nexport type EffectRenderApi = {\n // 渲染相关\n getNodeByID: (id?: string) => Promise<S_Node | undefined>\n getDocPathBySY: (sy?: S_Node) => Promise<string | undefined>\n getDocByChildID: (id: string) => Promise<S_Node | undefined>\n getHPathByID_Node: (id_node: string | S_Node) => Promise<string>\n}\nexport class EffectRender extends Context.Tag('EffectDep')<\n EffectRender,\n EffectRenderApi\n>() {}\n\n// 读写配置文件所依赖的副作用\nexport type effectLocalStorage = {\n setItem: (key: string, value: string) => void\n getItem: (key: string) => string | undefined\n}\n\nexport class EffectLocalStorageDep extends Context.Tag('EffectLocalStorageDep')<\n EffectLocalStorageDep,\n effectLocalStorage\n>() {}\n\n// 读写配置文件所依赖的副作用\nexport type effectLog = {\n // 进度输出相关\n log: (msg: string) => void\n percentage: (_n: number) => void\n}\n\nexport class EffectLogDep extends Context.Tag('EffectLogDep')<\n EffectLogDep,\n effectLog\n>() {}\n\nexport class EffectConfigDep extends Context.Tag('EffectConfigDep')<\n EffectConfigDep,\n Config\n>() {}\n","import JSZip from 'jszip'\n\n/** 下载zip */\nexport async function downloadZIP(\n docTree: { [htmlPath: string]: string | ArrayBuffer },\n config?: { publicZip?: string; withoutZip?: boolean },\n) {\n const content = await genZIP(docTree, config)\n if (globalThis.document) {\n // 将ZIP文件保存为下载\n const link = document.createElement('a')\n link.href = URL.createObjectURL(content)\n link.download = `notebook.zip`\n link.click()\n } else {\n //TODO node 环境下需要写文件\n }\n}\n\nexport async function genZIP(\n docTree: { [htmlPath: string]: string | ArrayBuffer },\n config?: {\n /** 默认的public.zip压缩包内容路径,默认为/public.zip */\n publicZip?: string\n /** 是否不包含默认的public.zip压缩包内容,设置为 true 则会不下载 public.zip 内容合并使用 */\n withoutZip?: boolean\n },\n) {\n const zip = new JSZip()\n if (config?.withoutZip !== true) {\n const presetZip = await (\n await fetch(config?.publicZip ?? '/public.zip')\n ).arrayBuffer()\n await zip.loadAsync(presetZip)\n }\n for (const [path, html] of Object.entries(docTree)) {\n const newPath = path.startsWith('/') ? path.slice(1) : path\n zip.file(newPath, html)\n }\n return await zip.generateAsync({ type: 'blob' })\n}\n","import { Meilisearch, Index } from 'meilisearch'\r\nimport { OceanPressPlugin } from '~/core/ocean_press.ts'\r\nimport { load } from 'cheerio'\r\ntype doc = {\r\n id: string\r\n title?: string\r\n content: string\r\n url: string\r\n lvl0?: string\r\n lvl1?: string\r\n lvl2?: string\r\n lvl3?: string\r\n lvl4?: string\r\n lvl5?: string\r\n lvl6?: string\r\n}\r\nexport class MeilisearchPlugin implements OceanPressPlugin {\r\n _melisearch: Meilisearch | undefined\r\n _index: Index | undefined\r\n _indexName: string\r\n host: string\r\n apiKey: string\r\n constructor(option: { host: string; apiKey: string; indexName: string }) {\r\n this.host = option.host\r\n this.apiKey = option.apiKey\r\n this._indexName = option.indexName\r\n }\r\n async _getMeliSearch() {\r\n if (this._melisearch === undefined) {\r\n this._melisearch = new Meilisearch({\r\n host: this.host,\r\n apiKey: this.apiKey,\r\n })\r\n }\r\n return this._melisearch!\r\n }\r\n async _getIndex() {\r\n if (this._index === undefined) {\r\n const meilisearch = await this._getMeliSearch()\r\n this._index = meilisearch.index(this._indexName)\r\n }\r\n return this._index!\r\n }\r\n docs: { [id: string]: doc } = {}\r\n async addDocument(doc: doc) {\r\n this.docs[doc.id] = doc\r\n }\r\n async updateDocument() {\r\n console.log(`开始上传数据到 ${this.host}`)\r\n const index = await this._getIndex()\r\n const res = await index.addDocuments(Object.values(this.docs))\r\n console.log(`上传结果`, res)\r\n }\r\n build_onFileTree: OceanPressPlugin['build_onFileTree'] = (c, next) => {\r\n const [tree] = c\r\n console.log('开始生成 meilisearch 所需数据结构')\r\n\r\n const htmlTree = Object.keys(tree)\r\n .filter((path) => path.endsWith('.html'))\r\n .map((path) => [path, tree[path]] as const)\r\n for (const [path, html] of htmlTree) {\r\n const $ = load(html.toString())\r\n const entries = $('.h1,.h2,.h3,.h4,.h5,.h6,.p').toArray()\r\n const level: Record<string, string> = { lvl0: $('title').text() }\r\n for (const el of entries) {\r\n /** h1~h6、p */\r\n const c = el.attribs.class\r\n if (c !== 'p') {\r\n Object.keys(level).forEach((lv) => {\r\n if (lv.substring(3, 4) > c.substring(1, 2)) {\r\n /** 跳出层级 */\r\n delete level[lv]\r\n }\r\n })\r\n /** 进入层级 */\r\n level[`lvl${c.substring(1, 2)}`] = $(el).text()\r\n }\r\n this.addDocument({\r\n id: el.attribs.id,\r\n content: $(el).text(),\r\n url: `${path}#${el.attribs.id}`,\r\n ...level,\r\n })\r\n }\r\n\r\n if (path.endsWith('index.html')) break\r\n }\r\n this.updateDocument()\r\n return next(...c)\r\n }\r\n}\r\n","import { createRPC } from 'oceanpress-rpc'\r\nimport type { API } from 'oceanpress-server'\r\nimport { stringify } from 'superjson'\r\nimport { type Config } from '~/core/config.ts'\r\nimport { genZIP } from '~/core/genZip.ts'\r\nimport type { OceanPressPlugin } from '~/core/ocean_press.ts'\r\n\r\n/** 上传数据到 OceanPressServer 适配云端 */\r\nexport function deployOceanPressServer_plugin(config: Config) {\r\n const plugin: OceanPressPlugin = {\r\n async build_onFileTree([tree,effectApi], next) {\r\n next(tree,effectApi)\r\n const client = await createRPC<API>('apiConsumer', {\r\n async remoteCall(method, data) {\r\n let body: ReadableStream | string | Blob\r\n // 如果第一参数是 ReadableStream 的时候,直接使用 ReadableStream 作为 body,不用考虑其他参数,因为这种情况只支持一个参数\r\n let content_type\r\n if (data[0] instanceof ReadableStream) {\r\n // body = data[0] //会遇到一些兼容性问题, http 1.1 不支持使用流作为 body,需要转换为 blob 或者 arraybuffer\r\n\r\n body = await new Response(data[0]).blob()\r\n content_type = 'application/octet-stream'\r\n } else {\r\n body = stringify(data)\r\n console.log('[body]', body)\r\n content_type = 'application/json'\r\n }\r\n return fetch(`${config.oceanPressServer.apiBase}/api/${method}`, {\r\n method: 'POST',\r\n body,\r\n headers: {\r\n 'x-api-key': config.oceanPressServer.apiKey,\r\n 'Content-Type': content_type,\r\n },\r\n // @ts-expect-error 在 node 运行的时候需要声明双工模式才能正确发送 ReadableStream,TODO 需要验证浏览器端可以这样运行吗\r\n duplex: 'half', // 关键:显式声明半双工模式\r\n })\r\n .then((res) => res.json())\r\n .then((r) => {\r\n if (r.error) {\r\n console.log('[r]', r)\r\n throw new Error()\r\n }\r\n return r.result\r\n })\r\n },\r\n })\r\n const zip = await genZIP(tree, { withoutZip: true })\r\n const sizeInMB = zip.size / (1024 * 1024)\r\n console.log('[zip.size in MB]', sizeInMB.toFixed(2))\r\n // 将 Blob 转换为 ReadableStream\r\n const readableStream = zip.stream()\r\n const { chunkCount, fileId } = await client.API.upload(readableStream)\r\n\r\n console.log('[res]', { chunkCount, fileId })\r\n const res = await client.API.deploy({ zipFileId: fileId })\r\n console.log('[deploy res]', res)\r\n },\r\n }\r\n return plugin\r\n}\r\n","import { S3 } from '@aws-sdk/client-s3'\r\nimport type { OceanPressPlugin } from '~/core/ocean_press.ts'\r\nimport type { uploadFiles } from './interface.ts'\r\n\r\n/** 上传数据到 s3 适配云端 */\r\nexport const s3Upload_plugin: OceanPressPlugin = {\r\n build: function ([config, otherConfig], next) {\r\n return next(config, {\r\n ...otherConfig,\r\n\r\n onFileTree: async (tree, effectApi) => {\r\n if (otherConfig?.onFileTree) {\r\n // 维持原有其他监听程序\r\n await otherConfig.onFileTree(tree, effectApi)\r\n }\r\n for await (const [fileName, ETag] of s3_uploads(tree, config)) {\r\n effectApi.log(`上传: ${fileName} ${ETag}`)\r\n }\r\n effectApi.log(`s3 上传完毕`)\r\n },\r\n })\r\n },\r\n}\r\nconst s3_uploads: uploadFiles = async function* (tree, config) {\r\n // https://help.aliyun.com/zh/oss/developer-reference/use-amazon-s3-sdks-to-access-oss#section-2ri-suq-pb3\r\n\r\n const s3 = new S3({\r\n region: config.s3.region,\r\n endpoint: config.s3.endpoint,\r\n credentials: {\r\n accessKeyId: config.s3.accessKeyId,\r\n secretAccessKey: config.s3.secretAccessKey,\r\n },\r\n })\r\n // 将文件逐个上传至 s3\r\n // TODO 可改成并发上传,以缩短时间\r\n const encoder = new TextEncoder()\r\n for (const [path, value] of Object.entries(tree)) {\r\n let buffer: Uint8Array\r\n if (typeof value === 'string') {\r\n buffer = encoder.encode(value)\r\n } else {\r\n buffer = new Uint8Array(value)\r\n }\r\n const r = await s3.putObject({\r\n Bucket: config.s3.bucket,\r\n Key: (config.s3.pathPrefix + path).replace(/\\/\\//g, '/'),\r\n Body: buffer,\r\n })\r\n yield [path, r.ETag] as const\r\n }\r\n}\r\n","import { Effect } from 'effect'\r\nimport packageJson from '~/../package.json' with { type: 'json' }\r\nimport { Config, currentConfig, tempConfig } from '~/core/config.ts'\r\nimport { deepAssign } from '~/util/deep_assign.ts'\r\nimport {\r\n allDocBlock_by_bookId,\r\n get_doc_by_SyPath,\r\n get_node_by_id,\r\n} from './cache.ts'\r\nimport { EffectLogDep, EffectRender, type effectLog } from './EffectDep.ts'\r\nimport { generateRSSXML, sitemap_xml } from './genRssXml.ts'\r\nimport { downloadZIP } from './genZip.ts'\r\nimport { htmlTemplate } from './htmlTemplate.ts'\r\nimport { getRender, renderHTML } from './render.ts'\r\nimport { API } from './siyuan_api.ts'\r\nimport { DB_block, DB_block_path, S_Node } from './siyuan_type.ts'\r\nimport { renderDocTree, renderDocTreeJsPath } from './renderDocTree.ts'\r\n\r\n/**\r\n * 生成面包屑导航数据\r\n */\r\nfunction generateBreadcrumbs(path: string, config: any): Array<{ name: string; url: string }> {\r\n const breadcrumbs: Array<{ name: string; url: string }> = []\r\n \r\n // 添加首页\r\n if (config.sitemap?.siteLink) {\r\n breadcrumbs.push({\r\n name: config.sitemap?.title || '首页',\r\n url: config.sitemap.siteLink\r\n })\r\n }\r\n \r\n // 解析路径\r\n const pathSegments = path.split('/').filter(segment => segment.length > 0)\r\n \r\n let currentPath = ''\r\n for (const segment of pathSegments) {\r\n currentPath += '/' + segment\r\n breadcrumbs.push({\r\n name: segment,\r\n url: `${config.sitemap?.siteLink || ''}${currentPath}.html`\r\n })\r\n }\r\n \r\n return breadcrumbs\r\n}\r\n\r\nexport interface DocTree {\r\n [/** \"/计算机基础课/自述\" */ docPath: string]: {\r\n sy: S_Node\r\n docBlock: DB_block\r\n }\r\n}\r\nexport interface FileTree {\r\n [path: string]: string | ArrayBuffer\r\n}\r\nexport type Build = typeof build\r\n/** 根据配置文件进行编译\r\n * TODO 将浏览器写文件的部分抽离出去,也改成使用 onFileTree\r\n */\r\nexport function build (config:Config,otherConfig?: {\r\n // 监听文件准备完毕 TODO:应该修改实现,而非目前直接全量加载到内存\r\n onFileTree?: (tree: FileTree,effectApi:effectLog) => void\r\n renderHtmlFn?: typeof renderHTML\r\n},){\r\n return Effect.gen(function*(){\r\n const effectApi = yield* EffectRender\r\n const effectLog = yield* EffectLogDep\r\n\r\n const _renderHTML = otherConfig?.renderHtmlFn ?? renderHTML\r\n const book = config.notebook\r\n const docTree: DocTree = {}\r\n const skipBuilds = useSkipBuilds()\r\n\r\n let oldPercentage = 0\r\n let total = 0\r\n /** 较为精准的估计进度 */\r\n function processPercentage(\r\n /** 0~1 的小数 表示这个数占整体百分之多少 */ percentage: number,\r\n ) {\r\n total += oldPercentage\r\n return (/** 0~1 的小数 */ process: number) => {\r\n oldPercentage = process * percentage\r\n effectLog.percentage((total + oldPercentage) * 100)\r\n }\r\n }\r\n effectLog.log( `=== 开始编译 ${book.name} ===`)\r\n let process = processPercentage(0.4)\r\n /** 查询所有文档级block\r\n * TODO 增量编译时不应该全部获取\r\n */\r\n const Doc_blocks: DB_block[] = yield* Effect.tryPromise(()=>allDocBlock_by_bookId(book.id))\r\n /** docBlock 的引用没有更新:true */\r\n function refsNotUpdated(docBlock: DB_block): boolean {\r\n const refs = config.__skipBuilds__[docBlock.id]?.refs ?? []\r\n for (const ref_id of refs) {\r\n const new_doc_hash = Doc_blocks.find(\r\n (docBlock) => docBlock.id === ref_id,\r\n )?.hash\r\n const old_doc_hash = config.__skipBuilds__[ref_id]?.hash\r\n if (new_doc_hash === undefined || old_doc_hash === undefined) {\r\n /** 不应该进入此分支的,如果进来了就重新编译吧 */\r\n return false\r\n } else if (new_doc_hash === old_doc_hash) {\r\n continue\r\n } else {\r\n return false\r\n }\r\n }\r\n /** 引用的都没有更新 */\r\n return true\r\n }\r\n effectLog.log (`=== 查询文档级block完成 ===`)\r\n let i = 0\r\n yield* Effect.tryPromise(()=>Promise.all(\r\n Doc_blocks.map(async (docBlock) => {\r\n const sy = await get_doc_by_SyPath(DB_block_path(docBlock))\r\n docTree[docBlock.hpath] = { sy, docBlock }\r\n i++\r\n process(i / Doc_blocks.length)\r\n }),\r\n ))\r\n const fileTree: FileTree = {}\r\n\r\n process = processPercentage(0.4)\r\n\r\n const enableIncrementalCompilation_doc = (() => {\r\n if (packageJson.version !== config.OceanPress.version) {\r\n effectLog.log(\r\n `配置文件版本号[${config.OceanPress.version}]与OceanPress版本[${packageJson.version}]不一致,将进行文档全量编译`,\r\n )\r\n return false\r\n }\r\n return config.enableIncrementalCompilation_doc\r\n })()\r\n effectLog.log (`=== 开始渲染文档 ===`)\r\n\r\n yield* Effect.forEach(Object.entries(docTree), ([path, { sy, docBlock }]) => {\r\n return Effect.gen(function*(){\r\n if (\r\n config.enableIncrementalCompilation &&\r\n enableIncrementalCompilation_doc &&\r\n /** 文档本身没有发生变化 */\r\n config.__skipBuilds__[docBlock.id]?.hash === docBlock.hash &&\r\n /** docBlock所引用的文档也没有更新 */\r\n refsNotUpdated(docBlock)\r\n ){\r\n return '/** skip */'\r\n }\r\n const renderInstance = yield* getRender\r\n try {\r\n const rootLevel = path.split('/').length - 2 /** 最开头有一个 / 还有一个 data 目录所以减二 */\r\n const htmlContent = yield* _renderHTML(sy, renderInstance)\r\n\r\n const pageUrl = config.sitemap.siteLink \r\n ? `${config.sitemap.siteLink}${path}.html`\r\n : `${path}.html`\r\n \r\n fileTree[path + '.html'] = yield* Effect.tryPromise( ()=>htmlTemplate(\r\n {\r\n title: sy.Properties?.title || '',\r\n htmlContent,\r\n level: rootLevel,\r\n seoData: {\r\n doc: sy,\r\n config: config,\r\n pageUrl: pageUrl,\r\n breadcrumbs: generateBreadcrumbs(path, config)\r\n },\r\n },\r\n {\r\n ...tempConfig.cdn,\r\n embedCode: config.embedCode,\r\n },\r\n ))\r\n /** rss.xml 生成 */\r\n if (config.sitemap.rss && path.endsWith('.rss.xml')) {\r\n const rssPath = path\r\n fileTree[rssPath] =yield* Effect.tryPromise(()=> generateRSSXML(rssPath, renderInstance, config,effectApi.getHPathByID_Node))\r\n effectLog.log(`渲染 rss.xml:${rssPath} 完毕`)\r\n }\r\n if (\r\n config.enableIncrementalCompilation &&\r\n config.enableIncrementalCompilation_doc\r\n ) {\r\n /** 更新为当前hash */\r\n skipBuilds.add(docBlock.id, {\r\n hash: docBlock.hash,\r\n })\r\n }\r\n /** 无论是否配置增量更新都要更新正向引用,不然开启增量更新后没有引用数据可用 */\r\n skipBuilds.add(docBlock.id, {\r\n refs: /** 保存引用 */ [...renderInstance.refs.values()],\r\n })\r\n effectLog.log(`渲染完毕:${path}`)\r\n } catch (error) {\r\n effectLog.log(`${path} 渲染失败:${error}`)\r\n console.log(error)\r\n }\r\n process(i / Doc_blocks.length)\r\n return `渲染完毕:${path}`\r\n })\r\n\r\n\r\n\r\n })\r\n\r\n effectLog.log( `=== 渲染文档完成 ===`)\r\n effectLog.log( `=== 开始生成 sitemap.xml ===`)\r\n if (config.sitemap.enable) {\r\n fileTree['sitemap.xml'] = sitemap_xml(Doc_blocks, config.sitemap)\r\n }\r\n if (config.excludeAssetsCopy === false) {\r\n effectLog.log( `=== 开始复制资源文件 ===`)\r\n const assets: {\r\n box: string\r\n docpath: string\r\n path: string\r\n hash: string\r\n id: string\r\n }[] = yield* Effect.tryPromise( ()=>API.query_sql({\r\n stmt: `SELECT * from assets\r\n WHERE box = '${book.id}'\r\n limit 150000 OFFSET 0`,\r\n }))\r\n yield* Effect.tryPromise(()=> Promise.all(\r\n assets.map(async (item) => {\r\n if (\r\n config.enableIncrementalCompilation &&\r\n /** 资源没有变化,直接跳过 */\r\n config.__skipBuilds__[item.id]?.hash === item.hash\r\n ) {\r\n return /** skip */\r\n } else {\r\n fileTree[item.path] = await API.get_assets({\r\n path: item.path,\r\n })\r\n if (config.enableIncrementalCompilation) {\r\n skipBuilds.add(item.id, { hash: item.hash })\r\n }\r\n }\r\n }),\r\n ))\r\n effectLog.log( `=== 开始复制挂件资源文件 ===`)\r\n const widgetList: DB_block[] =yield* Effect.tryPromise( ()=>API.query_sql({\r\n stmt: `\r\n SELECT *\r\n from blocks\r\n WHERE box = '${book.id}'\r\n AND type = 'widget'\r\n limit 150000 OFFSET 0\r\n `,\r\n }))\r\n const widgetNode = (\r\n yield* Effect.tryPromise( ()=>Promise.all(\r\n widgetList.map(async (el) => await get_node_by_id(el.id)),\r\n ))\r\n )\r\n .filter(\r\n (widget) =>\r\n (widget?.Properties as any)?.['custom-oceanpress-widget-update'],\r\n )\r\n .map(async (widget) => {\r\n if (!widget || !widget?.ID) return\r\n const update = (widget?.Properties as any)?.[\r\n 'custom-oceanpress-widget-update'\r\n ] as string\r\n if (\r\n config.enableIncrementalCompilation &&\r\n config.__skipBuilds__[widget.ID]?.updated === update\r\n ) {\r\n return /** 资源没有变化,直接跳过 */\r\n } else {\r\n const id = widget.ID\r\n // 快照保存的位置 `/data/storage/oceanpress/widget_img/${id}.jpg`\r\n fileTree[`assets/widget/${id}.jpg`] = (await API.file_getFile({\r\n path: `data/storage/oceanpress/widget_img/${id}.jpg`,\r\n })) as ArrayBuffer\r\n if (config.enableIncrementalCompilation) {\r\n skipBuilds.add(id, { updated: update })\r\n }\r\n }\r\n })\r\n yield* Effect.tryPromise( ()=> Promise.all(widgetNode))\r\n }\r\n if(config.sidebarCode.enableDocTree){\r\n effectLog.log( `=== 开始生成文档树 ===`)\r\n fileTree[renderDocTreeJsPath]=yield* renderDocTree()\r\n effectLog.log( `=== 文档树生成完成 ===`)\r\n }\r\n // === 输出编译成果 ===\r\n if (otherConfig?.onFileTree) {\r\n otherConfig.onFileTree(fileTree,effectLog)\r\n }\r\n if (config.compressedZip) {\r\n effectLog.log( `=== 开始生成压缩包 ===`)\r\n yield* Effect.tryPromise(() =>\r\n downloadZIP(fileTree, {\r\n // TODO 这里应该移出来成为全局的写选项\r\n withoutZip: tempConfig.withoutPublicZip,\r\n publicZip: tempConfig.cdn.publicZip,\r\n })\r\n )\r\n }\r\n\r\n config.OceanPress.version = packageJson.version\r\n /** 更新跳过编译的资源 */\r\n skipBuilds.write()\r\n effectLog.percentage(100)\r\n effectLog.log( '编译完毕')\r\n\r\n return {fileTree}\r\n })\r\n}\r\n\r\nfunction useSkipBuilds() {\r\n const obj: { [k: string]: { hash?: string } } = {}\r\n return {\r\n add(\r\n id: string,\r\n value: { hash?: string; refs?: string[]; updated?: string },\r\n ) {\r\n if (obj[id] === undefined) {\r\n obj[id] = {}\r\n }\r\n deepAssign(obj[id], value)\r\n },\r\n /** 将缓存的写入到配置文件 */\r\n write() {\r\n deepAssign(currentConfig.value.__skipBuilds__, obj)\r\n },\r\n }\r\n}\r\n","/** ════════════════════════🏳‍🌈 实用功能 🏳‍🌈════════════════════════\r\n * 利用 composition-api 实现的一些实用功能\r\n ** ════════════════════════🚧 实用功能 🚧════════════════════════ */\r\nimport { customRef, nextTick, watch, watchEffect, WatchSource } from \"vue\";\r\n\r\nexport class PromiseObj<T, Err = Error> {\r\n pending = false;\r\n fulfilled = false;\r\n rejected = false;\r\n data = {} as T;\r\n error = {} as Err;\r\n _p = Promise.resolve() as Promise<unknown>;\r\n setP(p: Promise<unknown>) {\r\n this._p = p;\r\n }\r\n equalP(p: Promise<unknown>) {\r\n return this._p === p;\r\n }\r\n reLoad() {}\r\n setValue(_data: T) {}\r\n}\r\nexport const continueLoading = Symbol();\r\n\r\nexport interface usePromiseComputedOptions<T> {\r\n /** 函数内的依赖变更的时候就重新计算,指定了 deps 则不会依赖于 getter 内的 ref 了\r\n * tips: 可以将其设置为 `()=>[]` 从而不主动执行 getter(), 可以通过调用返回的 reLoad 来调用 getter()\r\n */\r\n deps?: WatchSource<any>;\r\n /** data 的默认值 */\r\n defaultData?: T;\r\n /** 如果这个参数没有输入的话,应该自行调用 PromiseObj.setValue */\r\n getter?: () => Promise<T> | typeof continueLoading;\r\n /** 处理数据是否要和之前的数据进行合并 */\r\n dataMergeFun?: (oldData: T, newData: T) => T;\r\n}\r\n\r\nexport function usePromiseComputed<T, Err = Error>({\r\n deps,\r\n getter,\r\n dataMergeFun = (_oldData, newData) => newData,\r\n defaultData,\r\n}: usePromiseComputedOptions<T>) {\r\n const r = new PromiseObj<T, Err>();\r\n if (defaultData !== undefined) {\r\n r.data = defaultData;\r\n }\r\n return customRef<PromiseObj<T, Err>>((track, trigger) => {\r\n if (!deps && getter) {\r\n watchEffect(() => update(getter()));\r\n } else if (deps && getter) {\r\n if (deps instanceof Function) {\r\n const depsSource = deps();\r\n if (Array.isArray(depsSource) && depsSource.length === 0) {\r\n // 特性,传递空数组则先不执行 getter ,由用户自己决定时机执行 reload\r\n } else {\r\n watch(deps, () => update(getter()), { immediate: true });\r\n }\r\n } else {\r\n watch(deps, () => update(getter()), { immediate: true });\r\n }\r\n }\r\n function update(p: Promise<T> | typeof continueLoading) {\r\n r.pending = true;\r\n r.fulfilled = false;\r\n r.rejected = false;\r\n /** 返回值为继续加载则,getter函数中有特殊的判断逻辑,依据当前的 deps 还无法得出值,需要继续 loading */\r\n if (p === continueLoading) {\r\n nextTick(trigger);\r\n return;\r\n }\r\n r.setP(p);\r\n // 立即触发会导致死循环,所以包裹一层\r\n nextTick(trigger);\r\n p.then((res) => {\r\n // 避免 「求值fun」 第一次执行产生的 promise 比 第二次产生的后结束 导致 数据错误的采用了第一次的\r\n if (r.equalP(p)) {\r\n r.pending = false;\r\n r.fulfilled = true;\r\n r.data = dataMergeFun(r.data, res);\r\n }\r\n })\r\n .catch((e) => {\r\n if (r.equalP(p)) {\r\n r.pending = false;\r\n r.rejected = true;\r\n r.error = e;\r\n }\r\n })\r\n .finally(() => {\r\n if (r.equalP(p)) {\r\n trigger();\r\n }\r\n });\r\n }\r\n r.reLoad = () => {\r\n if (getter) update(getter());\r\n // 否则是用户通过 setValue 设定的值,是无法reLoad的\r\n };\r\n r.setValue = (data) => {\r\n r.pending = false;\r\n r.fulfilled = true;\r\n r.data = dataMergeFun(r.data, data);\r\n trigger();\r\n };\r\n return {\r\n get() {\r\n track();\r\n return r;\r\n },\r\n set(_newValue) {\r\n console.warn(\"不可设置值\");\r\n },\r\n };\r\n });\r\n}\r\n\r\nexport namespace usePromiseComputed {\r\n /** 辅助方法,返回一个deps为 `()=>{}` 的 PromiseObj */\r\n export function nullDeps<T>(getter: usePromiseComputedOptions<T>[\"getter\"]) {\r\n return usePromiseComputed({\r\n deps: () => [],\r\n getter,\r\n });\r\n }\r\n export function fn<T>(fn: () => Promise<T> | typeof continueLoading) {\r\n const p = usePromiseComputed({\r\n getter() {\r\n return fn();\r\n },\r\n });\r\n return p;\r\n }\r\n}\r\n\r\n/** 防抖的 ref */\r\nexport function useDebouncedRef<T>(value: T, delay = 200) {\r\n let timeout = 0;\r\n return customRef<T>((track, trigger) => {\r\n return {\r\n get() {\r\n track();\r\n return value;\r\n },\r\n set(newValue) {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(() => {\r\n value = newValue;\r\n trigger();\r\n }, delay) as unknown as number;\r\n },\r\n };\r\n });\r\n}\r\n","import { Ref } from 'vue'\r\nimport { currentConfig } from '~/core/config.ts'\r\nimport {\r\n PromiseObj,\r\n usePromiseComputed,\r\n} from '../components/data_promise/index.ts'\r\nimport { S_Node, file, notebook } from './siyuan_type.ts'\r\n\r\n/** oceanpress 所依赖的相关 api https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md */\r\nexport interface api {\r\n /**\r\n * 列出笔记本\r\n */\r\n notebook_lsNotebooks(): {\r\n notebooks: notebook[]\r\n }\r\n filetree_listDocsByPath(p: { notebook: notebook['id']; path: '/' }): {\r\n box: '20210816161940-zo21go1'\r\n files: file[]\r\n path: '/'\r\n }\r\n /** 执行 SQL 查询 https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md#执行-sql-查询 */\r\n query_sql(p: {\r\n /** SELECT * FROM blocks WHERE content LIKE'%content%' LIMIT 7 */ stmt: string\r\n }): any[]\r\n /** 获取文件 https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md#获取文件 */\r\n file_getFile(p: { path: string }): S_Node | ArrayBuffer\r\n get_assets(p: { path: string }): ArrayBuffer\r\n /** 根据人类可读路径获取 IDs https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md#根据人类可读路径获取-ids */\r\n filetree_getIDsByHPath(p: {\r\n /** /foo/bar */\r\n path: string\r\n /** 20210808180117-czj9bvb */\r\n notebook: string\r\n }): string[]\r\n}\r\ntype apiPromisify = {\r\n readonly [K in keyof api]: (\r\n ...arg: Parameters<api[K]>\r\n ) => Promise<unPromise<ReturnType<api[K]>>>\r\n}\r\n\r\n/** 解开 promise 类型包装 */\r\ndeclare type unPromise<T> = T extends Promise<infer R> ? R : T\r\nlet rpcCount = 0\r\nasync function rpc(method: string, arg: any) {\r\n const apiPrefix = currentConfig.value.apiPrefix\r\n const Authorization = currentConfig.value.authorized\r\n rpcCount++\r\n\r\n if (method === 'get_assets') {\r\n return fetch(`${apiPrefix}/${arg[0].path}`, {\r\n headers: {\r\n Authorization: `Token ${Authorization}`,\r\n },\r\n body: null,\r\n method: 'GET',\r\n mode: 'cors',\r\n }).then((r) => r.arrayBuffer())\r\n }\r\n const res = await fetch(`${apiPrefix}/api/${method.replace(/_/g, '/')}`, {\r\n headers: {\r\n Authorization: `Token ${Authorization}`,\r\n },\r\n body: JSON.stringify(arg[0]),\r\n method: 'POST',\r\n }).catch((err: Error) => {\r\n err.message = `访问思源接口时出错了,请检查思源服务是否启动以及配置接口地址是否正确。`\r\n throw err\r\n })\r\n if (method === 'file_getFile') {\r\n const path = arg[0].path as string\r\n if (path.endsWith('.sy')) {\r\n return await res.json()\r\n } else {\r\n const buffer = await res.arrayBuffer()\r\n if (buffer.byteLength < 200) {\r\n const decoder = new TextDecoder()\r\n const text = decoder.decode(buffer)\r\n if (JSON.parse(text).code === 404) {\r\n throw new Error(`文件不存在: ${path}`)\r\n }\r\n }\r\n return buffer\r\n }\r\n }\r\n const json = await res.json()\r\n\r\n if (json.code !== 0) {\r\n throw new Error(json.msg)\r\n }\r\n return json.data\r\n}\r\n\r\n/** 包装了一次的 RC 方便跳转到函数定义 */\r\nexport const API = new Proxy(\r\n {},\r\n {\r\n get(_, method: string) {\r\n return (...arg: any) => rpc(method, arg)\r\n },\r\n },\r\n) as apiPromisify\r\n\r\ntype vApi = {\r\n readonly [K in keyof api]: (\r\n ...arg: Parameters<api[K]>\r\n ) => Ref<PromiseObj<unPromise<ReturnType<api[K]>>, Error>>\r\n}\r\n/** 使用 usePromiseComputed 包装的方法,便于使用 */\r\nexport const vApi = new Proxy(\r\n {},\r\n {\r\n get(_, method: string) {\r\n return (...arg: any) => usePromiseComputed.fn(() => rpc(method, arg))\r\n },\r\n },\r\n) as vApi\r\n","export interface notebook {\r\n id: \"20210808180117-czj9bvb\";\r\n name: \"思源笔记用户指南\";\r\n icon: \"1f4d4\";\r\n sort: 1;\r\n closed: false;\r\n}\r\nexport interface file {\r\n /** \"/20210816161946-cktc4gf.sy\" */\r\n path: string;\r\n name: \"关于.sy\";\r\n icon: \"\";\r\n name1: \"\";\r\n alias: \"\";\r\n memo: \"\";\r\n bookmark: \"\";\r\n /** \"20210816161946-cktc4gf\" */\r\n id: string;\r\n count: 0;\r\n size: 362;\r\n hSize: \"362 B\";\r\n mtime: 1629101986;\r\n ctime: 1629101986;\r\n hMtime: \"2 年以前\";\r\n hCtime: \"2021-08-16 16:19:46\";\r\n sort: 0;\r\n subFileCount: 9;\r\n newFlashcardCount: 0;\r\n dueFlashcardCount: 0;\r\n flashcardCount: 0;\r\n}\r\nexport interface NodeDocument {\r\n blockCount: 2;\r\n box: \"20210808180117-czj9bvb\";\r\n content: \"<html>\";\r\n eof: false;\r\n id: \"20230519105228-hm0y74i\";\r\n isBacklinkExpand: false;\r\n isSyncing: false;\r\n mode: 0;\r\n parent2ID: \"20230519105228-hm0y74i\";\r\n parentID: \"20230519105228-hm0y74i\";\r\n path: \"/20230519105228-hm0y74i.sy\";\r\n rootID: \"20230519105228-hm0y74i\";\r\n scroll: false;\r\n type: \"NodeDocument\";\r\n}\r\n\r\nexport function DB_block_path(p: DB_block) {\r\n return `data/${p.box}${p.path}`;\r\n}\r\nexport interface DB_block {\r\n alias: \"\";\r\n box: \"20210816161940-3mfvumm\";\r\n content: \"自述\";\r\n created: \"20201125202944\";\r\n fcontent: \"自述\";\r\n hash: \"922ee83\";\r\n hpath: \"/计算机基础课/自述\";\r\n ial: '{: id=\"20201125202944-01mdxqn\" title=\"自述\" type=\"doc\" updated=\"20201125202944\"}';\r\n id: \"20201125202944-01mdxqn\";\r\n length: 2;\r\n markdown: \"\";\r\n memo: \"\";\r\n name: \"\";\r\n parent_id: \"\";\r\n path: \"/20210816161944-io0cgn6/20201125202944-01mdxqn.sy\";\r\n root_id: \"20201125202944-01mdxqn\";\r\n sort: 0;\r\n subtype: \"\";\r\n tag: \"\";\r\n type: \"d\";\r\n updated: \"20201125202944\";\r\n}\r\nexport interface S_Node {\r\n ID?: string; // 节点的唯一标识\r\n Box?: string; // 容器\r\n Path?: string; // 路径\r\n Spec?: string; // 规范版本号\r\n Type: NodeType; // 节点类型\r\n Parent: S_Node; // 父节点 在 node.ts 中被重建了,所以这个引用关系是可用的\r\n Previous?: S_Node; // 前一个兄弟节点\r\n Next?: S_Node; // 后一个兄弟节点\r\n FirstChild?: S_Node; // 第一个子节点\r\n LastChild?: S_Node; // 最后一个子节点\r\n Children?: S_Node[]; // 所有子节点\r\n Tokens?: number[]; // 词法分析结果 Tokens,语法分析阶段会继续操作这些 Tokens\r\n TypeStr: string; // 类型字符串\r\n Data?: string; // Tokens 字符串\r\n Close?: boolean; // 标识是否关闭\r\n LastLineBlank?: boolean; // 标识最后一行是否是空行\r\n LastLineChecked?: boolean; // 标识最后一行是否检查过\r\n CodeMarkerLen?: number; // ` 个数,1 或 2\r\n IsFencedCodeBlock?: boolean;\r\n CodeBlockFenceChar?: number;\r\n CodeBlockFenceLen?: number;\r\n CodeBlockFenceOffset?: number;\r\n CodeBlockOpenFence?: number[];\r\n CodeBlockInfo?: string; // Z28= | atob = 'go'\r\n CodeBlockCloseFence?: number[];\r\n HtmlBlockType?: number;\r\n ListData?: ListData;\r\n TaskListItemChecked?: boolean;\r\n TableAligns?: number[];\r\n TableCellAlign?: number;\r\n TableCellContentWidth?: number;\r\n TableCellContentMaxWidth?: number;\r\n LinkType?: number;\r\n LinkRefLabel?: number[];\r\n HeadingLevel?: number;\r\n HeadingSetext?: boolean;\r\n HeadingNormalizedID?: string;\r\n MathBlockDollarOffset?: number;\r\n FootnotesRefLabel?: number[];\r\n FootnotesRefId?: string;\r\n FootnotesRefs?: Node[];\r\n HtmlEntityTokens?: number[];\r\n KramdownIAL?: string[][];\r\n Properties?: {\r\n icon: \"1f4f0\";\r\n id: \"20200825162036-4dx365o\";\r\n title: \"排版元素\";\r\n \"title-img\": \"background-color: hsl(2, 57%, 40%);background-image: repeating-linear-gradient(transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(270deg, transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(125deg, transparent, transparent 2px, rgba(0,0,0,.2) 2px, rgba(0,0,0,.2) 3px, transparent 3px, transparent 5px, rgba(0,0,0,.2) 5px);\";\r\n type: \"doc\";\r\n updated: \"20230820185054\";\r\n \"parent-style\"?: \"max-width: 137px;\";\r\n style?: \"display: block;\";\r\n };\r\n TextMarkType?: \"block-ref\" | \"a\" | \"tag\" | \"inline-math\" | \"inline-memo\";\r\n TextMarkAHref?: string;\r\n TextMarkATitle?: string;\r\n TextMarkInlineMathContent?: string;\r\n TextMarkInlineMemoContent?: string;\r\n TextMarkBlockRefID?: string;\r\n TextMarkBlockRefSubtype?: string;\r\n TextMarkFileAnnotationRefID?: string;\r\n TextMarkTextContent?: string;\r\n AttributeViewID?: string;\r\n AttributeViewType?: string;\r\n CustomBlockFenceOffset?: number;\r\n CustomBlockInfo?: string;\r\n}\r\ntype NodeType = ValueKeys<typeof NodeType>;\r\ntype ValueKeys<T> = keyof { [K in keyof T]: T[K] extends string ? K : never };\r\ninterface ListData {\r\n Typ?: number; // 0:无序列表,1:有序列表,3:任务列表\r\n Tight?: boolean; // 是否是紧凑模式\r\n BulletChar?: number; // 无序列表标识,* - 或者 +\r\n Start?: number; // 有序列表起始序号\r\n Delimiter?: number; // 有序列表分隔符,. 或者 )\r\n Padding?: number; // 列表内部缩进空格数(包含标识符长度,即规范中的 W+N)\r\n MarkerOffset?: number; // 标识符(* - + 或者 1 2 3)相对缩进空格数\r\n Checked?: boolean; // 任务列表项是否勾选\r\n Marker?: string; // 列表标识符\r\n Num?: number; // 有序列表项修正过的序号\r\n}\r\n\r\nexport const NodeType = {\r\n NodeDocument: 0, // 根\r\n NodeParagraph: 1, // 段落\r\n NodeHeading: 2, // 标题\r\n NodeHeadingC8hMarker: 3, // ATX 标题标记符 #\r\n NodeThematicBreak: 4, // 分隔线\r\n NodeBlockquote: 5, // 块引用\r\n NodeBlockquoteMarker: 6, // 块引用标记符 >\r\n NodeList: 7, // 列表\r\n NodeListItem: 8, // 列表项\r\n NodeHTMLBlock: 9, // HTML 块\r\n NodeInlineHTML: 10, // 内联 HTML\r\n NodeCodeBlock: 11, // 代码块\r\n NodeCodeBlockFenceOpenMarker: 12, // 开始围栏代码块标记符 ```\r\n NodeCodeBlockFenceCloseMarker: 13, // 结束围栏代码块标记符 ```\r\n NodeCodeBlockFenceInfoMarker: 14, // 围栏代码块信息标记符 info string\r\n NodeCodeBlockCode: 15, // 围栏代码块代码\r\n NodeText: 16, // 文本\r\n NodeEmphasis: 17, // 强调\r\n NodeEmA6kOpenMarker: 18, // 开始强调标记符 *\r\n NodeEmA6kCloseMarker: 19, // 结束强调标记符 *\r\n NodeEmU8eOpenMarker: 20, // 开始强调标记符 _\r\n NodeEmU8eCloseMarker: 21, // 结束强调标记符 _\r\n NodeStrong: 22, // 加粗\r\n NodeStrongA6kOpenMarker: 23, // 开始加粗标记符 **\r\n NodeStrongA6kCloseMarker: 24, // 结束加粗标记符 **\r\n NodeStrongU8eOpenMarker: 25, // 开始加粗标记符 __\r\n NodeStrongU8eCloseMarker: 26, // 结束加粗标记符 __\r\n NodeCodeSpan: 27, // 代码\r\n NodeCodeSpanOpenMarker: 28, // 开始代码标记符 `\r\n NodeCodeSpanContent: 29, // 代码内容\r\n NodeCodeSpanCloseMarker: 30, // 结束代码标记符 `\r\n NodeHardBreak: 31, // 硬换行\r\n NodeSoftBreak: 32, // 软换行\r\n NodeLink: 33, // 链接\r\n NodeImage: 34, // 图片\r\n NodeBang: 35, // !\r\n NodeOpenBracket: 36, // [\r\n NodeCloseBracket: 37, // ]\r\n NodeOpenParen: 38, // (\r\n NodeCloseParen: 39, // )\r\n NodeLinkText: 40, // 链接文本\r\n NodeLinkDest: 41, // 链接地址\r\n NodeLinkTitle: 42, // 链接标题\r\n NodeLinkSpace: 43, // 链接地址和链接标题之间的空格\r\n NodeHTMLEntity: 44, // HTML 实体\r\n NodeLinkRefDefBlock: 45, // 链接引用定义块\r\n NodeLinkRefDef: 46, // 链接引用定义 [label]:\r\n NodeLess: 47, // <\r\n NodeGreater: 48, // >\r\n\r\n // GFM\r\n\r\n NodeTaskListItemMarker: 100, // 任务列表项标记符\r\n NodeStrikethrough: 101, // 删除线\r\n NodeStrikethrough1OpenMarker: 102, // 开始删除线标记符 ~\r\n NodeStrikethrough1CloseMarker: 103, // 结束删除线标记符 ~\r\n NodeStrikethrough2OpenMarker: 104, // 开始删除线标记符 ~~\r\n NodeStrikethrough2CloseMarker: 105, // 结束删除线标记符 ~~\r\n NodeTable: 106, // 表\r\n NodeTableHead: 107, // 表头\r\n NodeTableRow: 108, // 表行\r\n NodeTableCell: 109, // 表格\r\n\r\n // Emoji\r\n\r\n NodeEmoji: 200, // Emoji\r\n NodeEmojiUnicode: 201, // Emoji Unicode\r\n NodeEmojiImg: 202, // Emoji 图片\r\n NodeEmojiAlias: 203, // Emoji ASCII\r\n\r\n // 数学公式\r\n\r\n NodeMathBlock: 300, // 数学公式块\r\n NodeMathBlockOpenMarker: 301, // 开始数学公式块标记符 $$\r\n NodeMathBlockContent: 302, // 数学公式块内容\r\n NodeMathBlockCloseMarker: 303, // 结束数学公式块标记符 $$\r\n NodeInlineMath: 304, // 内联数学公式\r\n NodeInlineMathOpenMarker: 305, // 开始内联数学公式标记符 $\r\n NodeInlineMathContent: 306, // 内联数学公式内容\r\n NodeInlineMathCloseMarker: 307, // 结束内联数学公式标记符 $\r\n\r\n // 转义\r\n\r\n NodeBackslash: 400, // 转义反斜杠标记符 \\\r\n NodeBackslashContent: 401, // 转义反斜杠后的内容\r\n\r\n // Vditor 支持\r\n\r\n NodeVditorCaret: 405, // 插入符,某些情况下需要使用该节点进行插入符位置调整\r\n\r\n // 脚注\r\n\r\n NodeFootnotesDefBlock: 410, // 脚注定义块\r\n NodeFootnotesDef: 411, // 脚注定义 [^label]:\r\n NodeFootnotesRef: 412, // 脚注引用 [^label]\r\n\r\n // 目录\r\n\r\n NodeToC: 415, // 目录 [toc]\r\n\r\n // 标题\r\n\r\n NodeHeadingID: 420, // 标题 ID # foo {id}\r\n\r\n // YAML Front Matter\r\n\r\n NodeYamlFrontMatter: 425, // https://,jekyllrb.com/docs/front-matter/\r\n NodeYamlFrontMatterOpenMarker: 426, // 开始 YAML Front Matter 标记符 ---\r\n NodeYamlFrontMatterContent: 427, // YAML Front Matter 内容\r\n NodeYamlFrontMatterCloseMarker: 428, // 结束 YAML Front Matter 标记符 ---\r\n\r\n // 内容块引用(Block Reference) https://,github.com/88250/lute/issues/82\r\n\r\n NodeBlockRef: 430, // 内容块引用节点\r\n NodeBlockRefID: 431, // 被引用的内容块(定义块)ID\r\n NodeBlockRefSpace: 432, // 被引用的内容块 ID 和内容块引用锚文本之间的空格\r\n NodeBlockRefText: 433, // 内容块引用锚文本\r\n NodeBlockRefDynamicText: 434, // 内容块引用动态锚文本\r\n\r\n // ==Mark== 标记语法 https://,github.com/88250/lute/issues/84\r\n\r\n NodeMark: 450, // 标记\r\n NodeMark1OpenMarker: 451, // 开始标记标记符 =\r\n NodeMark1CloseMarker: 452, // 结束标记标记符 =\r\n NodeMark2OpenMarker: 453, // 开始标记标记符 ==\r\n NodeMark2CloseMarker: 454, // 结束标记标记符 ==\r\n\r\n // kramdown 内联属性列表 https://,github.com/88250/lute/issues/89 and https://,github.com/88250/lute/issues/118\r\n\r\n NodeKramdownBlockIAL: 455, // 块级内联属性列表 {: name,=\"value\"}\r\n NodeKramdownSpanIAL: 456, // 行级内联属性列表 *foo*{: name,=\"value\"}bar\r\n\r\n // #Tag# 标签语法 https://,github.com/88250/lute/issues/92\r\n\r\n NodeTag: 460, // 标签\r\n NodeTagOpenMarker: 461, // 开始标签标记符 #\r\n NodeTagCloseMarker: 462, // 结束标签标记符 #\r\n\r\n // 内容块查询嵌入(Block Query Embed)语法 https://,github.com/88250/lute/issues/96\r\n\r\n NodeBlockQueryEmbed: 465, // 内容块查询嵌入\r\n NodeOpenBrace: 466, // {\r\n NodeCloseBrace: 467, // }\r\n NodeBlockQueryEmbedScript: 468, // 内容块查询嵌入脚本\r\n\r\n // 超级块语法 https://,github.com/88250/lute/issues/111\r\n\r\n NodeSuperBlock: 475, // 超级块节点\r\n NodeSuperBlockOpenMarker: 476, // 开始超级块标记符 {{{\r\n NodeSuperBlockLayoutMarker: 477, // 超级块布局 row/col\r\n NodeSuperBlockCloseMarker: 478, // 结束超级块标记符 }}}\r\n\r\n // 上标下标语法 https://,github.com/88250/lute/issues/113\r\n\r\n NodeSup: 485, // 上标\r\n NodeSupOpenMarker: 486, // 开始上标标记符 ^\r\n NodeSupCloseMarker: 487, // 结束上标标记符 ^\r\n NodeSub: 490, // 下标\r\n NodeSubOpenMarker: 491, // 开始下标标记符 ~\r\n NodeSubCloseMarker: 492, // 结束下标标记符 ~\r\n\r\n // Git 冲突标记 https://,github.com/88250/lute/issues/131\r\n\r\n NodeGitConflict: 495, // Git 冲突标记\r\n NodeGitConflictOpenMarker: 496, // 开始 Git 冲突标记标记符 <<<<<<<\r\n NodeGitConflictContent: 497, // Git 冲突标记内容\r\n NodeGitConflictCloseMarker: 498, // 结束 Git 冲突标记标记符 >>>>>>>\r\n\r\n // <iframe> 标签\r\n\r\n NodeIFrame: 500, // <iframe> 标签\r\n\r\n // <audio> 标签\r\n\r\n NodeAudio: 505, // <audio> 标签\r\n\r\n // <video> 标签\r\n\r\n NodeVideo: 510, // <video> 标签\r\n\r\n // <kbd> 标签\r\n\r\n NodeKbd: 515, // 键盘\r\n NodeKbdOpenMarker: 516, // 开始 kbd 标记符 <kbd>\r\n NodeKbdCloseMarker: 517, // 结束 kbd 标记符 </kbd>\r\n\r\n // <u> 标签\r\n\r\n NodeUnderline: 520, // 下划线\r\n NodeUnderlineOpenMarker: 521, // 开始下划线标记符 <u>\r\n NodeUnderlineCloseMarker: 522, // 结束下划线标记符 </u>\r\n\r\n // <br> 标签\r\n\r\n NodeBr: 525, // <br> 换行\r\n\r\n // <span data-type=\"mark\">foo</span> 通用的行级文本标记,不能嵌套\r\n\r\n NodeTextMark: 530, // 文本标记,该节点因为不存在嵌套,所以不使用 Open/Close 标记符\r\n\r\n // Protyle 挂件,<iframe data-type=\"NodeWidget\">\r\n\r\n NodeWidget: 535, // <iframe data-type=\"NodeWidget\" data-subtype=\"widget\"></iframe>\r\n\r\n // 文件注解引用 https://,github.com/88250/lute/issues/155\r\n\r\n NodeFileAnnotationRef: 540, // 文件注解引用节点\r\n NodeFileAnnotationRefID: 541, // 被引用的文件注解 ID(file/annotation)\r\n NodeFileAnnotationRefSpace: 542, // 被引用的文件注解 ID 和文件注解引用锚文本之间的空格\r\n NodeFileAnnotationRefText: 543, // 文件注解引用锚文本(不能为空,如果为空的话会自动使用 ID 渲染)\r\n\r\n // 属性视图 https://,github.com/siyuan-note/siyuan/issues/7535 <div data-type=\"NodeAttributeView\" data-av-type=\"table\" data-av-id=\"xxx\"></div>\r\n\r\n NodeAttributeView: 550, // 属性视图\r\n\r\n // 自定义块 https://,github.com/siyuan-note/siyuan/issues/8418 ;;;info\r\n\r\n NodeCustomBlock: 560, // 自定义块\r\n\r\n NodeTypeMaxVal: 1024, // 节点类型最大值\r\n};\r\n","/** ════════════════════════🏳‍🌈 cache 🏳‍🌈════════════════════════\r\n * 对于思源内核 api 的调用存到内存,通过快取技术避免重复请求和没有必要的请求,加速程序运行速度,但这可能会导致数据不是最新的\r\n ** ════════════════════════🚧 cache 🚧════════════════════════ */\r\n\r\nimport { API } from './siyuan_api.ts'\r\nimport { DB_block, DB_block_path, S_Node } from './siyuan_type.ts'\r\n\r\nlet cache = true\r\n/** 控制是否启用快取功能 */\r\nexport function setCache(b: boolean) {\r\n cache = b\r\n}\r\n\r\n/** sql->查询结果 */\r\nconst sqlCacheMap = new Map<string, any>()\r\n/** hpath->S_Node文档节点 */\r\nconst hpathCacheMap = new Map<string, S_Node>()\r\n/** id->S_Node */\r\nconst idCacheMap = new Map<string, S_Node>()\r\n/** id->DB_block */\r\nconst blockCacheMap = new Map<string, DB_block>()\r\n\r\nexport async function getIDsByHPath(p: {\r\n path: string\r\n notebook: string\r\n}): Promise<string[]> {\r\n if (cache && hpathCacheMap.has(p.path)) {\r\n const id = hpathCacheMap.get(p.path)?.ID\r\n // TODO 也许会有重复hpath这里暂不考虑\r\n return id ? [id] : []\r\n }\r\n const ids = await API.filetree_getIDsByHPath(p)\r\n return ids\r\n}\r\n\r\n/** 设置快取 sqlCacheMap */\r\nexport async function query_sql(stmt: string): Promise<any> {\r\n if (cache && sqlCacheMap.has(stmt)) {\r\n return sqlCacheMap.get(stmt)\r\n }\r\n const res = await API.query_sql({\r\n stmt,\r\n })\r\n if (cache) {\r\n sqlCacheMap.set(stmt, res)\r\n }\r\n return res\r\n}\r\n\r\n/** 设置快取 hpathCacheMap idCacheMap */\r\nexport async function get_doc_by_hpath(hpath: string): Promise<S_Node> {\r\n if (cache) {\r\n const c = hpathCacheMap.get(hpath)\r\n if (c) return c\r\n }\r\n const docBlock = (\r\n (await query_sql(\r\n `SELECT * FROM blocks WHERE hpath = '${hpath}'`,\r\n )) as DB_block[]\r\n )[0]\r\n if (docBlock === undefined) throw new Error(`not doc by:${hpath}`)\r\n const res = await get_doc_by_SyPath(DB_block_path(docBlock))\r\n if (cache) {\r\n hpathCacheMap.set(hpath, res)\r\n }\r\n return res\r\n}\r\n/** 设置快取 idCacheMap */\r\nexport async function get_doc_by_SyPath(path: string): Promise<S_Node> {\r\n const res = parentRef(\r\n (await API.file_getFile({\r\n path,\r\n })) as S_Node,\r\n )\r\n if (cache) {\r\n idCache(res)\r\n }\r\n return res\r\n}\r\n\r\nexport async function get_block_by_id(id: string) {\r\n if (cache) {\r\n const block = blockCacheMap.get(id)\r\n if (block) return block\r\n }\r\n const blocks = (await query_sql(`\r\n SELECT * from blocks\r\n WHERE id = '${id}'\r\n `)) as DB_block[]\r\n if (blocks.length === 0) {\r\n return\r\n }\r\n if (cache) blockCacheMap.set(id, blocks[0])\r\n return blocks[0]\r\n}\r\nexport async function get_node_by_id(id?: string) {\r\n if (id === undefined) return\r\n if (cache) {\r\n const node = idCacheMap.get(id)\r\n if (node) return node\r\n }\r\n const doc = await get_doc_by_child_id(id)\r\n if (doc === undefined) return\r\n return findNode(doc)\r\n\r\n function findNode(node: S_Node): S_Node | undefined {\r\n if (node.ID === id) return node\r\n if (node.Children) {\r\n return node.Children.find((child) => findNode(child))\r\n }\r\n }\r\n}\r\n/** set blockCacheMap*/\r\n// TODO 需要更换成能够完全遍历一个笔记本的写法\r\nexport async function allDocBlock_by_bookId(id: string) {\r\n const res = (await query_sql(`\r\n SELECT * from blocks\r\n WHERE box = '${id}'\r\n AND type = 'd'\r\n limit 150000 OFFSET 0\r\n `)) as DB_block[]\r\n if (cache) {\r\n res.forEach((block) => blockCacheMap.set(block.id, block))\r\n }\r\n return res\r\n}\r\n\r\nexport async function get_doc_by_child_id(\r\n id: string,\r\n): Promise<S_Node | undefined> {\r\n if (cache) {\r\n const child = idCacheMap.get(id)\r\n if (child) {\r\n let node = child\r\n while (true) {\r\n if (node.Type === 'NodeDocument') {\r\n return node\r\n } else if (node === undefined) {\r\n break\r\n }\r\n node = node.Parent\r\n }\r\n }\r\n }\r\n const block = await get_block_by_id(id)\r\n if (block === undefined) return\r\n return await get_doc_by_hpath(block.hpath)\r\n}\r\n\r\nfunction idCache(node: S_Node) {\r\n if (node.ID) {\r\n idCacheMap.set(node.ID, node)\r\n }\r\n if (node.Children) {\r\n node.Children.forEach(idCache)\r\n }\r\n}\r\n\r\n/** 为 children 节点附加 Parent 引用 */\r\nexport function parentRef(sy: S_Node) {\r\n for (const child of sy?.Children ?? []) {\r\n child.Parent = sy\r\n parentRef(child)\r\n }\r\n return sy\r\n}\r\n","import { get_node_by_id } from './cache.ts'\nimport type { Config } from './config.ts'\nimport type { Render } from './render.ts'\nimport type { DB_block, S_Node } from './siyuan_type.ts'\n\n/** 生成当前实例所有引用文档的RSS XML */\nexport async function generateRSSXML(\n path: string,\n renderInstance: Render,\n config: Config,\n getHPathByID_Node: (id_node: string | S_Node) => Promise<string>,\n): Promise<string> {\n const refNode = (\n await Promise.all([...renderInstance.refs.values()].map(get_node_by_id))\n ).filter((el) => el)\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n <channel>\n <title>${config.sitemap.title}</title>\n <link>${config.sitemap.siteLink}</link>\n <description>${config.sitemap.description}</description>\n <atom:link href=\"${\n config.sitemap.sitePrefix\n }${path}\" rel=\"self\" type=\"application/rss+xml\"/>\n <lastBuildDate>${new Date().toISOString()}</lastBuildDate>\n ${(\n await Promise.all(\n refNode.map(\n async (node) => `<item>\n <title>${node?.Properties?.title}</title>\n <link>${config.sitemap.sitePrefix}${\n node?.ID ? (await getHPathByID_Node(node?.ID)) + '.html' : ''\n }</link>\n <description>${'' /** TODO 或许可以加入ai 进行摘要 */}</description>\n <pubDate>${\n node?.Properties?.updated\n ? new Date(\n node.Properties.updated.replace(\n /(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})/,\n '$1/$2/$3 $4:$5:$6',\n ),\n ).toISOString()\n : ''\n }</pubDate>\n </item>`,\n ),\n )\n ).join('\\n')}\n </channel>\n </rss>`\n}\n\n/** 生成 sitemap.xml 文件内容 */\nexport function sitemap_xml(\n docArr: DB_block[],\n config: {\n sitePrefix: string\n },\n) {\n const urlList: string = docArr\n .map((doc) => {\n let lastmod = ''\n const time = doc.ial.match(/updated=\\\"(\\d+)\\\"/)?.[1] ?? doc.created\n if (time) {\n lastmod = `\\n<lastmod>${time.slice(0, 4)}-${time.slice(\n 4,\n 6,\n )}-${time.slice(6, 8)}</lastmod>`\n }\n return `<url>\n <loc>${config.sitePrefix}${doc.hpath}.html</loc>${lastmod}\n </url>\\n`\n })\n .join('')\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n ${urlList}\n </urlset>`\n}\n","/**\r\n * SEO 优化和结构化数据生成工具\r\n * 为 OceanPress 生成的 HTML 页面添加 JSON-LD 结构化数据和其他 SEO 优化\r\n */\r\n\r\nimport { Config } from './config.ts'\r\nimport { S_Node } from './siyuan_type.ts'\r\n\r\n\r\n/**\r\n * 从思源文档ID中提取日期时间并格式化为 ISO 8601\r\n * 思源ID格式: 20250801084546-uvfteud -> 2025-08-01T08:45:46Z\r\n */\r\nfunction extractDateFromId(id?: string): string {\r\n if (!id || id.length < 14) return new Date().toISOString()\r\n\r\n try {\r\n const datePart = id.slice(0, 14) // 取前14位: 20250801084546\r\n if (datePart.length === 14) {\r\n const year = datePart.slice(0, 4)\r\n const month = datePart.slice(4, 6)\r\n const day = datePart.slice(6, 8)\r\n const hour = datePart.slice(8, 10)\r\n const minute = datePart.slice(10, 12)\r\n const second = datePart.slice(12, 14)\r\n return `${year}-${month}-${day}T${hour}:${minute}:${second}Z`\r\n }\r\n } catch {\r\n // 忽略解析错误,使用默认值\r\n }\r\n return new Date().toISOString()\r\n}\r\n\r\n/**\r\n * 格式化日期为 ISO 8601 格式\r\n */\r\nfunction formatDate(dateString?: string): string {\r\n if (!dateString) return new Date().toISOString()\r\n try {\r\n // 思源笔记的日期格式通常是 YYYYMMDDHHMMSS 或时间戳\r\n if (dateString.length === 14) {\r\n // YYYYMMDDHHMMSS 格式\r\n const year = dateString.slice(0, 4)\r\n const month = dateString.slice(4, 6)\r\n const day = dateString.slice(6, 8)\r\n const hour = dateString.slice(8, 10)\r\n const minute = dateString.slice(10, 12)\r\n const second = dateString.slice(12, 14)\r\n return `${year}-${month}-${day}T${hour}:${minute}:${second}Z`\r\n }\r\n // 尝试解析为时间戳\r\n const timestamp = parseInt(dateString)\r\n if (!isNaN(timestamp)) {\r\n return new Date(timestamp).toISOString()\r\n }\r\n // 尝试直接解析\r\n return new Date(dateString).toISOString()\r\n } catch {\r\n return new Date().toISOString()\r\n }\r\n}\r\n\r\n/**\r\n * TF-IDF 关键词提取算法\r\n */\r\nclass TFIDFKeywordExtractor {\r\n private stopWords = new Set([\r\n // 中文停用词\r\n '的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这', '那', '现在', '可以', '但是', '还是', '因为', '什么', '如果', '所以', '对于', '关于', '通过', '进行', '基于', '以及', '或者', '而且', '然后', '只是', '已经', '正在', '应该', '能够', '需要', '可能', '一定', '这样', '那样', '怎么', '为什么', '哪里', '哪个', '多少', '几个', '什么', '怎么', '如何', '为什么',\r\n // 英文停用词\r\n 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'must', 'can', 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they', 'me', 'him', 'her', 'us', 'them', 'my', 'your', 'his', 'its', 'our', 'their', 'not', 'no', 'yes', 'so', 'if', 'when', 'where', 'how', 'why', 'what', 'which', 'who', 'whom', 'there', 'here'\r\n ])\r\n\r\n /**\r\n * 计算词频 (TF)\r\n */\r\n private calculateTermFrequency(text: string): Map<string, number> {\r\n const words = this.tokenize(text)\r\n const tf = new Map<string, number>()\r\n const totalWords = words.length\r\n\r\n for (const word of words) {\r\n tf.set(word, (tf.get(word) || 0) + 1)\r\n }\r\n\r\n // 标准化词频\r\n for (const [word, count] of tf) {\r\n tf.set(word, count / totalWords)\r\n }\r\n\r\n return tf\r\n }\r\n\r\n /**\r\n * 分词处理(针对中文和英文优化)\r\n */\r\n private tokenize(text: string): string[] {\r\n const tokens: string[] = []\r\n\r\n // 首先彻底清理HTML标签和属性,只保留纯文本内容\r\n const plainText = text\r\n .replace(/<[^>]*>/g, ' ') // 移除所有HTML标签\r\n .replace(/&[^;]+;/g, ' ') // 移除HTML实体\r\n .replace(/\\s+/g, ' ') // 合并多个空格\r\n .trim()\r\n\r\n // 1. 提取英文单词和技术术语(优先处理)\r\n const englishWords = plainText.match(/[a-zA-Z]{3,}/g) || []\r\n tokens.push(...englishWords.map(word => word.toLowerCase()).filter(word => !this.stopWords.has(word)))\r\n\r\n // 2. 提取驼峰命名(如 useState, useEffect)\r\n const camelCaseWords = plainText.match(/[a-z]+[A-Z][a-zA-Z0-9]*|[A-Z][a-z0-9]+[A-Z][a-zA-Z0-9]*/g) || []\r\n tokens.push(...camelCaseWords.map(word => word.toLowerCase()))\r\n\r\n // 3. 智能中文分词 - 基于文本特征分析\r\n const chineseTokens = this.extractChineseTokens(plainText)\r\n tokens.push(...chineseTokens)\r\n\r\n // 4. 后处理:过滤掉无意义的词汇\r\n const filteredTokens = tokens.filter(token => {\r\n // 过滤掉长度小于2的词汇\r\n if (token.length < 2) return false\r\n\r\n // 过滤掉HTML相关的无意义词汇\r\n const htmlRelatedWords = ['div', 'span', 'class', 'id', 'type', 'data', 'href', 'src', 'alt', 'title', 'style', 'width', 'height', 'rootid', 'endid', 'nodedocument', 'ezcqbj', 'cktc', 'quot']\r\n if (htmlRelatedWords.includes(token.toLowerCase())) {\r\n return false\r\n }\r\n\r\n // 过滤掉看起来像属性名或ID的词汇\r\n if (token.match(/^[a-f0-9]{6,}$/)) return false // 过滤掉十六进制ID\r\n\r\n // 过滤掉看起来不像是完整词汇的中文词汇\r\n if (/[\\u4e00-\\u9fa5]/.test(token) && token.length < 2) {\r\n return false\r\n }\r\n\r\n return true\r\n })\r\n\r\n return filteredTokens\r\n }\r\n\r\n /**\r\n * 智能中文分词 - 基于文本特征分析\r\n */\r\n private extractChineseTokens(text: string): string[] {\r\n const tokens: string[] = []\r\n\r\n // 提取中文文本\r\n const chineseText = text.replace(/[^\\u4e00-\\u9fa5\\s]/g, ' ')\r\n\r\n // 基于常见中文词汇模式进行提取\r\n // 2-4字的中文词汇通常是完整的词汇\r\n const wordPatterns = [\r\n /[\\u4e00-\\u9fa5]{4}/g, // 4字词汇\r\n /[\\u4e00-\\u9fa5]{3}/g, // 3字词汇\r\n /[\\u4e00-\\u9fa5]{2}/g, // 2字词汇\r\n ]\r\n\r\n for (const pattern of wordPatterns) {\r\n const matches = chineseText.match(pattern) || []\r\n for (const word of matches) {\r\n if (!this.stopWords.has(word) && this.isMeaningfulChineseWord(word)) {\r\n tokens.push(word.toLowerCase())\r\n }\r\n }\r\n }\r\n\r\n return tokens\r\n }\r\n\r\n /**\r\n * 判断是否为有意义的中文词汇\r\n */\r\n private isMeaningfulChineseWord(word: string): boolean {\r\n // 过滤掉常见的无意义组合\r\n const meaninglessPatterns = [\r\n /^的.*$/, /^.*的$/, /^了.*$/, /^.*了$/,\r\n /^在.*$/, /^.*在$/, /^是.*$/, /^.*是$/,\r\n /^我.*$/, /^.*我$/, /^有.*$/, /^.*有$/,\r\n /^和.*$/, /^.*和$/, /^就.*$/, /^.*就$/,\r\n /^不.*$/, /^.*不$/, /^人.*$/, /^.*人$/\r\n ]\r\n\r\n for (const pattern of meaninglessPatterns) {\r\n if (pattern.test(word)) {\r\n return false\r\n }\r\n }\r\n\r\n // 检查是否包含重复字符\r\n if (/(.)\\1{2,}/.test(word)) {\r\n return false\r\n }\r\n\r\n return true\r\n }\r\n\r\n /**\r\n * 计算逆文档频率 (IDF) - 简化版本\r\n */\r\n private calculateInverseDocumentFrequency(term: string): number {\r\n // 简化的IDF计算,基于常见词汇频率\r\n const commonTerms = new Set([\r\n '技术', '开发', '代码', '系统', '数据', '功能', '应用', '实现', '方法', '问题',\r\n 'time', 'data', 'system', 'code', 'development', 'application', 'function', 'method', 'problem', 'solution'\r\n ])\r\n\r\n if (commonTerms.has(term.toLowerCase())) {\r\n return Math.log(1000 / 500) // 常见词汇权重较低\r\n }\r\n\r\n return Math.log(1000 / 10) // 稀有词汇权重较高\r\n }\r\n\r\n /**\r\n * 提取关键词\r\n */\r\n extractKeywords(content: string, maxKeywords: number = 10): string[] {\r\n const tf = this.calculateTermFrequency(content)\r\n const keywordScores = new Map<string, number>()\r\n\r\n // 计算 TF-IDF 分数\r\n for (const [term, frequency] of tf) {\r\n const idf = this.calculateInverseDocumentFrequency(term)\r\n const tfidf = frequency * idf\r\n\r\n // 额外的权重规则\r\n let bonus = 1\r\n\r\n // 标题中的词汇权重更高\r\n if (content.toLowerCase().includes(term.toLowerCase()) &&\r\n (content.match(new RegExp(`^${term}`, 'mi')) || content.match(new RegExp(`${term}$`, 'mi')))) {\r\n bonus *= 1.5\r\n }\r\n\r\n // 长度适中的词汇权重更高\r\n if (term.length >= 2 && term.length <= 6) {\r\n bonus *= 1.2\r\n }\r\n\r\n keywordScores.set(term, tfidf * bonus)\r\n }\r\n\r\n // 排序并返回前N个关键词\r\n return Array.from(keywordScores.entries())\r\n .sort((a, b) => b[1] - a[1])\r\n .slice(0, maxKeywords)\r\n .map(([term]) => term)\r\n }\r\n}\r\n\r\n/**\r\n * 从文档内容中提取描述文本\r\n */\r\nfunction extractDescription(content: string, maxLength = 160): string {\r\n // 移除 HTML 标签\r\n const plainText = content\r\n .replace(/<[^>]*>/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim()\r\n\r\n if (plainText.length <= maxLength) return plainText\r\n\r\n // 尝试在句子边界截断\r\n const truncated = plainText.substring(0, maxLength)\r\n const lastSentenceEnd = Math.max(\r\n truncated.lastIndexOf('。'),\r\n truncated.lastIndexOf('!'),\r\n truncated.lastIndexOf('?'),\r\n truncated.lastIndexOf('.'),\r\n truncated.lastIndexOf('!'),\r\n truncated.lastIndexOf('?')\r\n )\r\n\r\n if (lastSentenceEnd > maxLength * 0.7) {\r\n return truncated.substring(0, lastSentenceEnd + 1)\r\n }\r\n\r\n return truncated + '...'\r\n}\r\n\r\n/**\r\n * 从内容中提取关键词(使用TF-IDF算法)\r\n */\r\nfunction extractKeywords(content: string): string[] {\r\n const tfidfExtractor = new TFIDFKeywordExtractor()\r\n return tfidfExtractor.extractKeywords(content, 8)\r\n}\r\n\r\n/**\r\n * 生成文章的 JSON-LD 结构化数据\r\n */\r\nexport function generateArticleJsonLd(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n content: string\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const description = extractDescription(content)\r\n const keywords = extractKeywords(content)\r\n // 从ID中提取创建时间,如果没有则使用updated时间\r\n const datePublished = extractDateFromId(doc.ID)\r\n const dateModified = formatDate(doc.Properties?.updated)\r\n\r\n const jsonLd = {\r\n '@context': 'https://schema.org',\r\n '@type': 'Article',\r\n headline: title,\r\n description: description,\r\n keywords: keywords.join(', '),\r\n datePublished: datePublished,\r\n dateModified: dateModified,\r\n author: {\r\n '@type': 'Person',\r\n name: config.sitemap?.title || '崮生',\r\n url: config.sitemap?.siteLink || ''\r\n },\r\n publisher: {\r\n '@type': 'Organization',\r\n name: config.sitemap?.title || 'OceanPress',\r\n logo: {\r\n '@type': 'ImageObject',\r\n url: `${config.sitemap?.siteLink || ''}/assets/logo.png`\r\n }\r\n },\r\n mainEntityOfPage: {\r\n '@type': 'WebPage',\r\n '@id': pageUrl\r\n },\r\n image: doc.Properties?.['title-img'] ? {\r\n '@type': 'ImageObject',\r\n url: `${config.sitemap?.siteLink || ''}${doc.Properties['title-img'].replace('assets', '/assets')}`,\r\n width: 1200,\r\n height: 630\r\n } : undefined,\r\n wordCount: content.replace(/<[^>]*>/g, '').length,\r\n articleSection: '技术文档',\r\n inLanguage: 'zh-CN'\r\n }\r\n\r\n return `<script type=\"application/ld+json\">\r\n${JSON.stringify(jsonLd, null, 2)}\r\n</script>`\r\n}\r\n\r\n/**\r\n * 生成面包屑导航的 JSON-LD\r\n */\r\nexport function generateBreadcrumbJsonLd(\r\n breadcrumbs: Array<{ name: string; url: string }>\r\n): string {\r\n const itemListElement = breadcrumbs.map((crumb, index) => ({\r\n '@type': 'ListItem',\r\n position: index + 1,\r\n name: crumb.name,\r\n item: crumb.url\r\n }))\r\n\r\n const jsonLd = {\r\n '@context': 'https://schema.org',\r\n '@type': 'BreadcrumbList',\r\n itemListElement: itemListElement\r\n }\r\n\r\n return `<script type=\"application/ld+json\">\r\n${JSON.stringify(jsonLd, null, 2)}\r\n</script>`\r\n}\r\n\r\n/**\r\n * 生成网站的 JSON-LD\r\n */\r\nexport function generateWebsiteJsonLd(config: Config): string {\r\n const jsonLd = {\r\n '@context': 'https://schema.org',\r\n '@type': 'WebSite',\r\n name: config.sitemap?.title || 'OceanPress 站点',\r\n description: config.sitemap?.description || '基于思源笔记的静态站点',\r\n url: config.sitemap?.siteLink || '',\r\n author: {\r\n '@type': 'Person',\r\n name: '崮生'\r\n },\r\n potentialAction: {\r\n '@type': 'SearchAction',\r\n target: {\r\n '@type': 'EntryPoint',\r\n urlTemplate: `${config.sitemap?.siteLink || ''}/search?q={search_term_string}`\r\n },\r\n 'query-input': 'required name=search_term_string'\r\n },\r\n inLanguage: 'zh-CN'\r\n }\r\n\r\n return `<script type=\"application/ld+json\">\r\n${JSON.stringify(jsonLd, null, 2)}\r\n</script>`\r\n}\r\n\r\n/**\r\n * 生成完整的 SEO meta 标签\r\n */\r\nexport function generateSeoMetaTags(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n content: string\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const description = extractDescription(content)\r\n const keywords = extractKeywords(content)\r\n\r\n let metaTags = ''\r\n\r\n // 基础 meta 标签\r\n metaTags += ` <meta name=\"description\" content=\"${description.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta name=\"keywords\" content=\"${keywords.join(', ')}\" />\\n`\r\n metaTags += ` <meta name=\"author\" content=\"${config.sitemap?.title || '崮生'}\" />\\n`\r\n\r\n // Open Graph 标签\r\n metaTags += ` <meta property=\"og:title\" content=\"${title.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta property=\"og:description\" content=\"${description.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta property=\"og:type\" content=\"article\" />\\n`\r\n metaTags += ` <meta property=\"og:url\" content=\"${pageUrl}\" />\\n`\r\n metaTags += ` <meta property=\"og:site_name\" content=\"${config.sitemap?.title || 'OceanPress'}\" />\\n`\r\n\r\n if (doc.Properties?.['title-img']) {\r\n const imageUrl = `${config.sitemap?.siteLink || ''}${doc.Properties['title-img'].replace('assets', '/assets')}`\r\n metaTags += ` <meta property=\"og:image\" content=\"${imageUrl}\" />\\n`\r\n metaTags += ` <meta property=\"og:image:width\" content=\"1200\" />\\n`\r\n metaTags += ` <meta property=\"og:image:height\" content=\"630\" />\\n`\r\n }\r\n\r\n // 从ID中提取创建时间\r\n const datePublished = extractDateFromId(doc.ID)\r\n const dateModified = formatDate(doc.Properties?.updated)\r\n\r\n metaTags += ` <meta property=\"article:published_time\" content=\"${datePublished}\" />\\n`\r\n metaTags += ` <meta property=\"article:modified_time\" content=\"${dateModified}\" />\\n`\r\n\r\n // Twitter Card 标签\r\n metaTags += ` <meta name=\"twitter:card\" content=\"summary_large_image\" />\\n`\r\n metaTags += ` <meta name=\"twitter:title\" content=\"${title.replace(/\"/g, '&quot;')}\" />\\n`\r\n metaTags += ` <meta name=\"twitter:description\" content=\"${description.replace(/\"/g, '&quot;')}\" />\\n`\r\n\r\n if (doc.Properties?.['title-img']) {\r\n const imageUrl = `${config.sitemap?.siteLink || ''}${doc.Properties['title-img'].replace('assets', '/assets')}`\r\n metaTags += ` <meta name=\"twitter:image\" content=\"${imageUrl}\" />\\n`\r\n }\r\n\r\n // 其他 SEO 标签\r\n metaTags += ` <meta name=\"robots\" content=\"index, follow\" />\\n`\r\n metaTags += ` <link rel=\"canonical\" href=\"${pageUrl}\" />\\n`\r\n\r\n return metaTags\r\n}\r\n\r\n/**\r\n * SEO 数据接口\r\n */\r\nexport interface SeoData {\r\n doc: S_Node\r\n config: Config\r\n pageUrl: string\r\n content: string\r\n breadcrumbs?: Array<{ name: string; url: string }>\r\n}\r\n\r\n/**\r\n * 生成完整的 SEO 优化代码\r\n */\r\nexport function generateSeoContent(data: SeoData): {\r\n metaTags: string\r\n jsonLd: string\r\n} {\r\n const metaTags = generateSeoMetaTags(data.doc, data.config, data.pageUrl, data.content)\r\n\r\n let jsonLd = generateArticleJsonLd(data.doc, data.config, data.pageUrl, data.content)\r\n\r\n if (data.breadcrumbs && data.breadcrumbs.length > 0) {\r\n jsonLd += '\\n' + generateBreadcrumbJsonLd(data.breadcrumbs)\r\n }\r\n\r\n return {\r\n metaTags,\r\n jsonLd\r\n }\r\n}","import { generateSeoContent } from './seo.ts'\r\n\r\n/** 添加对应的 html 模板 */\r\nexport async function htmlTemplate(\r\n p: {\r\n htmlContent: string\r\n title: string\r\n level: number\r\n seoData?: {\r\n doc: any\r\n config: any\r\n pageUrl: string\r\n breadcrumbs?: Array<{ name: string; url: string }>\r\n }\r\n },\r\n config?: {\r\n siyuanPrefix: string\r\n embedCode?: { head?: string; beforeBody?: string; afterBody?: string }\r\n },\r\n) {\r\n /** 根据level有几级返回多少个 '../' ,用于解决 file协议打开html文档无法正常加载资源 */\r\n let prePath = ''\r\n if (config?.siyuanPrefix) {\r\n prePath = config.siyuanPrefix\r\n } else {\r\n for (let i = 0; i < p.level; i++) {\r\n prePath += '../'\r\n }\r\n }\r\n const version = '2.10.5'\r\n /** 思源中导出 html 代码: https://github1s.com/siyuan-note/siyuan/blob/HEAD/app/src/protyle/export/index.ts#L652 */\r\n //data-theme-mode=\"dark\" data-light-theme=\"daylight\" data-dark-theme=\"midnight\"\r\n return `<!DOCTYPE html>\r\n<html lang=\"zh_CN\" data-theme-mode=\"light\" data-light-theme=\"daylight\" data-dark-theme=\"midnight\">\r\n<head>\r\n ${config?.embedCode?.head ?? ''}\r\n <meta charset=\"utf-8\" />\r\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"/>\r\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\r\n <meta name=\"mobile-web-app-capable\" content=\"yes\" />\r\n <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black\" />\r\n ${\r\n p.seoData\r\n ? generateSeoContent({\r\n doc: p.seoData.doc,\r\n config: p.seoData.config,\r\n pageUrl: p.seoData.pageUrl,\r\n content: p.htmlContent,\r\n breadcrumbs: p.seoData.breadcrumbs,\r\n }).metaTags\r\n : ''\r\n }\r\n <link rel=\"stylesheet\" type=\"text/css\" id=\"baseStyle\" href=\"${prePath}stage/build/export/base.css?${version}\"/>\r\n <script>\r\n // 更好的主题切换方案\r\n (function() {\r\n // 主题配置\r\n const themes = {\r\n light: {\r\n name: 'daylight',\r\n mode: 'light',\r\n icon: '☀️'\r\n },\r\n dark: {\r\n name: 'midnight',\r\n mode: 'dark',\r\n icon: '🌙'\r\n },\r\n auto: {\r\n name: 'auto',\r\n mode: 'auto',\r\n icon: '🌗',\r\n getTheme: function() {\r\n const currentHour = new Date().getHours();\r\n return currentHour >= 18 || currentHour < 6 ? 'dark' : 'light';\r\n }\r\n }\r\n };\r\n\r\n // 获取当前主题设置\r\n function getCurrentTheme() {\r\n // 优先级:localStorage > 系统偏好 > auto\r\n const savedTheme = localStorage.getItem('oceanpress-theme');\r\n if (savedTheme && themes[savedTheme]) {\r\n return savedTheme;\r\n }\r\n\r\n // 检测系统偏好\r\n if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {\r\n return 'dark';\r\n }\r\n if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {\r\n return 'light';\r\n }\r\n\r\n return 'auto';\r\n }\r\n\r\n // 应用主题\r\n function applyTheme(themeName) {\r\n const theme = themes[themeName] || themes.auto;\r\n const actualTheme = themeName === 'auto' ? theme.getTheme() : themeName;\r\n const themeConfig = themes[actualTheme];\r\n\r\n // 设置 CSS 变量\r\n document.documentElement.setAttribute('data-theme-mode', themeConfig.mode);\r\n document.documentElement.setAttribute('data-light-theme', 'daylight');\r\n document.documentElement.setAttribute('data-dark-theme', 'midnight');\r\n\r\n // 加载对应的 CSS\r\n const themeStyle = document.getElementById('themeDefaultStyle');\r\n if (themeStyle) {\r\n themeStyle.href = '${prePath}appearance/themes/' + themeConfig.name + '/theme.css?${version}';\r\n } else {\r\n // 如果元素不存在,创建它\r\n const link = document.createElement('link');\r\n link.id = 'themeDefaultStyle';\r\n link.rel = 'stylesheet';\r\n link.type = 'text/css';\r\n link.href = '${prePath}appearance/themes/' + themeConfig.name + '/theme.css?${version}';\r\n document.head.appendChild(link);\r\n }\r\n\r\n // 更新主题切换按钮\r\n updateThemeToggle(themeName);\r\n\r\n // 保存到 localStorage\r\n localStorage.setItem('oceanpress-theme', themeName);\r\n\r\n // 触发自定义事件\r\n window.dispatchEvent(new CustomEvent('oceanpress-theme-changed', {\r\n detail: { theme: themeName, actualTheme: actualTheme }\r\n }));\r\n }\r\n\r\n // 创建主题切换按钮\r\n function createThemeToggle() {\r\n const toggle = document.createElement('div');\r\n toggle.id = 'oceanpress-theme-toggle';\r\n toggle.innerHTML = '<span class=\"theme-icon\">🌗</span><span class=\"theme-text\">自动</span>';\r\n toggle.addEventListener('click', toggleTheme);\r\n (document.querySelector('[data-type=\"NodeDocument\"]')||document.body).appendChild(toggle);\r\n }\r\n\r\n // 更新主题切换按钮\r\n function updateThemeToggle(themeName) {\r\n const toggle = document.getElementById('oceanpress-theme-toggle');\r\n if (!toggle) return;\r\n\r\n const theme = themes[themeName] || themes.auto;\r\n toggle.innerHTML = '<span class=\"theme-icon\">' + theme.icon + '</span><span class=\"theme-text\">' +\r\n (themeName === 'auto' ? '自动' : (themeName === 'dark' ? '深色' : '浅色')) + '</span>';\r\n }\r\n\r\n // 切换主题\r\n function toggleTheme() {\r\n const currentTheme = getCurrentTheme();\r\n const themeOrder = ['auto', 'light', 'dark'];\r\n const currentIndex = themeOrder.indexOf(currentTheme);\r\n const nextIndex = (currentIndex + 1) % themeOrder.length;\r\n const nextTheme = themeOrder[nextIndex];\r\n\r\n applyTheme(nextTheme);\r\n }\r\n\r\n // 监听系统主题变化\r\n if (window.matchMedia) {\r\n window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {\r\n const currentTheme = getCurrentTheme();\r\n if (currentTheme === 'auto') {\r\n applyTheme('auto');\r\n }\r\n });\r\n }\r\n\r\n // 监听自定义主题变化事件(用于侧边栏等组件)\r\n window.addEventListener('oceanpress-theme-changed', function(e) {\r\n // 这里可以添加其他组件需要响应主题变化的逻辑\r\n console.log('Theme changed to:', e.detail);\r\n });\r\n\r\n // 初始化主题\r\n function initTheme() {\r\n const themeName = getCurrentTheme();\r\n const theme = themes[themeName] || themes.auto;\r\n const actualTheme = themeName === 'auto' ? theme.getTheme() : themeName;\r\n const themeConfig = themes[actualTheme];\r\n\r\n // 立即设置基础主题,避免闪烁\r\n document.documentElement.setAttribute('data-theme-mode', themeConfig.mode);\r\n document.documentElement.setAttribute('data-light-theme', 'daylight');\r\n document.documentElement.setAttribute('data-dark-theme', 'midnight');\r\n\r\n // 创建主题切换按钮\r\n createThemeToggle();\r\n\r\n // 应用完整主题\r\n applyTheme(themeName);\r\n }\r\n\r\n // 页面加载完成后初始化\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', initTheme);\r\n } else {\r\n initTheme();\r\n }\r\n })();\r\n </script>\r\n <link rel=\"stylesheet\" type=\"text/css\" href=\"${prePath}appearance/oceanpress.css\"/>\r\n <title>${p.title}</title>\r\n ${\r\n p.seoData\r\n ? generateSeoContent({\r\n doc: p.seoData.doc,\r\n config: p.seoData.config,\r\n pageUrl: p.seoData.pageUrl,\r\n content: p.htmlContent,\r\n breadcrumbs: p.seoData.breadcrumbs,\r\n }).jsonLd\r\n : ''\r\n }\r\n</head>\r\n<body>\r\n ${config?.embedCode?.beforeBody ?? ''}\r\n ${p.htmlContent}\r\n <script src=\"${prePath}appearance/icons/material/icon.js?${version}\"></script>\r\n <script src=\"${prePath}stage/build/export/protyle-method.js?${version}\"></script>\r\n <script src=\"${prePath}stage/protyle/js/lute/lute.min.js?${version}\"></script>\r\n <script>\r\n window.siyuan = {\r\n config: {\r\n appearance: {\r\n mode: document.documentElement.getAttribute('data-theme-mode') === 'dark' ? 1 : 0,//主题 明亮=0 暗黑=1\r\n codeBlockThemeDark: \"base16/dracula\",\r\n codeBlockThemeLight: \"github\",\r\n },\r\n editor: {\r\n codeLineWrap: true,\r\n codeLigatures: false,\r\n plantUMLServePath: \"https://www.plantuml.com/plantuml/svg/~1\",\r\n codeSyntaxHighlightLineNum: true,\r\n katexMacros: JSON.stringify({}),\r\n },\r\n },\r\n languages: { copy: \"复制\" },\r\n };\r\n const cdn = \"${prePath}stage/protyle\";\r\n const previewElement = document.getElementById(\"preview\");\r\n\r\n Protyle.highlightRender(previewElement, cdn);\r\n Protyle.mathRender(previewElement, cdn, false);\r\n Protyle.mermaidRender(previewElement, cdn);\r\n Protyle.flowchartRender(previewElement, cdn);\r\n Protyle.graphvizRender(previewElement, cdn);\r\n Protyle.chartRender(previewElement, cdn);\r\n Protyle.mindmapRender(previewElement, cdn);\r\n Protyle.abcRender(previewElement, cdn);\r\n Protyle.htmlRender(previewElement);\r\n Protyle.plantumlRender(previewElement, cdn);\r\n document.querySelectorAll(\".protyle-action__copy\").forEach((item) => {\r\n item.addEventListener(\"click\", (event) => {\r\n navigator.clipboard.writeText(\r\n item.parentElement.nextElementSibling.textContent.trimEnd(),\r\n );\r\n event.preventDefault();\r\n event.stopPropagation();\r\n });\r\n });\r\n </script>\r\n ${config?.embedCode?.afterBody ?? ''}\r\n</body>\r\n</html>`\r\n}\r\n","import { Context, Effect } from 'effect'\r\nimport { escaping, unescaping } from '~/util/escaping.ts'\r\nimport { EffectConfigDep, EffectRender } from './EffectDep.ts'\r\nimport { API } from './siyuan_api.ts'\r\nimport { DB_block, NodeType, S_Node } from './siyuan_type.ts'\r\nimport { renderDocTreeJsPath } from './renderDocTree.ts'\r\n\r\nexport type RenderHTML = typeof renderHTML\r\nexport type Render = Effect.Effect.Success<typeof renderProgram>\r\n\r\n/** 将指定 S_Node 渲染成对应的 html 代码 */\r\nexport const renderHTML = (\r\n sy: S_Node | undefined,\r\n /**\r\n * renderHTML 内部会创建一个 renderInstance 的浅克隆\r\n * 用来维护 renderHTML.nodeStack 的正常运转\r\n */\r\n render?: Render,\r\n) =>\r\n Effect.gen(function* () {\r\n if (sy === undefined) return ''\r\n const defaultRender = yield* getRender\r\n const renderInstance = render ?? defaultRender\r\n const renderObj: Render = {\r\n ...renderInstance,\r\n nodeStack: [\r\n /** 避免让所有的 renderInstance.nodeStack 是同一个对象 ,所以这里复制一个新的 */ ...renderInstance.nodeStack,\r\n ],\r\n }\r\n if (\r\n renderInstance.nodeStack.find(\r\n (node) => node.ID && sy.ID && node.ID === sy.ID,\r\n )\r\n ) {\r\n return warnDiv(\r\n '循环引用',\r\n [...renderInstance.nodeStack, sy].map((el) => el.ID),\r\n )\r\n }\r\n if (renderObj[sy.Type] === undefined) {\r\n return warnDiv(\r\n `没有找到对应的渲染方法 ${sy.Type} ${renderObj.nodeStack[0].Properties?.title}`,\r\n )\r\n } else {\r\n /** 入栈 */\r\n renderObj.nodeStack.push(sy)\r\n /** 维护引用关系 */\r\n if (sy.ID && renderInstance.nodeStack[0]?.ID) {\r\n const storeDep = yield* EffectRender\r\n const id = sy.ID\r\n const targetDoc = yield* Effect.tryPromise(() =>\r\n storeDep.getDocByChildID(id),\r\n )\r\n const currentDoc = renderInstance.nodeStack[0]\r\n if (\r\n targetDoc?.ID !== undefined &&\r\n targetDoc.ID !== currentDoc.ID &&\r\n currentDoc.ID\r\n ) {\r\n /** 代表这个节点不在当前文档中,却在编译currentDoc时出现了,所以 currentDoc依赖(正向引用)targetDoc */\r\n // 记录引用 TODO 不应该在 render中之直接记录,该上报\r\n renderObj.refs.add(targetDoc.ID)\r\n }\r\n }\r\n const r = yield* Effect.tryPromise(() => renderObj[sy.Type]!(sy))\r\n /** 出栈 */\r\n renderObj.nodeStack.pop()\r\n return r\r\n }\r\n })\r\n\r\nfunction warnDiv(msg: string, ...args: any[]) {\r\n warn(msg, ...args)\r\n return `<div class=\"ft__smaller ft__secondary b3-form__space--small\">${msg}</div>`\r\n}\r\nfunction isRenderCode(sy: S_Node) {\r\n const mark = atob(\r\n sy.CodeBlockInfo ??\r\n sy.Children?.find((el) => el.Type === 'NodeCodeBlockFenceInfoMarker')\r\n ?.CodeBlockInfo ??\r\n '',\r\n )\r\n return [\r\n [\r\n 'mindmap',\r\n 'mermaid',\r\n 'echarts',\r\n 'abc',\r\n 'graphviz',\r\n 'flowchart',\r\n 'plantuml',\r\n ].includes(mark),\r\n mark,\r\n ] as const\r\n}\r\nconst html = String.raw\r\n\r\nfunction strAttr(\r\n sy: S_Node,\r\n config: {\r\n subtype_class?: string | [string, string]\r\n data_type?: string\r\n } = {},\r\n) {\r\n if (config?.subtype_class === undefined) {\r\n config.subtype_class = (() => {\r\n const typ_subtype =\r\n sy.ListData?.Typ === 1\r\n ? /** 有序列表 */ 'o'\r\n : sy.ListData?.Typ === 3\r\n ? /** 任务列表 */ 't'\r\n : /** 无序列表 */ 'u'\r\n\r\n if (sy.Type === 'NodeDocument') return ''\r\n else if (sy.Type === 'NodeHeading') return `h${sy.HeadingLevel}`\r\n else if (sy.Type === 'NodeList') return [typ_subtype, 'list']\r\n else if (sy.Type === 'NodeListItem') return [typ_subtype, 'li']\r\n else if (sy.Type === 'NodeParagraph') return ['', 'p']\r\n else if (sy.Type === 'NodeImage') return ['', 'img']\r\n else if (sy.Type === 'NodeBlockquote') return ['', 'bq']\r\n else if (sy.Type === 'NodeSuperBlock') return ['', 'sb']\r\n else if (sy.Type === 'NodeCodeBlock') {\r\n const [yes, mark] = isRenderCode(sy)\r\n if (yes) {\r\n /** 脑图等需要渲染的块 */\r\n return [mark, 'render-node']\r\n } else {\r\n return ['', 'code-block']\r\n }\r\n } else if (sy.Type === 'NodeTable') return ['', 'table']\r\n else if (sy.Type === 'NodeThematicBreak') return ['', 'hr']\r\n else if (sy.Type === 'NodeMathBlock') return ['math', 'render-node']\r\n else if (sy.Type === 'NodeIFrame') return ['', 'iframe']\r\n else if (sy.Type === 'NodeVideo') return ['', 'iframe']\r\n else return ''\r\n })()\r\n }\r\n const attrObj = {} as { [k: string]: string }\r\n function addAttr(key: string, value: string) {\r\n attrObj[key] = value\r\n }\r\n if (sy.ID) {\r\n addAttr('id', sy.ID)\r\n addAttr('data-node-id', sy.ID)\r\n }\r\n\r\n if (sy?.TextMarkType === 'tag') {\r\n addAttr(`data-type`, sy.TextMarkType ?? '')\r\n } else {\r\n addAttr(`data-type`, config?.data_type ?? sy.Type)\r\n }\r\n if (sy.Properties?.updated) addAttr('updated', sy.Properties.updated)\r\n if (config?.subtype_class) {\r\n if (typeof config.subtype_class === 'string') {\r\n addAttr('data-subtype', config.subtype_class)\r\n addAttr('class', config.subtype_class)\r\n } else {\r\n if (config.subtype_class[0] !== '')\r\n addAttr('data-subtype', config.subtype_class[0])\r\n if (config.subtype_class[1] !== '')\r\n addAttr('class', config.subtype_class[1])\r\n }\r\n }\r\n if (sy.Properties) {\r\n Object.entries(sy.Properties).forEach(([k, v]) => addAttr(k, v))\r\n }\r\n if (sy.ListData?.Marker) addAttr('data-marker', atob(sy.ListData.Marker))\r\n if (\r\n /** 任务列表 */ sy.ListData?.Typ === 3 &&\r\n /** 该项被选中 */ sy.Children?.find(\r\n (el) => el.Type === 'NodeTaskListItemMarker',\r\n )?.TaskListItemChecked\r\n ) {\r\n attrObj['class'] = (attrObj['class'] ?? '') + ' protyle-task--done '\r\n }\r\n /** 不折叠任何项目 */ delete attrObj['fold']\r\n /** 避免任意元素上悬停都显示文档标题 */\r\n if (sy.Type === 'NodeDocument') delete attrObj['title']\r\n return Object.entries(attrObj)\r\n .map(([k, v]) => `${k}=\"${v}\"`)\r\n .join(' ')\r\n}\r\n/** 返回空字符串,一般用于不用解析的节点 */\r\nconst _emptyString = async (_sy: S_Node) => ''\r\nconst _dataString = async (sy: S_Node) => sy.Data ?? ''\r\n\r\n/** 对一些数据常量进行处理 */\r\nexport const getRender = Effect.gen(function* () {\r\n const render = yield* renderProgram\r\n return {\r\n ...render,\r\n nodeStack: [],\r\n refs: new Set(),\r\n } as Render\r\n})\r\n\r\nconst renderProgram = Effect.gen(function* () {\r\n const storeDep = yield* EffectRender\r\n const config = yield* EffectConfigDep\r\n const context = Context.empty().pipe(\r\n Context.add(EffectRender, storeDep),\r\n Context.add(EffectConfigDep, config),\r\n )\r\n async function callChildRender(sy: S_Node, renderInstance: Render) {\r\n const children = sy?.Children ?? []\r\n\r\n // 1. 创建所有子节点的渲染任务(并发启动)\r\n const promises = children.map((el) =>\r\n Effect.runPromise(\r\n Effect.provide(renderHTML(el, renderInstance), context),\r\n ),\r\n )\r\n\r\n // 2. 等待所有任务完成,保持原顺序\r\n const results = await Promise.all(promises)\r\n\r\n // 3. 按顺序拼接结果\r\n return results.join('')\r\n }\r\n async function callRenderHTML(sy: S_Node | undefined, render?: Render) {\r\n return Effect.runPromise(Effect.provide(renderHTML(sy, render), context))\r\n }\r\n\r\n const render: {\r\n [key in keyof typeof NodeType]?: (sy: S_Node) => Promise<string>\r\n } & {\r\n /**\r\n * 用于保存调用栈,即从根节点到当前节点。\r\n * 例如在渲染 文档A中引用了文档B中的节点 时调用栈如下\r\n * ```\r\n * nodeStack ~= [A_NodeDocument,A_NodeList,...,A_block-ref,B_Node]\r\n * ```\r\n * 对render中的函数意味着 `this.nodeStack[0]===需要生成的文档`\r\n * 这样就方便解决 block-ref 等链接问题\r\n * */\r\n nodeStack: S_Node[]\r\n /** 当前实例所引用的其他文档id,在渲染中计算 */\r\n refs: Set<string>\r\n /** 返回当前文档到顶层文档的路径前缀,例如: ./../.. */\r\n getTopPathPrefix: (sy_doc?: S_Node) => Promise<string>\r\n } = {\r\n nodeStack: [] as S_Node[],\r\n refs: new Set(),\r\n async getTopPathPrefix() {\r\n const sy = this.nodeStack[0]\r\n let prefix = '.'\r\n if (sy.Type === 'NodeDocument' && sy.ID) {\r\n /** 基于当前文档路径将 href ../ 到顶层 */\r\n const path = await storeDep.getDocPathBySY(sy)\r\n if (path) {\r\n /** path data/box_id/doc_id/doc_id/doc_id.sy `data/box_id/` 这一节是多出来的,所以要减3 */\r\n const level = path.split('/').length - 3\r\n for (let i = 0; i < level; i++) {\r\n prefix += '/..'\r\n }\r\n }\r\n return prefix\r\n } else {\r\n console.log('未定义顶层元素非 NodeDocument 时的处理方式', sy)\r\n return ''\r\n }\r\n },\r\n async NodeDocument(sy) {\r\n /** 对于顶层文档,也就是当前html的主要内容,渲染题头图和标题等其他信息,相比被嵌入的 doc 块需要做一些特殊处理 */\r\n const isTopDoc = this.nodeStack.length === 1\r\n\r\n let html = `<div style=\"min-height: 150px;\" ${strAttr(sy)}>\\n${\r\n /** 题头图 */\r\n isTopDoc && sy.Properties?.['title-img']\r\n ? `<div class=\"protyle-background__img\" style=\"margin-bottom: 30px;position: relative;height: 16vh;${sy.Properties?.[\r\n 'title-img'\r\n ].replace(\r\n /assets/,\r\n // 修改为相对路径\r\n (await this.getTopPathPrefix()) + '/assets',\r\n )}\"/>${\r\n sy.Properties?.['icon']\r\n ? `<div style=\"position: absolute;bottom:-10px;left:15px;height: 80px;width: 80px;transition: var(--b3-transition);cursor: pointer;font-size: 68px;line-height: 80px;text-align: center;font-family: var(--b3-font-family-emoji);margin-right: 16px;\"> &#x${sy.Properties?.['icon']} </div>`\r\n : ''\r\n }</div>`\r\n : ''\r\n }\\n${\r\n /** h1 文档标题 */ isTopDoc\r\n ? `<h1 ${strAttr(sy)} data-type=\"NodeHeading\" class=\"h1\">${\r\n sy.Properties?.title\r\n }</h1>`\r\n : ''\r\n }\\n${await callChildRender(sy, this)}</div>`\r\n /** 添加 protyle-wysiwyg 容器和侧边栏,这里面的才会得到对应的样式效果 */\r\n if (isTopDoc) {\r\n html = `<div class=\"protyle-wysiwyg protyle-wysiwyg--attr\" id=\"preview\">\r\n <div id=\"oceanpress-left-sidebar\">\r\n ${config.sidebarCode.leftCode}\r\n ${\r\n config.sidebarCode.enableDocTree\r\n ? `<div id=\"oceanpress-doctree\"></div>\r\n <script src=\"${await this.getTopPathPrefix()}${renderDocTreeJsPath}\" async></script>`\r\n : ''\r\n }\r\n </div>\r\n ${html}\r\n <div id=\"oceanpress-right-sidebar\">${config.sidebarCode.rightCode}</div>\r\n</div>`\r\n }\r\n return html\r\n },\r\n async NodeHeading(sy) {\r\n const tagName = `h${sy.HeadingLevel}`\r\n let html = `<${tagName} ${strAttr(sy)}>${await callChildRender(\r\n sy,\r\n this,\r\n )}</${tagName}>`\r\n\r\n // 在被嵌入查询块的情况下需要查询渲染其后面的非标题块\r\n const parentNode =\r\n this.nodeStack[\r\n this.nodeStack.length -\r\n 2 /** 最后一个元素是 sy本身(NodeHeading)还得要往前一个,所以是2 */\r\n ]\r\n\r\n if (parentNode?.Type === 'NodeBlockQueryEmbedScript') {\r\n let afterFlag = false\r\n for (const node of sy.Parent.Children ?? []) {\r\n if (node === sy) {\r\n afterFlag = true\r\n } else if (node !== sy && node.Type === 'NodeHeading') {\r\n afterFlag = false\r\n } else if (afterFlag) {\r\n html += '\\n' + (await callRenderHTML(node, this))\r\n }\r\n }\r\n }\r\n return html\r\n },\r\n NodeText: _dataString,\r\n async NodeList(sy) {\r\n return html`<div ${strAttr(sy)}>${await callChildRender(sy, this)}</div>`\r\n },\r\n async NodeListItem(sy) {\r\n return html`<div ${await strAttr(sy)}>\r\n <div class=\"protyle-action\">\r\n ${\r\n sy.ListData?.Typ === 1\r\n ? /** 有序列表 */ atob(sy.ListData?.Marker ?? '')\r\n : sy.ListData?.Typ === 3\r\n ? /** 任务列表 */ `<svg><use xlink:href=\"#${\r\n sy.Children?.find(\r\n (el) => el.Type === 'NodeTaskListItemMarker',\r\n )?.TaskListItemChecked\r\n ? 'iconCheck'\r\n : 'iconUncheck'\r\n }\"></use></svg>`\r\n : /** 无序列表 */ `<svg><use xlink:href=\"#iconDot\"></use></svg>`\r\n }\r\n </div>\r\n ${await callChildRender(sy, this)}\r\n </div>`\r\n },\r\n NodeTaskListItemMarker: _emptyString,\r\n\r\n async NodeParagraph(sy) {\r\n /** .protyle-wysiwyg [data-node-id] [spellcheck] 定义了换行样式 */\r\n return `<div ${strAttr(\r\n sy,\r\n )}><div spellcheck=\"false\">${await callChildRender(sy, this)}</div></div>`\r\n },\r\n async NodeTextMark(sy) {\r\n const that = this\r\n let r: string = ''\r\n /** 从后向前渲染每一层mark ,TextMarkType有可能是 `a sub` |`sub a` | `a` |`code`等 */\r\n for (const type of (\r\n sy.TextMarkType?.split(' ') ?? []\r\n ).reverse() as S_Node['TextMarkType'][]) {\r\n if (r === '') {\r\n r = await TextMarkRender(sy, type, sy.TextMarkTextContent ?? '')\r\n } else {\r\n r = await TextMarkRender(sy, type, r)\r\n }\r\n }\r\n return r\r\n async function TextMarkRender(\r\n sy: S_Node,\r\n type: S_Node['TextMarkType'],\r\n content: string,\r\n ): Promise<string> {\r\n if (type === 'inline-math') {\r\n return `<span data-type=\"inline-math\" data-subtype=\"math\" data-content=\"${sy.TextMarkInlineMathContent}\" class=\"render-node\"></span>`\r\n } else if (type === 'inline-memo' /** 备注 */) {\r\n return `${content}<sup>(${sy.TextMarkInlineMemoContent})</sup>`\r\n } else if (type === 'block-ref' /** 引用块 */) {\r\n let href = ''\r\n if (sy.TextMarkBlockRefID) {\r\n const doc = await storeDep.getDocByChildID(sy.TextMarkBlockRefID)\r\n if (doc?.ID) {\r\n href = `${await that.getTopPathPrefix()}${await storeDep.getHPathByID_Node(\r\n doc /** 要先定位到文档,再通过下面的hash(#)定位到具体元素 */,\r\n )}.html#${sy.TextMarkBlockRefID}`\r\n that.refs.add(doc.ID)\r\n } else {\r\n warn(`未查找到${sy.ID}所指向的文档节点 ${sy.TextMarkBlockRefID}`)\r\n }\r\n } else {\r\n warn(`${sy.ID} 块引用没有设定 ref id`)\r\n }\r\n\r\n return `<span data-type=\"${sy.TextMarkType}\" \\\r\n data-subtype=\"${/** \"s\" */ sy.TextMarkBlockRefSubtype}\" \\\r\n data-id=\"${\r\n /** 被引用块的id */ sy.TextMarkBlockRefID\r\n }\"><a href=\"${href}\">${content}</a></span>`\r\n } else if (type === 'a') {\r\n let href = sy.TextMarkAHref\r\n if (href?.startsWith('assets/')) {\r\n /** TODO 应该有一个统一处理资源的方案 */\r\n href = `${await that.getTopPathPrefix()}/${href}`\r\n }\r\n return `<a href=\"${href}\">${content}</a>`\r\n } else if (\r\n `strong em u s mark sup sub kbd tag code strong code text`.includes(\r\n type ?? '',\r\n )\r\n ) {\r\n return `<span ${strAttr(sy, { data_type: type })}>${content}</span>`\r\n } else {\r\n return warnDiv(\r\n `没有找到对应的渲染器 ${sy.TextMarkType} ${that.nodeStack[0].Properties?.title}`,\r\n )\r\n }\r\n }\r\n },\r\n async NodeImage(sy) {\r\n let link = ''\r\n const LinkDest = sy.Children?.filter((c) => c.Type === 'NodeLinkDest')\r\n if (LinkDest?.length === 1) {\r\n link = await callRenderHTML(LinkDest[0], this)\r\n } else if (LinkDest?.length && LinkDest.length > 1) {\r\n warn('NodeImage 存在多个 LinkDest', sy)\r\n }\r\n\r\n let title = ''\r\n const LinkTitle = sy.Children?.filter((c) => c.Type === 'NodeLinkTitle')\r\n if (LinkTitle?.length === 1) {\r\n title = await callRenderHTML(LinkTitle[0], this)\r\n } else if (LinkTitle?.length && LinkTitle.length > 1) {\r\n warn('NodeImage 存在多个 LinkTitle', sy)\r\n }\r\n return `<span ${await strAttr(sy)} style=\"${\r\n sy.Properties?.['parent-style'] ?? ''\r\n }\">\r\n <img\r\n src=\"${link}\"\r\n data-src=\"${link}\"\r\n title=\"${title}\"\r\n style=\"${sy.Properties?.style ?? ''}\"\r\n loading=\"lazy\"\r\n />\r\n <span class=\"protyle-action__title\">${title}</span></span>`\r\n },\r\n async NodeLinkDest(sy) {\r\n /** 绝对路径 */\r\n if (/^(?:[a-z]+:)?\\/\\/|^(?:\\/)/.test(sy.Data ?? '')) {\r\n return sy.Data ?? ''\r\n }\r\n /** 为相对路径添加正确的前缀 */\r\n return `${await this.getTopPathPrefix()}/${sy.Data}`\r\n },\r\n NodeLinkTitle: _dataString,\r\n NodeKramdownSpanIAL: _emptyString,\r\n async NodeSuperBlock(sy) {\r\n return `<div ${strAttr(sy)} data-sb-layout=\"${childDateByType(\r\n sy,\r\n 'NodeSuperBlockLayoutMarker',\r\n )}\">${await callChildRender(sy, this)}</div>`\r\n },\r\n NodeSuperBlockOpenMarker: _emptyString,\r\n NodeSuperBlockCloseMarker: _emptyString,\r\n NodeSuperBlockLayoutMarker: _emptyString,\r\n async NodeBlockQueryEmbed(sy) {\r\n return `<div ${strAttr(sy)} data-type=\"NodeBlockquote\" class=\"bq\">\\\r\n ${await callChildRender(sy, this)}\\\r\n </div>`\r\n },\r\n NodeOpenBrace: _emptyString,\r\n NodeCloseBrace: _emptyString,\r\n async NodeBlockQueryEmbedScript(sy) {\r\n const sql = sy.Data\r\n if (!sql) {\r\n console.log('no sql', sy)\r\n return html`<pre>${sql}</pre>`\r\n }\r\n let htmlStr = ''\r\n const blocks: DB_block[] = await API.query_sql({\r\n stmt: /** sql 被思源转义了,类似 :SELECT * FROM blocks WHERE id = &#39;20201227174241-nxny1tq&#39;\r\n 所以这里将它转义回来\r\n TODO 当用户确实使用了包含转义的字符串时,这个实现是错误的 */ unescaping(\r\n sql,\r\n ).replace(\r\n /** 我不理解lute为什么这样实现 https://github.com/88250/lute/blob/HEAD/editor/const.go#L38\r\n * https://ld246.com/article/1696750832289\r\n */\r\n /_esc_newline_/g,\r\n '\\n',\r\n ),\r\n }).catch((err) => {\r\n throw new Error(\r\n `sql error: ${err.message}\\nrawSql:${sql}\\nunescapingSql:${unescaping(\r\n sql,\r\n )}`,\r\n )\r\n })\r\n for (const block of blocks) {\r\n const node = await storeDep.getNodeByID(block.id)\r\n if (node === undefined) {\r\n return warnDiv('未找到此块,可能为跨笔记引用', block.id, sql)\r\n }\r\n htmlStr += await callRenderHTML(node, this)\r\n }\r\n\r\n return htmlStr\r\n },\r\n async NodeBlockquote(sy) {\r\n return html`<div ${strAttr(sy)}>${await callChildRender(sy, this)}</div>`\r\n },\r\n NodeBlockquoteMarker: _emptyString,\r\n NodeCodeBlock: async function (sy) {\r\n const [yes, _] = isRenderCode(sy)\r\n if (yes) {\r\n return `<div ${strAttr(sy)} data-content=\"${escaping(\r\n sy.Children?.find((el) => el.Type === 'NodeCodeBlockCode')?.Data ??\r\n '',\r\n )}\">\r\n <div spin=\"1\"></div>\r\n <div class=\"protyle-attr\" contenteditable=\"false\"></div>\r\n </div>`\r\n }\r\n return `<div ${strAttr(sy)}>\r\n <div class=\"protyle-action\">\r\n <span class=\"protyle-action--first protyle-action__language\">${await callRenderHTML(\r\n sy.Children?.find(\r\n (el) => el.Type === 'NodeCodeBlockFenceInfoMarker',\r\n ),\r\n this,\r\n )}</span>\r\n <span class=\"fn__flex-1\"></span><span class=\"protyle-icon protyle-icon--only protyle-action__copy\"><svg><use xlink:href=\"#iconCopy\"></use></svg></span>\r\n </div>\r\n ${await callRenderHTML(\r\n sy.Children?.find((el) => el.Type === 'NodeCodeBlockCode'),\r\n this,\r\n )}\r\n </div>`\r\n },\r\n NodeCodeBlockFenceInfoMarker: async (sy) => atob(sy.CodeBlockInfo ?? ''),\r\n NodeCodeBlockCode: async (sy) =>\r\n `<div class=\"hljs\" spellcheck=\"false\">${sy.Data}</div>`,\r\n NodeCodeBlockFenceOpenMarker: _emptyString,\r\n NodeCodeBlockFenceCloseMarker: _emptyString,\r\n async NodeTable(sy) {\r\n return `<div ${strAttr(sy)}>\r\n <div>\r\n <table spellcheck=\"false\">\r\n <colgroup>\r\n ${sy.TableAligns?.map(() => '<col />').join('')}\r\n </colgroup>\r\n ${await callRenderHTML(\r\n sy.Children?.find((el) => el.Type === 'NodeTableHead'),\r\n this,\r\n )}\r\n <tbody>\r\n ${(\r\n await Promise.all(\r\n sy.Children?.filter((el) => el.Type === 'NodeTableRow').map(\r\n (el) => callRenderHTML(el, this),\r\n ) ?? [],\r\n )\r\n ).join('\\n')}\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>`\r\n },\r\n async NodeTableHead(sy) {\r\n return `<${sy.Data}>${await callChildRender(sy, this)}</${sy.Data}>`\r\n },\r\n async NodeTableRow(sy) {\r\n return `<tr>${await callChildRender(sy, this)}</tr>`\r\n },\r\n async NodeTableCell(sy) {\r\n return `<td>${await callChildRender(sy, this)}</td>`\r\n },\r\n NodeHTMLBlock: async (sy) => `<div ${strAttr(sy)}>${sy.Data}</div>`,\r\n NodeThematicBreak: async (sy) => `<div ${strAttr(sy)}><div></div></div>`,\r\n NodeMathBlock: async (sy) => `<div ${strAttr(\r\n sy,\r\n )} data-content=\"${childDateByType(sy, 'NodeMathBlockContent')}\">\r\n <div spin=\"1\"></div>\r\n </div>`,\r\n NodeMathBlockOpenMarker: _emptyString,\r\n NodeMathBlockCloseMarker: _emptyString,\r\n async NodeIFrame(sy) {\r\n return ` <div ${strAttr(sy)}>\r\n <div class=\"iframe-content\">\r\n ${\r\n /** 资源总是被复制到顶层目录,所以直接跳到顶层即可 */\r\n /** TODO 应该有一个统一处理资源的方案 */\r\n sy.Data?.replace(\r\n /src=\"assets\\//,\r\n `src=\"${await this.getTopPathPrefix()}/assets\\/`,\r\n )\r\n }\r\n </div>\r\n </div>`\r\n },\r\n async NodeVideo(sy) {\r\n return await this.NodeIFrame!(sy)\r\n },\r\n async NodeAudio(sy) {\r\n return await this.NodeIFrame!(sy)\r\n },\r\n /** 虚拟链接 */\r\n NodeHeadingC8hMarker: _emptyString,\r\n async NodeSoftBreak(_sy) {\r\n //TODO 此处实现应该有问题\r\n /** https://zh.wikipedia.org/wiki/零宽空格 */\r\n return '\\u200B'\r\n },\r\n async NodeBr(sy) {\r\n return `<${sy.Data}>`\r\n },\r\n async NodeWidget(sy) {\r\n return `<div ${strAttr(\r\n sy,\r\n )}><img src=\"${await this.getTopPathPrefix()}/assets/widget/${\r\n sy.ID\r\n }.jpg\"/></div>`\r\n },\r\n async NodeBackslash(sy) {\r\n if (sy.Data === undefined || sy.Data === 'span') {\r\n return `${await callChildRender(sy, this)}`\r\n } else {\r\n return warnDiv(\r\n `未定义的 NodeBackslash 处理 ${sy.Data}`,\r\n this.nodeStack[0].Properties?.title,\r\n )\r\n }\r\n },\r\n NodeBackslashContent: _dataString,\r\n }\r\n\r\n return render\r\n})\r\n\r\n/** 获取sy节点的child中第一个type类型节点的data */\r\nfunction childDateByType(sy: S_Node, type: S_Node['Type']) {\r\n return sy.Children?.find((el) => el.Type === type)?.Data\r\n}\r\n\r\nfunction warn(...arg: any[]) {\r\n console.warn('\\n', ...arg)\r\n}\r\n","/** html 实体转义 https://www.sitemaps.org/protocol.html#escaping */\r\nexport function escaping(s: string) {\r\n return s\r\n .replace(/&/g, \"&amp;\")\r\n .replace(/</g, \"&lt;\")\r\n .replace(/>/g, \"&gt;\")\r\n .replace(/\"/g, \"&quot;\")\r\n .replace(/'/g, \"&apos\");\r\n}\r\nexport function unescaping(s: string) {\r\n return s\r\n .replace(/&amp;/g, \"&\")\r\n .replace(/&lt;/g, \"<\")\r\n .replace(/&gt;/g, \">\")\r\n .replace(/&quot;/g, '\"')\r\n .replace(/&apos;/g, \"'\")\r\n .replace(/&#(\\d+);/g, (_sub,code) => {\r\n return String.fromCharCode(Number(code));\r\n });\r\n}\r\n","import { Effect } from 'effect'\nimport { EffectConfigDep } from './EffectDep.ts'\nimport type { DB_block } from './siyuan_type.ts'\nimport { allDocBlock_by_bookId } from './cache.ts'\nimport { API } from './siyuan_api.ts'\nimport { tempConfig } from './config.ts'\n\nexport const renderDocTreeJsPath = `/__oceanpress/docTree.js`\n/** 生成文档树 JS 文件 */\nexport function renderDocTree() {\n return Effect.gen(function* () {\n const config = yield* EffectConfigDep\n const Doc_blocks: DB_block[] = yield* Effect.tryPromise(() =>\n allDocBlock_by_bookId(config.notebook.id),\n )\n /** 获取文档树排序信息 */\n const sortJSON: { [id: string]: number | undefined } =\n yield* Effect.tryPromise(() =>\n API.file_getFile({\n path: `/data/${config.notebook.id}/.siyuan/sort.json`,\n }).then((r) => {\n // 1. 将 ArrayBuffer 转为字符串\n const decoder = new TextDecoder('utf-8')\n const jsonString = decoder.decode(r as ArrayBuffer)\n // 2. 解析字符串为 JSON 对象\n return JSON.parse(jsonString)\n }),\n )\n const docs = Doc_blocks.map((el) => ({\n id: el.id,\n /** 类似 '/record/cssFlex' */\n hpath: el.hpath,\n title: el.content,\n sort: sortJSON[el.id],\n }))\n const tree = buildTree(docs)\n \n // 生成 JS 代码\n const jsCode = generateJSTree(tree)\n return `\n// OceanPress DocTree - 动态加载的文档树\n(function() {\n 'use strict';\n \n // 文档树数据\n const docTreeData = ${jsCode};\n \n // 渲染函数\n function renderDocTree(containerId, options = {}) {\n const container = document.getElementById(containerId);\n if (!container) {\n console.error('Container not found:', containerId);\n return;\n }\n \n const currentPath = options.currentPath || window.location.pathname.replace(/\\\\.html$/, '');\n \n // 生成 HTML\n const html = generateHTMLTree(docTreeData, currentPath);\n container.innerHTML = html;\n \n // 加载样式\n loadStyles();\n \n // 初始化交互\n initInteractions(container, currentPath);\n }\n \n // 检查是否为单一路径(只有单个子节点的文件夹)\n function isSinglePath(node) {\n if (!node.children || node.children.length !== 1) {\n return false;\n }\n \n let current = node;\n while (current.children && current.children.length === 1) {\n current = current.children[0];\n }\n \n // 如果最终节点没有子节点,说明是单一路径\n return !current.children || current.children.length === 0;\n }\n\n // 获取单一路径的所有节点\n function getSinglePathNodes(node) {\n const pathNodes = [node];\n let current = node;\n \n while (current.children && current.children.length === 1) {\n current = current.children[0];\n pathNodes.push(current);\n }\n \n return pathNodes;\n }\n\n // 生成面包屑路径\n function generateBreadcrumb(pathNodes, currentPath) {\n const lastNode = pathNodes[pathNodes.length - 1];\n const isCurrent = lastNode.hpath === currentPath;\n \n let breadcrumbHtml = '<div class=\"breadcrumb-path\">';\n \n pathNodes.forEach((node, index) => {\n if (index > 0) {\n breadcrumbHtml += '<span class=\"breadcrumb-separator\">/</span>';\n }\n \n const isLast = index === pathNodes.length - 1;\n const nodeCurrent = node.hpath === currentPath;\n \n breadcrumbHtml += \\`\n <a href=\"\\${node.hpath}.html\" class=\"breadcrumb-part \\${(isLast && isCurrent) ? 'current' : ''}\" target=\"_top\">\\${node.title}</a>\n \\`;\n });\n \n breadcrumbHtml += '</div>';\n return breadcrumbHtml;\n }\n\n // 生成 HTML 树\n function generateHTMLTree(nodes, currentPath, level = 0) {\n let html = '';\n for (const node of nodes) {\n const isCurrent = node.hpath === currentPath;\n const isActive = isCurrent || (currentPath && node.hpath && currentPath.startsWith(node.hpath));\n \n // 检查是否为单一路径,如果是则显示为面包屑\n if (isSinglePath(node)) {\n const pathNodes = getSinglePathNodes(node);\n html += generateBreadcrumb(pathNodes, currentPath);\n continue;\n }\n \n if (node.children && node.children.length > 0) {\n // 有子节点时使用 details/summary\n const isExpanded = isActive ? 'open' : '';\n html += \\`\n <details class=\"folder\" \\${isExpanded}>\n <summary class=\"folder-summary\">\n <a href=\"\\${node.hpath}.html\" class=\"folder-link \\${isCurrent ? 'current' : ''}\" target=\"_top\">\\${node.title}</a>\n </summary>\n <div class=\"folder-children\" style=\"padding:0 0 0 10px;\">\n \\${generateHTMLTree(node.children, currentPath, level + 1)}\n </div>\n </details>\n \\`;\n } else {\n // 没有子节点的普通项目\n html += \\`\n <div class=\"file \\${isCurrent ? 'current' : ''}\">\n <a href=\"\\${node.hpath}.html\" class=\"file-link\" target=\"_top\">\\${node.title}</a>\n </div>\n \\`;\n }\n }\n return html;\n }\n \n // 加载样式\n function loadStyles() {\n if (document.getElementById('oceanpress-doctree-styles')) return;\n \n const link = document.createElement('link');\n link.id = 'oceanpress-doctree-styles';\n link.rel = 'stylesheet';\n link.type = 'text/css';\n link.href = '${tempConfig.cdn.siyuanPrefix}appearance/docTree.css';\n document.head.appendChild(link);\n }\n \n // 初始化交互\n function initInteractions(container, currentPath) {\n // 为当前页面项添加高亮样式\n const currentItems = container.querySelectorAll('.current');\n currentItems.forEach(item => {\n // 如果是面包屑路径中的当前项,需要特殊处理\n if (item.classList.contains('breadcrumb-part')) {\n item.style.fontWeight = 'bold';\n item.style.color = 'var(--oceanpress-sidebar-current-border)';\n } else {\n // 使用 CSS 变量而不是硬编码颜色\n item.style.backgroundColor = 'var(--oceanpress-sidebar-current-bg)';\n item.style.borderLeft = '3px solid var(--oceanpress-sidebar-current-border)';\n item.style.paddingLeft = '7px';\n }\n });\n \n // 确保当前页面的所有父文件夹都展开\n const currentElements = container.querySelectorAll('.current');\n currentElements.forEach(currentElement => {\n // 向上遍历所有父级 details 元素并展开\n let parent = currentElement.parentElement;\n while (parent) {\n if (parent.tagName === 'DETAILS') {\n parent.setAttribute('open', 'open');\n }\n parent = parent.parentElement;\n }\n });\n \n // 自动滚动到当前页面\n const firstCurrent = container.querySelector('.current');\n if (firstCurrent) {\n setTimeout(() => {\n firstCurrent.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 100);\n }\n \n // 监听主题变化事件,更新高亮样式\n window.addEventListener('oceanpress-theme-changed', function(e) {\n currentItems.forEach(item => {\n if (item.classList.contains('breadcrumb-part')) {\n item.style.fontWeight = 'bold';\n item.style.color = 'var(--oceanpress-sidebar-current-border)';\n } else {\n item.style.backgroundColor = 'var(--oceanpress-sidebar-current-bg)';\n item.style.borderLeft = '3px solid var(--oceanpress-sidebar-current-border)';\n }\n });\n });\n }\n \n // 暴露到全局\n window.OceanPressDocTree = {\n render: renderDocTree,\n data: docTreeData\n };\n \n // 自动渲染(如果容器存在)\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n if (document.getElementById('oceanpress-doctree')) {\n renderDocTree('oceanpress-doctree');\n }\n });\n } else {\n if (document.getElementById('oceanpress-doctree')) {\n renderDocTree('oceanpress-doctree');\n }\n }\n})();\n `\n })\n}\n\n/** 生成 JavaScript 格式的文档树数据 */\nfunction generateJSTree(nodes: DocNode[]): string {\n return JSON.stringify(nodes, null, 2);\n}\n\n\ninterface DocNode {\n id: string\n hpath: string\n title: string\n sort: number | undefined\n children?: DocNode[]\n}\n\nfunction buildTree(docs: DocNode[]): DocNode[] {\n // 1. 创建根节点和路径映射\n const root: DocNode[] = []\n const pathMap: Record<string, DocNode> = {}\n\n // 2. 先按 hpath 排序,确保父节点先处理\n docs.sort((a, b) => a.hpath.localeCompare(b.hpath))\n\n // 3. 构建树结构\n for (const doc of docs) {\n const pathParts = doc.hpath.split('/').filter((part) => part !== '')\n let currentPath = ''\n let parentNode: DocNode | undefined = undefined\n\n // 逐级查找或创建父节点\n for (let i = 0; i < pathParts.length - 1; i++) {\n currentPath += '/' + pathParts[i]\n if (!pathMap[currentPath]) {\n // 创建虚拟父节点\n pathMap[currentPath] = {\n id: 'virtual_' + currentPath,\n hpath: currentPath,\n title: pathParts[i],\n sort: undefined,\n children: [],\n }\n // 添加到父节点的children中\n if (parentNode) {\n parentNode.children = parentNode.children || []\n parentNode.children.push(pathMap[currentPath])\n } else {\n root.push(pathMap[currentPath])\n }\n }\n parentNode = pathMap[currentPath]\n }\n\n // 添加当前节点\n if (parentNode) {\n parentNode.children = parentNode.children || []\n parentNode.children.push(doc)\n } else {\n root.push(doc)\n }\n pathMap[doc.hpath] = doc\n }\n\n // 4. 递归排序\n function sortNodes(nodes: DocNode[]): DocNode[] {\n return nodes\n .map((node) => {\n if (node.children) {\n node.children = sortNodes(node.children)\n }\n return node\n })\n .sort((a, b) => {\n // 有sort值的优先按sort排序,没有sort值的按title排序\n if (a.sort !== undefined && b.sort !== undefined) {\n return a.sort - b.sort\n } else if (a.sort !== undefined) {\n return -1\n } else if (b.sort !== undefined) {\n return 1\n } else {\n return (a.title || '').localeCompare(b.title || '')\n }\n })\n }\n\n return sortNodes(root)\n}\n","/** 基于洋葱 HOOk 机制的插件管理器\r\n * 我感觉这个手搓的插件机制还可以,类型完备,可拓展性强,\r\n */\r\nexport class PluginCenter<T extends Record<string, (...args: any[]) => any>> {\r\n plugins: PluginCenter<T>['pluginType'][] = []\r\n registerPlugin(plugin: PluginCenter<T>['pluginType']) {\r\n this.plugins.push(plugin)\r\n }\r\n removePlugin(plugin: PluginCenter<T>['pluginType']) {\r\n this.plugins = this.plugins.filter((p) => p !== plugin)\r\n }\r\n /** 洋葱hook调用机制的实现 */\r\n callFn<R extends keyof PluginCenter<T>['pluginType']>(\r\n name: R,\r\n fn: GetMiddlewareFunc<Required<PluginCenter<T>['pluginType']>[R]>,\r\n ) {\r\n return ((...arg: any) => {\r\n // 此处可优化,不必每次都重新生成 middlewareRunner\r\n const m = new middlewareRunner(fn)\r\n // 注入 plugins 中的对应中间件\r\n for (const plugin of this.plugins) {\r\n const middleware = plugin[name]\r\n if (middleware) {\r\n m.use(middleware)\r\n }\r\n }\r\n return m.runMiddlewareHandel(...arg)\r\n }) as GetMiddlewareFunc<Required<PluginCenter<T>['pluginType']>[R]>\r\n }\r\n /** 辅助类型,不可调用! */\r\n pluginType: {\r\n [key in keyof PluginCenter<T>['_funMap']]?: FuncMiddlewares<\r\n PluginCenter<T>['_funMap'][key]\r\n >\r\n } = 0 as any\r\n /** 对需要调用的函数进行代理,完成插件hook介入。 */\r\n fun: PluginCenter<T>['_funMap']\r\n constructor(\r\n /** 原始函数映射表,这里的函数全部可以被插件处理 */\r\n public _funMap: T,\r\n ) {\r\n const that = this\r\n // 可以改成生成对象 {} 的方式,比 proxy 开销要小\r\n this.fun = new Proxy({} as T, {\r\n get(_target, propertyKey, receiver) {\r\n const method = Reflect.get(that._funMap, propertyKey, receiver)\r\n if (typeof method === 'function') {\r\n return (...args: any) => {\r\n return that.callFn(\r\n propertyKey as keyof T,\r\n //@ts-ignore 懒得推类型了。属于内部实现,就直接忽略掉吧\r\n method,\r\n )(...args)\r\n }\r\n }\r\n return method\r\n },\r\n })\r\n }\r\n}\r\n\r\ntype GetMiddlewareFunc<T> = T extends FuncMiddlewares<infer R> ? R : never\r\n\r\n// 小中间件实现,接收一个函数 handel 作为最终执行的函数,当执行 runMiddlewareHandel 时等价于执行 Handel\r\n// 通过 use 注册中间件,类似于洋葱路由,先注册的先执行\r\ntype FuncMiddlewares<Handel extends (...args: any[]) => any> = (\r\n ctx: Parameters<Handel>,\r\n next: Handel,\r\n) => ReturnType<Handel>\r\nclass middlewareRunner<Handel extends (...args: any[]) => any> {\r\n middlewares: FuncMiddlewares<Handel>[] = []\r\n constructor(public handel: Handel) {}\r\n use(middleware: FuncMiddlewares<Handel>) {\r\n this.middlewares.push(middleware)\r\n }\r\n runMiddlewareHandel(...ctx: Parameters<typeof this.handel>) {\r\n let index = 0\r\n const next = ((...ctx2: Parameters<Handel>) => {\r\n const middleware = this.middlewares[index]\r\n index++\r\n if (middleware === undefined) {\r\n return this.handel.call(this, ...ctx2)\r\n }\r\n return middleware(ctx2, next)\r\n }) as Handel\r\n return next.call(this, ...ctx)\r\n }\r\n}\r\n","import { MeilisearchPlugin } from '~/plugins/meilisearch_plugin/meilisearch_upload.ts'\r\nimport { deployOceanPressServer_plugin } from '~/plugins/publish/OceanPressServer.ts'\r\nimport { s3Upload_plugin } from '~/plugins/publish/s3.ts'\r\nimport { FileTree, build } from './build.ts'\r\nimport { Config } from './config.ts'\r\nimport type { effectLog } from './EffectDep.ts'\r\nimport { PluginCenter } from './plugin.ts'\r\nimport { renderHTML } from './render.ts'\r\n\r\nexport type OceanPressPlugin = PluginCenter<OceanPress['funMap']>['pluginType']\r\n\r\n/** OceanPress 核心类,用于管理插件和配置,执行构建过程。 */\r\nexport class OceanPress {\r\n build() {\r\n const build_res = this.pluginCenter.fun.build(this.config, {\r\n renderHtmlFn: this.pluginCenter.fun.build_renderHTML,\r\n onFileTree: this.pluginCenter.fun.build_onFileTree,\r\n })\r\n return build_res\r\n }\r\n funMap = {\r\n /** 开始整体编译 */\r\n build,\r\n /** 用于渲染文档的函数 */\r\n build_renderHTML: renderHTML,\r\n /** 编译完成后文件树的处理回调函数 */\r\n build_onFileTree: (_tree: FileTree, _effectApi: effectLog) => {},\r\n }\r\n pluginCenter: PluginCenter<OceanPress['funMap']> = new PluginCenter(\r\n this.funMap,\r\n )\r\n constructor(public config: Config) {\r\n // TODO 内置插件,以后应该改成由用户配置\r\n if (config.meilisearch.enable) {\r\n this.pluginCenter.registerPlugin(\r\n new MeilisearchPlugin(config.meilisearch),\r\n )\r\n }\r\n if (config.s3.enable) {\r\n this.pluginCenter.registerPlugin(s3Upload_plugin)\r\n }\r\n if (config.oceanPressServer.enable) {\r\n this.pluginCenter.registerPlugin(\r\n deployOceanPressServer_plugin(this.config),\r\n )\r\n }\r\n }\r\n}\r\n","import { get_block_by_id, get_doc_by_child_id } from './cache.ts'\r\nimport { DB_block_path, type S_Node } from './siyuan_type.ts'\r\n\r\n/** 通过 fetch 实现的平台无关 api 依赖 */\r\nexport const renderApiDep = {\r\n getDocByChildID: async (id: string) => {\r\n return await get_doc_by_child_id(id)\r\n },\r\n\r\n getDocPathBySY: async (sy?: S_Node) => {\r\n if (sy?.ID) {\r\n const block = await get_block_by_id(sy.ID)\r\n if (block) {\r\n return DB_block_path(block)\r\n }\r\n }\r\n },\r\n\r\n /** TODO 应该可以从cache中获取,而不需要查询 */\r\n getHPathByID_Node: async (id_node: string | S_Node): Promise<string> => {\r\n const id = typeof id_node === 'string' ? id_node : id_node.ID\r\n if (id === undefined) throw new Error('id is undefined')\r\n const docNode = await get_doc_by_child_id(id)\r\n if (docNode === undefined) throw new Error('docNode is undefined')\r\n const docBlock = await get_block_by_id(id)\r\n if (docBlock === undefined) throw new Error('docBlock is undefined')\r\n return docBlock.hpath\r\n },\r\n\r\n getNodeByID: async (id?: string): Promise<S_Node | undefined> => {\r\n if (id === undefined) return\r\n const doc = await renderApiDep.getDocByChildID(id)\r\n if (doc === undefined) return\r\n return getNode(doc)\r\n function getNode(node: S_Node): S_Node | undefined {\r\n if (node.ID === id) return node\r\n if (node.Children === undefined) return\r\n for (const child of node.Children) {\r\n const n = getNode(child)\r\n if (n) return n\r\n }\r\n }\r\n },\r\n log(msg: string) {\r\n console.log(msg)\r\n },\r\n percentage: (n: number) => {\r\n console.log(n)\r\n },\r\n}\r\n","import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'node:fs'\r\n\r\nexport function setItem(key: string, value: string) {\r\n if (!existsSync('./store/')) {\r\n // 目录不存在,递归创建目录\r\n mkdirSync('./store/', { recursive: true })\r\n }\r\n return writeFileSync(`./store/${key}`, value, {\r\n encoding: 'utf-8',\r\n })\r\n}\r\n\r\nexport function getItem(key: string): string | undefined {\r\n try {\r\n return readFileSync(`./store/${key}`, 'utf-8')\r\n } catch (_) {\r\n return undefined\r\n }\r\n}\r\nexport const nodeApiDep = {\r\n setItem,\r\n getItem,\r\n}\r\n","import '~/core/render.api.dep.ts'\nimport '~/util/store.node.dep.ts'\nimport { Command } from 'commander'\n\nexport const program = new Command()\n\nprogram\n .name('OceanPress')\n .description('这是一款从思源笔记本生成一个静态站点的工具')\n","import { mkdir, readFile, writeFile } from 'fs/promises'\nimport { resolve } from 'path'\nimport { join } from 'path/posix'\nimport { currentConfig, loadConfigFile } from '~/core/config.ts'\nimport { OceanPress } from '~/core/ocean_press.ts'\nimport { program } from './common.ts'\nimport { Context, Effect } from 'effect'\nimport {\n EffectRender,\n EffectLocalStorageDep,\n EffectLogDep,\n EffectConfigDep,\n} from '~/core/EffectDep.ts'\nimport { renderApiDep } from '~/core/render.api.dep.ts'\nimport { nodeApiDep } from '~/util/store.node.dep.ts'\n\nprogram\n .command('build')\n .description('输出静态站点源码')\n .option('-c, --config <string>', '指定配置文件的位置')\n .option('-o, --output <string>', '指定输出目录位置')\n .action(async (opt: { config: string; output: string }) => {\n if (!opt.config || !opt.output) {\n console.log(`请设置配置文件位置和输出目录位置`)\n throw new Error('请设置配置文件位置和输出目录位置')\n }\n const config = await readFile(opt.config, 'utf-8')\n const filePath = resolve(opt.output)\n\n /** 先加载配置 */\n await Effect.runPromise(\n Effect.provideService(\n loadConfigFile(JSON.parse(config)),\n EffectLocalStorageDep,\n nodeApiDep,\n ),\n )\n const context = Context.empty().pipe(\n Context.add(EffectRender, renderApiDep),\n Context.add(EffectLocalStorageDep, nodeApiDep),\n Context.add(EffectConfigDep, currentConfig.value),\n Context.add(EffectLogDep, {\n log: (msg) => {\n if (msg.startsWith('渲染:')) {\n process.stdout.write(`\\r\\x1b[K${msg}`)\n } else {\n process.stdout.write(`\\n${msg}`)\n }\n },\n percentage: (n) => {\n process.stdout.write(`\\r\\x1b[K进度:${n}%`)\n },\n }),\n )\n\n const p = Effect.provide(\n Effect.gen(function* () {\n const ocean_press = new OceanPress(currentConfig.value)\n\n // node 端写磁盘插件\n ocean_press.pluginCenter.registerPlugin({\n async build_onFileTree([tree]) {\n for (const [path, data] of Object.entries(tree)) {\n const fullPath = join(filePath, './', path)\n const pathArray = fullPath.split('/').slice(0, -1)\n const dirPath = pathArray.join('/')\n mkdir(dirPath, { recursive: true })\n try {\n if (typeof data === 'string') {\n await writeFile(fullPath, data, 'utf-8')\n } else {\n await writeFile(fullPath, new DataView(data))\n }\n } catch (error) {\n console.log(`${fullPath} 无法写入`)\n }\n }\n },\n })\n\n console.log('[config.__current__]', JSON.parse(config).__current__)\n console.log('[currentConfig.value.name]', currentConfig.value.name)\n return yield* ocean_press.build()\n }),\n context,\n )\n await Effect.runPromise(p)\n })\n","import { readFile } from 'fs/promises'\nimport { setCache } from '~/core/cache.ts'\nimport { loadConfigFile, tempConfig } from '~/core/config.ts'\nimport { server } from '~/server.ts'\nimport { program } from './common.ts'\nimport { Context, Effect } from 'effect'\nimport {\n EffectRender,\n EffectLocalStorageDep,\n EffectLogDep,\n} from '~/core/EffectDep.ts'\nimport { renderApiDep } from '~/core/render.api.dep.ts'\nimport { nodeApiDep } from '~/util/store.node.dep.ts'\nprogram\n .command('server')\n .description('启动动态代理')\n .option('-c, --config <string>', '指定配置文件的位置')\n .option('-h, --host <string>', 'web服务绑定到的地址', '127.0.0.1')\n .option('-p, --port <number>', 'web服务绑定到的端口', '80')\n .option(\n '--cache <boolean>',\n '配置为 true 时开启缓存,默认为 false 不开启缓存',\n 'false',\n )\n .action(\n async (opt: {\n config: string\n host: string\n port: string\n cache: 'false'\n }) => {\n if (!opt.config) {\n console.log(`请设置配置文件位置`)\n }\n const config = await readFile(opt.config, 'utf-8')\n setCache(opt.cache !== 'false')\n\n const context = Context.empty().pipe(\n Context.add(EffectRender, renderApiDep),\n Context.add(EffectLocalStorageDep, nodeApiDep),\n Context.add(EffectLogDep, {\n log: (msg) => {\n if (msg.startsWith('渲染:')) {\n process.stdout.write(`\\r\\x1b[K${msg}`)\n } else {\n process.stdout.write(`\\n${msg}`)\n }\n },\n percentage: (n) => {\n process.stdout.write(`\\r\\x1b[K进度:${n}%`)\n },\n }),\n )\n\n const p = Effect.provide(\n Effect.gen(function* () {\n yield* loadConfigFile(JSON.parse(config))\n /** 使用本地的文件,方便调试 */\n tempConfig.cdn.siyuanPrefix = '/notebook/'\n return yield* server({\n hostname: opt.host,\n port: Number(opt.port),\n })\n }),\n context,\n )\n\n await Effect.runPromise(p)\n },\n )\n","import { serve } from '@hono/node-server'\r\nimport { serveStatic } from '@hono/node-server/serve-static'\r\nimport { Effect } from 'effect'\r\nimport { Hono } from 'hono'\r\nimport { EffectRender } from './core/EffectDep.ts'\r\nimport { createHonoApp } from './core/hono_server.ts'\r\n\r\nexport function server(config = { port: 80, hostname: '0.0.0.0' }) {\r\n return Effect.gen(function* () {\r\n const app = new Hono()\r\n // 方便开发调试样式\r\n app.use(\r\n '/notebook/*',\r\n serveStatic({\r\n root: './public/',\r\n onNotFound(path, c) {\r\n console.log('[onNotFound notebook path]', path)\r\n // ./public/notebook/appearance/fonts/JetBrainsMono-2.304/JetBrainsMono-Regular.woff2\r\n // ./public/notebook/appearance/fonts\\JetBrainsMono-2.304/JetBrainsMono-Regular.woff2\r\n },\r\n }),\r\n )\r\n const effectDep = yield* EffectRender\r\n createHonoApp(app, effectDep)\r\n return new Promise((resolve, _reject) => {\r\n serve(\r\n {\r\n fetch: app.fetch,\r\n port: config.port,\r\n hostname: config.hostname,\r\n },\r\n (info) => {\r\n resolve({ info, app })\r\n console.log(`Listening on http://${info.address}:${info.port}`)\r\n },\r\n )\r\n })\r\n })\r\n}\r\n","import { Context as HonoContext, Hono } from 'hono'\r\nimport { currentConfig, tempConfig } from './config.ts'\r\nimport { get_doc_by_hpath } from './cache.ts'\r\nimport { htmlTemplate } from './htmlTemplate.ts'\r\nimport { renderHTML } from './render.ts'\r\nimport { stream } from 'hono/streaming'\r\nimport type { StatusCode } from 'hono/utils/http-status'\r\nimport { Effect, Context } from 'effect'\r\nimport {\r\n EffectConfigDep,\r\n EffectRender,\r\n type EffectRenderApi,\r\n} from './EffectDep.ts'\r\nimport { renderDocTree, renderDocTreeJsPath } from './renderDocTree.ts'\r\n\r\nexport function createHonoApp(\r\n app: Hono = new Hono(),\r\n renderapi: EffectRenderApi,\r\n) {\r\n const context = Context.empty().pipe(\r\n Context.add(EffectRender, renderapi),\r\n Context.add(EffectConfigDep, currentConfig.value),\r\n )\r\n /** 处理文档树的接口 */\r\n app.get(renderDocTreeJsPath, async (c) => {\r\n const p = Effect.provide(renderDocTree(), context)\r\n const r = await Effect.runPromise(p)\r\n return c.text(r, 200, {\r\n 'Content-Type': 'application/javascript',\r\n 'Cache-Control': 'public, max-age=3600'\r\n })\r\n })\r\n app.get('/', (c) => c.redirect('/index.html'))\r\n\r\n app.get('/assets/*', assetsHandle)\r\n app.get('/favicon.ico', assetsHandle)\r\n app.get('*', async (c) => {\r\n const path = decodeURIComponent(c.req.path)\r\n\r\n const p = Effect.provide(renderHtmlByUriPath(path), context)\r\n const r = await Effect.runPromise(p)\r\n return c.html(r)\r\n })\r\n return app\r\n}\r\nasync function assetsHandle(c: HonoContext) {\r\n // TODO 处于安全考虑应该防范 file 跳出 assets\r\n const file = c.req.path\r\n const widgetPrefix = '/assets/widget/'\r\n const isWidget = file.startsWith(widgetPrefix)\r\n const apiPath = `${currentConfig.value.apiPrefix}${\r\n isWidget ? '/api/file/getFile' : file\r\n }`\r\n const r = await fetch(apiPath, {\r\n headers: {\r\n Authorization: `Token ${currentConfig.value.authorized}`,\r\n },\r\n method: isWidget ? 'POST' : 'GET',\r\n body: isWidget\r\n ? JSON.stringify({\r\n path: `/data/storage/oceanpress/widget_img/${file.substring(\r\n widgetPrefix.length,\r\n )}`,\r\n })\r\n : undefined,\r\n })\r\n const body = r.body\r\n if (!body) {\r\n return c.text('响应体为 null', 500, { 'Content-Type': 'text/plain' })\r\n }\r\n c.status(r.status as StatusCode)\r\n return stream(c, async (writeStream) => {\r\n const reader = body.getReader()\r\n while (true) {\r\n const r = await reader.read()\r\n if (r.done) {\r\n writeStream.close()\r\n break\r\n } else {\r\n writeStream.write(r.value)\r\n }\r\n }\r\n })\r\n}\r\n/** 渲染文档,通过 path 路径 */\r\nfunction renderHtmlByUriPath(path: string) {\r\n\r\n return Effect.gen(function* () {\r\n const hpath = decodeURIComponent(path)\r\n .replace(/\\#(.*)?$/, '')\r\n .replace(/\\.html$/, '')\r\n\r\n const doc = yield* Effect.tryPromise(() => get_doc_by_hpath(hpath))\r\n const htmlContent = yield* renderHTML(doc)\r\n return yield* Effect.tryPromise(() =>\r\n htmlTemplate(\r\n {\r\n title: doc.Properties?.title || '',\r\n htmlContent,\r\n level: path.split('/').length - 1 /** 最开头有一个 / */,\r\n },\r\n {\r\n ...tempConfig.cdn,\r\n embedCode: currentConfig.value.embedCode,\r\n },\r\n ),\r\n )\r\n })\r\n}\r\n","\r\n\r\nimport './cli/deploy.ts'\r\nimport './cli/build.ts'\r\nimport './cli/server.ts'\r\nimport { program } from './cli/common.ts'\r\n\r\nprogram.parse(process.argv)\r\n"],"mappings":"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","names":["API","stringify","html","html","c","res","Effect","watch","watch","usePromiseComputed","fn","version","Context","Effect","Effect","Effect","Effect","Context","render","html","sy","Effect","process","docBlock","Context","Effect","stringify","Context","Effect","readFile","Context","Effect","readFile","Effect","Context","readFile","Effect","Hono","Effect","Context","Context","Effect","r","Effect","Hono","resolve","Context","Effect","readFile","Context","Effect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oceanpress",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite",
@@ -28,6 +28,10 @@
28
28
  "dist-cli",
29
29
  "*.md"
30
30
  ],
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/siyuan-note/oceanpress.git"
34
+ },
31
35
  "dependencies": {
32
36
  "@aws-sdk/client-s3": "^3.873.0",
33
37
  "@hono/node-server": "^1.19.0",