@heycys/gallery 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +51 -1
- package/browser/editor/components/callout/index.mjs +40 -15
- package/browser/editor/components/columns/page.mjs +45 -32
- package/browser/editor/components/details/index.mjs +2 -1
- package/browser/editor/components/dialog/index.mjs +2 -1
- package/browser/editor/components/dialog/page.mjs +0 -18
- package/browser/editor/components/divider/index.mjs +1 -1
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/figure/page.mjs +10 -1
- package/browser/editor/components/file/page.mjs +2 -2
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/heading/index.mjs +2 -0
- package/browser/editor/components/heading/page.mjs +6 -0
- package/browser/editor/components/highlight/index.mjs +4 -20
- package/browser/editor/components/icons.mjs +13 -2
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/page.mjs +2 -2
- package/browser/editor/components/installed/index.mjs +82 -29
- package/browser/editor/components/installed/page.mjs +146 -34
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/kit.mjs +3 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/page.mjs +44 -14
- package/browser/editor/components/pages.mjs +2 -2
- package/browser/editor/components/registry.mjs +68 -33
- package/browser/editor/components/section/index.mjs +2 -1
- package/browser/editor/components/set-apart.mjs +24 -0
- package/browser/editor/components/table/index.mjs +64 -5
- package/browser/editor/components/table/page.mjs +30 -19
- package/browser/editor/page/annotate/anchors.mjs +4 -3
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/annotate/index.mjs +61 -34
- package/browser/editor/page/autosave.mjs +357 -38
- package/browser/editor/page/beside.mjs +5 -5
- package/browser/editor/page/block-menu/colors.mjs +3 -1
- package/browser/editor/page/block-menu/index.mjs +8 -6
- package/browser/editor/page/blocks.mjs +16 -7
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +145 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +970 -0
- package/browser/editor/page/board/settings.mjs +209 -0
- package/browser/editor/page/caret.mjs +5 -2
- package/browser/editor/page/changes/bar.mjs +94 -0
- package/browser/editor/page/changes/ghost.mjs +206 -0
- package/browser/editor/page/changes/gone-words.mjs +94 -0
- package/browser/editor/page/changes/index.mjs +447 -0
- package/browser/editor/page/changes/words.mjs +27 -0
- package/browser/editor/page/clipboard/import/colors.mjs +3 -3
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +156 -26
- package/browser/editor/page/clipboard/own/blocks.mjs +25 -16
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +16 -7
- package/browser/editor/page/clipboard/own/export.mjs +6 -6
- package/browser/editor/page/clipboard/own/selection.mjs +3 -3
- package/browser/editor/page/clipboard/own/writers.mjs +0 -11
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +98 -25
- package/browser/editor/page/conflicts.mjs +13 -33
- package/browser/editor/page/convert.mjs +8 -7
- package/browser/editor/page/core.mjs +81 -27
- package/browser/editor/page/custom-page.mjs +106 -0
- package/browser/editor/page/drag/index.mjs +40 -24
- package/browser/editor/page/drag/preview.mjs +9 -4
- package/browser/editor/page/editor.mjs +120 -28
- package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
- package/browser/editor/page/emoji-picker/grid.mjs +7 -5
- package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
- package/browser/editor/page/emoji-picker/icons.mjs +0 -1
- package/browser/editor/page/emoji-picker/index.mjs +11 -9
- package/browser/editor/page/emoji-picker/styles.mjs +156 -2
- package/browser/editor/page/emoji-picker/support.mjs +6 -4
- package/browser/editor/page/emoji-picker/upload.mjs +14 -13
- package/browser/editor/page/fills.mjs +5 -3
- package/browser/editor/page/fold/index.mjs +348 -0
- package/browser/editor/page/fold/rule.mjs +125 -0
- package/browser/editor/page/folded.mjs +23 -0
- package/browser/editor/page/format-bar/bar.mjs +2 -1
- package/browser/editor/page/format-bar/index.mjs +1 -1
- package/browser/editor/page/geometry.mjs +8 -6
- package/browser/editor/page/handle/index.mjs +22 -14
- package/browser/editor/page/hints/index.mjs +1 -1
- package/browser/editor/page/history.mjs +24 -4
- package/browser/editor/page/insert/index.mjs +30 -17
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/long-runs.mjs +75 -0
- package/browser/editor/page/look.mjs +69 -6
- package/browser/editor/page/margin.mjs +63 -27
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +86 -31
- package/browser/editor/page/merge.mjs +24 -0
- package/browser/editor/page/notices.mjs +3 -3
- package/browser/editor/page/offered.mjs +1 -1
- package/browser/editor/page/outline/folds.mjs +11 -10
- package/browser/editor/page/outline/index.mjs +131 -45
- package/browser/editor/page/outline/list.mjs +23 -11
- package/browser/editor/page/outline/read.mjs +1 -1
- package/browser/editor/page/outline/strip.mjs +7 -1
- package/browser/editor/page/page-objects.mjs +13 -2
- package/browser/editor/page/panel.mjs +9 -13
- package/browser/editor/page/present-links.mjs +11 -2
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/delete.mjs +8 -6
- package/browser/editor/page/selection/index.mjs +10 -3
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +101 -6
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/cell-bar.mjs +4 -1
- package/browser/editor/page/table/cells.mjs +103 -47
- package/browser/editor/page/table/icons.mjs +3 -1
- package/browser/editor/page/table/index.mjs +40 -16
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +150 -0
- package/browser/editor/page/table/widths.mjs +9 -4
- package/browser/editor/page/text-select/index.mjs +43 -14
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/tooltip.mjs +1 -1
- package/browser/editor/page/type-grid.mjs +4 -3
- package/browser/editor/page/typing/code-edges.mjs +63 -17
- package/browser/editor/page/typing/index.mjs +65 -9
- package/browser/editor/page/typing/leave.mjs +1 -1
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/annotations.mjs +8 -10
- package/browser/shared/block-packs.mjs +404 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/code-folds.mjs +5 -1
- package/browser/shared/colors.mjs +17 -14
- package/browser/shared/component-catalog.mjs +345 -54
- package/browser/shared/component-source.mjs +37 -0
- package/browser/shared/components/callout.mjs +4 -2
- package/browser/shared/components/index.mjs +72 -9
- package/browser/shared/components/installed.mjs +110 -8
- package/browser/shared/components/page.mjs +22 -3
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -1
- package/browser/shared/components/text.mjs +2 -2
- package/browser/shared/document-look.mjs +183 -0
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
- package/browser/shared/emoji/data/README.md +4 -2
- package/browser/shared/emoji/data/categories.json +1 -1
- package/browser/shared/emoji/data/keywords-en.json +1 -1
- package/browser/shared/emoji/data/keywords-zh.json +1 -1
- package/browser/shared/emoji/data/names.json +1 -1
- package/browser/shared/emoji/data/positions.json +1 -1
- package/browser/shared/emoji/data/twemoji-index.json +1 -1
- package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
- package/browser/shared/emoji/data.mjs +10 -12
- package/browser/shared/emoji/emoji.mjs +8 -7
- package/browser/shared/emoji/icon-value.mjs +4 -3
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/html-tree.mjs +11 -5
- package/browser/shared/i18n/en.mjs +374 -35
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/long-runs.mjs +39 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/new-names.mjs +5 -2
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +458 -0
- package/browser/shared/pack-manifest.mjs +77 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +388 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/preferences.mjs +10 -4
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +13 -5
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +134 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-look.mjs +91 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/browser/shared/zoom.mjs +5 -5
- package/dist/chunk-2NRBY6AJ.mjs +2 -0
- package/dist/chunk-32ZUEFZ7.mjs +2 -0
- package/dist/chunk-35NQ4PLQ.mjs +2 -0
- package/dist/chunk-3KJHLHUO.mjs +2 -0
- package/dist/chunk-3NJACR4W.mjs +2 -0
- package/dist/chunk-4AV456RQ.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5XYHDBJ5.mjs +2 -0
- package/dist/chunk-5ZJA7CXT.mjs +2 -0
- package/dist/chunk-6A53MZYZ.mjs +2 -0
- package/dist/chunk-6EXH3ORZ.mjs +166 -0
- package/dist/chunk-6EZ7FNIK.mjs +3 -0
- package/dist/{chunk-UXUK4PMC.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/{chunk-6U2SLSDN.mjs → chunk-6VTU6KEO.mjs} +1 -1
- package/dist/chunk-B4P2CM2J.mjs +3 -0
- package/dist/chunk-BPL64HGA.mjs +4 -0
- package/dist/chunk-BVEFGE4B.mjs +2 -0
- package/dist/chunk-BZ5RAF7L.mjs +2 -0
- package/dist/chunk-CRJEG7MT.mjs +2 -0
- package/dist/{chunk-B3VTYBYR.mjs → chunk-D4CKRD3V.mjs} +91 -91
- package/dist/chunk-D4EURAX4.mjs +4 -0
- package/dist/chunk-DQCE7TJY.mjs +5 -0
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/{chunk-DB4WKGYF.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-FJYN7RTH.mjs +4 -0
- package/dist/chunk-FWNRPMCJ.mjs +12 -0
- package/dist/chunk-FWW4CSAZ.mjs +2 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-GY3FAUVM.mjs +2 -0
- package/dist/chunk-HLYV7RIH.mjs +2 -0
- package/dist/chunk-HMYTM3GT.mjs +15 -0
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JVHHHGEA.mjs +3 -0
- package/dist/chunk-KTKHRC6H.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-MHW7ZKOU.mjs +2 -0
- package/dist/chunk-N76HWBA3.mjs +10 -0
- package/dist/chunk-N7AZZLGT.mjs +548 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-YXAUQPVK.mjs → chunk-NFMCP2HI.mjs} +3 -3
- package/dist/chunk-NG375ILQ.mjs +2 -0
- package/dist/chunk-NVRNLK25.mjs +6 -0
- package/dist/chunk-NWFBE2YA.mjs +2 -0
- package/dist/chunk-NWR2LT5B.mjs +2 -0
- package/dist/chunk-OJKMINIU.mjs +20 -0
- package/dist/chunk-OUUP3WKT.mjs +2 -0
- package/dist/chunk-OW5NWPOJ.mjs +10 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-POQSE4C2.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/{chunk-Z52HTUW7.mjs → chunk-PVER7LSC.mjs} +2 -2
- package/dist/chunk-PZDLJJTJ.mjs +3 -0
- package/dist/chunk-Q47PLKIJ.mjs +15 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QKXMPUXC.mjs +2 -0
- package/dist/chunk-QOUEFUCH.mjs +16 -0
- package/dist/chunk-RFDZXFJF.mjs +13 -0
- package/dist/chunk-RKPWLGZ3.mjs +4 -0
- package/dist/chunk-RMECZA2K.mjs +2 -0
- package/dist/{chunk-EUX7IC5J.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SX4LJYT6.mjs +8 -0
- package/dist/chunk-SXHBYZST.mjs +16 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TEZAWDSQ.mjs +2 -0
- package/dist/chunk-UBBRTJ2R.mjs +24 -0
- package/dist/chunk-UFNYFFKO.mjs +20 -0
- package/dist/chunk-UGWYKHBL.mjs +170 -0
- package/dist/chunk-UKSHDZZ6.mjs +2 -0
- package/dist/chunk-UMHUSOPJ.mjs +2 -0
- package/dist/chunk-UNOYVIYR.mjs +2 -0
- package/dist/chunk-V6RIYQZZ.mjs +4 -0
- package/dist/chunk-VJPFVNNW.mjs +15 -0
- package/dist/chunk-VS3ZMVGX.mjs +5 -0
- package/dist/chunk-VTKNEYT3.mjs +6 -0
- package/dist/chunk-VXACTLO3.mjs +3 -0
- package/dist/chunk-W3BGBJQW.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YQGT4AB2.mjs +6 -0
- package/dist/chunk-ZB4H7ZN4.mjs +2 -0
- package/dist/{chunk-ACOPDCNB.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZUNVAXLH.mjs +2 -0
- package/dist/chunk-ZWPMCK7P.mjs +2 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-EVJ3BX3M.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +14 -14
- package/kit/math.js +18 -2
- package/kit/report.css +500 -151
- package/kit/runtime.js +1720 -170
- package/kit/state.js +10 -1
- package/kit/tables.js +172 -37
- package/kit/ui.js +166 -27
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +156 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +130 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +295 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +246 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +351 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +201 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +102 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +76 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +238 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +158 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +138 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +166 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +151 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +185 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +120 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +342 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +267 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +312 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +258 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/release.json +13 -11
- package/sdk/doc-kit.d.ts +404 -7
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +71 -26
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/example-report.html +1 -1
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +221 -0
- package/skill/references/writing-html.md +9 -7
- package/skill/sdk/doc-kit.d.ts +404 -7
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BK2e_07w.js +13 -0
- package/web/assets/index-CWFI83mF.css +1 -0
- package/web/index.html +2 -2
- package/browser/editor/components/callout/page.mjs +0 -13
- package/dist/chunk-2PBALTR3.mjs +0 -57
- package/dist/chunk-3LA3EMDE.mjs +0 -15
- package/dist/chunk-5FRMCDPY.mjs +0 -16
- package/dist/chunk-5LEK2CBS.mjs +0 -2
- package/dist/chunk-5OFN5AHC.mjs +0 -2
- package/dist/chunk-5SIYS5HN.mjs +0 -2
- package/dist/chunk-5TEK3RAD.mjs +0 -2
- package/dist/chunk-6CYG3Z4V.mjs +0 -2
- package/dist/chunk-7GHT2UCA.mjs +0 -15
- package/dist/chunk-7QQBR7PB.mjs +0 -2
- package/dist/chunk-ATCJYAR4.mjs +0 -2
- package/dist/chunk-C7HWOBIF.mjs +0 -2
- package/dist/chunk-E7VYDG2X.mjs +0 -2
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FQGQH4KM.mjs +0 -2
- package/dist/chunk-G7TOXONE.mjs +0 -6
- package/dist/chunk-GPF4YWWB.mjs +0 -9
- package/dist/chunk-GYQV7Y4J.mjs +0 -120
- package/dist/chunk-HMHK3EQ6.mjs +0 -2
- package/dist/chunk-HQQMJCQJ.mjs +0 -10
- package/dist/chunk-IERUOGC3.mjs +0 -6
- package/dist/chunk-ITNLYXXV.mjs +0 -3
- package/dist/chunk-L4DVONOG.mjs +0 -2
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LC7YNQFG.mjs +0 -2
- package/dist/chunk-LHTFLRB6.mjs +0 -4
- package/dist/chunk-NFIBI4IP.mjs +0 -26
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O52JMOCZ.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-QMQUXTU4.mjs +0 -12
- package/dist/chunk-QVWVFC5K.mjs +0 -6
- package/dist/chunk-QYKCJ7FG.mjs +0 -8
- package/dist/chunk-QZY6Q64C.mjs +0 -2
- package/dist/chunk-TDQP3DKQ.mjs +0 -10
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-UNUEWH4S.mjs +0 -2
- package/dist/chunk-V4CPWKMZ.mjs +0 -2
- package/dist/chunk-VACRB2NE.mjs +0 -3
- package/dist/chunk-W63L7367.mjs +0 -7
- package/dist/chunk-W7CXPCRV.mjs +0 -6
- package/dist/chunk-XINNG4F2.mjs +0 -4
- package/dist/chunk-YL2DPWVS.mjs +0 -4
- package/dist/chunk-YZ5Z6H4W.mjs +0 -4
- package/dist/chunk-ZBIM6ARY.mjs +0 -216
- package/skill/references/building-components.md +0 -327
- package/web/assets/index-B6Ai3wsa.js +0 -13
- package/web/assets/index-SYPC3EZy.css +0 -1
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { isUtf8 } from "node:buffer";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
3
|
+
import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { parseFragment, serializeOuter } from "parse5";
|
|
7
7
|
import { isInstance, parseCompound, parsePart, parseSelector, partOf } from "./components/index.mjs";
|
|
8
|
-
import { ATTRIBUTE, NO_TEXT, PACKAGE_ID, PACKAGE_MARK, instanceMatch, refusedInCopy, settingState } from "./components/installed.mjs";
|
|
8
|
+
import { ATTRIBUTE, NO_TEXT, PACKAGE_ID, PACKAGE_MARK, SLOT, inDocumentMenus, instanceMatch, refusedInCopy, settingState } from "./components/installed.mjs";
|
|
9
9
|
import { writeAtomic } from "./files.mjs";
|
|
10
10
|
import { attr, walk } from "./html-tree.mjs";
|
|
11
|
+
import { HOST, NET, netHostsOf } from "./net-policy.mjs";
|
|
11
12
|
import { inLanguage, refusal, said, saying, told } from "./i18n/index.mjs";
|
|
13
|
+
import { PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
12
14
|
import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf, markerOf, packageFolders } from "./workspace.mjs";
|
|
13
15
|
|
|
14
|
-
//
|
|
16
|
+
// 组件包, custom blocks (自定义块) as the UI and the Agent's documents call them: what the workspace's
|
|
17
|
+
// component packages say of themselves to Gallery, read from
|
|
15
18
|
// <workspace>/components/<scope>/<name>/component.json, plain data, whose code no system runs here. A
|
|
16
19
|
// package is a description as a kit component's is (src/shared/components/): its id, where its
|
|
17
20
|
// instances are, its parts and what it leaves on a page, so that what reads a built-in's reads a
|
|
@@ -19,19 +22,22 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf
|
|
|
19
22
|
// A manifest offers only FIELDS, no unit, box, host, rank or category: those are the engines', and a
|
|
20
23
|
// field it does not know keeps its package from loading.
|
|
21
24
|
//
|
|
22
|
-
// The catalog is { packages, problems, settings, stamp }. `packages`, by id, are those that load. A
|
|
25
|
+
// The catalog is { packages, problems, settings, packs, stamp }. `packages`, by id, are those that load. A
|
|
23
26
|
// package that does not load (a manifest that does not read as one, one for an apiVersion this Gallery
|
|
24
27
|
// does not run, which counts as disabled, or one the settings turned off) stands in `problems`, by its
|
|
25
28
|
// id in lowercase, as an instance names it, with why (`problem`, said()'s, in either language by
|
|
26
29
|
// problemIn), and touches nothing else: its instances show as those of a package that is not there,
|
|
27
|
-
// and whoever reads them says why. `settings` is what gallery.json says of the components (设置 ›
|
|
28
|
-
// componentSettings): `hidden` and `
|
|
29
|
-
// component, and `
|
|
30
|
-
//
|
|
31
|
-
//
|
|
30
|
+
// and whoever reads them says why. `settings` is what gallery.json says of the components (设置 › 组件列表,
|
|
31
|
+
// componentSettings): `hidden`, `disabled`, `shown` and `unlisted`, by the id of a package (`hidden` the name of a
|
|
32
|
+
// built-in component too), `packs` and `packsOff`, the packs' switches (a pack off: none of its blocks offered,
|
|
33
|
+
// as one unlisted), and `problem` where the file cannot be read as saying anything (settingsNow). `packs`, by
|
|
34
|
+
// the scope of a block (a pack: ./pack-manifest.mjs), what its pack.json names it, or null for a scope with
|
|
35
|
+
// none or one that does not read (who lists it says it by its scope).
|
|
36
|
+
// A package the document's menus do not offer (inDocumentMenus: hidden, unlisted, or a custom page's alone and not
|
|
37
|
+
// shown) runs as any other and is left out of those menus, which read its state (menuOf, packageStates); one disabled is one that does not load, so that nothing that loads a
|
|
32
38
|
// package has a case for it. A stamp is a hash of what files hold: `stamp`, of a package, over what
|
|
33
39
|
// reaches a page of it (STAMPED and the files `assets` names), of one that does not load over those
|
|
34
|
-
// and why, and of the catalog, over its packages', what is hidden and whether gallery.json reads;
|
|
40
|
+
// and why, and of the catalog, over its packages', what is hidden, shown and unlisted and whether gallery.json reads;
|
|
35
41
|
// `definition`, over the manifest alone, is what a page's commit is to be held to.
|
|
36
42
|
//
|
|
37
43
|
// readCatalog reads the disk; what reads a catalog for use (the scan, the checks, a page) asks
|
|
@@ -43,16 +49,47 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf
|
|
|
43
49
|
/** The apiVersion this Gallery runs. */
|
|
44
50
|
export const API_VERSION = 1;
|
|
45
51
|
|
|
46
|
-
/** The kit's files a package may ask for by id in `assets`, as src/render/assets.mjs names them (the others are on every page). */
|
|
52
|
+
/** The kit's files a package may ask for by id in `assets`, as src/render/assets.mjs names them (the others are on every page, or, the board's, on every custom page). */
|
|
47
53
|
export const KIT_ASSETS = new Set(["code", "state", "sheets", "tokens", "dialogs", "katex-styles", "katex", "katex-auto-render", "math", "d3", "charts", "tables"]);
|
|
48
54
|
|
|
49
55
|
// What a manifest may hold, a part of one and its `runtime`.
|
|
50
|
-
const FIELDS = ["id", "apiVersion", "version", "name", "description", "words", "parts", "runtime", "assets", "markdown", "schema"];
|
|
56
|
+
const FIELDS = ["id", "apiVersion", "version", "name", "description", "words", "parts", "runtime", "assets", "markdown", "schema", "places", "card", "settings", "needs"];
|
|
51
57
|
const PART_FIELDS = ["at", "edit", "optional", "min", "max"];
|
|
52
58
|
const RUNTIME_FIELDS = ["generated", "attrs"];
|
|
53
59
|
|
|
54
|
-
//
|
|
55
|
-
|
|
60
|
+
// Where a block may stand (`places`, notes/plans/custom-blocks-spec-2026-11-07.md section 1): in a
|
|
61
|
+
// document's flow, on a custom page's board as a card. One that says nothing is a document's, as every
|
|
62
|
+
// package before the field was.
|
|
63
|
+
const PLACES = ["document", "page"];
|
|
64
|
+
const DOCUMENT_ONLY = ["document"];
|
|
65
|
+
// What `card` says of a card on a board, in cells of the grid: a row is 12 of them, and a card at most
|
|
66
|
+
// 24 high.
|
|
67
|
+
const CARD_FIELDS = ["sizes", "w", "h", "min", "max", "resize", "fit", "bare"];
|
|
68
|
+
const GRID = { w: 12, h: 24 };
|
|
69
|
+
const FITS = ["fixed", "content"];
|
|
70
|
+
const NO_CARD = { sizes: null, any: false, w: 4, h: null, min: { w: 1, h: 1 }, max: { ...GRID }, resize: false, fit: "fixed", bare: false };
|
|
71
|
+
// A card setting: its key, a JavaScript name as a block reads it from its settings part; its kinds,
|
|
72
|
+
// each a field of the form the board draws; `required`: the card shows nothing until the setting holds a
|
|
73
|
+
// value (a weather card's city), which gallery page check says of a card that has none.
|
|
74
|
+
const SETTING_FIELDS = ["key", "label", "type", "options", "default", "required"];
|
|
75
|
+
const SETTING_KEY = /^[a-z][a-zA-Z0-9]*$/;
|
|
76
|
+
const SETTING_TYPES = ["text", "number", "select", "date", "switch", "document"];
|
|
77
|
+
const DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
78
|
+
/** The data part a block with settings keeps their values in, JSON, as the board's form writes them. */
|
|
79
|
+
export const SETTINGS_PART = "settings";
|
|
80
|
+
// What a block asks to use: the workspace's data, the keyed tables of its document, the network of a
|
|
81
|
+
// host (lowercase, no port and no path, "*." first for its subdomains: ./net-policy.mjs HOST).
|
|
82
|
+
const NEEDS = ["workspace", "tables"];
|
|
83
|
+
|
|
84
|
+
// What a package's part may be edited as: its text, its data through the kit's edit, the document's
|
|
85
|
+
// blocks (a slot, marked data-doc-slot="<name>" in its markup), or not at all.
|
|
86
|
+
const EDITS = ["text", "data", "flow", "none"];
|
|
87
|
+
// What a slot's name may be: it is written in an attribute's value, and a selector finds it there.
|
|
88
|
+
const SLOT_NAME = /^[a-z][a-z0-9-]*$/;
|
|
89
|
+
/** Where a part edited as flow is in an instance: the slot of its name. */
|
|
90
|
+
export const slotAt = (name) => `div[${SLOT}="${name}"], section[${SLOT}="${name}"]`;
|
|
91
|
+
// A manifest's parts as the engines read them: a slot's `at` is its mark, which the manifest does not write.
|
|
92
|
+
const partsRead = (parts) => Object.fromEntries(Object.entries(parts).map(([name, part]) => [name, part.edit === "flow" ? { ...part, at: slotAt(name) } : part]));
|
|
56
93
|
const MARKDOWN = ["parts", "text"];
|
|
57
94
|
|
|
58
95
|
// The files of a package by their fixed names: those served from its folder (kit.js and style.css are
|
|
@@ -142,7 +179,7 @@ const notTooLong = (bytes, name) => {
|
|
|
142
179
|
};
|
|
143
180
|
|
|
144
181
|
const onlyFields = (table, fields, where = "") => {
|
|
145
|
-
for (const key of Object.keys(table)) if (!fields.includes(key)) fail(said("{0}
|
|
182
|
+
for (const key of Object.keys(table)) if (!fields.includes(key)) fail(said("{0} 不是自定义块的清单能写的字段", `${where}${key}`));
|
|
146
183
|
};
|
|
147
184
|
const required = (manifest, fields) => {
|
|
148
185
|
for (const field of fields) if (manifest[field] === undefined) fail(said("缺少 {0}", field));
|
|
@@ -158,13 +195,21 @@ function checkPart(name, part) {
|
|
|
158
195
|
const where = `parts.${name}`;
|
|
159
196
|
if (!isTable(part)) fail(said("{0} 要写成一张表", where));
|
|
160
197
|
onlyFields(part, PART_FIELDS, `${where}.`);
|
|
198
|
+
if (part.edit === "flow") {
|
|
199
|
+
// A slot: found by its mark, one to an instance.
|
|
200
|
+
if (!SLOT_NAME.test(name)) fail(said("{0} 是插槽,名字只用小写字母、数字和连字符", where));
|
|
201
|
+
if (part.at !== undefined) fail(said("{0} 是插槽,由 data-doc-slot=\"{1}\" 标出,不写 at", where, name));
|
|
202
|
+
if (part.min !== undefined || part.max !== undefined) fail(said("{0} 是插槽,一个实例里只有一个,不写 min、max", where));
|
|
203
|
+
if (part.optional !== undefined && typeof part.optional !== "boolean") fail(said("{0} 要写成 true 或 false", `${where}.optional`));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
161
206
|
if (!isWords(part.at)) fail(said("缺少 {0}", `${where}.at`));
|
|
162
207
|
try {
|
|
163
208
|
parsePart(part.at);
|
|
164
209
|
} catch (error) {
|
|
165
210
|
fail(said("{0} 写错了:{1}", `${where}.at`, error.message));
|
|
166
211
|
}
|
|
167
|
-
if (!EDITS.includes(part.edit)) fail(said("{0} 的 edit 只能是 text、data 或 none", where));
|
|
212
|
+
if (!EDITS.includes(part.edit)) fail(said("{0} 的 edit 只能是 text、data、flow 或 none", where));
|
|
168
213
|
if (part.optional !== undefined && typeof part.optional !== "boolean") fail(said("{0} 要写成 true 或 false", `${where}.optional`));
|
|
169
214
|
for (const bound of ["min", "max"]) if (part[bound] !== undefined && !(Number.isInteger(part[bound]) && part[bound] >= 0)) fail(said("{0} 要写成不小于 0 的整数", `${where}.${bound}`));
|
|
170
215
|
if (part.min > part.max) fail(said("{0} 的 min 比 max 大,没有实例能满足", where));
|
|
@@ -195,7 +240,7 @@ function runtimeOf(runtime, id) {
|
|
|
195
240
|
if (!isTable(attrs)) fail(said("{0} 要写成一张表", "runtime.attrs"));
|
|
196
241
|
for (const names of Object.values(attrs)) {
|
|
197
242
|
if (!Array.isArray(names) || !names.every(isWords)) fail(said("{0} 要写成一串文字", "runtime.attrs"));
|
|
198
|
-
for (const name of names) if (OWN_NAME.test(name)) fail(said("{0} 是 Gallery
|
|
243
|
+
for (const name of names) if (OWN_NAME.test(name)) fail(said("{0} 是 Gallery 自己的名字,自定义块不能用", name));
|
|
199
244
|
}
|
|
200
245
|
const made = (selector) => {
|
|
201
246
|
const written = scoped(selector, "runtime.generated");
|
|
@@ -208,14 +253,136 @@ function runtimeOf(runtime, id) {
|
|
|
208
253
|
};
|
|
209
254
|
}
|
|
210
255
|
|
|
256
|
+
const isCount = (value, most) => Number.isInteger(value) && value >= 1 && value <= most;
|
|
257
|
+
const twice = (list) => list.find((value, index) => list.indexOf(value) !== index);
|
|
258
|
+
|
|
259
|
+
// `places`: one place or both, each once.
|
|
260
|
+
function placesOf(places) {
|
|
261
|
+
if (places === undefined) return DOCUMENT_ONLY;
|
|
262
|
+
if (!Array.isArray(places) || places.length === 0 || !places.every((place) => PLACES.includes(place))) fail(said("places 要写成 document、page 中的一个或两个,如 [\"document\"]"));
|
|
263
|
+
if (twice(places)) fail(said("places 里 {0} 写了两次", twice(places)));
|
|
264
|
+
return [...places];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// `card`: as a board reads it, every field there (NO_CARD's where the manifest says nothing; `h` null:
|
|
268
|
+
// the fewest whole cells its content takes). With `sizes`, the first is the default, and no w or h is
|
|
269
|
+
// written beside them; a min or a max beside them frees the card (`any`): the sizes are the common ones
|
|
270
|
+
// its 大小 menu lists, any whole size between min and max is its too (resizing by the corner, a place),
|
|
271
|
+
// and each of the sizes stands inside them.
|
|
272
|
+
function cardOf(card) {
|
|
273
|
+
if (card === undefined) return NO_CARD;
|
|
274
|
+
if (!isTable(card)) fail(said("{0} 要写成一张表", "card"));
|
|
275
|
+
onlyFields(card, CARD_FIELDS, "card.");
|
|
276
|
+
const sized = (pair) => Array.isArray(pair) && pair.length === 2 && isCount(pair[0], GRID.w) && isCount(pair[1], GRID.h);
|
|
277
|
+
if (card.sizes !== undefined) {
|
|
278
|
+
if (!Array.isArray(card.sizes) || card.sizes.length === 0 || !card.sizes.every(sized)) fail(said("card.sizes 要写成 [宽, 高] 的一串,宽 1 到 {0} 格,高 1 到 {1} 格", GRID.w, GRID.h));
|
|
279
|
+
const repeated = twice(card.sizes.map((pair) => pair.join("x")));
|
|
280
|
+
if (repeated) fail(said("card.sizes 里 {0} 写了两次", repeated));
|
|
281
|
+
const beside = ["w", "h"].find((field) => card[field] !== undefined);
|
|
282
|
+
if (beside) fail(said("写了 card.sizes,就不再写 card.{0}:第一种大小是默认的", beside));
|
|
283
|
+
}
|
|
284
|
+
for (const axis of ["w", "h"]) if (card[axis] !== undefined && !isCount(card[axis], GRID[axis])) fail(said("{0} 要写成 1 到 {1} 的整数", `card.${axis}`, GRID[axis]));
|
|
285
|
+
const bounds = {};
|
|
286
|
+
for (const bound of ["min", "max"]) {
|
|
287
|
+
const value = card[bound];
|
|
288
|
+
if (value === undefined) continue;
|
|
289
|
+
if (!isTable(value)) fail(said("{0} 要写成 { w, h },单位是格", `card.${bound}`));
|
|
290
|
+
onlyFields(value, ["w", "h"], `card.${bound}.`);
|
|
291
|
+
for (const axis of ["w", "h"]) if (value[axis] !== undefined && !isCount(value[axis], GRID[axis])) fail(said("{0} 要写成 1 到 {1} 的整数", `card.${bound}.${axis}`, GRID[axis]));
|
|
292
|
+
bounds[bound] = value;
|
|
293
|
+
}
|
|
294
|
+
const min = { w: bounds.min?.w ?? 1, h: bounds.min?.h ?? 1 };
|
|
295
|
+
const max = { w: bounds.max?.w ?? GRID.w, h: bounds.max?.h ?? GRID.h };
|
|
296
|
+
const w = card.sizes ? card.sizes[0][0] : card.w ?? NO_CARD.w;
|
|
297
|
+
const h = card.sizes ? card.sizes[0][1] : card.h ?? null;
|
|
298
|
+
const any = Boolean(card.sizes) && (card.min !== undefined || card.max !== undefined);
|
|
299
|
+
if (any) {
|
|
300
|
+
const outside = card.sizes.find(([width, height]) => width < min.w || width > max.w || height < min.h || height > max.h);
|
|
301
|
+
if (outside) fail(said("card.sizes 里 {0} 不在 card.min 到 card.max 之间", outside.join("x")));
|
|
302
|
+
}
|
|
303
|
+
for (const axis of ["w", "h"]) {
|
|
304
|
+
if (min[axis] > max[axis]) fail(said("card.min.{0} 比 card.max.{0} 大", axis));
|
|
305
|
+
const value = { w, h }[axis];
|
|
306
|
+
if (value !== null && !card.sizes && (value < min[axis] || value > max[axis])) fail(said("默认的 card.{0} 是 {1},不在 card.min 到 card.max 之间({2} 到 {3})", axis, value, min[axis], max[axis]));
|
|
307
|
+
}
|
|
308
|
+
for (const flag of ["resize", "bare"]) if (card[flag] !== undefined && typeof card[flag] !== "boolean") fail(said("{0} 要写成 true 或 false", `card.${flag}`));
|
|
309
|
+
if (card.fit !== undefined && !FITS.includes(card.fit)) fail(said("card.fit 只能是 fixed 或 content"));
|
|
310
|
+
return {
|
|
311
|
+
sizes: card.sizes ? card.sizes.map(([width, height]) => [width, height]) : null,
|
|
312
|
+
any, w, h, min, max,
|
|
313
|
+
resize: card.resize ?? false,
|
|
314
|
+
fit: card.fit ?? "fixed",
|
|
315
|
+
bare: card.bare ?? false,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Whether `value` can be the default of a setting of `type` (with its `options`).
|
|
320
|
+
const fitsSetting = (value, { type, options }) => ({
|
|
321
|
+
text: typeof value === "string",
|
|
322
|
+
number: typeof value === "number" && Number.isFinite(value),
|
|
323
|
+
select: options?.includes(value),
|
|
324
|
+
date: typeof value === "string" && DATE.test(value),
|
|
325
|
+
switch: typeof value === "boolean",
|
|
326
|
+
document: typeof value === "string",
|
|
327
|
+
})[type];
|
|
328
|
+
|
|
329
|
+
// `settings`: the fields of a card's form, each key once; a block with any keeps their values in a JSON
|
|
330
|
+
// data part of its own (SETTINGS_PART), which its parts are to name.
|
|
331
|
+
function settingsOf(settings, parts) {
|
|
332
|
+
if (settings === undefined) return [];
|
|
333
|
+
if (!Array.isArray(settings)) fail(said("{0} 要写成一串字段", "settings"));
|
|
334
|
+
const keys = [];
|
|
335
|
+
settings.forEach((setting, index) => {
|
|
336
|
+
const where = `settings[${index}]`;
|
|
337
|
+
if (!isTable(setting)) fail(said("{0} 要写成一张表", where));
|
|
338
|
+
onlyFields(setting, SETTING_FIELDS, `${where}.`);
|
|
339
|
+
if (typeof setting.key !== "string" || !SETTING_KEY.test(setting.key)) fail(said("{0} 的 key 以小写字母开头,只用字母和数字(如 city、startDate)", where));
|
|
340
|
+
if (keys.includes(setting.key)) fail(said("settings 里 key {0} 写了两次", setting.key));
|
|
341
|
+
keys.push(setting.key);
|
|
342
|
+
bothLanguages(setting.label, `${where}.label`);
|
|
343
|
+
if (!SETTING_TYPES.includes(setting.type)) fail(said("{0} 的 type 只能是 {1}", where, SETTING_TYPES.join(", ")));
|
|
344
|
+
if (setting.type === "select") {
|
|
345
|
+
if (!Array.isArray(setting.options) || setting.options.length === 0 || !setting.options.every(isWords)) fail(said("{0} 是 select,要有 options:一串文字", where));
|
|
346
|
+
if (twice(setting.options)) fail(said("{0} 的 options 里 {1} 写了两次", where, twice(setting.options)));
|
|
347
|
+
} else if (setting.options !== undefined) fail(said("{0} 不是 select,不写 options", where));
|
|
348
|
+
if (setting.default !== undefined && !fitsSetting(setting.default, setting)) fail(said("{0} 的 default 和它的 type {1} 不符", where, setting.type));
|
|
349
|
+
if (setting.required !== undefined && typeof setting.required !== "boolean") fail(said("{0} 的 required 要写 true 或 false", where));
|
|
350
|
+
});
|
|
351
|
+
const part = parts[SETTINGS_PART];
|
|
352
|
+
if (settings.length > 0 && !(part?.edit === "data" && tailTags(part.at).every((tag) => tag === "script") && tailTags(part.at).length > 0)) {
|
|
353
|
+
fail(said("写了 settings,parts 里就要有一个名为 settings、edit 为 data 的部分,它是一个 <script type=\"application/json\">,存卡片设置的值"));
|
|
354
|
+
}
|
|
355
|
+
return settings.map((setting) => ({ ...setting }));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// `needs`: what a block asks to use, each once.
|
|
359
|
+
function needsOf(needs) {
|
|
360
|
+
if (needs === undefined) return [];
|
|
361
|
+
if (!Array.isArray(needs)) fail(said("{0} 要写成一串文字", "needs"));
|
|
362
|
+
for (const need of needs) {
|
|
363
|
+
if (typeof need === "string" && (NEEDS.includes(need) || (need.startsWith(NET) && HOST.test(need.slice(NET.length))))) continue;
|
|
364
|
+
fail(said("needs 里的 {0} 不认识:只认 workspace、tables 和 net:<域名>(小写的主机名,不带端口和路径,可以以 *. 开头)", typeof need === "string" ? need : JSON.stringify(need)));
|
|
365
|
+
}
|
|
366
|
+
if (twice(needs)) fail(said("needs 里 {0} 写了两次", twice(needs)));
|
|
367
|
+
return [...needs];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// What a block that may stand on a custom page cannot hold: a slot, whose blocks are a document's,
|
|
371
|
+
// which no page has the editor and the rendering of.
|
|
372
|
+
function pageParts(places, parts) {
|
|
373
|
+
if (!places.includes("page")) return;
|
|
374
|
+
const slot = Object.entries(parts).find(([, part]) => part.edit === "flow");
|
|
375
|
+
if (slot) fail(said("places 里有 page,就不能有插槽:{0} 的 edit 是 flow,插槽放的是文档的块,自定义页上没有", `parts.${slot[0]}`));
|
|
376
|
+
}
|
|
377
|
+
|
|
211
378
|
// `assets`: the kit's files a package asks for, by id, and files of its own, by their path in its folder.
|
|
212
379
|
function assetsOf(assets, folder) {
|
|
213
380
|
if (assets === undefined) return { kit: [], own: [] };
|
|
214
381
|
if (!Array.isArray(assets) || !assets.every(isWords)) fail(said("{0} 要写成一串文字", "assets"));
|
|
215
382
|
const own = assets.filter((asset) => !KIT_ASSETS.has(asset));
|
|
216
383
|
for (const asset of own) {
|
|
217
|
-
if (!OWN_FILE.test(asset)) fail(said("assets 里的 {0}
|
|
218
|
-
if (!ownPath(folder, asset)) fail(said("assets 写了 {0}
|
|
384
|
+
if (!OWN_FILE.test(asset)) fail(said("assets 里的 {0} 既不是套件的资源,也不是块的文件夹里的文件", asset));
|
|
385
|
+
if (!ownPath(folder, asset)) fail(said("assets 写了 {0},块的文件夹里没有这个文件", asset));
|
|
219
386
|
}
|
|
220
387
|
return { kit: assets.filter((asset) => KIT_ASSETS.has(asset)), own };
|
|
221
388
|
}
|
|
@@ -230,12 +397,12 @@ function packageOf(id, folder, text) {
|
|
|
230
397
|
fail(said("component.json 不是 JSON:{0}", error.message));
|
|
231
398
|
}
|
|
232
399
|
if (!isTable(manifest)) fail(said("component.json 写的不是一个对象"));
|
|
233
|
-
if (!PACKAGE_ID.test(id)) fail(said("{0}
|
|
234
|
-
for (const name of id.split("/")) if (DEVICE_NAMES.has(name)) fail(said("{0}
|
|
400
|
+
if (!PACKAGE_ID.test(id)) fail(said("{0} 不能做自定义块的 id:范围和名字都只用小写字母、数字和连字符", id));
|
|
401
|
+
for (const name of id.split("/")) if (DEVICE_NAMES.has(name)) fail(said("{0} 不能做自定义块的 id:{1} 是 Windows 留给设备的名字", id, name));
|
|
235
402
|
if (manifest.id !== id) fail(said("清单的 id 是 {0},和它的文件夹 {1} 不一样", String(manifest.id), id));
|
|
236
403
|
required(manifest, ["apiVersion"]);
|
|
237
404
|
if (!Number.isInteger(manifest.apiVersion) || manifest.apiVersion < 1) fail(said("apiVersion 要写成一个正整数"));
|
|
238
|
-
if (manifest.apiVersion !== API_VERSION) throw refusal(said("
|
|
405
|
+
if (manifest.apiVersion !== API_VERSION) throw refusal(said("这个自定义块要 apiVersion {0},这一版 Gallery 只支持 {1}", manifest.apiVersion, API_VERSION), { disabled: true, version: isWords(manifest.version) ? manifest.version : null });
|
|
239
406
|
onlyFields(manifest, FIELDS);
|
|
240
407
|
required(manifest, ["version", "name", "description", "parts"]);
|
|
241
408
|
if (!isWords(manifest.version)) fail(said("{0} 要写成文字", "version"));
|
|
@@ -248,12 +415,17 @@ function packageOf(id, folder, text) {
|
|
|
248
415
|
const { kit, own } = assetsOf(manifest.assets, folder);
|
|
249
416
|
if (manifest.markdown !== undefined && !MARKDOWN.includes(manifest.markdown)) fail(said("markdown 只能是 parts 或 text"));
|
|
250
417
|
if (manifest.schema !== undefined && !(Number.isInteger(manifest.schema) && manifest.schema >= 1)) fail(said("schema 要写成一个正整数"));
|
|
418
|
+
const places = placesOf(manifest.places);
|
|
419
|
+
pageParts(places, manifest.parts);
|
|
420
|
+
const card = cardOf(manifest.card);
|
|
421
|
+
const settings = settingsOf(manifest.settings, manifest.parts);
|
|
422
|
+
const needs = needsOf(manifest.needs);
|
|
251
423
|
const template = ownFile(folder, TEMPLATE);
|
|
252
424
|
if (template) notTooLong(template, TEMPLATE);
|
|
253
425
|
return {
|
|
254
426
|
id,
|
|
255
427
|
match: instanceMatch(id),
|
|
256
|
-
parts: manifest.parts,
|
|
428
|
+
parts: partsRead(manifest.parts),
|
|
257
429
|
...(runtime ? { runtime } : {}),
|
|
258
430
|
...(manifest.schema !== undefined ? { schema: manifest.schema } : {}),
|
|
259
431
|
apiVersion: manifest.apiVersion,
|
|
@@ -263,6 +435,10 @@ function packageOf(id, folder, text) {
|
|
|
263
435
|
words: manifest.words ?? "",
|
|
264
436
|
assets: kit,
|
|
265
437
|
markdown: manifest.markdown ?? "parts",
|
|
438
|
+
places,
|
|
439
|
+
card,
|
|
440
|
+
settings,
|
|
441
|
+
needs,
|
|
266
442
|
files: [...new Set([...SERVED.filter((file) => ownPath(folder, file)), ...own])],
|
|
267
443
|
template: template && wordsOf(template),
|
|
268
444
|
folder,
|
|
@@ -290,10 +466,20 @@ const workspaceRoot = () => findWorkspace().root;
|
|
|
290
466
|
|
|
291
467
|
// A file edited by hand holds what it holds: of its lists, what can be an id is read, once each, and
|
|
292
468
|
// the rest is passed over, one that names nothing there doing nothing. An id may be of a package that
|
|
293
|
-
// comes back, so it stays. Only a package can be disabled.
|
|
469
|
+
// comes back, so it stays. Only a package can be disabled or unlisted.
|
|
294
470
|
const NAMED = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-]*)?$/;
|
|
295
471
|
const idsIn = (list, shape) => [...new Set(Array.isArray(list) ? list.filter((id) => typeof id === "string" && shape.test(id)) : [])];
|
|
296
|
-
|
|
472
|
+
// `net`, the reader's consents (a block's card, 设置 › 组件列表): of each package by its id, the hosts of its
|
|
473
|
+
// needs it was allowed to reach, those that can be a needs' host (./net-policy.mjs HOST), once each; a
|
|
474
|
+
// package with none named none.
|
|
475
|
+
const consentsIn = (net) => Object.fromEntries(Object.entries(isTable(net) ? net : {}).filter(([id]) => PACKAGE_ID.test(id)).map(([id, hosts]) => [id, idsIn(hosts, HOST)]).filter(([, hosts]) => hosts.length > 0));
|
|
476
|
+
// `packs`, the packs' switches (设置 › 组件列表's pack cards): { "<pack id>": { "enabled": false } }, by id, a
|
|
477
|
+
// pack it names none of on; what is no pack's id or says no boolean is passed over.
|
|
478
|
+
const switchesIn = (packs) => Object.fromEntries(Object.entries(isTable(packs) ? packs : {}).filter(([id, entry]) => PACK_ID.test(id) && typeof entry?.enabled === "boolean").map(([id, entry]) => [id, entry.enabled]));
|
|
479
|
+
const settingsIn = (file) => {
|
|
480
|
+
const packs = switchesIn(file?.components?.packs);
|
|
481
|
+
return { hidden: idsIn(file?.components?.hidden, NAMED), disabled: idsIn(file?.components?.disabled, PACKAGE_ID), shown: idsIn(file?.components?.shown, PACKAGE_ID), unlisted: idsIn(file?.components?.unlisted, PACKAGE_ID), net: consentsIn(file?.components?.net), packs, packsOff: Object.keys(packs).filter((id) => packs[id] === false).sort() };
|
|
482
|
+
};
|
|
297
483
|
|
|
298
484
|
// gallery.json's text (null: no file) as what it holds, `value`, or `problem`, why it cannot be taken
|
|
299
485
|
// for a workspace's: what the catalog goes on through (settingsNow) and no writer writes over.
|
|
@@ -314,8 +500,11 @@ function fileAt(root) {
|
|
|
314
500
|
}
|
|
315
501
|
|
|
316
502
|
/**
|
|
317
|
-
* What gallery.json says of the components: { hidden, disabled }, ids of packages and, in
|
|
318
|
-
* names of built-in components
|
|
503
|
+
* What gallery.json says of the components: { hidden, disabled, shown, unlisted, net, packs, packsOff }, ids of packages and, in
|
|
504
|
+
* `hidden`, names of built-in components (inDocumentMenus reads `hidden`, `shown` and `unlisted`; a block
|
|
505
|
+
* unlisted, 设置 › 组件列表's master switch off, is offered by no menu and no library); `net` the hosts
|
|
506
|
+
* each package was allowed to reach, by its id (consentsIn); `packs` each pack's switch named there, by its id (true on,
|
|
507
|
+
* false off), `packsOff` the ids of those off. One that is not there says nothing, and neither does one that does not
|
|
319
508
|
* read or is another program's: what goes on using a workspace goes by the catalog (readCatalog).
|
|
320
509
|
*/
|
|
321
510
|
export const componentSettings = (root = workspaceRoot()) => settingsIn(fileAt(root).value);
|
|
@@ -324,12 +513,17 @@ export const componentSettings = (root = workspaceRoot()) => settingsIn(fileAt(r
|
|
|
324
513
|
const NOT_WRITABLE = ["EPERM", "EACCES", "EBUSY", "EROFS"];
|
|
325
514
|
|
|
326
515
|
/**
|
|
327
|
-
* gallery.json with `
|
|
328
|
-
*
|
|
516
|
+
* gallery.json with the pack `pack` on or off, as `enabled` says (components.packs, its entry's other fields
|
|
517
|
+
* kept), or with `id` hidden or not, shown or not, disabled or not and unlisted or not, as `hidden`,
|
|
518
|
+
* `shown`, `disabled` and `unlisted` say (true, false, or left out for as it is), written at once and with
|
|
519
|
+
* all else it holds kept; `shown` and `unlisted` are written where they hold an id or were there already
|
|
520
|
+
* (a block no entry names is listed). `net`, the hosts `id` is allowed
|
|
521
|
+
* to reach (a list: its consent, all it names in place of what was there; [] takes it back), written in
|
|
522
|
+
* components.net under its id, which goes with its last host, and components.net with its last id. A file that does
|
|
329
523
|
* not read, is another program's, changed under this write or cannot be written is refused, and stays
|
|
330
524
|
* as it is: it is not this write's to mend.
|
|
331
525
|
*/
|
|
332
|
-
export async function writeComponentSettings(root, { id, hidden, disabled }) {
|
|
526
|
+
export async function writeComponentSettings(root, { id, hidden, shown, disabled, unlisted, net, pack, enabled }) {
|
|
333
527
|
const file = layoutOf(root).marker;
|
|
334
528
|
const text = await fs.readFile(file, "utf8").catch((error) => {
|
|
335
529
|
if (error.code === "ENOENT") return null;
|
|
@@ -338,8 +532,26 @@ export async function writeComponentSettings(root, { id, hidden, disabled }) {
|
|
|
338
532
|
const { value, problem } = fileOf(text);
|
|
339
533
|
if (problem) fail(problem);
|
|
340
534
|
const named = (list, on) => (on === undefined ? list : on ? [...new Set([...list, id])] : list.filter((other) => other !== id));
|
|
341
|
-
const { hidden: wasHidden, disabled: wasDisabled } = settingsIn(value);
|
|
342
|
-
const
|
|
535
|
+
const { hidden: wasHidden, disabled: wasDisabled, shown: wasShown, unlisted: wasUnlisted } = settingsIn(value);
|
|
536
|
+
const before = isTable(value?.components) ? value.components : {};
|
|
537
|
+
const nowShown = named(wasShown, shown);
|
|
538
|
+
const nowUnlisted = named(wasUnlisted, unlisted);
|
|
539
|
+
const components = {
|
|
540
|
+
...before, hidden: named(wasHidden, hidden), disabled: named(wasDisabled, disabled),
|
|
541
|
+
...(nowShown.length > 0 || Object.hasOwn(before, "shown") ? { shown: nowShown } : {}),
|
|
542
|
+
...(nowUnlisted.length > 0 || Object.hasOwn(before, "unlisted") ? { unlisted: nowUnlisted } : {}),
|
|
543
|
+
};
|
|
544
|
+
if (pack !== undefined) {
|
|
545
|
+
const switches = isTable(before.packs) ? before.packs : {};
|
|
546
|
+
components.packs = { ...switches, [pack]: { ...(isTable(switches[pack]) ? switches[pack] : {}), enabled: enabled === true } };
|
|
547
|
+
}
|
|
548
|
+
if (net !== undefined) {
|
|
549
|
+
const consents = { ...(isTable(before.net) ? before.net : {}) };
|
|
550
|
+
if (net.length > 0) consents[id] = [...new Set(net)];
|
|
551
|
+
else delete consents[id];
|
|
552
|
+
if (Object.keys(consents).length > 0) components.net = consents;
|
|
553
|
+
else delete components.net;
|
|
554
|
+
}
|
|
343
555
|
const written = await writeAtomic(file, `${JSON.stringify({ ...(value ?? WORKSPACE_MARK), components }, null, 2)}\n`, { expect: text }).catch((error) => {
|
|
344
556
|
if (NOT_WRITABLE.includes(error.code)) fail(said("gallery.json 写不进去:可能是只读的,或被别的程序占着"));
|
|
345
557
|
throw error;
|
|
@@ -353,31 +565,60 @@ const turnedOff = (found) => ({ ...found, off: true, disabled: true, problem: sa
|
|
|
353
565
|
|
|
354
566
|
const NO_SETTINGS = settingsIn(null);
|
|
355
567
|
|
|
356
|
-
/** The stamp of a catalog: of what its packages are, those that do not load and why too, of what is hidden and of why gallery.json does not read,
|
|
357
|
-
export const catalogStamp = ({ packages, problems, settings = NO_SETTINGS }) => hashOf((hash) => {
|
|
568
|
+
/** The stamp of a catalog: of what its packages are, those that do not load and why too, of what is hidden, shown and unlisted, the packs off and their names, and of why gallery.json does not read, none of which changes a package. */
|
|
569
|
+
export const catalogStamp = ({ packages, problems, settings = NO_SETTINGS, packs = new Map() }) => hashOf((hash) => {
|
|
358
570
|
for (const { id, stamp } of [...packages.values(), ...problems.values()].sort(byId)) hash.update(`${id} ${stamp}\n`);
|
|
359
571
|
hash.update(`hidden ${[...settings.hidden].sort().join(" ")}\n`);
|
|
572
|
+
hash.update(`shown ${[...settings.shown].sort().join(" ")}\n`);
|
|
573
|
+
hash.update(`unlisted ${[...(settings.unlisted ?? [])].sort().join(" ")}\n`);
|
|
574
|
+
hash.update(`net ${consentPairs(settings).join(" ")}\n`);
|
|
575
|
+
hash.update(`packs off ${(settings.packsOff ?? []).join(" ")}\n`);
|
|
576
|
+
for (const [scope, name] of [...packs].sort(([a], [b]) => (a < b ? -1 : 1))) hash.update(`pack ${scope} ${JSON.stringify(name)}\n`);
|
|
360
577
|
hash.update(`settings ${settings.problem?.message ?? ""}\n`);
|
|
361
578
|
});
|
|
362
579
|
|
|
580
|
+
// The consents of `settings` as "<id>@<host>", sorted: what the stamp and the settings line say of them.
|
|
581
|
+
const consentPairs = ({ net = {} }) => Object.entries(net).flatMap(([id, hosts]) => hosts.map((host) => `${id}@${host}`)).sort();
|
|
582
|
+
|
|
363
583
|
// The settings a catalog goes by: what gallery.json says or, while it cannot be read as saying
|
|
364
584
|
// anything, what was in use (`held`, a broken manifest's hold, for a slip by hand), with why (`problem`).
|
|
365
585
|
function settingsNow(root, held) {
|
|
366
586
|
const { value, problem } = fileAt(root);
|
|
367
|
-
return problem ? { hidden: held.hidden, disabled: held.disabled, problem } : settingsIn(value);
|
|
587
|
+
return problem ? { hidden: held.hidden, disabled: held.disabled, shown: held.shown ?? [], unlisted: held.unlisted ?? [], net: held.net ?? {}, packs: held.packs ?? {}, packsOff: held.packsOff ?? [], problem } : settingsIn(value);
|
|
368
588
|
}
|
|
369
589
|
|
|
590
|
+
// What runs before the catalog reads the blocks of a workspace that holds Gallery's own (the scopes of
|
|
591
|
+
// Gallery's packs, `ownScopes`): (root, ids) -> anything. A server sets it as it starts
|
|
592
|
+
// (shared/shipped-blocks.mjs followOnRead: a copy as it was added brought up to Gallery's first), so that
|
|
593
|
+
// this file imports nothing of the package's paths, reading whichever workspace it is given; a command sets none.
|
|
594
|
+
let beforeRead = null;
|
|
595
|
+
let ownScopes = [];
|
|
596
|
+
|
|
597
|
+
/** `run(root, ids)` runs before each read of a workspace's blocks that finds Gallery's own (`ids`, those of `scopes`, the scopes of Gallery's packs), from now on in this process. */
|
|
598
|
+
export const beforeCatalogRead = (run, scopes = ["gallery"]) => {
|
|
599
|
+
beforeRead = run;
|
|
600
|
+
ownScopes = [...scopes];
|
|
601
|
+
};
|
|
602
|
+
|
|
370
603
|
/**
|
|
371
604
|
* The workspace's packages as they are on disk now: the catalog, whatever a package or gallery.json
|
|
372
605
|
* holds. `held`: the settings of the catalog in use, for a file that does not read; a process with
|
|
373
606
|
* none has nothing to go by. `on`: a package read as its files say whatever gallery.json says of it,
|
|
374
|
-
* for what holds it to them (gallery
|
|
607
|
+
* for what holds it to them (gallery block check). In a server, Gallery's own blocks as they were
|
|
608
|
+
* added are brought up to Gallery's first (beforeCatalogRead).
|
|
375
609
|
*/
|
|
376
610
|
export function readCatalog(root = workspaceRoot(), held = NO_SETTINGS, { on = null } = {}) {
|
|
377
611
|
const settings = settingsNow(root, held);
|
|
378
612
|
const packages = new Map();
|
|
379
613
|
const problems = new Map();
|
|
380
|
-
|
|
614
|
+
const folders = packageFolders(root);
|
|
615
|
+
const own = folders.map(({ id }) => id).filter((id) => ownScopes.includes(id.split("/")[0]));
|
|
616
|
+
if (beforeRead && own.length > 0) {
|
|
617
|
+
try {
|
|
618
|
+
beforeRead(root, own);
|
|
619
|
+
} catch {} // what it could not do leaves the blocks as they are
|
|
620
|
+
}
|
|
621
|
+
for (const { id, folder } of folders) {
|
|
381
622
|
const found = readPackage(id, folder);
|
|
382
623
|
(found.problem ? problems : packages).set(found.id, found);
|
|
383
624
|
}
|
|
@@ -387,7 +628,30 @@ export function readCatalog(root = workspaceRoot(), held = NO_SETTINGS, { on = n
|
|
|
387
628
|
problems.set(id, turnedOff(packages.get(id)));
|
|
388
629
|
packages.delete(id);
|
|
389
630
|
}
|
|
390
|
-
|
|
631
|
+
const packs = packNames(root, folders.map(({ id }) => id.split("/")[0]));
|
|
632
|
+
return { packages, problems, settings, packs, stamp: catalogStamp({ packages, problems, settings, packs }) };
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* What the pack.json of each scope of `scopes` (and of each folder of components/ that holds one) names
|
|
637
|
+
* it: a Map, by scope, of { zh, en }, or null where it has none or one that does not read (a scope of
|
|
638
|
+
* blocks with no pack.json is a pack of its own by its scope's name: ./block-packs.mjs).
|
|
639
|
+
*/
|
|
640
|
+
export function packNames(root, scopes = []) {
|
|
641
|
+
const { components } = layoutOf(root);
|
|
642
|
+
let withFile = [];
|
|
643
|
+
try {
|
|
644
|
+
withFile = readdirSync(components).filter((name) => PACK_ID.test(name) && existsSync(path.join(components, name, PACK_FILE)));
|
|
645
|
+
} catch {}
|
|
646
|
+
const names = new Map();
|
|
647
|
+
for (const scope of [...new Set([...scopes, ...withFile])].sort()) {
|
|
648
|
+
let name = null;
|
|
649
|
+
try {
|
|
650
|
+
name = readPackManifest(readFileSync(path.join(components, scope, PACK_FILE), "utf8")).name;
|
|
651
|
+
} catch {}
|
|
652
|
+
names.set(scope, name);
|
|
653
|
+
}
|
|
654
|
+
return names;
|
|
391
655
|
}
|
|
392
656
|
|
|
393
657
|
const kept = new Map(); // a workspace's root -> the catalog in use
|
|
@@ -411,15 +675,21 @@ export const problemIn = (language, problem) => inLanguage(language, () => told(
|
|
|
411
675
|
// Why a package does not load, in both languages, as a page and a list say it.
|
|
412
676
|
const bothProblems = (problem) => ({ zh: problemIn("zh", problem), en: problemIn("en", problem) });
|
|
413
677
|
|
|
414
|
-
/** Why gallery.json cannot be read, in both languages, as 设置 ›
|
|
678
|
+
/** Why gallery.json cannot be read, in both languages, as 设置 › 组件列表 says it, or null. */
|
|
415
679
|
export const settingsProblem = ({ settings }) => (settings.problem ? bothProblems(settings.problem) : null);
|
|
416
680
|
|
|
417
|
-
// What a package is now: "normal"
|
|
418
|
-
// does not run), or "broken", one that
|
|
419
|
-
|
|
681
|
+
// What a package is now: "normal" (the document's menus offer it: inDocumentMenus), "hidden" (they do
|
|
682
|
+
// not), "disabled" (turned off, or for an apiVersion this Gallery does not run), or "broken", one that
|
|
683
|
+
// does not load of itself.
|
|
684
|
+
const stateOf = (found, settings) => (found.problem ? (found.disabled ? "disabled" : "broken") : settingState(found.id, settings, found.places));
|
|
420
685
|
|
|
421
|
-
/**
|
|
422
|
-
|
|
686
|
+
/**
|
|
687
|
+
* What the kit is told of a package: where its instances are, its parts, what it leaves on a page, how far
|
|
688
|
+
* its content's shape goes, and what it uses (`needs`, where it names any: the kit gives an instance
|
|
689
|
+
* context.workspace for "workspace", context.fetch for a host of the net and context.table() for
|
|
690
|
+
* "tables").
|
|
691
|
+
*/
|
|
692
|
+
export const descriptionOf = ({ id, match, parts, runtime, schema, needs }) => ({ id, match, parts, ...(runtime ? { runtime } : {}), ...(schema !== undefined ? { schema } : {}), ...(needs?.length ? { needs } : {}) });
|
|
423
693
|
|
|
424
694
|
/**
|
|
425
695
|
* What the kit is told of a catalog, each by DocKit.describe, the one way a page learns a package's
|
|
@@ -494,18 +764,18 @@ export function instanceMarkup(text, id) {
|
|
|
494
764
|
function readTemplate({ id, template, parts }) {
|
|
495
765
|
if (!template) return {};
|
|
496
766
|
const read = instanceMarkup(template, id);
|
|
497
|
-
if (!read) return { problem: said("template.html
|
|
767
|
+
if (!read) return { problem: said("template.html 要是这个自定义块的一个实例,有自己的结束标签,此外什么都没有") };
|
|
498
768
|
const held = [];
|
|
499
769
|
walk({ childNodes: [read.root] }, (node) => { if (refusedInCopy(node.tagName, node.attrs)) held.push(node.tagName); });
|
|
500
770
|
if (held.length > 0) return { problem: said("template.html 里的 <{0}> 进不了新建的块:脚本、事件、样式和 Gallery 自己的标记都不写在模板里", held[0]) };
|
|
501
771
|
const short = Object.entries(parts).find(([, part]) => {
|
|
502
772
|
const count = partOf(read.root, part.at).length;
|
|
503
|
-
return count < (part.optional ? 0 : part.min ?? 1) || count > (part.max ?? Infinity);
|
|
773
|
+
return count < (part.optional ? 0 : part.min ?? 1) || count > (part.edit === "flow" ? 1 : part.max ?? Infinity);
|
|
504
774
|
});
|
|
505
775
|
return short ? { problem: said("template.html 的 {0} 和清单写的数目不符", short[0]) } : { markup: read.markup };
|
|
506
776
|
}
|
|
507
777
|
|
|
508
|
-
/** Why no menu offers the template of `found`, said()'s, for `gallery
|
|
778
|
+
/** Why no menu offers the template of `found`, said()'s, for `gallery block check` to say, or null: it has none, or one no reason keeps out. */
|
|
509
779
|
export const templateProblem = (found) => readTemplate(found).problem ?? null;
|
|
510
780
|
|
|
511
781
|
/** The markup of an instance of `found` as a new one is written, or null: it has no template a menu offers. */
|
|
@@ -515,13 +785,15 @@ export const templateOf = (found) => readTemplate(found).markup ?? null;
|
|
|
515
785
|
* What the page the editor runs on holds of a catalog: its MAP's `components` (src/editor/service.mjs),
|
|
516
786
|
* no route and no dynamic import. One entry for each package that loads, by id: { id, version, name:
|
|
517
787
|
* { zh, en }, description: { zh, en }, words, definition, stamp, template (the markup "/" puts in: one
|
|
518
|
-
* instance of it, or null), preview (the address of its picture, or null), state ("normal", or "hidden":
|
|
519
|
-
*
|
|
788
|
+
* instance of it, or null), preview (the address of its picture, or null), state ("normal", or "hidden": a menu offers what is "normal" and reads no setting), places (which the page's
|
|
789
|
+
* settingState reads with gallery.json's lists as its event stream says them), needs, markdown, assets (the kit's files it asks for,
|
|
520
790
|
* by id), tags (packageTags: what loads it in a page that was served without it, the line that tells the
|
|
521
|
-
* kit of its parts among them)
|
|
791
|
+
* kit of its parts among them), pack ({ id, name }: the pack it is of, its scope, and what its pack.json names
|
|
792
|
+
* it, null where none does: a menu writes the pack's name after a block's in grey where two packs offer
|
|
793
|
+
* blocks of one name) }. A page knows what it holds of a package's parts from the kit
|
|
522
794
|
* (descriptionsOf), and of one that came after it was served from these tags.
|
|
523
795
|
*/
|
|
524
|
-
export const menuOf = ({ packages, settings = NO_SETTINGS }) => [...packages.values()].sort(byId).map((found) => ({
|
|
796
|
+
export const menuOf = ({ packages, settings = NO_SETTINGS, packs = new Map() }) => [...packages.values()].sort(byId).map((found) => ({
|
|
525
797
|
id: found.id,
|
|
526
798
|
version: found.version,
|
|
527
799
|
name: found.name,
|
|
@@ -532,28 +804,47 @@ export const menuOf = ({ packages, settings = NO_SETTINGS }) => [...packages.val
|
|
|
532
804
|
template: templateOf(found),
|
|
533
805
|
preview: found.files.includes("preview.svg") ? packageAddress(found, "preview.svg") : null,
|
|
534
806
|
state: stateOf(found, settings),
|
|
807
|
+
places: found.places,
|
|
808
|
+
needs: found.needs,
|
|
535
809
|
markdown: found.markdown,
|
|
536
810
|
assets: found.assets,
|
|
537
811
|
tags: packageTags(found),
|
|
812
|
+
pack: { id: found.id.split("/")[0], name: packs.get(found.id.split("/")[0]) ?? null },
|
|
538
813
|
}));
|
|
539
814
|
|
|
540
815
|
/**
|
|
541
816
|
* The workspace's packages as who lists them says them, by id: { id, version, name, description (what
|
|
542
817
|
* a manifest says, null where it does not read), state ("normal", "hidden", "disabled" or "broken":
|
|
543
818
|
* stateOf), reason ({ zh, en }, why it does not load of itself, or null), template (whether it has one
|
|
544
|
-
* a menu can put in: with none, none can),
|
|
819
|
+
* a menu can put in: with none, none can), places and needs (what its manifest says, null where it does
|
|
820
|
+
* not read), hidden, shown, disabled and unlisted (what gallery.json says of it), allowed (the hosts of its needs
|
|
821
|
+
* the reader allowed it to reach, gallery.json's components.net: its switch 允许联网 is on while it holds
|
|
822
|
+
* every host its needs name) and menu (whether its switch
|
|
823
|
+
* 在文档菜单里显示 is on: inDocumentMenus, whatever `disabled` and `unlisted` say, which are switches of their
|
|
824
|
+
* own: the row's master switch is on while it is not unlisted, nor its pack's) and pack (the pack it is of: its scope) }.
|
|
545
825
|
*/
|
|
546
826
|
export const packageStates = ({ packages, problems, settings = NO_SETTINGS }) => [...packages.values(), ...problems.values()].sort(byId).map((found) => ({
|
|
547
827
|
id: found.id,
|
|
828
|
+
pack: found.id.split("/")[0],
|
|
548
829
|
version: found.version ?? null,
|
|
549
830
|
name: found.name ?? null,
|
|
550
831
|
description: found.description ?? null,
|
|
551
832
|
state: stateOf(found, settings),
|
|
552
833
|
reason: found.problem && !found.off ? bothProblems(found.problem) : null,
|
|
553
834
|
template: Boolean(templateOf(found)),
|
|
835
|
+
places: found.places ?? null,
|
|
836
|
+
needs: found.needs ?? null,
|
|
554
837
|
hidden: settings.hidden.includes(found.id),
|
|
838
|
+
shown: settings.shown.includes(found.id),
|
|
555
839
|
disabled: settings.disabled.includes(found.id),
|
|
840
|
+
unlisted: (settings.unlisted ?? []).includes(found.id),
|
|
841
|
+
allowed: (settings.net?.[found.id] ?? []).filter((host) => netHostsOf(found.needs).includes(host)),
|
|
842
|
+
menu: inDocumentMenus(found.places, { ...settings, disabled: [], unlisted: [], packsOff: [] }, found.id),
|
|
556
843
|
}));
|
|
557
844
|
|
|
558
|
-
/**
|
|
559
|
-
|
|
845
|
+
/**
|
|
846
|
+
* The message that tells a page of `settings` on its event stream, its six lists by commas (hidden,
|
|
847
|
+
* disabled, shown, the consents, "<id>@<host>" each, unlisted, and the packs off): what it offers follows
|
|
848
|
+
* them, whatever it holds, and an instance whose consent changed starts again (the kit's net.js).
|
|
849
|
+
*/
|
|
850
|
+
export const settingsLine = (settings) => `settings ${settings.hidden.join(",")} ${settings.disabled.join(",")} ${settings.shown.join(",")} ${consentPairs(settings).join(",")} ${(settings.unlisted ?? []).join(",")} ${(settings.packsOff ?? []).join(",")}`;
|