oceanpress 1.0.13 → 1.0.15
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 +45 -1
- package/README_EN.md +131 -0
- package/dist-cli/cli.js +4 -5
- package/dist-cli/cli.js.map +1 -1
- package/package.json +1 -1
package/dist-cli/cli.js.map
CHANGED
|
@@ -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/plugins/markdown_mirror/plugin.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 console.error(`请配置 apiBase 和 apiKey`)\n throw new Error('请配置 apiBase 和 apiKey')\n }\n let config\n try {\n config = await readFile(opt.config, 'utf-8')\n } catch (error) {\n console.error('配置文件读取失败:', error)\n throw new Error('配置文件读取失败')\n }\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 if (process.env.NODE_ENV !== 'production') {\n console.log('[body]', body)\n }\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(r.error.message || 'API请求失败')\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 let parsedConfig\n try {\n parsedConfig = JSON.parse(config)\n } catch (error) {\n console.error('配置文件解析失败:', error)\n throw new Error('配置文件格式错误')\n }\n yield* loadConfigFile(parsedConfig)\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 /** Markdown 镜像导出配置 */\r\n markdownMirror: {\r\n enable: false,\r\n outputDir: '',\r\n includeAssets: false,\r\n watchMode: false,\r\n /** 定时同步间隔(毫秒) */\r\n watchInterval: 60000,\r\n /** 是否移除头部和底部(侧边栏、导航、footer 等) */\r\n removeTemplate: false,\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.13\",\n \"type\": \"module\",\n \"description\": \"从思源笔记本生成静态站点的工具\",\n \"author\": \"siyuan-note\",\n \"license\": \"MIT\",\n \"keywords\": [\n \"siyuan\",\n \"static-site-generator\",\n \"markdown\",\n \"blog\",\n \"ssg\"\n ],\n \"homepage\": \"https://github.com/siyuan-note/oceanpress#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/siyuan-note/oceanpress/issues\"\n },\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 \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/siyuan-note/oceanpress.git\"\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 \"turndown\": \"^7.2.2\",\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 \"@types/turndown\": \"^5.0.6\",\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 type { OceanPressPlugin } from '~/core/ocean_press.ts'\r\nimport type { FileTree } from '~/core/build.ts'\r\n// @ts-ignore - turndown 类型定义问题\r\nimport TurndownService from 'turndown'\r\n\r\nexport interface MarkdownMirrorConfig {\r\n /** 是否启用 Markdown 镜像导出 */\r\n enable: boolean\r\n /** 是否同步资源文件 */\r\n includeAssets: boolean\r\n}\r\n\r\nexport class MarkdownMirrorPlugin implements OceanPressPlugin {\r\n name = 'MarkdownMirrorPlugin'\r\n\r\n constructor(private config: MarkdownMirrorConfig) {\r\n // 无需初始化操作\r\n }\r\n\r\n /** 拦截 build,添加 Markdown 导出回调 */\r\n build: OceanPressPlugin['build'] = function ([config, otherConfig], next) {\r\n return next(config, {\r\n ...otherConfig,\r\n beforeFileTree: async (tree: FileTree, effectApi: any) => {\r\n // 先执行原有的 beforeFileTree 回调(如果有的话)\r\n if (otherConfig?.beforeFileTree) {\r\n await otherConfig.beforeFileTree(tree, effectApi)\r\n }\r\n\r\n // 执行 Markdown 镜像导出\r\n if (config.markdownMirror?.enable) {\r\n effectApi.log('\\n=== 开始 Markdown 镜像导出 ===')\r\n\r\n try {\r\n convertHtmlToMarkdown(\r\n tree,\r\n config.markdownMirror.includeAssets\r\n )\r\n effectApi.log('=== Markdown 镜像导出完成 ===\\n')\r\n } catch (error) {\r\n effectApi.log('❌ Markdown 镜像导出失败: ' + error)\r\n }\r\n }\r\n },\r\n onFileTree: async (tree: FileTree, effectApi: any) => {\r\n // 先执行原有的 onFileTree 回调\r\n if (otherConfig?.onFileTree) {\r\n await otherConfig.onFileTree(tree, effectApi)\r\n }\r\n },\r\n })\r\n }\r\n}\r\n\r\n/** 从 HTML 内容中提取所有标题的 ID 到标题文本的映射 */\r\nfunction buildIdToHeadingMap(htmlContent: string): Map<string, string> {\r\n const idToHeading = new Map<string, string>()\r\n\r\n // 使用正则表达式匹配所有带 ID 的标题\r\n // 格式:<h1 id=\"xxx\" ...>标题文本</h1>\r\n const headingRegex = /<h([1-6])\\s+id=\"([^\"]+)\"[^>]*>(.*?)<\\/h\\1>/gi\r\n let match\r\n\r\n while ((match = headingRegex.exec(htmlContent)) !== null) {\r\n const id = match[2]\r\n const headingText = match[3]\r\n // 移除 HTML 标签\r\n .replace(/<[^>]+>/g, '')\r\n // 解码 HTML 实体\r\n .replace(/ /g, ' ')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/&/g, '&')\r\n .replace(/"/g, '\"')\r\n .replace(/'/g, \"'\")\r\n .trim()\r\n\r\n idToHeading.set(id, headingText)\r\n }\r\n\r\n return idToHeading\r\n}\r\n\r\n/** 将标题文本转换为 URL 友好的锚点格式 */\r\nfunction headingToAnchor(headingText: string): string {\r\n return headingText\r\n .toLowerCase()\r\n // 移除特殊字符,保留中文、字母、数字、连字符和空格\r\n .replace(/[^\\p{L}\\p{N}\\s-]/gu, '')\r\n // 将空格和连字符替换为单个连字符\r\n .replace(/[\\s_]+/g, '-')\r\n // 移除开头和结尾的连字符\r\n .replace(/^-+|-+$/g, '')\r\n}\r\n\r\n/** 规范化文件路径,将相对路径转换为绝对路径 */\r\nfunction normalizePath(relativePath: string): string {\r\n // 移除开头的 ./ 或 ../\r\n let normalized = relativePath.replace(/^\\.\\//, '')\r\n\r\n // 处理 ../\r\n while (normalized.startsWith('../')) {\r\n normalized = normalized.slice(3)\r\n }\r\n\r\n return normalized\r\n}\r\n\r\n/** 在文件树中将 HTML 转换为 Markdown */\r\nfunction convertHtmlToMarkdown(tree: FileTree, includeAssets: boolean = false) {\r\n // 调试:输出文件树中的所有文件\r\n const allFiles = Object.keys(tree)\r\n console.log(`📂 文件树中共有 ${allFiles.length} 个文件`)\r\n if (allFiles.length > 0) {\r\n console.log('📂 前 10 个文件:', allFiles.slice(0, 10))\r\n }\r\n\r\n // 第一阶段:扫描所有 HTML 文件,建立全局的 ID 到标题映射\r\n const globalIdToHeading = new Map<string, string>()\r\n const htmlFiles = Object.entries(tree).filter(([filePath]) => filePath.endsWith('.html'))\r\n\r\n console.log('📖 正在扫描 HTML 文件以建立标题映射...')\r\n\r\n for (const [htmlPath, htmlContent] of htmlFiles) {\r\n const htmlStr = htmlContent.toString()\r\n const idToHeading = buildIdToHeadingMap(htmlStr)\r\n\r\n // 将文件路径前缀添加到 ID 中,形成全局唯一标识\r\n for (const [id, heading] of idToHeading.entries()) {\r\n // 使用 .md 路径作为键(因为链接会被转换为 .md)\r\n const mdPath = htmlPath.replace(/\\.html$/, '.md')\r\n globalIdToHeading.set(`${mdPath}:${id}`, heading)\r\n // 也存储 .html 路径作为备份\r\n globalIdToHeading.set(`${htmlPath}:${id}`, heading)\r\n // 存储 ./ 前缀的路径\r\n globalIdToHeading.set(`./${mdPath}:${id}`, heading)\r\n globalIdToHeading.set(`./${htmlPath}:${id}`, heading)\r\n }\r\n }\r\n\r\n console.log(`✅ 建立了 ${globalIdToHeading.size} 个标题映射\\n`)\r\n\r\n // 初始化 Turndown 服务\r\n const turndownService = new (TurndownService as any)({\r\n headingStyle: 'atx',\r\n codeBlockStyle: 'fenced',\r\n bulletListMarker: '-',\r\n })\r\n\r\n // 添加自定义规则\r\n turndownService.addRule('remove-sidebars', {\r\n filter: (node: any) => {\r\n return node.id === 'oceanpress-left-sidebar' ||\r\n node.id === 'oceanpress-right-sidebar'\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除 head、style、script 等标签\r\n turndownService.addRule('remove-html-metadata', {\r\n filter: (node: any) => {\r\n return ['head', 'style', 'script', 'noscript', 'link', 'meta', 'title'].includes(\r\n node.nodeName?.toLowerCase()\r\n )\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除 JSON-LD 结构化数据\r\n turndownService.addRule('remove-json-ld', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'SCRIPT' &&\r\n node.getAttribute('type') === 'application/ld+json'\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除思源的配置脚本\r\n turndownService.addRule('remove-siyuan-config', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'SCRIPT' &&\r\n node.textContent?.includes('window.siyuan')\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除 footer 元素\r\n turndownService.addRule('remove-footer', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'FOOTER' ||\r\n (node.nodeName === 'DIV' && node.classList?.contains('theme-aware-footer'))\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除首页链接(在标题前的单独链接)\r\n turndownService.addRule('remove-home-link', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'A' && node.getAttribute('href') === '/'\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 转换内部链接:.html -> .md,并使用标题锚点\r\n turndownService.addRule('convert-internal-links', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'A' && node.getAttribute('href')?.includes('.html')\r\n },\r\n replacement: (content: string, node: any) => {\r\n const href = node.getAttribute('href')\r\n if (!href) return content\r\n\r\n // 解析链接:提取路径和锚点\r\n const linkMatch = href.match(/^(.+?\\.html)(#.+)?$/)\r\n if (!linkMatch) return `[${content}](${href})`\r\n\r\n const htmlPath = linkMatch[1]\r\n const anchor = linkMatch[2] || '' // #xxxxx\r\n\r\n // 规范化路径(移除 ../ 和 ./)\r\n const normalizedHtmlPath = normalizePath(htmlPath)\r\n const mdPath = normalizedHtmlPath.replace(/\\.html$/, '.md')\r\n\r\n // 如果有锚点,尝试转换为标题锚点\r\n if (anchor) {\r\n const anchorId = anchor.slice(1) // 移除 #\r\n\r\n // 在全局映射中查找标题\r\n let headingText: string | undefined\r\n\r\n // 尝试不同的路径格式\r\n const possiblePaths = [\r\n `/${mdPath}:${anchorId}`, // /工具/blender.md:xxx\r\n `${mdPath}:${anchorId}`, // 工具/blender.md:xxx\r\n `/${normalizedHtmlPath}:${anchorId}`,\r\n `${normalizedHtmlPath}:${anchorId}`,\r\n ]\r\n\r\n for (const possiblePath of possiblePaths) {\r\n if (globalIdToHeading.has(possiblePath)) {\r\n headingText = globalIdToHeading.get(possiblePath)\r\n break\r\n }\r\n }\r\n\r\n if (headingText) {\r\n // 使用标题文本作为锚点\r\n const headingAnchor = headingToAnchor(headingText)\r\n // 如果原链接有 ../ 前缀,保留它\r\n const prefix = href.startsWith('../') ? '../' : (href.startsWith('./') ? './' : '')\r\n return `[${content}](${prefix}${mdPath}#${headingAnchor})`\r\n } else {\r\n // 调试:只记录前几个失败的链接\r\n if (Math.random() < 0.05) {\r\n console.warn(`⚠️ 未找到标题映射: ${href}`)\r\n console.warn(` 尝试的路径:`, possiblePaths.slice(0, 2))\r\n }\r\n }\r\n }\r\n\r\n // 如果没有找到标题,不使用锚点\r\n const prefix = href.startsWith('../') ? '../' : (href.startsWith('./') ? './' : '')\r\n return `[${content}](${prefix}${mdPath})`\r\n }\r\n })\r\n\r\n // 转换代码块:将 <div class=\"hljs\"> 转换为 Markdown 代码块\r\n turndownService.addRule('convert-code-blocks', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'DIV' && node.classList?.contains('hljs')\r\n },\r\n replacement: (_content: string, node: any) => {\r\n const code = node.textContent || ''\r\n // 确定语言\r\n let language = ''\r\n\r\n // 检查前面的兄弟节点是否有语言标识\r\n const previousSibling = node.previousSibling\r\n if (previousSibling && previousSibling.nodeName === 'DIV') {\r\n const actionDiv = previousSibling.querySelector('.protyle-action--first')\r\n if (actionDiv) {\r\n const langText = actionDiv.textContent?.trim()\r\n if (langText && langText !== 'Copy') {\r\n language = langText.toLowerCase()\r\n }\r\n }\r\n }\r\n\r\n // 如果没有找到语言标识,尝试从内容检测\r\n if (!language) {\r\n if (code.includes('function ') || code.includes('const ') || code.includes('let ') || code.includes('=>') || code.includes('interface ')) {\r\n language = 'typescript'\r\n } else if (code.includes('def ') || code.includes('import ') || code.includes('class ')) {\r\n language = 'python'\r\n } else if (code.includes('SELECT ') || code.includes('INSERT ') || code.includes('UPDATE ')) {\r\n language = 'sql'\r\n }\r\n }\r\n\r\n return `\\n\\`\\`\\`${language}\\n${code.trim()}\\n\\`\\`\\`\\n`\r\n }\r\n })\r\n\r\n console.log(`📄 找到 ${htmlFiles.length} 个 HTML 文件\\n`)\r\n\r\n // 转换每个 HTML 文件为 Markdown,直接在文件树上操作\r\n let convertedCount = 0\r\n\r\n for (const [htmlPath, htmlContent] of htmlFiles) {\r\n try {\r\n const mdPath = htmlPath.replace(/\\.html$/, '.md')\r\n const htmlStr = htmlContent.toString()\r\n let markdown = turndownService.turndown(htmlStr)\r\n\r\n // 移除开头的多余空行和空格\r\n markdown = markdown.trimStart()\r\n\r\n // 后处理:移除代码块前的单独语言标识行\r\n markdown = markdown.replace(/\\n([a-z]+)\\n\\n(```[a-z]+\\n)/g, '\\n$2')\r\n\r\n // 在文件树中添加 Markdown 文件\r\n tree[mdPath] = markdown\r\n\r\n // 删除原来的 HTML 文件\r\n delete tree[htmlPath]\r\n\r\n convertedCount++\r\n console.log(`✅ [${convertedCount}] ${htmlPath} → ${mdPath}`)\r\n } catch (error) {\r\n console.error(`❌ 转换失败: ${htmlPath}`, error)\r\n }\r\n }\r\n\r\n console.log(`\\n🎉 成功转换 ${convertedCount} 个 HTML 文件为 Markdown`)\r\n\r\n // 如果不同步资源文件,删除 assets 目录\r\n if (!includeAssets) {\r\n const assetPaths = Object.keys(tree).filter(path => path.startsWith('assets/'))\r\n assetPaths.forEach(assetPath => {\r\n delete tree[assetPath]\r\n })\r\n if (assetPaths.length > 0) {\r\n console.log(`🗑️ 已从文件树中移除 ${assetPaths.length} 个资源文件`)\r\n }\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 // 在文件树构建完成后、写入磁盘前调用,可以修改文件树\r\n beforeFileTree?: (tree: FileTree,effectApi:effectLog) => void | Promise<void>\r\n // 监听文件准备完毕 TODO:应该修改实现,而非目前直接全量加载到内存\r\n onFileTree?: (tree: FileTree,effectApi:effectLog) => void | Promise<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 const renderStartTime = Date.now()\r\n\r\n yield* Effect.all(Object.entries(docTree).map( ([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\r\n })\r\n }), {\r\n /** 这里设置为 6 会比 'unbounded' 更快,猜测是并发太高会导致栈切换不过来. 在我的电脑上测试 6 是一个最佳数值 */\r\n concurrency: 6 })\r\n\r\n const renderEndTime = Date.now()\r\n const renderDuration = ((renderEndTime - renderStartTime) / 1000).toFixed(2)\r\n effectLog.log( `=== 文档渲染完毕,共 ${Object.keys(docTree).length+1}篇,耗时: ${renderDuration}秒 ===`)\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?.beforeFileTree) {\r\n yield* Effect.tryPromise(() => Promise.resolve(otherConfig.beforeFileTree!(fileTree,effectLog)))\r\n }\r\n if (otherConfig?.onFileTree) {\r\n yield* Effect.tryPromise(() => Promise.resolve(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\nconst simplifiedStopWords = new Set([\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'\r\n])\r\n\r\n// HTML标签清理缓存(针对相同内容的重复处理)\r\nconst htmlCleanupCache = new Map<string, string>()\r\n\r\n// 限制缓存大小\r\nconst MAX_CACHE_SIZE = 500\r\nfunction manageCacheSize(): void {\r\n if (htmlCleanupCache.size > MAX_CACHE_SIZE) {\r\n const firstKey = htmlCleanupCache.keys().next().value\r\n if (firstKey) {\r\n htmlCleanupCache.delete(firstKey)\r\n }\r\n }\r\n}\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 * 优化的HTML清理函数(带缓存)\r\n */\r\nfunction cleanHtmlContent(content: string): string {\r\n const cacheKey = content\r\n if (htmlCleanupCache.has(cacheKey)) {\r\n return htmlCleanupCache.get(cacheKey)!\r\n }\r\n \r\n const cleaned = content\r\n .replace(/<[^>]*>/g, ' ')\r\n .replace(/&[^;]+;/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim()\r\n \r\n htmlCleanupCache.set(cacheKey, cleaned)\r\n manageCacheSize()\r\n return cleaned\r\n}\r\n\r\n/**\r\n * 从文档内容中提取描述文本(带缓存)\r\n */\r\nfunction extractDescription(content: string, maxLength = 160): string {\r\n const plainText = cleanHtmlContent(content)\r\n\r\n if (plainText.length <= maxLength) {\r\n return plainText\r\n }\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 return lastSentenceEnd > maxLength * 0.7 \r\n ? truncated.substring(0, lastSentenceEnd + 1)\r\n : truncated + '...'\r\n}\r\n\r\n/**\r\n * 优化的关键词提取(带缓存和简化算法)\r\n */\r\nfunction extractKeywords(content: string): string[] {\r\n const plainText = cleanHtmlContent(content)\r\n return simplifiedKeywordExtraction(plainText, 8)\r\n}\r\n\r\n/**\r\n * 简化的关键词提取算法(性能优化)\r\n */\r\nfunction simplifiedKeywordExtraction(text: string, maxKeywords: number = 8): string[] {\r\n const words: string[] = []\r\n const wordCount = new Map<string, number>()\r\n \r\n // 快速提取英文单词和技术术语\r\n const englishWords = text.match(/[a-zA-Z]{3,}/g) || []\r\n for (const word of englishWords) {\r\n const lowerWord = word.toLowerCase()\r\n if (!simplifiedStopWords.has(lowerWord) && lowerWord.length >= 3) {\r\n words.push(lowerWord)\r\n wordCount.set(lowerWord, (wordCount.get(lowerWord) || 0) + 1)\r\n }\r\n }\r\n \r\n // 快速提取中文词汇(2-4字)\r\n const chineseWords = text.match(/[\\u4e00-\\u9fa5]{2,4}/g) || []\r\n for (const word of chineseWords) {\r\n if (!simplifiedStopWords.has(word)) {\r\n words.push(word)\r\n wordCount.set(word, (wordCount.get(word) || 0) + 1)\r\n }\r\n }\r\n \r\n // 基于词频排序,返回前N个关键词\r\n return Array.from(wordCount.entries())\r\n .sort((a, b) => b[1] - a[1])\r\n .slice(0, maxKeywords)\r\n .map(([word]) => word)\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, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta property=\"og:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta name=\"twitter:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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 // 只对内容处理进行缓存,不缓存整个SEO结果\r\n const plainText = cleanHtmlContent(data.content)\r\n const description = extractDescriptionFromPlainText(plainText)\r\n const keywords = simplifiedKeywordExtraction(plainText, 8)\r\n \r\n const metaTags = generateSeoMetaTagsFromCache(data.doc, data.config, data.pageUrl, { plainText, description, keywords })\r\n let jsonLd = generateArticleJsonLdFromCache(data.doc, data.config, data.pageUrl, { plainText, description, keywords })\r\n \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 { metaTags, jsonLd }\r\n}\r\n\r\n/**\r\n * 从缓存生成SEO meta标签\r\n */\r\nfunction generateSeoMetaTagsFromCache(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n cache: { plainText: string; description: string; keywords: string[] }\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const { description, keywords } = cache\r\n\r\n let metaTags = ''\r\n\r\n // 基础 meta 标签\r\n metaTags += ` <meta name=\"description\" content=\"${description.replace(/\"/g, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta property=\"og:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta name=\"twitter:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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 * 从缓存生成JSON-LD\r\n */\r\nfunction generateArticleJsonLdFromCache(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n cache: { plainText: string; description: string; keywords: string[] }\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const { description, keywords } = cache\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: cache.plainText.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 * 从纯文本提取描述(优化版本)\r\n */\r\nfunction extractDescriptionFromPlainText(plainText: string, maxLength = 160): string {\r\n if (plainText.length <= maxLength) return plainText\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 return lastSentenceEnd > maxLength * 0.7 \r\n ? truncated.substring(0, lastSentenceEnd + 1)\r\n : truncated + '...'\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 = '20201227174241-nxny1tq'\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, \"&\")\r\n .replace(/</g, \"<\")\r\n .replace(/>/g, \">\")\r\n .replace(/\"/g, \""\")\r\n .replace(/'/g, \"&apos\");\r\n}\r\nexport function unescaping(s: string) {\r\n return s\r\n .replace(/&/g, \"&\")\r\n .replace(/</g, \"<\")\r\n .replace(/>/g, \">\")\r\n .replace(/"/g, '\"')\r\n .replace(/'/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 { MarkdownMirrorPlugin } from '~/plugins/markdown_mirror/plugin.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 // MarkdownMirror 插件:根据配置文件自动注册\r\n if (config.markdownMirror?.enable) {\r\n this.pluginCenter.registerPlugin(\r\n new MarkdownMirrorPlugin(config.markdownMirror),\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'\nimport packageJson from '../../package.json' with { type: 'json' }\n\nexport const program = new Command()\n\nprogram\n .name('OceanPress')\n .description('这是一款从思源笔记本生成一个静态站点的工具')\n .version(packageJson.version)\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 .option('--md', '启用 Markdown 镜像导出模式')\n .option('--watch', '启用监听模式,定时自动重新构建')\n .option('--watch-interval <number>', '监听模式下的同步间隔(秒)', '60')\n .action(async (opt: { config: string; output: string; md?: boolean; watch?: boolean; watchInterval?: 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 let parsedConfig\n try {\n parsedConfig = JSON.parse(config)\n } catch (error) {\n console.error('配置文件解析失败:', error)\n throw new Error('配置文件格式错误')\n }\n\n /** 如果启用了 --md 参数,自动添加 MarkdownMirror 插件配置 */\n if (opt.md) {\n const currentProfileName = parsedConfig.__current__\n const currentProfile = parsedConfig[currentProfileName]\n\n if (currentProfile) {\n // 保留用户现有的配置,只设置缺失的默认值\n currentProfile.markdownMirror = {\n enable: true, // --md 参数强制启用\n includeAssets: currentProfile.markdownMirror?.includeAssets ?? false, // 默认不同步资源\n }\n console.log('✅ 已启用 Markdown 镜像导出模式\\n')\n }\n }\n\n /** 先加载配置 */\n await Effect.runPromise(\n Effect.provideService(\n loadConfigFile(parsedConfig),\n EffectLocalStorageDep,\n nodeApiDep,\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\n /** 执行构建 */\n const runBuild = async () => {\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 const dirPromises = new Set<string>()\n\n for (const [path, data] of Object.entries(tree)) {\n const fullPath = join(filePath, path)\n const dirPath = resolve(fullPath, '..')\n\n // 避免重复创建目录\n if (!dirPromises.has(dirPath)) {\n dirPromises.add(dirPath)\n await mkdir(dirPath, { recursive: true })\n }\n\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.error(`${fullPath} 无法写入:`, error)\n }\n }\n },\n })\n\n console.log('[config.__current__]', parsedConfig.__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\n // 如果是 watch 模式,定时执行构建\n if (opt.watch) {\n const intervalSeconds = parseInt(opt.watchInterval || '60', 10)\n const intervalMs = intervalSeconds * 1000\n console.log(`\\n🔄 监听模式已启动,每 ${intervalSeconds} 秒自动构建一次\\n`)\n\n // 立即执行第一次构建\n await runBuild()\n\n // 定时执行构建\n setInterval(async () => {\n console.log('\\n⏰ 定时任务触发,开始构建...')\n try {\n await runBuild()\n const nextTime = new Date(Date.now() + intervalMs).toLocaleTimeString()\n console.log(`\\n⏰ 下次构建: ${nextTime}\\n`)\n } catch (error) {\n console.error('❌ 构建失败:', error)\n }\n }, intervalMs)\n } else {\n // 单次构建\n await runBuild()\n }\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'\n\nfunction validatePort(port: string): number {\n const portNum = Number(port)\n if (isNaN(portNum) || portNum < 1 || portNum > 65535) {\n throw new Error(`端口号必须在 1-65535 之间,当前值: ${port}`)\n }\n return portNum\n}\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: string\n }) => {\n if (!opt.config) {\n console.log(`请设置配置文件位置`)\n throw new Error('请设置配置文件位置')\n }\n let config\n try {\n config = await readFile(opt.config, 'utf-8')\n } catch (error) {\n console.error('配置文件读取失败:', error)\n throw new Error('配置文件读取失败')\n }\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 let parsedConfig\n try {\n parsedConfig = JSON.parse(config)\n } catch (error) {\n console.error('配置文件解析失败:', error)\n throw new Error('配置文件格式错误')\n }\n yield* loadConfigFile(parsedConfig)\n /** 使用本地的文件,方便调试 */\n tempConfig.cdn.siyuanPrefix = '/notebook/'\n return yield* server({\n hostname: opt.host,\n port: validatePort(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\n// 全局错误处理\r\nprocess.on('uncaughtException', (error) => {\r\n console.error('未捕获的异常:', error)\r\n process.exit(1)\r\n})\r\n\r\nprocess.on('unhandledRejection', (reason, promise) => {\r\n console.error('未处理的 Promise 拒绝:', reason)\r\n process.exit(1)\r\n})\r\n\r\nprogram.parse(process.argv)\r\n"],"mappings":"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","names":["API","stringify","html","html","c","res","prefix","Effect","watch","watch","usePromiseComputed","fn","cache","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/plugins/markdown_mirror/plugin.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 console.error(`请配置 apiBase 和 apiKey`)\n throw new Error('请配置 apiBase 和 apiKey')\n }\n let config\n try {\n config = await readFile(opt.config, 'utf-8')\n } catch (error) {\n console.error('配置文件读取失败:', error)\n throw new Error('配置文件读取失败')\n }\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 if (process.env.NODE_ENV !== 'production') {\n console.log('[body]', body)\n }\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(r.error.message || 'API请求失败')\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 let parsedConfig\n try {\n parsedConfig = JSON.parse(config)\n } catch (error) {\n console.error('配置文件解析失败:', error)\n throw new Error('配置文件格式错误')\n }\n yield* loadConfigFile(parsedConfig)\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 /** Markdown 镜像导出配置 */\r\n markdownMirror: {\r\n enable: false,\r\n includeAssets: false,\r\n /** 是否移除头部和底部(侧边栏、导航、footer 等) */\r\n removeTemplate: false,\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.14\",\n \"type\": \"module\",\n \"description\": \"从思源笔记本生成静态站点的工具\",\n \"author\": \"siyuan-note\",\n \"license\": \"MIT\",\n \"keywords\": [\n \"siyuan\",\n \"static-site-generator\",\n \"markdown\",\n \"blog\",\n \"ssg\"\n ],\n \"homepage\": \"https://github.com/siyuan-note/oceanpress#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/siyuan-note/oceanpress/issues\"\n },\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 \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/siyuan-note/oceanpress.git\"\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 \"turndown\": \"^7.2.2\",\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 \"@types/turndown\": \"^5.0.6\",\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 type { OceanPressPlugin } from '~/core/ocean_press.ts'\r\nimport type { FileTree } from '~/core/build.ts'\r\n// @ts-ignore - turndown 类型定义问题\r\nimport TurndownService from 'turndown'\r\n\r\nexport interface MarkdownMirrorConfig {\r\n /** 是否启用 Markdown 镜像导出 */\r\n enable: boolean\r\n /** 是否同步资源文件 */\r\n includeAssets: boolean\r\n}\r\n\r\nexport class MarkdownMirrorPlugin implements OceanPressPlugin {\r\n name = 'MarkdownMirrorPlugin'\r\n\r\n constructor(private config: MarkdownMirrorConfig) {\r\n // 无需初始化操作\r\n }\r\n\r\n /** 拦截 build,添加 Markdown 导出回调 */\r\n build: OceanPressPlugin['build'] = function ([config, otherConfig], next) {\r\n return next(config, {\r\n ...otherConfig,\r\n beforeFileTree: async (tree: FileTree, effectApi: any) => {\r\n // 先执行原有的 beforeFileTree 回调(如果有的话)\r\n if (otherConfig?.beforeFileTree) {\r\n await otherConfig.beforeFileTree(tree, effectApi)\r\n }\r\n\r\n // 调试:输出 markdownMirror 配置状态\r\n console.log('[MarkdownMirrorPlugin] config.markdownMirror?.enable:', config.markdownMirror?.enable)\r\n\r\n // 执行 Markdown 镜像导出\r\n if (config.markdownMirror?.enable) {\r\n effectApi.log('\\n=== 开始 Markdown 镜像导出 ===')\r\n\r\n try {\r\n convertHtmlToMarkdown(\r\n tree,\r\n config.markdownMirror.includeAssets\r\n )\r\n effectApi.log('=== Markdown 镜像导出完成 ===\\n')\r\n } catch (error) {\r\n effectApi.log('❌ Markdown 镜像导出失败: ' + error)\r\n }\r\n }\r\n },\r\n onFileTree: async (tree: FileTree, effectApi: any) => {\r\n // 先执行原有的 onFileTree 回调\r\n if (otherConfig?.onFileTree) {\r\n await otherConfig.onFileTree(tree, effectApi)\r\n }\r\n },\r\n })\r\n }\r\n}\r\n\r\n/** 从 HTML 内容中提取所有标题的 ID 到标题文本的映射 */\r\nfunction buildIdToHeadingMap(htmlContent: string): Map<string, string> {\r\n const idToHeading = new Map<string, string>()\r\n\r\n // 使用正则表达式匹配所有带 ID 的标题\r\n // 格式:<h1 id=\"xxx\" ...>标题文本</h1>\r\n const headingRegex = /<h([1-6])\\s+id=\"([^\"]+)\"[^>]*>(.*?)<\\/h\\1>/gi\r\n let match\r\n\r\n while ((match = headingRegex.exec(htmlContent)) !== null) {\r\n const id = match[2]\r\n const headingText = match[3]\r\n // 移除 HTML 标签\r\n .replace(/<[^>]+>/g, '')\r\n // 解码 HTML 实体\r\n .replace(/ /g, ' ')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/&/g, '&')\r\n .replace(/"/g, '\"')\r\n .replace(/'/g, \"'\")\r\n .trim()\r\n\r\n idToHeading.set(id, headingText)\r\n }\r\n\r\n return idToHeading\r\n}\r\n\r\n/** 将标题文本转换为 URL 友好的锚点格式 */\r\nfunction headingToAnchor(headingText: string): string {\r\n return headingText\r\n .toLowerCase()\r\n // 移除特殊字符,保留中文、字母、数字、连字符和空格\r\n .replace(/[^\\p{L}\\p{N}\\s-]/gu, '')\r\n // 将空格和连字符替换为单个连字符\r\n .replace(/[\\s_]+/g, '-')\r\n // 移除开头和结尾的连字符\r\n .replace(/^-+|-+$/g, '')\r\n}\r\n\r\n/** 规范化文件路径,将相对路径转换为绝对路径 */\r\nfunction normalizePath(relativePath: string): string {\r\n // 移除开头的 ./ 或 ../\r\n let normalized = relativePath.replace(/^\\.\\//, '')\r\n\r\n // 处理 ../\r\n while (normalized.startsWith('../')) {\r\n normalized = normalized.slice(3)\r\n }\r\n\r\n return normalized\r\n}\r\n\r\n/** 在文件树中将 HTML 转换为 Markdown */\r\nfunction convertHtmlToMarkdown(tree: FileTree, includeAssets: boolean = false) {\r\n // 调试:输出文件树中的所有文件\r\n const allFiles = Object.keys(tree)\r\n console.log(`📂 文件树中共有 ${allFiles.length} 个文件`)\r\n if (allFiles.length > 0) {\r\n console.log('📂 前 10 个文件:', allFiles.slice(0, 10))\r\n }\r\n\r\n // 第一阶段:扫描所有 HTML 文件,建立全局的 ID 到标题映射\r\n const globalIdToHeading = new Map<string, string>()\r\n const htmlFiles = Object.entries(tree).filter(([filePath]) => filePath.endsWith('.html'))\r\n\r\n console.log('📖 正在扫描 HTML 文件以建立标题映射...')\r\n\r\n for (const [htmlPath, htmlContent] of htmlFiles) {\r\n const htmlStr = htmlContent.toString()\r\n const idToHeading = buildIdToHeadingMap(htmlStr)\r\n\r\n // 将文件路径前缀添加到 ID 中,形成全局唯一标识\r\n for (const [id, heading] of idToHeading.entries()) {\r\n // 使用 .md 路径作为键(因为链接会被转换为 .md)\r\n const mdPath = htmlPath.replace(/\\.html$/, '.md')\r\n globalIdToHeading.set(`${mdPath}:${id}`, heading)\r\n // 也存储 .html 路径作为备份\r\n globalIdToHeading.set(`${htmlPath}:${id}`, heading)\r\n // 存储 ./ 前缀的路径\r\n globalIdToHeading.set(`./${mdPath}:${id}`, heading)\r\n globalIdToHeading.set(`./${htmlPath}:${id}`, heading)\r\n }\r\n }\r\n\r\n console.log(`✅ 建立了 ${globalIdToHeading.size} 个标题映射\\n`)\r\n\r\n // 初始化 Turndown 服务\r\n const turndownService = new (TurndownService as any)({\r\n headingStyle: 'atx',\r\n codeBlockStyle: 'fenced',\r\n bulletListMarker: '-',\r\n })\r\n\r\n // 添加自定义规则\r\n turndownService.addRule('remove-sidebars', {\r\n filter: (node: any) => {\r\n return node.id === 'oceanpress-left-sidebar' ||\r\n node.id === 'oceanpress-right-sidebar'\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除 head、style、script 等标签\r\n turndownService.addRule('remove-html-metadata', {\r\n filter: (node: any) => {\r\n return ['head', 'style', 'script', 'noscript', 'link', 'meta', 'title'].includes(\r\n node.nodeName?.toLowerCase()\r\n )\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除 JSON-LD 结构化数据\r\n turndownService.addRule('remove-json-ld', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'SCRIPT' &&\r\n node.getAttribute('type') === 'application/ld+json'\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除思源的配置脚本\r\n turndownService.addRule('remove-siyuan-config', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'SCRIPT' &&\r\n node.textContent?.includes('window.siyuan')\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除 footer 元素\r\n turndownService.addRule('remove-footer', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'FOOTER' ||\r\n (node.nodeName === 'DIV' && node.classList?.contains('theme-aware-footer'))\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 移除首页链接(在标题前的单独链接)\r\n turndownService.addRule('remove-home-link', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'A' && node.getAttribute('href') === '/'\r\n },\r\n replacement: () => ''\r\n })\r\n\r\n // 转换内部链接:.html -> .md,并使用标题锚点\r\n turndownService.addRule('convert-internal-links', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'A' && node.getAttribute('href')?.includes('.html')\r\n },\r\n replacement: (content: string, node: any) => {\r\n const href = node.getAttribute('href')\r\n if (!href) return content\r\n\r\n // 解析链接:提取路径和锚点\r\n const linkMatch = href.match(/^(.+?\\.html)(#.+)?$/)\r\n if (!linkMatch) return `[${content}](${href})`\r\n\r\n const htmlPath = linkMatch[1]\r\n const anchor = linkMatch[2] || '' // #xxxxx\r\n\r\n // 规范化路径(移除 ../ 和 ./)\r\n const normalizedHtmlPath = normalizePath(htmlPath)\r\n const mdPath = normalizedHtmlPath.replace(/\\.html$/, '.md')\r\n\r\n // 如果有锚点,尝试转换为标题锚点\r\n if (anchor) {\r\n const anchorId = anchor.slice(1) // 移除 #\r\n\r\n // 在全局映射中查找标题\r\n let headingText: string | undefined\r\n\r\n // 尝试不同的路径格式\r\n const possiblePaths = [\r\n `/${mdPath}:${anchorId}`, // /工具/blender.md:xxx\r\n `${mdPath}:${anchorId}`, // 工具/blender.md:xxx\r\n `/${normalizedHtmlPath}:${anchorId}`,\r\n `${normalizedHtmlPath}:${anchorId}`,\r\n ]\r\n\r\n for (const possiblePath of possiblePaths) {\r\n if (globalIdToHeading.has(possiblePath)) {\r\n headingText = globalIdToHeading.get(possiblePath)\r\n break\r\n }\r\n }\r\n\r\n if (headingText) {\r\n // 使用标题文本作为锚点\r\n const headingAnchor = headingToAnchor(headingText)\r\n // 如果原链接有 ../ 前缀,保留它\r\n const prefix = href.startsWith('../') ? '../' : (href.startsWith('./') ? './' : '')\r\n return `[${content}](${prefix}${mdPath}#${headingAnchor})`\r\n } else {\r\n // 调试:只记录前几个失败的链接\r\n if (Math.random() < 0.05) {\r\n console.warn(`⚠️ 未找到标题映射: ${href}`)\r\n console.warn(` 尝试的路径:`, possiblePaths.slice(0, 2))\r\n }\r\n }\r\n }\r\n\r\n // 如果没有找到标题,不使用锚点\r\n const prefix = href.startsWith('../') ? '../' : (href.startsWith('./') ? './' : '')\r\n return `[${content}](${prefix}${mdPath})`\r\n }\r\n })\r\n\r\n // 转换代码块:将 <div class=\"hljs\"> 转换为 Markdown 代码块\r\n turndownService.addRule('convert-code-blocks', {\r\n filter: (node: any) => {\r\n return node.nodeName === 'DIV' && node.classList?.contains('hljs')\r\n },\r\n replacement: (_content: string, node: any) => {\r\n const code = node.textContent || ''\r\n // 确定语言\r\n let language = ''\r\n\r\n // 检查前面的兄弟节点是否有语言标识\r\n const previousSibling = node.previousSibling\r\n if (previousSibling && previousSibling.nodeName === 'DIV') {\r\n const actionDiv = previousSibling.querySelector('.protyle-action--first')\r\n if (actionDiv) {\r\n const langText = actionDiv.textContent?.trim()\r\n if (langText && langText !== 'Copy') {\r\n language = langText.toLowerCase()\r\n }\r\n }\r\n }\r\n\r\n // 如果没有找到语言标识,尝试从内容检测\r\n if (!language) {\r\n if (code.includes('function ') || code.includes('const ') || code.includes('let ') || code.includes('=>') || code.includes('interface ')) {\r\n language = 'typescript'\r\n } else if (code.includes('def ') || code.includes('import ') || code.includes('class ')) {\r\n language = 'python'\r\n } else if (code.includes('SELECT ') || code.includes('INSERT ') || code.includes('UPDATE ')) {\r\n language = 'sql'\r\n }\r\n }\r\n\r\n return `\\n\\`\\`\\`${language}\\n${code.trim()}\\n\\`\\`\\`\\n`\r\n }\r\n })\r\n\r\n console.log(`📄 找到 ${htmlFiles.length} 个 HTML 文件\\n`)\r\n\r\n // 转换每个 HTML 文件为 Markdown,直接在文件树上操作\r\n let convertedCount = 0\r\n\r\n for (const [htmlPath, htmlContent] of htmlFiles) {\r\n try {\r\n const mdPath = htmlPath.replace(/\\.html$/, '.md')\r\n const htmlStr = htmlContent.toString()\r\n let markdown = turndownService.turndown(htmlStr)\r\n\r\n // 移除开头的多余空行和空格\r\n markdown = markdown.trimStart()\r\n\r\n // 后处理:移除代码块前的单独语言标识行\r\n markdown = markdown.replace(/\\n([a-z]+)\\n\\n(```[a-z]+\\n)/g, '\\n$2')\r\n\r\n // 在文件树中添加 Markdown 文件\r\n tree[mdPath] = markdown\r\n\r\n // 删除原来的 HTML 文件\r\n delete tree[htmlPath]\r\n\r\n convertedCount++\r\n console.log(`✅ [${convertedCount}] ${htmlPath} → ${mdPath}`)\r\n } catch (error) {\r\n console.error(`❌ 转换失败: ${htmlPath}`, error)\r\n }\r\n }\r\n\r\n console.log(`\\n🎉 成功转换 ${convertedCount} 个 HTML 文件为 Markdown`)\r\n\r\n // 如果不同步资源文件,删除 assets 目录\r\n if (!includeAssets) {\r\n const assetPaths = Object.keys(tree).filter(path => path.startsWith('assets/'))\r\n assetPaths.forEach(assetPath => {\r\n delete tree[assetPath]\r\n })\r\n if (assetPaths.length > 0) {\r\n console.log(`🗑️ 已从文件树中移除 ${assetPaths.length} 个资源文件`)\r\n }\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 // 在文件树构建完成后、写入磁盘前调用,可以修改文件树\r\n beforeFileTree?: (tree: FileTree,effectApi:effectLog) => void | Promise<void>\r\n // 监听文件准备完毕 TODO:应该修改实现,而非目前直接全量加载到内存\r\n onFileTree?: (tree: FileTree,effectApi:effectLog) => void | Promise<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 const renderStartTime = Date.now()\r\n\r\n yield* Effect.all(Object.entries(docTree).map( ([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\r\n })\r\n }), {\r\n /** 这里设置为 6 会比 'unbounded' 更快,猜测是并发太高会导致栈切换不过来. 在我的电脑上测试 6 是一个最佳数值 */\r\n concurrency: 6 })\r\n\r\n const renderEndTime = Date.now()\r\n const renderDuration = ((renderEndTime - renderStartTime) / 1000).toFixed(2)\r\n effectLog.log( `=== 文档渲染完毕,共 ${Object.keys(docTree).length+1}篇,耗时: ${renderDuration}秒 ===`)\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?.beforeFileTree) {\r\n yield* Effect.tryPromise(() => Promise.resolve(otherConfig.beforeFileTree!(fileTree,effectLog)))\r\n }\r\n if (otherConfig?.onFileTree) {\r\n yield* Effect.tryPromise(() => Promise.resolve(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\nconst simplifiedStopWords = new Set([\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'\r\n])\r\n\r\n// HTML标签清理缓存(针对相同内容的重复处理)\r\nconst htmlCleanupCache = new Map<string, string>()\r\n\r\n// 限制缓存大小\r\nconst MAX_CACHE_SIZE = 500\r\nfunction manageCacheSize(): void {\r\n if (htmlCleanupCache.size > MAX_CACHE_SIZE) {\r\n const firstKey = htmlCleanupCache.keys().next().value\r\n if (firstKey) {\r\n htmlCleanupCache.delete(firstKey)\r\n }\r\n }\r\n}\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 * 优化的HTML清理函数(带缓存)\r\n */\r\nfunction cleanHtmlContent(content: string): string {\r\n const cacheKey = content\r\n if (htmlCleanupCache.has(cacheKey)) {\r\n return htmlCleanupCache.get(cacheKey)!\r\n }\r\n \r\n const cleaned = content\r\n .replace(/<[^>]*>/g, ' ')\r\n .replace(/&[^;]+;/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim()\r\n \r\n htmlCleanupCache.set(cacheKey, cleaned)\r\n manageCacheSize()\r\n return cleaned\r\n}\r\n\r\n/**\r\n * 从文档内容中提取描述文本(带缓存)\r\n */\r\nfunction extractDescription(content: string, maxLength = 160): string {\r\n const plainText = cleanHtmlContent(content)\r\n\r\n if (plainText.length <= maxLength) {\r\n return plainText\r\n }\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 return lastSentenceEnd > maxLength * 0.7 \r\n ? truncated.substring(0, lastSentenceEnd + 1)\r\n : truncated + '...'\r\n}\r\n\r\n/**\r\n * 优化的关键词提取(带缓存和简化算法)\r\n */\r\nfunction extractKeywords(content: string): string[] {\r\n const plainText = cleanHtmlContent(content)\r\n return simplifiedKeywordExtraction(plainText, 8)\r\n}\r\n\r\n/**\r\n * 简化的关键词提取算法(性能优化)\r\n */\r\nfunction simplifiedKeywordExtraction(text: string, maxKeywords: number = 8): string[] {\r\n const words: string[] = []\r\n const wordCount = new Map<string, number>()\r\n \r\n // 快速提取英文单词和技术术语\r\n const englishWords = text.match(/[a-zA-Z]{3,}/g) || []\r\n for (const word of englishWords) {\r\n const lowerWord = word.toLowerCase()\r\n if (!simplifiedStopWords.has(lowerWord) && lowerWord.length >= 3) {\r\n words.push(lowerWord)\r\n wordCount.set(lowerWord, (wordCount.get(lowerWord) || 0) + 1)\r\n }\r\n }\r\n \r\n // 快速提取中文词汇(2-4字)\r\n const chineseWords = text.match(/[\\u4e00-\\u9fa5]{2,4}/g) || []\r\n for (const word of chineseWords) {\r\n if (!simplifiedStopWords.has(word)) {\r\n words.push(word)\r\n wordCount.set(word, (wordCount.get(word) || 0) + 1)\r\n }\r\n }\r\n \r\n // 基于词频排序,返回前N个关键词\r\n return Array.from(wordCount.entries())\r\n .sort((a, b) => b[1] - a[1])\r\n .slice(0, maxKeywords)\r\n .map(([word]) => word)\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, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta property=\"og:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta name=\"twitter:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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 // 只对内容处理进行缓存,不缓存整个SEO结果\r\n const plainText = cleanHtmlContent(data.content)\r\n const description = extractDescriptionFromPlainText(plainText)\r\n const keywords = simplifiedKeywordExtraction(plainText, 8)\r\n \r\n const metaTags = generateSeoMetaTagsFromCache(data.doc, data.config, data.pageUrl, { plainText, description, keywords })\r\n let jsonLd = generateArticleJsonLdFromCache(data.doc, data.config, data.pageUrl, { plainText, description, keywords })\r\n \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 { metaTags, jsonLd }\r\n}\r\n\r\n/**\r\n * 从缓存生成SEO meta标签\r\n */\r\nfunction generateSeoMetaTagsFromCache(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n cache: { plainText: string; description: string; keywords: string[] }\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const { description, keywords } = cache\r\n\r\n let metaTags = ''\r\n\r\n // 基础 meta 标签\r\n metaTags += ` <meta name=\"description\" content=\"${description.replace(/\"/g, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta property=\"og:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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, '"')}\" />\\n`\r\n metaTags += ` <meta name=\"twitter:description\" content=\"${description.replace(/\"/g, '"')}\" />\\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 * 从缓存生成JSON-LD\r\n */\r\nfunction generateArticleJsonLdFromCache(\r\n doc: S_Node,\r\n config: Config,\r\n pageUrl: string,\r\n cache: { plainText: string; description: string; keywords: string[] }\r\n): string {\r\n const title = doc.Properties?.title || '未命名文档'\r\n const { description, keywords } = cache\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: cache.plainText.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 * 从纯文本提取描述(优化版本)\r\n */\r\nfunction extractDescriptionFromPlainText(plainText: string, maxLength = 160): string {\r\n if (plainText.length <= maxLength) return plainText\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 return lastSentenceEnd > maxLength * 0.7 \r\n ? truncated.substring(0, lastSentenceEnd + 1)\r\n : truncated + '...'\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 = '20201227174241-nxny1tq'\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, \"&\")\r\n .replace(/</g, \"<\")\r\n .replace(/>/g, \">\")\r\n .replace(/\"/g, \""\")\r\n .replace(/'/g, \"&apos\");\r\n}\r\nexport function unescaping(s: string) {\r\n return s\r\n .replace(/&/g, \"&\")\r\n .replace(/</g, \"<\")\r\n .replace(/>/g, \">\")\r\n .replace(/"/g, '\"')\r\n .replace(/'/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 { MarkdownMirrorPlugin } from '~/plugins/markdown_mirror/plugin.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 // MarkdownMirror 插件:根据配置文件自动注册\r\n console.log('[OceanPress constructor] config.markdownMirror?.enable:', config.markdownMirror?.enable)\r\n if (config.markdownMirror?.enable) {\r\n console.log('[OceanPress] 注册 MarkdownMirror 插件')\r\n this.pluginCenter.registerPlugin(\r\n new MarkdownMirrorPlugin(config.markdownMirror),\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'\nimport packageJson from '../../package.json' with { type: 'json' }\n\nexport const program = new Command()\n\nprogram\n .name('OceanPress')\n .description('这是一款从思源笔记本生成一个静态站点的工具')\n .version(packageJson.version)\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 .option('--md', '启用 Markdown 镜像导出模式')\n .option('--watch', '启用监听模式,定时自动重新构建')\n .option('--watch-interval <number>', '监听模式下的同步间隔(秒)', '60')\n .action(async (opt: { config: string; output: string; md?: boolean; watch?: boolean; watchInterval?: 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 let parsedConfig\n try {\n parsedConfig = JSON.parse(config)\n } catch (error) {\n console.error('配置文件解析失败:', error)\n throw new Error('配置文件格式错误')\n }\n\n /** 如果启用了 --md 参数,自动添加 MarkdownMirror 插件配置 */\n if (opt.md) {\n const currentProfileName = parsedConfig.__current__\n const currentProfile = parsedConfig[currentProfileName]\n\n if (currentProfile) {\n // 保留用户现有的配置,只设置缺失的默认值\n currentProfile.markdownMirror = {\n enable: true, // --md 参数强制启用\n includeAssets: currentProfile.markdownMirror?.includeAssets ?? false, // 默认不同步资源\n }\n console.log('✅ 已启用 Markdown 镜像导出模式\\n')\n }\n }\n\n /** 先加载配置 */\n await Effect.runPromise(\n Effect.provideService(\n loadConfigFile(parsedConfig),\n EffectLocalStorageDep,\n nodeApiDep,\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\n /** 执行构建 */\n const runBuild = async () => {\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 const dirPromises = new Set<string>()\n\n for (const [path, data] of Object.entries(tree)) {\n const fullPath = join(filePath, path)\n const dirPath = resolve(fullPath, '..')\n\n // 避免重复创建目录\n if (!dirPromises.has(dirPath)) {\n dirPromises.add(dirPath)\n await mkdir(dirPath, { recursive: true })\n }\n\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.error(`${fullPath} 无法写入:`, error)\n }\n }\n },\n })\n\n console.log('[config.__current__]', parsedConfig.__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\n // 如果是 watch 模式,定时执行构建\n if (opt.watch) {\n const intervalSeconds = parseInt(opt.watchInterval || '60', 10)\n const intervalMs = intervalSeconds * 1000\n console.log(`\\n🔄 监听模式已启动,每 ${intervalSeconds} 秒自动构建一次\\n`)\n\n // 立即执行第一次构建\n await runBuild()\n\n // 定时执行构建\n setInterval(async () => {\n console.log('\\n⏰ 定时任务触发,开始构建...')\n try {\n await runBuild()\n const nextTime = new Date(Date.now() + intervalMs).toLocaleTimeString()\n console.log(`\\n⏰ 下次构建: ${nextTime}\\n`)\n } catch (error) {\n console.error('❌ 构建失败:', error)\n }\n }, intervalMs)\n } else {\n // 单次构建\n await runBuild()\n }\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'\n\nfunction validatePort(port: string): number {\n const portNum = Number(port)\n if (isNaN(portNum) || portNum < 1 || portNum > 65535) {\n throw new Error(`端口号必须在 1-65535 之间,当前值: ${port}`)\n }\n return portNum\n}\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: string\n }) => {\n if (!opt.config) {\n console.log(`请设置配置文件位置`)\n throw new Error('请设置配置文件位置')\n }\n let config\n try {\n config = await readFile(opt.config, 'utf-8')\n } catch (error) {\n console.error('配置文件读取失败:', error)\n throw new Error('配置文件读取失败')\n }\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 let parsedConfig\n try {\n parsedConfig = JSON.parse(config)\n } catch (error) {\n console.error('配置文件解析失败:', error)\n throw new Error('配置文件格式错误')\n }\n yield* loadConfigFile(parsedConfig)\n /** 使用本地的文件,方便调试 */\n tempConfig.cdn.siyuanPrefix = '/notebook/'\n return yield* server({\n hostname: opt.host,\n port: validatePort(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\n// 全局错误处理\r\nprocess.on('uncaughtException', (error) => {\r\n console.error('未捕获的异常:', error)\r\n process.exit(1)\r\n})\r\n\r\nprocess.on('unhandledRejection', (reason, promise) => {\r\n console.error('未处理的 Promise 拒绝:', reason)\r\n process.exit(1)\r\n})\r\n\r\nprogram.parse(process.argv)\r\n"],"mappings":"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","names":["API","stringify","html","html","c","res","prefix","Effect","watch","watch","usePromiseComputed","fn","cache","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"]}
|