@heycys/gallery 0.2.1 → 0.2.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.
Files changed (169) hide show
  1. package/THIRD-PARTY-NOTICES.md +1 -1
  2. package/browser/editor/page/annotate/index.mjs +3 -2
  3. package/browser/editor/page/board/index.mjs +2 -1
  4. package/browser/editor/page/board/settings.mjs +2 -1
  5. package/browser/editor/page/core.mjs +3 -2
  6. package/browser/editor/page/custom-page.mjs +4 -3
  7. package/browser/editor/page/editor.mjs +9 -5
  8. package/browser/editor/page/emoji-picker/support.mjs +3 -2
  9. package/browser/editor/page/links/index.mjs +1 -12
  10. package/browser/editor/page/links/pages.mjs +3 -2
  11. package/browser/editor/page/outline/folds.mjs +3 -0
  12. package/browser/editor/page/post.mjs +2 -1
  13. package/browser/editor/page/present-links.mjs +4 -3
  14. package/browser/editor/page/present-shell.mjs +3 -58
  15. package/browser/editor/page/session.mjs +3 -37
  16. package/browser/editor/page/storage.mjs +5 -5
  17. package/browser/shared/component-catalog.mjs +2 -2
  18. package/browser/shared/drafts.mjs +26 -51
  19. package/browser/shared/emoji/icon-value.mjs +2 -1
  20. package/browser/shared/extension-manifest.mjs +90 -0
  21. package/browser/shared/extensions.mjs +26 -16
  22. package/browser/shared/http.mjs +1 -1
  23. package/browser/shared/i18n/en.mjs +46 -15
  24. package/browser/shared/media.mjs +2 -1
  25. package/browser/shared/outline.mjs +11 -51
  26. package/browser/shared/page-address.mjs +8 -15
  27. package/browser/shared/paths.mjs +2 -1
  28. package/browser/shared/preferences.mjs +3 -1
  29. package/browser/shared/preview-server.mjs +51 -63
  30. package/browser/shared/service-location.mjs +18 -0
  31. package/browser/shared/session.mjs +3 -6
  32. package/browser/shared/workspace-address.mjs +19 -0
  33. package/browser/shared/workspace-columns.mjs +1 -2
  34. package/browser/shared/workspace-registry.mjs +6 -40
  35. package/browser/shared/workspace.mjs +3 -6
  36. package/browser/shared/writing-preferences.mjs +6 -4
  37. package/dist/{chunk-BYSF5UMM.mjs → chunk-236JJXWY.mjs} +2 -2
  38. package/dist/{chunk-3A5I2GJK.mjs → chunk-2KAVXMKG.mjs} +1 -1
  39. package/dist/chunk-2T4PZQEP.mjs +2 -0
  40. package/dist/{chunk-SAHS56QM.mjs → chunk-3SKOU6OZ.mjs} +1 -1
  41. package/dist/{chunk-S2Y7VI4H.mjs → chunk-3XZOA7AH.mjs} +2 -2
  42. package/dist/{chunk-MKTX5PGV.mjs → chunk-43B75J5T.mjs} +1 -1
  43. package/dist/{chunk-VKSRM7EY.mjs → chunk-4B2TB5K2.mjs} +1 -1
  44. package/dist/{chunk-LV24RY2E.mjs → chunk-4K5KC6V2.mjs} +1 -1
  45. package/dist/{chunk-SOD23RGL.mjs → chunk-4KUO7R2M.mjs} +8 -8
  46. package/dist/chunk-4SNV4HA5.mjs +2 -0
  47. package/dist/chunk-53XDTHTG.mjs +4 -0
  48. package/dist/chunk-5XV3YYLG.mjs +2 -0
  49. package/dist/{chunk-VNUWREXU.mjs → chunk-65NTKF4N.mjs} +1 -1
  50. package/dist/chunk-6GV3CBB2.mjs +2 -0
  51. package/dist/{chunk-DH6GMDNN.mjs → chunk-6L6V7YR2.mjs} +1 -1
  52. package/dist/{chunk-TOE6DPLH.mjs → chunk-6NLXUKAY.mjs} +1 -1
  53. package/dist/chunk-6Q7ASAXJ.mjs +3 -0
  54. package/dist/{chunk-ZCP7BTOZ.mjs → chunk-6QBHU4DF.mjs} +1 -1
  55. package/dist/{chunk-QXVNUASA.mjs → chunk-6QWQXHAV.mjs} +1 -1
  56. package/dist/chunk-6XD6U3QA.mjs +5 -0
  57. package/dist/{chunk-36FIRJIF.mjs → chunk-742D2WWJ.mjs} +2 -2
  58. package/dist/{chunk-7M7UPWU6.mjs → chunk-7EFHNQ5B.mjs} +1 -1
  59. package/dist/{chunk-JI6T3A4Y.mjs → chunk-7ISBBDJR.mjs} +1 -1
  60. package/dist/{chunk-2GKGEVMR.mjs → chunk-7UZUQQ7Q.mjs} +25 -24
  61. package/dist/{chunk-VPVOAJ7X.mjs → chunk-AGDILNWB.mjs} +1 -1
  62. package/dist/{chunk-5IIH335D.mjs → chunk-ALZ6ZENZ.mjs} +1 -1
  63. package/dist/{chunk-G4YP7GVC.mjs → chunk-BFJGHSQN.mjs} +1 -1
  64. package/dist/chunk-BLNQUR5R.mjs +168 -0
  65. package/dist/chunk-BMX3VUHY.mjs +2 -0
  66. package/dist/chunk-BN7M3IN7.mjs +8 -0
  67. package/dist/{chunk-AMDGVDNV.mjs → chunk-BQNTTFPL.mjs} +1 -1
  68. package/dist/chunk-C257H6IA.mjs +2 -0
  69. package/dist/{chunk-74RPP2M2.mjs → chunk-C564NU2H.mjs} +1 -1
  70. package/dist/chunk-CHQU37CA.mjs +2 -0
  71. package/dist/{chunk-WCWYNFDF.mjs → chunk-E4IHAIJ7.mjs} +1 -1
  72. package/dist/{chunk-7XDYK3UC.mjs → chunk-E7656LR7.mjs} +1 -1
  73. package/dist/{chunk-KFZBYDIS.mjs → chunk-ECZBLQKK.mjs} +1 -1
  74. package/dist/{chunk-PAFSFVYB.mjs → chunk-ERE2BXYV.mjs} +1 -1
  75. package/dist/{chunk-ZEY2RLBT.mjs → chunk-ERLAIBOA.mjs} +2 -2
  76. package/dist/chunk-FFV733MA.mjs +2 -0
  77. package/dist/{chunk-CZ5KJSGK.mjs → chunk-GJJRBGMY.mjs} +1 -1
  78. package/dist/{chunk-VA3KAQZD.mjs → chunk-GKOBB6DH.mjs} +1 -1
  79. package/dist/chunk-GMJD7ID3.mjs +2 -0
  80. package/dist/{chunk-QZ35UAB4.mjs → chunk-GRAXKKG4.mjs} +1 -1
  81. package/dist/{chunk-2RKIHJI2.mjs → chunk-HYMEEXKN.mjs} +1 -1
  82. package/dist/{chunk-DKR7LFIY.mjs → chunk-IA2SIEJQ.mjs} +1 -1
  83. package/dist/{chunk-QK3VISCA.mjs → chunk-IA4PSIMD.mjs} +1 -1
  84. package/dist/chunk-JPG2LBQM.mjs +11 -0
  85. package/dist/{chunk-VGTMLQWZ.mjs → chunk-JXXHAXYH.mjs} +1 -1
  86. package/dist/{chunk-5MEXZ2UF.mjs → chunk-K3JKPFL5.mjs} +1 -1
  87. package/dist/{chunk-LE44MD3O.mjs → chunk-KLQP46Y3.mjs} +1 -1
  88. package/dist/{chunk-NAGMRVW4.mjs → chunk-LKX55H76.mjs} +1 -1
  89. package/dist/chunk-LMUZQK5O.mjs +2 -0
  90. package/dist/{chunk-CG3UHDKH.mjs → chunk-M4NRDYI5.mjs} +1 -1
  91. package/dist/{chunk-HM4E43VM.mjs → chunk-MAFIGVXY.mjs} +1 -1
  92. package/dist/{chunk-4DNHHJSL.mjs → chunk-MKIBJTJZ.mjs} +1 -1
  93. package/dist/{chunk-L7W624FD.mjs → chunk-MNWJ4EZY.mjs} +1 -1
  94. package/dist/{chunk-FXQBADMN.mjs → chunk-NHP66IWR.mjs} +1 -1
  95. package/dist/{chunk-YBB5LWZK.mjs → chunk-OEIJLMPI.mjs} +1 -1
  96. package/dist/{chunk-NWRZXELO.mjs → chunk-PAREWQGB.mjs} +1 -1
  97. package/dist/{chunk-7N2LPG33.mjs → chunk-PDZR3L3C.mjs} +1 -1
  98. package/dist/{chunk-YFJU3O7G.mjs → chunk-PLB7L22J.mjs} +1 -1
  99. package/dist/{chunk-4AMTKWDO.mjs → chunk-PUOQ65NC.mjs} +1 -1
  100. package/dist/chunk-Q4MS6OFC.mjs +2 -0
  101. package/dist/{chunk-3OFXMN6N.mjs → chunk-Q7P3Q5YX.mjs} +1 -1
  102. package/dist/{chunk-6MPKCH3P.mjs → chunk-QNECWMGR.mjs} +1 -1
  103. package/dist/{chunk-HBAUKKQH.mjs → chunk-QP7BOHE4.mjs} +1 -1
  104. package/dist/chunk-QVGOPHOF.mjs +2 -0
  105. package/dist/{chunk-NFABH3QW.mjs → chunk-RRKJMHNX.mjs} +2 -2
  106. package/dist/chunk-S3SX3COT.mjs +20 -0
  107. package/dist/{chunk-ZO7SFB2E.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  108. package/dist/{chunk-VG5JEIUQ.mjs → chunk-TKWEX4FD.mjs} +2 -2
  109. package/dist/{chunk-CCSGFCLZ.mjs → chunk-U3SSPL4K.mjs} +1 -1
  110. package/dist/{chunk-DHB7UZ7F.mjs → chunk-U5XL7D6A.mjs} +1 -1
  111. package/dist/{chunk-CPS4SRPF.mjs → chunk-ULXSPX5H.mjs} +2 -2
  112. package/dist/{chunk-JXLSHVJ2.mjs → chunk-UMHUSOPJ.mjs} +1 -1
  113. package/dist/chunk-USIHBCSW.mjs +15 -0
  114. package/dist/{chunk-GWOYMENX.mjs → chunk-V6XZ4VIR.mjs} +1 -1
  115. package/dist/{chunk-AFGUR7SY.mjs → chunk-VPMRP2TL.mjs} +1 -1
  116. package/dist/{chunk-WTEGUPFG.mjs → chunk-VRPVVMRB.mjs} +1 -1
  117. package/dist/chunk-VZ2RQ3AM.mjs +2 -0
  118. package/dist/{chunk-XKOHV4H6.mjs → chunk-W5NPH5UA.mjs} +1 -1
  119. package/dist/chunk-WFGPMCTZ.mjs +4 -0
  120. package/dist/chunk-XZCFPKGO.mjs +2 -0
  121. package/dist/{chunk-QJ3TFJLQ.mjs → chunk-Y34NR5JL.mjs} +1 -1
  122. package/dist/{chunk-V5JRSGZF.mjs → chunk-YN37ZDLW.mjs} +1 -1
  123. package/dist/chunk-ZFGMJVJC.mjs +2 -0
  124. package/dist/{chunk-KH24LWAT.mjs → chunk-ZTHICSSF.mjs} +1 -1
  125. package/dist/cli.mjs +1 -1
  126. package/dist/server.mjs +1 -1
  127. package/dist/worker.mjs +1 -1
  128. package/kit/math.js +1 -1
  129. package/kit/runtime.js +12 -2
  130. package/kit/state.js +2 -0
  131. package/kit/ui.js +5 -1
  132. package/package.json +1 -1
  133. package/release.json +7 -7
  134. package/skill/SKILL.md +13 -13
  135. package/skill/references/building-blocks.md +1 -1
  136. package/skill/references/extensions.md +45 -9
  137. package/web/assets/{index-xP0uw3a0.css → index-FLb9jCfl.css} +1 -1
  138. package/web/assets/index-czjrXVjf.js +15 -0
  139. package/web/index.html +2 -2
  140. package/dist/chunk-46ACXOU5.mjs +0 -2
  141. package/dist/chunk-5DPABPBI.mjs +0 -2
  142. package/dist/chunk-5L26JUYA.mjs +0 -2
  143. package/dist/chunk-AEMVZYZQ.mjs +0 -166
  144. package/dist/chunk-ASAXY2DJ.mjs +0 -2
  145. package/dist/chunk-DAMVDXR3.mjs +0 -2
  146. package/dist/chunk-DLFZJJEE.mjs +0 -2
  147. package/dist/chunk-EKNHM3P4.mjs +0 -2
  148. package/dist/chunk-FCK6NXON.mjs +0 -3
  149. package/dist/chunk-FX42XU6J.mjs +0 -2
  150. package/dist/chunk-HATA2W7X.mjs +0 -2
  151. package/dist/chunk-JJNRIFND.mjs +0 -8
  152. package/dist/chunk-JL6R4FG4.mjs +0 -4
  153. package/dist/chunk-KUILYI7H.mjs +0 -4
  154. package/dist/chunk-NIW7F7LU.mjs +0 -4
  155. package/dist/chunk-OU3S466R.mjs +0 -20
  156. package/dist/chunk-QCEATQC4.mjs +0 -2
  157. package/dist/chunk-TDWJKOLN.mjs +0 -2
  158. package/dist/chunk-UGO5N3EI.mjs +0 -15
  159. package/dist/chunk-XMKHCUI6.mjs +0 -15
  160. package/dist/chunk-XQRUG4G3.mjs +0 -2
  161. package/dist/chunk-YPPJVDQI.mjs +0 -2
  162. package/dist/chunk-ZANMKAWS.mjs +0 -2
  163. package/web/assets/index-BHC5ZOMh.js +0 -15
  164. /package/dist/{chunk-N3DSBH5S.mjs → chunk-A55HN5OK.mjs} +0 -0
  165. /package/dist/{chunk-KNZJT4ET.mjs → chunk-QAIHRH3I.mjs} +0 -0
  166. /package/dist/{chunk-ZW2A6GBW.mjs → chunk-QR6A54KJ.mjs} +0 -0
  167. /package/dist/{chunk-74UW7QSL.mjs → chunk-UH4SIXTR.mjs} +0 -0
  168. /package/dist/{chunk-EKGYYOSP.mjs → chunk-W7XHE4CT.mjs} +0 -0
  169. /package/dist/{chunk-5MMN3N5J.mjs → chunk-YEY3RSFQ.mjs} +0 -0
@@ -6,7 +6,7 @@ sidebar's \u9ED8\u8BA4\u6587\u6863 (GALLERY_DEFAULT_WORKSPACE names another fold
6
6
  whole address, as a user hands one over (http://127.0.0.1:4317/#\u5468\u62A5-k3xv9q2a, a block's id after a / or not): the
7
7
  words in a link are a label, and a title changed since leaves the address good.`,a={init:`Usage: gallery init [<dir>] [--from <old reports dir>] [--name "<name>"]
8
8
  Makes a workspace: <dir> (else the workspace found as every command finds it) with its gallery.json
9
- and .gallery/ (never over a gallery.json that is there). Prints \u5DE5\u4F5C\u533A\uFF1A<abs>\uFF08\u65B0\u5EFA or \u5DF2\u6709\uFF09.
9
+ only (never over a gallery.json that is there); the home workspace also gets its application folders. Prints \u5DE5\u4F5C\u533A\uFF1A<abs>\uFF08\u65B0\u5EFA or \u5DF2\u6709\uFF09.
10
10
  --name writes the workspace's name in its gallery.json (the project's: what the sidebar and gallery
11
11
  workspaces call it; else its folder's), said as \u540D\u5B57\uFF1A<name>; gallery workspaces --name changes it.
12
12
  The workspace goes on this machine's registry, as every command's does (gallery workspaces).
@@ -15,7 +15,7 @@ holding report.html or doc.html) into the workspace: every document whose slug i
15
15
  others listed as skipped), its preferences.md when the workspace has none, the sidebar's order, the
