@nhtio/adk 0.1.0-master-e6c58205 → 0.1.0-master-89b47bec
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/CHANGELOG.md +94 -0
- package/__vite-browser-external-CU7uua8b.mjs +9 -0
- package/__vite-browser-external-CU7uua8b.mjs.map +1 -0
- package/__vite-browser-external-DAHxjh-D.js +13 -0
- package/__vite-browser-external-DAHxjh-D.js.map +1 -0
- package/batteries/embeddings/openai/adapter.cjs +1 -1
- package/batteries/embeddings/openai/adapter.mjs +1 -1
- package/batteries/embeddings/webllm/adapter.cjs +1 -1
- package/batteries/embeddings/webllm/adapter.mjs +1 -1
- package/batteries/llm/ollama/adapter.cjs +5 -5
- package/batteries/llm/ollama/adapter.mjs +5 -5
- package/batteries/llm/ollama/helpers.cjs +2 -2
- package/batteries/llm/ollama/helpers.mjs +2 -2
- package/batteries/llm/ollama/validation.cjs +1 -1
- package/batteries/llm/ollama/validation.mjs +1 -1
- package/batteries/llm/openai_chat_completions/adapter.cjs +5 -5
- package/batteries/llm/openai_chat_completions/adapter.mjs +5 -5
- package/batteries/llm/openai_chat_completions/helpers.cjs +2 -2
- package/batteries/llm/openai_chat_completions/helpers.mjs +2 -2
- package/batteries/llm/openai_chat_completions/validation.cjs +1 -1
- package/batteries/llm/openai_chat_completions/validation.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +5 -5
- package/batteries/llm/webllm_chat_completions/adapter.mjs +5 -5
- package/batteries/llm/webllm_chat_completions/validation.cjs +1 -1
- package/batteries/llm/webllm_chat_completions/validation.mjs +1 -1
- package/batteries/media/contracts.cjs +38 -8
- package/batteries/media/contracts.cjs.map +1 -1
- package/batteries/media/contracts.d.ts +86 -6
- package/batteries/media/contracts.mjs +37 -9
- package/batteries/media/contracts.mjs.map +1 -1
- package/batteries/media/engines/audio_decode.cjs +46 -6
- package/batteries/media/engines/audio_decode.cjs.map +1 -1
- package/batteries/media/engines/audio_decode.d.ts +9 -5
- package/batteries/media/engines/audio_decode.mjs +47 -7
- package/batteries/media/engines/audio_decode.mjs.map +1 -1
- package/batteries/media/engines/data.cjs +159 -0
- package/batteries/media/engines/data.cjs.map +1 -0
- package/batteries/media/engines/data.d.ts +36 -0
- package/batteries/media/engines/data.mjs +157 -0
- package/batteries/media/engines/data.mjs.map +1 -0
- package/batteries/media/engines/exceljs.cjs +290 -0
- package/batteries/media/engines/exceljs.cjs.map +1 -0
- package/batteries/media/engines/exceljs.d.ts +41 -0
- package/batteries/media/engines/exceljs.mjs +288 -0
- package/batteries/media/engines/exceljs.mjs.map +1 -0
- package/batteries/media/engines/execa_executor.cjs +1 -1
- package/batteries/media/engines/execa_executor.mjs +1 -1
- package/batteries/media/engines/fs_workspace.cjs +1 -1
- package/batteries/media/engines/fs_workspace.mjs +1 -1
- package/batteries/media/engines/jimp.cjs +24 -2
- package/batteries/media/engines/jimp.cjs.map +1 -1
- package/batteries/media/engines/jimp.d.ts +3 -1
- package/batteries/media/engines/jimp.mjs +24 -2
- package/batteries/media/engines/jimp.mjs.map +1 -1
- package/batteries/media/engines/sharp.cjs +37 -4
- package/batteries/media/engines/sharp.cjs.map +1 -1
- package/batteries/media/engines/sharp.d.ts +5 -3
- package/batteries/media/engines/sharp.mjs +37 -4
- package/batteries/media/engines/sharp.mjs.map +1 -1
- package/batteries/media/engines/sheetjs.cjs +438 -0
- package/batteries/media/engines/sheetjs.cjs.map +1 -0
- package/batteries/media/engines/sheetjs.d.ts +51 -0
- package/batteries/media/engines/sheetjs.mjs +436 -0
- package/batteries/media/engines/sheetjs.mjs.map +1 -0
- package/batteries/media/engines/soffice.cjs +37 -3
- package/batteries/media/engines/soffice.cjs.map +1 -1
- package/batteries/media/engines/soffice.mjs +38 -4
- package/batteries/media/engines/soffice.mjs.map +1 -1
- package/batteries/media/engines/tesseract_js.cjs +1 -1
- package/batteries/media/engines/tesseract_js.mjs +1 -1
- package/batteries/media/engines/transformers_asr.cjs +1 -1
- package/batteries/media/engines/transformers_asr.mjs +1 -1
- package/batteries/media/forge.cjs +89 -20
- package/batteries/media/forge.cjs.map +1 -1
- package/batteries/media/forge.mjs +89 -20
- package/batteries/media/forge.mjs.map +1 -1
- package/batteries/media/formats.d.ts +9 -0
- package/batteries/media/index.d.ts +8 -6
- package/batteries/media/lint.cjs +270 -58
- package/batteries/media/lint.cjs.map +1 -1
- package/batteries/media/lint.d.ts +45 -0
- package/batteries/media/lint.mjs +267 -58
- package/batteries/media/lint.mjs.map +1 -1
- package/batteries/media/registry.d.ts +11 -2
- package/batteries/media/steps/data.d.ts +26 -0
- package/batteries/media/steps/doc.d.ts +17 -7
- package/batteries/media/steps/patch.d.ts +90 -0
- package/batteries/media/steps/sheet.d.ts +10 -6
- package/batteries/media/steps/text.d.ts +4 -1
- package/batteries/media/validate.d.ts +5 -0
- package/batteries/media/verbs.d.ts +12 -1
- package/batteries/media.cjs +869 -448
- package/batteries/media.cjs.map +1 -1
- package/batteries/media.mjs +829 -409
- package/batteries/media.mjs.map +1 -1
- package/batteries/storage/flydrive.cjs +3 -6
- package/batteries/storage/flydrive.cjs.map +1 -1
- package/batteries/storage/flydrive.mjs +3 -6
- package/batteries/storage/flydrive.mjs.map +1 -1
- package/batteries/storage/in_memory.cjs +1 -1
- package/batteries/storage/in_memory.mjs +1 -1
- package/batteries/storage/opfs.cjs +1 -1
- package/batteries/storage/opfs.mjs +1 -1
- package/batteries/tools/_shared.cjs +2 -2
- package/batteries/tools/_shared.mjs +2 -2
- package/batteries/tools/color.cjs +2 -2
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +3 -3
- package/batteries/tools/comparison.mjs +3 -3
- package/batteries/tools/data_structure.cjs +3 -3
- package/batteries/tools/data_structure.mjs +3 -3
- package/batteries/tools/datetime_extended.cjs +3 -3
- package/batteries/tools/datetime_extended.mjs +3 -3
- package/batteries/tools/datetime_math.cjs +3 -3
- package/batteries/tools/datetime_math.mjs +3 -3
- package/batteries/tools/encoding.cjs +3 -3
- package/batteries/tools/encoding.mjs +3 -3
- package/batteries/tools/formatting.cjs +3 -3
- package/batteries/tools/formatting.mjs +3 -3
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math.cjs +3 -3
- package/batteries/tools/math.mjs +3 -3
- package/batteries/tools/memory.cjs +6 -6
- package/batteries/tools/memory.mjs +6 -6
- package/batteries/tools/parsing.cjs +4 -4
- package/batteries/tools/parsing.mjs +4 -4
- package/batteries/tools/retrievables.cjs +5 -5
- package/batteries/tools/retrievables.mjs +5 -5
- package/batteries/tools/scrapper.cjs +1 -1
- package/batteries/tools/scrapper.mjs +1 -1
- package/batteries/tools/searxng.cjs +1 -1
- package/batteries/tools/searxng.mjs +1 -1
- package/batteries/tools/standing_instructions.cjs +4 -4
- package/batteries/tools/standing_instructions.mjs +4 -4
- package/batteries/tools/statistics.cjs +4 -4
- package/batteries/tools/statistics.mjs +4 -4
- package/batteries/tools/string_processing.cjs +3 -3
- package/batteries/tools/string_processing.mjs +3 -3
- package/batteries/tools/structured_data.cjs +3 -3
- package/batteries/tools/structured_data.mjs +3 -3
- package/batteries/tools/text_analysis.cjs +3 -3
- package/batteries/tools/text_analysis.mjs +3 -3
- package/batteries/tools/text_comparison.cjs +2 -2
- package/batteries/tools/text_comparison.mjs +2 -2
- package/batteries/tools/time.cjs +3 -3
- package/batteries/tools/time.mjs +3 -3
- package/batteries/tools/unit_conversion.cjs +2 -2
- package/batteries/tools/unit_conversion.mjs +2 -2
- package/batteries/tools/web_retrieval.cjs +1 -1
- package/batteries/tools/web_retrieval.mjs +1 -1
- package/batteries/tools.cjs +2 -2
- package/batteries/tools.mjs +2 -2
- package/batteries/vector/arangodb.cjs +1 -1
- package/batteries/vector/arangodb.mjs +1 -1
- package/batteries/vector/clickhouse.cjs +1 -1
- package/batteries/vector/clickhouse.mjs +1 -1
- package/batteries/vector/cloudflare.cjs +1 -1
- package/batteries/vector/cloudflare.mjs +1 -1
- package/batteries/vector/couchbase.cjs +1 -1
- package/batteries/vector/couchbase.mjs +1 -1
- package/batteries/vector/duckdb.cjs +1 -1
- package/batteries/vector/duckdb.mjs +1 -1
- package/batteries/vector/elasticsearch.cjs +1 -1
- package/batteries/vector/elasticsearch.mjs +1 -1
- package/batteries/vector/filters.cjs +1 -1
- package/batteries/vector/filters.mjs +1 -1
- package/batteries/vector/hnswlib.cjs +1 -1
- package/batteries/vector/hnswlib.mjs +1 -1
- package/batteries/vector/lancedb.cjs +1 -1
- package/batteries/vector/lancedb.mjs +1 -1
- package/batteries/vector/mariadb.cjs +1 -1
- package/batteries/vector/mariadb.mjs +1 -1
- package/batteries/vector/meilisearch.cjs +1 -1
- package/batteries/vector/meilisearch.mjs +1 -1
- package/batteries/vector/migrate.cjs +1 -1
- package/batteries/vector/migrate.mjs +1 -1
- package/batteries/vector/mongodb.cjs +1 -1
- package/batteries/vector/mongodb.mjs +1 -1
- package/batteries/vector/neo4j.cjs +1 -1
- package/batteries/vector/neo4j.mjs +1 -1
- package/batteries/vector/opensearch.cjs +1 -1
- package/batteries/vector/opensearch.mjs +1 -1
- package/batteries/vector/oracle23ai.cjs +1 -1
- package/batteries/vector/oracle23ai.mjs +1 -1
- package/batteries/vector/pinecone.cjs +1 -1
- package/batteries/vector/pinecone.mjs +1 -1
- package/batteries/vector/redis.cjs +1 -1
- package/batteries/vector/redis.mjs +1 -1
- package/batteries/vector/retrievable.cjs +1 -1
- package/batteries/vector/retrievable.mjs +1 -1
- package/batteries/vector/s3vectors.cjs +1 -1
- package/batteries/vector/s3vectors.mjs +1 -1
- package/batteries/vector/solr.cjs +1 -1
- package/batteries/vector/solr.mjs +1 -1
- package/batteries/vector/surrealdb.cjs +1 -1
- package/batteries/vector/surrealdb.mjs +1 -1
- package/batteries/vector/typesense.cjs +1 -1
- package/batteries/vector/typesense.mjs +1 -1
- package/batteries/vector/vespa.cjs +1 -1
- package/batteries/vector/vespa.mjs +1 -1
- package/batteries/vector/weaviate.cjs +1 -1
- package/batteries/vector/weaviate.mjs +1 -1
- package/batteries.cjs +2 -2
- package/batteries.mjs +2 -2
- package/bundled_xlsx.d.ts +1075 -0
- package/{common-BxoznqbX.mjs → common-BQoFv108.mjs} +7 -7
- package/{common-BxoznqbX.mjs.map → common-BQoFv108.mjs.map} +1 -1
- package/{common-BBK2e5ro.js → common-DmDn4Gfl.js} +7 -7
- package/{common-BBK2e5ro.js.map → common-DmDn4Gfl.js.map} +1 -1
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-Hn5idJYx.js → dispatch_runner-BwplbCPr.js} +3 -3
- package/{dispatch_runner-Hn5idJYx.js.map → dispatch_runner-BwplbCPr.js.map} +1 -1
- package/{dispatch_runner-DUrpj0xR.mjs → dispatch_runner-C1ar_D7W.mjs} +3 -3
- package/{dispatch_runner-DUrpj0xR.mjs.map → dispatch_runner-C1ar_D7W.mjs.map} +1 -1
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.mjs +1 -1
- package/eslint.cjs +1 -1
- package/eslint.mjs +1 -1
- package/forge.cjs +4 -4
- package/forge.mjs +4 -4
- package/formats-CCylUHZw.mjs +161 -0
- package/formats-CCylUHZw.mjs.map +1 -0
- package/formats-DZVuqZUN.js +196 -0
- package/formats-DZVuqZUN.js.map +1 -0
- package/guards.cjs +8 -8
- package/guards.mjs +8 -8
- package/index.cjs +11 -11
- package/index.mjs +11 -11
- package/mcp/adk-docs-corpus.json +1 -1
- package/package.json +198 -182
- package/{scrapper-DLj_KkxK.mjs → scrapper-Dn2wXu0Y.mjs} +5 -5
- package/{scrapper-DLj_KkxK.mjs.map → scrapper-Dn2wXu0Y.mjs.map} +1 -1
- package/{scrapper-Cmf1CSA-.js → scrapper-mBZ0Odq7.js} +5 -5
- package/{scrapper-Cmf1CSA-.js.map → scrapper-mBZ0Odq7.js.map} +1 -1
- package/{searxng-BKs5s8Su.js → searxng-Dj-iP_Vz.js} +5 -5
- package/{searxng-BKs5s8Su.js.map → searxng-Dj-iP_Vz.js.map} +1 -1
- package/{searxng-BJ-aZcMz.mjs → searxng-DjFxtFf6.mjs} +5 -5
- package/{searxng-BJ-aZcMz.mjs.map → searxng-DjFxtFf6.mjs.map} +1 -1
- package/server.json +21 -0
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-BR0IhU9y.js → spooled_artifact-BCmPrxZS.js} +3 -3
- package/{spooled_artifact-BR0IhU9y.js.map → spooled_artifact-BCmPrxZS.js.map} +1 -1
- package/{spooled_artifact-nTE6ujM8.mjs → spooled_artifact-DL36jnqA.mjs} +3 -3
- package/{spooled_artifact-nTE6ujM8.mjs.map → spooled_artifact-DL36jnqA.mjs.map} +1 -1
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-Dj3fNowz.js → spooled_markdown_artifact-CD4PrrpV.js} +3 -3
- package/{spooled_markdown_artifact-Dj3fNowz.js.map → spooled_markdown_artifact-CD4PrrpV.js.map} +1 -1
- package/{spooled_markdown_artifact-DIYzbQv8.mjs → spooled_markdown_artifact-Da-Xnebh.mjs} +3 -3
- package/{spooled_markdown_artifact-DIYzbQv8.mjs.map → spooled_markdown_artifact-Da-Xnebh.mjs.map} +1 -1
- package/{thought-Cde2Y_GK.mjs → thought-CtOoZUSE.mjs} +3 -3
- package/{thought-Cde2Y_GK.mjs.map → thought-CtOoZUSE.mjs.map} +1 -1
- package/{thought-BFtsnUTU.js → thought-eka4iUHa.js} +3 -3
- package/{thought-BFtsnUTU.js.map → thought-eka4iUHa.js.map} +1 -1
- package/{tool-CcxYxA5X.mjs → tool-CITF20yJ.mjs} +3 -3
- package/{tool-CcxYxA5X.mjs.map → tool-CITF20yJ.mjs.map} +1 -1
- package/{tool-B2nnkwNU.js → tool-Dhjca7rC.js} +3 -3
- package/{tool-B2nnkwNU.js.map → tool-Dhjca7rC.js.map} +1 -1
- package/{tool_call-BxL3eU1k.js → tool_call-Cyi0hUUc.js} +4 -4
- package/{tool_call-BxL3eU1k.js.map → tool_call-Cyi0hUUc.js.map} +1 -1
- package/{tool_call-B3MOog2R.mjs → tool_call-D_k36aI4.mjs} +4 -4
- package/{tool_call-B3MOog2R.mjs.map → tool_call-D_k36aI4.mjs.map} +1 -1
- package/{tool_registry-BaLUIzWz.mjs → tool_registry-CZ55mIti.mjs} +152 -143
- package/tool_registry-CZ55mIti.mjs.map +1 -0
- package/{tool_registry-BdKlPuHS.js → tool_registry-DwZ6pzN4.js} +151 -142
- package/tool_registry-DwZ6pzN4.js.map +1 -0
- package/{turn_runner-M2I8G2ok.js → turn_runner-CCZcsoDU.js} +5 -5
- package/{turn_runner-M2I8G2ok.js.map → turn_runner-CCZcsoDU.js.map} +1 -1
- package/{turn_runner-BV4BaZK9.mjs → turn_runner-DRPpVvsd.mjs} +5 -5
- package/{turn_runner-BV4BaZK9.mjs.map → turn_runner-DRPpVvsd.mjs.map} +1 -1
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/{validate-JOHfh-BB.mjs → validate-C_hTnDBE.mjs} +95 -8
- package/validate-C_hTnDBE.mjs.map +1 -0
- package/{validate-DgDZkUKs.js → validate-gaSa9bsk.js} +95 -8
- package/validate-gaSa9bsk.js.map +1 -0
- package/xlsx-B0sTpEC2.js +30615 -0
- package/xlsx-B0sTpEC2.js.map +1 -0
- package/xlsx-DiMpn_Xv.mjs +30596 -0
- package/xlsx-DiMpn_Xv.mjs.map +1 -0
- package/xlsx.zahl-D2_Q-Xs4.mjs +6 -0
- package/xlsx.zahl-D2_Q-Xs4.mjs.map +1 -0
- package/xlsx.zahl-ZIcUQVv8.js +7 -0
- package/xlsx.zahl-ZIcUQVv8.js.map +1 -0
- package/tool_registry-BaLUIzWz.mjs.map +0 -1
- package/tool_registry-BdKlPuHS.js.map +0 -1
- package/validate-DgDZkUKs.js.map +0 -1
- package/validate-JOHfh-BB.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceljs.cjs","names":[],"sources":["../../../../src/batteries/media/engines/exceljs.ts"],"sourcesContent":["/**\n * The ExcelJS-backed workbook {@link @nhtio/adk/batteries/media/contracts!MediaEngine}: the\n * fidelity-preserving structural editor for xlsx, plus in-process blank-workbook generation.\n *\n * @module @nhtio/adk/batteries/media/engines/exceljs\n *\n * @remarks\n * ExcelJS models the parts of a workbook that matter to humans — fonts, fills, comments,\n * merged ranges, data validations — and carries them through a read→edit→write cycle intact.\n * That is this engine's whole reason to exist: the `sheet.*` verbs mutate workbooks users\n * hand us, and an edit that strips the user's formatting as a side effect is corruption with\n * good intentions. Compose this engine FIRST in the engines array when fidelity matters; the\n * sheetjs engine edits a far wider read matrix (ODS, XLS, NUMBERS, …) but SheetJS Community\n * Edition strips styling in the process.\n *\n * Capabilities:\n *\n * - **generate**: `EMPTY_MIME` → xlsx (a blank workbook with one `Sheet1` — every sheet step\n * expects at least one worksheet).\n * - **edit**: the ten `sheet.*` structural ops over xlsx, styling preserved.\n *\n * `exceljs` is an optional peer dependency, lazily imported on first actual use. Cross-env by\n * construction: no `node:*` imports, `Uint8Array` in and out (ExcelJS ships a browser build\n * via its `browser` field).\n */\n\nimport { MIME } from '../formats'\nimport { EMPTY_MIME } from '../contracts'\nimport { isError } from '@nhtio/adk/guards'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type { default as ExcelJSNS } from 'exceljs'\nimport type {\n MediaEngine,\n ConvertRequest,\n ConvertResult,\n EditRequest,\n EditResult,\n EditSummary,\n} from '../contracts'\n\ntype ExcelJSModule = typeof ExcelJSNS\n\n/** Options for {@link exceljsEngine}. */\nexport interface ExceljsEngineOptions {\n /** Override the module resolution (tests / custom builds). Default: `import('exceljs')`. */\n exceljs?: () => ExcelJSModule | Promise<ExcelJSModule>\n}\n\n/** The structural ops this engine edits (same names the verb table uses). */\nconst SHEET_OPS: readonly string[] = [\n 'sheet.add_rows',\n 'sheet.add_columns',\n 'sheet.update_cells',\n 'sheet.delete_rows',\n 'sheet.delete_columns',\n 'sheet.rename_sheet',\n 'sheet.add_sheet',\n 'sheet.remove_sheet',\n 'sheet.reorder_sheets',\n 'sheet.transform_table',\n]\n\n/**\n * Construct the ExcelJS-backed workbook engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const exceljsEngine = (options: ExceljsEngineOptions = {}): MediaEngine => {\n let modPromise: Promise<ExcelJSModule> | undefined\n const getExcel = (): Promise<ExcelJSModule> => {\n modPromise ??= Promise.resolve(\n options.exceljs\n ? options.exceljs()\n : import('exceljs').then((m) => ('default' in m ? m.default : m) as ExcelJSModule)\n ).catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the exceljs engine could not load its peer dependency \"exceljs\": ${detail} — install it (pnpm add exceljs)`,\n ])\n })\n return modPromise\n }\n\n const convert = async (request: ConvertRequest): Promise<ConvertResult> => {\n if (request.to !== 'xlsx') {\n throw new Error(`exceljs generates \"xlsx\" only; requested \"${request.to}\"`)\n }\n const ExcelJS = await getExcel()\n const wb = new ExcelJS.Workbook()\n wb.addWorksheet('Sheet1')\n const bytes = new Uint8Array(await wb.xlsx.writeBuffer())\n return { outputs: [{ bytes, mimeType: MIME.XLSX }] }\n }\n\n const edit = async (request: EditRequest): Promise<EditResult> => {\n const ExcelJS = await getExcel()\n const wb = new ExcelJS.Workbook()\n try {\n await wb.xlsx.load(\n request.bytes.buffer.slice(\n request.bytes.byteOffset,\n request.bytes.byteOffset + request.bytes.byteLength\n ) as ArrayBuffer\n )\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new Error(`could not open the spreadsheet: ${detail}`)\n }\n const summary = applyEdit(wb, request.op, request.args)\n const bytes = new Uint8Array(await wb.xlsx.writeBuffer())\n return { bytes, mimeType: MIME.XLSX, summary }\n }\n\n return {\n id: 'exceljs',\n converts: [{ from: [EMPTY_MIME], to: ['xlsx'], convert }],\n edits: [{ over: [MIME.XLSX], ops: SHEET_OPS, edit }],\n }\n}\n\n// ── op implementations (moved from steps/sheet.ts; styling-preserving by library) ───────────\n\n/** Resolve the target worksheet from the frozen `sheet=` rule (bare number=index, string=name). */\nconst resolveSheet = (wb: ExcelJSNS.Workbook, sheetArg: unknown): ExcelJSNS.Worksheet => {\n if (sheetArg === undefined || sheetArg === null) {\n const first = wb.worksheets[0]\n if (!first) throw new Error('the workbook has no worksheets')\n return first\n }\n // Frozen 0.11: bare number targets by 1-based index; quoted string targets by name.\n if (typeof sheetArg === 'number') {\n const byIndex = wb.worksheets[sheetArg - 1]\n if (byIndex) return byIndex\n const byName = wb.getWorksheet(String(sheetArg))\n if (byName) {\n throw new Error(\n `no sheet at index ${sheetArg}, but a sheet NAMED \"${sheetArg}\" exists — quote it: sheet=\"${sheetArg}\"`\n )\n }\n throw new Error(\n `sheet index ${sheetArg} is out of range (1-based; the workbook has ${wb.worksheets.length})`\n )\n }\n const ws = wb.getWorksheet(sheetArg as string)\n if (!ws) {\n const names = wb.worksheets.map((w) => `\"${w.name}\"`).join(', ')\n throw new Error(`no sheet named \"${String(sheetArg)}\". Sheets: ${names}`)\n }\n return ws\n}\n\nconst columnLetterToNumber = (col: string): number => {\n let n = 0\n for (const ch of col.toUpperCase()) n = n * 26 + (ch.charCodeAt(0) - 64)\n return n\n}\n\ntype CellValue = string | number | boolean | null\n\nconst asCellValue = (value: unknown): ExcelJSNS.CellValue => {\n if (value === null) return null\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value\n }\n throw new Error(`cell values must be string, number, boolean, or null; got ${typeof value}`)\n}\n\n/** Apply one structural op to the workbook in place; returns the change summary. */\nconst applyEdit = (\n wb: ExcelJSNS.Workbook,\n op: string,\n args: Record<string, unknown>\n): EditSummary => {\n switch (op) {\n case 'sheet.add_rows': {\n const rows = args.rows\n if (!Array.isArray(rows) || rows.length === 0 || !rows.every(Array.isArray)) {\n throw new Error(`rows must be a non-empty JSON array of arrays, e.g. rows='[[\"a\",1]]'`)\n }\n const before = args.before as number | undefined\n const after = args.after as number | undefined\n const ws = resolveSheet(wb, args.sheet)\n const insertAt =\n before !== undefined ? before : after !== undefined ? after + 1 : ws.rowCount + 1\n const cellRows = (rows as unknown[][]).map((r) => r.map(asCellValue))\n ws.spliceRows(insertAt, 0, ...cellRows)\n return { added: cellRows.length }\n }\n case 'sheet.add_columns': {\n const headers = args.headers as string[] | undefined\n const columns: Array<{ header: string; values?: CellValue[] }> | undefined =\n (args.columns as Array<{ header: string; values?: CellValue[] }> | undefined) ??\n headers?.map((header) => ({ header }) as { header: string; values?: CellValue[] })\n if (!Array.isArray(columns) || columns.length === 0) {\n throw new Error(`provide headers=a,b or columns='[{\"header\":\"X\",\"values\":[1]}]'`)\n }\n const before = args.before as number | undefined\n const after = args.after as number | undefined\n const ws = resolveSheet(wb, args.sheet)\n const insertAt =\n before !== undefined ? before : after !== undefined ? after + 1 : ws.columnCount + 1\n for (const [i, col] of columns.entries()) {\n if (typeof col?.header !== 'string') throw new Error('every column needs a string header')\n ws.spliceColumns(insertAt + i, 0, [col.header, ...(col.values ?? []).map(asCellValue)])\n }\n return { added: columns.length }\n }\n case 'sheet.update_cells': {\n const updates = args.updates\n if (!Array.isArray(updates) || updates.length === 0) {\n throw new Error(\n `updates must be a non-empty JSON array, e.g. updates='[{\"address\":\"B2\",\"value\":3}]'`\n )\n }\n const ws = resolveSheet(wb, args.sheet)\n let modified = 0\n for (const raw of updates as Array<Record<string, unknown>>) {\n const address = raw.address as string | undefined\n const row = raw.row as number | undefined\n const col = raw.col as number | string | undefined\n let cell: ExcelJSNS.Cell\n if (address) {\n cell = ws.getCell(address)\n } else if (row !== undefined && col !== undefined) {\n cell =\n typeof col === 'string'\n ? ws.getCell(row, columnLetterToNumber(col))\n : ws.getCell(row, col)\n } else {\n throw new Error('each update needs address, or both row and col')\n }\n const value = raw.value\n if (typeof value === 'string' && value.startsWith('=')) {\n cell.value = { formula: value.slice(1) } as ExcelJSNS.CellValue\n } else {\n cell.value = asCellValue(value)\n }\n modified += 1\n }\n return { modified }\n }\n case 'sheet.delete_rows': {\n const rows = args.rows as number[]\n const ws = resolveSheet(wb, args.sheet)\n for (const r of [...rows].sort((a, b) => b - a)) ws.spliceRows(r, 1)\n return { removed: rows.length }\n }\n case 'sheet.delete_columns': {\n const columns = args.columns as number[]\n const ws = resolveSheet(wb, args.sheet)\n for (const c of [...columns].sort((a, b) => b - a)) ws.spliceColumns(c, 1)\n return { removed: columns.length }\n }\n case 'sheet.rename_sheet': {\n const sheet = args.sheet as string\n const to = args.to as string\n const ws = wb.getWorksheet(sheet)\n if (!ws) {\n const names = wb.worksheets.map((w) => `\"${w.name}\"`).join(', ')\n throw new Error(`rename targets a sheet NAME; no sheet named \"${sheet}\". Sheets: ${names}`)\n }\n ws.name = to\n return { modified: 1 }\n }\n case 'sheet.add_sheet': {\n const name = args.name as string\n const at = args.at as number | undefined\n if (wb.getWorksheet(name)) throw new Error(`a sheet named \"${name}\" already exists`)\n const ws = wb.addWorksheet(name)\n if (at !== undefined) {\n const all = wb.worksheets\n const wsIdx = all.indexOf(ws)\n if (wsIdx !== at - 1) {\n all.forEach((w, i) => {\n ;(w as unknown as { orderNo: number }).orderNo =\n w === ws ? at : i + 1 >= at && i < wsIdx ? i + 2 : i + 1\n })\n }\n }\n return { added: 1 }\n }\n case 'sheet.remove_sheet': {\n const sheet = args.sheet as string\n const ws = wb.getWorksheet(sheet)\n if (!ws) {\n const names = wb.worksheets.map((w) => `\"${w.name}\"`).join(', ')\n throw new Error(`remove targets a sheet NAME; no sheet named \"${sheet}\". Sheets: ${names}`)\n }\n wb.removeWorksheet(ws.id)\n return { removed: 1 }\n }\n case 'sheet.reorder_sheets': {\n const order = args.order\n if (!Array.isArray(order) || order.length === 0) {\n throw new Error(`order must be a JSON array of names/indices, e.g. order='[\"Summary\",2]'`)\n }\n const refs = order as Array<string | number>\n if (refs.length !== wb.worksheets.length) {\n throw new Error(\n `order must include every worksheet exactly once (the workbook has ${wb.worksheets.length})`\n )\n }\n const reordered: ExcelJSNS.Worksheet[] = []\n const seen = new Set<number>()\n for (const ref of refs) {\n const ws = typeof ref === 'number' ? wb.worksheets[ref - 1] : wb.getWorksheet(ref)\n if (!ws) throw new Error(`sheet not found: ${String(ref)}`)\n if (seen.has(ws.id)) throw new Error(`duplicate sheet reference: ${String(ref)}`)\n seen.add(ws.id)\n reordered.push(ws)\n }\n // ExcelJS serializes by orderNo; the worksheets getter returns a sorted clone.\n reordered.forEach((ws, i) => {\n ;(ws as unknown as { orderNo: number }).orderNo = i + 1\n })\n return { modified: reordered.length }\n }\n case 'sheet.transform_table': {\n const headerRow = (args.header_row as number | undefined) ?? 1\n const rename = args.rename as Array<{ from: string; to: string }> | undefined\n const select = args.select as string[] | undefined\n const drop = args.drop as string[] | undefined\n const ws = resolveSheet(wb, args.sheet)\n let modified = 0\n const headerMap = new Map<string, number>()\n ws.getRow(headerRow).eachCell({ includeEmpty: false }, (cell, colNumber) => {\n if (typeof cell.value === 'string') headerMap.set(cell.value, colNumber)\n })\n if (rename) {\n for (const { from, to } of rename) {\n const colNum = headerMap.get(from)\n if (colNum !== undefined) {\n ws.getRow(headerRow).getCell(colNum).value = to\n headerMap.delete(from)\n headerMap.set(to, colNum)\n modified += 1\n }\n }\n }\n if (drop) {\n const cols = drop\n .map((name) => headerMap.get(name))\n .filter((n): n is number => n !== undefined)\n .sort((a, b) => b - a)\n for (const col of cols) {\n ws.spliceColumns(col, 1)\n modified += 1\n }\n }\n if (select) {\n const keep = new Set(select)\n const cols: number[] = []\n ws.getRow(headerRow).eachCell({ includeEmpty: false }, (cell, colNumber) => {\n if (typeof cell.value === 'string' && !keep.has(cell.value)) cols.push(colNumber)\n })\n cols.sort((a, b) => b - a)\n for (const col of cols) {\n ws.spliceColumns(col, 1)\n modified += 1\n }\n }\n return { modified }\n }\n default:\n throw new Error(`exceljs does not implement edit op \"${op}\"`)\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ExcelJS-backed workbook {@link @nhtio/adk/batteries/media/contracts!MediaEngine}: the
|
|
3
|
+
* fidelity-preserving structural editor for xlsx, plus in-process blank-workbook generation.
|
|
4
|
+
*
|
|
5
|
+
* @module @nhtio/adk/batteries/media/engines/exceljs
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* ExcelJS models the parts of a workbook that matter to humans — fonts, fills, comments,
|
|
9
|
+
* merged ranges, data validations — and carries them through a read→edit→write cycle intact.
|
|
10
|
+
* That is this engine's whole reason to exist: the `sheet.*` verbs mutate workbooks users
|
|
11
|
+
* hand us, and an edit that strips the user's formatting as a side effect is corruption with
|
|
12
|
+
* good intentions. Compose this engine FIRST in the engines array when fidelity matters; the
|
|
13
|
+
* sheetjs engine edits a far wider read matrix (ODS, XLS, NUMBERS, …) but SheetJS Community
|
|
14
|
+
* Edition strips styling in the process.
|
|
15
|
+
*
|
|
16
|
+
* Capabilities:
|
|
17
|
+
*
|
|
18
|
+
* - **generate**: `EMPTY_MIME` → xlsx (a blank workbook with one `Sheet1` — every sheet step
|
|
19
|
+
* expects at least one worksheet).
|
|
20
|
+
* - **edit**: the ten `sheet.*` structural ops over xlsx, styling preserved.
|
|
21
|
+
*
|
|
22
|
+
* `exceljs` is an optional peer dependency, lazily imported on first actual use. Cross-env by
|
|
23
|
+
* construction: no `node:*` imports, `Uint8Array` in and out (ExcelJS ships a browser build
|
|
24
|
+
* via its `browser` field).
|
|
25
|
+
*/
|
|
26
|
+
import type { default as ExcelJSNS } from 'exceljs';
|
|
27
|
+
import type { MediaEngine } from "../contracts";
|
|
28
|
+
type ExcelJSModule = typeof ExcelJSNS;
|
|
29
|
+
/** Options for {@link exceljsEngine}. */
|
|
30
|
+
export interface ExceljsEngineOptions {
|
|
31
|
+
/** Override the module resolution (tests / custom builds). Default: `import('exceljs')`. */
|
|
32
|
+
exceljs?: () => ExcelJSModule | Promise<ExcelJSModule>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Construct the ExcelJS-backed workbook engine.
|
|
36
|
+
*
|
|
37
|
+
* @param options - Optional module resolver override.
|
|
38
|
+
* @returns The engine.
|
|
39
|
+
*/
|
|
40
|
+
export declare const exceljsEngine: (options?: ExceljsEngineOptions) => MediaEngine;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { o as isError } from "../../../tool_registry-CZ55mIti.mjs";
|
|
2
|
+
import "../../../guards.mjs";
|
|
3
|
+
import { EMPTY_MIME } from "../contracts.mjs";
|
|
4
|
+
import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../../exceptions-BLTn4Ofs.mjs";
|
|
5
|
+
import { n as MIME } from "../../../formats-CCylUHZw.mjs";
|
|
6
|
+
//#region src/batteries/media/engines/exceljs.ts
|
|
7
|
+
/**
|
|
8
|
+
* The ExcelJS-backed workbook {@link @nhtio/adk/batteries/media/contracts!MediaEngine}: the
|
|
9
|
+
* fidelity-preserving structural editor for xlsx, plus in-process blank-workbook generation.
|
|
10
|
+
*
|
|
11
|
+
* @module @nhtio/adk/batteries/media/engines/exceljs
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* ExcelJS models the parts of a workbook that matter to humans — fonts, fills, comments,
|
|
15
|
+
* merged ranges, data validations — and carries them through a read→edit→write cycle intact.
|
|
16
|
+
* That is this engine's whole reason to exist: the `sheet.*` verbs mutate workbooks users
|
|
17
|
+
* hand us, and an edit that strips the user's formatting as a side effect is corruption with
|
|
18
|
+
* good intentions. Compose this engine FIRST in the engines array when fidelity matters; the
|
|
19
|
+
* sheetjs engine edits a far wider read matrix (ODS, XLS, NUMBERS, …) but SheetJS Community
|
|
20
|
+
* Edition strips styling in the process.
|
|
21
|
+
*
|
|
22
|
+
* Capabilities:
|
|
23
|
+
*
|
|
24
|
+
* - **generate**: `EMPTY_MIME` → xlsx (a blank workbook with one `Sheet1` — every sheet step
|
|
25
|
+
* expects at least one worksheet).
|
|
26
|
+
* - **edit**: the ten `sheet.*` structural ops over xlsx, styling preserved.
|
|
27
|
+
*
|
|
28
|
+
* `exceljs` is an optional peer dependency, lazily imported on first actual use. Cross-env by
|
|
29
|
+
* construction: no `node:*` imports, `Uint8Array` in and out (ExcelJS ships a browser build
|
|
30
|
+
* via its `browser` field).
|
|
31
|
+
*/
|
|
32
|
+
/** The structural ops this engine edits (same names the verb table uses). */
|
|
33
|
+
var SHEET_OPS = [
|
|
34
|
+
"sheet.add_rows",
|
|
35
|
+
"sheet.add_columns",
|
|
36
|
+
"sheet.update_cells",
|
|
37
|
+
"sheet.delete_rows",
|
|
38
|
+
"sheet.delete_columns",
|
|
39
|
+
"sheet.rename_sheet",
|
|
40
|
+
"sheet.add_sheet",
|
|
41
|
+
"sheet.remove_sheet",
|
|
42
|
+
"sheet.reorder_sheets",
|
|
43
|
+
"sheet.transform_table"
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Construct the ExcelJS-backed workbook engine.
|
|
47
|
+
*
|
|
48
|
+
* @param options - Optional module resolver override.
|
|
49
|
+
* @returns The engine.
|
|
50
|
+
*/
|
|
51
|
+
var exceljsEngine = (options = {}) => {
|
|
52
|
+
let modPromise;
|
|
53
|
+
const getExcel = () => {
|
|
54
|
+
modPromise ??= Promise.resolve(options.exceljs ? options.exceljs() : import("exceljs").then((m) => "default" in m ? m.default : m)).catch((err) => {
|
|
55
|
+
throw new E_INVALID_MEDIA_PIPELINE_CONFIG([`the exceljs engine could not load its peer dependency "exceljs": ${isError(err) ? err.message : String(err)} — install it (pnpm add exceljs)`]);
|
|
56
|
+
});
|
|
57
|
+
return modPromise;
|
|
58
|
+
};
|
|
59
|
+
const convert = async (request) => {
|
|
60
|
+
if (request.to !== "xlsx") throw new Error(`exceljs generates "xlsx" only; requested "${request.to}"`);
|
|
61
|
+
const wb = new (await (getExcel())).Workbook();
|
|
62
|
+
wb.addWorksheet("Sheet1");
|
|
63
|
+
return { outputs: [{
|
|
64
|
+
bytes: new Uint8Array(await wb.xlsx.writeBuffer()),
|
|
65
|
+
mimeType: MIME.XLSX
|
|
66
|
+
}] };
|
|
67
|
+
};
|
|
68
|
+
const edit = async (request) => {
|
|
69
|
+
const wb = new (await (getExcel())).Workbook();
|
|
70
|
+
try {
|
|
71
|
+
await wb.xlsx.load(request.bytes.buffer.slice(request.bytes.byteOffset, request.bytes.byteOffset + request.bytes.byteLength));
|
|
72
|
+
} catch (err) {
|
|
73
|
+
const detail = isError(err) ? err.message : String(err);
|
|
74
|
+
throw new Error(`could not open the spreadsheet: ${detail}`);
|
|
75
|
+
}
|
|
76
|
+
const summary = applyEdit(wb, request.op, request.args);
|
|
77
|
+
return {
|
|
78
|
+
bytes: new Uint8Array(await wb.xlsx.writeBuffer()),
|
|
79
|
+
mimeType: MIME.XLSX,
|
|
80
|
+
summary
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
id: "exceljs",
|
|
85
|
+
converts: [{
|
|
86
|
+
from: [EMPTY_MIME],
|
|
87
|
+
to: ["xlsx"],
|
|
88
|
+
convert
|
|
89
|
+
}],
|
|
90
|
+
edits: [{
|
|
91
|
+
over: [MIME.XLSX],
|
|
92
|
+
ops: SHEET_OPS,
|
|
93
|
+
edit
|
|
94
|
+
}]
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
/** Resolve the target worksheet from the frozen `sheet=` rule (bare number=index, string=name). */
|
|
98
|
+
var resolveSheet = (wb, sheetArg) => {
|
|
99
|
+
if (sheetArg === void 0 || sheetArg === null) {
|
|
100
|
+
const first = wb.worksheets[0];
|
|
101
|
+
if (!first) throw new Error("the workbook has no worksheets");
|
|
102
|
+
return first;
|
|
103
|
+
}
|
|
104
|
+
if (typeof sheetArg === "number") {
|
|
105
|
+
const byIndex = wb.worksheets[sheetArg - 1];
|
|
106
|
+
if (byIndex) return byIndex;
|
|
107
|
+
if (wb.getWorksheet(String(sheetArg))) throw new Error(`no sheet at index ${sheetArg}, but a sheet NAMED "${sheetArg}" exists — quote it: sheet="${sheetArg}"`);
|
|
108
|
+
throw new Error(`sheet index ${sheetArg} is out of range (1-based; the workbook has ${wb.worksheets.length})`);
|
|
109
|
+
}
|
|
110
|
+
const ws = wb.getWorksheet(sheetArg);
|
|
111
|
+
if (!ws) {
|
|
112
|
+
const names = wb.worksheets.map((w) => `"${w.name}"`).join(", ");
|
|
113
|
+
throw new Error(`no sheet named "${String(sheetArg)}". Sheets: ${names}`);
|
|
114
|
+
}
|
|
115
|
+
return ws;
|
|
116
|
+
};
|
|
117
|
+
var columnLetterToNumber = (col) => {
|
|
118
|
+
let n = 0;
|
|
119
|
+
for (const ch of col.toUpperCase()) n = n * 26 + (ch.charCodeAt(0) - 64);
|
|
120
|
+
return n;
|
|
121
|
+
};
|
|
122
|
+
var asCellValue = (value) => {
|
|
123
|
+
if (value === null) return null;
|
|
124
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
125
|
+
throw new Error(`cell values must be string, number, boolean, or null; got ${typeof value}`);
|
|
126
|
+
};
|
|
127
|
+
/** Apply one structural op to the workbook in place; returns the change summary. */
|
|
128
|
+
var applyEdit = (wb, op, args) => {
|
|
129
|
+
switch (op) {
|
|
130
|
+
case "sheet.add_rows": {
|
|
131
|
+
const rows = args.rows;
|
|
132
|
+
if (!Array.isArray(rows) || rows.length === 0 || !rows.every(Array.isArray)) throw new Error(`rows must be a non-empty JSON array of arrays, e.g. rows='[["a",1]]'`);
|
|
133
|
+
const before = args.before;
|
|
134
|
+
const after = args.after;
|
|
135
|
+
const ws = resolveSheet(wb, args.sheet);
|
|
136
|
+
const insertAt = before !== void 0 ? before : after !== void 0 ? after + 1 : ws.rowCount + 1;
|
|
137
|
+
const cellRows = rows.map((r) => r.map(asCellValue));
|
|
138
|
+
ws.spliceRows(insertAt, 0, ...cellRows);
|
|
139
|
+
return { added: cellRows.length };
|
|
140
|
+
}
|
|
141
|
+
case "sheet.add_columns": {
|
|
142
|
+
const headers = args.headers;
|
|
143
|
+
const columns = args.columns ?? headers?.map((header) => ({ header }));
|
|
144
|
+
if (!Array.isArray(columns) || columns.length === 0) throw new Error(`provide headers=a,b or columns='[{"header":"X","values":[1]}]'`);
|
|
145
|
+
const before = args.before;
|
|
146
|
+
const after = args.after;
|
|
147
|
+
const ws = resolveSheet(wb, args.sheet);
|
|
148
|
+
const insertAt = before !== void 0 ? before : after !== void 0 ? after + 1 : ws.columnCount + 1;
|
|
149
|
+
for (const [i, col] of columns.entries()) {
|
|
150
|
+
if (typeof col?.header !== "string") throw new Error("every column needs a string header");
|
|
151
|
+
ws.spliceColumns(insertAt + i, 0, [col.header, ...(col.values ?? []).map(asCellValue)]);
|
|
152
|
+
}
|
|
153
|
+
return { added: columns.length };
|
|
154
|
+
}
|
|
155
|
+
case "sheet.update_cells": {
|
|
156
|
+
const updates = args.updates;
|
|
157
|
+
if (!Array.isArray(updates) || updates.length === 0) throw new Error(`updates must be a non-empty JSON array, e.g. updates='[{"address":"B2","value":3}]'`);
|
|
158
|
+
const ws = resolveSheet(wb, args.sheet);
|
|
159
|
+
let modified = 0;
|
|
160
|
+
for (const raw of updates) {
|
|
161
|
+
const address = raw.address;
|
|
162
|
+
const row = raw.row;
|
|
163
|
+
const col = raw.col;
|
|
164
|
+
let cell;
|
|
165
|
+
if (address) cell = ws.getCell(address);
|
|
166
|
+
else if (row !== void 0 && col !== void 0) cell = typeof col === "string" ? ws.getCell(row, columnLetterToNumber(col)) : ws.getCell(row, col);
|
|
167
|
+
else throw new Error("each update needs address, or both row and col");
|
|
168
|
+
const value = raw.value;
|
|
169
|
+
if (typeof value === "string" && value.startsWith("=")) cell.value = { formula: value.slice(1) };
|
|
170
|
+
else cell.value = asCellValue(value);
|
|
171
|
+
modified += 1;
|
|
172
|
+
}
|
|
173
|
+
return { modified };
|
|
174
|
+
}
|
|
175
|
+
case "sheet.delete_rows": {
|
|
176
|
+
const rows = args.rows;
|
|
177
|
+
const ws = resolveSheet(wb, args.sheet);
|
|
178
|
+
for (const r of [...rows].sort((a, b) => b - a)) ws.spliceRows(r, 1);
|
|
179
|
+
return { removed: rows.length };
|
|
180
|
+
}
|
|
181
|
+
case "sheet.delete_columns": {
|
|
182
|
+
const columns = args.columns;
|
|
183
|
+
const ws = resolveSheet(wb, args.sheet);
|
|
184
|
+
for (const c of [...columns].sort((a, b) => b - a)) ws.spliceColumns(c, 1);
|
|
185
|
+
return { removed: columns.length };
|
|
186
|
+
}
|
|
187
|
+
case "sheet.rename_sheet": {
|
|
188
|
+
const sheet = args.sheet;
|
|
189
|
+
const to = args.to;
|
|
190
|
+
const ws = wb.getWorksheet(sheet);
|
|
191
|
+
if (!ws) {
|
|
192
|
+
const names = wb.worksheets.map((w) => `"${w.name}"`).join(", ");
|
|
193
|
+
throw new Error(`rename targets a sheet NAME; no sheet named "${sheet}". Sheets: ${names}`);
|
|
194
|
+
}
|
|
195
|
+
ws.name = to;
|
|
196
|
+
return { modified: 1 };
|
|
197
|
+
}
|
|
198
|
+
case "sheet.add_sheet": {
|
|
199
|
+
const name = args.name;
|
|
200
|
+
const at = args.at;
|
|
201
|
+
if (wb.getWorksheet(name)) throw new Error(`a sheet named "${name}" already exists`);
|
|
202
|
+
const ws = wb.addWorksheet(name);
|
|
203
|
+
if (at !== void 0) {
|
|
204
|
+
const all = wb.worksheets;
|
|
205
|
+
const wsIdx = all.indexOf(ws);
|
|
206
|
+
if (wsIdx !== at - 1) all.forEach((w, i) => {
|
|
207
|
+
w.orderNo = w === ws ? at : i + 1 >= at && i < wsIdx ? i + 2 : i + 1;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return { added: 1 };
|
|
211
|
+
}
|
|
212
|
+
case "sheet.remove_sheet": {
|
|
213
|
+
const sheet = args.sheet;
|
|
214
|
+
const ws = wb.getWorksheet(sheet);
|
|
215
|
+
if (!ws) {
|
|
216
|
+
const names = wb.worksheets.map((w) => `"${w.name}"`).join(", ");
|
|
217
|
+
throw new Error(`remove targets a sheet NAME; no sheet named "${sheet}". Sheets: ${names}`);
|
|
218
|
+
}
|
|
219
|
+
wb.removeWorksheet(ws.id);
|
|
220
|
+
return { removed: 1 };
|
|
221
|
+
}
|
|
222
|
+
case "sheet.reorder_sheets": {
|
|
223
|
+
const order = args.order;
|
|
224
|
+
if (!Array.isArray(order) || order.length === 0) throw new Error(`order must be a JSON array of names/indices, e.g. order='["Summary",2]'`);
|
|
225
|
+
const refs = order;
|
|
226
|
+
if (refs.length !== wb.worksheets.length) throw new Error(`order must include every worksheet exactly once (the workbook has ${wb.worksheets.length})`);
|
|
227
|
+
const reordered = [];
|
|
228
|
+
const seen = /* @__PURE__ */ new Set();
|
|
229
|
+
for (const ref of refs) {
|
|
230
|
+
const ws = typeof ref === "number" ? wb.worksheets[ref - 1] : wb.getWorksheet(ref);
|
|
231
|
+
if (!ws) throw new Error(`sheet not found: ${String(ref)}`);
|
|
232
|
+
if (seen.has(ws.id)) throw new Error(`duplicate sheet reference: ${String(ref)}`);
|
|
233
|
+
seen.add(ws.id);
|
|
234
|
+
reordered.push(ws);
|
|
235
|
+
}
|
|
236
|
+
reordered.forEach((ws, i) => {
|
|
237
|
+
ws.orderNo = i + 1;
|
|
238
|
+
});
|
|
239
|
+
return { modified: reordered.length };
|
|
240
|
+
}
|
|
241
|
+
case "sheet.transform_table": {
|
|
242
|
+
const headerRow = args.header_row ?? 1;
|
|
243
|
+
const rename = args.rename;
|
|
244
|
+
const select = args.select;
|
|
245
|
+
const drop = args.drop;
|
|
246
|
+
const ws = resolveSheet(wb, args.sheet);
|
|
247
|
+
let modified = 0;
|
|
248
|
+
const headerMap = /* @__PURE__ */ new Map();
|
|
249
|
+
ws.getRow(headerRow).eachCell({ includeEmpty: false }, (cell, colNumber) => {
|
|
250
|
+
if (typeof cell.value === "string") headerMap.set(cell.value, colNumber);
|
|
251
|
+
});
|
|
252
|
+
if (rename) for (const { from, to } of rename) {
|
|
253
|
+
const colNum = headerMap.get(from);
|
|
254
|
+
if (colNum !== void 0) {
|
|
255
|
+
ws.getRow(headerRow).getCell(colNum).value = to;
|
|
256
|
+
headerMap.delete(from);
|
|
257
|
+
headerMap.set(to, colNum);
|
|
258
|
+
modified += 1;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (drop) {
|
|
262
|
+
const cols = drop.map((name) => headerMap.get(name)).filter((n) => n !== void 0).sort((a, b) => b - a);
|
|
263
|
+
for (const col of cols) {
|
|
264
|
+
ws.spliceColumns(col, 1);
|
|
265
|
+
modified += 1;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (select) {
|
|
269
|
+
const keep = new Set(select);
|
|
270
|
+
const cols = [];
|
|
271
|
+
ws.getRow(headerRow).eachCell({ includeEmpty: false }, (cell, colNumber) => {
|
|
272
|
+
if (typeof cell.value === "string" && !keep.has(cell.value)) cols.push(colNumber);
|
|
273
|
+
});
|
|
274
|
+
cols.sort((a, b) => b - a);
|
|
275
|
+
for (const col of cols) {
|
|
276
|
+
ws.spliceColumns(col, 1);
|
|
277
|
+
modified += 1;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return { modified };
|
|
281
|
+
}
|
|
282
|
+
default: throw new Error(`exceljs does not implement edit op "${op}"`);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
//#endregion
|
|
286
|
+
export { exceljsEngine };
|
|
287
|
+
|
|
288
|
+
//# sourceMappingURL=exceljs.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceljs.mjs","names":[],"sources":["../../../../src/batteries/media/engines/exceljs.ts"],"sourcesContent":["/**\n * The ExcelJS-backed workbook {@link @nhtio/adk/batteries/media/contracts!MediaEngine}: the\n * fidelity-preserving structural editor for xlsx, plus in-process blank-workbook generation.\n *\n * @module @nhtio/adk/batteries/media/engines/exceljs\n *\n * @remarks\n * ExcelJS models the parts of a workbook that matter to humans — fonts, fills, comments,\n * merged ranges, data validations — and carries them through a read→edit→write cycle intact.\n * That is this engine's whole reason to exist: the `sheet.*` verbs mutate workbooks users\n * hand us, and an edit that strips the user's formatting as a side effect is corruption with\n * good intentions. Compose this engine FIRST in the engines array when fidelity matters; the\n * sheetjs engine edits a far wider read matrix (ODS, XLS, NUMBERS, …) but SheetJS Community\n * Edition strips styling in the process.\n *\n * Capabilities:\n *\n * - **generate**: `EMPTY_MIME` → xlsx (a blank workbook with one `Sheet1` — every sheet step\n * expects at least one worksheet).\n * - **edit**: the ten `sheet.*` structural ops over xlsx, styling preserved.\n *\n * `exceljs` is an optional peer dependency, lazily imported on first actual use. Cross-env by\n * construction: no `node:*` imports, `Uint8Array` in and out (ExcelJS ships a browser build\n * via its `browser` field).\n */\n\nimport { MIME } from '../formats'\nimport { EMPTY_MIME } from '../contracts'\nimport { isError } from '@nhtio/adk/guards'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type { default as ExcelJSNS } from 'exceljs'\nimport type {\n MediaEngine,\n ConvertRequest,\n ConvertResult,\n EditRequest,\n EditResult,\n EditSummary,\n} from '../contracts'\n\ntype ExcelJSModule = typeof ExcelJSNS\n\n/** Options for {@link exceljsEngine}. */\nexport interface ExceljsEngineOptions {\n /** Override the module resolution (tests / custom builds). Default: `import('exceljs')`. */\n exceljs?: () => ExcelJSModule | Promise<ExcelJSModule>\n}\n\n/** The structural ops this engine edits (same names the verb table uses). */\nconst SHEET_OPS: readonly string[] = [\n 'sheet.add_rows',\n 'sheet.add_columns',\n 'sheet.update_cells',\n 'sheet.delete_rows',\n 'sheet.delete_columns',\n 'sheet.rename_sheet',\n 'sheet.add_sheet',\n 'sheet.remove_sheet',\n 'sheet.reorder_sheets',\n 'sheet.transform_table',\n]\n\n/**\n * Construct the ExcelJS-backed workbook engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const exceljsEngine = (options: ExceljsEngineOptions = {}): MediaEngine => {\n let modPromise: Promise<ExcelJSModule> | undefined\n const getExcel = (): Promise<ExcelJSModule> => {\n modPromise ??= Promise.resolve(\n options.exceljs\n ? options.exceljs()\n : import('exceljs').then((m) => ('default' in m ? m.default : m) as ExcelJSModule)\n ).catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the exceljs engine could not load its peer dependency \"exceljs\": ${detail} — install it (pnpm add exceljs)`,\n ])\n })\n return modPromise\n }\n\n const convert = async (request: ConvertRequest): Promise<ConvertResult> => {\n if (request.to !== 'xlsx') {\n throw new Error(`exceljs generates \"xlsx\" only; requested \"${request.to}\"`)\n }\n const ExcelJS = await getExcel()\n const wb = new ExcelJS.Workbook()\n wb.addWorksheet('Sheet1')\n const bytes = new Uint8Array(await wb.xlsx.writeBuffer())\n return { outputs: [{ bytes, mimeType: MIME.XLSX }] }\n }\n\n const edit = async (request: EditRequest): Promise<EditResult> => {\n const ExcelJS = await getExcel()\n const wb = new ExcelJS.Workbook()\n try {\n await wb.xlsx.load(\n request.bytes.buffer.slice(\n request.bytes.byteOffset,\n request.bytes.byteOffset + request.bytes.byteLength\n ) as ArrayBuffer\n )\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new Error(`could not open the spreadsheet: ${detail}`)\n }\n const summary = applyEdit(wb, request.op, request.args)\n const bytes = new Uint8Array(await wb.xlsx.writeBuffer())\n return { bytes, mimeType: MIME.XLSX, summary }\n }\n\n return {\n id: 'exceljs',\n converts: [{ from: [EMPTY_MIME], to: ['xlsx'], convert }],\n edits: [{ over: [MIME.XLSX], ops: SHEET_OPS, edit }],\n }\n}\n\n// ── op implementations (moved from steps/sheet.ts; styling-preserving by library) ───────────\n\n/** Resolve the target worksheet from the frozen `sheet=` rule (bare number=index, string=name). */\nconst resolveSheet = (wb: ExcelJSNS.Workbook, sheetArg: unknown): ExcelJSNS.Worksheet => {\n if (sheetArg === undefined || sheetArg === null) {\n const first = wb.worksheets[0]\n if (!first) throw new Error('the workbook has no worksheets')\n return first\n }\n // Frozen 0.11: bare number targets by 1-based index; quoted string targets by name.\n if (typeof sheetArg === 'number') {\n const byIndex = wb.worksheets[sheetArg - 1]\n if (byIndex) return byIndex\n const byName = wb.getWorksheet(String(sheetArg))\n if (byName) {\n throw new Error(\n `no sheet at index ${sheetArg}, but a sheet NAMED \"${sheetArg}\" exists — quote it: sheet=\"${sheetArg}\"`\n )\n }\n throw new Error(\n `sheet index ${sheetArg} is out of range (1-based; the workbook has ${wb.worksheets.length})`\n )\n }\n const ws = wb.getWorksheet(sheetArg as string)\n if (!ws) {\n const names = wb.worksheets.map((w) => `\"${w.name}\"`).join(', ')\n throw new Error(`no sheet named \"${String(sheetArg)}\". Sheets: ${names}`)\n }\n return ws\n}\n\nconst columnLetterToNumber = (col: string): number => {\n let n = 0\n for (const ch of col.toUpperCase()) n = n * 26 + (ch.charCodeAt(0) - 64)\n return n\n}\n\ntype CellValue = string | number | boolean | null\n\nconst asCellValue = (value: unknown): ExcelJSNS.CellValue => {\n if (value === null) return null\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value\n }\n throw new Error(`cell values must be string, number, boolean, or null; got ${typeof value}`)\n}\n\n/** Apply one structural op to the workbook in place; returns the change summary. */\nconst applyEdit = (\n wb: ExcelJSNS.Workbook,\n op: string,\n args: Record<string, unknown>\n): EditSummary => {\n switch (op) {\n case 'sheet.add_rows': {\n const rows = args.rows\n if (!Array.isArray(rows) || rows.length === 0 || !rows.every(Array.isArray)) {\n throw new Error(`rows must be a non-empty JSON array of arrays, e.g. rows='[[\"a\",1]]'`)\n }\n const before = args.before as number | undefined\n const after = args.after as number | undefined\n const ws = resolveSheet(wb, args.sheet)\n const insertAt =\n before !== undefined ? before : after !== undefined ? after + 1 : ws.rowCount + 1\n const cellRows = (rows as unknown[][]).map((r) => r.map(asCellValue))\n ws.spliceRows(insertAt, 0, ...cellRows)\n return { added: cellRows.length }\n }\n case 'sheet.add_columns': {\n const headers = args.headers as string[] | undefined\n const columns: Array<{ header: string; values?: CellValue[] }> | undefined =\n (args.columns as Array<{ header: string; values?: CellValue[] }> | undefined) ??\n headers?.map((header) => ({ header }) as { header: string; values?: CellValue[] })\n if (!Array.isArray(columns) || columns.length === 0) {\n throw new Error(`provide headers=a,b or columns='[{\"header\":\"X\",\"values\":[1]}]'`)\n }\n const before = args.before as number | undefined\n const after = args.after as number | undefined\n const ws = resolveSheet(wb, args.sheet)\n const insertAt =\n before !== undefined ? before : after !== undefined ? after + 1 : ws.columnCount + 1\n for (const [i, col] of columns.entries()) {\n if (typeof col?.header !== 'string') throw new Error('every column needs a string header')\n ws.spliceColumns(insertAt + i, 0, [col.header, ...(col.values ?? []).map(asCellValue)])\n }\n return { added: columns.length }\n }\n case 'sheet.update_cells': {\n const updates = args.updates\n if (!Array.isArray(updates) || updates.length === 0) {\n throw new Error(\n `updates must be a non-empty JSON array, e.g. updates='[{\"address\":\"B2\",\"value\":3}]'`\n )\n }\n const ws = resolveSheet(wb, args.sheet)\n let modified = 0\n for (const raw of updates as Array<Record<string, unknown>>) {\n const address = raw.address as string | undefined\n const row = raw.row as number | undefined\n const col = raw.col as number | string | undefined\n let cell: ExcelJSNS.Cell\n if (address) {\n cell = ws.getCell(address)\n } else if (row !== undefined && col !== undefined) {\n cell =\n typeof col === 'string'\n ? ws.getCell(row, columnLetterToNumber(col))\n : ws.getCell(row, col)\n } else {\n throw new Error('each update needs address, or both row and col')\n }\n const value = raw.value\n if (typeof value === 'string' && value.startsWith('=')) {\n cell.value = { formula: value.slice(1) } as ExcelJSNS.CellValue\n } else {\n cell.value = asCellValue(value)\n }\n modified += 1\n }\n return { modified }\n }\n case 'sheet.delete_rows': {\n const rows = args.rows as number[]\n const ws = resolveSheet(wb, args.sheet)\n for (const r of [...rows].sort((a, b) => b - a)) ws.spliceRows(r, 1)\n return { removed: rows.length }\n }\n case 'sheet.delete_columns': {\n const columns = args.columns as number[]\n const ws = resolveSheet(wb, args.sheet)\n for (const c of [...columns].sort((a, b) => b - a)) ws.spliceColumns(c, 1)\n return { removed: columns.length }\n }\n case 'sheet.rename_sheet': {\n const sheet = args.sheet as string\n const to = args.to as string\n const ws = wb.getWorksheet(sheet)\n if (!ws) {\n const names = wb.worksheets.map((w) => `\"${w.name}\"`).join(', ')\n throw new Error(`rename targets a sheet NAME; no sheet named \"${sheet}\". Sheets: ${names}`)\n }\n ws.name = to\n return { modified: 1 }\n }\n case 'sheet.add_sheet': {\n const name = args.name as string\n const at = args.at as number | undefined\n if (wb.getWorksheet(name)) throw new Error(`a sheet named \"${name}\" already exists`)\n const ws = wb.addWorksheet(name)\n if (at !== undefined) {\n const all = wb.worksheets\n const wsIdx = all.indexOf(ws)\n if (wsIdx !== at - 1) {\n all.forEach((w, i) => {\n ;(w as unknown as { orderNo: number }).orderNo =\n w === ws ? at : i + 1 >= at && i < wsIdx ? i + 2 : i + 1\n })\n }\n }\n return { added: 1 }\n }\n case 'sheet.remove_sheet': {\n const sheet = args.sheet as string\n const ws = wb.getWorksheet(sheet)\n if (!ws) {\n const names = wb.worksheets.map((w) => `\"${w.name}\"`).join(', ')\n throw new Error(`remove targets a sheet NAME; no sheet named \"${sheet}\". Sheets: ${names}`)\n }\n wb.removeWorksheet(ws.id)\n return { removed: 1 }\n }\n case 'sheet.reorder_sheets': {\n const order = args.order\n if (!Array.isArray(order) || order.length === 0) {\n throw new Error(`order must be a JSON array of names/indices, e.g. order='[\"Summary\",2]'`)\n }\n const refs = order as Array<string | number>\n if (refs.length !== wb.worksheets.length) {\n throw new Error(\n `order must include every worksheet exactly once (the workbook has ${wb.worksheets.length})`\n )\n }\n const reordered: ExcelJSNS.Worksheet[] = []\n const seen = new Set<number>()\n for (const ref of refs) {\n const ws = typeof ref === 'number' ? wb.worksheets[ref - 1] : wb.getWorksheet(ref)\n if (!ws) throw new Error(`sheet not found: ${String(ref)}`)\n if (seen.has(ws.id)) throw new Error(`duplicate sheet reference: ${String(ref)}`)\n seen.add(ws.id)\n reordered.push(ws)\n }\n // ExcelJS serializes by orderNo; the worksheets getter returns a sorted clone.\n reordered.forEach((ws, i) => {\n ;(ws as unknown as { orderNo: number }).orderNo = i + 1\n })\n return { modified: reordered.length }\n }\n case 'sheet.transform_table': {\n const headerRow = (args.header_row as number | undefined) ?? 1\n const rename = args.rename as Array<{ from: string; to: string }> | undefined\n const select = args.select as string[] | undefined\n const drop = args.drop as string[] | undefined\n const ws = resolveSheet(wb, args.sheet)\n let modified = 0\n const headerMap = new Map<string, number>()\n ws.getRow(headerRow).eachCell({ includeEmpty: false }, (cell, colNumber) => {\n if (typeof cell.value === 'string') headerMap.set(cell.value, colNumber)\n })\n if (rename) {\n for (const { from, to } of rename) {\n const colNum = headerMap.get(from)\n if (colNum !== undefined) {\n ws.getRow(headerRow).getCell(colNum).value = to\n headerMap.delete(from)\n headerMap.set(to, colNum)\n modified += 1\n }\n }\n }\n if (drop) {\n const cols = drop\n .map((name) => headerMap.get(name))\n .filter((n): n is number => n !== undefined)\n .sort((a, b) => b - a)\n for (const col of cols) {\n ws.spliceColumns(col, 1)\n modified += 1\n }\n }\n if (select) {\n const keep = new Set(select)\n const cols: number[] = []\n ws.getRow(headerRow).eachCell({ includeEmpty: false }, (cell, colNumber) => {\n if (typeof cell.value === 'string' && !keep.has(cell.value)) cols.push(colNumber)\n })\n cols.sort((a, b) => b - a)\n for (const col of cols) {\n ws.spliceColumns(col, 1)\n modified += 1\n }\n }\n return { modified }\n }\n default:\n throw new Error(`exceljs does not implement edit op \"${op}\"`)\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_tool_registry = require("../../../tool_registry-
|
|
3
|
+
const require_tool_registry = require("../../../tool_registry-DwZ6pzN4.js");
|
|
4
4
|
require("../../../guards.cjs");
|
|
5
5
|
const require_exceptions = require("../../../exceptions-D79HIKeX.js");
|
|
6
6
|
//#region src/batteries/media/engines/execa_executor.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as isObject, o as isError } from "../../../tool_registry-
|
|
1
|
+
import { c as isObject, o as isError } from "../../../tool_registry-CZ55mIti.mjs";
|
|
2
2
|
import "../../../guards.mjs";
|
|
3
3
|
import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../../exceptions-BLTn4Ofs.mjs";
|
|
4
4
|
//#region src/batteries/media/engines/execa_executor.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_tool_registry = require("../../../tool_registry-
|
|
3
|
+
const require_tool_registry = require("../../../tool_registry-DwZ6pzN4.js");
|
|
4
4
|
require("../../../guards.cjs");
|
|
5
5
|
const require_exceptions = require("../../../exceptions-D79HIKeX.js");
|
|
6
6
|
//#region src/batteries/media/engines/fs_workspace.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as isError, s as isInstanceOf } from "../../../tool_registry-
|
|
1
|
+
import { o as isError, s as isInstanceOf } from "../../../tool_registry-CZ55mIti.mjs";
|
|
2
2
|
import "../../../guards.mjs";
|
|
3
3
|
import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../../exceptions-BLTn4Ofs.mjs";
|
|
4
4
|
//#region src/batteries/media/engines/fs_workspace.ts
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_tool_registry = require("../../../tool_registry-
|
|
3
|
+
const require_tool_registry = require("../../../tool_registry-DwZ6pzN4.js");
|
|
4
4
|
require("../../../guards.cjs");
|
|
5
|
+
const require_batteries_media_contracts = require("../contracts.cjs");
|
|
5
6
|
const require_exceptions = require("../../../exceptions-D79HIKeX.js");
|
|
6
7
|
//#region src/batteries/media/engines/jimp.ts
|
|
7
8
|
/**
|
|
@@ -14,7 +15,9 @@ const require_exceptions = require("../../../exceptions-D79HIKeX.js");
|
|
|
14
15
|
* The local-by-default raster engine: runs anywhere TypeScript runs. Declares one mutate
|
|
15
16
|
* capability over png/jpeg/bmp/gif/tiff with resize (cover/contain approximations), rotate,
|
|
16
17
|
* flip, quality, and metadata stripping (Jimp re-encodes pixels, so EXIF never survives —
|
|
17
|
-
* `strip_metadata` is inherently satisfied)
|
|
18
|
+
* `strip_metadata` is inherently satisfied), plus a generation edge: `EMPTY_MIME` → a blank
|
|
19
|
+
* 1024×1024 white canvas in any supported encoding (resize in the same statement —
|
|
20
|
+
* `empty:png | image resize width=64`). For webp/avif output or native-speed processing,
|
|
18
21
|
* compose a sharp-backed engine instead — the capability declaration is the seam.
|
|
19
22
|
*
|
|
20
23
|
* `jimp` is an optional peer dependency, lazily imported on first actual use (constructing
|
|
@@ -85,8 +88,27 @@ var jimpEngine = (options = {}) => {
|
|
|
85
88
|
mimeType
|
|
86
89
|
};
|
|
87
90
|
};
|
|
91
|
+
const convert = async (request) => {
|
|
92
|
+
const mimeType = MIME_BY_FORMAT[request.to];
|
|
93
|
+
if (!mimeType) throw new Error(`jimp cannot generate "${request.to}"; supported: ${SUPPORTED_OUTPUT.join(", ")}`);
|
|
94
|
+
const { Jimp } = await getJimp();
|
|
95
|
+
const buffer = await new Jimp({
|
|
96
|
+
width: 1024,
|
|
97
|
+
height: 1024,
|
|
98
|
+
color: 4294967295
|
|
99
|
+
}).getBuffer(mimeType);
|
|
100
|
+
return { outputs: [{
|
|
101
|
+
bytes: new Uint8Array(buffer),
|
|
102
|
+
mimeType
|
|
103
|
+
}] };
|
|
104
|
+
};
|
|
88
105
|
return {
|
|
89
106
|
id: "jimp",
|
|
107
|
+
converts: [{
|
|
108
|
+
from: [require_batteries_media_contracts.EMPTY_MIME],
|
|
109
|
+
to: SUPPORTED_OUTPUT,
|
|
110
|
+
convert
|
|
111
|
+
}],
|
|
90
112
|
mutates: [{
|
|
91
113
|
over: [
|
|
92
114
|
"image/png",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jimp.cjs","names":[],"sources":["../../../../src/batteries/media/engines/jimp.ts"],"sourcesContent":["/**\n * A cross-environment image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by Jimp (pure JavaScript — no native bindings, no binaries).\n *\n * @module @nhtio/adk/batteries/media/engines/jimp\n *\n * @remarks\n * The local-by-default raster engine: runs anywhere TypeScript runs. Declares one mutate\n * capability over png/jpeg/bmp/gif/tiff with resize (cover/contain approximations), rotate,\n * flip, quality, and metadata stripping (Jimp re-encodes pixels, so EXIF never survives —\n * `strip_metadata` is inherently satisfied). For webp/avif output or native-speed processing,\n * compose a sharp-backed engine instead — the capability declaration is the seam.\n *\n * `jimp` is an optional peer dependency, lazily imported on first actual use (constructing\n * the engine — and therefore the pipeline — never loads it).\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type * as JimpNS from 'jimp'\nimport type {
|
|
1
|
+
{"version":3,"file":"jimp.cjs","names":[],"sources":["../../../../src/batteries/media/engines/jimp.ts"],"sourcesContent":["/**\n * A cross-environment image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by Jimp (pure JavaScript — no native bindings, no binaries).\n *\n * @module @nhtio/adk/batteries/media/engines/jimp\n *\n * @remarks\n * The local-by-default raster engine: runs anywhere TypeScript runs. Declares one mutate\n * capability over png/jpeg/bmp/gif/tiff with resize (cover/contain approximations), rotate,\n * flip, quality, and metadata stripping (Jimp re-encodes pixels, so EXIF never survives —\n * `strip_metadata` is inherently satisfied), plus a generation edge: `EMPTY_MIME` → a blank\n * 1024×1024 white canvas in any supported encoding (resize in the same statement —\n * `empty:png | image resize width=64`). For webp/avif output or native-speed processing,\n * compose a sharp-backed engine instead — the capability declaration is the seam.\n *\n * `jimp` is an optional peer dependency, lazily imported on first actual use (constructing\n * the engine — and therefore the pipeline — never loads it).\n */\n\nimport { EMPTY_MIME } from '../contracts'\nimport { isError } from '@nhtio/adk/guards'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type * as JimpNS from 'jimp'\nimport type {\n MediaEngine,\n MutateRequest,\n EngineBytesResult,\n ConvertRequest,\n ConvertResult,\n} from '../contracts'\n\ntype JimpModule = typeof JimpNS\n\n/** Options for {@link jimpEngine}. */\nexport interface JimpEngineOptions {\n /** Override the module resolution (tests / custom builds). Default: `import('jimp')`. */\n jimp?: () => JimpModule | Promise<JimpModule>\n}\n\nconst SUPPORTED_OUTPUT = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'] as const\n\nconst MIME_BY_FORMAT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n bmp: 'image/bmp',\n gif: 'image/gif',\n tiff: 'image/tiff',\n}\n\n/**\n * Construct the Jimp-backed image engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const jimpEngine = (options: JimpEngineOptions = {}): MediaEngine => {\n let modPromise: Promise<JimpModule> | undefined\n const getJimp = (): Promise<JimpModule> => {\n modPromise ??= Promise.resolve(options.jimp ? options.jimp() : import('jimp')).catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the jimp engine could not load its peer dependency \"jimp\": ${detail} — install it (pnpm add jimp)`,\n ])\n })\n return modPromise\n }\n\n const mutate = async (request: MutateRequest): Promise<EngineBytesResult> => {\n const { Jimp } = await getJimp()\n const image = await Jimp.read(\n request.bytes.buffer.slice(\n request.bytes.byteOffset,\n request.bytes.byteOffset + request.bytes.byteLength\n ) as ArrayBuffer\n )\n\n if (request.resize) {\n const { width, height, fit } = request.resize\n if (width !== undefined && height !== undefined) {\n if (fit === 'cover') image.cover({ w: width, h: height })\n else if (fit === 'contain') image.contain({ w: width, h: height })\n else image.resize({ w: width, h: height })\n } else if (width !== undefined) {\n image.resize({ w: width })\n } else if (height !== undefined) {\n image.resize({ h: height })\n }\n }\n if (request.rotate) {\n image.rotate(request.rotate)\n }\n if (request.flip) {\n image.flip({\n horizontal: request.flip.horizontal === true,\n vertical: request.flip.vertical === true,\n })\n }\n\n const targetFormat = request.format?.to ?? mimeToFormat(request.mimeType)\n const mimeType = MIME_BY_FORMAT[targetFormat]\n if (!mimeType) {\n throw new Error(\n `jimp cannot encode \"${targetFormat}\"; supported: ${SUPPORTED_OUTPUT.join(', ')} (compose a sharp engine for webp/avif)`\n )\n }\n const quality = request.format?.quality\n const buffer =\n mimeType === 'image/jpeg' && quality !== undefined\n ? await image.getBuffer('image/jpeg', { quality })\n : await image.getBuffer(mimeType as 'image/png')\n return { bytes: new Uint8Array(buffer), mimeType }\n }\n\n // Generation: a blank 1024×1024 white canvas, encoded to the requested format.\n const convert = async (request: ConvertRequest): Promise<ConvertResult> => {\n const mimeType = MIME_BY_FORMAT[request.to]\n if (!mimeType) {\n throw new Error(\n `jimp cannot generate \"${request.to}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`\n )\n }\n const { Jimp } = await getJimp()\n const image = new Jimp({ width: 1024, height: 1024, color: 0xffffffff })\n const buffer = await image.getBuffer(mimeType as 'image/png')\n return { outputs: [{ bytes: new Uint8Array(buffer), mimeType }] }\n }\n\n return {\n id: 'jimp',\n converts: [{ from: [EMPTY_MIME], to: SUPPORTED_OUTPUT, convert }],\n mutates: [\n {\n over: ['image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/tiff'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: SUPPORTED_OUTPUT,\n mutate,\n },\n ],\n }\n}\n\nconst mimeToFormat = (mimeType: string): string => {\n const sub = mimeType.toLowerCase().split(';')[0].trim().split('/')[1] ?? 'png'\n return sub === 'jpeg' ? 'jpg' : sub\n}\n"],"mappings":"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"}
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* The local-by-default raster engine: runs anywhere TypeScript runs. Declares one mutate
|
|
9
9
|
* capability over png/jpeg/bmp/gif/tiff with resize (cover/contain approximations), rotate,
|
|
10
10
|
* flip, quality, and metadata stripping (Jimp re-encodes pixels, so EXIF never survives —
|
|
11
|
-
* `strip_metadata` is inherently satisfied)
|
|
11
|
+
* `strip_metadata` is inherently satisfied), plus a generation edge: `EMPTY_MIME` → a blank
|
|
12
|
+
* 1024×1024 white canvas in any supported encoding (resize in the same statement —
|
|
13
|
+
* `empty:png | image resize width=64`). For webp/avif output or native-speed processing,
|
|
12
14
|
* compose a sharp-backed engine instead — the capability declaration is the seam.
|
|
13
15
|
*
|
|
14
16
|
* `jimp` is an optional peer dependency, lazily imported on first actual use (constructing
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { o as isError } from "../../../tool_registry-
|
|
1
|
+
import { o as isError } from "../../../tool_registry-CZ55mIti.mjs";
|
|
2
2
|
import "../../../guards.mjs";
|
|
3
|
+
import { EMPTY_MIME } from "../contracts.mjs";
|
|
3
4
|
import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../../exceptions-BLTn4Ofs.mjs";
|
|
4
5
|
//#region src/batteries/media/engines/jimp.ts
|
|
5
6
|
/**
|
|
@@ -12,7 +13,9 @@ import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../../exceptions-BLTn4O
|
|
|
12
13
|
* The local-by-default raster engine: runs anywhere TypeScript runs. Declares one mutate
|
|
13
14
|
* capability over png/jpeg/bmp/gif/tiff with resize (cover/contain approximations), rotate,
|
|
14
15
|
* flip, quality, and metadata stripping (Jimp re-encodes pixels, so EXIF never survives —
|
|
15
|
-
* `strip_metadata` is inherently satisfied)
|
|
16
|
+
* `strip_metadata` is inherently satisfied), plus a generation edge: `EMPTY_MIME` → a blank
|
|
17
|
+
* 1024×1024 white canvas in any supported encoding (resize in the same statement —
|
|
18
|
+
* `empty:png | image resize width=64`). For webp/avif output or native-speed processing,
|
|
16
19
|
* compose a sharp-backed engine instead — the capability declaration is the seam.
|
|
17
20
|
*
|
|
18
21
|
* `jimp` is an optional peer dependency, lazily imported on first actual use (constructing
|
|
@@ -83,8 +86,27 @@ var jimpEngine = (options = {}) => {
|
|
|
83
86
|
mimeType
|
|
84
87
|
};
|
|
85
88
|
};
|
|
89
|
+
const convert = async (request) => {
|
|
90
|
+
const mimeType = MIME_BY_FORMAT[request.to];
|
|
91
|
+
if (!mimeType) throw new Error(`jimp cannot generate "${request.to}"; supported: ${SUPPORTED_OUTPUT.join(", ")}`);
|
|
92
|
+
const { Jimp } = await getJimp();
|
|
93
|
+
const buffer = await new Jimp({
|
|
94
|
+
width: 1024,
|
|
95
|
+
height: 1024,
|
|
96
|
+
color: 4294967295
|
|
97
|
+
}).getBuffer(mimeType);
|
|
98
|
+
return { outputs: [{
|
|
99
|
+
bytes: new Uint8Array(buffer),
|
|
100
|
+
mimeType
|
|
101
|
+
}] };
|
|
102
|
+
};
|
|
86
103
|
return {
|
|
87
104
|
id: "jimp",
|
|
105
|
+
converts: [{
|
|
106
|
+
from: [EMPTY_MIME],
|
|
107
|
+
to: SUPPORTED_OUTPUT,
|
|
108
|
+
convert
|
|
109
|
+
}],
|
|
88
110
|
mutates: [{
|
|
89
111
|
over: [
|
|
90
112
|
"image/png",
|