@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
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// JSON written back as it was laid out (references/block-script.md, "Writing back"): what a
|
|
2
|
+
// package's script of data holds, rewritten by a reader's gesture, changes on the lines that gesture
|
|
3
|
+
// means and no others. One copy for every side: the kit's context.editJSON (runtime/kernel.js) writes
|
|
4
|
+
// by it, and gallery block check (cli/component-look.mjs) says by it how a part not laid out so
|
|
5
|
+
// would be. Pure, no DOM and no Node.
|
|
6
|
+
|
|
7
|
+
// A value that stands alone on a line's end: no object, no list.
|
|
8
|
+
const isValue = (value) => value === null || typeof value !== "object";
|
|
9
|
+
|
|
10
|
+
/** Whether an object or a list holds values alone, or lists of values: what stands on one line (`{ "name": "价格", "weight": 3 }`, `[[1, 2], [3, 4]]`). */
|
|
11
|
+
export const isFlat = (value) => Object.values(value).every((each) => isValue(each) || (Array.isArray(each) && each.every(isValue)));
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `value` as JSON laid out as a person writes it: what isFlat says on one line, with a space inside an
|
|
15
|
+
* object's braces (`{ "name": "价格", "weight": 3 }`, `[4, 3, 5]`), anything else a line for each
|
|
16
|
+
* entry, two spaces a level from `indent`, so that a change of one value changes its line alone.
|
|
17
|
+
* @param {unknown} value
|
|
18
|
+
* @param {string} indent
|
|
19
|
+
* @returns {string}
|
|
20
|
+
*/
|
|
21
|
+
export function laidOut(value, indent) {
|
|
22
|
+
if (typeof value?.toJSON === "function") return laidOut(value.toJSON(), indent); // a Date, as JSON.stringify writes it
|
|
23
|
+
if (isValue(value)) return JSON.stringify(value) ?? "null";
|
|
24
|
+
const list = Array.isArray(value);
|
|
25
|
+
// An object's entry of no JSON (undefined, a function) is left out, as JSON.stringify leaves it; a
|
|
26
|
+
// value with toJSON (a Date) is what that gives.
|
|
27
|
+
const entries = Object.entries(value).map(([key, each]) => [key, typeof each?.toJSON === "function" ? each.toJSON() : each]).filter(([, each]) => list || (each !== undefined && typeof each !== "function"));
|
|
28
|
+
const items = entries.map(([key, each]) => `${list ? "" : `${JSON.stringify(key)}: `}${laidOut(each, `${indent} `)}`);
|
|
29
|
+
if (items.length === 0) return list ? "[]" : "{}";
|
|
30
|
+
if (isFlat(Object.fromEntries(entries))) return list ? `[${items.join(", ")}]` : `{ ${items.join(", ")} }`;
|
|
31
|
+
return `${list ? "[" : "{"}\n${items.map((item) => `${indent} ${item}`).join(",\n")}\n${indent}${list ? "]" : "}"}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The JSON of `value` in place of what `text` holds (a script of data's text): on one line where it
|
|
36
|
+
* was on one, else laid out (laidOut) from the indentation its first character stands at; the blanks
|
|
37
|
+
* around it kept, and `</` and `<!--`, which could end the script it stands in, escaped.
|
|
38
|
+
* @param {string} text
|
|
39
|
+
* @param {unknown} value
|
|
40
|
+
*/
|
|
41
|
+
export function jsonIn(text, value) {
|
|
42
|
+
const start = text.length - text.trimStart().length;
|
|
43
|
+
const end = text.trimEnd().length;
|
|
44
|
+
const indent = text.slice(text.lastIndexOf("\n", start) + 1, start);
|
|
45
|
+
const json = text.slice(start, end).includes("\n") ? laidOut(value, indent) : JSON.stringify(value) ?? "null";
|
|
46
|
+
return text.slice(0, start) + json.replaceAll("</", "<\\/").replaceAll("<!--", "\\u003c!--") + text.slice(end);
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Where a line may break inside a word: one rule for the kit's runtime (runtime/spacing.js: the
|
|
2
|
+
// reading page holds each long run in a span that breaks anywhere), its flowcharts' line model
|
|
3
|
+
// (runtime/flowchart.js piecesOf) and the page editor (page/long-runs.mjs: a text block holding one
|
|
4
|
+
// breaks anywhere as a whole). Ordinary words stay whole at a line's end, in a Chinese page as in an
|
|
5
|
+
// English one; a run of more than LONG_RUN characters with no place to break inside it (a path, a
|
|
6
|
+
// URL, a long identifier) breaks where its line ends, never carried whole to the next line leaving
|
|
7
|
+
// the line before it short (the user's words of 2026-11-07, and of 2026-11-06 before them).
|
|
8
|
+
//
|
|
9
|
+
// A run is what stands between spaces, Chinese, Japanese or Korean characters, full-width forms and
|
|
10
|
+
// the general punctuation (dashes, curly quotes, an ellipsis, a zero-width space: where a line breaks
|
|
11
|
+
// already, or what a path or an identifier does not hold): letters, digits and the marks of paths and
|
|
12
|
+
// URLs (. : / \ _ = & % # @ …). Inside one Chrome breaks a line after a hyphen and after a question
|
|
13
|
+
// mark, and at no other mark of ASCII (Chrome 156: not at a slash, a dot, a colon, a backslash or an
|
|
14
|
+
// underscore), so a run is counted by its pieces there: state-of-the-art is three short pieces, never
|
|
15
|
+
// long; D:\code\FinHarness\FinHarness-Demo.html is long by its first piece (30 characters).
|
|
16
|
+
// DOM-free.
|
|
17
|
+
|
|
18
|
+
/** A run longer than this many characters (by its longest piece) breaks anywhere. */
|
|
19
|
+
export const LONG_RUN = 20;
|
|
20
|
+
|
|
21
|
+
const RUNS = /[^\s\u2000-\u206f\u2e80-\u9fff\uac00-\ud7af\uf900-\ufaff\ufe30-\ufe4f\uff00-\uffef]+/gu;
|
|
22
|
+
const PIECES = /(?<=[-?])/u;
|
|
23
|
+
|
|
24
|
+
const long = (run) => run.length > LONG_RUN && run.split(PIECES).some((piece) => [...piece].length > LONG_RUN);
|
|
25
|
+
|
|
26
|
+
/** The long runs of `text`, in order: { index, length } each (code units). */
|
|
27
|
+
export function longRuns(text) {
|
|
28
|
+
const found = [];
|
|
29
|
+
if (text.length <= LONG_RUN) return found;
|
|
30
|
+
for (const match of text.matchAll(RUNS)) if (long(match[0])) found.push({ index: match.index, length: match[0].length });
|
|
31
|
+
return found;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Whether `text` holds a long run. */
|
|
35
|
+
export function holdsLongRun(text) {
|
|
36
|
+
if (text.length <= LONG_RUN) return false;
|
|
37
|
+
for (const match of text.matchAll(RUNS)) if (long(match[0])) return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { writeAtomic } from "./files.mjs";
|
|
5
|
+
import { layoutOf } from "./workspace.mjs";
|
|
6
|
+
|
|
7
|
+
// What the server's net route kept of the web (src/server/net-route.mjs; docs/render.md, "A block
|
|
8
|
+
// online"): each answer by the address a block asked for (its href, `{key}` as the block wrote it, never
|
|
9
|
+
// the key: ./net-policy.mjs), in memory and in the workspace's .gallery/cache/net/, a file each
|
|
10
|
+
// (<hash>.json: { url, at, type, text }), the last FILES of them. Which document's instances asked for
|
|
11
|
+
// which address, and as what, is kept beside them (documents/<slug>.json: { <url>: { at, as } }), the
|
|
12
|
+
// last PER_DOCUMENT of each: what an export of that document embeds (netSnapshot, the spec §9), so that
|
|
13
|
+
// the file shows what the reader saw last. Anything here may be thrown away: the next ask fetches again.
|
|
14
|
+
// Gallery's own, never served by a route, never in a file of the user's.
|
|
15
|
+
|
|
16
|
+
/** How many answers stay on disk. */
|
|
17
|
+
export const FILES = 200;
|
|
18
|
+
/** How many addresses a document's index keeps. */
|
|
19
|
+
export const PER_DOCUMENT = 20;
|
|
20
|
+
/** What an export's snapshot holds of the net at most: addresses, and the bytes of their answers. */
|
|
21
|
+
export const SNAPSHOT = { count: 20, bytes: 512 * 1024 };
|
|
22
|
+
|
|
23
|
+
const folderOf = (root) => layoutOf(root).netCache;
|
|
24
|
+
const fileOf = (root, url) => path.join(folderOf(root), `${createHash("sha256").update(url).digest("hex").slice(0, 24)}.json`);
|
|
25
|
+
const indexOf = (root, slug) => path.join(folderOf(root), "documents", `${slug}.json`);
|
|
26
|
+
const readJson = (file) => {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const isEntry = (entry, url) => entry && entry.url === url && typeof entry.at === "string" && typeof entry.text === "string" && typeof entry.type === "string";
|
|
34
|
+
|
|
35
|
+
/** An answer as a block asked for it (`as`: "json" or "text"): its JSON read, or its text; undefined for JSON that does not read. */
|
|
36
|
+
export function dataOf(entry, as) {
|
|
37
|
+
if (as === "text") return entry.text;
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(entry.text);
|
|
40
|
+
} catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The cache of workspace `root`: get(url) (the entry kept, from memory or disk, or null), put(url,
|
|
47
|
+
* { type, text, at }) (kept in both; the oldest files beyond FILES go), used(url, slug, as) (a document's
|
|
48
|
+
* instance asked for it: its index says so). Writes go on after the call returns; `settled()` waits for them.
|
|
49
|
+
*/
|
|
50
|
+
export function createNetCache(root, { memory = 100 } = {}) {
|
|
51
|
+
const held = new Map(); // url -> entry, the most recent last
|
|
52
|
+
let writes = Promise.resolve();
|
|
53
|
+
const later = (task) => {
|
|
54
|
+
writes = writes.then(task).catch(() => {});
|
|
55
|
+
return writes;
|
|
56
|
+
};
|
|
57
|
+
const hold = (url, entry) => {
|
|
58
|
+
held.delete(url);
|
|
59
|
+
held.set(url, entry);
|
|
60
|
+
while (held.size > memory) held.delete(held.keys().next().value);
|
|
61
|
+
};
|
|
62
|
+
const prune = () => {
|
|
63
|
+
const folder = folderOf(root);
|
|
64
|
+
let names = [];
|
|
65
|
+
try {
|
|
66
|
+
names = fs.readdirSync(folder).filter((name) => name.endsWith(".json"));
|
|
67
|
+
} catch {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (names.length <= FILES) return;
|
|
71
|
+
const dated = names.map((name) => ({ name, at: fs.statSync(path.join(folder, name), { throwIfNoEntry: false })?.mtimeMs ?? 0 })).sort((a, b) => a.at - b.at);
|
|
72
|
+
for (const { name } of dated.slice(0, dated.length - FILES)) fs.rmSync(path.join(folder, name), { force: true });
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
get(url) {
|
|
76
|
+
if (held.has(url)) return held.get(url);
|
|
77
|
+
const entry = readJson(fileOf(root, url));
|
|
78
|
+
if (!isEntry(entry, url)) return null;
|
|
79
|
+
hold(url, entry);
|
|
80
|
+
return entry;
|
|
81
|
+
},
|
|
82
|
+
put(url, { type, text, at }) {
|
|
83
|
+
const entry = { url, at, type, text };
|
|
84
|
+
hold(url, entry);
|
|
85
|
+
later(async () => {
|
|
86
|
+
await fs.promises.mkdir(folderOf(root), { recursive: true });
|
|
87
|
+
await writeAtomic(fileOf(root, url), `${JSON.stringify(entry)}\n`);
|
|
88
|
+
prune();
|
|
89
|
+
});
|
|
90
|
+
return entry;
|
|
91
|
+
},
|
|
92
|
+
used(url, slug, as) {
|
|
93
|
+
if (typeof slug !== "string" || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) return;
|
|
94
|
+
later(async () => {
|
|
95
|
+
const file = indexOf(root, slug);
|
|
96
|
+
const index = readJson(file) ?? {};
|
|
97
|
+
delete index[url];
|
|
98
|
+
index[url] = { at: new Date().toISOString(), as };
|
|
99
|
+
const kept = Object.entries(index).slice(-PER_DOCUMENT);
|
|
100
|
+
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
101
|
+
await writeAtomic(file, `${JSON.stringify(Object.fromEntries(kept))}\n`);
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
settled: () => writes,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* What an export of document `slug` of workspace `root` embeds of the net (the spec §9 `net`): { <url>:
|
|
110
|
+
* { data, at } } of the answers its instances asked for last, the most recent first, at most
|
|
111
|
+
* SNAPSHOT.count of them and SNAPSHOT.bytes of their text, `data` as each was asked for; only those on a
|
|
112
|
+
* host `allowed(url)` says (an address of a block the document holds, on a host of its needs); null
|
|
113
|
+
* where it has none.
|
|
114
|
+
*/
|
|
115
|
+
export function netSnapshot(root, slug, allowed = () => true) {
|
|
116
|
+
const index = readJson(indexOf(root, slug));
|
|
117
|
+
if (!index || typeof index !== "object") return null;
|
|
118
|
+
const snapshot = {};
|
|
119
|
+
let bytes = 0;
|
|
120
|
+
let count = 0;
|
|
121
|
+
for (const [url, use] of Object.entries(index).reverse()) {
|
|
122
|
+
if (count >= SNAPSHOT.count) break;
|
|
123
|
+
const entry = readJson(fileOf(root, url));
|
|
124
|
+
if (!isEntry(entry, url) || !allowed(url)) continue;
|
|
125
|
+
const data = dataOf(entry, use?.as === "text" ? "text" : "json");
|
|
126
|
+
if (data === undefined) continue;
|
|
127
|
+
bytes += Buffer.byteLength(entry.text);
|
|
128
|
+
if (bytes > SNAPSHOT.bytes) break;
|
|
129
|
+
snapshot[url] = { data, at: entry.at };
|
|
130
|
+
count += 1;
|
|
131
|
+
}
|
|
132
|
+
return count > 0 ? snapshot : null;
|
|
133
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { writeAtomic } from "./files.mjs";
|
|
3
|
+
import { HOST } from "./net-policy.mjs";
|
|
4
|
+
import { layoutOf } from "./workspace.mjs";
|
|
5
|
+
|
|
6
|
+
// The workspace's keys for the sites its blocks reach (docs/render.md, "A block online"): .gallery/keys.json,
|
|
7
|
+
// { "<host>": "<key>" }, written by gallery block key, read by the server's net route as a block's
|
|
8
|
+
// address names one ({key}: ./net-policy.mjs), which it writes in there itself. A file of Gallery's own,
|
|
9
|
+
// apart from gallery.json: that one's settings are told to every page and read by Agents, and a
|
|
10
|
+
// workspace is handed on with it; a key is neither's. No route serves this file, no page holds a key,
|
|
11
|
+
// and the cache, a snapshot and an export know an address by what the block wrote ({key}), never by
|
|
12
|
+
// the key.
|
|
13
|
+
|
|
14
|
+
/** The keys of workspace `root`, by host ({} where there are none, or the file does not read). */
|
|
15
|
+
export function readKeys(root) {
|
|
16
|
+
try {
|
|
17
|
+
const keys = JSON.parse(fs.readFileSync(layoutOf(root).keys, "utf8"));
|
|
18
|
+
if (!keys || typeof keys !== "object" || Array.isArray(keys)) return {};
|
|
19
|
+
return Object.fromEntries(Object.entries(keys).filter(([host, key]) => HOST.test(host) && typeof key === "string" && key !== ""));
|
|
20
|
+
} catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Workspace `root` with `host`'s key `key` (null takes it away); the other keys as they were. */
|
|
26
|
+
export async function writeKey(root, host, key) {
|
|
27
|
+
const keys = readKeys(root);
|
|
28
|
+
if (key === null) delete keys[host];
|
|
29
|
+
else keys[host] = key;
|
|
30
|
+
await fs.promises.mkdir(layoutOf(root).gallery, { recursive: true });
|
|
31
|
+
await writeAtomic(layoutOf(root).keys, `${JSON.stringify(keys, null, 2)}\n`);
|
|
32
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// What a custom block may reach of the web, and how its address is read (notes/plans/custom-blocks-spec-2026-11-07.md
|
|
2
|
+
// §3; docs/render.md, "A block online"): pure, no Node, read by the catalog (a manifest's needs), the
|
|
3
|
+
// server's net route (src/server/net-route.mjs: which address a block asks for is its to ask, which
|
|
4
|
+
// machine a name stands for may be reached) and the export's snapshot (shared/net-cache.mjs).
|
|
5
|
+
//
|
|
6
|
+
// A block names each host it reaches in its needs, "net:<host>": a lowercase host name, no port and no
|
|
7
|
+
// path, "*." before it for any name under it (never the name itself: write both where both are meant).
|
|
8
|
+
// What it asks for is an absolute http or https address on that host, at the scheme's own port, with no
|
|
9
|
+
// user or password in it; `{key}` in it (its path or its query) is where the server writes the
|
|
10
|
+
// workspace's key for that host, which no page ever holds (keyIn, withKey).
|
|
11
|
+
//
|
|
12
|
+
// A machine is reached only at an address of the public internet: none of this computer (127/8, ::1),
|
|
13
|
+
// of a private network (10/8, 172.16/12, 192.168/16, fc00::/7, 100.64/10 a carrier's), of a link
|
|
14
|
+
// (169.254/16, fe80::/10), of what is no host (0/8, multicast, the reserved 240/4, the broadcast) or of
|
|
15
|
+
// the ranges kept for documents and tests (192.0.2/24, 198.51.100/24, 203.0.113/24, 2001:db8::/32); an
|
|
16
|
+
// IPv6 address that holds an IPv4 one (::ffff:a.b.c.d, ::a.b.c.d, 64:ff9b::a.b.c.d, 2002:…) is held to
|
|
17
|
+
// that one. 198.18.0.0/15 (benchmarking) is what a proxy's fake-ip DNS answers with (Clash and its
|
|
18
|
+
// kind): it is one only where the address is handed to that proxy (FAKE_IP, proxyHere). A name this
|
|
19
|
+
// computer's resolver answers with addresses of this computer or unique-local ones alone (a proxy that
|
|
20
|
+
// maps names to 127.x or fd00::/8 addresses of its own: mapsHere) is reached by its name through such a
|
|
21
|
+
// proxy, for https alone, its TLS the guard (src/server/net-route.mjs); never a name kept for this
|
|
22
|
+
// computer (keptHere), nor one answered with a private IPv4 network's address.
|
|
23
|
+
|
|
24
|
+
/** The word a manifest's needs say a host after. */
|
|
25
|
+
export const NET = "net:";
|
|
26
|
+
/** A host a manifest's needs may name: a lowercase name, "*." before it for any name under it. */
|
|
27
|
+
export const HOST = /^(?:\*\.)?[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*$/;
|
|
28
|
+
|
|
29
|
+
/** The hosts a block's needs name ("net:<host>" each), in its order. */
|
|
30
|
+
export const netHostsOf = (needs) => (Array.isArray(needs) ? needs.filter((need) => typeof need === "string" && need.startsWith(NET)).map((need) => need.slice(NET.length)) : []);
|
|
31
|
+
|
|
32
|
+
/** Whether `host` (an address's, lowercase) is one a needs' host names: itself, or, for "*.<name>", a name under it. */
|
|
33
|
+
export function hostMatches(host, pattern) {
|
|
34
|
+
if (pattern.startsWith("*.")) return host.endsWith(pattern.slice(1)) && host.length > pattern.length - 1;
|
|
35
|
+
return host === pattern;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The first of `hosts` (a block's needs' hosts) that `host` is, or null. */
|
|
39
|
+
export const hostIn = (host, hosts) => hosts.find((pattern) => hostMatches(host, pattern)) ?? null;
|
|
40
|
+
|
|
41
|
+
// `{key}` as written, and as an address's path writes it (%7B key %7D).
|
|
42
|
+
const KEY = /\{key\}|%7Bkey%7D/gi;
|
|
43
|
+
|
|
44
|
+
/** Whether an address names the workspace's key for its host. */
|
|
45
|
+
export const keyIn = (address) => new RegExp(KEY.source, "i").test(address);
|
|
46
|
+
|
|
47
|
+
/** The address with the key written where it names it (`{key}`), encoded as a part of an address. */
|
|
48
|
+
export const withKey = (address, key) => address.replace(KEY, () => encodeURIComponent(key));
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* What a block's `raw` address is: { url } (a URL, its href what the cache and a snapshot name it by), or
|
|
52
|
+
* { code: "url", why } when it is no address a block may ask for.
|
|
53
|
+
*/
|
|
54
|
+
export function addressOf(raw) {
|
|
55
|
+
if (typeof raw !== "string" || raw.length > 4096) return { code: "url", why: "an address is a string of at most 4096 characters" };
|
|
56
|
+
let url;
|
|
57
|
+
try {
|
|
58
|
+
url = new URL(raw);
|
|
59
|
+
} catch {
|
|
60
|
+
return { code: "url", why: "not an absolute address" };
|
|
61
|
+
}
|
|
62
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return { code: "url", why: "only http and https addresses" };
|
|
63
|
+
if (url.username || url.password) return { code: "url", why: "an address with a user or a password in it" };
|
|
64
|
+
if (url.port !== "") return { code: "url", why: "an address at another port than its scheme's: a needs' host names none" };
|
|
65
|
+
url.hash = "";
|
|
66
|
+
return { url };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------- addresses ----------
|
|
70
|
+
|
|
71
|
+
// An IPv4 address as its four numbers, or null.
|
|
72
|
+
function ipv4(text) {
|
|
73
|
+
const parts = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(text);
|
|
74
|
+
if (!parts) return null;
|
|
75
|
+
const numbers = parts.slice(1).map(Number);
|
|
76
|
+
return numbers.every((number) => number <= 255) ? numbers : null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// An IPv6 address as its eight groups (numbers), a zone (%…) left out, or null.
|
|
80
|
+
function ipv6(text) {
|
|
81
|
+
let rest = text.replace(/^\[|\]$/g, "").replace(/%.*$/, "").toLowerCase();
|
|
82
|
+
let tail = [];
|
|
83
|
+
const dotted = /^(.*:)(\d+\.\d+\.\d+\.\d+)$/.exec(rest);
|
|
84
|
+
if (dotted) {
|
|
85
|
+
const four = ipv4(dotted[2]);
|
|
86
|
+
if (!four) return null;
|
|
87
|
+
tail = [(four[0] << 8) | four[1], (four[2] << 8) | four[3]];
|
|
88
|
+
rest = dotted[1].endsWith("::") ? dotted[1] : dotted[1].slice(0, -1);
|
|
89
|
+
}
|
|
90
|
+
const halves = rest.split("::");
|
|
91
|
+
if (halves.length > 2) return null;
|
|
92
|
+
const groups = (half) => (half === "" ? [] : half.split(":"));
|
|
93
|
+
const [head, after = null] = [groups(halves[0]), halves.length === 2 ? groups(halves[1]) : null];
|
|
94
|
+
if (![...head, ...(after ?? [])].every((group) => /^[0-9a-f]{1,4}$/.test(group))) return null;
|
|
95
|
+
const known = head.length + (after?.length ?? 0) + tail.length;
|
|
96
|
+
if (after === null ? known !== 8 : known > 7) return null;
|
|
97
|
+
const numbers = (list) => list.map((group) => Number.parseInt(group, 16));
|
|
98
|
+
return [...numbers(head), ...Array(8 - known).fill(0), ...numbers(after ?? []), ...tail];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const inRange = (numbers, [first, ...rest], bits) => {
|
|
102
|
+
// `numbers` (an IPv4's four) within first.rest…/bits
|
|
103
|
+
const value = (list) => list.reduce((sum, number) => sum * 256 + number, 0);
|
|
104
|
+
const shift = 2 ** (32 - bits);
|
|
105
|
+
return Math.floor(value(numbers) / shift) === Math.floor(value([first, ...rest]) / shift);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// The IPv4 ranges no block reaches: this network, the private ones, a carrier's, loopback, link-local,
|
|
109
|
+
// the protocols', the documents' and tests', the old 6to4 relay, multicast, the reserved and the broadcast.
|
|
110
|
+
const V4_REFUSED = [
|
|
111
|
+
[[0, 0, 0, 0], 8], [[10, 0, 0, 0], 8], [[100, 64, 0, 0], 10], [[127, 0, 0, 0], 8], [[169, 254, 0, 0], 16],
|
|
112
|
+
[[172, 16, 0, 0], 12], [[192, 0, 0, 0], 24], [[192, 0, 2, 0], 24], [[192, 88, 99, 0], 24], [[192, 168, 0, 0], 16],
|
|
113
|
+
[[198, 51, 100, 0], 24], [[203, 0, 113, 0], 24], [[224, 0, 0, 0], 4], [[240, 0, 0, 0], 4],
|
|
114
|
+
];
|
|
115
|
+
/** The fake-ip range a proxy's DNS answers with (198.18.0.0/15, benchmarking's). */
|
|
116
|
+
export const FAKE_IP = [[198, 18, 0, 0], 15];
|
|
117
|
+
|
|
118
|
+
const v4Kind = (four) => (inRange(four, ...FAKE_IP) ? "fake-ip" : V4_REFUSED.some(([start, bits]) => inRange(four, start, bits)) ? "private" : "public");
|
|
119
|
+
const embedded = (groups, at) => [groups[at] >> 8, groups[at] & 255, groups[at + 1] >> 8, groups[at + 1] & 255];
|
|
120
|
+
|
|
121
|
+
// What an IPv6 address is: of the public internet (2000::/3 but the documents', benchmarking's and
|
|
122
|
+
// ORCHID's), what the IPv4 address it holds is, or none to reach.
|
|
123
|
+
function v6Kind(groups) {
|
|
124
|
+
const zeros = (count) => groups.slice(0, count).every((group) => group === 0);
|
|
125
|
+
if (zeros(5) && groups[5] === 0xffff) return v4Kind(embedded(groups, 6)); // ::ffff:a.b.c.d
|
|
126
|
+
if (zeros(6)) return groups[6] === 0 && groups[7] <= 1 ? "private" : v4Kind(embedded(groups, 6)); // ::, ::1, ::a.b.c.d
|
|
127
|
+
if (groups[0] === 0x64 && groups[1] === 0xff9b && groups.slice(2, 6).every((group) => group === 0)) return v4Kind(embedded(groups, 6)); // NAT64
|
|
128
|
+
if (groups[0] === 0x2002) return v4Kind(embedded(groups, 1)); // 6to4
|
|
129
|
+
if ((groups[0] & 0xe000) !== 0x2000) return "private"; // not global unicast: fc00::/7, fe80::/10, ff00::/8, 100::/64…
|
|
130
|
+
if (groups[0] === 0x2001 && (groups[1] === 0x0db8 || groups[1] === 0x0002 || (groups[1] & 0xfff0) === 0x0010)) return "private";
|
|
131
|
+
return "public";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* What `address` (an IP address, as a resolver gives it) is to a block: "public" (it may be reached),
|
|
136
|
+
* "fake-ip" (198.18.0.0/15, a proxy's DNS: FAKE_IP), "private" (this computer, a private network, or no
|
|
137
|
+
* host to reach), or "none" (no IP address).
|
|
138
|
+
*/
|
|
139
|
+
export function addressKind(address) {
|
|
140
|
+
const four = ipv4(String(address));
|
|
141
|
+
if (four) return v4Kind(four);
|
|
142
|
+
const groups = ipv6(String(address));
|
|
143
|
+
return groups ? v6Kind(groups) : "none";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Whether `address` (one addressKind calls private) is what a proxy of this computer that maps names
|
|
148
|
+
* answers with: this computer's (127/8, ::1, ::ffff:127.x) or an IPv6 unique-local one (fc00::/7).
|
|
149
|
+
* Never a private IPv4 network's (10/8, 172.16/12, 192.168/16), a carrier's or a link's: a network's own
|
|
150
|
+
* machines are there (a company's names that its DNS answers inside), which no name may reach.
|
|
151
|
+
*/
|
|
152
|
+
export function mapsHere(address) {
|
|
153
|
+
const four = ipv4(String(address));
|
|
154
|
+
if (four) return four[0] === 127;
|
|
155
|
+
const groups = ipv6(String(address));
|
|
156
|
+
if (!groups) return false;
|
|
157
|
+
if (groups.slice(0, 5).every((group) => group === 0) && groups[5] === 0xffff) return groups[6] >> 8 === 127;
|
|
158
|
+
return groups.every((group, index) => group === (index === 7 ? 1 : 0)) || (groups[0] & 0xfe00) === 0xfc00;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Whether `host` (an address's) is a name a resolver keeps for this computer: localhost and the names under it (RFC 6761). */
|
|
162
|
+
export const keptHere = (host) => /(?:^|\.)localhost\.?$/i.test(String(host));
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Whether a proxy's address (`proxy`, a URL or null) is a program on this computer: what a fake-ip
|
|
166
|
+
* answer is handed to, and the name of an https address whose answer here is none of the public internet.
|
|
167
|
+
*/
|
|
168
|
+
export function proxyHere(proxy) {
|
|
169
|
+
if (!proxy) return false;
|
|
170
|
+
try {
|
|
171
|
+
const host = new URL(proxy).hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
172
|
+
const loopback6 = ipv6(host)?.every((group, index) => group === (index === 7 ? 1 : 0)) ?? false;
|
|
173
|
+
return host === "localhost" || ipv4(host)?.[0] === 127 || loopback6;
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parse } from "parse5";
|
|
2
|
-
import { isInstance } from "./components/index.mjs";
|
|
2
|
+
import { instanceSlots, isInstance } from "./components/index.mjs";
|
|
3
3
|
import { mayHoldOldNames, newAttributeName, newAttributeValue, newScriptNames, newStyleNames } from "./old-names.mjs";
|
|
4
4
|
|
|
5
5
|
// A file's text with the format's old names new (old-names.mjs says which, and where the tools read
|
|
@@ -50,7 +50,10 @@ export function newNames(html) {
|
|
|
50
50
|
}
|
|
51
51
|
const visit = (node) => {
|
|
52
52
|
for (const child of node.childNodes ?? []) {
|
|
53
|
-
if (isInstance(child))
|
|
53
|
+
if (isInstance(child)) {
|
|
54
|
+
instanceSlots(child).forEach(visit); // what its slots hold is the document's, its own region the component's
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
54
57
|
if (child.tagName) element(child);
|
|
55
58
|
visit(child.tagName === "template" && child.content ? child.content : child);
|
|
56
59
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// The shape of the sidebar's tree (the workspace's outline, ./outline.mjs reads and writes its file),
|
|
2
|
+
// pure, the same on the server and in the workbench (workspace/meta.ts): the columns of the sidebar,
|
|
3
|
+
// each a list of entries under one another, and what names them.
|
|
4
|
+
//
|
|
5
|
+
// A column (栏) is { id, title?, role?, workspace?, picked?, hidden?, left? }: "docs" is the workspace's own
|
|
6
|
+
// column (its own documents; 默认文档 when it is the default workspace, else called by the workspace's
|
|
7
|
+
// name), always there and never removed; workspace "<ws-id>" is another registered workspace's column
|
|
8
|
+
// (./workspace-columns.mjs: one for each registered workspace, made as the outline is read; "whole",
|
|
9
|
+
// holding all its documents, those no column holds coming last in it but the ones in its `left` (the slugs
|
|
10
|
+
// there of the documents the user took out: 从文档树移除), or `picked`, holding only the documents put in
|
|
11
|
+
// it: 添加其他 Gallery 项目… with a document; `hidden` once the user removed it from the sidebar, kept so
|
|
12
|
+
// that it comes back as it was); another is one the user made (a column's ⋯ › 新建栏),
|
|
13
|
+
// or of an older kind still read: role "links" (链接, where the web links went before 2026-11-09);
|
|
14
|
+
// extension "<id>" for the column an extension provides
|
|
15
|
+
// (extensions/<id>/sidebar.json: ./extension-sidebar.mjs): its place is kept here, so that it can be
|
|
16
|
+
// dragged, but its title and its entries are the extension's, never the outline's. `title` is the
|
|
17
|
+
// user's name for it; none, the name it goes by in the UI's language (文档, 链接, …). Its order is the sidebar's.
|
|
18
|
+
// An entry is a document's or a web link's slug of this workspace; "~<ws-id>/<slug>" names a draft of
|
|
19
|
+
// another workspace (./drafts.mjs: kept in the outline whether it is there or not).
|
|
20
|
+
// In the outline as read, every list is one of `children`: under a top key, a column's top level (""
|
|
21
|
+
// the 文档 column's, as before columns came, ":<id>" another's), under a slug, the entries under that
|
|
22
|
+
// entry. So an entry moved to another column is an entry moved under another parent, and the 文档
|
|
23
|
+
// column's tree is what an outline of version 1 was.
|
|
24
|
+
|
|
25
|
+
/** The 文档 column's id: the workspace's own documents, never removed. */
|
|
26
|
+
export const DOCS = "docs";
|
|
27
|
+
/** A column's id: a slug's letters ("docs", "g-7k2m", "ws-3f2a9c"), 64 at most. */
|
|
28
|
+
export const groupIdPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
29
|
+
/** An entry: a slug of this workspace, or a draft of another, "~ws-<6 hex>/<slug>". */
|
|
30
|
+
export const entryPattern = /^(?:~ws-[0-9a-f]{6}\/)?[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
31
|
+
/** The roles a column can have: the one web links went to before 2026-11-09 (none is made any more; one there stays). */
|
|
32
|
+
export const GROUP_ROLES = ["links"];
|
|
33
|
+
export const GROUP_LIMITS = { groups: 50, title: 100, left: 1000 };
|
|
34
|
+
/** A slug of a workspace (a document's, a web link's folder name). */
|
|
35
|
+
const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* An extension's id, the name of its folder under extensions/: a slug of 48 letters, digits and dashes
|
|
39
|
+
* at most (its column's id is ext-<id>, 64 at most), and never the notation of a workspace's id
|
|
40
|
+
* (ws-<6 hex>: the address `#~ws-…/<slug>` names a draft of another workspace, `#~<id>/<entry>` an
|
|
41
|
+
* entry of an extension).
|
|
42
|
+
*/
|
|
43
|
+
export const EXTENSION_ID_MAX = 48;
|
|
44
|
+
export const extensionIdPattern = /^(?!ws-[0-9a-f]{6}$)[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
45
|
+
export const isExtensionId = (id) => typeof id === "string" && id.length <= EXTENSION_ID_MAX && extensionIdPattern.test(id);
|
|
46
|
+
/** The id of the column extension `id` makes. */
|
|
47
|
+
export const extensionGroupId = (id) => `ext-${id}`;
|
|
48
|
+
|
|
49
|
+
/** A column's top key in the outline's children: "" for 文档 (as before columns came), ":<id>" for another. */
|
|
50
|
+
export const topOf = (id) => (id === DOCS ? "" : `:${id}`);
|
|
51
|
+
/** Whether a key of the children is a column's top level (else it is an entry's). */
|
|
52
|
+
export const isTop = (key) => key === "" || key.startsWith(":");
|
|
53
|
+
/** The column whose top key `key` is. */
|
|
54
|
+
export const groupOfTop = (key) => (key === "" ? DOCS : key.slice(1));
|
|
55
|
+
/** Whether `entry` names a draft of another workspace. */
|
|
56
|
+
export const isForeign = (entry) => entry.startsWith("~");
|
|
57
|
+
|
|
58
|
+
const tidy = (value) => (typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "");
|
|
59
|
+
|
|
60
|
+
/** A whole column's `left` as it is kept: the slugs once each, 1000 at most; none when there are none. */
|
|
61
|
+
const leftOf = (value) => {
|
|
62
|
+
const left = [...new Set(value.filter((slug) => typeof slug === "string" && slugPattern.test(slug)))].slice(0, GROUP_LIMITS.left);
|
|
63
|
+
return left.length ? { left } : {};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Column `value` as it is kept ({ id, title?, role?, workspace?, picked?, hidden?, left? } or an extension's { id, extension }),
|
|
68
|
+
* or null for one that is none. An extension's column is its id's, whatever else a file says of it: no
|
|
69
|
+
* title (the extension's own), role or workspace.
|
|
70
|
+
*/
|
|
71
|
+
export function groupOf(value) {
|
|
72
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
73
|
+
const { id, role, workspace, extension } = value;
|
|
74
|
+
if (typeof id !== "string" || id.length > 64 || !groupIdPattern.test(id)) return null;
|
|
75
|
+
if (isExtensionId(extension) && id === extensionGroupId(extension)) return { id, extension };
|
|
76
|
+
const title = tidy(value.title).slice(0, GROUP_LIMITS.title);
|
|
77
|
+
const isWorkspaceColumn = typeof workspace === "string" && /^ws-[0-9a-f]{6}$/.test(workspace) && id !== DOCS;
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
...(title ? { title } : {}),
|
|
81
|
+
...(GROUP_ROLES.includes(role) && id !== DOCS ? { role } : {}),
|
|
82
|
+
...(isWorkspaceColumn ? { workspace } : {}),
|
|
83
|
+
// A workspace's column alone is picked or hidden (the user's columns and 链接 are removed, never hidden).
|
|
84
|
+
...(isWorkspaceColumn && value.picked === true ? { picked: true } : {}),
|
|
85
|
+
...(isWorkspaceColumn && value.hidden === true ? { hidden: true } : {}),
|
|
86
|
+
// What the user took out of a whole one (a picked one holds what was put in it: nothing to leave out).
|
|
87
|
+
...(isWorkspaceColumn && value.picked !== true && Array.isArray(value.left) ? leftOf(value.left) : {}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Whether `groups` is a list of columns to keep: each a column, ids once each, 文档 among them, 50 at most. */
|
|
92
|
+
export function validGroups(groups) {
|
|
93
|
+
if (!Array.isArray(groups) || groups.length === 0 || groups.length > GROUP_LIMITS.groups) return false;
|
|
94
|
+
const ids = new Set();
|
|
95
|
+
for (const value of groups) {
|
|
96
|
+
const group = groupOf(value);
|
|
97
|
+
if (!group || ids.has(group.id)) return false;
|
|
98
|
+
if (value.title !== undefined && (typeof value.title !== "string" || tidy(value.title).length > GROUP_LIMITS.title)) return false;
|
|
99
|
+
if (value.role !== undefined && !GROUP_ROLES.includes(value.role)) return false;
|
|
100
|
+
if (value.extension !== undefined && group.extension !== value.extension) return false;
|
|
101
|
+
if (value.left !== undefined && (!Array.isArray(value.left) || value.left.length > GROUP_LIMITS.left || !value.left.every((slug) => typeof slug === "string" && slugPattern.test(slug)))) return false;
|
|
102
|
+
ids.add(group.id);
|
|
103
|
+
}
|
|
104
|
+
return ids.has(DOCS);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** A new column's id, none of `groups`' (g- and four letters or digits). */
|
|
108
|
+
export function newGroupId(groups, random = Math.random) {
|
|
109
|
+
for (;;) {
|
|
110
|
+
const id = `g-${Math.floor(random() * 36 ** 4).toString(36).padStart(4, "0")}`;
|
|
111
|
+
if (!groups.some((group) => group.id === id)) return id;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** The top key of the column `slug` is in (walking up `children`), or null when the outline holds it not. */
|
|
116
|
+
export function topIn(children, slug) {
|
|
117
|
+
const parentOf = (entry) => {
|
|
118
|
+
for (const [key, list] of Object.entries(children)) if (list.includes(entry)) return key;
|
|
119
|
+
return null;
|
|
120
|
+
};
|
|
121
|
+
const seen = new Set();
|
|
122
|
+
for (let key = parentOf(slug); key !== null; key = parentOf(key)) {
|
|
123
|
+
if (isTop(key)) return key;
|
|
124
|
+
if (seen.has(key)) return null;
|
|
125
|
+
seen.add(key);
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|