@akairos/pipeline 0.18.1 → 0.19.0
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/ARTICLE-THEMES.md +2 -0
- package/README.md +27 -4
- package/package.json +7 -5
- package/src/adapter-loader.ts +24 -4
- package/src/adapter-types.ts +14 -0
- package/src/article-theme.test.ts +55 -0
- package/src/article-theme.ts +10 -2
- package/src/commands/article-theme.ts +1 -1
- package/src/commands/init.ts +2 -0
- package/src/commands/publish.ts +1 -1
- package/src/commands/typeset-assets-sync.test.ts +12 -1
- package/src/commands/wechat-export.ts +9 -4
- package/src/plugin-runner.ts +10 -4
- package/src/plugin-runtime.test.ts +19 -0
- package/src/plugin-runtime.ts +11 -2
- package/src/providers/index.ts +4 -2
- package/src/runtime-package.ts +13 -6
- package/src/wechat-preview/assets/browser-dist/.vite/manifest.json +1280 -5
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/src/wechat-preview/assets/browser-dist/assets/apl-B4CMkyY2.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/asciiarmor-Df11BRmG.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/asn1-EdZsLKOL.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/asterisk-B-8jnY81.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/clike-B9uivgTg.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/clojure-BMjYHr_A.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/cmake-BQqOBYOt.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/cobol-CWcv1MsR.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/coffeescript-S37ZYGWr.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/commonlisp-DBKNyK5s.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/crystal-SjHAIU92.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/css-BnMrqG3P.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/cypher-C_CwsFkJ.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/d-pRatUO7H.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/diff-DbItnlRl.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/dockerfile-BKs6k2Af.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/dtd-DF_7sFjM.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/dylan-DwRh75JA.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/ebnf-CDyGwa7X.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/ecl-Cabwm37j.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/eiffel-CnydiIhH.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/elm-vLlmbW-K.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/erlang-BNw1qcRV.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/factor-kuTfRLto.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/fcl-Kvtd6kyn.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/forth-Ffai-XNe.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/fortran-DYz_wnZ1.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/gas-Bneqetm1.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/gherkin-heZmZLOM.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/groovy-D9Dt4D0W.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/haskell-Cw1EW3IL.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/haxe-H-WmDvRZ.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/http-DBlCnlav.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/idl-BEugSyMb.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-B13lCSuc.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BDdU9pNh.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BFLGVgsp.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BHJY0B4E.js +8 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BOnKEJxh.js +7 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BPmBcGI-.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BTVIa90Y.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BYV6TA8f.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BlVpb0dF.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BqKARoyW.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-BzHql5Rp.js +20 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-CPFEJ9fX.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-CdxKyTX6.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-CyXDvcwY.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-DA7Z4paG.js +13 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-DDQGWU_D.js +3 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-DENMoE5l.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-D_EI5vFS.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-DpuVrwze.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-IBlhKHQr.js +8 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-ifI5svkD.js +2 -0
- package/src/wechat-preview/assets/browser-dist/assets/index-vRiJxvj2.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/javascript-iXu5QeM3.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/julia-DuME0IfC.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/livescript-BwQOo05w.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/lua-VAEuO923.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/mathematica-DTrFuWx2.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/mbox-CNhZ1qSd.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/mirc-CjQqDB4T.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/mllike-CXdrOF99.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/modelica-Dc1JOy9r.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/mscgen-BA5vi2Kp.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/mumps-BT43cFF4.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/nginx-DdIZxoE0.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/nsis-LY0VT_u5.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/ntriples-BfvgReVJ.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/octave-Ck1zUtKM.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/oz-BzwKVEFT.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/pascal--L3eBynH.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/perl-CdXCOZ3F.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/pig-CevX1Tat.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/powershell-CFHJl5sT.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/properties-C78fOPTZ.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/protobuf-ChK-085T.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/pug-DeIclll2.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/puppet-DMA9R1ak.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/python-BuPzkPfP.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/q-pXgVlZs6.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/r-B6wPVr8A.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/rpm-CTu-6PCP.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/ruby-BK5aLJev.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/sas-B4kiWyti.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/scheme-C41bIUwD.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/shell-CjFT_Tl9.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/sieve-C3Gn_uJK.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/simple-mode-GW_nhZxv.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/smalltalk-CnHTOXQT.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/solr-DehyRSwq.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/sparql-DkYu6x3z.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/sql-D0XecflT.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/stex-C3f8Ysf7.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/style-Cif_gYUW.css +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/stylus-B533Al4x.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/swift-BzpIVaGY.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/tcl-DVfN8rqt.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/textile-CnDTJFAw.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/tiki-DGYXhP31.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/toml-Bm5Em-hy.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/troff-wAsdV37c.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/ttcn-CfJYG6tj.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/turtle-B1tBg_DP.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/vb-CmGdzxic.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/vbscript-BuJXcnF6.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/velocity-D8B20fx6.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/verilog-C6RDOZhf.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/vhdl-lSbBsy5d.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/webidl-ZXfAyPTL.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/{wechat-renderer-GgNrlSLi.js → wechat-renderer-CcHuq7M-.js} +83 -61
- package/src/wechat-preview/assets/browser-dist/assets/xquery-DzFWVndE.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/yacas-BJ4BC0dw.js +1 -0
- package/src/wechat-preview/assets/browser-dist/assets/z80-Hz9HOZM7.js +1 -0
- package/src/wechat-preview/assets/browser-dist/editor-export.js +1 -1
- package/src/wechat-preview/assets/browser-dist/src/wechat-preview/browser/studio/studio.html +215 -165
- package/src/wechat-preview/assets/browser-dist/studio.js +1148 -237
- package/src/wechat-preview/browser/studio/color-palettes.ts +28 -0
- package/src/wechat-preview/browser/studio/config-manager.ts +49 -0
- package/src/wechat-preview/browser/studio/milkdown-article-menu.ts +251 -0
- package/src/wechat-preview/browser/studio/myno-editor.ts +122 -0
- package/src/wechat-preview/browser/studio/studio.css +493 -250
- package/src/wechat-preview/browser/studio/studio.html +213 -163
- package/src/wechat-preview/browser/studio/studio.ts +684 -211
- package/src/wechat-preview/browser/studio/style-packs.ts +201 -0
- package/src/wechat-preview/browser/studio/syntax-presets.test.ts +10 -32
- package/src/wechat-preview/browser/studio/syntax-presets.ts +19 -357
- package/src/wechat-preview/fixtures/all-nodes.md +2 -11
- package/src/wechat-preview/index.ts +35 -14
- package/src/wechat-preview/server/http.ts +64 -8
- package/src/wechat-preview/server/studio.test.ts +60 -1
- package/src/wechat-preview/wechat-export.integration.test.ts +49 -8
- package/src/wechat-preview/wechat-renderer.ts +134 -11
- package/src/workflow.test.ts +2 -0
- package/src/wechat-preview/assets/browser-dist/assets/style-C9-YtTIm.css +0 -1
|
@@ -29,6 +29,7 @@ export interface WechatRenderContext {
|
|
|
29
29
|
theme: WechatExportTheme;
|
|
30
30
|
references: WechatLinkReference[];
|
|
31
31
|
structure?: ArticleStructure;
|
|
32
|
+
strictImageDecode?: boolean;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
/** 模板仅声明有限的结构变化,不注入脚本或任意 HTML。 */
|
|
@@ -61,6 +62,7 @@ export interface RenderWechatHtmlInput {
|
|
|
61
62
|
editorVars?: Record<string, string>;
|
|
62
63
|
theme: WechatExportTheme;
|
|
63
64
|
renderers?: WechatRendererOverrides;
|
|
65
|
+
strictImageDecode?: boolean;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
const ALLOWED_TAGS = new Set([
|
|
@@ -131,6 +133,7 @@ const ALLOWED_STYLE_PROPERTIES = new Set([
|
|
|
131
133
|
"text-decoration-style",
|
|
132
134
|
"text-indent",
|
|
133
135
|
"background",
|
|
136
|
+
"background-image",
|
|
134
137
|
"background-color",
|
|
135
138
|
"border",
|
|
136
139
|
"border-top",
|
|
@@ -234,7 +237,8 @@ function imageIsOnlyContent(parent: HTMLElement, image: HTMLElement): boolean {
|
|
|
234
237
|
});
|
|
235
238
|
}
|
|
236
239
|
|
|
237
|
-
//
|
|
240
|
+
// 图片缩放与图注共用导出流程:Markdown 往返读两位小数 alt 与 title;
|
|
241
|
+
// Crepe 块级图片 DOM 读 ratio 与 caption 属性。
|
|
238
242
|
const imageRenderer: WechatElementRenderer = {
|
|
239
243
|
kind: "image",
|
|
240
244
|
selector: "img",
|
|
@@ -245,35 +249,66 @@ const imageRenderer: WechatElementRenderer = {
|
|
|
245
249
|
if (src) element.setAttribute("data-src", src);
|
|
246
250
|
|
|
247
251
|
const parent = element.parentElement;
|
|
248
|
-
|
|
252
|
+
const inOwnParagraph =
|
|
253
|
+
!!parent && parent.tagName.toLowerCase() === "p" && imageIsOnlyContent(parent, element);
|
|
254
|
+
// Crepe 块级图片是文章根的顶层裸 <img>,同样视为独立图片。
|
|
255
|
+
const topLevelBlock = parent === context.root;
|
|
256
|
+
if (!parent || (!inOwnParagraph && !topLevelBlock)) {
|
|
249
257
|
return;
|
|
250
258
|
}
|
|
251
259
|
|
|
252
|
-
|
|
260
|
+
const ratioRaw = element.getAttribute("ratio");
|
|
261
|
+
const ratioFromAttr = ratioRaw ? Number(ratioRaw) : NaN;
|
|
253
262
|
const alt = element.getAttribute("alt") ?? "";
|
|
254
|
-
const ratio =
|
|
263
|
+
const ratio =
|
|
264
|
+
Number.isFinite(ratioFromAttr) && ratioFromAttr > 0
|
|
265
|
+
? ratioFromAttr
|
|
266
|
+
: /^(?:0|[1-9]\d*)\.\d{2}$/.test(alt) ? Number(alt) : 0;
|
|
255
267
|
if (ratio > 0 && Number.isFinite(ratio)) {
|
|
256
268
|
// DOMParser 文档不加载图片,用浏览器图片对象读取原始尺寸。
|
|
257
269
|
const sourceImage = new Image();
|
|
258
|
-
|
|
270
|
+
let imageSrc = src ?? "";
|
|
271
|
+
if (
|
|
272
|
+
typeof window !== "undefined" &&
|
|
273
|
+
window.location &&
|
|
274
|
+
window.location.origin &&
|
|
275
|
+
window.location.origin.startsWith("http") &&
|
|
276
|
+
imageSrc &&
|
|
277
|
+
!/^(?:https?:|data:|blob:|\/\/)/i.test(imageSrc)
|
|
278
|
+
) {
|
|
279
|
+
if (imageSrc.startsWith("/") && !imageSrc.startsWith("/local-file")) {
|
|
280
|
+
imageSrc = `/local-file?path=${encodeURIComponent(imageSrc)}`;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
sourceImage.src = imageSrc;
|
|
259
284
|
try {
|
|
260
285
|
await sourceImage.decode();
|
|
261
286
|
if (!sourceImage.naturalWidth) throw new Error("图片原始宽度为空");
|
|
287
|
+
element.style.width = `${Math.min(ratio, 1) * 100}%`;
|
|
288
|
+
element.style.maxWidth = `${sourceImage.naturalWidth * ratio}px`;
|
|
289
|
+
element.style.height = "auto";
|
|
262
290
|
} catch (error) {
|
|
263
|
-
|
|
291
|
+
if (context.strictImageDecode ?? true) {
|
|
292
|
+
throw new Error(`无法读取缩放图片的原始尺寸:${element.getAttribute("title") || "无图注"}`, { cause: error });
|
|
293
|
+
}
|
|
294
|
+
// 非严格模式(如 Studio 可视化编辑预览)降级处理,保证编辑器正常渲染
|
|
295
|
+
element.style.width = `${Math.min(ratio, 1) * 100}%`;
|
|
296
|
+
element.style.height = "auto";
|
|
264
297
|
}
|
|
265
|
-
element.style.width = `${Math.min(ratio, 1) * 100}%`;
|
|
266
|
-
element.style.maxWidth = `${sourceImage.naturalWidth * ratio}px`;
|
|
267
|
-
element.style.height = "auto";
|
|
268
298
|
}
|
|
269
299
|
|
|
270
300
|
const figure = context.document.createElement("figure");
|
|
271
301
|
setNodeKind(figure, "image-block");
|
|
272
|
-
|
|
302
|
+
if (inOwnParagraph) {
|
|
303
|
+
parent.replaceWith(figure);
|
|
304
|
+
} else {
|
|
305
|
+
element.replaceWith(figure);
|
|
306
|
+
}
|
|
273
307
|
figure.appendChild(element);
|
|
274
308
|
|
|
275
|
-
const caption = element.getAttribute("title")
|
|
309
|
+
const caption = (element.getAttribute("caption") || element.getAttribute("title") || "").trim();
|
|
276
310
|
element.removeAttribute("title");
|
|
311
|
+
element.removeAttribute("caption");
|
|
277
312
|
if (caption) {
|
|
278
313
|
const figcaption = context.document.createElement("figcaption");
|
|
279
314
|
setNodeKind(figcaption, "image-caption");
|
|
@@ -382,6 +417,10 @@ const blockquoteRenderer: WechatElementRenderer = {
|
|
|
382
417
|
element.prepend(label);
|
|
383
418
|
}
|
|
384
419
|
},
|
|
420
|
+
finalize(element) {
|
|
421
|
+
// 微信编辑器会给原生 blockquote 强制加灰色左边框,导出时降级为 section,外观全靠内联样式。
|
|
422
|
+
replaceTag(element, "section");
|
|
423
|
+
},
|
|
385
424
|
};
|
|
386
425
|
|
|
387
426
|
/** Normalize URL for reference dedupe (same target → one footnote entry). */
|
|
@@ -631,6 +670,33 @@ export function buildWechatThemeCss(
|
|
|
631
670
|
.milkdown .editor p {
|
|
632
671
|
${theme.bodyFontSize ? `font-size: ${theme.bodyFontSize};` : ""}
|
|
633
672
|
${theme.bodyParagraphSpacing ? `margin-bottom: ${theme.bodyParagraphSpacing};` : ""}
|
|
673
|
+
${theme.bodyLineHeight ? `line-height: ${theme.bodyLineHeight};` : ""}
|
|
674
|
+
${theme.bodyLetterSpacing ? `letter-spacing: ${theme.bodyLetterSpacing};` : ""}
|
|
675
|
+
${theme.bodyColor ? `color: ${theme.bodyColor};` : ""}
|
|
676
|
+
}
|
|
677
|
+
`;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* 结构装饰(编号 / 章节标签 / 引用标签)在导出时是真实节点,编辑器里是 ::before。
|
|
682
|
+
* 此处样式与 studio 编辑器的 ::before 视觉对齐,否则预览中退化为普通正文。
|
|
683
|
+
*/
|
|
684
|
+
function buildStructureDecorationCss(structure?: ArticleStructure): string {
|
|
685
|
+
if (!structure?.numberedHeadings && !structure?.headingLabel && !structure?.quoteLabel) return "";
|
|
686
|
+
return `
|
|
687
|
+
.milkdown .editor [data-wechat-node="heading-number"],
|
|
688
|
+
.milkdown .editor [data-wechat-node="heading-label"] {
|
|
689
|
+
margin-right: 0.3em;
|
|
690
|
+
opacity: 0.7;
|
|
691
|
+
font-weight: 600;
|
|
692
|
+
}
|
|
693
|
+
.milkdown .editor [data-wechat-node="quote-label"] {
|
|
694
|
+
margin: 0 0 6px;
|
|
695
|
+
font-size: 11px;
|
|
696
|
+
font-weight: 600;
|
|
697
|
+
letter-spacing: 0.05em;
|
|
698
|
+
color: var(--wx-brand-ink, var(--wx-brand-accent, #ca6093));
|
|
699
|
+
text-transform: uppercase;
|
|
634
700
|
}
|
|
635
701
|
`;
|
|
636
702
|
}
|
|
@@ -639,6 +705,59 @@ function parseHtml(html: string): Document {
|
|
|
639
705
|
return new DOMParser().parseFromString(`<!doctype html><html><body>${html}</body></html>`, "text/html");
|
|
640
706
|
}
|
|
641
707
|
|
|
708
|
+
const BORDER_SIDES = ["top", "right", "bottom", "left"] as const;
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* 浏览器把 `border: none; border-left: X` 或 `border-left: none` 序列化成多值简写或
|
|
712
|
+
* none 边的长属性,其中 border-color 是 currentcolor——公众号编辑器解析不了,整条
|
|
713
|
+
* 声明作废后边框退回正文灰色。展开为可见边的单值属性,丢弃 none/hidden 边。
|
|
714
|
+
*/
|
|
715
|
+
function normalizeBorderShorthands(element: HTMLElement): void {
|
|
716
|
+
const style = element.style;
|
|
717
|
+
const sides = BORDER_SIDES.map((side) => ({
|
|
718
|
+
side,
|
|
719
|
+
width: style.getPropertyValue(`border-${side}-width`),
|
|
720
|
+
style: style.getPropertyValue(`border-${side}-style`),
|
|
721
|
+
color: style.getPropertyValue(`border-${side}-color`),
|
|
722
|
+
}));
|
|
723
|
+
|
|
724
|
+
const invisible = (entry: (typeof sides)[number]) => entry.style === "none" || entry.style === "hidden";
|
|
725
|
+
const hasShorthand =
|
|
726
|
+
!!style.getPropertyValue("border-style") ||
|
|
727
|
+
!!style.getPropertyValue("border-width") ||
|
|
728
|
+
!!style.getPropertyValue("border-color");
|
|
729
|
+
if (!hasShorthand && !sides.some(invisible)) return;
|
|
730
|
+
|
|
731
|
+
if (!hasShorthand) {
|
|
732
|
+
// 单边 none/hidden 长属性:只删除,其余保持原样
|
|
733
|
+
for (const { side, style: borderStyle } of sides) {
|
|
734
|
+
if (borderStyle !== "none" && borderStyle !== "hidden") continue;
|
|
735
|
+
style.removeProperty(`border-${side}`);
|
|
736
|
+
style.removeProperty(`border-${side}-width`);
|
|
737
|
+
style.removeProperty(`border-${side}-style`);
|
|
738
|
+
style.removeProperty(`border-${side}-color`);
|
|
739
|
+
}
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const removable = ["border", "border-width", "border-style", "border-color"];
|
|
744
|
+
for (const { side } of sides) {
|
|
745
|
+
removable.push(`border-${side}`, `border-${side}-width`, `border-${side}-style`, `border-${side}-color`);
|
|
746
|
+
}
|
|
747
|
+
for (const property of removable) style.removeProperty(property);
|
|
748
|
+
|
|
749
|
+
for (const entry of sides) {
|
|
750
|
+
if (!entry.style || invisible(entry)) continue;
|
|
751
|
+
if (entry.width && entry.color) {
|
|
752
|
+
style.setProperty(`border-${entry.side}`, `${entry.width} ${entry.style} ${entry.color}`);
|
|
753
|
+
} else {
|
|
754
|
+
if (entry.width) style.setProperty(`border-${entry.side}-width`, entry.width);
|
|
755
|
+
style.setProperty(`border-${entry.side}-style`, entry.style);
|
|
756
|
+
if (entry.color) style.setProperty(`border-${entry.side}-color`, entry.color);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
642
761
|
function sanitizeStyle(element: HTMLElement): void {
|
|
643
762
|
const propertyNames: string[] = [];
|
|
644
763
|
for (let index = 0; index < element.style.length; index += 1) {
|
|
@@ -711,6 +830,7 @@ function sanitizeTree(root: HTMLElement): void {
|
|
|
711
830
|
sanitizeImageUrl(element, "data-src");
|
|
712
831
|
}
|
|
713
832
|
sanitizeStyle(element);
|
|
833
|
+
normalizeBorderShorthands(element);
|
|
714
834
|
}
|
|
715
835
|
}
|
|
716
836
|
|
|
@@ -753,11 +873,13 @@ export async function renderWechatHtml(input: RenderWechatHtmlInput): Promise<st
|
|
|
753
873
|
theme: input.theme,
|
|
754
874
|
references,
|
|
755
875
|
structure: input.structure,
|
|
876
|
+
strictImageDecode: input.strictImageDecode ?? true,
|
|
756
877
|
});
|
|
757
878
|
|
|
758
879
|
const css = [
|
|
759
880
|
input.baseCss,
|
|
760
881
|
buildWechatThemeCss(input.editorVars ?? {}, input.theme),
|
|
882
|
+
buildStructureDecorationCss(input.structure),
|
|
761
883
|
pluginCss,
|
|
762
884
|
input.customCss ?? "",
|
|
763
885
|
].filter(Boolean).join("\n");
|
|
@@ -788,6 +910,7 @@ export async function renderWechatHtml(input: RenderWechatHtmlInput): Promise<st
|
|
|
788
910
|
theme: input.theme,
|
|
789
911
|
references,
|
|
790
912
|
structure: input.structure,
|
|
913
|
+
strictImageDecode: input.strictImageDecode ?? true,
|
|
791
914
|
});
|
|
792
915
|
sanitizeTree(finalRoot);
|
|
793
916
|
return finalRoot.outerHTML;
|
package/src/workflow.test.ts
CHANGED
|
@@ -150,12 +150,14 @@ describe("init", () => {
|
|
|
150
150
|
"--content-form", "article",
|
|
151
151
|
"--targets", "wechat@ancientone",
|
|
152
152
|
"--content-origin", "user",
|
|
153
|
+
"--article-theme", "./styles/standalone.json",
|
|
153
154
|
]));
|
|
154
155
|
const state = await readState(output.state_path);
|
|
155
156
|
expect(state.publish_targets).toEqual([
|
|
156
157
|
{ route: "wechat-article", account: "ancientone" },
|
|
157
158
|
]);
|
|
158
159
|
expect(state.route.primary).toBe("wechat-article");
|
|
160
|
+
expect(state.intent.article_theme).toBe(join(process.cwd(), "styles/standalone.json"));
|
|
159
161
|
});
|
|
160
162
|
|
|
161
163
|
test("normalizes underscore flags and resolves route/account from intent text", async () => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--bg-main: #f8fafc;--bg-panel: #ffffff;--border: #e2e8f0;--border-focus: #ca6093;--text-main: #1e293b;--text-muted: #64748b;--brand: #ca6093;--brand-hover: #b35082;--brand-light: rgba(202, 96, 147, .08);--success: #10b981;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;--font-mono: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace}*{box-sizing:border-box;margin:0;padding:0}body{font-family:var(--font-sans);color:var(--text-main);background:var(--bg-main);height:100vh;display:flex;flex-direction:column;overflow:hidden}.studio-header{height:52px;background:var(--bg-panel);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;padding:0 16px;z-index:10}.brand-section{display:flex;align-items:center;gap:10px}.brand-logo{font-size:18px}.brand-title{font-size:15px;font-weight:700;color:var(--text-main);letter-spacing:-.01em}.brand-badge{font-size:11px;font-weight:600;background:var(--brand-light);color:var(--brand);padding:2px 8px;border-radius:999px}.header-controls{display:flex;align-items:center;gap:12px}.account-select-wrap{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--text-muted)}.account-select{padding:5px 10px;font-size:13px;border-radius:6px;border:1px solid var(--border);background:#fff;color:var(--text-main);outline:none;cursor:pointer}.account-select:focus{border-color:var(--border-focus)}.btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:6px;font-size:13px;font-weight:500;cursor:pointer;border:1px solid var(--border);background:#fff;color:var(--text-main);transition:all .15s ease;text-decoration:none}.btn:hover{background:#f1f5f9}.btn-primary{background:var(--brand);color:#fff;border-color:var(--brand)}.btn-primary:hover{background:var(--brand-hover);border-color:var(--brand-hover)}.btn-success{background:#059669;color:#fff;border-color:#059669}.btn-success:hover{background:#047857;border-color:#047857}.studio-body{flex:1;display:flex;min-height:0;overflow:hidden}.panel{display:flex;flex-direction:column;background:var(--bg-panel);min-height:0}.panel-header{padding:10px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;background:#fafbfc}.panel-title{font-size:13px;font-weight:650;color:var(--text-main);display:flex;align-items:center;gap:6px}.left-panel{width:360px;border-right:1px solid var(--border);flex-shrink:0}.tab-nav{display:flex;border-bottom:1px solid var(--border);background:#f8fafc}.tab-btn{flex:1;padding:10px 12px;font-size:13px;font-weight:600;border:none;background:transparent;color:var(--text-muted);cursor:pointer;border-bottom:2px solid transparent;transition:all .15s}.tab-btn:hover{color:var(--text-main)}.tab-btn.active{color:var(--brand);background:#fff;border-bottom-color:var(--brand)}.tab-content{flex:1;overflow-y:auto;padding:16px}.config-section{margin-bottom:22px}.section-label{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:12px;display:flex;align-items:center;gap:6px}.form-group{margin-bottom:14px}.form-label{display:flex;justify-content:space-between;align-items:center;font-size:12px;color:var(--text-main);margin-bottom:6px}.form-val{font-family:var(--font-mono);font-size:11px;color:var(--text-muted)}.slider-input{width:100%;accent-color:var(--brand);cursor:pointer}.color-input-row{display:flex;align-items:center;gap:8px}.color-picker{-webkit-appearance:none;appearance:none;border:1px solid var(--border);border-radius:6px;width:32px;height:32px;cursor:pointer;padding:2px;background:#fff}.color-picker::-webkit-color-swatch-wrapper{padding:0}.color-picker::-webkit-color-swatch{border:none;border-radius:4px}.color-hex{flex:1;padding:6px 10px;font-family:var(--font-mono);font-size:12px;border:1px solid var(--border);border-radius:6px;color:var(--text-main)}.switch-label{display:flex;align-items:center;justify-content:space-between;cursor:pointer;font-size:12px}.switch-toggle{position:relative;display:inline-block;width:38px;height:20px}.switch-toggle input{opacity:0;width:0;height:0}.slider-round{position:absolute;cursor:pointer;inset:0;background-color:#cbd5e1;transition:.2s;border-radius:20px}.slider-round:before{position:absolute;content:"";height:14px;width:14px;left:3px;bottom:3px;background-color:#fff;transition:.2s;border-radius:50%}input:checked+.slider-round{background-color:var(--brand)}input:checked+.slider-round:before{transform:translate(18px)}.css-editor{width:100%;height:140px;font-family:var(--font-mono);font-size:12px;line-height:1.5;padding:8px 10px;border:1px solid var(--border);border-radius:6px;background:#fafbfc;color:#0f172a;resize:vertical;outline:none}.css-editor:focus{border-color:var(--border-focus);background:#fff}.syntax-card{border:1px solid var(--border);border-radius:8px;padding:12px;margin-bottom:12px;background:#fff;transition:border-color .15s}.syntax-card:hover{border-color:#cbd5e1}.syntax-card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.syntax-card-title{font-size:13px;font-weight:650;color:var(--text-main)}.syntax-card-badge{font-size:10px;font-weight:600;padding:1px 6px;border-radius:999px;background:#f1f5f9;color:var(--text-muted)}.syntax-card-desc{font-size:12px;color:var(--text-muted);margin-bottom:8px;line-height:1.4}.syntax-code-snippet{background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;padding:8px 10px;font-family:var(--font-mono);font-size:11px;color:#334155;white-space:pre-wrap;margin-bottom:8px}.syntax-btn-insert{width:100%;padding:4px 8px;font-size:11px;font-weight:600;border:1px dashed var(--border);border-radius:4px;background:#fafbfc;color:var(--brand);cursor:pointer}.syntax-btn-insert:hover{background:var(--brand-light);border-color:var(--brand)}.editor-panel{flex:1;border-right:1px solid var(--border);min-width:320px}.editor-toolbar{display:flex;gap:8px;align-items:center}.editor-textarea{flex:1;width:100%;border:none;outline:none;resize:none;padding:16px 20px;font-family:var(--font-mono);font-size:13px;line-height:1.7;color:#1e293b;background:#fff}.editor-footer{padding:6px 16px;border-top:1px solid var(--border);background:#fafbfc;font-size:11px;color:var(--text-muted);display:flex;justify-content:space-between}.preview-panel{width:480px;flex-shrink:0;background:#f1f5f9}.preview-container{flex:1;overflow-y:auto;display:flex;flex-direction:column;align-items:center;padding:24px 16px 48px}.device-frame{width:430px;min-height:680px;background:#fff;border-radius:18px;box-shadow:0 10px 30px #00000014,0 1px 3px #0000000d;overflow:hidden;display:flex;flex-direction:column;border:1px solid #e2e8f0}.device-notch-bar{height:28px;background:#fafbfc;border-bottom:1px solid #f1f5f9;display:flex;align-items:center;justify-content:space-between;padding:0 16px;font-size:11px;font-weight:600;color:#64748b}.device-screen{flex:1;padding:20px 16px 36px;box-sizing:border-box;overflow-y:auto}.toast-container{position:fixed;bottom:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast{background:#1e293b;color:#fff;padding:10px 16px;border-radius:8px;font-size:13px;font-weight:500;box-shadow:0 6px 18px #00000026;opacity:0;transform:translateY(10px);transition:all .25s ease;pointer-events:auto}.toast.show{opacity:1;transform:translateY(0)}.toast.toast-success{background:#065f46;border:1px solid #10b981}.preset-group{margin-bottom:10px;padding:10px 12px;background:#f8fafc;border:1px solid var(--border);border-radius:var(--radius-sm);transition:border-color .15s}.preset-group:hover{border-color:#cbd5e1}.preset-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.preset-title{font-size:12px;font-weight:650;color:var(--text-main);display:flex;align-items:center;gap:5px}.preset-select{width:100%;padding:5px 8px;font-size:12px;font-weight:500;border:1px solid var(--border);border-radius:4px;background:#fff;color:var(--text-main);outline:none;cursor:pointer;transition:border-color .15s}.preset-select:focus{border-color:var(--brand)}.preset-desc{font-size:11px;color:var(--text-muted);margin-top:5px;line-height:1.4;padding-left:2px}.btn-extract-css{padding:2px 7px;font-size:11px;font-weight:550;color:var(--brand);background:#fff;border:1px solid var(--border);border-radius:4px;cursor:pointer;transition:all .15s ease;white-space:nowrap}.btn-extract-css:hover{background:#f1f5f9;border-color:var(--brand)}#studio-editor-host{display:none}
|