lark-docx2md 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  将飞书文档转换为 Markdown 文件的命令行工具。
6
6
 
7
- > 支持的飞书文档链接格式:`https://*.feishu.cn/wiki/*`、`https://*.feishu.cn/sheets/*`
7
+ > 支持的飞书文档链接格式:`https://*.feishu.cn/wiki/*`、`https://*.feishu.cn/sheets/*`(支持 `?sheet=<sheetId>` 指定子表)
8
8
 
9
9
  ## 使用
10
10
 
@@ -32,7 +32,7 @@ npx -y lark-docx2md@latest download <url>
32
32
 
33
33
  | 参数 | 说明 | 环境变量 | 默认值 |
34
34
  |--------------------------|-------------------------------------------|------------------------------|-----------------------|
35
- | `<url>` | 飞书文档链接(`https://*.feishu.cn/wiki/*` 或 `/sheets/*`) | — | — |
35
+ | `<url>` | 飞书文档链接(`https://*.feishu.cn/wiki/*` 或 `/sheets/*`,支持 `?sheet=<sheetId>` 指定子表) | — | — |
36
36
  | `--app-id <id>` | 飞书应用 App ID | `LARK_DOCX2MD_APP_ID` | — |
37
37
  | `--app-secret <secret>` | 飞书应用 App Secret | `LARK_DOCX2MD_APP_SECRET` | — |
38
38
  | `-o, --output <dir>` | 输出目录 | `LARK_DOCX2MD_OUTPUT` | `./larkDocx2mdOutput` |
@@ -55,7 +55,7 @@ npx -y lark-docx2md@latest download <url>
55
55
  - 输出标准 Markdown 文件
56
56
  - 支持飞书画板,输出格式:`base64`(data URI 内嵌)、`inline-svg`(SVG 标签内嵌)、`svg`(独立文件)、`yaml`(AI
57
57
  友好结构化数据)。详见 [画板支持说明](./WHITEBOARD.md)
58
- - 支持飞书电子表格(独立 sheet URL 或 docx 内嵌 sheet 块),输出 GFM 表格,自动展开合并单元格。详见 [电子表格支持说明](./SHEET.md)
58
+ - 支持飞书电子表格(独立 sheet URL 或 docx 内嵌 sheet 块),输出 GFM 表格,自动展开合并单元格;支持 `?sheet=<sheetId>` 仅处理指定子表。详见 [电子表格支持说明](./SHEET.md)
59
59
 
60
60
  ### 支持的内容块类型
61
61
 
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { r as setLogLevel, t as convert } from "./converter-C5Nrkvfa.js";
2
+ import { r as setLogLevel, t as convert } from "./converter-jW2Zu4Pb.js";
3
3
  import { Command } from "commander";
4
4
  import { LoggerLevel } from "@larksuiteoapi/node-sdk";
5
5
  //#region src/cli.ts
@@ -59,7 +59,7 @@ program.command("download").alias("dl").description("Download a wiki document to
59
59
  wbFormat: opts.wbFormat,
60
60
  agent: agentLocal ? "local" : opts.agent === true
61
61
  });
62
- if (agentLocal) process.stdout.write(`The Feishu document has been downloaded to the following absolute path:\n${result.filePath}\n\nPlease read this file to access the full markdown content.\n`);
62
+ if (agentLocal) process.stdout.write(`**The Feishu document has been downloaded to the following absolute path:**\n\n\`${result.filePath}\`\n\n**Read this file to access the full markdown content.**\n`);
63
63
  else if (opts.agent === true) process.stdout.write(result.markdown);
64
64
  });
