@nhtio/adk 0.1.0-master-2a4e1bd2 → 0.1.0-master-cd595e6f
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 +40 -0
- package/artifact_methods-CJDQ5Lv-.mjs +1 -0
- package/artifact_methods-D6k_82r3.js +1 -0
- package/batteries/artifacts/ecmascript.cjs +1 -1
- package/batteries/artifacts/ecmascript.mjs +1 -1
- package/batteries/artifacts/toon.cjs +1 -1
- package/batteries/artifacts/toon.mjs +1 -1
- package/batteries/artifacts/xml.cjs +1 -1
- package/batteries/artifacts/xml.mjs +1 -1
- package/batteries/artifacts/yaml.cjs +1 -1
- package/batteries/artifacts/yaml.mjs +1 -1
- package/batteries/artifacts.cjs +4 -4
- package/batteries/artifacts.mjs +4 -4
- package/batteries/dev-tools/forge.cjs +3 -3
- package/batteries/dev-tools/forge.mjs +3 -3
- package/batteries/dev-tools.cjs +2 -2
- package/batteries/dev-tools.mjs +2 -2
- package/batteries/encoding.cjs +7 -7
- package/batteries/encoding.mjs +7 -7
- package/batteries/generation/gemini/adapter.cjs +1 -1
- package/batteries/generation/gemini/adapter.mjs +1 -1
- package/batteries/generation/local_diffusion/adapter.cjs +1 -1
- package/batteries/generation/local_diffusion/adapter.mjs +1 -1
- package/batteries/generation/openai/adapter.cjs +1 -1
- package/batteries/generation/openai/adapter.mjs +1 -1
- package/batteries/isolation/browser.d.ts +1 -1
- package/batteries/isolation/child_process/transport.d.ts +2 -2
- package/batteries/isolation/child_process.cjs +4 -4
- package/batteries/isolation/child_process.cjs.map +1 -1
- package/batteries/isolation/child_process.mjs +4 -4
- package/batteries/isolation/child_process.mjs.map +1 -1
- package/batteries/isolation/codec.d.ts +2 -2
- package/batteries/isolation/crash_policy.d.ts +1 -1
- package/batteries/isolation/isolate_function.d.ts +2 -2
- package/batteries/isolation/protocol.d.ts +4 -4
- package/batteries/isolation/serve.d.ts +2 -2
- package/batteries/isolation/types.d.ts +4 -4
- package/batteries/isolation.cjs +1 -1
- package/batteries/isolation.mjs +1 -1
- package/batteries/llm/anthropic_messages/adapter.cjs +6 -6
- package/batteries/llm/anthropic_messages/adapter.cjs.map +1 -1
- package/batteries/llm/anthropic_messages/adapter.mjs +6 -6
- package/batteries/llm/anthropic_messages/adapter.mjs.map +1 -1
- package/batteries/llm/anthropic_messages/count_tokens.cjs +1 -1
- package/batteries/llm/anthropic_messages/count_tokens.mjs +1 -1
- package/batteries/llm/anthropic_messages/helpers.cjs +3 -3
- package/batteries/llm/anthropic_messages/helpers.mjs +3 -3
- package/batteries/llm/anthropic_messages/types.d.ts +2 -2
- package/batteries/llm/anthropic_messages/validation.cjs +3 -3
- package/batteries/llm/anthropic_messages/validation.cjs.map +1 -1
- package/batteries/llm/anthropic_messages/validation.mjs +3 -3
- package/batteries/llm/anthropic_messages/validation.mjs.map +1 -1
- package/batteries/llm/anthropic_messages.cjs +2 -2
- package/batteries/llm/anthropic_messages.mjs +2 -2
- package/batteries/llm/bedrock_converse/adapter.cjs +29 -7
- package/batteries/llm/bedrock_converse/adapter.cjs.map +1 -1
- package/batteries/llm/bedrock_converse/adapter.mjs +30 -8
- package/batteries/llm/bedrock_converse/adapter.mjs.map +1 -1
- package/batteries/llm/bedrock_converse/exceptions.cjs +3 -0
- package/batteries/llm/bedrock_converse/exceptions.cjs.map +1 -1
- package/batteries/llm/bedrock_converse/exceptions.d.ts +6 -0
- package/batteries/llm/bedrock_converse/exceptions.mjs +3 -1
- package/batteries/llm/bedrock_converse/exceptions.mjs.map +1 -1
- package/batteries/llm/bedrock_converse/helpers.cjs +1 -1
- package/batteries/llm/bedrock_converse/helpers.mjs +1 -1
- package/batteries/llm/bedrock_converse/types.d.ts +6 -2
- package/batteries/llm/bedrock_converse/validation.cjs +7 -1
- package/batteries/llm/bedrock_converse/validation.cjs.map +1 -1
- package/batteries/llm/bedrock_converse/validation.mjs +7 -1
- package/batteries/llm/bedrock_converse/validation.mjs.map +1 -1
- package/batteries/llm/bedrock_converse.cjs +2 -2
- package/batteries/llm/bedrock_converse.mjs +2 -2
- package/batteries/llm/claude_code_cli/adapter.cjs +6 -6
- package/batteries/llm/claude_code_cli/adapter.cjs.map +1 -1
- package/batteries/llm/claude_code_cli/adapter.mjs +6 -6
- package/batteries/llm/claude_code_cli/adapter.mjs.map +1 -1
- package/batteries/llm/claude_code_cli/helpers.cjs +3 -3
- package/batteries/llm/claude_code_cli/helpers.mjs +3 -3
- package/batteries/llm/claude_code_cli/types.d.ts +3 -2
- package/batteries/llm/claude_code_cli/validation.cjs +3 -3
- package/batteries/llm/claude_code_cli/validation.cjs.map +1 -1
- package/batteries/llm/claude_code_cli/validation.mjs +3 -3
- package/batteries/llm/claude_code_cli/validation.mjs.map +1 -1
- package/batteries/llm/claude_code_cli.cjs +1 -1
- package/batteries/llm/claude_code_cli.mjs +1 -1
- package/batteries/llm/gemini_generate_content/adapter.cjs +29 -7
- package/batteries/llm/gemini_generate_content/adapter.cjs.map +1 -1
- package/batteries/llm/gemini_generate_content/adapter.mjs +30 -8
- package/batteries/llm/gemini_generate_content/adapter.mjs.map +1 -1
- package/batteries/llm/gemini_generate_content/exceptions.cjs +3 -0
- package/batteries/llm/gemini_generate_content/exceptions.cjs.map +1 -1
- package/batteries/llm/gemini_generate_content/exceptions.d.ts +6 -0
- package/batteries/llm/gemini_generate_content/exceptions.mjs +3 -1
- package/batteries/llm/gemini_generate_content/exceptions.mjs.map +1 -1
- package/batteries/llm/gemini_generate_content/helpers.cjs +1 -1
- package/batteries/llm/gemini_generate_content/helpers.mjs +1 -1
- package/batteries/llm/gemini_generate_content/types.d.ts +7 -3
- package/batteries/llm/gemini_generate_content/validation.cjs +11 -2
- package/batteries/llm/gemini_generate_content/validation.cjs.map +1 -1
- package/batteries/llm/gemini_generate_content/validation.mjs +11 -2
- package/batteries/llm/gemini_generate_content/validation.mjs.map +1 -1
- package/batteries/llm/gemini_generate_content.cjs +1 -1
- package/batteries/llm/gemini_generate_content.mjs +1 -1
- package/batteries/llm/litert_lm/adapter.cjs +6 -6
- package/batteries/llm/litert_lm/adapter.cjs.map +1 -1
- package/batteries/llm/litert_lm/adapter.mjs +6 -6
- package/batteries/llm/litert_lm/adapter.mjs.map +1 -1
- package/batteries/llm/litert_lm/helpers.cjs +3 -3
- package/batteries/llm/litert_lm/helpers.mjs +3 -3
- package/batteries/llm/litert_lm/types.d.ts +2 -2
- package/batteries/llm/litert_lm/validation.cjs +3 -3
- package/batteries/llm/litert_lm/validation.cjs.map +1 -1
- package/batteries/llm/litert_lm/validation.mjs +3 -3
- package/batteries/llm/litert_lm/validation.mjs.map +1 -1
- package/batteries/llm/litert_lm.cjs +1 -1
- package/batteries/llm/litert_lm.mjs +1 -1
- package/batteries/llm/ollama/adapter.cjs +6 -6
- package/batteries/llm/ollama/adapter.cjs.map +1 -1
- package/batteries/llm/ollama/adapter.mjs +6 -6
- package/batteries/llm/ollama/adapter.mjs.map +1 -1
- package/batteries/llm/ollama/helpers.cjs +4 -4
- package/batteries/llm/ollama/helpers.mjs +4 -4
- package/batteries/llm/ollama/types.d.ts +2 -2
- package/batteries/llm/ollama/validation.cjs +3 -3
- package/batteries/llm/ollama/validation.cjs.map +1 -1
- package/batteries/llm/ollama/validation.mjs +3 -3
- package/batteries/llm/ollama/validation.mjs.map +1 -1
- package/batteries/llm/ollama.cjs +2 -2
- package/batteries/llm/ollama.mjs +2 -2
- package/batteries/llm/openai_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions/helpers.cjs +4 -4
- package/batteries/llm/openai_chat_completions/helpers.mjs +4 -4
- package/batteries/llm/openai_chat_completions/types.d.ts +2 -2
- package/batteries/llm/openai_chat_completions/validation.cjs +3 -3
- package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/openai_chat_completions/validation.mjs +3 -3
- package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -1
- package/batteries/llm/openai_chat_completions.cjs +2 -2
- package/batteries/llm/openai_chat_completions.mjs +2 -2
- package/batteries/llm/openai_responses/adapter.cjs +6 -6
- package/batteries/llm/openai_responses/adapter.cjs.map +1 -1
- package/batteries/llm/openai_responses/adapter.mjs +6 -6
- package/batteries/llm/openai_responses/adapter.mjs.map +1 -1
- package/batteries/llm/openai_responses/helpers.cjs +3 -3
- package/batteries/llm/openai_responses/helpers.mjs +3 -3
- package/batteries/llm/openai_responses/types.d.ts +2 -2
- package/batteries/llm/openai_responses/validation.cjs +3 -3
- package/batteries/llm/openai_responses/validation.cjs.map +1 -1
- package/batteries/llm/openai_responses/validation.mjs +3 -3
- package/batteries/llm/openai_responses/validation.mjs.map +1 -1
- package/batteries/llm/openai_responses.cjs +2 -2
- package/batteries/llm/openai_responses.mjs +2 -2
- package/batteries/llm/transformers_js/adapter.cjs +6 -6
- package/batteries/llm/transformers_js/adapter.cjs.map +1 -1
- package/batteries/llm/transformers_js/adapter.mjs +6 -6
- package/batteries/llm/transformers_js/adapter.mjs.map +1 -1
- package/batteries/llm/transformers_js/helpers.cjs +3 -3
- package/batteries/llm/transformers_js/helpers.mjs +3 -3
- package/batteries/llm/transformers_js/types.d.ts +2 -2
- package/batteries/llm/transformers_js/validation.cjs +3 -3
- package/batteries/llm/transformers_js/validation.cjs.map +1 -1
- package/batteries/llm/transformers_js/validation.mjs +3 -3
- package/batteries/llm/transformers_js/validation.mjs.map +1 -1
- package/batteries/llm/transformers_js.cjs +1 -1
- package/batteries/llm/transformers_js.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.cjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/adapter.mjs +6 -6
- package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/helpers.cjs +1 -1
- package/batteries/llm/webllm_chat_completions/helpers.mjs +1 -1
- package/batteries/llm/webllm_chat_completions/validation.cjs +3 -3
- package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
- package/batteries/llm/webllm_chat_completions/validation.mjs +3 -3
- package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
- package/batteries/llm/webllm_chat_completions.cjs +2 -2
- package/batteries/llm/webllm_chat_completions.mjs +2 -2
- package/batteries/llm.cjs +2 -2
- package/batteries/llm.mjs +2 -2
- package/batteries/media/builder.d.ts +3 -0
- package/batteries/media/contracts.cjs.map +1 -1
- package/batteries/media/contracts.d.ts +40 -1
- package/batteries/media/contracts.mjs.map +1 -1
- package/batteries/media/engines/sharp.cjs +36 -2
- package/batteries/media/engines/sharp.cjs.map +1 -1
- package/batteries/media/engines/sharp.mjs +36 -2
- package/batteries/media/engines/sharp.mjs.map +1 -1
- package/batteries/media/forge.cjs +5 -5
- package/batteries/media/forge.mjs +5 -5
- package/batteries/media/index.d.ts +1 -1
- package/batteries/media/lint.cjs +3 -2
- package/batteries/media/lint.cjs.map +1 -1
- package/batteries/media/lint.mjs +3 -2
- package/batteries/media/lint.mjs.map +1 -1
- package/batteries/media.cjs +66 -2
- package/batteries/media.cjs.map +1 -1
- package/batteries/media.mjs +66 -2
- package/batteries/media.mjs.map +1 -1
- package/batteries/orchestration/conformance.cjs +123 -74
- package/batteries/orchestration/conformance.cjs.map +1 -1
- package/batteries/orchestration/conformance.d.ts +10 -8
- package/batteries/orchestration/conformance.mjs +54 -5
- package/batteries/orchestration/conformance.mjs.map +1 -1
- package/batteries/orchestration/dispatch_reasoner.cjs +4 -4
- package/batteries/orchestration/dispatch_reasoner.mjs +4 -4
- package/batteries/orchestration/executor.cjs +2 -2
- package/batteries/orchestration/executor.mjs +2 -2
- package/batteries/orchestration/forge.cjs +4 -4
- package/batteries/orchestration/forge.mjs +4 -4
- package/batteries/orchestration/validation.cjs +2 -2
- package/batteries/orchestration/validation.mjs +2 -2
- package/batteries/orchestration.cjs +4 -4
- package/batteries/orchestration.mjs +4 -4
- package/batteries/sandbox/contracts/policy_enforcer.d.ts +13 -1
- package/batteries/sandbox/js/compartment.d.ts +7 -2
- package/batteries/sandbox/js/exceptions.d.ts +4 -0
- package/batteries/sandbox/js/runner.d.ts +1 -1
- package/batteries/sandbox/js/service.d.ts +1 -1
- package/batteries/sandbox/js/ses_contracts.d.ts +4 -3
- package/batteries/sandbox/js.cjs +17 -8
- package/batteries/sandbox/js.cjs.map +1 -1
- package/batteries/sandbox/js.mjs +17 -9
- package/batteries/sandbox/js.mjs.map +1 -1
- package/batteries/sandbox/manager.d.ts +4 -3
- package/batteries/sandbox/node/srt_enforcer.d.ts +1 -1
- package/batteries/sandbox/node.cjs +36 -12
- package/batteries/sandbox/node.cjs.map +1 -1
- package/batteries/sandbox/node.mjs +36 -12
- package/batteries/sandbox/node.mjs.map +1 -1
- package/batteries/sandbox/tools.cjs +1 -1
- package/batteries/sandbox/tools.mjs +1 -1
- package/batteries/sandbox/types.d.ts +10 -1
- package/batteries/sandbox.cjs +27 -9
- package/batteries/sandbox.cjs.map +1 -1
- package/batteries/sandbox.mjs +28 -11
- package/batteries/sandbox.mjs.map +1 -1
- package/batteries/skills.cjs +9 -9
- package/batteries/skills.mjs +9 -9
- package/batteries/tools/_shared.cjs +1 -1
- package/batteries/tools/_shared.mjs +1 -1
- package/batteries/tools/color.cjs +2 -2
- package/batteries/tools/color.mjs +2 -2
- package/batteries/tools/comparison.cjs +2 -2
- package/batteries/tools/comparison.mjs +2 -2
- package/batteries/tools/data_structure.cjs +2 -2
- package/batteries/tools/data_structure.mjs +2 -2
- 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 +2 -2
- package/batteries/tools/encoding.mjs +2 -2
- package/batteries/tools/formatting.cjs +2 -2
- package/batteries/tools/formatting.mjs +2 -2
- package/batteries/tools/geo_basics.cjs +2 -2
- package/batteries/tools/geo_basics.mjs +2 -2
- package/batteries/tools/math.cjs +2 -2
- package/batteries/tools/math.mjs +2 -2
- package/batteries/tools/memory.cjs +5 -5
- package/batteries/tools/memory.mjs +5 -5
- package/batteries/tools/parsing.cjs +3 -3
- package/batteries/tools/parsing.mjs +3 -3
- 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 +3 -3
- package/batteries/tools/standing_instructions.mjs +3 -3
- package/batteries/tools/statistics.cjs +3 -3
- package/batteries/tools/statistics.mjs +3 -3
- package/batteries/tools/string_processing.cjs +2 -2
- package/batteries/tools/string_processing.mjs +2 -2
- package/batteries/tools/structured_data.cjs +2 -2
- package/batteries/tools/structured_data.mjs +2 -2
- 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.cjs +2 -2
- package/batteries/tools.mjs +2 -2
- package/batteries/validation.cjs +5 -5
- package/batteries/validation.mjs +5 -5
- package/batteries/vector/conformance/index.d.ts +11 -16
- package/batteries/vector/conformance.cjs +107 -36
- package/batteries/vector/conformance.cjs.map +1 -1
- package/batteries/vector/conformance.mjs +84 -13
- package/batteries/vector/conformance.mjs.map +1 -1
- package/batteries/vector/retrievable.cjs +1 -1
- package/batteries/vector/retrievable.mjs +1 -1
- package/batteries.cjs +5 -5
- package/batteries.mjs +5 -5
- package/{chat_common-DbbIESdo.mjs → chat_common-CmKV5Dz4.mjs} +2 -2
- package/{chat_common-DbbIESdo.mjs.map → chat_common-CmKV5Dz4.mjs.map} +1 -1
- package/{chat_common-B3O3zz-i.js → chat_common-Dpan9moo.js} +2 -2
- package/{chat_common-B3O3zz-i.js.map → chat_common-Dpan9moo.js.map} +1 -1
- package/{common-v9Jo9M5k.mjs → common-BpdHIpQE.mjs} +7 -7
- package/{common-v9Jo9M5k.mjs.map → common-BpdHIpQE.mjs.map} +1 -1
- package/{common-BV3HGeLj.js → common-H44Ik9ou.js} +7 -7
- package/{common-BV3HGeLj.js.map → common-H44Ik9ou.js.map} +1 -1
- package/common.cjs +7 -7
- package/common.mjs +7 -7
- package/{dispatch_runner-CbNyqSMy.mjs → dispatch_runner-BZDXUe0G.mjs} +5 -5
- package/{dispatch_runner-CbNyqSMy.mjs.map → dispatch_runner-BZDXUe0G.mjs.map} +1 -1
- package/{dispatch_runner-Bl3Xwebu.js → dispatch_runner-CKhm-scw.js} +5 -5
- package/{dispatch_runner-Bl3Xwebu.js.map → dispatch_runner-CKhm-scw.js.map} +1 -1
- package/dispatch_runner.cjs +1 -1
- package/dispatch_runner.mjs +1 -1
- package/{ecmascript-BSnvyY8T.js → ecmascript-CCtgamDh.js} +3 -3
- package/{ecmascript-BSnvyY8T.js.map → ecmascript-CCtgamDh.js.map} +1 -1
- package/{ecmascript-CZ7_YKfZ.mjs → ecmascript-DcmUQ9Jx.mjs} +3 -3
- package/{ecmascript-CZ7_YKfZ.mjs.map → ecmascript-DcmUQ9Jx.mjs.map} +1 -1
- package/eslint.cjs +1 -1
- package/eslint.mjs +1 -1
- package/exceptions.cjs +1 -1
- package/exceptions.mjs +1 -1
- package/forge.cjs +2 -2
- package/forge.mjs +2 -2
- package/guards.cjs +7 -7
- package/guards.mjs +7 -7
- package/{helpers-CDmLDBq5.mjs → helpers-BH7HTtkD.mjs} +3 -3
- package/{helpers-CDmLDBq5.mjs.map → helpers-BH7HTtkD.mjs.map} +1 -1
- package/{helpers-Tvvwpx1M.js → helpers-CEjjkXso.js} +3 -3
- package/{helpers-Tvvwpx1M.js.map → helpers-CEjjkXso.js.map} +1 -1
- package/index.cjs +10 -10
- package/index.mjs +10 -10
- package/{isolation-BQCTQYZ_.js → isolation-7Jrcucgc.js} +11 -11
- package/isolation-7Jrcucgc.js.map +1 -0
- package/{isolation-7xbkc12r.mjs → isolation-CO0NiK8R.mjs} +11 -11
- package/isolation-CO0NiK8R.mjs.map +1 -0
- package/lib/classes/tokenizable.d.ts +2 -3
- package/mcp/adk-docs-corpus.json +2 -2
- package/package.json +469 -469
- package/{retrievable-C5dXuDhD.js → retrievable-BTwjmPnl.js} +3 -3
- package/{retrievable-C5dXuDhD.js.map → retrievable-BTwjmPnl.js.map} +1 -1
- package/{retrievable-gl_TIHnX.mjs → retrievable-CXTAUuuv.mjs} +3 -3
- package/{retrievable-gl_TIHnX.mjs.map → retrievable-CXTAUuuv.mjs.map} +1 -1
- package/{scrapper-DD6-_2u-.js → scrapper-CJexXXK-.js} +4 -4
- package/{scrapper-DD6-_2u-.js.map → scrapper-CJexXXK-.js.map} +1 -1
- package/{scrapper-u_orpxIB.mjs → scrapper-DiQ5FfDL.mjs} +4 -4
- package/{scrapper-u_orpxIB.mjs.map → scrapper-DiQ5FfDL.mjs.map} +1 -1
- package/{searxng-fVdJUCK2.mjs → searxng-BFTJ6rTE.mjs} +4 -4
- package/{searxng-fVdJUCK2.mjs.map → searxng-BFTJ6rTE.mjs.map} +1 -1
- package/{searxng-C7GK0Nrz.js → searxng-DzlGZG4V.js} +4 -4
- package/{searxng-C7GK0Nrz.js.map → searxng-DzlGZG4V.js.map} +1 -1
- package/server.json +2 -2
- package/skills/adk-assembly/SKILL.md +2 -2
- package/{spooled_artifact-DriNQRj7.js → spooled_artifact-BpcesRBv.js} +384 -384
- package/spooled_artifact-BpcesRBv.js.map +1 -0
- package/{spooled_artifact-BkueYJhR.mjs → spooled_artifact-Bw_7swIp.mjs} +385 -385
- package/spooled_artifact-Bw_7swIp.mjs.map +1 -0
- package/spooled_artifact.cjs +2 -2
- package/spooled_artifact.mjs +2 -2
- package/{spooled_markdown_artifact-CfHRZUkl.mjs → spooled_markdown_artifact-vd6eNtIP.mjs} +3 -3
- package/{spooled_markdown_artifact-CfHRZUkl.mjs.map → spooled_markdown_artifact-vd6eNtIP.mjs.map} +1 -1
- package/{spooled_markdown_artifact-C_VkCDhF.js → spooled_markdown_artifact-wJPnE8Ij.js} +3 -3
- package/{spooled_markdown_artifact-C_VkCDhF.js.map → spooled_markdown_artifact-wJPnE8Ij.js.map} +1 -1
- package/{thought-B8JAi3-W.mjs → thought-BE1KGEhV.mjs} +3 -3
- package/{thought-B8JAi3-W.mjs.map → thought-BE1KGEhV.mjs.map} +1 -1
- package/{thought--fRgOwTP.js → thought-bS7O9O5H.js} +3 -3
- package/{thought--fRgOwTP.js.map → thought-bS7O9O5H.js.map} +1 -1
- package/{tokenizable-CWW7iSrD.js → tokenizable-BMZuGWRd.js} +35 -29
- package/tokenizable-BMZuGWRd.js.map +1 -0
- package/{tokenizable-DLMP68ZV.mjs → tokenizable-VB4Av8GF.mjs} +36 -30
- package/tokenizable-VB4Av8GF.mjs.map +1 -0
- package/{tool_call-CPjyvkm4.mjs → tool_call-Cfaj-6zK.mjs} +4 -4
- package/{tool_call-CPjyvkm4.mjs.map → tool_call-Cfaj-6zK.mjs.map} +1 -1
- package/{tool_call-DgqVwL5n.js → tool_call-Fs_Uh5wQ.js} +4 -4
- package/{tool_call-DgqVwL5n.js.map → tool_call-Fs_Uh5wQ.js.map} +1 -1
- package/{tools-BmLzkvNr.mjs → tools-B3_8C78Q.mjs} +6 -6
- package/{tools-BmLzkvNr.mjs.map → tools-B3_8C78Q.mjs.map} +1 -1
- package/{tools-DmcIe2Cb.js → tools-CqOcmHR8.js} +6 -6
- package/{tools-DmcIe2Cb.js.map → tools-CqOcmHR8.js.map} +1 -1
- package/{toon-BvTQsKdN.mjs → toon-BSlr88px.mjs} +5 -5
- package/{toon-BvTQsKdN.mjs.map → toon-BSlr88px.mjs.map} +1 -1
- package/{toon-B05eKx-q.js → toon-D71tkyI3.js} +5 -5
- package/{toon-B05eKx-q.js.map → toon-D71tkyI3.js.map} +1 -1
- package/{turn_runner-DEGCvfVZ.mjs → turn_runner-BHHD6h77.mjs} +5 -5
- package/{turn_runner-DEGCvfVZ.mjs.map → turn_runner-BHHD6h77.mjs.map} +1 -1
- package/{turn_runner-DT8TseR4.js → turn_runner-DhLI7OTH.js} +5 -5
- package/{turn_runner-DT8TseR4.js.map → turn_runner-DhLI7OTH.js.map} +1 -1
- package/turn_runner.cjs +1 -1
- package/turn_runner.mjs +1 -1
- package/types-D6X_aUIb.mjs.map +1 -1
- package/types-DrSosVaM.js.map +1 -1
- package/{validate-lzy9nG_E.mjs → validate-Bi7FGjoq.mjs} +13 -1
- package/{validate-lzy9nG_E.mjs.map → validate-Bi7FGjoq.mjs.map} +1 -1
- package/{validate-CdOS7S2u.js → validate-CkQI-48O.js} +13 -1
- package/{validate-CdOS7S2u.js.map → validate-CkQI-48O.js.map} +1 -1
- package/{xml-DDTIMpY3.js → xml-BeNvlifb.js} +5 -5
- package/{xml-DDTIMpY3.js.map → xml-BeNvlifb.js.map} +1 -1
- package/{xml-VhJ4NrMB.mjs → xml-vyCZZiF_.mjs} +5 -5
- package/{xml-VhJ4NrMB.mjs.map → xml-vyCZZiF_.mjs.map} +1 -1
- package/{yaml-Cx16IYJq.js → yaml-DhLLa2cj.js} +5 -5
- package/{yaml-Cx16IYJq.js.map → yaml-DhLLa2cj.js.map} +1 -1
- package/{yaml-Du4wFGzL.mjs → yaml-Dtz0Bd7J.mjs} +5 -5
- package/{yaml-Du4wFGzL.mjs.map → yaml-Dtz0Bd7J.mjs.map} +1 -1
- package/artifact_methods-BMCahBLn.mjs +0 -1
- package/artifact_methods-f_bSy4kX.js +0 -1
- package/isolation-7xbkc12r.mjs.map +0 -1
- package/isolation-BQCTQYZ_.js.map +0 -1
- package/spooled_artifact-BkueYJhR.mjs.map +0 -1
- package/spooled_artifact-DriNQRj7.js.map +0 -1
- package/tokenizable-CWW7iSrD.js.map +0 -1
- package/tokenizable-DLMP68ZV.mjs.map +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../chunk-Cek0wNdY.js");
|
|
3
3
|
const require_guards = require("../../guards-05Uq3J4M.js");
|
|
4
|
-
const require_spooled_artifact = require("../../spooled_artifact-
|
|
5
|
-
const require_tool_call = require("../../tool_call-
|
|
6
|
-
require("../../common-
|
|
7
|
-
const require_spooled_markdown_artifact = require("../../spooled_markdown_artifact-
|
|
4
|
+
const require_spooled_artifact = require("../../spooled_artifact-BpcesRBv.js");
|
|
5
|
+
const require_tool_call = require("../../tool_call-Fs_Uh5wQ.js");
|
|
6
|
+
require("../../common-H44Ik9ou.js");
|
|
7
|
+
const require_spooled_markdown_artifact = require("../../spooled_markdown_artifact-wJPnE8Ij.js");
|
|
8
8
|
require("../../guards.cjs");
|
|
9
9
|
const require_batteries_media_contracts = require("./contracts.cjs");
|
|
10
10
|
const require_exceptions = require("../../exceptions-Dlw1Jr6E.js");
|
|
11
|
-
const require_validate = require("../../validate-
|
|
11
|
+
const require_validate = require("../../validate-CkQI-48O.js");
|
|
12
12
|
let _nhtio_validation = require("@nhtio/validation");
|
|
13
13
|
//#region src/batteries/media/forge.ts
|
|
14
14
|
/**
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as isError } from "../../guards-BEpY7lBI.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { n as Media } from "../../tool_call-
|
|
4
|
-
import "../../common-
|
|
5
|
-
import { n as SpooledJsonArtifact } from "../../spooled_markdown_artifact-
|
|
2
|
+
import { p as Tool } from "../../spooled_artifact-Bw_7swIp.mjs";
|
|
3
|
+
import { n as Media } from "../../tool_call-Cfaj-6zK.mjs";
|
|
4
|
+
import "../../common-BpdHIpQE.mjs";
|
|
5
|
+
import { n as SpooledJsonArtifact } from "../../spooled_markdown_artifact-vd6eNtIP.mjs";
|
|
6
6
|
import "../../guards.mjs";
|
|
7
7
|
import { EMPTY_MIME } from "./contracts.mjs";
|
|
8
8
|
import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../exceptions-7Kh_BCpv.mjs";
|
|
9
|
-
import { m as toPipe, o as VERB_INDEX, s as foldVerb, t as availableVerbs } from "../../validate-
|
|
9
|
+
import { m as toPipe, o as VERB_INDEX, s as foldVerb, t as availableVerbs } from "../../validate-Bi7FGjoq.mjs";
|
|
10
10
|
import { validator } from "@nhtio/validation";
|
|
11
11
|
//#region src/batteries/media/forge.ts
|
|
12
12
|
/**
|
|
@@ -55,7 +55,7 @@ export type { ValidateOptions, CapabilityProbe } from "./validate";
|
|
|
55
55
|
export { VERBS, VERB_INDEX, FOLDED_VERBS, foldVerb, suggestVerbs } from "./verbs";
|
|
56
56
|
export type { VerbSpec, VerbArgSpec, VerbArgType, VerbOutput, VerbRequirement, FormatFamily, } from "./verbs";
|
|
57
57
|
export { PCM_MIME, EMPTY_MIME, pcmToBytes, bytesToPcm, implementsMediaEngine } from "./contracts";
|
|
58
|
-
export type { MediaEngine, EngineResolver, ConvertCapability, ConvertRequest, ConvertResult, ConvertOutput, ConvertOptions, OcrConvertOptions, AsrConvertOptions, ImagesConvertOptions, MutateCapability, MutateRequest, EditCapability, EditRequest, EditResult, EditSummary, MimePattern, } from "./contracts";
|
|
58
|
+
export type { MediaEngine, EngineResolver, ConvertCapability, ConvertRequest, ConvertResult, ConvertOutput, ConvertOptions, OcrConvertOptions, AsrConvertOptions, ImagesConvertOptions, MutateCapability, MutateRequest, ImageAnnotation, EditCapability, EditRequest, EditResult, EditSummary, MimePattern, } from "./contracts";
|
|
59
59
|
export { buildEngineRegistry } from "./registry";
|
|
60
60
|
export type { EngineRegistry, EngineSelectionContext, EngineSelectionMiddlewareFn, } from "./registry";
|
|
61
61
|
export type { StepPayload, StepResult, PlanResult, StepContext, StepImpl, MediaStepMiddlewareFn, } from "./runtime";
|
package/batteries/media/lint.cjs
CHANGED
|
@@ -208,7 +208,8 @@ var BUNDLED_SUMMARIES = {
|
|
|
208
208
|
"resize",
|
|
209
209
|
"rotate",
|
|
210
210
|
"flip",
|
|
211
|
-
"strip_metadata"
|
|
211
|
+
"strip_metadata",
|
|
212
|
+
"annotate"
|
|
212
213
|
],
|
|
213
214
|
encodes: [
|
|
214
215
|
"png",
|
|
@@ -540,7 +541,7 @@ var rules = {
|
|
|
540
541
|
var plugin = {
|
|
541
542
|
meta: {
|
|
542
543
|
name: "@nhtio/adk/batteries/media/lint",
|
|
543
|
-
version: "0.1.0-master-
|
|
544
|
+
version: "0.1.0-master-cd595e6f"
|
|
544
545
|
},
|
|
545
546
|
rules
|
|
546
547
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.cjs","names":[],"sources":["../../../src/batteries/media/lint.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/media/lint\n *\n * ESLint rules for consumers of the media pipeline battery: machine-checkable enforcement of\n * the engine-composition contracts implementors are most likely to get wrong.\n *\n * @remarks\n * Battery-scoped rules ship with the battery, not with the core `@nhtio/adk/eslint` plugin —\n * they only matter to deployments that compose this battery, and they version with the\n * battery's own API. The rules are report-only (no autofix); carve out a deliberate exception\n * with an inline `// eslint-disable-next-line adk-media/{rule} -- {reason}` comment.\n *\n * `@typescript-eslint/utils` and `eslint` are OPTIONAL peer dependencies of `@nhtio/adk` —\n * installed only by consumers who lint with this plugin. The battery never imports this\n * module at runtime.\n *\n * @example Flat config\n * ```ts\n * import adkMedia from '@nhtio/adk/batteries/media/lint'\n *\n * export default [\n * { plugins: { 'adk-media': adkMedia.plugin }, rules: adkMedia.configs.recommended.rules },\n * ]\n * ```\n */\n\nimport { createRequire } from 'node:module'\nimport { ESLintUtils } from '@typescript-eslint/utils'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'\n\nconst createRule = ESLintUtils.RuleCreator(\n (name) => `https://adk.nht.io/batteries/media/lint#${name}`\n)\n\n// ── prefer-engine-resolver ───────────────────────────────────────────────────\n\nconst ENGINE_SUBPATH = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\//\n\n/**\n * Flags a static value import of a bundled engine subpath. The documented canonical supply\n * form is the dynamic-import resolver, which keeps the engine wrapper module out of every\n * bundle that merely might use it. Type-only imports are fine.\n */\nconst preferEngineResolver = createRule({\n name: 'prefer-engine-resolver',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Supply bundled media engines as dynamic-import resolvers, not static imports — a static import puts the engine wrapper in every bundle, even when the engine is conditional.',\n },\n schema: [],\n messages: {\n preferResolver:\n \"Import bundled engines lazily: supply `() => import('{{source}}').then((m) => m.{{hint}}(…))` in the engines array instead of a static import. Static imports put the engine wrapper module in every bundle. Opt out with an eslint-disable-next-line adk-media/prefer-engine-resolver comment + reason.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value !== 'string') return\n if (!ENGINE_SUBPATH.test(node.source.value)) return\n if (node.importKind === 'type') return\n const valueSpecifiers = node.specifiers.filter(\n (s) => !(s.type === 'ImportSpecifier' && s.importKind === 'type')\n )\n if (valueSpecifiers.length === 0) return\n const first = valueSpecifiers[0]\n const hint =\n first.type === 'ImportSpecifier' && first.imported.type === 'Identifier'\n ? first.imported.name\n : 'engineFactory'\n context.report({\n node,\n messageId: 'preferResolver',\n data: { source: node.source.value, hint },\n })\n },\n }\n },\n})\n\n// ── no-shadowed-engine ───────────────────────────────────────────────────────\n\n/** A statically-derived capability summary for one engines-array element. */\nexport interface EngineSummary {\n /** Display label for the diagnostic. */\n label: string\n /** Mutate groups: input patterns, ops, encodes. */\n mutates: Array<{ over: string[]; ops: string[]; encodes: string[] }>\n /** Convert groups: input patterns, target tokens. */\n converts: Array<{ from: string[]; to: string[] }>\n /** Edit groups: input patterns, ops. */\n edits: Array<{ over: string[]; ops: string[] }>\n}\n\nconst SHEET_OPS = [\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\nconst SHEET_WRITE_TARGETS = [\n 'xlsx',\n 'xlsm',\n 'xlsb',\n 'xls',\n 'ods',\n 'fods',\n 'csv',\n 'txt',\n 'html',\n 'rtf',\n 'sylk',\n 'dif',\n 'dbf',\n 'numbers',\n 'json',\n]\n\nconst SHEET_READ_MIMES = [\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-excel.sheet.macroEnabled.12',\n 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',\n 'application/vnd.ms-excel',\n 'application/vnd.oasis.opendocument.spreadsheet',\n 'application/vnd.oasis.opendocument.spreadsheet-flat-xml',\n 'text/csv',\n 'application/x-iwork-numbers-sffnumbers',\n 'application/x-sylk',\n 'application/x-dif',\n 'application/x-dbf',\n]\n\n/**\n * Known declarations of the bundled engine factories, for shadow analysis. An ESLint rule\n * cannot execute the factories it lints, so this table mirrors their declarations by hand —\n * and is pinned against the live factories by a drift test (`lint_drift.node.spec.ts`).\n * Exported for that test only.\n */\nexport const BUNDLED_SUMMARIES: Record<string, EngineSummary> = {\n dataEngine: {\n label: 'dataEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: ['txt', 'md', 'json', 'yaml', 'csv', 'html'] },\n { from: ['application/json'], to: ['yaml', 'txt', 'csv'] },\n { from: ['application/yaml'], to: ['json'] },\n { from: ['text/csv'], to: ['json'] },\n ],\n edits: [],\n },\n exceljsEngine: {\n label: 'exceljsEngine',\n mutates: [],\n converts: [{ from: ['application/x-adk-empty'], to: ['xlsx'] }],\n edits: [\n {\n over: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],\n ops: SHEET_OPS,\n },\n ],\n },\n jimpEngine: {\n label: 'jimpEngine',\n mutates: [\n {\n over: ['image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/tiff'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'],\n },\n ],\n converts: [\n { from: ['application/x-adk-empty'], to: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'] },\n ],\n edits: [],\n },\n sharpEngine: {\n label: 'sharpEngine',\n mutates: [\n {\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n converts: [\n {\n from: ['application/x-adk-empty'],\n to: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n edits: [],\n },\n sheetjsEngine: {\n label: 'sheetjsEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: SHEET_WRITE_TARGETS },\n { from: SHEET_READ_MIMES, to: SHEET_WRITE_TARGETS },\n ],\n edits: [{ over: SHEET_READ_MIMES, ops: SHEET_OPS }],\n },\n}\n\nconst literalStrings = (node: TSESTree.Node | undefined): string[] | undefined => {\n if (!node || node.type !== 'ArrayExpression') return undefined\n const out: string[] = []\n for (const el of node.elements) {\n if (!el || el.type !== 'Literal' || typeof el.value !== 'string') return undefined\n out.push(el.value)\n }\n return out\n}\n\nconst propOf = (obj: TSESTree.ObjectExpression, name: string): TSESTree.Node | undefined =>\n obj.properties.find(\n (p): p is TSESTree.Property =>\n p.type === 'Property' && !p.computed && p.key.type === 'Identifier' && p.key.name === name\n )?.value\n\n/** Find the bundled factory name referenced by an element (direct call or resolver arrow). */\nconst bundledFactoryName = (node: TSESTree.Node): string | undefined => {\n if (\n node.type === 'CallExpression' &&\n node.callee.type === 'Identifier' &&\n node.callee.name in BUNDLED_SUMMARIES\n ) {\n return node.callee.name\n }\n // Resolver forms: () => …; scan the body for m.jimpEngine(…) / jimpEngine(…).\n if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {\n let found: string | undefined\n const visit = (n: TSESTree.Node): void => {\n if (found) return\n if (n.type === 'CallExpression') {\n if (n.callee.type === 'Identifier' && n.callee.name in BUNDLED_SUMMARIES) {\n found = n.callee.name\n } else if (\n n.callee.type === 'MemberExpression' &&\n n.callee.property.type === 'Identifier' &&\n n.callee.property.name in BUNDLED_SUMMARIES\n ) {\n found = n.callee.property.name\n }\n }\n for (const key of Object.keys(n)) {\n if (key === 'parent') continue\n const value = (n as unknown as Record<string, unknown>)[key]\n const children = Array.isArray(value) ? value : [value]\n for (const child of children) {\n if (!child || typeof child !== 'object') continue\n const childNode = child as TSESTree.Node\n if (typeof childNode.type !== 'string') continue\n visit(childNode)\n }\n }\n }\n visit(node.body)\n return found\n }\n return undefined\n}\n\n/** Derive a capability summary from an element, or undefined when not statically known. */\nconst summarize = (node: TSESTree.Node): EngineSummary | undefined => {\n const factory = bundledFactoryName(node)\n if (factory) return BUNDLED_SUMMARIES[factory]\n if (node.type !== 'ObjectExpression') return undefined\n const idNode = propOf(node, 'id')\n const label =\n idNode?.type === 'Literal' && typeof idNode.value === 'string' ? idNode.value : 'engine'\n const summary: EngineSummary = { label, mutates: [], converts: [], edits: [] }\n const mutates = propOf(node, 'mutates')\n if (mutates) {\n if (mutates.type !== 'ArrayExpression') return undefined\n for (const el of mutates.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n const encodes = literalStrings(propOf(el, 'encodes'))\n if (!over || !ops || !encodes) return undefined\n summary.mutates.push({ over, ops, encodes })\n }\n }\n const converts = propOf(node, 'converts')\n if (converts) {\n if (converts.type !== 'ArrayExpression') return undefined\n for (const el of converts.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const from = literalStrings(propOf(el, 'from'))\n const to = literalStrings(propOf(el, 'to'))\n if (!from || !to) return undefined\n summary.converts.push({ from, to })\n }\n }\n const edits = propOf(node, 'edits')\n if (edits) {\n if (edits.type !== 'ArrayExpression') return undefined\n for (const el of edits.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n if (!over || !ops) return undefined\n summary.edits.push({ over, ops })\n }\n }\n if (summary.mutates.length + summary.converts.length + summary.edits.length === 0) {\n return undefined\n }\n return summary\n}\n\nconst patternCovers = (broad: string, narrow: string): boolean => {\n if (broad === narrow) return true\n if (broad.endsWith('/*')) return narrow.startsWith(broad.slice(0, -1))\n return false\n}\n\nconst patternsCover = (broad: string[], narrow: string[]): boolean =>\n narrow.every((n) => broad.some((b) => patternCovers(b, n)))\n\nconst subset = (sup: string[], sub: string[]): boolean => sub.every((s) => sup.includes(s))\n\n/** `true` when EVERY capability of `later` is subsumed by some capability of `earlier`. */\nconst shadows = (earlier: EngineSummary, later: EngineSummary): boolean => {\n if (later.mutates.length + later.converts.length + later.edits.length === 0) return false\n const mutatesCovered = later.mutates.every((lm) =>\n earlier.mutates.some(\n (em) =>\n patternsCover(em.over, lm.over) && subset(em.ops, lm.ops) && subset(em.encodes, lm.encodes)\n )\n )\n const convertsCovered = later.converts.every((lc) =>\n earlier.converts.some((ec) => patternsCover(ec.from, lc.from) && subset(ec.to, lc.to))\n )\n const editsCovered = later.edits.every((le) =>\n earlier.edits.some((ee) => patternsCover(ee.over, le.over) && subset(ee.ops, le.ops))\n )\n return mutatesCovered && convertsCovered && editsCovered\n}\n\n/**\n * Flags an engines-array element whose statically-known capabilities are entirely covered by\n * an EARLIER element — dispatch is first-capable-wins, so the later engine is dead code.\n */\nconst noShadowedEngine = createRule({\n name: 'no-shadowed-engine',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'An engine whose declared capabilities are a subset of an earlier engine in the array can never be selected — first-capable-wins dispatch makes it dead code. Reorder (narrow before broad) or remove it.',\n },\n schema: [],\n messages: {\n shadowed:\n 'Engine \"{{later}}\" can never be selected: \"{{earlier}}\" appears earlier in the array and declares a superset of its capabilities (dispatch is first-capable-wins). Put the narrower engine first, or remove it. Opt out with an eslint-disable-next-line adk-media/no-shadowed-engine comment + reason.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression) {\n if (node.callee.type !== 'Identifier' || node.callee.name !== 'createMediaPipeline') {\n return\n }\n const config = node.arguments[0]\n if (!config || config.type !== 'ObjectExpression') return\n const engines = propOf(config, 'engines')\n if (!engines || engines.type !== 'ArrayExpression') return\n const summaries = engines.elements.map((el) => (el ? summarize(el) : undefined))\n for (let i = 1; i < summaries.length; i++) {\n const later = summaries[i]\n if (!later) continue\n for (let j = 0; j < i; j++) {\n const earlier = summaries[j]\n if (!earlier) continue\n if (shadows(earlier, later)) {\n context.report({\n node: engines.elements[i]!,\n messageId: 'shadowed',\n data: { earlier: earlier.label, later: later.label },\n })\n break\n }\n }\n }\n },\n }\n },\n})\n\n// ── augment-contracts-module ─────────────────────────────────────────────────\n\nconst CONTRACTS_SUBPATH = '@nhtio/adk/batteries/media/contracts'\n\n/**\n * Flags a `ConvertOptions` declaration-merging block whose module specifier is not the\n * contracts subpath. Augmenting the barrel (or any other module) silently does nothing —\n * the keys never merge, and the typo costs hours.\n */\nconst augmentContractsModule = createRule({\n name: 'augment-contracts-module',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'ConvertOptions augmentation must target the contracts subpath — declaration merging against any other module specifier silently fails to merge.',\n },\n schema: [],\n messages: {\n wrongModule:\n 'This ConvertOptions augmentation targets \"{{actual}}\", so it will silently never merge. Declaration merging must target the module that declares the interface: declare module \\'{{expected}}\\'.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n TSModuleDeclaration(node: TSESTree.TSModuleDeclaration) {\n if (node.global) return\n if (node.id.type !== 'Literal' || typeof node.id.value !== 'string') return\n const specifier = node.id.value\n if (specifier === CONTRACTS_SUBPATH || specifier.endsWith('/media/contracts')) return\n // Only flag specifiers that are plausibly aimed at this battery.\n if (!specifier.includes('media') && !specifier.includes('@nhtio/adk')) return\n const body = node.body\n if (!body || body.type !== 'TSModuleBlock') return\n const declaresConvertOptions = body.body.some(\n (stmt) => stmt.type === 'TSInterfaceDeclaration' && stmt.id.name === 'ConvertOptions'\n )\n if (!declaresConvertOptions) return\n context.report({\n node: node.id,\n messageId: 'wrongModule',\n data: { actual: specifier, expected: CONTRACTS_SUBPATH },\n })\n },\n }\n },\n})\n\n// ── require-engine-peers ─────────────────────────────────────────────────────\n\n/**\n * The optional peer dependencies each bundled engine subpath lazily imports at runtime.\n * Keyed by the engine's subpath suffix (after `engines/`). An engine with no external peer\n * (soffice, fs_workspace) is absent — there's nothing to install. Kept in lockstep with the\n * engines' actual `import(...)` calls by `engine_peers_drift.node.spec.ts`.\n */\nexport const ENGINE_PEERS: Record<string, readonly string[]> = {\n jimp: ['jimp'],\n sharp: ['sharp'],\n sheetjs: ['xlsx'],\n exceljs: ['exceljs'],\n data: ['js-yaml', 'papaparse'],\n tesseract_js: ['tesseract.js'],\n audio_decode: ['audio-decode'],\n transformers_asr: ['@huggingface/transformers'],\n execa_executor: ['execa'],\n}\n\n/** Map a bundled engine subpath to its peer list, or undefined when it isn't a known engine. */\nconst peersForSubpath = (source: string): readonly string[] | undefined => {\n const m = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\/([a-z_]+)$/.exec(source)\n if (!m) return undefined\n return ENGINE_PEERS[m[1]]\n}\n\n/**\n * Flags an import of a bundled engine subpath whose optional peer dependency cannot be\n * resolved from the linting file — the \"I composed `sheetjsEngine()` but never installed\n * `xlsx`, and now my pipeline throws `E_INVALID_MEDIA_PIPELINE_CONFIG` at the first sheet\n * op\" footgun, caught at lint time instead of runtime. Resolution uses Node's resolver from\n * the file's own directory, so it honors the consumer's real `node_modules` layout.\n *\n * Reports once per missing peer per engine import (whether the import is a static value\n * import or a dynamic-import resolver — both reference the engine and both need the peer).\n */\n/**\n * The peer-resolution probe: returns `true` when `peer` resolves from `fromFile`. Defaults to\n * Node's resolver anchored at the linted file (so it sees the consumer's `node_modules`).\n * Exposed as a settable seam so the rule's spec can simulate installed/missing peers without\n * depending on the test runner's own `node_modules` layout — production never sets it.\n */\nexport type PeerResolver = (peer: string, fromFile: string) => boolean\n\nconst defaultPeerResolver: PeerResolver = (peer, fromFile) => {\n try {\n createRequire(fromFile).resolve(peer)\n return true\n } catch {\n return false\n }\n}\n\nlet activePeerResolver: PeerResolver = defaultPeerResolver\n\n/** Override the peer resolver (spec-only seam). Pass nothing to restore the Node default. */\nexport const setPeerResolverForTesting = (resolver?: PeerResolver): void => {\n activePeerResolver = resolver ?? defaultPeerResolver\n}\n\nconst requireEnginePeers = createRule<[{ ignore?: readonly string[] }], 'missingPeer'>({\n name: 'require-engine-peers',\n meta: {\n type: 'problem',\n docs: {\n description:\n \"A bundled media engine's optional peer dependency must be installed where it's composed — otherwise the pipeline throws at first use, not at construction.\",\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Peer package names to skip (e.g. one resolved via a custom loader the linter cannot see).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingPeer:\n 'The \"{{engine}}\" media engine requires the optional peer \"{{peer}}\", which cannot be resolved from this file. Install it ({{install}}) or the pipeline will throw E_INVALID_MEDIA_PIPELINE_CONFIG the first time this engine runs. Opt out with an eslint-disable-next-line adk-media/require-engine-peers comment + reason.',\n },\n },\n defaultOptions: [{ ignore: [] }],\n create(context, [options]) {\n const ignore = new Set(options?.ignore ?? [])\n\n /** SheetJS ships only from its CDN tarball, so the install hint must not say the registry. */\n const installHint = (peer: string): string =>\n peer === 'xlsx'\n ? 'pnpm add xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz'\n : `pnpm add ${peer}`\n\n const checkSource = (source: string, reportNode: TSESTree.Node): void => {\n const peers = peersForSubpath(source)\n if (!peers) return\n const engine = source.slice(source.lastIndexOf('/') + 1)\n for (const peer of peers) {\n if (ignore.has(peer)) continue\n if (!activePeerResolver(peer, context.filename)) {\n context.report({\n node: reportNode,\n messageId: 'missingPeer',\n data: { engine, peer, install: installHint(peer) },\n })\n }\n }\n }\n\n return {\n // Static value/type import of an engine subpath.\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value === 'string') checkSource(node.source.value, node.source)\n },\n // The canonical resolver form: import('@nhtio/adk/batteries/media/engines/…').\n ImportExpression(node: TSESTree.ImportExpression) {\n if (node.source.type === 'Literal' && typeof node.source.value === 'string') {\n checkSource(node.source.value, node.source)\n }\n },\n }\n },\n})\n\n// ── plugin assembly ──────────────────────────────────────────────────────────\n\n/**\n * Map of rule id (without the `adk-media/` plugin prefix) to its rule object. Registered on\n * the plugin as `rules`, so configs reference them as `adk-media/{id}`.\n */\nexport const rules = {\n 'prefer-engine-resolver': preferEngineResolver,\n 'no-shadowed-engine': noShadowedEngine,\n 'augment-contracts-module': augmentContractsModule,\n 'require-engine-peers': requireEnginePeers,\n} satisfies FlatConfig.Plugin['rules']\n\n/**\n * The media battery's ESLint plugin object. Register under the `adk-media` namespace:\n * `plugins: { 'adk-media': plugin }`.\n */\nexport const plugin: FlatConfig.Plugin = {\n meta: { name: '@nhtio/adk/batteries/media/lint', version: __VERSION__ },\n rules,\n}\n\nconst recommendedRules: NonNullable<FlatConfig.Config['rules']> = Object.fromEntries(\n Object.keys(rules).map((id) => [`adk-media/${id}`, 'error'])\n)\n\n/**\n * Named config presets. `recommended` enables every rule at `error` and registers the plugin\n * under the `adk-media` namespace — spread it into a flat config to adopt the full set.\n */\nexport const configs = {\n recommended: {\n name: '@nhtio/adk/batteries/media/lint/recommended',\n plugins: { 'adk-media': plugin },\n rules: recommendedRules,\n } satisfies FlatConfig.Config,\n}\n\n/**\n * Default export bundles the plugin and its config presets, mirroring the shape ESLint flat\n * configs expect from a plugin module.\n */\nexport default { plugin, rules, configs }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lint.cjs","names":[],"sources":["../../../src/batteries/media/lint.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/media/lint\n *\n * ESLint rules for consumers of the media pipeline battery: machine-checkable enforcement of\n * the engine-composition contracts implementors are most likely to get wrong.\n *\n * @remarks\n * Battery-scoped rules ship with the battery, not with the core `@nhtio/adk/eslint` plugin —\n * they only matter to deployments that compose this battery, and they version with the\n * battery's own API. The rules are report-only (no autofix); carve out a deliberate exception\n * with an inline `// eslint-disable-next-line adk-media/{rule} -- {reason}` comment.\n *\n * `@typescript-eslint/utils` and `eslint` are OPTIONAL peer dependencies of `@nhtio/adk` —\n * installed only by consumers who lint with this plugin. The battery never imports this\n * module at runtime.\n *\n * @example Flat config\n * ```ts\n * import adkMedia from '@nhtio/adk/batteries/media/lint'\n *\n * export default [\n * { plugins: { 'adk-media': adkMedia.plugin }, rules: adkMedia.configs.recommended.rules },\n * ]\n * ```\n */\n\nimport { createRequire } from 'node:module'\nimport { ESLintUtils } from '@typescript-eslint/utils'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'\n\nconst createRule = ESLintUtils.RuleCreator(\n (name) => `https://adk.nht.io/batteries/media/lint#${name}`\n)\n\n// ── prefer-engine-resolver ───────────────────────────────────────────────────\n\nconst ENGINE_SUBPATH = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\//\n\n/**\n * Flags a static value import of a bundled engine subpath. The documented canonical supply\n * form is the dynamic-import resolver, which keeps the engine wrapper module out of every\n * bundle that merely might use it. Type-only imports are fine.\n */\nconst preferEngineResolver = createRule({\n name: 'prefer-engine-resolver',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Supply bundled media engines as dynamic-import resolvers, not static imports — a static import puts the engine wrapper in every bundle, even when the engine is conditional.',\n },\n schema: [],\n messages: {\n preferResolver:\n \"Import bundled engines lazily: supply `() => import('{{source}}').then((m) => m.{{hint}}(…))` in the engines array instead of a static import. Static imports put the engine wrapper module in every bundle. Opt out with an eslint-disable-next-line adk-media/prefer-engine-resolver comment + reason.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value !== 'string') return\n if (!ENGINE_SUBPATH.test(node.source.value)) return\n if (node.importKind === 'type') return\n const valueSpecifiers = node.specifiers.filter(\n (s) => !(s.type === 'ImportSpecifier' && s.importKind === 'type')\n )\n if (valueSpecifiers.length === 0) return\n const first = valueSpecifiers[0]\n const hint =\n first.type === 'ImportSpecifier' && first.imported.type === 'Identifier'\n ? first.imported.name\n : 'engineFactory'\n context.report({\n node,\n messageId: 'preferResolver',\n data: { source: node.source.value, hint },\n })\n },\n }\n },\n})\n\n// ── no-shadowed-engine ───────────────────────────────────────────────────────\n\n/** A statically-derived capability summary for one engines-array element. */\nexport interface EngineSummary {\n /** Display label for the diagnostic. */\n label: string\n /** Mutate groups: input patterns, ops, encodes. */\n mutates: Array<{ over: string[]; ops: string[]; encodes: string[] }>\n /** Convert groups: input patterns, target tokens. */\n converts: Array<{ from: string[]; to: string[] }>\n /** Edit groups: input patterns, ops. */\n edits: Array<{ over: string[]; ops: string[] }>\n}\n\nconst SHEET_OPS = [\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\nconst SHEET_WRITE_TARGETS = [\n 'xlsx',\n 'xlsm',\n 'xlsb',\n 'xls',\n 'ods',\n 'fods',\n 'csv',\n 'txt',\n 'html',\n 'rtf',\n 'sylk',\n 'dif',\n 'dbf',\n 'numbers',\n 'json',\n]\n\nconst SHEET_READ_MIMES = [\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-excel.sheet.macroEnabled.12',\n 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',\n 'application/vnd.ms-excel',\n 'application/vnd.oasis.opendocument.spreadsheet',\n 'application/vnd.oasis.opendocument.spreadsheet-flat-xml',\n 'text/csv',\n 'application/x-iwork-numbers-sffnumbers',\n 'application/x-sylk',\n 'application/x-dif',\n 'application/x-dbf',\n]\n\n/**\n * Known declarations of the bundled engine factories, for shadow analysis. An ESLint rule\n * cannot execute the factories it lints, so this table mirrors their declarations by hand —\n * and is pinned against the live factories by a drift test (`lint_drift.node.spec.ts`).\n * Exported for that test only.\n */\nexport const BUNDLED_SUMMARIES: Record<string, EngineSummary> = {\n dataEngine: {\n label: 'dataEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: ['txt', 'md', 'json', 'yaml', 'csv', 'html'] },\n { from: ['application/json'], to: ['yaml', 'txt', 'csv'] },\n { from: ['application/yaml'], to: ['json'] },\n { from: ['text/csv'], to: ['json'] },\n ],\n edits: [],\n },\n exceljsEngine: {\n label: 'exceljsEngine',\n mutates: [],\n converts: [{ from: ['application/x-adk-empty'], to: ['xlsx'] }],\n edits: [\n {\n over: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],\n ops: SHEET_OPS,\n },\n ],\n },\n jimpEngine: {\n label: 'jimpEngine',\n mutates: [\n {\n over: ['image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/tiff'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'],\n },\n ],\n converts: [\n { from: ['application/x-adk-empty'], to: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'] },\n ],\n edits: [],\n },\n sharpEngine: {\n label: 'sharpEngine',\n mutates: [\n {\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata', 'annotate'],\n encodes: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n converts: [\n {\n from: ['application/x-adk-empty'],\n to: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n edits: [],\n },\n sheetjsEngine: {\n label: 'sheetjsEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: SHEET_WRITE_TARGETS },\n { from: SHEET_READ_MIMES, to: SHEET_WRITE_TARGETS },\n ],\n edits: [{ over: SHEET_READ_MIMES, ops: SHEET_OPS }],\n },\n}\n\nconst literalStrings = (node: TSESTree.Node | undefined): string[] | undefined => {\n if (!node || node.type !== 'ArrayExpression') return undefined\n const out: string[] = []\n for (const el of node.elements) {\n if (!el || el.type !== 'Literal' || typeof el.value !== 'string') return undefined\n out.push(el.value)\n }\n return out\n}\n\nconst propOf = (obj: TSESTree.ObjectExpression, name: string): TSESTree.Node | undefined =>\n obj.properties.find(\n (p): p is TSESTree.Property =>\n p.type === 'Property' && !p.computed && p.key.type === 'Identifier' && p.key.name === name\n )?.value\n\n/** Find the bundled factory name referenced by an element (direct call or resolver arrow). */\nconst bundledFactoryName = (node: TSESTree.Node): string | undefined => {\n if (\n node.type === 'CallExpression' &&\n node.callee.type === 'Identifier' &&\n node.callee.name in BUNDLED_SUMMARIES\n ) {\n return node.callee.name\n }\n // Resolver forms: () => …; scan the body for m.jimpEngine(…) / jimpEngine(…).\n if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {\n let found: string | undefined\n const visit = (n: TSESTree.Node): void => {\n if (found) return\n if (n.type === 'CallExpression') {\n if (n.callee.type === 'Identifier' && n.callee.name in BUNDLED_SUMMARIES) {\n found = n.callee.name\n } else if (\n n.callee.type === 'MemberExpression' &&\n n.callee.property.type === 'Identifier' &&\n n.callee.property.name in BUNDLED_SUMMARIES\n ) {\n found = n.callee.property.name\n }\n }\n for (const key of Object.keys(n)) {\n if (key === 'parent') continue\n const value = (n as unknown as Record<string, unknown>)[key]\n const children = Array.isArray(value) ? value : [value]\n for (const child of children) {\n if (!child || typeof child !== 'object') continue\n const childNode = child as TSESTree.Node\n if (typeof childNode.type !== 'string') continue\n visit(childNode)\n }\n }\n }\n visit(node.body)\n return found\n }\n return undefined\n}\n\n/** Derive a capability summary from an element, or undefined when not statically known. */\nconst summarize = (node: TSESTree.Node): EngineSummary | undefined => {\n const factory = bundledFactoryName(node)\n if (factory) return BUNDLED_SUMMARIES[factory]\n if (node.type !== 'ObjectExpression') return undefined\n const idNode = propOf(node, 'id')\n const label =\n idNode?.type === 'Literal' && typeof idNode.value === 'string' ? idNode.value : 'engine'\n const summary: EngineSummary = { label, mutates: [], converts: [], edits: [] }\n const mutates = propOf(node, 'mutates')\n if (mutates) {\n if (mutates.type !== 'ArrayExpression') return undefined\n for (const el of mutates.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n const encodes = literalStrings(propOf(el, 'encodes'))\n if (!over || !ops || !encodes) return undefined\n summary.mutates.push({ over, ops, encodes })\n }\n }\n const converts = propOf(node, 'converts')\n if (converts) {\n if (converts.type !== 'ArrayExpression') return undefined\n for (const el of converts.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const from = literalStrings(propOf(el, 'from'))\n const to = literalStrings(propOf(el, 'to'))\n if (!from || !to) return undefined\n summary.converts.push({ from, to })\n }\n }\n const edits = propOf(node, 'edits')\n if (edits) {\n if (edits.type !== 'ArrayExpression') return undefined\n for (const el of edits.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n if (!over || !ops) return undefined\n summary.edits.push({ over, ops })\n }\n }\n if (summary.mutates.length + summary.converts.length + summary.edits.length === 0) {\n return undefined\n }\n return summary\n}\n\nconst patternCovers = (broad: string, narrow: string): boolean => {\n if (broad === narrow) return true\n if (broad.endsWith('/*')) return narrow.startsWith(broad.slice(0, -1))\n return false\n}\n\nconst patternsCover = (broad: string[], narrow: string[]): boolean =>\n narrow.every((n) => broad.some((b) => patternCovers(b, n)))\n\nconst subset = (sup: string[], sub: string[]): boolean => sub.every((s) => sup.includes(s))\n\n/** `true` when EVERY capability of `later` is subsumed by some capability of `earlier`. */\nconst shadows = (earlier: EngineSummary, later: EngineSummary): boolean => {\n if (later.mutates.length + later.converts.length + later.edits.length === 0) return false\n const mutatesCovered = later.mutates.every((lm) =>\n earlier.mutates.some(\n (em) =>\n patternsCover(em.over, lm.over) && subset(em.ops, lm.ops) && subset(em.encodes, lm.encodes)\n )\n )\n const convertsCovered = later.converts.every((lc) =>\n earlier.converts.some((ec) => patternsCover(ec.from, lc.from) && subset(ec.to, lc.to))\n )\n const editsCovered = later.edits.every((le) =>\n earlier.edits.some((ee) => patternsCover(ee.over, le.over) && subset(ee.ops, le.ops))\n )\n return mutatesCovered && convertsCovered && editsCovered\n}\n\n/**\n * Flags an engines-array element whose statically-known capabilities are entirely covered by\n * an EARLIER element — dispatch is first-capable-wins, so the later engine is dead code.\n */\nconst noShadowedEngine = createRule({\n name: 'no-shadowed-engine',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'An engine whose declared capabilities are a subset of an earlier engine in the array can never be selected — first-capable-wins dispatch makes it dead code. Reorder (narrow before broad) or remove it.',\n },\n schema: [],\n messages: {\n shadowed:\n 'Engine \"{{later}}\" can never be selected: \"{{earlier}}\" appears earlier in the array and declares a superset of its capabilities (dispatch is first-capable-wins). Put the narrower engine first, or remove it. Opt out with an eslint-disable-next-line adk-media/no-shadowed-engine comment + reason.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression) {\n if (node.callee.type !== 'Identifier' || node.callee.name !== 'createMediaPipeline') {\n return\n }\n const config = node.arguments[0]\n if (!config || config.type !== 'ObjectExpression') return\n const engines = propOf(config, 'engines')\n if (!engines || engines.type !== 'ArrayExpression') return\n const summaries = engines.elements.map((el) => (el ? summarize(el) : undefined))\n for (let i = 1; i < summaries.length; i++) {\n const later = summaries[i]\n if (!later) continue\n for (let j = 0; j < i; j++) {\n const earlier = summaries[j]\n if (!earlier) continue\n if (shadows(earlier, later)) {\n context.report({\n node: engines.elements[i]!,\n messageId: 'shadowed',\n data: { earlier: earlier.label, later: later.label },\n })\n break\n }\n }\n }\n },\n }\n },\n})\n\n// ── augment-contracts-module ─────────────────────────────────────────────────\n\nconst CONTRACTS_SUBPATH = '@nhtio/adk/batteries/media/contracts'\n\n/**\n * Flags a `ConvertOptions` declaration-merging block whose module specifier is not the\n * contracts subpath. Augmenting the barrel (or any other module) silently does nothing —\n * the keys never merge, and the typo costs hours.\n */\nconst augmentContractsModule = createRule({\n name: 'augment-contracts-module',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'ConvertOptions augmentation must target the contracts subpath — declaration merging against any other module specifier silently fails to merge.',\n },\n schema: [],\n messages: {\n wrongModule:\n 'This ConvertOptions augmentation targets \"{{actual}}\", so it will silently never merge. Declaration merging must target the module that declares the interface: declare module \\'{{expected}}\\'.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n TSModuleDeclaration(node: TSESTree.TSModuleDeclaration) {\n if (node.global) return\n if (node.id.type !== 'Literal' || typeof node.id.value !== 'string') return\n const specifier = node.id.value\n if (specifier === CONTRACTS_SUBPATH || specifier.endsWith('/media/contracts')) return\n // Only flag specifiers that are plausibly aimed at this battery.\n if (!specifier.includes('media') && !specifier.includes('@nhtio/adk')) return\n const body = node.body\n if (!body || body.type !== 'TSModuleBlock') return\n const declaresConvertOptions = body.body.some(\n (stmt) => stmt.type === 'TSInterfaceDeclaration' && stmt.id.name === 'ConvertOptions'\n )\n if (!declaresConvertOptions) return\n context.report({\n node: node.id,\n messageId: 'wrongModule',\n data: { actual: specifier, expected: CONTRACTS_SUBPATH },\n })\n },\n }\n },\n})\n\n// ── require-engine-peers ─────────────────────────────────────────────────────\n\n/**\n * The optional peer dependencies each bundled engine subpath lazily imports at runtime.\n * Keyed by the engine's subpath suffix (after `engines/`). An engine with no external peer\n * (soffice, fs_workspace) is absent — there's nothing to install. Kept in lockstep with the\n * engines' actual `import(...)` calls by `engine_peers_drift.node.spec.ts`.\n */\nexport const ENGINE_PEERS: Record<string, readonly string[]> = {\n jimp: ['jimp'],\n sharp: ['sharp'],\n sheetjs: ['xlsx'],\n exceljs: ['exceljs'],\n data: ['js-yaml', 'papaparse'],\n tesseract_js: ['tesseract.js'],\n audio_decode: ['audio-decode'],\n transformers_asr: ['@huggingface/transformers'],\n execa_executor: ['execa'],\n}\n\n/** Map a bundled engine subpath to its peer list, or undefined when it isn't a known engine. */\nconst peersForSubpath = (source: string): readonly string[] | undefined => {\n const m = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\/([a-z_]+)$/.exec(source)\n if (!m) return undefined\n return ENGINE_PEERS[m[1]]\n}\n\n/**\n * Flags an import of a bundled engine subpath whose optional peer dependency cannot be\n * resolved from the linting file — the \"I composed `sheetjsEngine()` but never installed\n * `xlsx`, and now my pipeline throws `E_INVALID_MEDIA_PIPELINE_CONFIG` at the first sheet\n * op\" footgun, caught at lint time instead of runtime. Resolution uses Node's resolver from\n * the file's own directory, so it honors the consumer's real `node_modules` layout.\n *\n * Reports once per missing peer per engine import (whether the import is a static value\n * import or a dynamic-import resolver — both reference the engine and both need the peer).\n */\n/**\n * The peer-resolution probe: returns `true` when `peer` resolves from `fromFile`. Defaults to\n * Node's resolver anchored at the linted file (so it sees the consumer's `node_modules`).\n * Exposed as a settable seam so the rule's spec can simulate installed/missing peers without\n * depending on the test runner's own `node_modules` layout — production never sets it.\n */\nexport type PeerResolver = (peer: string, fromFile: string) => boolean\n\nconst defaultPeerResolver: PeerResolver = (peer, fromFile) => {\n try {\n createRequire(fromFile).resolve(peer)\n return true\n } catch {\n return false\n }\n}\n\nlet activePeerResolver: PeerResolver = defaultPeerResolver\n\n/** Override the peer resolver (spec-only seam). Pass nothing to restore the Node default. */\nexport const setPeerResolverForTesting = (resolver?: PeerResolver): void => {\n activePeerResolver = resolver ?? defaultPeerResolver\n}\n\nconst requireEnginePeers = createRule<[{ ignore?: readonly string[] }], 'missingPeer'>({\n name: 'require-engine-peers',\n meta: {\n type: 'problem',\n docs: {\n description:\n \"A bundled media engine's optional peer dependency must be installed where it's composed — otherwise the pipeline throws at first use, not at construction.\",\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Peer package names to skip (e.g. one resolved via a custom loader the linter cannot see).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingPeer:\n 'The \"{{engine}}\" media engine requires the optional peer \"{{peer}}\", which cannot be resolved from this file. Install it ({{install}}) or the pipeline will throw E_INVALID_MEDIA_PIPELINE_CONFIG the first time this engine runs. Opt out with an eslint-disable-next-line adk-media/require-engine-peers comment + reason.',\n },\n },\n defaultOptions: [{ ignore: [] }],\n create(context, [options]) {\n const ignore = new Set(options?.ignore ?? [])\n\n /** SheetJS ships only from its CDN tarball, so the install hint must not say the registry. */\n const installHint = (peer: string): string =>\n peer === 'xlsx'\n ? 'pnpm add xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz'\n : `pnpm add ${peer}`\n\n const checkSource = (source: string, reportNode: TSESTree.Node): void => {\n const peers = peersForSubpath(source)\n if (!peers) return\n const engine = source.slice(source.lastIndexOf('/') + 1)\n for (const peer of peers) {\n if (ignore.has(peer)) continue\n if (!activePeerResolver(peer, context.filename)) {\n context.report({\n node: reportNode,\n messageId: 'missingPeer',\n data: { engine, peer, install: installHint(peer) },\n })\n }\n }\n }\n\n return {\n // Static value/type import of an engine subpath.\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value === 'string') checkSource(node.source.value, node.source)\n },\n // The canonical resolver form: import('@nhtio/adk/batteries/media/engines/…').\n ImportExpression(node: TSESTree.ImportExpression) {\n if (node.source.type === 'Literal' && typeof node.source.value === 'string') {\n checkSource(node.source.value, node.source)\n }\n },\n }\n },\n})\n\n// ── plugin assembly ──────────────────────────────────────────────────────────\n\n/**\n * Map of rule id (without the `adk-media/` plugin prefix) to its rule object. Registered on\n * the plugin as `rules`, so configs reference them as `adk-media/{id}`.\n */\nexport const rules = {\n 'prefer-engine-resolver': preferEngineResolver,\n 'no-shadowed-engine': noShadowedEngine,\n 'augment-contracts-module': augmentContractsModule,\n 'require-engine-peers': requireEnginePeers,\n} satisfies FlatConfig.Plugin['rules']\n\n/**\n * The media battery's ESLint plugin object. Register under the `adk-media` namespace:\n * `plugins: { 'adk-media': plugin }`.\n */\nexport const plugin: FlatConfig.Plugin = {\n meta: { name: '@nhtio/adk/batteries/media/lint', version: __VERSION__ },\n rules,\n}\n\nconst recommendedRules: NonNullable<FlatConfig.Config['rules']> = Object.fromEntries(\n Object.keys(rules).map((id) => [`adk-media/${id}`, 'error'])\n)\n\n/**\n * Named config presets. `recommended` enables every rule at `error` and registers the plugin\n * under the `adk-media` namespace — spread it into a flat config to adopt the full set.\n */\nexport const configs = {\n recommended: {\n name: '@nhtio/adk/batteries/media/lint/recommended',\n plugins: { 'adk-media': plugin },\n rules: recommendedRules,\n } satisfies FlatConfig.Config,\n}\n\n/**\n * Default export bundles the plugin and its config presets, mirroring the shape ESLint flat\n * configs expect from a plugin module.\n */\nexport default { plugin, rules, configs }\n"],"mappings":"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"}
|
package/batteries/media/lint.mjs
CHANGED
|
@@ -203,7 +203,8 @@ var BUNDLED_SUMMARIES = {
|
|
|
203
203
|
"resize",
|
|
204
204
|
"rotate",
|
|
205
205
|
"flip",
|
|
206
|
-
"strip_metadata"
|
|
206
|
+
"strip_metadata",
|
|
207
|
+
"annotate"
|
|
207
208
|
],
|
|
208
209
|
encodes: [
|
|
209
210
|
"png",
|
|
@@ -535,7 +536,7 @@ var rules = {
|
|
|
535
536
|
var plugin = {
|
|
536
537
|
meta: {
|
|
537
538
|
name: "@nhtio/adk/batteries/media/lint",
|
|
538
|
-
version: "0.1.0-master-
|
|
539
|
+
version: "0.1.0-master-cd595e6f"
|
|
539
540
|
},
|
|
540
541
|
rules
|
|
541
542
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.mjs","names":[],"sources":["../../../src/batteries/media/lint.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/media/lint\n *\n * ESLint rules for consumers of the media pipeline battery: machine-checkable enforcement of\n * the engine-composition contracts implementors are most likely to get wrong.\n *\n * @remarks\n * Battery-scoped rules ship with the battery, not with the core `@nhtio/adk/eslint` plugin —\n * they only matter to deployments that compose this battery, and they version with the\n * battery's own API. The rules are report-only (no autofix); carve out a deliberate exception\n * with an inline `// eslint-disable-next-line adk-media/{rule} -- {reason}` comment.\n *\n * `@typescript-eslint/utils` and `eslint` are OPTIONAL peer dependencies of `@nhtio/adk` —\n * installed only by consumers who lint with this plugin. The battery never imports this\n * module at runtime.\n *\n * @example Flat config\n * ```ts\n * import adkMedia from '@nhtio/adk/batteries/media/lint'\n *\n * export default [\n * { plugins: { 'adk-media': adkMedia.plugin }, rules: adkMedia.configs.recommended.rules },\n * ]\n * ```\n */\n\nimport { createRequire } from 'node:module'\nimport { ESLintUtils } from '@typescript-eslint/utils'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'\n\nconst createRule = ESLintUtils.RuleCreator(\n (name) => `https://adk.nht.io/batteries/media/lint#${name}`\n)\n\n// ── prefer-engine-resolver ───────────────────────────────────────────────────\n\nconst ENGINE_SUBPATH = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\//\n\n/**\n * Flags a static value import of a bundled engine subpath. The documented canonical supply\n * form is the dynamic-import resolver, which keeps the engine wrapper module out of every\n * bundle that merely might use it. Type-only imports are fine.\n */\nconst preferEngineResolver = createRule({\n name: 'prefer-engine-resolver',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Supply bundled media engines as dynamic-import resolvers, not static imports — a static import puts the engine wrapper in every bundle, even when the engine is conditional.',\n },\n schema: [],\n messages: {\n preferResolver:\n \"Import bundled engines lazily: supply `() => import('{{source}}').then((m) => m.{{hint}}(…))` in the engines array instead of a static import. Static imports put the engine wrapper module in every bundle. Opt out with an eslint-disable-next-line adk-media/prefer-engine-resolver comment + reason.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value !== 'string') return\n if (!ENGINE_SUBPATH.test(node.source.value)) return\n if (node.importKind === 'type') return\n const valueSpecifiers = node.specifiers.filter(\n (s) => !(s.type === 'ImportSpecifier' && s.importKind === 'type')\n )\n if (valueSpecifiers.length === 0) return\n const first = valueSpecifiers[0]\n const hint =\n first.type === 'ImportSpecifier' && first.imported.type === 'Identifier'\n ? first.imported.name\n : 'engineFactory'\n context.report({\n node,\n messageId: 'preferResolver',\n data: { source: node.source.value, hint },\n })\n },\n }\n },\n})\n\n// ── no-shadowed-engine ───────────────────────────────────────────────────────\n\n/** A statically-derived capability summary for one engines-array element. */\nexport interface EngineSummary {\n /** Display label for the diagnostic. */\n label: string\n /** Mutate groups: input patterns, ops, encodes. */\n mutates: Array<{ over: string[]; ops: string[]; encodes: string[] }>\n /** Convert groups: input patterns, target tokens. */\n converts: Array<{ from: string[]; to: string[] }>\n /** Edit groups: input patterns, ops. */\n edits: Array<{ over: string[]; ops: string[] }>\n}\n\nconst SHEET_OPS = [\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\nconst SHEET_WRITE_TARGETS = [\n 'xlsx',\n 'xlsm',\n 'xlsb',\n 'xls',\n 'ods',\n 'fods',\n 'csv',\n 'txt',\n 'html',\n 'rtf',\n 'sylk',\n 'dif',\n 'dbf',\n 'numbers',\n 'json',\n]\n\nconst SHEET_READ_MIMES = [\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-excel.sheet.macroEnabled.12',\n 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',\n 'application/vnd.ms-excel',\n 'application/vnd.oasis.opendocument.spreadsheet',\n 'application/vnd.oasis.opendocument.spreadsheet-flat-xml',\n 'text/csv',\n 'application/x-iwork-numbers-sffnumbers',\n 'application/x-sylk',\n 'application/x-dif',\n 'application/x-dbf',\n]\n\n/**\n * Known declarations of the bundled engine factories, for shadow analysis. An ESLint rule\n * cannot execute the factories it lints, so this table mirrors their declarations by hand —\n * and is pinned against the live factories by a drift test (`lint_drift.node.spec.ts`).\n * Exported for that test only.\n */\nexport const BUNDLED_SUMMARIES: Record<string, EngineSummary> = {\n dataEngine: {\n label: 'dataEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: ['txt', 'md', 'json', 'yaml', 'csv', 'html'] },\n { from: ['application/json'], to: ['yaml', 'txt', 'csv'] },\n { from: ['application/yaml'], to: ['json'] },\n { from: ['text/csv'], to: ['json'] },\n ],\n edits: [],\n },\n exceljsEngine: {\n label: 'exceljsEngine',\n mutates: [],\n converts: [{ from: ['application/x-adk-empty'], to: ['xlsx'] }],\n edits: [\n {\n over: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],\n ops: SHEET_OPS,\n },\n ],\n },\n jimpEngine: {\n label: 'jimpEngine',\n mutates: [\n {\n over: ['image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/tiff'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'],\n },\n ],\n converts: [\n { from: ['application/x-adk-empty'], to: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'] },\n ],\n edits: [],\n },\n sharpEngine: {\n label: 'sharpEngine',\n mutates: [\n {\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n converts: [\n {\n from: ['application/x-adk-empty'],\n to: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n edits: [],\n },\n sheetjsEngine: {\n label: 'sheetjsEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: SHEET_WRITE_TARGETS },\n { from: SHEET_READ_MIMES, to: SHEET_WRITE_TARGETS },\n ],\n edits: [{ over: SHEET_READ_MIMES, ops: SHEET_OPS }],\n },\n}\n\nconst literalStrings = (node: TSESTree.Node | undefined): string[] | undefined => {\n if (!node || node.type !== 'ArrayExpression') return undefined\n const out: string[] = []\n for (const el of node.elements) {\n if (!el || el.type !== 'Literal' || typeof el.value !== 'string') return undefined\n out.push(el.value)\n }\n return out\n}\n\nconst propOf = (obj: TSESTree.ObjectExpression, name: string): TSESTree.Node | undefined =>\n obj.properties.find(\n (p): p is TSESTree.Property =>\n p.type === 'Property' && !p.computed && p.key.type === 'Identifier' && p.key.name === name\n )?.value\n\n/** Find the bundled factory name referenced by an element (direct call or resolver arrow). */\nconst bundledFactoryName = (node: TSESTree.Node): string | undefined => {\n if (\n node.type === 'CallExpression' &&\n node.callee.type === 'Identifier' &&\n node.callee.name in BUNDLED_SUMMARIES\n ) {\n return node.callee.name\n }\n // Resolver forms: () => …; scan the body for m.jimpEngine(…) / jimpEngine(…).\n if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {\n let found: string | undefined\n const visit = (n: TSESTree.Node): void => {\n if (found) return\n if (n.type === 'CallExpression') {\n if (n.callee.type === 'Identifier' && n.callee.name in BUNDLED_SUMMARIES) {\n found = n.callee.name\n } else if (\n n.callee.type === 'MemberExpression' &&\n n.callee.property.type === 'Identifier' &&\n n.callee.property.name in BUNDLED_SUMMARIES\n ) {\n found = n.callee.property.name\n }\n }\n for (const key of Object.keys(n)) {\n if (key === 'parent') continue\n const value = (n as unknown as Record<string, unknown>)[key]\n const children = Array.isArray(value) ? value : [value]\n for (const child of children) {\n if (!child || typeof child !== 'object') continue\n const childNode = child as TSESTree.Node\n if (typeof childNode.type !== 'string') continue\n visit(childNode)\n }\n }\n }\n visit(node.body)\n return found\n }\n return undefined\n}\n\n/** Derive a capability summary from an element, or undefined when not statically known. */\nconst summarize = (node: TSESTree.Node): EngineSummary | undefined => {\n const factory = bundledFactoryName(node)\n if (factory) return BUNDLED_SUMMARIES[factory]\n if (node.type !== 'ObjectExpression') return undefined\n const idNode = propOf(node, 'id')\n const label =\n idNode?.type === 'Literal' && typeof idNode.value === 'string' ? idNode.value : 'engine'\n const summary: EngineSummary = { label, mutates: [], converts: [], edits: [] }\n const mutates = propOf(node, 'mutates')\n if (mutates) {\n if (mutates.type !== 'ArrayExpression') return undefined\n for (const el of mutates.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n const encodes = literalStrings(propOf(el, 'encodes'))\n if (!over || !ops || !encodes) return undefined\n summary.mutates.push({ over, ops, encodes })\n }\n }\n const converts = propOf(node, 'converts')\n if (converts) {\n if (converts.type !== 'ArrayExpression') return undefined\n for (const el of converts.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const from = literalStrings(propOf(el, 'from'))\n const to = literalStrings(propOf(el, 'to'))\n if (!from || !to) return undefined\n summary.converts.push({ from, to })\n }\n }\n const edits = propOf(node, 'edits')\n if (edits) {\n if (edits.type !== 'ArrayExpression') return undefined\n for (const el of edits.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n if (!over || !ops) return undefined\n summary.edits.push({ over, ops })\n }\n }\n if (summary.mutates.length + summary.converts.length + summary.edits.length === 0) {\n return undefined\n }\n return summary\n}\n\nconst patternCovers = (broad: string, narrow: string): boolean => {\n if (broad === narrow) return true\n if (broad.endsWith('/*')) return narrow.startsWith(broad.slice(0, -1))\n return false\n}\n\nconst patternsCover = (broad: string[], narrow: string[]): boolean =>\n narrow.every((n) => broad.some((b) => patternCovers(b, n)))\n\nconst subset = (sup: string[], sub: string[]): boolean => sub.every((s) => sup.includes(s))\n\n/** `true` when EVERY capability of `later` is subsumed by some capability of `earlier`. */\nconst shadows = (earlier: EngineSummary, later: EngineSummary): boolean => {\n if (later.mutates.length + later.converts.length + later.edits.length === 0) return false\n const mutatesCovered = later.mutates.every((lm) =>\n earlier.mutates.some(\n (em) =>\n patternsCover(em.over, lm.over) && subset(em.ops, lm.ops) && subset(em.encodes, lm.encodes)\n )\n )\n const convertsCovered = later.converts.every((lc) =>\n earlier.converts.some((ec) => patternsCover(ec.from, lc.from) && subset(ec.to, lc.to))\n )\n const editsCovered = later.edits.every((le) =>\n earlier.edits.some((ee) => patternsCover(ee.over, le.over) && subset(ee.ops, le.ops))\n )\n return mutatesCovered && convertsCovered && editsCovered\n}\n\n/**\n * Flags an engines-array element whose statically-known capabilities are entirely covered by\n * an EARLIER element — dispatch is first-capable-wins, so the later engine is dead code.\n */\nconst noShadowedEngine = createRule({\n name: 'no-shadowed-engine',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'An engine whose declared capabilities are a subset of an earlier engine in the array can never be selected — first-capable-wins dispatch makes it dead code. Reorder (narrow before broad) or remove it.',\n },\n schema: [],\n messages: {\n shadowed:\n 'Engine \"{{later}}\" can never be selected: \"{{earlier}}\" appears earlier in the array and declares a superset of its capabilities (dispatch is first-capable-wins). Put the narrower engine first, or remove it. Opt out with an eslint-disable-next-line adk-media/no-shadowed-engine comment + reason.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression) {\n if (node.callee.type !== 'Identifier' || node.callee.name !== 'createMediaPipeline') {\n return\n }\n const config = node.arguments[0]\n if (!config || config.type !== 'ObjectExpression') return\n const engines = propOf(config, 'engines')\n if (!engines || engines.type !== 'ArrayExpression') return\n const summaries = engines.elements.map((el) => (el ? summarize(el) : undefined))\n for (let i = 1; i < summaries.length; i++) {\n const later = summaries[i]\n if (!later) continue\n for (let j = 0; j < i; j++) {\n const earlier = summaries[j]\n if (!earlier) continue\n if (shadows(earlier, later)) {\n context.report({\n node: engines.elements[i]!,\n messageId: 'shadowed',\n data: { earlier: earlier.label, later: later.label },\n })\n break\n }\n }\n }\n },\n }\n },\n})\n\n// ── augment-contracts-module ─────────────────────────────────────────────────\n\nconst CONTRACTS_SUBPATH = '@nhtio/adk/batteries/media/contracts'\n\n/**\n * Flags a `ConvertOptions` declaration-merging block whose module specifier is not the\n * contracts subpath. Augmenting the barrel (or any other module) silently does nothing —\n * the keys never merge, and the typo costs hours.\n */\nconst augmentContractsModule = createRule({\n name: 'augment-contracts-module',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'ConvertOptions augmentation must target the contracts subpath — declaration merging against any other module specifier silently fails to merge.',\n },\n schema: [],\n messages: {\n wrongModule:\n 'This ConvertOptions augmentation targets \"{{actual}}\", so it will silently never merge. Declaration merging must target the module that declares the interface: declare module \\'{{expected}}\\'.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n TSModuleDeclaration(node: TSESTree.TSModuleDeclaration) {\n if (node.global) return\n if (node.id.type !== 'Literal' || typeof node.id.value !== 'string') return\n const specifier = node.id.value\n if (specifier === CONTRACTS_SUBPATH || specifier.endsWith('/media/contracts')) return\n // Only flag specifiers that are plausibly aimed at this battery.\n if (!specifier.includes('media') && !specifier.includes('@nhtio/adk')) return\n const body = node.body\n if (!body || body.type !== 'TSModuleBlock') return\n const declaresConvertOptions = body.body.some(\n (stmt) => stmt.type === 'TSInterfaceDeclaration' && stmt.id.name === 'ConvertOptions'\n )\n if (!declaresConvertOptions) return\n context.report({\n node: node.id,\n messageId: 'wrongModule',\n data: { actual: specifier, expected: CONTRACTS_SUBPATH },\n })\n },\n }\n },\n})\n\n// ── require-engine-peers ─────────────────────────────────────────────────────\n\n/**\n * The optional peer dependencies each bundled engine subpath lazily imports at runtime.\n * Keyed by the engine's subpath suffix (after `engines/`). An engine with no external peer\n * (soffice, fs_workspace) is absent — there's nothing to install. Kept in lockstep with the\n * engines' actual `import(...)` calls by `engine_peers_drift.node.spec.ts`.\n */\nexport const ENGINE_PEERS: Record<string, readonly string[]> = {\n jimp: ['jimp'],\n sharp: ['sharp'],\n sheetjs: ['xlsx'],\n exceljs: ['exceljs'],\n data: ['js-yaml', 'papaparse'],\n tesseract_js: ['tesseract.js'],\n audio_decode: ['audio-decode'],\n transformers_asr: ['@huggingface/transformers'],\n execa_executor: ['execa'],\n}\n\n/** Map a bundled engine subpath to its peer list, or undefined when it isn't a known engine. */\nconst peersForSubpath = (source: string): readonly string[] | undefined => {\n const m = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\/([a-z_]+)$/.exec(source)\n if (!m) return undefined\n return ENGINE_PEERS[m[1]]\n}\n\n/**\n * Flags an import of a bundled engine subpath whose optional peer dependency cannot be\n * resolved from the linting file — the \"I composed `sheetjsEngine()` but never installed\n * `xlsx`, and now my pipeline throws `E_INVALID_MEDIA_PIPELINE_CONFIG` at the first sheet\n * op\" footgun, caught at lint time instead of runtime. Resolution uses Node's resolver from\n * the file's own directory, so it honors the consumer's real `node_modules` layout.\n *\n * Reports once per missing peer per engine import (whether the import is a static value\n * import or a dynamic-import resolver — both reference the engine and both need the peer).\n */\n/**\n * The peer-resolution probe: returns `true` when `peer` resolves from `fromFile`. Defaults to\n * Node's resolver anchored at the linted file (so it sees the consumer's `node_modules`).\n * Exposed as a settable seam so the rule's spec can simulate installed/missing peers without\n * depending on the test runner's own `node_modules` layout — production never sets it.\n */\nexport type PeerResolver = (peer: string, fromFile: string) => boolean\n\nconst defaultPeerResolver: PeerResolver = (peer, fromFile) => {\n try {\n createRequire(fromFile).resolve(peer)\n return true\n } catch {\n return false\n }\n}\n\nlet activePeerResolver: PeerResolver = defaultPeerResolver\n\n/** Override the peer resolver (spec-only seam). Pass nothing to restore the Node default. */\nexport const setPeerResolverForTesting = (resolver?: PeerResolver): void => {\n activePeerResolver = resolver ?? defaultPeerResolver\n}\n\nconst requireEnginePeers = createRule<[{ ignore?: readonly string[] }], 'missingPeer'>({\n name: 'require-engine-peers',\n meta: {\n type: 'problem',\n docs: {\n description:\n \"A bundled media engine's optional peer dependency must be installed where it's composed — otherwise the pipeline throws at first use, not at construction.\",\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Peer package names to skip (e.g. one resolved via a custom loader the linter cannot see).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingPeer:\n 'The \"{{engine}}\" media engine requires the optional peer \"{{peer}}\", which cannot be resolved from this file. Install it ({{install}}) or the pipeline will throw E_INVALID_MEDIA_PIPELINE_CONFIG the first time this engine runs. Opt out with an eslint-disable-next-line adk-media/require-engine-peers comment + reason.',\n },\n },\n defaultOptions: [{ ignore: [] }],\n create(context, [options]) {\n const ignore = new Set(options?.ignore ?? [])\n\n /** SheetJS ships only from its CDN tarball, so the install hint must not say the registry. */\n const installHint = (peer: string): string =>\n peer === 'xlsx'\n ? 'pnpm add xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz'\n : `pnpm add ${peer}`\n\n const checkSource = (source: string, reportNode: TSESTree.Node): void => {\n const peers = peersForSubpath(source)\n if (!peers) return\n const engine = source.slice(source.lastIndexOf('/') + 1)\n for (const peer of peers) {\n if (ignore.has(peer)) continue\n if (!activePeerResolver(peer, context.filename)) {\n context.report({\n node: reportNode,\n messageId: 'missingPeer',\n data: { engine, peer, install: installHint(peer) },\n })\n }\n }\n }\n\n return {\n // Static value/type import of an engine subpath.\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value === 'string') checkSource(node.source.value, node.source)\n },\n // The canonical resolver form: import('@nhtio/adk/batteries/media/engines/…').\n ImportExpression(node: TSESTree.ImportExpression) {\n if (node.source.type === 'Literal' && typeof node.source.value === 'string') {\n checkSource(node.source.value, node.source)\n }\n },\n }\n },\n})\n\n// ── plugin assembly ──────────────────────────────────────────────────────────\n\n/**\n * Map of rule id (without the `adk-media/` plugin prefix) to its rule object. Registered on\n * the plugin as `rules`, so configs reference them as `adk-media/{id}`.\n */\nexport const rules = {\n 'prefer-engine-resolver': preferEngineResolver,\n 'no-shadowed-engine': noShadowedEngine,\n 'augment-contracts-module': augmentContractsModule,\n 'require-engine-peers': requireEnginePeers,\n} satisfies FlatConfig.Plugin['rules']\n\n/**\n * The media battery's ESLint plugin object. Register under the `adk-media` namespace:\n * `plugins: { 'adk-media': plugin }`.\n */\nexport const plugin: FlatConfig.Plugin = {\n meta: { name: '@nhtio/adk/batteries/media/lint', version: __VERSION__ },\n rules,\n}\n\nconst recommendedRules: NonNullable<FlatConfig.Config['rules']> = Object.fromEntries(\n Object.keys(rules).map((id) => [`adk-media/${id}`, 'error'])\n)\n\n/**\n * Named config presets. `recommended` enables every rule at `error` and registers the plugin\n * under the `adk-media` namespace — spread it into a flat config to adopt the full set.\n */\nexport const configs = {\n recommended: {\n name: '@nhtio/adk/batteries/media/lint/recommended',\n plugins: { 'adk-media': plugin },\n rules: recommendedRules,\n } satisfies FlatConfig.Config,\n}\n\n/**\n * Default export bundles the plugin and its config presets, mirroring the shape ESLint flat\n * configs expect from a plugin module.\n */\nexport default { plugin, rules, configs }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lint.mjs","names":[],"sources":["../../../src/batteries/media/lint.ts"],"sourcesContent":["/**\n * @module @nhtio/adk/batteries/media/lint\n *\n * ESLint rules for consumers of the media pipeline battery: machine-checkable enforcement of\n * the engine-composition contracts implementors are most likely to get wrong.\n *\n * @remarks\n * Battery-scoped rules ship with the battery, not with the core `@nhtio/adk/eslint` plugin —\n * they only matter to deployments that compose this battery, and they version with the\n * battery's own API. The rules are report-only (no autofix); carve out a deliberate exception\n * with an inline `// eslint-disable-next-line adk-media/{rule} -- {reason}` comment.\n *\n * `@typescript-eslint/utils` and `eslint` are OPTIONAL peer dependencies of `@nhtio/adk` —\n * installed only by consumers who lint with this plugin. The battery never imports this\n * module at runtime.\n *\n * @example Flat config\n * ```ts\n * import adkMedia from '@nhtio/adk/batteries/media/lint'\n *\n * export default [\n * { plugins: { 'adk-media': adkMedia.plugin }, rules: adkMedia.configs.recommended.rules },\n * ]\n * ```\n */\n\nimport { createRequire } from 'node:module'\nimport { ESLintUtils } from '@typescript-eslint/utils'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { FlatConfig } from '@typescript-eslint/utils/ts-eslint'\n\nconst createRule = ESLintUtils.RuleCreator(\n (name) => `https://adk.nht.io/batteries/media/lint#${name}`\n)\n\n// ── prefer-engine-resolver ───────────────────────────────────────────────────\n\nconst ENGINE_SUBPATH = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\//\n\n/**\n * Flags a static value import of a bundled engine subpath. The documented canonical supply\n * form is the dynamic-import resolver, which keeps the engine wrapper module out of every\n * bundle that merely might use it. Type-only imports are fine.\n */\nconst preferEngineResolver = createRule({\n name: 'prefer-engine-resolver',\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Supply bundled media engines as dynamic-import resolvers, not static imports — a static import puts the engine wrapper in every bundle, even when the engine is conditional.',\n },\n schema: [],\n messages: {\n preferResolver:\n \"Import bundled engines lazily: supply `() => import('{{source}}').then((m) => m.{{hint}}(…))` in the engines array instead of a static import. Static imports put the engine wrapper module in every bundle. Opt out with an eslint-disable-next-line adk-media/prefer-engine-resolver comment + reason.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value !== 'string') return\n if (!ENGINE_SUBPATH.test(node.source.value)) return\n if (node.importKind === 'type') return\n const valueSpecifiers = node.specifiers.filter(\n (s) => !(s.type === 'ImportSpecifier' && s.importKind === 'type')\n )\n if (valueSpecifiers.length === 0) return\n const first = valueSpecifiers[0]\n const hint =\n first.type === 'ImportSpecifier' && first.imported.type === 'Identifier'\n ? first.imported.name\n : 'engineFactory'\n context.report({\n node,\n messageId: 'preferResolver',\n data: { source: node.source.value, hint },\n })\n },\n }\n },\n})\n\n// ── no-shadowed-engine ───────────────────────────────────────────────────────\n\n/** A statically-derived capability summary for one engines-array element. */\nexport interface EngineSummary {\n /** Display label for the diagnostic. */\n label: string\n /** Mutate groups: input patterns, ops, encodes. */\n mutates: Array<{ over: string[]; ops: string[]; encodes: string[] }>\n /** Convert groups: input patterns, target tokens. */\n converts: Array<{ from: string[]; to: string[] }>\n /** Edit groups: input patterns, ops. */\n edits: Array<{ over: string[]; ops: string[] }>\n}\n\nconst SHEET_OPS = [\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\nconst SHEET_WRITE_TARGETS = [\n 'xlsx',\n 'xlsm',\n 'xlsb',\n 'xls',\n 'ods',\n 'fods',\n 'csv',\n 'txt',\n 'html',\n 'rtf',\n 'sylk',\n 'dif',\n 'dbf',\n 'numbers',\n 'json',\n]\n\nconst SHEET_READ_MIMES = [\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-excel.sheet.macroEnabled.12',\n 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',\n 'application/vnd.ms-excel',\n 'application/vnd.oasis.opendocument.spreadsheet',\n 'application/vnd.oasis.opendocument.spreadsheet-flat-xml',\n 'text/csv',\n 'application/x-iwork-numbers-sffnumbers',\n 'application/x-sylk',\n 'application/x-dif',\n 'application/x-dbf',\n]\n\n/**\n * Known declarations of the bundled engine factories, for shadow analysis. An ESLint rule\n * cannot execute the factories it lints, so this table mirrors their declarations by hand —\n * and is pinned against the live factories by a drift test (`lint_drift.node.spec.ts`).\n * Exported for that test only.\n */\nexport const BUNDLED_SUMMARIES: Record<string, EngineSummary> = {\n dataEngine: {\n label: 'dataEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: ['txt', 'md', 'json', 'yaml', 'csv', 'html'] },\n { from: ['application/json'], to: ['yaml', 'txt', 'csv'] },\n { from: ['application/yaml'], to: ['json'] },\n { from: ['text/csv'], to: ['json'] },\n ],\n edits: [],\n },\n exceljsEngine: {\n label: 'exceljsEngine',\n mutates: [],\n converts: [{ from: ['application/x-adk-empty'], to: ['xlsx'] }],\n edits: [\n {\n over: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],\n ops: SHEET_OPS,\n },\n ],\n },\n jimpEngine: {\n label: 'jimpEngine',\n mutates: [\n {\n over: ['image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/tiff'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'],\n },\n ],\n converts: [\n { from: ['application/x-adk-empty'], to: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'] },\n ],\n edits: [],\n },\n sharpEngine: {\n label: 'sharpEngine',\n mutates: [\n {\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata', 'annotate'],\n encodes: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n converts: [\n {\n from: ['application/x-adk-empty'],\n to: ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'],\n },\n ],\n edits: [],\n },\n sheetjsEngine: {\n label: 'sheetjsEngine',\n mutates: [],\n converts: [\n { from: ['application/x-adk-empty'], to: SHEET_WRITE_TARGETS },\n { from: SHEET_READ_MIMES, to: SHEET_WRITE_TARGETS },\n ],\n edits: [{ over: SHEET_READ_MIMES, ops: SHEET_OPS }],\n },\n}\n\nconst literalStrings = (node: TSESTree.Node | undefined): string[] | undefined => {\n if (!node || node.type !== 'ArrayExpression') return undefined\n const out: string[] = []\n for (const el of node.elements) {\n if (!el || el.type !== 'Literal' || typeof el.value !== 'string') return undefined\n out.push(el.value)\n }\n return out\n}\n\nconst propOf = (obj: TSESTree.ObjectExpression, name: string): TSESTree.Node | undefined =>\n obj.properties.find(\n (p): p is TSESTree.Property =>\n p.type === 'Property' && !p.computed && p.key.type === 'Identifier' && p.key.name === name\n )?.value\n\n/** Find the bundled factory name referenced by an element (direct call or resolver arrow). */\nconst bundledFactoryName = (node: TSESTree.Node): string | undefined => {\n if (\n node.type === 'CallExpression' &&\n node.callee.type === 'Identifier' &&\n node.callee.name in BUNDLED_SUMMARIES\n ) {\n return node.callee.name\n }\n // Resolver forms: () => …; scan the body for m.jimpEngine(…) / jimpEngine(…).\n if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {\n let found: string | undefined\n const visit = (n: TSESTree.Node): void => {\n if (found) return\n if (n.type === 'CallExpression') {\n if (n.callee.type === 'Identifier' && n.callee.name in BUNDLED_SUMMARIES) {\n found = n.callee.name\n } else if (\n n.callee.type === 'MemberExpression' &&\n n.callee.property.type === 'Identifier' &&\n n.callee.property.name in BUNDLED_SUMMARIES\n ) {\n found = n.callee.property.name\n }\n }\n for (const key of Object.keys(n)) {\n if (key === 'parent') continue\n const value = (n as unknown as Record<string, unknown>)[key]\n const children = Array.isArray(value) ? value : [value]\n for (const child of children) {\n if (!child || typeof child !== 'object') continue\n const childNode = child as TSESTree.Node\n if (typeof childNode.type !== 'string') continue\n visit(childNode)\n }\n }\n }\n visit(node.body)\n return found\n }\n return undefined\n}\n\n/** Derive a capability summary from an element, or undefined when not statically known. */\nconst summarize = (node: TSESTree.Node): EngineSummary | undefined => {\n const factory = bundledFactoryName(node)\n if (factory) return BUNDLED_SUMMARIES[factory]\n if (node.type !== 'ObjectExpression') return undefined\n const idNode = propOf(node, 'id')\n const label =\n idNode?.type === 'Literal' && typeof idNode.value === 'string' ? idNode.value : 'engine'\n const summary: EngineSummary = { label, mutates: [], converts: [], edits: [] }\n const mutates = propOf(node, 'mutates')\n if (mutates) {\n if (mutates.type !== 'ArrayExpression') return undefined\n for (const el of mutates.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n const encodes = literalStrings(propOf(el, 'encodes'))\n if (!over || !ops || !encodes) return undefined\n summary.mutates.push({ over, ops, encodes })\n }\n }\n const converts = propOf(node, 'converts')\n if (converts) {\n if (converts.type !== 'ArrayExpression') return undefined\n for (const el of converts.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const from = literalStrings(propOf(el, 'from'))\n const to = literalStrings(propOf(el, 'to'))\n if (!from || !to) return undefined\n summary.converts.push({ from, to })\n }\n }\n const edits = propOf(node, 'edits')\n if (edits) {\n if (edits.type !== 'ArrayExpression') return undefined\n for (const el of edits.elements) {\n if (!el || el.type !== 'ObjectExpression') return undefined\n const over = literalStrings(propOf(el, 'over'))\n const ops = literalStrings(propOf(el, 'ops'))\n if (!over || !ops) return undefined\n summary.edits.push({ over, ops })\n }\n }\n if (summary.mutates.length + summary.converts.length + summary.edits.length === 0) {\n return undefined\n }\n return summary\n}\n\nconst patternCovers = (broad: string, narrow: string): boolean => {\n if (broad === narrow) return true\n if (broad.endsWith('/*')) return narrow.startsWith(broad.slice(0, -1))\n return false\n}\n\nconst patternsCover = (broad: string[], narrow: string[]): boolean =>\n narrow.every((n) => broad.some((b) => patternCovers(b, n)))\n\nconst subset = (sup: string[], sub: string[]): boolean => sub.every((s) => sup.includes(s))\n\n/** `true` when EVERY capability of `later` is subsumed by some capability of `earlier`. */\nconst shadows = (earlier: EngineSummary, later: EngineSummary): boolean => {\n if (later.mutates.length + later.converts.length + later.edits.length === 0) return false\n const mutatesCovered = later.mutates.every((lm) =>\n earlier.mutates.some(\n (em) =>\n patternsCover(em.over, lm.over) && subset(em.ops, lm.ops) && subset(em.encodes, lm.encodes)\n )\n )\n const convertsCovered = later.converts.every((lc) =>\n earlier.converts.some((ec) => patternsCover(ec.from, lc.from) && subset(ec.to, lc.to))\n )\n const editsCovered = later.edits.every((le) =>\n earlier.edits.some((ee) => patternsCover(ee.over, le.over) && subset(ee.ops, le.ops))\n )\n return mutatesCovered && convertsCovered && editsCovered\n}\n\n/**\n * Flags an engines-array element whose statically-known capabilities are entirely covered by\n * an EARLIER element — dispatch is first-capable-wins, so the later engine is dead code.\n */\nconst noShadowedEngine = createRule({\n name: 'no-shadowed-engine',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'An engine whose declared capabilities are a subset of an earlier engine in the array can never be selected — first-capable-wins dispatch makes it dead code. Reorder (narrow before broad) or remove it.',\n },\n schema: [],\n messages: {\n shadowed:\n 'Engine \"{{later}}\" can never be selected: \"{{earlier}}\" appears earlier in the array and declares a superset of its capabilities (dispatch is first-capable-wins). Put the narrower engine first, or remove it. Opt out with an eslint-disable-next-line adk-media/no-shadowed-engine comment + reason.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression) {\n if (node.callee.type !== 'Identifier' || node.callee.name !== 'createMediaPipeline') {\n return\n }\n const config = node.arguments[0]\n if (!config || config.type !== 'ObjectExpression') return\n const engines = propOf(config, 'engines')\n if (!engines || engines.type !== 'ArrayExpression') return\n const summaries = engines.elements.map((el) => (el ? summarize(el) : undefined))\n for (let i = 1; i < summaries.length; i++) {\n const later = summaries[i]\n if (!later) continue\n for (let j = 0; j < i; j++) {\n const earlier = summaries[j]\n if (!earlier) continue\n if (shadows(earlier, later)) {\n context.report({\n node: engines.elements[i]!,\n messageId: 'shadowed',\n data: { earlier: earlier.label, later: later.label },\n })\n break\n }\n }\n }\n },\n }\n },\n})\n\n// ── augment-contracts-module ─────────────────────────────────────────────────\n\nconst CONTRACTS_SUBPATH = '@nhtio/adk/batteries/media/contracts'\n\n/**\n * Flags a `ConvertOptions` declaration-merging block whose module specifier is not the\n * contracts subpath. Augmenting the barrel (or any other module) silently does nothing —\n * the keys never merge, and the typo costs hours.\n */\nconst augmentContractsModule = createRule({\n name: 'augment-contracts-module',\n meta: {\n type: 'problem',\n docs: {\n description:\n 'ConvertOptions augmentation must target the contracts subpath — declaration merging against any other module specifier silently fails to merge.',\n },\n schema: [],\n messages: {\n wrongModule:\n 'This ConvertOptions augmentation targets \"{{actual}}\", so it will silently never merge. Declaration merging must target the module that declares the interface: declare module \\'{{expected}}\\'.',\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n TSModuleDeclaration(node: TSESTree.TSModuleDeclaration) {\n if (node.global) return\n if (node.id.type !== 'Literal' || typeof node.id.value !== 'string') return\n const specifier = node.id.value\n if (specifier === CONTRACTS_SUBPATH || specifier.endsWith('/media/contracts')) return\n // Only flag specifiers that are plausibly aimed at this battery.\n if (!specifier.includes('media') && !specifier.includes('@nhtio/adk')) return\n const body = node.body\n if (!body || body.type !== 'TSModuleBlock') return\n const declaresConvertOptions = body.body.some(\n (stmt) => stmt.type === 'TSInterfaceDeclaration' && stmt.id.name === 'ConvertOptions'\n )\n if (!declaresConvertOptions) return\n context.report({\n node: node.id,\n messageId: 'wrongModule',\n data: { actual: specifier, expected: CONTRACTS_SUBPATH },\n })\n },\n }\n },\n})\n\n// ── require-engine-peers ─────────────────────────────────────────────────────\n\n/**\n * The optional peer dependencies each bundled engine subpath lazily imports at runtime.\n * Keyed by the engine's subpath suffix (after `engines/`). An engine with no external peer\n * (soffice, fs_workspace) is absent — there's nothing to install. Kept in lockstep with the\n * engines' actual `import(...)` calls by `engine_peers_drift.node.spec.ts`.\n */\nexport const ENGINE_PEERS: Record<string, readonly string[]> = {\n jimp: ['jimp'],\n sharp: ['sharp'],\n sheetjs: ['xlsx'],\n exceljs: ['exceljs'],\n data: ['js-yaml', 'papaparse'],\n tesseract_js: ['tesseract.js'],\n audio_decode: ['audio-decode'],\n transformers_asr: ['@huggingface/transformers'],\n execa_executor: ['execa'],\n}\n\n/** Map a bundled engine subpath to its peer list, or undefined when it isn't a known engine. */\nconst peersForSubpath = (source: string): readonly string[] | undefined => {\n const m = /^@nhtio\\/adk\\/batteries\\/media\\/engines\\/([a-z_]+)$/.exec(source)\n if (!m) return undefined\n return ENGINE_PEERS[m[1]]\n}\n\n/**\n * Flags an import of a bundled engine subpath whose optional peer dependency cannot be\n * resolved from the linting file — the \"I composed `sheetjsEngine()` but never installed\n * `xlsx`, and now my pipeline throws `E_INVALID_MEDIA_PIPELINE_CONFIG` at the first sheet\n * op\" footgun, caught at lint time instead of runtime. Resolution uses Node's resolver from\n * the file's own directory, so it honors the consumer's real `node_modules` layout.\n *\n * Reports once per missing peer per engine import (whether the import is a static value\n * import or a dynamic-import resolver — both reference the engine and both need the peer).\n */\n/**\n * The peer-resolution probe: returns `true` when `peer` resolves from `fromFile`. Defaults to\n * Node's resolver anchored at the linted file (so it sees the consumer's `node_modules`).\n * Exposed as a settable seam so the rule's spec can simulate installed/missing peers without\n * depending on the test runner's own `node_modules` layout — production never sets it.\n */\nexport type PeerResolver = (peer: string, fromFile: string) => boolean\n\nconst defaultPeerResolver: PeerResolver = (peer, fromFile) => {\n try {\n createRequire(fromFile).resolve(peer)\n return true\n } catch {\n return false\n }\n}\n\nlet activePeerResolver: PeerResolver = defaultPeerResolver\n\n/** Override the peer resolver (spec-only seam). Pass nothing to restore the Node default. */\nexport const setPeerResolverForTesting = (resolver?: PeerResolver): void => {\n activePeerResolver = resolver ?? defaultPeerResolver\n}\n\nconst requireEnginePeers = createRule<[{ ignore?: readonly string[] }], 'missingPeer'>({\n name: 'require-engine-peers',\n meta: {\n type: 'problem',\n docs: {\n description:\n \"A bundled media engine's optional peer dependency must be installed where it's composed — otherwise the pipeline throws at first use, not at construction.\",\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Peer package names to skip (e.g. one resolved via a custom loader the linter cannot see).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingPeer:\n 'The \"{{engine}}\" media engine requires the optional peer \"{{peer}}\", which cannot be resolved from this file. Install it ({{install}}) or the pipeline will throw E_INVALID_MEDIA_PIPELINE_CONFIG the first time this engine runs. Opt out with an eslint-disable-next-line adk-media/require-engine-peers comment + reason.',\n },\n },\n defaultOptions: [{ ignore: [] }],\n create(context, [options]) {\n const ignore = new Set(options?.ignore ?? [])\n\n /** SheetJS ships only from its CDN tarball, so the install hint must not say the registry. */\n const installHint = (peer: string): string =>\n peer === 'xlsx'\n ? 'pnpm add xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz'\n : `pnpm add ${peer}`\n\n const checkSource = (source: string, reportNode: TSESTree.Node): void => {\n const peers = peersForSubpath(source)\n if (!peers) return\n const engine = source.slice(source.lastIndexOf('/') + 1)\n for (const peer of peers) {\n if (ignore.has(peer)) continue\n if (!activePeerResolver(peer, context.filename)) {\n context.report({\n node: reportNode,\n messageId: 'missingPeer',\n data: { engine, peer, install: installHint(peer) },\n })\n }\n }\n }\n\n return {\n // Static value/type import of an engine subpath.\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (typeof node.source.value === 'string') checkSource(node.source.value, node.source)\n },\n // The canonical resolver form: import('@nhtio/adk/batteries/media/engines/…').\n ImportExpression(node: TSESTree.ImportExpression) {\n if (node.source.type === 'Literal' && typeof node.source.value === 'string') {\n checkSource(node.source.value, node.source)\n }\n },\n }\n },\n})\n\n// ── plugin assembly ──────────────────────────────────────────────────────────\n\n/**\n * Map of rule id (without the `adk-media/` plugin prefix) to its rule object. Registered on\n * the plugin as `rules`, so configs reference them as `adk-media/{id}`.\n */\nexport const rules = {\n 'prefer-engine-resolver': preferEngineResolver,\n 'no-shadowed-engine': noShadowedEngine,\n 'augment-contracts-module': augmentContractsModule,\n 'require-engine-peers': requireEnginePeers,\n} satisfies FlatConfig.Plugin['rules']\n\n/**\n * The media battery's ESLint plugin object. Register under the `adk-media` namespace:\n * `plugins: { 'adk-media': plugin }`.\n */\nexport const plugin: FlatConfig.Plugin = {\n meta: { name: '@nhtio/adk/batteries/media/lint', version: __VERSION__ },\n rules,\n}\n\nconst recommendedRules: NonNullable<FlatConfig.Config['rules']> = Object.fromEntries(\n Object.keys(rules).map((id) => [`adk-media/${id}`, 'error'])\n)\n\n/**\n * Named config presets. `recommended` enables every rule at `error` and registers the plugin\n * under the `adk-media` namespace — spread it into a flat config to adopt the full set.\n */\nexport const configs = {\n recommended: {\n name: '@nhtio/adk/batteries/media/lint/recommended',\n plugins: { 'adk-media': plugin },\n rules: recommendedRules,\n } satisfies FlatConfig.Config,\n}\n\n/**\n * Default export bundles the plugin and its config presets, mirroring the shape ESLint flat\n * configs expect from a plugin module.\n */\nexport default { plugin, rules, configs }\n"],"mappings":"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"}
|
package/batteries/media.cjs
CHANGED
|
@@ -5,7 +5,7 @@ require("../guards.cjs");
|
|
|
5
5
|
const require_lib_utils_audio = require("../lib/utils/audio.cjs");
|
|
6
6
|
const require_batteries_media_contracts = require("./media/contracts.cjs");
|
|
7
7
|
const require_exceptions = require("../exceptions-Dlw1Jr6E.js");
|
|
8
|
-
const require_validate = require("../validate-
|
|
8
|
+
const require_validate = require("../validate-CkQI-48O.js");
|
|
9
9
|
const require_patch = require("../patch-BXX9Q0FM.js");
|
|
10
10
|
const require_formats = require("../formats-DZVuqZUN.js");
|
|
11
11
|
let _nhtio_validation = require("@nhtio/validation");
|
|
@@ -648,6 +648,10 @@ var ImageNamespace = class {
|
|
|
648
648
|
stripMetadata() {
|
|
649
649
|
return this.#chain.withOp("image.strip_metadata", {});
|
|
650
650
|
}
|
|
651
|
+
/** Draw vector primitives and text over the image. */
|
|
652
|
+
annotate(shapes) {
|
|
653
|
+
return this.#chain.withOp("image.annotate", { shapes });
|
|
654
|
+
}
|
|
651
655
|
};
|
|
652
656
|
/** `audio.*` verbs. */
|
|
653
657
|
var AudioNamespace = class {
|
|
@@ -2493,6 +2497,7 @@ var requestedOps = (request) => {
|
|
|
2493
2497
|
if (request.rotate !== void 0) ops.push("rotate");
|
|
2494
2498
|
if (request.flip) ops.push("flip");
|
|
2495
2499
|
if (request.stripMetadata) ops.push("strip_metadata");
|
|
2500
|
+
if (request.annotate) ops.push("annotate");
|
|
2496
2501
|
return ops;
|
|
2497
2502
|
};
|
|
2498
2503
|
/**
|
|
@@ -2750,7 +2755,8 @@ var IMAGE_VERBS = new Set([
|
|
|
2750
2755
|
"image.format",
|
|
2751
2756
|
"image.rotate",
|
|
2752
2757
|
"image.flip",
|
|
2753
|
-
"image.strip_metadata"
|
|
2758
|
+
"image.strip_metadata",
|
|
2759
|
+
"image.annotate"
|
|
2754
2760
|
]);
|
|
2755
2761
|
var requireImage = (ctx, verb) => {
|
|
2756
2762
|
if (!ctx.payload.mimeType.toLowerCase().startsWith("image/")) fail(verb, `image operations expect an image; the media is ${ctx.payload.mimeType}`);
|
|
@@ -2797,6 +2803,63 @@ var foldImageStep = (ctx, fused) => {
|
|
|
2797
2803
|
...fused,
|
|
2798
2804
|
stripMetadata: true
|
|
2799
2805
|
};
|
|
2806
|
+
case "image.annotate": {
|
|
2807
|
+
const shapes = args.shapes;
|
|
2808
|
+
if (!Array.isArray(shapes)) fail("image annotate", "shapes must be an array");
|
|
2809
|
+
const shapeList = shapes;
|
|
2810
|
+
for (const value of shapeList) {
|
|
2811
|
+
if (!require_guards.isObject(value) || typeof value.type !== "string") fail("image annotate", "each shape must have a type");
|
|
2812
|
+
const shape = value;
|
|
2813
|
+
const type = shape.type;
|
|
2814
|
+
if (![
|
|
2815
|
+
"rect",
|
|
2816
|
+
"line",
|
|
2817
|
+
"arrow",
|
|
2818
|
+
"ellipse",
|
|
2819
|
+
"text"
|
|
2820
|
+
].includes(type)) fail("image annotate", `unsupported shape type "${type}"`);
|
|
2821
|
+
const required = type === "rect" ? [
|
|
2822
|
+
"x",
|
|
2823
|
+
"y",
|
|
2824
|
+
"width",
|
|
2825
|
+
"height"
|
|
2826
|
+
] : type === "line" || type === "arrow" ? [
|
|
2827
|
+
"x1",
|
|
2828
|
+
"y1",
|
|
2829
|
+
"x2",
|
|
2830
|
+
"y2"
|
|
2831
|
+
] : type === "ellipse" ? [
|
|
2832
|
+
"cx",
|
|
2833
|
+
"cy",
|
|
2834
|
+
"rx",
|
|
2835
|
+
"ry"
|
|
2836
|
+
] : [
|
|
2837
|
+
"x",
|
|
2838
|
+
"y",
|
|
2839
|
+
"text"
|
|
2840
|
+
];
|
|
2841
|
+
for (const key of required) {
|
|
2842
|
+
if (!(key in shape) || key !== "text" && typeof shape[key] !== "number" || key === "text" && typeof shape[key] !== "string") fail("image annotate", `shape ${type} requires ${key}`);
|
|
2843
|
+
if (key !== "text" && !Number.isFinite(shape[key])) fail("image annotate", `${type}.${key} must be finite`);
|
|
2844
|
+
if ([
|
|
2845
|
+
"width",
|
|
2846
|
+
"height",
|
|
2847
|
+
"rx",
|
|
2848
|
+
"ry"
|
|
2849
|
+
].includes(key) && shape[key] <= 0) fail("image annotate", `${type}.${key} must be positive`);
|
|
2850
|
+
}
|
|
2851
|
+
for (const key of ["strokeWidth", "size"]) if (key in shape && (typeof shape[key] !== "number" || !Number.isFinite(shape[key]) || shape[key] <= 0)) fail("image annotate", `${type}.${key} must be a positive finite number`);
|
|
2852
|
+
for (const key of [
|
|
2853
|
+
"color",
|
|
2854
|
+
"fill",
|
|
2855
|
+
"font"
|
|
2856
|
+
]) if (key in shape && typeof shape[key] !== "string") fail("image annotate", `${type}.${key} must be text`);
|
|
2857
|
+
}
|
|
2858
|
+
return {
|
|
2859
|
+
...fused,
|
|
2860
|
+
annotate: [...fused.annotate ?? [], ...shapeList]
|
|
2861
|
+
};
|
|
2862
|
+
}
|
|
2800
2863
|
default: return fused;
|
|
2801
2864
|
}
|
|
2802
2865
|
};
|
|
@@ -2887,6 +2950,7 @@ var IMAGE_AUDIO_STEPS = [
|
|
|
2887
2950
|
["image.rotate", imageStep],
|
|
2888
2951
|
["image.flip", imageStep],
|
|
2889
2952
|
["image.strip_metadata", imageStep],
|
|
2953
|
+
["image.annotate", imageStep],
|
|
2890
2954
|
["audio.transcribe", audioTranscribeStep]
|
|
2891
2955
|
];
|
|
2892
2956
|
//#endregion
|