16
16
  \u5199\u4F5C\u504F\u597D page, the custom emoji and the documents' recent versions. The old folder is only read:
17
17
  nothing there is changed, moved or deleted.
18
- A workspace that never had one gets its home page (\u9996\u9875, pages/home/: Gallery's today and note cards),
18
+ Only the default workspace gets its home page (\u9996\u9875, pages/home/: Gallery's today and note cards),
19
19
  as a server's first start gives it, said in a line; once made, nothing makes it again.
20
20
  Exits 1 when the workspace cannot be written or --from names no folder; 2 for a name that is empty,
21
21
  over 80 characters or more than one line.`,new:`Usage: gallery new <slug> "<title>" ["<description>"] [--under <document>] [--after <document> | --first] [--no-preview] [--no-browser]
@@ -25,13 +25,13 @@ in the sidebar's tree: under --under's document, last (first with --first), or r
25
25
  (at that one's level); neither, at the top level, last. A document is named there by its slug, link
26
26
  or address (gallery help says how), and must be there, not in the trash; the \u5199\u4F5C\u504F\u597D page holds none.
27
27
  Then says where it went (Placed it \u2026), where it wrote (the workspace), where the user's writing preferences are (\u5199\u4F5C\u504F\u597D,
28
- <workspace>/preferences.md, to read first: made from Gallery's default when there are none yet) and
29
- the next steps (the first: send the user the address now), and last starts this workspace's Gallery
28
+ <home>/preferences.md, to read first: made from Gallery's default when there are none yet) and
29
+ the next steps (the first: send the user the address now), and last starts the one Gallery
30
30
  server (or uses the one running: it runs on after this command), opens the default browser at the
31
31
  document and prints the address to give the user, as gallery open does. In a workspace other than the
32
32
  default one, the document also joins the default workspace's sidebar (when there is one), in its
33
33
  workspace's column: a line says where, \u9ED8\u8BA4\u5DE5\u4F5C\u533A\uFF08\u2026\uFF09\u7684\u4FA7\u8FB9\u680F\uFF1A\u5DF2\u52A0\u8FDB\u2026; it is a display only, the file stays in
34
- its own workspace. GALLERY_NO_DEFAULT_TREE=1 leaves that out. --no-preview (or
34
+ its own workspace. --no-preview (or
35
35
  GALLERY_NO_PREVIEW=1) leaves the server alone; --no-browser (or GALLERY_NO_BROWSER=1) opens no
36
36
  browser. Editing needs Chrome or Edge.
37
37
  A title or a description that starts with "-" and a letter would be read as an option: put "--"
@@ -54,7 +54,7 @@ Put "--" before a title that starts with "-" and a letter.
54
54
  Exits 1 when the file is not there, cannot be read, or gallery new would refuse the slug; 2 for a
55
55
  kind it does not take.`,open:`Usage: gallery open [<slug>] [--no-browser]
56
56
  Starts this workspace's Gallery server (or uses the one running: it runs on after this command, its
57
- log in <workspace>/.gallery/logs/server.log), waits until it answers, and opens the default browser
57
+ log in <data>/logs/server.log), waits until it answers, and opens the default browser
58
58
  at the workbench, or at the document <slug>, at its block when an address names one (--no-browser,
59
59
  or GALLERY_NO_BROWSER=1, opens none).
60
60
  ${t}
@@ -63,7 +63,7 @@ the address to give the user. With a slug in a workspace other than the default
63
63
  them says the document joined the default workspace's sidebar (as gallery new's does). Editing needs Chrome or Edge: open the address there.
64
64
  With a slug and no qa baseline yet, it first keeps one of the document as it is now, so that the
65
65
  first gallery qa after the changes pictures what changed.
66
- Exits 1 when there is no such document, no server answers, or the workspace's server takes the
66
+ Exits 1 when there is no such document, no server answers, or the shared Gallery server takes the
67
67
  request and gives no answer (a second server is never started beside it).`,serve:`Usage: gallery serve [--port <n>]
68
68
  Runs this workspace's Gallery server in the foreground until Ctrl+C (gallery open runs one in the
69
69
  background instead). Prints the address once it answers. --port picks the port (else the last one
@@ -83,7 +83,7 @@ Exits 1 when a document fails, unless --allow-failures.`,export:`Usage: gallery
83
83
  gallery export --all [--allow-failures]
84
84
  Hands each named document in: its doc.html (report.html in an older document) written as its
85
85
  preview shows it, natural HTML as the kit's markup and every block given an id (through the
86
- workspace's server while one runs); then checks it and writes one standalone offline file per
86
+ shared Gallery server while one runs); then checks it and writes one standalone offline file per
87
87
  passing document, <workspace>/exports/<slug>.html. A document the quick checks fail is not handed in.
88
88
  ${t}
89
89
  It says first, once, what the preview wrote when the reader edited a document and the \u6279\u6CE8 it deleted;
@@ -119,7 +119,7 @@ with --no-export or --blocks names an id the document has not, else 0. A warning
119
119
  gallery list [<words>...] --all
120
120
  The workspace's documents, for an Agent to find the one the user means: each one's slug and title,
121
121
  its description, where it is in the sidebar's tree when it is under another (\u4F4D\u7F6E\uFF1Athe documents above