65
65
  program.parse();
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { LoggerLevel } from '@larksuiteoapi/node-sdk';\nimport { convert } from './converter.js';\nimport { setLogLevel } from './logger.js';\nimport type { SvgBackground, WbFormat, WbImageMode } from './types.js';\n\nconst program = new Command();\nprogram.name('larkDocx2md').description('Download Lark/Feishu documents to markdown');\n\nprogram\n .command('download')\n .alias('dl')\n .description('Download a wiki document to markdown')\n .option('--app-id <id>', 'Feishu app ID (or read from LARK_DOCX2MD_APP_ID)')\n .option('--app-secret <secret>', 'Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)')\n .option('-o, --output <dir>', 'Output directory (or LARK_DOCX2MD_OUTPUT)')\n .option('--agent [mode]', 'Enable agent mode: ERROR log level, and AI-oriented stdout. Pass \"local\" to save markdown/images/whiteboards to disk and print a read-file prompt (or LARK_DOCX2MD_AGENT=true|local)')\n .option('--wb-format <format>', 'Whiteboard output format: \"base64\", \"inline-svg\", \"svg\", or \"yaml\" (or LARK_DOCX2MD_WB_FORMAT)')\n .option('--wb-bg <style>', 'Whiteboard SVG background: \"none\", \"dot\", or a color like \"#fff\" (or LARK_DOCX2MD_WB_BG)')\n .option('--wb-image-mode <mode>', 'Whiteboard image mode: \"online\", \"base64\", or \"local\" (or LARK_DOCX2MD_WB_IMAGE_MODE)')\n .option('--image-mode <mode>', 'Image handling mode: \"local\" or \"online\" (or LARK_DOCX2MD_IMAGE_MODE)')\n .argument('<url>', 'Feishu wiki document URL: https://*.feishu.cn/wiki/*')\n .action(async (url: string, opts: { appId?: string; appSecret?: string; output?: string; agent?: boolean | string; imageMode?: string; wbImageMode?: string; wbBg?: SvgBackground; wbFormat?: string }) => {\n // ─── 环境变量默认值(直接指定 > 环境变量 > 内置默认值)────────────────\n opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;\n opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;\n opts.output = opts.output ?? process.env.LARK_DOCX2MD_OUTPUT ?? './larkDocx2mdOutput';\n // 解析 --agent:可能为 undefined | true | 'local' | 其他字符串\n if (opts.agent === undefined) {\n const envAgent = process.env.LARK_DOCX2MD_AGENT;\n if (envAgent === 'true') opts.agent = true;\n else if (envAgent === 'local') opts.agent = 'local';\n else opts.agent = false;\n } else if (typeof opts.agent === 'string' && opts.agent !== 'local') {\n program.error(`Invalid --agent value \"${opts.agent}\", only \"local\" is supported (or omit the value)`);\n }\n const agentEnabled = opts.agent === true || opts.agent === 'local';\n const agentLocal = opts.agent === 'local';\n\n opts.imageMode = opts.imageMode ?? process.env.LARK_DOCX2MD_IMAGE_MODE ?? 'local';\n opts.wbFormat = opts.wbFormat ?? process.env.LARK_DOCX2MD_WB_FORMAT;\n opts.wbBg = opts.wbBg ?? process.env.LARK_DOCX2MD_WB_BG ?? 'none';\n opts.wbImageMode = opts.wbImageMode ?? process.env.LARK_DOCX2MD_WB_IMAGE_MODE ?? 'local';\n\n // 设置 wb-format 默认值:--agent local 默认 inline-svg(兼容本地画板图片),--agent(在线)默认 yaml,其余 svg\n if (!opts.wbFormat) {\n opts.wbFormat = agentEnabled ? 'yaml' : 'svg';\n }\n\n if (agentEnabled) {\n setLogLevel(LoggerLevel.error);\n if (agentLocal) {\n // --agent local:图片/画板图片均落盘\n opts.imageMode = 'local';\n opts.wbImageMode = 'local';\n } else {\n // --agent(在线):一律在线,且画板仅支持内嵌形式\n opts.imageMode = 'online';\n opts.wbImageMode = 'online';\n }\n if (!['inline-svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Agent mode only supports \"inline-svg\" or \"yaml\" for --wb-format`);\n }\n } else {\n // yaml 格式图片仅支持 online\n if (opts.wbFormat === 'yaml') {\n opts.wbImageMode = 'online';\n }\n }\n\n if (opts.imageMode && !['local', 'online'].includes(opts.imageMode)) {\n program.error(`Invalid --image-mode \"${opts.imageMode}\", must be \"local\" or \"online\"`);\n }\n if (!['base64', 'inline-svg', 'svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Invalid --wb-format \"${opts.wbFormat}\", must be \"base64\", \"inline-svg\", \"svg\", or \"yaml\"`);\n }\n if (!['online', 'base64', 'local'].includes(opts.wbImageMode)) {\n program.error(`Invalid --wb-image-mode \"${opts.wbImageMode}\", must be \"online\", \"base64\", or \"local\"`);\n }\n\n const appId = opts.appId!;\n const appSecret = opts.appSecret!;\n if (!appId || !appSecret) {\n program.error('Missing credentials: pass --app-id/--app-secret or set LARK_DOCX2MD_APP_ID/LARK_DOCX2MD_APP_SECRET');\n }\n\n const result = await convert({\n appId,\n appSecret,\n url,\n output: opts.output,\n imageMode: opts.imageMode as 'local' | 'online',\n wbImageMode: opts.wbImageMode as WbImageMode,\n wbBg: opts.wbBg,\n wbFormat: opts.wbFormat as WbFormat,\n agent: agentLocal ? 'local' : (opts.agent === true),\n });\n\n if (agentLocal) {\n // 本地模式:输出引导 AI 读取文件的提示词(绝对路径)\n process.stdout.write(\n `The Feishu document has been downloaded to the following absolute path:\\n` +\n `${result.filePath}\\n\\n` +\n `Please read this file to access the full markdown content.\\n`,\n );\n } else if (opts.agent === true) {\n process.stdout.write(result.markdown);\n }\n });\n\nprogram.parse();\n"],"mappings":";;;;;AAOA,MAAM,UAAU,IAAI,SAAS;AAC7B,QAAQ,KAAK,cAAc,CAAC,YAAY,6CAA6C;AAErF,QACG,QAAQ,WAAW,CACnB,MAAM,KAAK,CACX,YAAY,uCAAuC,CACnD,OAAO,iBAAiB,mDAAmD,CAC3E,OAAO,yBAAyB,2DAA2D,CAC3F,OAAO,sBAAsB,4CAA4C,CACzE,OAAO,kBAAkB,yLAAuL,CAChN,OAAO,wBAAwB,yGAAiG,CAChI,OAAO,mBAAmB,iGAA2F,CACrH,OAAO,0BAA0B,8FAAwF,CACzH,OAAO,uBAAuB,4EAAwE,CACtG,SAAS,SAAS,uDAAuD,CACzE,OAAO,OAAO,KAAa,SAA+K;AAEzM,MAAK,QAAQ,KAAK,SAAS,QAAQ,IAAI;AACvC,MAAK,YAAY,KAAK,aAAa,QAAQ,IAAI;AAC/C,MAAK,SAAS,KAAK,UAAU,QAAQ,IAAI,uBAAuB;AAEhE,KAAI,KAAK,UAAU,KAAA,GAAW;EAC5B,MAAM,WAAW,QAAQ,IAAI;AAC7B,MAAI,aAAa,OAAQ,MAAK,QAAQ;WAC7B,aAAa,QAAS,MAAK,QAAQ;MACvC,MAAK,QAAQ;YACT,OAAO,KAAK,UAAU,YAAY,KAAK,UAAU,QAC1D,SAAQ,MAAM,0BAA0B,KAAK,MAAM,kDAAkD;CAEvG,MAAM,eAAe,KAAK,UAAU,QAAQ,KAAK,UAAU;CAC3D,MAAM,aAAa,KAAK,UAAU;AAElC,MAAK,YAAY,KAAK,aAAa,QAAQ,IAAI,2BAA2B;AAC1E,MAAK,WAAW,KAAK,YAAY,QAAQ,IAAI;AAC7C,MAAK,OAAO,KAAK,QAAQ,QAAQ,IAAI,sBAAsB;AAC3D,MAAK,cAAc,KAAK,eAAe,QAAQ,IAAI,8BAA8B;AAGjF,KAAI,CAAC,KAAK,SACR,MAAK,WAAW,eAAe,SAAS;AAG1C,KAAI,cAAc;AAChB,cAAY,YAAY,MAAM;AAC9B,MAAI,YAAY;AAEd,QAAK,YAAY;AACjB,QAAK,cAAc;SACd;AAEL,QAAK,YAAY;AACjB,QAAK,cAAc;;AAErB,MAAI,CAAC,CAAC,cAAc,OAAO,CAAC,SAAS,KAAK,SAAS,CACjD,SAAQ,MAAM,kEAAkE;YAI9E,KAAK,aAAa,OACpB,MAAK,cAAc;AAIvB,KAAI,KAAK,aAAa,CAAC,CAAC,SAAS,SAAS,CAAC,SAAS,KAAK,UAAU,CACjE,SAAQ,MAAM,yBAAyB,KAAK,UAAU,gCAAgC;AAExF,KAAI,CAAC;EAAC;EAAU;EAAc;EAAO;EAAO,CAAC,SAAS,KAAK,SAAS,CAClE,SAAQ,MAAM,wBAAwB,KAAK,SAAS,qDAAqD;AAE3G,KAAI,CAAC;EAAC;EAAU;EAAU;EAAQ,CAAC,SAAS,KAAK,YAAY,CAC3D,SAAQ,MAAM,4BAA4B,KAAK,YAAY,2CAA2C;CAGxG,MAAM,QAAQ,KAAK;CACnB,MAAM,YAAY,KAAK;AACvB,KAAI,CAAC,SAAS,CAAC,UACb,SAAQ,MAAM,qGAAqG;CAGrH,MAAM,SAAS,MAAM,QAAQ;EAC3B;EACA;EACA;EACA,QAAQ,KAAK;EACb,WAAW,KAAK;EAChB,aAAa,KAAK;EAClB,MAAM,KAAK;EACX,UAAU,KAAK;EACf,OAAO,aAAa,UAAW,KAAK,UAAU;EAC/C,CAAC;AAEF,KAAI,WAEF,SAAQ,OAAO,MACb,4EACG,OAAO,SAAS,kEAEpB;UACQ,KAAK,UAAU,KACxB,SAAQ,OAAO,MAAM,OAAO,SAAS;EAEvC;AAEJ,QAAQ,OAAO"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { LoggerLevel } from '@larksuiteoapi/node-sdk';\nimport { convert } from './converter.js';\nimport { setLogLevel } from './logger.js';\nimport type { SvgBackground, WbFormat, WbImageMode } from './types.js';\n\nconst program = new Command();\nprogram.name('larkDocx2md').description('Download Lark/Feishu documents to markdown');\n\nprogram\n .command('download')\n .alias('dl')\n .description('Download a wiki document to markdown')\n .option('--app-id <id>', 'Feishu app ID (or read from LARK_DOCX2MD_APP_ID)')\n .option('--app-secret <secret>', 'Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)')\n .option('-o, --output <dir>', 'Output directory (or LARK_DOCX2MD_OUTPUT)')\n .option('--agent [mode]', 'Enable agent mode: ERROR log level, and AI-oriented stdout. Pass \"local\" to save markdown/images/whiteboards to disk and print a read-file prompt (or LARK_DOCX2MD_AGENT=true|local)')\n .option('--wb-format <format>', 'Whiteboard output format: \"base64\", \"inline-svg\", \"svg\", or \"yaml\" (or LARK_DOCX2MD_WB_FORMAT)')\n .option('--wb-bg <style>', 'Whiteboard SVG background: \"none\", \"dot\", or a color like \"#fff\" (or LARK_DOCX2MD_WB_BG)')\n .option('--wb-image-mode <mode>', 'Whiteboard image mode: \"online\", \"base64\", or \"local\" (or LARK_DOCX2MD_WB_IMAGE_MODE)')\n .option('--image-mode <mode>', 'Image handling mode: \"local\" or \"online\" (or LARK_DOCX2MD_IMAGE_MODE)')\n .argument('<url>', 'Feishu wiki document URL: https://*.feishu.cn/wiki/*')\n .action(async (url: string, opts: { appId?: string; appSecret?: string; output?: string; agent?: boolean | string; imageMode?: string; wbImageMode?: string; wbBg?: SvgBackground; wbFormat?: string }) => {\n // ─── 环境变量默认值(直接指定 > 环境变量 > 内置默认值)────────────────\n opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;\n opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;\n opts.output = opts.output ?? process.env.LARK_DOCX2MD_OUTPUT ?? './larkDocx2mdOutput';\n // 解析 --agent:可能为 undefined | true | 'local' | 其他字符串\n if (opts.agent === undefined) {\n const envAgent = process.env.LARK_DOCX2MD_AGENT;\n if (envAgent === 'true') opts.agent = true;\n else if (envAgent === 'local') opts.agent = 'local';\n else opts.agent = false;\n } else if (typeof opts.agent === 'string' && opts.agent !== 'local') {\n program.error(`Invalid --agent value \"${opts.agent}\", only \"local\" is supported (or omit the value)`);\n }\n const agentEnabled = opts.agent === true || opts.agent === 'local';\n const agentLocal = opts.agent === 'local';\n\n opts.imageMode = opts.imageMode ?? process.env.LARK_DOCX2MD_IMAGE_MODE ?? 'local';\n opts.wbFormat = opts.wbFormat ?? process.env.LARK_DOCX2MD_WB_FORMAT;\n opts.wbBg = opts.wbBg ?? process.env.LARK_DOCX2MD_WB_BG ?? 'none';\n opts.wbImageMode = opts.wbImageMode ?? process.env.LARK_DOCX2MD_WB_IMAGE_MODE ?? 'local';\n\n // 设置 wb-format 默认值:--agent local 默认 inline-svg(兼容本地画板图片),--agent(在线)默认 yaml,其余 svg\n if (!opts.wbFormat) {\n opts.wbFormat = agentEnabled ? 'yaml' : 'svg';\n }\n\n if (agentEnabled) {\n setLogLevel(LoggerLevel.error);\n if (agentLocal) {\n // --agent local:图片/画板图片均落盘\n opts.imageMode = 'local';\n opts.wbImageMode = 'local';\n } else {\n // --agent(在线):一律在线,且画板仅支持内嵌形式\n opts.imageMode = 'online';\n opts.wbImageMode = 'online';\n }\n if (!['inline-svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Agent mode only supports \"inline-svg\" or \"yaml\" for --wb-format`);\n }\n } else {\n // yaml 格式图片仅支持 online\n if (opts.wbFormat === 'yaml') {\n opts.wbImageMode = 'online';\n }\n }\n\n if (opts.imageMode && !['local', 'online'].includes(opts.imageMode)) {\n program.error(`Invalid --image-mode \"${opts.imageMode}\", must be \"local\" or \"online\"`);\n }\n if (!['base64', 'inline-svg', 'svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Invalid --wb-format \"${opts.wbFormat}\", must be \"base64\", \"inline-svg\", \"svg\", or \"yaml\"`);\n }\n if (!['online', 'base64', 'local'].includes(opts.wbImageMode)) {\n program.error(`Invalid --wb-image-mode \"${opts.wbImageMode}\", must be \"online\", \"base64\", or \"local\"`);\n }\n\n const appId = opts.appId!;\n const appSecret = opts.appSecret!;\n if (!appId || !appSecret) {\n program.error('Missing credentials: pass --app-id/--app-secret or set LARK_DOCX2MD_APP_ID/LARK_DOCX2MD_APP_SECRET');\n }\n\n const result = await convert({\n appId,\n appSecret,\n url,\n output: opts.output,\n imageMode: opts.imageMode as 'local' | 'online',\n wbImageMode: opts.wbImageMode as WbImageMode,\n wbBg: opts.wbBg,\n wbFormat: opts.wbFormat as WbFormat,\n agent: agentLocal ? 'local' : (opts.agent === true),\n });\n\n if (agentLocal) {\n // 本地模式:输出引导 AI 读取文件的提示词(绝对路径)\n process.stdout.write(\n `**The Feishu document has been downloaded to the following absolute path:**\\n\\n` +\n `\\`${result.filePath}\\`\\n\\n` +\n `**Read this file to access the full markdown content.**\\n`,\n );\n } else if (opts.agent === true) {\n process.stdout.write(result.markdown);\n }\n });\n\nprogram.parse();\n"],"mappings":";;;;;AAOA,MAAM,UAAU,IAAI,SAAS;AAC7B,QAAQ,KAAK,cAAc,CAAC,YAAY,6CAA6C;AAErF,QACG,QAAQ,WAAW,CACnB,MAAM,KAAK,CACX,YAAY,uCAAuC,CACnD,OAAO,iBAAiB,mDAAmD,CAC3E,OAAO,yBAAyB,2DAA2D,CAC3F,OAAO,sBAAsB,4CAA4C,CACzE,OAAO,kBAAkB,yLAAuL,CAChN,OAAO,wBAAwB,yGAAiG,CAChI,OAAO,mBAAmB,iGAA2F,CACrH,OAAO,0BAA0B,8FAAwF,CACzH,OAAO,uBAAuB,4EAAwE,CACtG,SAAS,SAAS,uDAAuD,CACzE,OAAO,OAAO,KAAa,SAA+K;AAEzM,MAAK,QAAQ,KAAK,SAAS,QAAQ,IAAI;AACvC,MAAK,YAAY,KAAK,aAAa,QAAQ,IAAI;AAC/C,MAAK,SAAS,KAAK,UAAU,QAAQ,IAAI,uBAAuB;AAEhE,KAAI,KAAK,UAAU,KAAA,GAAW;EAC5B,MAAM,WAAW,QAAQ,IAAI;AAC7B,MAAI,aAAa,OAAQ,MAAK,QAAQ;WAC7B,aAAa,QAAS,MAAK,QAAQ;MACvC,MAAK,QAAQ;YACT,OAAO,KAAK,UAAU,YAAY,KAAK,UAAU,QAC1D,SAAQ,MAAM,0BAA0B,KAAK,MAAM,kDAAkD;CAEvG,MAAM,eAAe,KAAK,UAAU,QAAQ,KAAK,UAAU;CAC3D,MAAM,aAAa,KAAK,UAAU;AAElC,MAAK,YAAY,KAAK,aAAa,QAAQ,IAAI,2BAA2B;AAC1E,MAAK,WAAW,KAAK,YAAY,QAAQ,IAAI;AAC7C,MAAK,OAAO,KAAK,QAAQ,QAAQ,IAAI,sBAAsB;AAC3D,MAAK,cAAc,KAAK,eAAe,QAAQ,IAAI,8BAA8B;AAGjF,KAAI,CAAC,KAAK,SACR,MAAK,WAAW,eAAe,SAAS;AAG1C,KAAI,cAAc;AAChB,cAAY,YAAY,MAAM;AAC9B,MAAI,YAAY;AAEd,QAAK,YAAY;AACjB,QAAK,cAAc;SACd;AAEL,QAAK,YAAY;AACjB,QAAK,cAAc;;AAErB,MAAI,CAAC,CAAC,cAAc,OAAO,CAAC,SAAS,KAAK,SAAS,CACjD,SAAQ,MAAM,kEAAkE;YAI9E,KAAK,aAAa,OACpB,MAAK,cAAc;AAIvB,KAAI,KAAK,aAAa,CAAC,CAAC,SAAS,SAAS,CAAC,SAAS,KAAK,UAAU,CACjE,SAAQ,MAAM,yBAAyB,KAAK,UAAU,gCAAgC;AAExF,KAAI,CAAC;EAAC;EAAU;EAAc;EAAO;EAAO,CAAC,SAAS,KAAK,SAAS,CAClE,SAAQ,MAAM,wBAAwB,KAAK,SAAS,qDAAqD;AAE3G,KAAI,CAAC;EAAC;EAAU;EAAU;EAAQ,CAAC,SAAS,KAAK,YAAY,CAC3D,SAAQ,MAAM,4BAA4B,KAAK,YAAY,2CAA2C;CAGxG,MAAM,QAAQ,KAAK;CACnB,MAAM,YAAY,KAAK;AACvB,KAAI,CAAC,SAAS,CAAC,UACb,SAAQ,MAAM,qGAAqG;CAGrH,MAAM,SAAS,MAAM,QAAQ;EAC3B;EACA;EACA;EACA,QAAQ,KAAK;EACb,WAAW,KAAK;EAChB,aAAa,KAAK;EAClB,MAAM,KAAK;EACX,UAAU,KAAK;EACf,OAAO,aAAa,UAAW,KAAK,UAAU;EAC/C,CAAC;AAEF,KAAI,WAEF,SAAQ,OAAO,MACb,oFACK,OAAO,SAAS,iEAEtB;UACQ,KAAK,UAAU,KACxB,SAAQ,OAAO,MAAM,OAAO,SAAS;EAEvC;AAEJ,QAAQ,OAAO"}
@@ -28,10 +28,11 @@ interface ConvertResult {
28
28
  declare function parseWikiUrl(url: string): {
29
29
  docType: string;
30
30
  docToken: string;
31
+ sheetId?: string;
31
32
  };
32
33
  declare function convert(opts: ConvertOptions): Promise<ConvertResult>;
33
34
  //# sourceMappingURL=converter.d.ts.map
34
35
 
35
36
  //#endregion
36
37
  export { convert, parseWikiUrl };
37
- //# sourceMappingURL=converter-Bxdyw2k9.d.ts.map
38
+ //# sourceMappingURL=converter-C_2JDVY1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converter-C_2JDVY1.d.ts","names":[],"sources":["../src/types.ts","../src/converter.ts"],"mappings":";;;;AAsCa,KAhBD,SAAA,GAgBC,OAAA,GAAA,QAAA;AACE,KAdH,WAAA,GAcG,QAAA,GAAA,QAAA,GAAA,OAAA;AACP,KAZI,QAAA,GAYJ,QAAA,GAAA,YAAA,GAAA,KAAA,GAAA,MAAA;AACI,KAVA,aAAA,GAUA,MAAA,GAAA,KAAA,GAAA,CAAA,MAAA,GAAA,CAAA,CAAA,CAAA;AAAQ,UARH,cAAA,CAQG;EASH,KAAA,EAAA,MAAA;;;;ECnCD,SAAA,EDuBH,SCvBe;EAUN,WAAO,EDcd,WCdc;EAAA,IAAA,EDerB,aCfqB;UAAQ,EDgBzB,QChByB;OAAyB,CAAA,EAAA,OAAA,GAAA,OAAA;;AAAD,UDyB5C,aAAA,CCzB4C;;;;;;;;iBAV7C,YAAA;;EDOJ,QAAA,EAAA,MAAS;EAGT,OAAA,CAAA,EAAA,MAAW;AAGvB,CAAA;AAGY,iBCNU,OAAA,CDMG,IAAA,ECNY,cDMZ,CAAA,ECN6B,ODM7B,CCNqC,aDMrC,CAAA;AAEzB"}
@@ -644,8 +644,9 @@ var MdSerializer = class {
644
644
  register(serializer) {
645
645
  this.registry.register(serializer.type, serializer);
646
646
  }
647
- serialize(root) {
647
+ serialize(root, options = {}) {
648
648
  const ctx = {
649
+ sourceType: options.sourceType ?? "docx",
649
650
  serialize: (node, indent = 0) => {
650
651
  const serializer = this.registry.get(node.type);
651
652
  if (serializer) return serializer.serialize(node, ctx);
@@ -831,11 +832,11 @@ const htmlSerializer = {
831
832
  };
832
833
  const sheetResolvedSerializer = {
833
834
  type: "sheetResolved",
834
- serialize(node) {
835
+ serialize(node, ctx) {
835
836
  if (node.type !== "sheetResolved") return "";
836
837
  let out = "";
837
838
  for (const s of node.sheets) {
838
- if (node.showTitle) out += `## ${node.title}-${s.title}\n\n`;
839
+ if (ctx.sourceType === "sheet") out += `## ${node.title}-${s.title}\n\n`;
839
840
  if (s.error) {
840
841
  out += `> ${s.error}\n\n`;
841
842
  continue;
@@ -2823,7 +2824,7 @@ var MdTransformer = class {
2823
2824
  try {
2824
2825
  const info = await this.client.getSpreadsheetInfo(spreadsheetToken);
2825
2826
  const list = await this.client.listSheets(spreadsheetToken);
2826
- const sheetsToProcess = this.sourceType === "sheet" ? list : list.filter((s) => s.sheet_id === sheetId);
2827
+ const sheetsToProcess = this.sourceType === "sheet" && !sheetId ? list : list.filter((s) => s.sheet_id === sheetId);
2827
2828
  const resolved = [];
2828
2829
  for (const s of sheetsToProcess) {
2829
2830
  if (s.hidden) continue;
@@ -2868,16 +2869,14 @@ var MdTransformer = class {
2868
2869
  map.set(raw, {
2869
2870
  type: "sheetResolved",
2870
2871
  title: info.title ?? "",
2871
- sheets: resolved,
2872
- showTitle: this.sourceType === "sheet"
2872
+ sheets: resolved
2873
2873
  });
2874
2874
  } catch (e) {
2875
2875
  logger$1.warn(`Failed to resolve sheet ${raw}:`, e.message);
2876
2876
  map.set(raw, {
2877
2877
  type: "sheetResolved",
2878
2878
  title: "",
2879
- sheets: [],
2880
- showTitle: false
2879
+ sheets: []
2881
2880
  });
2882
2881
  }
2883
2882
  }
@@ -2960,14 +2959,16 @@ const logger = createLogger("converter");
2960
2959
  function parseWikiUrl(url) {
2961
2960
  const m = url.match(/^https:\/\/[\w.-]+\/(docs|docx|wiki|sheets)\/([a-zA-Z0-9]+)/);
2962
2961
  if (!m) throw new Error("Invalid feishu document URL");
2962
+ const sheetId = new URL(url).searchParams.get("sheet") ?? void 0;
2963
2963
  return {
2964
2964
  docType: m[1],
2965
- docToken: m[2]
2965
+ docToken: m[2],
2966
+ sheetId
2966
2967
  };
2967
2968
  }
2968
2969
  async function convert(opts) {
2969
- const { docType, docToken: rawToken } = parseWikiUrl(opts.url);
2970
- logger.info("Captured document token:", rawToken);
2970
+ const { docType, docToken: rawToken, sheetId } = parseWikiUrl(opts.url);
2971
+ logger.info("Captured document token:", rawToken, sheetId ? `sheetId: ${sheetId}` : "");
2971
2972
  const sdkLoggerLevel = opts.agent ? LoggerLevel.error : LoggerLevel.warn;
2972
2973
  const client = createClient(opts.appId, opts.appSecret, sdkLoggerLevel);
2973
2974
  let docToken = rawToken;
@@ -2979,18 +2980,21 @@ async function convert(opts) {
2979
2980
  logger.info("Resolved wiki node:", objType, docToken);
2980
2981
  } else if (docType === "sheets") objType = "sheet";
2981
2982
  let ast;
2982
- if (objType === "sheet") ast = {
2983
- type: "page",
2984
- title: [{
2985
- type: "text",
2986
- content: (await client.getSpreadsheetInfo(docToken)).title ?? ""
2987
- }],
2988
- children: [{
2989
- type: "sheet",
2990
- token: docToken
2991
- }]
2992
- };
2993
- else {
2983
+ if (objType === "sheet") {
2984
+ const info = await client.getSpreadsheetInfo(docToken);
2985
+ const sheetToken = sheetId ? `${docToken}_${sheetId}` : docToken;
2986
+ ast = {
2987
+ type: "page",
2988
+ title: [{
2989
+ type: "text",
2990
+ content: info.title ?? ""
2991
+ }],
2992
+ children: [{
2993
+ type: "sheet",
2994
+ token: sheetToken
2995
+ }]
2996
+ };
2997
+ } else {
2994
2998
  const doc = await client.getDocxDocument(docToken);
2995
2999
  const blocks = await client.getDocxBlocks(docToken);
2996
3000
  logger.info(`Fetched ${blocks.length} blocks`);
@@ -3001,7 +3005,7 @@ async function convert(opts) {
3001
3005
  await new MdTransformer(client, opts, objType === "sheet" ? "sheet" : "docx").transform(ast);
3002
3006
  const serializer = new MdSerializer();
3003
3007
  registerBuiltinSerializers(serializer);
3004
- const markdown = serializer.serialize(ast);
3008
+ const markdown = serializer.serialize(ast, { sourceType: objType === "sheet" ? "sheet" : "docx" });
3005
3009
  let filePath;
3006
3010
  if (!opts.agent || opts.agent === "local") {
3007
3011
  fs.mkdirSync(opts.output, { recursive: true });
@@ -3018,4 +3022,4 @@ async function convert(opts) {
3018
3022
  //#endregion
3019
3023
  export { parseWikiUrl as n, setLogLevel as r, convert as t };
3020
3024
 
3021
- //# sourceMappingURL=converter-C5Nrkvfa.js.map
3025
+ //# sourceMappingURL=converter-jW2Zu4Pb.js.map