122
- it, from the top), its address (\u5730\u5740\uFF1A/#<link>, after the port of the workspace's server), when its file
122
+ it, from the top), its address (\u5730\u5740\uFF1A/#<link>, after the port of the shared Gallery server), when its file
123
123
  was last written and where that file is, the one edited last first.
124
124
  With words, only those whose title, description or slug holds any of them (case alike, Chinese found
125
125
  inside words), the best first, then those whose text holds them, each with its first place there
@@ -145,13 +145,13 @@ Exits 1 when --tree names a document that is not there, 2 one in the trash.`,wor
145
145
  gallery workspaces --name "<name>"
146
146
  gallery workspaces --forget <path>
147
147
  The workspaces of this machine: every workspace a gallery command or a Gallery server has worked in
148
- (but one in the system's temporary folder) is registered in a file of the user's (GALLERY_DATA_DIR,
148
+ is registered in a file of the user's (GALLERY_DATA_DIR,
149
149
  else %LOCALAPPDATA%\\gallery\\workspaces.json on Windows, ~/Library/Application Support/gallery on macOS,
150
150
  $XDG_STATE_HOME/gallery or ~/.local/state/gallery elsewhere). Lists them, the current one first (*),
151
151
  then the one edited last first: each one's name (its gallery.json's, else its folder's; the folder
152
152
  above it, or its own path, after the name when two are called alike), its id (ws- and six hex
153
153
  digits), its path (\u8DEF\u5F84\uFF1A), how many documents it has and when one was last edited (\u6587\u6863\uFF1A), and its
154
- server's address while one runs (\u670D\u52A1\uFF1A); one whose folder or gallery.json is gone is marked \u4E0D\u5728\u4E86
154
+ one shared service address printed above the list (\u670D\u52A1\uFF1A); one whose folder or gallery.json is gone is marked \u4E0D\u5728\u4E86
155
155
  and stays registered (a drive may come back).
156
156
  --scan registers the workspaces in <folder> and below it, 6 levels down at most (not in node_modules,
157
157
  .git, a dot folder or the recycle bin): the Documents folder when none is named. --name names the
@@ -204,9 +204,11 @@ remove moves it to the trash, which the workbench's \u8BBE\u7F6E \u203A \u56DE\u
204
204
  Each is written through the workspace's running server when there is one (an open workbench shows it
205
205
  at once), else here.
206
206
  Exits 1 when a link, a column or an entry named is not there or the server refuses it; 2 for an
207
- address that is not http or https, an empty name, or two places at once.`,extension:`Usage: gallery extension new <id> "<title>" [--local]
207
+ address that is not http or https, an empty name, or two places at once.`,extension:`Usage: gallery extension new <id> "<title>"
208
208
  gallery extension list
209
209
  gallery extension check <id>
210
+ gallery extension install <folder | .zip>
211
+ gallery extension remove <id>
210
212
  An extension (\u6269\u5C55) gives the sidebar a column of entries of its own, beside \u6587\u6863: a folder
211
213
  <workspace>/extensions/<id>/ whose sidebar.json lists them (a title, an optional icon, and entries each with
212
214
  an id, a title, an optional address (http or https), an optional icon and optional children). The workbench
@@ -214,13 +216,12 @@ reads the file again within a second of every change; a click on an entry with a
214
216
  the sidebar (as a web link's), one without opens and closes what is under it. The user may drag the column to
215
217
  another place, rename it and reorder its root entries; title/order edits write back to sidebar.json.
216
218
  A file that does not read shows the column with one row, \u6761\u76EE\u8BFB\u4E0D\u51FA\u6765\uFF1A<why>.
217
- new creates an empty sidebar.json in the DEFAULT workspace, shared by every project's sidebar. Add --local
218
- to create it only in the selected workspace (--workspace still selects the project). Existing files are never
219
- overwritten. Read the printed file and fill its entries (references/extensions.md in the skill says how).
220
- Every sidebar reads the default workspace's extensions plus its own. A project sidebar.json with the same id
221
- takes precedence in that project; an empty folder does not. No files are copied or moved automatically.
219
+ new creates an empty sidebar.json in the default workspace. Project-local extensions are not read.
220
+ install <folder | .zip> validates and replaces an extension; remove <id> removes it.
221
+ list prints capabilities and AGENT.md paths. Executable extensions require user confirmation in Settings > Extensions.
222
+ Every sidebar reads only the default workspace's extensions. No files are copied or moved automatically.
222
223
  list prints the visible extensions, their source paths, titles and entry counts, or why they show none.
223
- check <id> resolves the same public/project source as the sidebar and prints what the sidebar will show:
224
+ check <id> resolves the same default-workspace source as the sidebar and prints what the sidebar will show:
224
225
  the column, then each entry with its id, title and address, one under another indented; notes (an icon that
225
226
  is no emoji and no icon of the \u56FE\u6807 tab, which is left out) follow. Writes nothing.
226
227
  Exits 0 when the file reads; 1 when the extension is not there, has no sidebar.json or its file does not
@@ -332,7 +333,7 @@ Exits 2 for an id no block can have.
332
333
  try makes what a reader does on an instance in a document, with the pointer and the keys, and says
333
334
  what it wrote. It makes it on a scratch copy of the document (<workspace>/.gallery/try/try-<8 hex>/,
334
335
  gone at the end, whatever came of it): doc.html is not written, and no page of the user's shows the trial;
335
- --keep makes it on the document itself and leaves what it wrote. It starts the workspace's server (or
336
+ --keep makes it on the document itself and leaves what it wrote. It starts the shared Gallery server (or
336
337
  uses the one running), as gallery open does, and opens the copy's page alone, editable, in Chrome or
337
338
  Edge, headless, in a profile of its own, and waits until the server has told the page of the writes
338
339
  made before it (a custom block changed), which load it again. Each selector is the first element of the
@@ -406,7 +407,7 @@ Documents and custom pages share one set of slugs: neither takes the other's, no
406
407
  The home page (\u9996\u9875) is pages/home, a page as any.
407
408
  new makes one: page.html with its title (in <title>: a page draws no big title) and one empty board (data-board-id="main"), and
408
409
  page.json with the title; it goes last in the sidebar's head. The server puts in the scripts and styles
409
- of the blocks its cards hold. Says where it wrote and what to write next, and with the workspace's server
410
+ of the blocks its cards hold. Says where it wrote and what to write next, and with the shared Gallery server
410
411
  running ends with the \u4EA4\u7ED9\u7528\u6237 line gallery open has: the page's whole address, to send the user at once
411
412
  (without one, gallery page open <slug> --no-browser gives it).
412
413
  Exits 1 when the slug is taken (a document's, a page's, the trash's) or kept (exports, components, pages,
@@ -415,7 +416,7 @@ its own cards; gallery open --no-browser starts one), gallery page open, add, tr
415
416
  so in place of "no such page".
416
417
  list says the workspace's custom pages in the sidebar's order (the order the user dragged them to, then
417
418
  gallery.json's pages.order, then by title): each one's slug, icon and title, its address (\u5730\u5740\uFF1A, the whole address with
418
- the workspace's server running, else /#@<slug>, after the port of a server) and where its page.html is;
419
+ the shared Gallery server running, else /#@<slug>, after the port of a server) and where its page.html is;
419
420
  in a workspace with no page whose home page is not made yet, only that the home page waits for the server.
420
421
  open starts this workspace's Gallery server (or uses the one running), as gallery open does, and opens
421
422
  the default browser at the page in the workbench (--no-browser, or GALLERY_NO_BROWSER=1, opens none).
@@ -448,7 +449,7 @@ gallery block try's gestures (--press, --drag \u2026 --to, --key, --type, --sele
448
449
  the first element of the instance it finds (gallery block --help says each). It makes them on a scratch
449
450
  copy of the page (<workspace>/.gallery/try/try-<8 hex>/, gone at the end, whatever came of it):
450
451
  page.html is not written, and no page of the user's shows the trial; --keep makes them on the page itself
451
- and leaves what they wrote. It starts the workspace's server (or uses the one running) and opens the
452
+ and leaves what they wrote. It starts the shared Gallery server (or uses the one running) and opens the
452
453
  copy's page alone (/pages/<slug>), editable, in Chrome or Edge, headless, in a profile of its own. A
453
454
  write is what the page's board sends the page service, as the user's gestures go: once each is
454
455
  answered, a Gesture line (Step N with --steps) and a Wrote line say each data part of the card's
@@ -486,7 +487,7 @@ the last check that found nothing saw it (or, before any, since the version the
486
487
  its last write): cards added, removed, moved (to another board too), resized, their data parts changed
487
488
  (with the lines), a card's own markup, the page's own HTML; each change the page wrote since, a gesture
488
489
  of the user's there (not gallery page add's), ends "(the user's, on the page)": leave it as it is. Then
489
- the page itself, a scratch copy of it on the workspace's server (started
490
+ the page itself, a scratch copy of it on the shared Gallery server (started
490
491
  or used, as gallery page open does), in Chrome or Edge at 1280, 1920 and 600px wide (a narrow board: fewer
491
492
  columns of the same 64px cells), light and dark: a card whose content does not fit it, a card drawn out of its board, the page
492
493
  wider than the window, a block that failed, a picture that does not load, what the console says; each
@@ -523,7 +524,7 @@ Gallery: documents written as HTML, edited in the browser, exported as one offli
523
524
  gallery import <file> [<slug> ["<title>"]] documents made of a file (Markdown, HTML, Word, PDF\u2026)
524
525
  gallery open [<slug>] [--no-browser] start or reuse the server and open the browser
525
526
  gallery serve [--port <n>] run the server in the foreground
526
- gallery stop stop the workspace's server
527
+ gallery stop stop the shared Gallery server
527
528
  gallery check [<slug>...] check documents (none named: all)
528
529
  gallery export <slug>... | --all write <workspace>/exports/<slug>.html
529
530
  gallery qa <slug>... [--blocks a,b] [--tiles] look at exports in Chrome or Edge
@@ -1,2 +1,2 @@
1
1
  import { createRequire as __galleryRequire } from "node:module"; import { fileURLToPath as __galleryPath } from "node:url"; const require = __galleryRequire(import.meta.url); const __filename = __galleryPath(import.meta.url); const __dirname = __galleryPath(new URL(".", import.meta.url));
2
- import{a}from"./chunk-HM4E43VM.mjs";import"./chunk-36FIRJIF.mjs";import"./chunk-5L7RYZCL.mjs";export{a as convertPuppeteerChannelToBrowsersChannel};
2
+ import{a}from"./chunk-MAFIGVXY.mjs";import"./chunk-742D2WWJ.mjs";import"./chunk-5L7RYZCL.mjs";export{a as convertPuppeteerChannelToBrowsersChannel};
@@ -1,3 +1,3 @@
1
1
  import { createRequire as __galleryRequire } from "node:module"; import { fileURLToPath as __galleryPath } from "node:url"; const require = __galleryRequire(import.meta.url); const __filename = __galleryPath(import.meta.url); const __dirname = __galleryPath(new URL(".", import.meta.url));
2
- import{a as q,b as B}from"./chunk-QK3VISCA.mjs";import{b as C}from"./chunk-KH24LWAT.mjs";import x from"node:fs/promises";import W from"node:path";import{MENTION as L}from"../browser/shared/components/mention.mjs";import{writeAtomic as R}from"../browser/shared/files.mjs";import{reportLines as U}from"../browser/shared/search.mjs";import{countWords as Q}from"../browser/shared/words.mjs";import{FACT_KINDS as V,QUERY_KINDS as Y,SNAPSHOT_LIMITS as y,queryOptions as G}from"../browser/shared/workspace-query.mjs";import{documentDirectory as M,documentFiles as T,layoutOf as X,listDocumentSlugs as _,listTrash as Z}from"../browser/shared/workspace.mjs";var ut=f=>c=>f.readTaken(c,{wait:0}),z=({todos:f})=>{let c=new Map,g=d=>JSON.stringify([d.text,d.path]);for(let d of f)c.set(g(d),(c.get(g(d))??0)+1);return f.some(d=>!d.block&&c.get(g(d))>1)},tt=(f,c)=>({hash:B(f),words:Q(c),todos:q(c)});function et(f){let c=new Date(f);return c.setHours(0,0,0,0),c.setDate(c.getDate()-(c.getDay()+6)%7),c.getTime()}function mt({root:f,read:c,draw:g=u=>u,activity:d=null,now:I=()=>new Date}){let u=new Map,m=new Map,b=t=>x.stat(t).then(({mtimeMs:e})=>e,()=>null);async function J(t,e=null){let o=T(M(t,f)),[a,n]=await Promise.all([b(o.html),b(o.json)]);if(a===null)return null;let s=e??await c(t);if(!s)return null;let r={};try{r=JSON.parse(await x.readFile(o.json,"utf8"))??{}}catch{}let{title:i,icon:h}=r,w={slug:t,title:typeof i=="string"&&i.trim()?i:t,icon:typeof h=="string"&&h?h:null,edited:Math.round(a),...tt(s.source,s.text)};return u.set(t,{html:a,json:n,facts:w,held:s.held===!0}),m.has(t)||m.set(t,w),w}async function O(t){let e=u.get(t);if(e&&!e.held){let o=T(M(t,f)),[a,n]=await Promise.all([b(o.html),b(o.json)]);if(a===e.html&&n===e.json)return e.facts}return J(t)}async function S(){let t=await _(f);for(let e of u.keys())t.includes(e)||u.delete(e);for(let e of m.keys())t.includes(e)||m.delete(e);return(await Promise.all(t.map(e=>O(e).catch(()=>null)))).filter(Boolean)}let P={async todos({done:t,slugs:e,limit:o}){let a=(await S()).filter(s=>!e||e.includes(s.slug)).sort((s,r)=>r.edited-s.edited||s.slug.localeCompare(r.slug)),n=[];for(let{slug:s,title:r,icon:i,todos:h,hash:w}of a)for(let l of h)if(!(t!==void 0&&l.done!==t)){if(n.length>=o)return n;n.push({ref:{slug:s,block:l.block,text:l.text,path:l.path,nth:l.nth,version:w},text:l.text,done:l.done,slug:s,title:r,icon:i,path:l.path})}return n},async recent({limit:t}){return(await S()).sort((e,o)=>o.edited-e.edited||e.slug.localeCompare(o.slug)).slice(0,t).map(({slug:e,title:o,icon:a,edited:n})=>({slug:e,title:o,icon:a,edited:new Date(n).toISOString()}))},async stats(){let t=await S(),e=et(I()),o=t.flatMap(a=>a.todos);return{documents:t.length,todos:{done:o.filter(a=>a.done).length,total:o.length},words:t.reduce((a,n)=>a+n.words,0),editedThisWeek:t.filter(a=>a.edited>=e).length}},async activity({days:t}){return d?(await d.load(),await $,d.days(t)):[]},async table({slug:t,key:e,where:o,limit:a},{words:n=!1}={}){let s=await O(t).catch(()=>null),r=u.get(t);if(!s||!r)return k(404,"missing",`no document "${t}"`);if(r.tables??=new Map,!r.tables.has(e)){let l=await c(t);if(!l)return k(404,"missing",`no document "${t}"`);r.tables.set(e,C(l.text,e,t))}let i=r.tables.get(e);if(i.error==="missing")return k(404,"missing",`"${t}" holds no table whose frame carries data-doc-chart-source="${e}"`);if(i.error)return k(422,"missing",`the table "${e}" of "${t}" has merged cells, which no view reads: write each value in its own cell`);let h=Object.keys(o).filter(l=>!i.columns.includes(l));if(h.length>0)return k(400,"options",`table: the table "${e}" of "${t}" has no column ${h.map(l=>JSON.stringify(l)).join(", ")} (its columns: ${i.columns.map(l=>JSON.stringify(l)).join(", ")})`);let w=i.rows.filter(l=>Object.entries(o).every(([D,v])=>l.words[D]===v.replace(/\s+/g," ").trim()));return{columns:[...i.columns],rows:w.slice(0,a).map(({values:l,links:D,words:v})=>({values:{...l},links:D.map(K=>({...K})),...n?{words:{...v}}:{}})),total:w.length}}},k=(t,e,o)=>{throw Object.assign(new Error(o),{refusal:[t,{ok:!1,reason:e,message:o}]})},p=new Map,j=t=>W.join(X(f).gallery,"cache","workspace",`${t}.json`),A=async t=>{if(!p.has(t)){let e=[];try{let o=JSON.parse(await x.readFile(j(t),"utf8"));Array.isArray(o?.tables)&&(e=o.tables.filter(a=>typeof a=="string").slice(-y.tables))}catch{}p.has(t)||p.set(t,e)}return p.get(t)},N=Promise.resolve(),H=async(t,e)=>{let o=await A(t);if(o.at(-1)===e)return;let a=[...o.filter(n=>n!==e),e].slice(-y.tables);p.set(t,a),N=N.then(async()=>{await x.mkdir(W.dirname(j(t)),{recursive:!0}),await R(j(t),`${JSON.stringify({tables:p.get(t)})}
2
+ import{a as q,b as B}from"./chunk-IA4PSIMD.mjs";import{b as C}from"./chunk-ZTHICSSF.mjs";import x from"node:fs/promises";import W from"node:path";import{MENTION as L}from"../browser/shared/components/mention.mjs";import{writeAtomic as R}from"../browser/shared/files.mjs";import{reportLines as U}from"../browser/shared/search.mjs";import{countWords as Q}from"../browser/shared/words.mjs";import{FACT_KINDS as V,QUERY_KINDS as Y,SNAPSHOT_LIMITS as y,queryOptions as G}from"../browser/shared/workspace-query.mjs";import{documentDirectory as M,documentFiles as T,layoutOf as X,listDocumentSlugs as _,listTrash as Z}from"../browser/shared/workspace.mjs";var ut=f=>c=>f.readTaken(c,{wait:0}),z=({todos:f})=>{let c=new Map,g=d=>JSON.stringify([d.text,d.path]);for(let d of f)c.set(g(d),(c.get(g(d))??0)+1);return f.some(d=>!d.block&&c.get(g(d))>1)},tt=(f,c)=>({hash:B(f),words:Q(c),todos:q(c)});function et(f){let c=new Date(f);return c.setHours(0,0,0,0),c.setDate(c.getDate()-(c.getDay()+6)%7),c.getTime()}function mt({root:f,read:c,draw:g=u=>u,activity:d=null,now:I=()=>new Date}){let u=new Map,m=new Map,b=t=>x.stat(t).then(({mtimeMs:e})=>e,()=>null);async function J(t,e=null){let o=T(M(t,f)),[a,n]=await Promise.all([b(o.html),b(o.json)]);if(a===null)return null;let s=e??await c(t);if(!s)return null;let r={};try{r=JSON.parse(await x.readFile(o.json,"utf8"))??{}}catch{}let{title:i,icon:h}=r,w={slug:t,title:typeof i=="string"&&i.trim()?i:t,icon:typeof h=="string"&&h?h:null,edited:Math.round(a),...tt(s.source,s.text)};return u.set(t,{html:a,json:n,facts:w,held:s.held===!0}),m.has(t)||m.set(t,w),w}async function O(t){let e=u.get(t);if(e&&!e.held){let o=T(M(t,f)),[a,n]=await Promise.all([b(o.html),b(o.json)]);if(a===e.html&&n===e.json)return e.facts}return J(t)}async function S(){let t=await _(f);for(let e of u.keys())t.includes(e)||u.delete(e);for(let e of m.keys())t.includes(e)||m.delete(e);return(await Promise.all(t.map(e=>O(e).catch(()=>null)))).filter(Boolean)}let P={async todos({done:t,slugs:e,limit:o}){let a=(await S()).filter(s=>!e||e.includes(s.slug)).sort((s,r)=>r.edited-s.edited||s.slug.localeCompare(r.slug)),n=[];for(let{slug:s,title:r,icon:i,todos:h,hash:w}of a)for(let l of h)if(!(t!==void 0&&l.done!==t)){if(n.length>=o)return n;n.push({ref:{slug:s,block:l.block,text:l.text,path:l.path,nth:l.nth,version:w},text:l.text,done:l.done,slug:s,title:r,icon:i,path:l.path})}return n},async recent({limit:t}){return(await S()).sort((e,o)=>o.edited-e.edited||e.slug.localeCompare(o.slug)).slice(0,t).map(({slug:e,title:o,icon:a,edited:n})=>({slug:e,title:o,icon:a,edited:new Date(n).toISOString()}))},async stats(){let t=await S(),e=et(I()),o=t.flatMap(a=>a.todos);return{documents:t.length,todos:{done:o.filter(a=>a.done).length,total:o.length},words:t.reduce((a,n)=>a+n.words,0),editedThisWeek:t.filter(a=>a.edited>=e).length}},async activity({days:t}){return d?(await d.load(),await $,d.days(t)):[]},async table({slug:t,key:e,where:o,limit:a},{words:n=!1}={}){let s=await O(t).catch(()=>null),r=u.get(t);if(!s||!r)return k(404,"missing",`no document "${t}"`);if(r.tables??=new Map,!r.tables.has(e)){let l=await c(t);if(!l)return k(404,"missing",`no document "${t}"`);r.tables.set(e,C(l.text,e,t))}let i=r.tables.get(e);if(i.error==="missing")return k(404,"missing",`"${t}" holds no table whose frame carries data-doc-chart-source="${e}"`);if(i.error)return k(422,"missing",`the table "${e}" of "${t}" has merged cells, which no view reads: write each value in its own cell`);let h=Object.keys(o).filter(l=>!i.columns.includes(l));if(h.length>0)return k(400,"options",`table: the table "${e}" of "${t}" has no column ${h.map(l=>JSON.stringify(l)).join(", ")} (its columns: ${i.columns.map(l=>JSON.stringify(l)).join(", ")})`);let w=i.rows.filter(l=>Object.entries(o).every(([D,v])=>l.words[D]===v.replace(/\s+/g," ").trim()));return{columns:[...i.columns],rows:w.slice(0,a).map(({values:l,links:D,words:v})=>({values:{...l},links:D.map(K=>({...K})),...n?{words:{...v}}:{}})),total:w.length}}},k=(t,e,o)=>{throw Object.assign(new Error(o),{refusal:[t,{ok:!1,reason:e,message:o}]})},p=new Map,j=t=>W.join(X(f).gallery,"cache","workspace",`${t}.json`),A=async t=>{if(!p.has(t)){let e=[];try{let o=JSON.parse(await x.readFile(j(t),"utf8"));Array.isArray(o?.tables)&&(e=o.tables.filter(a=>typeof a=="string").slice(-y.tables))}catch{}p.has(t)||p.set(t,e)}return p.get(t)},N=Promise.resolve(),H=async(t,e)=>{let o=await A(t);if(o.at(-1)===e)return;let a=[...o.filter(n=>n!==e),e].slice(-y.tables);p.set(t,a),N=N.then(async()=>{await x.mkdir(W.dirname(j(t)),{recursive:!0}),await R(j(t),`${JSON.stringify({tables:p.get(t)})}
3
3
  `)}).catch(()=>{})},F=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,$=Promise.resolve(),E={facts:O,all:S,async lines(t,e){let o=u.get(t);if(!await O(t))return null;let n=u.get(t);if(n!==o||!n.lines||n.lines.titles!==null&&n.lines.titles!==e){let s=await c(t);if(!s)return null;n.lines={titles:s.text.includes(L)?e:null,value:U(g(s.text,t))}}return n.lines.value},async query(t,e,{doc:o=null}={}){if(!Y.includes(t))return[400,{ok:!1,reason:"kind",message:`no kind "${t}": todos, recent, stats, activity or table`}];let{problem:a,options:n}=G(t,e);if(a)return[400,{ok:!1,reason:"options",message:`${t}: ${a}`}];let s;try{s=await P[t](n)}catch(r){if(r.refusal)return r.refusal;throw r}return t==="table"&&typeof o=="string"&&F.test(o)&&await H(o,`${n.slug}#${n.key}`),[200,{ok:!0,kind:t,data:s,at:new Date(I()).toISOString()}]},async snapshot(t){let e=async(n,s)=>{let[r,i]=await E.query(n,s);return r===200?i.data:null},o={todos:await e("todos",{limit:y.todos}),recent:await e("recent",{limit:y.recent}),stats:await e("stats"),activity:await e("activity",{days:y.activity})},a={};for(let n of F.test(t)?await A(t):[]){let[s,r]=n.split("#"),i=await P.table({slug:s,key:r,where:{},limit:y.rows},{words:!0}).catch(()=>null);i&&(a[n]=i)}return Object.keys(a).length>0&&(o.tables=a),Object.fromEntries(Object.entries(o).filter(([,n])=>n!==null))},stored:()=>N,async changed(t,{source:e=null,text:o=null,by:a="agent"}={}){let n=m.get(t)??u.get(t)?.facts??null;u.delete(t);let s=e===null?null:await J(t,{source:e,text:o??e}).catch(()=>null);s?m.set(t,s):m.delete(t);let r=new Set;if(!!n!=!!s)for(let i of["todos","recent","stats","table"])r.add(i);return n&&s&&n.hash!==s.hash&&r.add("table"),n&&s&&n.hash!==s.hash&&(z(n)||z(s))&&r.add("todos"),n&&s&&((n.title!==s.title||JSON.stringify(n.todos)!==JSON.stringify(s.todos))&&r.add("todos"),(n.title!==s.title||n.icon!==s.icon||n.edited!==s.edited)&&r.add("recent"),(n.words!==s.words||n.todos.length!==s.todos.length||n.todos.filter(i=>i.done).length!==s.todos.filter(i=>i.done).length||n.edited!==s.edited)&&r.add("stats")),!n&&s&&r.add("recent"),d&&s&&(await d.load(),await $,d.record(t,{hash:s.hash,words:s.words,mtime:s.edited,by:a})&&r.add("activity")),V.filter(i=>r.has(i))},start(){return d?($=(async()=>{await d.load();let t=await _(f),e=(await Promise.all(t.map(async a=>({slug:a,mtime:await b(T(M(a,f)).html)})))).filter(({mtime:a})=>a!==null),o=(await Z(f).catch(()=>[])).map(a=>a.slug);return d.catchUp(e.map(({slug:a,mtime:n})=>({slug:a,mtime:Math.round(n)})),O,{kept:o})})().catch(()=>0),$):Promise.resolve(0)},forget(t){u.delete(t),m.delete(t)}};return E}export{ut as a,mt as b};
@@ -1,2 +1,2 @@
1
1
  import { createRequire as __galleryRequire } from "node:module"; import { fileURLToPath as __galleryPath } from "node:url"; const require = __galleryRequire(import.meta.url); const __filename = __galleryPath(import.meta.url); const __dirname = __galleryPath(new URL(".", import.meta.url));
2
- import{f as A}from"./chunk-DHB7UZ7F.mjs";import{a as w,c as U}from"./chunk-2RKIHJI2.mjs";import he from"node:fs";import $e from"node:path";import{reportsDirectory as we}from"../browser/shared/paths.mjs";import{assetFile as be,assetProblem as ge,embedFile as ke}from"../browser/shared/media.mjs";import{attr as H,hasClass as xe,walk as ye}from"../browser/shared/html-tree.mjs";import _ from"node:fs";import ie from"node:path";import{attr as ae,hasClass as ce,walk as fe}from"../browser/shared/html-tree.mjs";import{MEDIA_ROUTES as le,mediaTypeOf as de,mediaUrl as ue}from"../browser/shared/media.mjs";import{documentDirectory as pe}from"../browser/shared/workspace.mjs";function k(e,n,o){let s=null;return fe(e,t=>{!s&&t.tagName===n&&ce(t,o)&&(s=t)}),s}function N(e,n){let o=ie.join(e,n);return _.statSync(o,{throwIfNoEntry:!1})?.isFile()?`data:${de(n)};base64,${_.readFileSync(o).toString("base64")}`:null}function me(e,{attribute:n,route:o,slug:s,mode:t,reportsDirectory:r}){if(!le[o](e))return null;if(t==="preview")return`${n}="${ue(o,s,e)}" data-ge-${n}="${e}"`;let a=N(pe(s,r),e);return a&&`${n}="${a}"`}function x(e,n,{attribute:o,route:s,slug:t,mode:r,reportsDirectory:a}){let i=n.map(f=>({place:f.sourceCodeLocation?.attrs?.[o],value:ae(f,o)})).filter(({place:f})=>f).sort((f,d)=>f.place.startOffset-d.place.startOffset),c=[],l=0;for(let{place:f,value:d}of i){let u=me(d,{attribute:o,route:s,slug:t,mode:r,reportsDirectory:a});u===null||f.startOffset<l||(c.push(e.slice(l,f.startOffset),u),l=f.endOffset)}return c.push(e.slice(l)),c.join("")}function D(e){let n=[];return ye(e,o=>{let s=o.tagName==="figure"&&xe(o,"doc-embed")?k(o,"iframe","doc-embed-frame"):null;s&&n.push(s)}),n}function bt(e,{slug:n,mode:o="export",reportsDirectory:s=we}){return e.includes("doc-embed")?x(e,D(w(e)),{attribute:"src",route:"embed",slug:n,mode:o,reportsDirectory:s}):e}var I=(e,n=w(e))=>D(n).map(o=>o.sourceCodeLocation.startOffset);function gt({html:e,directory:n,tree:o=w(e)}){let s=[];for(let t of D(o)){let r=`line ${t.sourceCodeLocation.startLine}`,a=H(t,"src")??"",i=H(t,"sandbox"),c=/^https:\/\/[^\s"]+$/.test(a),l=!c&&!/^[a-z][a-z0-9+.-]*:/i.test(a)&&!be(a)?ge(a):null;l?s.push(`${r}: an embed's frame (${a.slice(0,80)}): ${l} (an HTML or PDF file; or a web page, https://\u2026)`):!c&&!ke(a)?s.push(`${r}: an embed's frame (${a.slice(0,80)}) shows a web page (https://\u2026, never http) or an HTML or PDF file of the document's folder (assets/<file>)`):!c&&!he.existsSync($e.join(n,a))?s.push(`${r}: the embed's file ${a} is not in the document's folder`):(c||/\.html?$/i.test(a))&&i===void 0?s.push(`${r}: an embed's frame (${a.slice(0,80)}) is sandboxed: sandbox="allow-scripts allow-popups \u2026"`):!c&&/\.html?$/i.test(a)&&/\ballow-same-origin\b/.test(i)?s.push(`${r}: an embedded HTML file (${a}) keeps its own origin: its sandbox has no allow-same-origin`):!c&&/\.pdf$/i.test(a)&&i!==void 0&&s.push(`${r}: an embedded PDF (${a}) is sandboxed, and a sandboxed frame shows no PDF: take its sandbox attribute off`)}return[...new Set(s)]}import Oe from"node:fs";import Se from"node:path";import{reportsDirectory as ve}from"../browser/shared/paths.mjs";import{assetFile as Fe,assetProblem as Le}from"../browser/shared/media.mjs";import{attr as z,hasClass as Ee,walk as Ce}from"../browser/shared/html-tree.mjs";function F(e,n=w(e)){let o=[];return Ce(n,s=>{s.tagName==="figure"&&Ee(s,"doc-file")&&o.push({node:s,link:k(s,"a","doc-file-link")})}),o}function Et(e,{slug:n,mode:o="export",reportsDirectory:s=ve}){if(!e.includes("doc-file"))return e;let t=F(e).flatMap(({link:r})=>r?[r]:[]);return x(e,t,{attribute:"href",route:"file",slug:n,mode:o,reportsDirectory:s})}function Ct({html:e,directory:n,tree:o=w(e)}){let s=[];for(let{link:t}of F(e,o)){if(!t)continue;let r=`line ${t.sourceCodeLocation?.startLine}`,a=z(t,"href")??"";Fe(a)?Oe.existsSync(Se.join(n,a))||s.push(`${r}: the file block's file ${a} is not in the document's folder`):s.push(`${r}: a file block's file (${a.slice(0,80)}): ${Le(a)} (<a class="doc-file-link" href="assets/<file>" download="<name>">)`),z(t,"download")||s.push(`${r}: a file block's link (${a.slice(0,80)}) says the name to save it as: download="<name>"`)}return[...new Set(s)]}import Ne from"node:fs";import De from"node:path";import{reportsDirectory as Re}from"../browser/shared/paths.mjs";import{assetProblem as W,imageFile as K}from"../browser/shared/media.mjs";import{attr as R,hasClass as Me,walk as M}from"../browser/shared/html-tree.mjs";var je={"doc-image":"image","doc-bookmark":"bookmark"},Te={image:"an image's picture",bookmark:"a bookmark's icon or cover"},Pe=/doc-(?:image|bookmark|link-mention-icon)/;function G(e){let n=[];return M(e,o=>{let s=o.tagName==="figure"&&(R(o,"class")??"").split(/\s+/).map(t=>je[t]).find(Boolean);s&&n.push({node:o,kind:s})}),n}function L(e,n=w(e)){let o=new Map,s=(t,r,a)=>{let i=t.sourceCodeLocation;i&&!o.has(i.startOffset)&&o.set(i.startOffset,{at:i.startOffset,line:i.startLine,node:t,what:r,kind:a,mention:a==="mention"})};for(let{node:t,kind:r}of G(n))M(t,a=>a.tagName==="img"&&s(a,Te[r],r));return M(n,t=>t.tagName==="img"&&Me(t,"doc-link-mention-icon")&&s(t,"a link's icon","mention")),[...o.values()].sort((t,r)=>t.at-r.at)}function Ut(e,{slug:n,mode:o="export",reportsDirectory:s=Re}){return Pe.test(e)?x(e,L(e).map(({node:t})=>t),{attribute:"src",route:"asset",slug:n,mode:o,reportsDirectory:s}):e}function At({html:e,directory:n,tree:o=w(e)}){let s=[];for(let{line:t,node:r,what:a,mention:i}of L(e,o)){let c=R(r,"src");i&&!K(c)?s.push(`line ${t}: a link's icon (${(c??"").slice(0,80)}): ${W(c,{picture:!0})}; or write an empty <span class="doc-link-mention-icon"></span>`):c===void 0?s.push(`line ${t}: ${a} has no src: <img src="assets/<file>" alt="\u2026">`):K(c)?Ne.existsSync(De.join(n,c))||s.push(`line ${t}: ${a} ${c} is not in the document's folder`):s.push(`line ${t}: ${a} (${c.slice(0,80)}): ${W(c,{picture:!0})}`)}for(let{node:t,kind:r}of G(o)){let a=r==="bookmark"?k(t,"a","doc-bookmark-card"):null,i=a&&R(a,"href");a&&!/^https?:\/\/[^\s"]+$/.test(i??"")&&s.push(`line ${a.sourceCodeLocation?.startLine}: a bookmark's link (${(i??"").slice(0,80)}) is a web address: <a class="doc-bookmark-card" href="https://\u2026">`)}return[...new Set(s)]}import ee from"node:fs";import te from"node:path";import{escapeAttribute as S}from"../browser/shared/escape.mjs";import{attr as y,hasClass as Be,walk as Ue}from"../browser/shared/html-tree.mjs";import{cssReferences as q}from"../browser/shared/css-references.mjs";import{assetFile as Ae,assetProblem as _e,imageFile as He,mediaUrl as Ie,referencedFile as v}from"../browser/shared/media.mjs";import{reportsDirectory as ze}from"../browser/shared/paths.mjs";import{documentDirectory as We}from"../browser/shared/workspace.mjs";var Y=/^\s*(?:\.\/)?assets\//i,J=1e6;function Ke(e){let n=[],o=0;for(;o<e.length;){for(;o<e.length&&/[\s,]/.test(e[o]);)o++;if(o>=e.length)break;let s=o;for(;s<e.length&&!/\s/.test(e[s]);)s++;let t=e.slice(o,s),r="";if(t.endsWith(","))t=t.replace(/,+$/,""),o=s;else{let i=s;for(let c=0;i<e.length&&(e[i]!==","||c>0);i++)e[i]==="("?c++:e[i]===")"&&c--;r=e.slice(s,i).trim(),o=i+1}let a=r.split(/\s+/).find(i=>/^\d*\.?\d+[wx]$/i.test(i));n.push({url:t,descriptor:r,size:a?parseFloat(a):1,wide:/w$/i.test(a??"")})}return n}function Ge(e){let n=e.filter(o=>o.wide);return(n.length>0?n:e).reduce((o,s)=>!o||s.size>o.size?s:o,null)}var qe=new Set(["body","table","thead","tbody","tfoot","tr","td","th"]);function T(e,n,o=s=>Y.test(s)){let s=[],t=r=>{o(r.value,r.node)&&s.push({...r,value:r.value.trim(),written:r.css?.written})};return Ue(n,r=>{let a=r.sourceCodeLocation;if(a){for(let{name:i,value:c,prefix:l}of r.attrs){let f=l?`${l}:${i}`:i,d=a.attrs?.[f],u={node:r,how:i,key:f,place:d,line:d?.startLine??a.startLine};if(i==="src"||i==="href"||i==="poster"||i==="data"&&r.tagName==="object"||i==="background"&&qe.has(r.tagName))t({...u,value:c});else if(i==="srcset"){let p=Ke(c),g=Ge(p.filter(b=>Y.test(b.url)));p.forEach((b,m)=>t({...u,value:b.url,candidates:p,index:m,largest:b===g}))}else if(i==="style")for(let p of q(c))t({...u,value:p.value,css:p})}if(r.tagName==="style")for(let i of r.childNodes){if(i.nodeName!=="#text"||!i.sourceCodeLocation)continue;let{startOffset:c,endOffset:l}=i.sourceCodeLocation;for(let f of q(e.slice(c,l)))t({node:r,how:"css",value:f.value,line:U(e,c+f.index),css:{...f,offset:c}})}}}),s}function se(e,n){let o=new Map;for(let{at:s,kind:t}of L(e,n))o.set(s,{attribute:"src",owner:"block",icon:t!=="image"});for(let{link:s}of F(e,n))s&&o.set(s.sourceCodeLocation.startOffset,{attribute:"href",owner:"block"});for(let s of I(e,n))o.set(s,{attribute:"src",owner:"block"});for(let s of A(e))o.set(s,{attribute:"src",owner:"icon"});return o}var oe=(e,n)=>{let o=e.get(n.node.sourceCodeLocation.startOffset);return o?.attribute===n.how?o:null},Ye=new Set(["img","input","video","audio","source","track"]),Q="an export holds no stylesheet of the folder (the addresses in one are read from its own place): put its rules in the page's <style>",V=e=>(y(e,"rel")??"").toLowerCase().split(/\s+/),j=/\.html?$/i,Je={html:'src="assets/<file>.html" sandbox="allow-scripts"',pdf:'src="assets/<file>.pdf"'},P=e=>`<figure class="doc-embed doc-embed--file"><iframe class="doc-embed-frame" ${Je[e]}></iframe><figcaption></figcaption></figure>`,X=`its frame with no sandbox (a sandboxed one shows no PDF): ${P("pdf")}`,Z='show a picture with <img src="assets/<file>">, a file to save with a link, <a href="assets/<file>" download="<name>">';function B({node:e,how:n,css:o,value:s}){let t=e.tagName;if(n==="style"||n==="css")return o.kind==="import"?{not:Q}:{use:"shown"};if(n==="srcset"&&(t==="img"||t==="source")||n==="poster"&&t==="video"||n==="src"&&Ye.has(t)||n==="background")return{use:"shown"};if(n==="src"&&t==="iframe"){let r=v(s)??"";return j.test(r)?{use:"frame"}:/\.pdf$/i.test(r)?{not:`a PDF shows in an embed block alone (the kit hands its file to the browser's PDF viewer, in the preview and in an export): make it one, ${X}`}:{not:`a frame shows a page of the folder (an HTML file), not this file, which the preview would hand out for saving: ${Z}`}}if(n==="href"&&(t==="a"||t==="area"))return{use:"link"};if(n==="href"&&(t==="image"||t==="link"&&V(e).some(r=>r.endsWith("icon"))))return{use:"shown"};if(t==="object"||t==="embed"){let r=v(s)??"";return{not:`an export's policy loads no plugin content (<object>, <embed>): ${/\.pdf$/i.test(r)?`show a PDF in an embed block, ${X}`:j.test(r)?`show a page in an embed block, ${P("html")}`:Z}`}}return t==="script"?{not:"an export runs the page's own scripts alone: put the code in the page's <script>"}:t==="link"&&V(e).includes("stylesheet")?{not:Q}:{not:"an export holds a file of the folder as a picture, a font, a video or audio, a link or a frame, not there"}}var E=e=>e.startsWith("assets/")&&Ae(e),Qe=e=>_e(e)??`the folder is assets/, in lowercase: write it so (assets/${e.slice(7)})`,ne=(e,n,o)=>n==="link"&&j.test(o)&&y(e.node,"download")===void 0,Ve=(e,n)=>e==="frame"?"embed":e==="shown"&&He(n)?"asset":"file",Xe=(e,n)=>!!ee.statSync(te.join(e,n),{throwIfNoEntry:!1})?.isFile(),O=({node:e,how:n,value:o,written:s})=>({srcset:`<${e.tagName} srcset="\u2026 ${o} \u2026">`,style:`${s} in the style of <${e.tagName}>`,css:`${s} in <style>`})[n]??`<${e.tagName} ${n}="${o}">`,Ze=e=>{for(let n=e.parentNode;n;n=n.parentNode)if(n.tagName&&Be(n,"doc-icon"))return!0;return!1},et=e=>e.length>1?`${e.slice(0,-1).join(", ")} and ${e.at(-1)}`:`${e[0]}`;function tt(e,n){let o=new Map;for(let{file:a,line:i,owned:c}of e){let l=o.get(a)??o.set(a,{lines:[],owned:!1}).get(a);c?l.owned=!0:l.lines.push(i)}let s=0,t=[];for(let[a,{lines:i,owned:c}]of o){let l=c?i.length:i.length-1;if(l<1)continue;let f=l*Math.ceil(ee.statSync(te.join(n,a)).size/3)*4;s+=f;let d=i.length===1?"once":i.length===2?"twice":`${i.length} times`;t.push({bytes:f,said:`${a} ${d}${c?" besides a media block's or the icon's":""} (line${new Set(i).size>1?"s":""} ${et([...new Set(i)])})`})}if(s<=J)return[];let r=t.sort((a,i)=>i.bytes-a.bytes).map(({said:a})=>a).join(", ");return[`files embedded more than once make an export ${s.toLocaleString("en-US")} bytes bigger, over the ${J.toLocaleString("en-US")} bytes the copies outside the media blocks may add: ${r}; show each fewer times (a picture, a link or a frame holds a copy of its own each time it is written), or, for a CSS background (url() in a <style> or a style attribute), name it once in the page's <style> (--picture: url(assets/<file>)) and write var(--picture) where it shows`]}function re({html:e,directory:n,tree:o}){let s=se(e,o),t=[],r=[],a=[];for(let i of T(e,o)){let{line:c}=i,l=oe(s,i),f=v(i.value),d=f!==null&&Xe(n,f);if(d&&!E(f)&&a.push({file:f,line:c}),l?.owner==="block"){d&&E(f)&&r.push({file:f,line:c,owned:!0,icon:!!l.icon});continue}if(d||t.push(l?`line ${c}: the icon's image ${i.value} is not in the document's folder`:`line ${c}: ${O(i)} names a file that is not in the document's folder`),l){d&&r.push({file:f,line:c,owned:!0,icon:!0});continue}let{use:u,not:p}=B(i);p&&t.push(`line ${c}: ${O(i)}: ${p}`),!(!u||!d)&&(E(f)?ne(i,u,f)?t.push(`line ${c}: ${O(i)} opens an HTML file, which an export cannot (a browser opens no page from a data: address): show it in an embed block, ${P("html")}, or give the link download="<name>" to hand it out as a file`):i.node.tagName==="img"&&i.how==="src"&&Ze(i.node)?t.push(`line ${c}: ${O(i)} is in an icon (.doc-icon) written as an icon is not read (its picker, the browser tab's icon): write it <div class="doc-icon"><img src="assets/<file>" alt=""></div>, in double quotes and with no other class`):(i.how!=="srcset"||i.largest)&&r.push({file:f,line:c}):t.push(`line ${c}: ${O(i)}: ${Qe(f)}`))}return{failures:t,embedded:r,unserved:a}}function ts({html:e,directory:n,tree:o=w(e)}){let{failures:s,embedded:t}=re({html:e,directory:n,tree:o});return[...new Set([...s,...tt(t,n)])]}function ss({html:e,directory:n,tree:o=w(e)}){let{embedded:s,unserved:t}=re({html:e,directory:n,tree:o});return{embedded:s.map(({file:r,line:a,icon:i=!1})=>({file:r,line:a,icon:i})),unserved:t}}function st(e,{slug:n,mode:o,directory:s}){let{use:t}=B(e),r=v(e.value);if(!t||!r||!E(r)||ne(e,t,r))return null;let a=/#.*$/.exec(e.value)?.[0]??"";if(o==="preview")return`${Ie(Ve(t,r),n,r)}${a}`;let i=N(s,r);return i&&`${i}${a}`}function ot(e,n,{mode:o,shown:s}){let[t]=n,{node:r,how:a,key:i}=t,c=(m,h="")=>({start:e.startOffset,end:e.endOffset,text:`${i}="${S(m)}"${h}`}),l=o==="preview"?` data-ge-${a}="${S(y(r,a)??"")}"`:"",d=(o==="preview"?[`data-ge-${a}`,`data-rs-${a}`].map(m=>r.sourceCodeLocation.attrs?.[m]).filter(Boolean):[]).map(m=>({start:m.startOffset,end:m.endOffset,text:""}));if(a==="srcset"){if(o==="export"){let h=n.find(C=>C.largest),$=h&&s(h);return $?[c(`${$} ${h.candidates[h.index].descriptor}`.trim())]:[]}let m=new Map(n.map(h=>[h.index,s(h)]));return[...m.values()].some(Boolean)?[c(t.candidates.map((h,$)=>[m.get($)??h.url,h.descriptor].filter(Boolean).join(" ")).join(", "),l),...d]:[]}if(a==="style"){let m=y(r,"style"),h=n.map($=>({...$.css,address:s($)})).filter($=>$.address).sort(($,C)=>C.start-$.start);for(let $ of h)m=`${m.slice(0,$.start)}${$.address}${m.slice($.end)}`;return h.length>0?[c(m)]:[]}let u=s(t);if(!u)return[];if(o==="preview"||B(t).use!=="link")return[c(u,l),...d];let p=v(t.value).slice(7),g=y(r,"download");if(g===void 0)return[c(u,` download="${S(p)}"`)];let b=r.sourceCodeLocation.attrs?.download;return[c(u),...g===""&&b?[{start:b.startOffset,end:b.endOffset,text:`download="${S(p)}"`}]:[]]}function nt(e,n){let o=[],s=0;for(let{start:t,end:r,text:a}of[...n].sort((i,c)=>i.start-c.start))t<s||(o.push(e.slice(s,t),a),s=r);return o.push(e.slice(s)),o.join("")}var os=(e,n,o=w(e))=>T(e,o,n);function ns(e,n){let o=[],s=new Map;for(let t of e){let r=n(t);typeof r=="string"&&(t.how==="css"?o.push({start:t.css.offset+t.css.start,end:t.css.offset+t.css.end,text:r}):t.place&&s.set(t.place,[...s.get(t.place)??[],{...t,address:r}]))}for(let[t,r]of s){let[{node:a,how:i,key:c,candidates:l}]=r,f=r[0].address;if(i==="srcset"){let d=new Map(r.map(u=>[u.index,u.address]));f=l.map((u,p)=>[d.get(p)??u.url,u.descriptor].filter(Boolean).join(" ")).join(", ")}else if(i==="style"){f=y(a,"style");for(let{css:d,address:u}of[...r].sort((p,g)=>g.css.start-p.css.start))f=`${f.slice(0,d.start)}${u}${f.slice(d.end)}`}o.push({start:t.startOffset,end:t.endOffset,text:`${c}="${S(f)}"`})}return o}function rs(e,{slug:n,mode:o="export",reportsDirectory:s=ze}){if(!/assets\//i.test(e.replace(/\sdata-ge-(?:src|href|icon)="[^"]*"/g,"")))return e;let t=w(e),r=se(e,t),a=We(n,s),i=f=>st(f,{slug:n,mode:o,directory:a}),c=[],l=new Map;for(let f of T(e,t))if(!oe(r,f))if(f.how==="css"){let d=i(f),u=f.css.offset;d&&c.push({start:u+f.css.start,end:u+f.css.end,text:d})}else f.place&&l.set(f.place,[...l.get(f.place)??[],f]);for(let[f,d]of l)c.push(...ot(f,d,{mode:o,shown:i}));return nt(e,c)}export{bt as a,gt as b,Et as c,Ct as d,Ut as e,At as f,ts as g,ss as h,nt as i,os as j,ns as k,rs as l};
2
+ import{f as A}from"./chunk-U5XL7D6A.mjs";import{a as w,c as U}from"./chunk-HYMEEXKN.mjs";import he from"node:fs";import $e from"node:path";import{reportsDirectory as we}from"../browser/shared/paths.mjs";import{assetFile as be,assetProblem as ge,embedFile as ke}from"../browser/shared/media.mjs";import{attr as H,hasClass as xe,walk as ye}from"../browser/shared/html-tree.mjs";import _ from"node:fs";import ie from"node:path";import{attr as ae,hasClass as ce,walk as fe}from"../browser/shared/html-tree.mjs";import{MEDIA_ROUTES as le,mediaTypeOf as de,mediaUrl as ue}from"../browser/shared/media.mjs";import{documentDirectory as pe}from"../browser/shared/workspace.mjs";function k(e,n,o){let s=null;return fe(e,t=>{!s&&t.tagName===n&&ce(t,o)&&(s=t)}),s}function N(e,n){let o=ie.join(e,n);return _.statSync(o,{throwIfNoEntry:!1})?.isFile()?`data:${de(n)};base64,${_.readFileSync(o).toString("base64")}`:null}function me(e,{attribute:n,route:o,slug:s,mode:t,reportsDirectory:r}){if(!le[o](e))return null;if(t==="preview")return`${n}="${ue(o,s,e)}" data-ge-${n}="${e}"`;let a=N(pe(s,r),e);return a&&`${n}="${a}"`}function x(e,n,{attribute:o,route:s,slug:t,mode:r,reportsDirectory:a}){let i=n.map(f=>({place:f.sourceCodeLocation?.attrs?.[o],value:ae(f,o)})).filter(({place:f})=>f).sort((f,d)=>f.place.startOffset-d.place.startOffset),c=[],l=0;for(let{place:f,value:d}of i){let u=me(d,{attribute:o,route:s,slug:t,mode:r,reportsDirectory:a});u===null||f.startOffset<l||(c.push(e.slice(l,f.startOffset),u),l=f.endOffset)}return c.push(e.slice(l)),c.join("")}function D(e){let n=[];return ye(e,o=>{let s=o.tagName==="figure"&&xe(o,"doc-embed")?k(o,"iframe","doc-embed-frame"):null;s&&n.push(s)}),n}function bt(e,{slug:n,mode:o="export",reportsDirectory:s=we}){return e.includes("doc-embed")?x(e,D(w(e)),{attribute:"src",route:"embed",slug:n,mode:o,reportsDirectory:s}):e}var I=(e,n=w(e))=>D(n).map(o=>o.sourceCodeLocation.startOffset);function gt({html:e,directory:n,tree:o=w(e)}){let s=[];for(let t of D(o)){let r=`line ${t.sourceCodeLocation.startLine}`,a=H(t,"src")??"",i=H(t,"sandbox"),c=/^https:\/\/[^\s"]+$/.test(a),l=!c&&!/^[a-z][a-z0-9+.-]*:/i.test(a)&&!be(a)?ge(a):null;l?s.push(`${r}: an embed's frame (${a.slice(0,80)}): ${l} (an HTML or PDF file; or a web page, https://\u2026)`):!c&&!ke(a)?s.push(`${r}: an embed's frame (${a.slice(0,80)}) shows a web page (https://\u2026, never http) or an HTML or PDF file of the document's folder (assets/<file>)`):!c&&!he.existsSync($e.join(n,a))?s.push(`${r}: the embed's file ${a} is not in the document's folder`):(c||/\.html?$/i.test(a))&&i===void 0?s.push(`${r}: an embed's frame (${a.slice(0,80)}) is sandboxed: sandbox="allow-scripts allow-popups \u2026"`):!c&&/\.html?$/i.test(a)&&/\ballow-same-origin\b/.test(i)?s.push(`${r}: an embedded HTML file (${a}) keeps its own origin: its sandbox has no allow-same-origin`):!c&&/\.pdf$/i.test(a)&&i!==void 0&&s.push(`${r}: an embedded PDF (${a}) is sandboxed, and a sandboxed frame shows no PDF: take its sandbox attribute off`)}return[...new Set(s)]}import Oe from"node:fs";import Se from"node:path";import{reportsDirectory as ve}from"../browser/shared/paths.mjs";import{assetFile as Fe,assetProblem as Le}from"../browser/shared/media.mjs";import{attr as z,hasClass as Ee,walk as Ce}from"../browser/shared/html-tree.mjs";function F(e,n=w(e)){let o=[];return Ce(n,s=>{s.tagName==="figure"&&Ee(s,"doc-file")&&o.push({node:s,link:k(s,"a","doc-file-link")})}),o}function Et(e,{slug:n,mode:o="export",reportsDirectory:s=ve}){if(!e.includes("doc-file"))return e;let t=F(e).flatMap(({link:r})=>r?[r]:[]);return x(e,t,{attribute:"href",route:"file",slug:n,mode:o,reportsDirectory:s})}function Ct({html:e,directory:n,tree:o=w(e)}){let s=[];for(let{link:t}of F(e,o)){if(!t)continue;let r=`line ${t.sourceCodeLocation?.startLine}`,a=z(t,"href")??"";Fe(a)?Oe.existsSync(Se.join(n,a))||s.push(`${r}: the file block's file ${a} is not in the document's folder`):s.push(`${r}: a file block's file (${a.slice(0,80)}): ${Le(a)} (<a class="doc-file-link" href="assets/<file>" download="<name>">)`),z(t,"download")||s.push(`${r}: a file block's link (${a.slice(0,80)}) says the name to save it as: download="<name>"`)}return[...new Set(s)]}import Ne from"node:fs";import De from"node:path";import{reportsDirectory as Re}from"../browser/shared/paths.mjs";import{assetProblem as W,imageFile as K}from"../browser/shared/media.mjs";import{attr as R,hasClass as Me,walk as M}from"../browser/shared/html-tree.mjs";var je={"doc-image":"image","doc-bookmark":"bookmark"},Te={image:"an image's picture",bookmark:"a bookmark's icon or cover"},Pe=/doc-(?:image|bookmark|link-mention-icon)/;function G(e){let n=[];return M(e,o=>{let s=o.tagName==="figure"&&(R(o,"class")??"").split(/\s+/).map(t=>je[t]).find(Boolean);s&&n.push({node:o,kind:s})}),n}function L(e,n=w(e)){let o=new Map,s=(t,r,a)=>{let i=t.sourceCodeLocation;i&&!o.has(i.startOffset)&&o.set(i.startOffset,{at:i.startOffset,line:i.startLine,node:t,what:r,kind:a,mention:a==="mention"})};for(let{node:t,kind:r}of G(n))M(t,a=>a.tagName==="img"&&s(a,Te[r],r));return M(n,t=>t.tagName==="img"&&Me(t,"doc-link-mention-icon")&&s(t,"a link's icon","mention")),[...o.values()].sort((t,r)=>t.at-r.at)}function Ut(e,{slug:n,mode:o="export",reportsDirectory:s=Re}){return Pe.test(e)?x(e,L(e).map(({node:t})=>t),{attribute:"src",route:"asset",slug:n,mode:o,reportsDirectory:s}):e}function At({html:e,directory:n,tree:o=w(e)}){let s=[];for(let{line:t,node:r,what:a,mention:i}of L(e,o)){let c=R(r,"src");i&&!K(c)?s.push(`line ${t}: a link's icon (${(c??"").slice(0,80)}): ${W(c,{picture:!0})}; or write an empty <span class="doc-link-mention-icon"></span>`):c===void 0?s.push(`line ${t}: ${a} has no src: <img src="assets/<file>" alt="\u2026">`):K(c)?Ne.existsSync(De.join(n,c))||s.push(`line ${t}: ${a} ${c} is not in the document's folder`):s.push(`line ${t}: ${a} (${c.slice(0,80)}): ${W(c,{picture:!0})}`)}for(let{node:t,kind:r}of G(o)){let a=r==="bookmark"?k(t,"a","doc-bookmark-card"):null,i=a&&R(a,"href");a&&!/^https?:\/\/[^\s"]+$/.test(i??"")&&s.push(`line ${a.sourceCodeLocation?.startLine}: a bookmark's link (${(i??"").slice(0,80)}) is a web address: <a class="doc-bookmark-card" href="https://\u2026">`)}return[...new Set(s)]}import ee from"node:fs";import te from"node:path";import{escapeAttribute as S}from"../browser/shared/escape.mjs";import{attr as y,hasClass as Be,walk as Ue}from"../browser/shared/html-tree.mjs";import{cssReferences as q}from"../browser/shared/css-references.mjs";import{assetFile as Ae,assetProblem as _e,imageFile as He,mediaUrl as Ie,referencedFile as v}from"../browser/shared/media.mjs";import{reportsDirectory as ze}from"../browser/shared/paths.mjs";import{documentDirectory as We}from"../browser/shared/workspace.mjs";var Y=/^\s*(?:\.\/)?assets\//i,J=1e6;function Ke(e){let n=[],o=0;for(;o<e.length;){for(;o<e.length&&/[\s,]/.test(e[o]);)o++;if(o>=e.length)break;let s=o;for(;s<e.length&&!/\s/.test(e[s]);)s++;let t=e.slice(o,s),r="";if(t.endsWith(","))t=t.replace(/,+$/,""),o=s;else{let i=s;for(let c=0;i<e.length&&(e[i]!==","||c>0);i++)e[i]==="("?c++:e[i]===")"&&c--;r=e.slice(s,i).trim(),o=i+1}let a=r.split(/\s+/).find(i=>/^\d*\.?\d+[wx]$/i.test(i));n.push({url:t,descriptor:r,size:a?parseFloat(a):1,wide:/w$/i.test(a??"")})}return n}function Ge(e){let n=e.filter(o=>o.wide);return(n.length>0?n:e).reduce((o,s)=>!o||s.size>o.size?s:o,null)}var qe=new Set(["body","table","thead","tbody","tfoot","tr","td","th"]);function T(e,n,o=s=>Y.test(s)){let s=[],t=r=>{o(r.value,r.node)&&s.push({...r,value:r.value.trim(),written:r.css?.written})};return Ue(n,r=>{let a=r.sourceCodeLocation;if(a){for(let{name:i,value:c,prefix:l}of r.attrs){let f=l?`${l}:${i}`:i,d=a.attrs?.[f],u={node:r,how:i,key:f,place:d,line:d?.startLine??a.startLine};if(i==="src"||i==="href"||i==="poster"||i==="data"&&r.tagName==="object"||i==="background"&&qe.has(r.tagName))t({...u,value:c});else if(i==="srcset"){let p=Ke(c),g=Ge(p.filter(b=>Y.test(b.url)));p.forEach((b,m)=>t({...u,value:b.url,candidates:p,index:m,largest:b===g}))}else if(i==="style")for(let p of q(c))t({...u,value:p.value,css:p})}if(r.tagName==="style")for(let i of r.childNodes){if(i.nodeName!=="#text"||!i.sourceCodeLocation)continue;let{startOffset:c,endOffset:l}=i.sourceCodeLocation;for(let f of q(e.slice(c,l)))t({node:r,how:"css",value:f.value,line:U(e,c+f.index),css:{...f,offset:c}})}}}),s}function se(e,n){let o=new Map;for(let{at:s,kind:t}of L(e,n))o.set(s,{attribute:"src",owner:"block",icon:t!=="image"});for(let{link:s}of F(e,n))s&&o.set(s.sourceCodeLocation.startOffset,{attribute:"href",owner:"block"});for(let s of I(e,n))o.set(s,{attribute:"src",owner:"block"});for(let s of A(e))o.set(s,{attribute:"src",owner:"icon"});return o}var oe=(e,n)=>{let o=e.get(n.node.sourceCodeLocation.startOffset);return o?.attribute===n.how?o:null},Ye=new Set(["img","input","video","audio","source","track"]),Q="an export holds no stylesheet of the folder (the addresses in one are read from its own place): put its rules in the page's <style>",V=e=>(y(e,"rel")??"").toLowerCase().split(/\s+/),j=/\.html?$/i,Je={html:'src="assets/<file>.html" sandbox="allow-scripts"',pdf:'src="assets/<file>.pdf"'},P=e=>`<figure class="doc-embed doc-embed--file"><iframe class="doc-embed-frame" ${Je[e]}></iframe><figcaption></figcaption></figure>`,X=`its frame with no sandbox (a sandboxed one shows no PDF): ${P("pdf")}`,Z='show a picture with <img src="assets/<file>">, a file to save with a link, <a href="assets/<file>" download="<name>">';function B({node:e,how:n,css:o,value:s}){let t=e.tagName;if(n==="style"||n==="css")return o.kind==="import"?{not:Q}:{use:"shown"};if(n==="srcset"&&(t==="img"||t==="source")||n==="poster"&&t==="video"||n==="src"&&Ye.has(t)||n==="background")return{use:"shown"};if(n==="src"&&t==="iframe"){let r=v(s)??"";return j.test(r)?{use:"frame"}:/\.pdf$/i.test(r)?{not:`a PDF shows in an embed block alone (the kit hands its file to the browser's PDF viewer, in the preview and in an export): make it one, ${X}`}:{not:`a frame shows a page of the folder (an HTML file), not this file, which the preview would hand out for saving: ${Z}`}}if(n==="href"&&(t==="a"||t==="area"))return{use:"link"};if(n==="href"&&(t==="image"||t==="link"&&V(e).some(r=>r.endsWith("icon"))))return{use:"shown"};if(t==="object"||t==="embed"){let r=v(s)??"";return{not:`an export's policy loads no plugin content (<object>, <embed>): ${/\.pdf$/i.test(r)?`show a PDF in an embed block, ${X}`:j.test(r)?`show a page in an embed block, ${P("html")}`:Z}`}}return t==="script"?{not:"an export runs the page's own scripts alone: put the code in the page's <script>"}:t==="link"&&V(e).includes("stylesheet")?{not:Q}:{not:"an export holds a file of the folder as a picture, a font, a video or audio, a link or a frame, not there"}}var E=e=>e.startsWith("assets/")&&Ae(e),Qe=e=>_e(e)??`the folder is assets/, in lowercase: write it so (assets/${e.slice(7)})`,ne=(e,n,o)=>n==="link"&&j.test(o)&&y(e.node,"download")===void 0,Ve=(e,n)=>e==="frame"?"embed":e==="shown"&&He(n)?"asset":"file",Xe=(e,n)=>!!ee.statSync(te.join(e,n),{throwIfNoEntry:!1})?.isFile(),O=({node:e,how:n,value:o,written:s})=>({srcset:`<${e.tagName} srcset="\u2026 ${o} \u2026">`,style:`${s} in the style of <${e.tagName}>`,css:`${s} in <style>`})[n]??`<${e.tagName} ${n}="${o}">`,Ze=e=>{for(let n=e.parentNode;n;n=n.parentNode)if(n.tagName&&Be(n,"doc-icon"))return!0;return!1},et=e=>e.length>1?`${e.slice(0,-1).join(", ")} and ${e.at(-1)}`:`${e[0]}`;function tt(e,n){let o=new Map;for(let{file:a,line:i,owned:c}of e){let l=o.get(a)??o.set(a,{lines:[],owned:!1}).get(a);c?l.owned=!0:l.lines.push(i)}let s=0,t=[];for(let[a,{lines:i,owned:c}]of o){let l=c?i.length:i.length-1;if(l<1)continue;let f=l*Math.ceil(ee.statSync(te.join(n,a)).size/3)*4;s+=f;let d=i.length===1?"once":i.length===2?"twice":`${i.length} times`;t.push({bytes:f,said:`${a} ${d}${c?" besides a media block's or the icon's":""} (line${new Set(i).size>1?"s":""} ${et([...new Set(i)])})`})}if(s<=J)return[];let r=t.sort((a,i)=>i.bytes-a.bytes).map(({said:a})=>a).join(", ");return[`files embedded more than once make an export ${s.toLocaleString("en-US")} bytes bigger, over the ${J.toLocaleString("en-US")} bytes the copies outside the media blocks may add: ${r}; show each fewer times (a picture, a link or a frame holds a copy of its own each time it is written), or, for a CSS background (url() in a <style> or a style attribute), name it once in the page's <style> (--picture: url(assets/<file>)) and write var(--picture) where it shows`]}function re({html:e,directory:n,tree:o}){let s=se(e,o),t=[],r=[],a=[];for(let i of T(e,o)){let{line:c}=i,l=oe(s,i),f=v(i.value),d=f!==null&&Xe(n,f);if(d&&!E(f)&&a.push({file:f,line:c}),l?.owner==="block"){d&&E(f)&&r.push({file:f,line:c,owned:!0,icon:!!l.icon});continue}if(d||t.push(l?`line ${c}: the icon's image ${i.value} is not in the document's folder`:`line ${c}: ${O(i)} names a file that is not in the document's folder`),l){d&&r.push({file:f,line:c,owned:!0,icon:!0});continue}let{use:u,not:p}=B(i);p&&t.push(`line ${c}: ${O(i)}: ${p}`),!(!u||!d)&&(E(f)?ne(i,u,f)?t.push(`line ${c}: ${O(i)} opens an HTML file, which an export cannot (a browser opens no page from a data: address): show it in an embed block, ${P("html")}, or give the link download="<name>" to hand it out as a file`):i.node.tagName==="img"&&i.how==="src"&&Ze(i.node)?t.push(`line ${c}: ${O(i)} is in an icon (.doc-icon) written as an icon is not read (its picker, the browser tab's icon): write it <div class="doc-icon"><img src="assets/<file>" alt=""></div>, in double quotes and with no other class`):(i.how!=="srcset"||i.largest)&&r.push({file:f,line:c}):t.push(`line ${c}: ${O(i)}: ${Qe(f)}`))}return{failures:t,embedded:r,unserved:a}}function ts({html:e,directory:n,tree:o=w(e)}){let{failures:s,embedded:t}=re({html:e,directory:n,tree:o});return[...new Set([...s,...tt(t,n)])]}function ss({html:e,directory:n,tree:o=w(e)}){let{embedded:s,unserved:t}=re({html:e,directory:n,tree:o});return{embedded:s.map(({file:r,line:a,icon:i=!1})=>({file:r,line:a,icon:i})),unserved:t}}function st(e,{slug:n,mode:o,directory:s}){let{use:t}=B(e),r=v(e.value);if(!t||!r||!E(r)||ne(e,t,r))return null;let a=/#.*$/.exec(e.value)?.[0]??"";if(o==="preview")return`${Ie(Ve(t,r),n,r)}${a}`;let i=N(s,r);return i&&`${i}${a}`}function ot(e,n,{mode:o,shown:s}){let[t]=n,{node:r,how:a,key:i}=t,c=(m,h="")=>({start:e.startOffset,end:e.endOffset,text:`${i}="${S(m)}"${h}`}),l=o==="preview"?` data-ge-${a}="${S(y(r,a)??"")}"`:"",d=(o==="preview"?[`data-ge-${a}`,`data-rs-${a}`].map(m=>r.sourceCodeLocation.attrs?.[m]).filter(Boolean):[]).map(m=>({start:m.startOffset,end:m.endOffset,text:""}));if(a==="srcset"){if(o==="export"){let h=n.find(C=>C.largest),$=h&&s(h);return $?[c(`${$} ${h.candidates[h.index].descriptor}`.trim())]:[]}let m=new Map(n.map(h=>[h.index,s(h)]));return[...m.values()].some(Boolean)?[c(t.candidates.map((h,$)=>[m.get($)??h.url,h.descriptor].filter(Boolean).join(" ")).join(", "),l),...d]:[]}if(a==="style"){let m=y(r,"style"),h=n.map($=>({...$.css,address:s($)})).filter($=>$.address).sort(($,C)=>C.start-$.start);for(let $ of h)m=`${m.slice(0,$.start)}${$.address}${m.slice($.end)}`;return h.length>0?[c(m)]:[]}let u=s(t);if(!u)return[];if(o==="preview"||B(t).use!=="link")return[c(u,l),...d];let p=v(t.value).slice(7),g=y(r,"download");if(g===void 0)return[c(u,` download="${S(p)}"`)];let b=r.sourceCodeLocation.attrs?.download;return[c(u),...g===""&&b?[{start:b.startOffset,end:b.endOffset,text:`download="${S(p)}"`}]:[]]}function nt(e,n){let o=[],s=0;for(let{start:t,end:r,text:a}of[...n].sort((i,c)=>i.start-c.start))t<s||(o.push(e.slice(s,t),a),s=r);return o.push(e.slice(s)),o.join("")}var os=(e,n,o=w(e))=>T(e,o,n);function ns(e,n){let o=[],s=new Map;for(let t of e){let r=n(t);typeof r=="string"&&(t.how==="css"?o.push({start:t.css.offset+t.css.start,end:t.css.offset+t.css.end,text:r}):t.place&&s.set(t.place,[...s.get(t.place)??[],{...t,address:r}]))}for(let[t,r]of s){let[{node:a,how:i,key:c,candidates:l}]=r,f=r[0].address;if(i==="srcset"){let d=new Map(r.map(u=>[u.index,u.address]));f=l.map((u,p)=>[d.get(p)??u.url,u.descriptor].filter(Boolean).join(" ")).join(", ")}else if(i==="style"){f=y(a,"style");for(let{css:d,address:u}of[...r].sort((p,g)=>g.css.start-p.css.start))f=`${f.slice(0,d.start)}${u}${f.slice(d.end)}`}o.push({start:t.startOffset,end:t.endOffset,text:`${c}="${S(f)}"`})}return o}function rs(e,{slug:n,mode:o="export",reportsDirectory:s=ze}){if(!/assets\//i.test(e.replace(/\sdata-ge-(?:src|href|icon)="[^"]*"/g,"")))return e;let t=w(e),r=se(e,t),a=We(n,s),i=f=>st(f,{slug:n,mode:o,directory:a}),c=[],l=new Map;for(let f of T(e,t))if(!oe(r,f))if(f.how==="css"){let d=i(f),u=f.css.offset;d&&c.push({start:u+f.css.start,end:u+f.css.end,text:d})}else f.place&&l.set(f.place,[...l.get(f.place)??[],f]);for(let[f,d]of l)c.push(...ot(f,d,{mode:o,shown:i}));return nt(e,c)}export{bt as a,gt as b,Et as c,Ct as d,Ut as e,At as f,ts as g,ss as h,nt as i,os as j,ns as k,rs as l};