@jxsuite/studio 3.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/{2020-xp8vnwma.js → 2020-n6tfwnda.js} +2 -2
  3. package/dist/chunks/Overlay.dev-etqjwyf9.js +23 -0
  4. package/dist/chunks/cf-account-picker-en86v7x7.js +163 -0
  5. package/dist/chunks/{cf-settings-zj2cj1ar.js → cf-settings-45fgyx8y.js} +6 -5
  6. package/dist/chunks/{components-z6cnkyy1.js → components-zmx10t62.js} +6 -5
  7. package/dist/chunks/content-source-48xg86wj.js +49 -0
  8. package/dist/chunks/{convert-to-repeater-6vvx96n2.js → convert-to-repeater-43tfn7cs.js} +33 -25
  9. package/dist/chunks/entry-commands-e63f1xc0.js +46 -0
  10. package/dist/chunks/{extension-sections-kwzvpemr.js → extension-sections-txv08xxg.js} +34 -26
  11. package/dist/chunks/file-ops-wbh4hhsx.js +48 -0
  12. package/dist/chunks/files-3kfkwhk4.js +93 -0
  13. package/dist/chunks/{focus-trap.esm-ggawf1hy.js → focus-trap.esm-9t2drp0g.js} +6 -5
  14. package/dist/chunks/{format-host-8fr3545e.js → format-host-w16q81tf.js} +3 -3
  15. package/dist/chunks/fs-events-hrrg328g.js +21 -0
  16. package/dist/chunks/{git-panel-g01d93vc.js → git-panel-532whr1y.js} +22 -16
  17. package/dist/chunks/{index-nj44jpzj.js → index-wcnt3r9g.js} +2 -2
  18. package/dist/chunks/{jx-validate-jj9rnt4n.js → jx-validate-8er6gbxy.js} +6 -4
  19. package/dist/chunks/layers-panel-07hm7g5j.js +67 -0
  20. package/dist/chunks/layers-q75tj2mf.js +45 -0
  21. package/dist/chunks/lit-html-j055mkh8.js +22 -0
  22. package/dist/chunks/monaco-buffer-dqw0xxpx.js +25 -0
  23. package/dist/chunks/{monaco-setup-a5wkmbgh.js → monaco-setup-vx9bhp1d.js} +4 -4
  24. package/dist/chunks/notify-yjm79n4s.js +30 -0
  25. package/dist/chunks/parse-24d0gay3.js +19 -0
  26. package/dist/chunks/platform-ba1j1gbh.js +16 -0
  27. package/dist/chunks/publish-panel-v9st96ja.js +29 -0
  28. package/dist/chunks/quick-search-zccjp6gv.js +66 -0
  29. package/dist/chunks/references-3qx8fkyp.js +29 -0
  30. package/dist/chunks/right-panel-vm3b6kwy.js +46 -0
  31. package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +18 -0
  32. package/dist/chunks/sp-popover.dev-n2etmqdp.js +9 -0
  33. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +15 -0
  34. package/dist/chunks/sp-tooltip.dev-4sastdnw.js +15 -0
  35. package/dist/chunks/{sp-tray.dev-64v4pxw8.js → sp-tray.dev-tkbscm06.js} +5 -5
  36. package/dist/chunks/{studio-wdt9y92a.js → studio-0bq6eh7v.js} +2 -2
  37. package/dist/chunks/studio-1ngbejft.js +181 -0
  38. package/dist/chunks/studio-1wagb550.js +118 -0
  39. package/dist/chunks/{studio-j595e748.js → studio-2b946z26.js} +172 -95
  40. package/dist/chunks/{studio-pkp61mh8.js → studio-3bqpr0zh.js} +25 -17
  41. package/dist/chunks/{studio-k4jvjcfx.js → studio-4b5z1x43.js} +46 -12
  42. package/dist/chunks/{studio-ry1vz5sv.js → studio-4n2b5gzb.js} +15 -13
  43. package/dist/chunks/{studio-p5dja96s.js → studio-4r1pv6zf.js} +2 -2
  44. package/dist/chunks/{studio-kvfx9z2c.js → studio-4rzyrtjz.js} +70 -31
  45. package/dist/chunks/{studio-tzx3xmvx.js → studio-5fx3g9jg.js} +33 -52
  46. package/dist/chunks/{studio-rh1cnamv.js → studio-5myknm0a.js} +565 -135
  47. package/dist/chunks/studio-6yw4y3my.js +91 -0
  48. package/dist/chunks/{studio-0rqqhrdy.js → studio-7nte2hj4.js} +2 -2
  49. package/dist/chunks/studio-92ab2jqe.js +282 -0
  50. package/dist/chunks/{studio-6z5eyjwn.js → studio-950k0dx6.js} +72 -135
  51. package/dist/chunks/{studio-sas7mt3k.js → studio-9ab8gqsm.js} +2 -2
  52. package/dist/chunks/studio-9n4mrmnb.js +184 -0
  53. package/dist/chunks/{studio-hcxzyk3x.js → studio-ahn3pdgx.js} +6 -6
  54. package/dist/chunks/studio-b55y6ewx.js +498 -0
  55. package/dist/chunks/{studio-s519zc99.js → studio-bgxt93ga.js} +3 -3
  56. package/dist/chunks/studio-cft9r4r7.js +119 -0
  57. package/dist/chunks/{studio-dc8s8heb.js → studio-cmb03bg5.js} +6904 -8321
  58. package/dist/chunks/studio-dm19q43r.js +195 -0
  59. package/dist/chunks/{studio-2x9zbxmx.js → studio-ef49pnzx.js} +11 -9
  60. package/dist/chunks/{studio-ay8wcr2b.js → studio-eqq1w638.js} +7 -9
  61. package/dist/chunks/{studio-5efrtn1m.js → studio-ew0djmhg.js} +23 -19
  62. package/dist/chunks/{studio-tr20m8g8.js → studio-f3wqjtk5.js} +39 -3
  63. package/dist/chunks/{studio-xntfdy1x.js → studio-fbf92ckf.js} +36 -23
  64. package/dist/chunks/{studio-4q0wznzf.js → studio-gcye7qka.js} +442 -126
  65. package/dist/chunks/{studio-7p35254k.js → studio-gfgb8pe6.js} +36 -193
  66. package/dist/chunks/studio-jc994dnr.js +1066 -0
  67. package/dist/chunks/{studio-hj2se583.js → studio-jkftxyvz.js} +69 -3423
  68. package/dist/chunks/{studio-5x5774ak.js → studio-kryvsw6j.js} +3 -3
  69. package/dist/chunks/{studio-kfpek536.js → studio-kyh9avvv.js} +2 -2
  70. package/dist/chunks/{studio-twsafr1e.js → studio-m3hwn7y1.js} +3 -3
  71. package/dist/chunks/studio-msd847zn.js +1315 -0
  72. package/dist/chunks/{studio-g5gdqnyd.js → studio-mtfnaqs9.js} +19 -19
  73. package/dist/chunks/{studio-7ejemhej.js → studio-n6j9t10q.js} +6 -6
  74. package/dist/chunks/{studio-vhk5fmfv.js → studio-n8b9wqwy.js} +5 -5
  75. package/dist/chunks/{studio-cjm7fdjf.js → studio-p4ngc046.js} +8 -104
  76. package/dist/chunks/studio-q43a5y9h.js +394 -0
  77. package/dist/chunks/studio-q7v10cg2.js +106 -0
  78. package/dist/chunks/{studio-6kv3apa9.js → studio-q9jd1a60.js} +27 -11
  79. package/dist/chunks/studio-qcy05dp8.js +1743 -0
  80. package/dist/chunks/{studio-a0yp7syn.js → studio-qjy2z9bv.js} +29 -132
  81. package/dist/chunks/{studio-2w11grav.js → studio-qq6jym04.js} +3 -3
  82. package/dist/chunks/{studio-3fk1ac9z.js → studio-rdx8jcxy.js} +4 -4
  83. package/dist/chunks/{studio-4mqb9a0j.js → studio-rn9ta2mz.js} +4 -4
  84. package/dist/chunks/studio-t7qb9db8.js +665 -0
  85. package/dist/chunks/studio-tmc5emrw.js +8 -0
  86. package/dist/chunks/{studio-r5xbtctf.js → studio-trxrabqf.js} +292 -2297
  87. package/dist/chunks/studio-wcy8trfx.js +263 -0
  88. package/dist/chunks/{studio-3dkcd4c5.js → studio-x4qkdat5.js} +62 -57
  89. package/dist/chunks/studio-x813zp48.js +195 -0
  90. package/dist/chunks/{studio-qpfq7xhm.js → studio-xrapxwwc.js} +22 -285
  91. package/dist/chunks/{studio-xm3dbxvn.js → studio-zczps70q.js} +2 -2
  92. package/dist/chunks/{studio-8ezdegcx.js → studio-zqazsct2.js} +40 -36
  93. package/dist/chunks/workspace-fjx52ryv.js +89 -0
  94. package/dist/iframe-entry.js +141 -56
  95. package/dist/manifest.json +7 -0
  96. package/dist/studio.js +2605 -1950
  97. package/favicon.ico +0 -0
  98. package/index.html +1 -0
  99. package/package.json +20 -18
  100. package/src/about/about-modal.ts +4 -3
  101. package/src/browse/library-pane.ts +57 -3
  102. package/src/canvas/canvas-render.ts +23 -1
  103. package/src/canvas/iframe-patch.ts +47 -21
  104. package/src/canvas/iframe-render.ts +22 -6
  105. package/src/commands/app-commands.ts +4 -0
  106. package/src/commands/command-args.ts +29 -0
  107. package/src/commands/context.ts +15 -1
  108. package/src/commands/defaults.ts +29 -1
  109. package/src/commands/levels.ts +16 -0
  110. package/src/commands/live-context.ts +3 -0
  111. package/src/content/collection-match.ts +267 -0
  112. package/src/content/entry-commands.ts +38 -29
  113. package/src/content/entry-fields.ts +6 -0
  114. package/src/editor/shortcuts.ts +5 -0
  115. package/src/files/file-ops.ts +10 -42
  116. package/src/files/files.ts +487 -59
  117. package/src/files/fs-events.ts +9 -0
  118. package/src/files/gitignore.ts +432 -0
  119. package/src/files/media-paths.ts +13 -42
  120. package/src/files/media-usage.ts +41 -131
  121. package/src/files/serialize-document.ts +60 -0
  122. package/src/format/convert-file.ts +511 -0
  123. package/src/format/format-choices.ts +199 -0
  124. package/src/grid/grid-view.ts +16 -2
  125. package/src/hosting/document.ts +2 -0
  126. package/src/hosting/layout.ts +8 -0
  127. package/src/media/media-open.ts +58 -0
  128. package/src/media/media-pane.ts +310 -0
  129. package/src/new-project/import-tab.ts +357 -163
  130. package/src/new-project/location-fields.ts +8 -5
  131. package/src/new-project/new-project-modal.ts +27 -34
  132. package/src/packages/ensure-deps.ts +14 -7
  133. package/src/packages/jxsuite-update.ts +11 -11
  134. package/src/page-params.ts +10 -46
  135. package/src/panels/activity-bar.ts +45 -16
  136. package/src/panels/ai-chat/attached-context.ts +6 -1
  137. package/src/panels/ai-chat/chat-view.ts +255 -13
  138. package/src/panels/ai-chat/composer.ts +31 -97
  139. package/src/panels/ai-panel.ts +116 -2
  140. package/src/panels/navigator-panels.ts +7 -6
  141. package/src/panels/settings-menu.ts +799 -0
  142. package/src/panels/toolbar.ts +135 -15
  143. package/src/platforms/cloud.ts +261 -70
  144. package/src/platforms/devserver.ts +67 -33
  145. package/src/preview/preview-overlay.ts +226 -0
  146. package/src/publish/publish-panel.ts +62 -2
  147. package/src/services/ai-ask.ts +247 -0
  148. package/src/services/ai-import-tools.ts +532 -0
  149. package/src/services/ai-models.ts +108 -1
  150. package/src/services/ai-project-tools.ts +20 -26
  151. package/src/services/ai-system-prompt.ts +88 -2
  152. package/src/services/ai-turn-signal.ts +70 -0
  153. package/src/services/connection.ts +74 -0
  154. package/src/services/context-manager.ts +101 -1
  155. package/src/services/document-assistant.ts +45 -4
  156. package/src/services/import-client.ts +33 -6
  157. package/src/services/import-run.ts +158 -0
  158. package/src/services/import-seed.ts +120 -0
  159. package/src/services/jx-validate.ts +58 -6
  160. package/src/services/project-adoption.ts +71 -0
  161. package/src/services/references.ts +0 -0
  162. package/src/services/settings/definitions.ts +17 -0
  163. package/src/services/tool-executor.ts +45 -2
  164. package/src/settings/contexts-section.ts +45 -3
  165. package/src/settings/dependencies-editor.ts +43 -23
  166. package/src/settings/general-settings.ts +30 -12
  167. package/src/settings/preferences-accounts.ts +193 -12
  168. package/src/settings/preferences-dialog.ts +93 -59
  169. package/src/settings/preferences-sections.ts +57 -0
  170. package/src/settings/settings-document.ts +65 -9
  171. package/src/studio.ts +33 -6
  172. package/src/tabs/transact.ts +42 -19
  173. package/src/types.ts +129 -7
  174. package/src/ui/ai-managed-connect.ts +62 -13
  175. package/src/ui/ai-model-picker.ts +189 -0
  176. package/src/ui/cf-account-picker.ts +200 -0
  177. package/src/ui/choice-field.ts +72 -0
  178. package/src/ui/layers.ts +83 -5
  179. package/src/utils/studio-utils.ts +22 -52
  180. package/styles/forced-colors.css +7 -0
  181. package/styles/overlays.css +256 -0
  182. package/styles/panels.css +13 -1
  183. package/styles/shell.css +147 -0
  184. package/dist/chunks/Overlay.dev-d2ajy6sj.js +0 -23
  185. package/dist/chunks/content-source-7fy9qrm0.js +0 -40
  186. package/dist/chunks/files-xcybanxe.js +0 -70
  187. package/dist/chunks/layers-panel-27essgkc.js +0 -60
  188. package/dist/chunks/publish-panel-09sy2bab.js +0 -22
  189. package/dist/chunks/quick-search-sefb61v8.js +0 -55
  190. package/dist/chunks/right-panel-9r32jd5j.js +0 -39
  191. package/dist/chunks/sp-overlay.dev-s18hymn9.js +0 -18
  192. package/dist/chunks/sp-popover.dev-dj9x7e7a.js +0 -9
  193. package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +0 -15
  194. package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +0 -15
  195. package/dist/chunks/studio-bw5dz6km.js +0 -608
  196. package/dist/chunks/studio-c31yb4t6.js +0 -55
  197. package/src/canvas/site-style-css.ts +0 -117
@@ -0,0 +1,498 @@
1
+ import {
2
+ columnsFromSchema,
3
+ getGridController,
4
+ inferColumnsFromRows,
5
+ makeGridTabId,
6
+ parseSourceForPath
7
+ } from "./studio-cmb03bg5.js";
8
+ import {
9
+ isRecentLocal,
10
+ markLocalMutation
11
+ } from "./studio-q43a5y9h.js";
12
+ import {
13
+ workspace
14
+ } from "./studio-trxrabqf.js";
15
+ import {
16
+ projectState
17
+ } from "./studio-p4ngc046.js";
18
+ import {
19
+ reactive
20
+ } from "./studio-xrapxwwc.js";
21
+ import {
22
+ defaultContentFormat,
23
+ documentExtensions,
24
+ formatByName,
25
+ formatForPath,
26
+ formatSerialize,
27
+ loadFormats
28
+ } from "./studio-ahn3pdgx.js";
29
+ import {
30
+ getPlatform
31
+ } from "./studio-9ab8gqsm.js";
32
+ import {
33
+ __require
34
+ } from "./studio-a0tswy0w.js";
35
+
36
+ // src/content/draft-state.ts
37
+ var DRAFT_FIELD = "draft";
38
+ var DRAFT_MEANING = "Marked a draft. Studio filters drafts out of its own lists; the build does not exclude them yet.";
39
+ function isDraftEntry(fields) {
40
+ return fields?.[DRAFT_FIELD] === true;
41
+ }
42
+ function schemaDeclaresDraft(schema) {
43
+ return schema?.properties?.[DRAFT_FIELD]?.type === "boolean";
44
+ }
45
+ function hasDraftAxis(schema, fields) {
46
+ return schemaDeclaresDraft(schema) || isDraftEntry(fields);
47
+ }
48
+ var draftView = reactive({ includeDrafts: false });
49
+ function includingDrafts() {
50
+ return draftView.includeDrafts;
51
+ }
52
+ function setIncludeDrafts(include) {
53
+ draftView.includeDrafts = include;
54
+ }
55
+ function applyDraftFilter(items, fieldsOf, includeDrafts) {
56
+ return includeDrafts ? items : items.filter((item) => !isDraftEntry(fieldsOf(item)));
57
+ }
58
+
59
+ // src/grid/sources/content-source.ts
60
+ var PATH_FIELD = "__path";
61
+ function collectionInfo(typeName) {
62
+ const content = projectState?.projectConfig?.content ?? {};
63
+ const def = content[typeName];
64
+ if (!def?.source) {
65
+ return null;
66
+ }
67
+ const dir = def.source.replace(/^\.\//, "").replace(/\/$/, "");
68
+ const ext = def.format === "json" ? ".json" : formatByName(def.format)?.extensions[0] ?? defaultContentFormat()?.extensions[0] ?? ".json";
69
+ return { def, dir, ext, name: typeName };
70
+ }
71
+ function collectionDirs() {
72
+ const content = projectState?.projectConfig?.content ?? {};
73
+ return Object.entries(content).filter(([, def]) => {
74
+ const source = def.source?.replace(/^\.\//, "") ?? "";
75
+ return source !== "" && !/\.[a-z0-9]+$/i.test(source);
76
+ }).map(([name, def]) => ({ dir: def.source.replace(/^\.\//, "").replace(/\/$/, ""), name }));
77
+ }
78
+ async function listEntryFiles(dir, exts) {
79
+ const platform = getPlatform();
80
+ const results = [];
81
+ const walk = async (current) => {
82
+ let children;
83
+ try {
84
+ children = await platform.listDirectory(current);
85
+ } catch {
86
+ return;
87
+ }
88
+ for (const entry of children) {
89
+ if (entry.type === "directory") {
90
+ await walk(entry.path);
91
+ } else if (exts.some((ext) => entry.path.endsWith(ext))) {
92
+ results.push(entry.path);
93
+ }
94
+ }
95
+ };
96
+ await walk(dir);
97
+ return results.toSorted();
98
+ }
99
+ async function listCollectionEntryIds(typeName) {
100
+ await loadFormats().catch(() => {});
101
+ const info = collectionInfo(typeName);
102
+ if (!info) {
103
+ return [];
104
+ }
105
+ const files = await listEntryFiles(info.dir, [info.ext]);
106
+ return files.map((path) => {
107
+ const base = path.split("/").pop() ?? path;
108
+ return base.slice(0, base.length - info.ext.length);
109
+ });
110
+ }
111
+ async function mapLimit(items, limit, fn) {
112
+ const results = Array.from({ length: items.length });
113
+ let next = 0;
114
+ const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
115
+ while (next < items.length) {
116
+ const index = next;
117
+ next += 1;
118
+ results[index] = await fn(items[index]);
119
+ }
120
+ });
121
+ await Promise.all(workers);
122
+ return results;
123
+ }
124
+ function toCellValue(value) {
125
+ if (value === null || value === undefined) {
126
+ return null;
127
+ }
128
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
129
+ return value;
130
+ }
131
+ if (Array.isArray(value) && value.every((v) => typeof v !== "object" || v === null)) {
132
+ return value.map(String);
133
+ }
134
+ return JSON.stringify(value);
135
+ }
136
+ function openTabFor(path) {
137
+ for (const tab of workspace.tabs.values()) {
138
+ if (tab.documentPath === path) {
139
+ return tab;
140
+ }
141
+ }
142
+ return null;
143
+ }
144
+ function extraRowsAreStrings(rows, field) {
145
+ return rows.every((row) => {
146
+ const value = row[field];
147
+ return value === null || value === undefined || typeof value !== "string" ? true : !value.startsWith("{") && !value.startsWith("[");
148
+ });
149
+ }
150
+ var draftAwareSources = new WeakSet;
151
+ async function reloadDraftAwareGrids() {
152
+ const reloads = [];
153
+ for (const tab of workspace.tabs.values()) {
154
+ const controller = getGridController(tab);
155
+ if (controller && draftAwareSources.has(controller.source)) {
156
+ reloads.push(controller.load());
157
+ }
158
+ }
159
+ await Promise.all(reloads);
160
+ }
161
+ function createEntryFileSource(opts) {
162
+ const source = buildEntryFileSource(opts);
163
+ if (opts.drafts) {
164
+ draftAwareSources.add(source);
165
+ }
166
+ return source;
167
+ }
168
+ function buildEntryFileSource(opts) {
169
+ const entries = new Map;
170
+ let loadPromise = null;
171
+ let columnsCache = null;
172
+ const load = (force = false) => {
173
+ if (!force && loadPromise) {
174
+ return loadPromise;
175
+ }
176
+ loadPromise = (async () => {
177
+ await loadFormats().catch(() => {});
178
+ const platform = getPlatform();
179
+ const files = await opts.list();
180
+ entries.clear();
181
+ columnsCache = null;
182
+ const loaded = await mapLimit(files, 8, async (path) => {
183
+ try {
184
+ const text = await platform.readFile(path);
185
+ const parsed = await parseSourceForPath(path, text);
186
+ return {
187
+ document: parsed.document,
188
+ formatName: parsed.format.name,
189
+ frontmatter: parsed.frontmatter ?? {},
190
+ rawText: text
191
+ };
192
+ } catch {
193
+ return null;
194
+ }
195
+ });
196
+ for (const [index, path] of files.entries()) {
197
+ const record = loaded[index];
198
+ if (record) {
199
+ entries.set(path, record);
200
+ }
201
+ }
202
+ })();
203
+ return loadPromise;
204
+ };
205
+ const buildColumns = () => {
206
+ if (columnsCache) {
207
+ return columnsCache;
208
+ }
209
+ const pathColumn = {
210
+ editable: false,
211
+ field: PATH_FIELD,
212
+ insertOnly: true,
213
+ kind: "string",
214
+ pk: true,
215
+ required: true,
216
+ title: "Path",
217
+ widthHint: 220
218
+ };
219
+ const schemaColumns = columnsFromSchema(opts.schema());
220
+ const known = new Set([PATH_FIELD, ...schemaColumns.map((c) => c.field)]);
221
+ const extraRows = [...entries.values()].map((entry) => {
222
+ const cells = {};
223
+ for (const [key, value] of Object.entries(entry.frontmatter)) {
224
+ if (!known.has(key) && !key.startsWith("$")) {
225
+ cells[key] = toCellValue(value);
226
+ }
227
+ }
228
+ return cells;
229
+ });
230
+ const extraColumns = inferColumnsFromRows(extraRows);
231
+ for (const column of extraColumns) {
232
+ column.editable = column.kind !== "text" || extraRowsAreStrings(extraRows, column.field);
233
+ }
234
+ if (opts.priorityFields?.length) {
235
+ const rank = (c) => {
236
+ const index = opts.priorityFields.indexOf(c.field);
237
+ return index === -1 ? opts.priorityFields.length : index;
238
+ };
239
+ extraColumns.sort((a, b) => rank(a) - rank(b));
240
+ }
241
+ columnsCache = withDraftColumn([pathColumn, ...schemaColumns, ...extraColumns]);
242
+ return columnsCache;
243
+ };
244
+ const draftAxis = () => {
245
+ if (!opts.drafts) {
246
+ return false;
247
+ }
248
+ const schema = opts.schema();
249
+ return hasDraftAxis(schema) || [...entries.values()].some((entry) => hasDraftAxis(schema, entry.frontmatter));
250
+ };
251
+ const withDraftColumn = (columns) => {
252
+ const index = columns.findIndex((column) => column.field === DRAFT_FIELD);
253
+ if (index < 1 || !draftAxis()) {
254
+ return columns;
255
+ }
256
+ const rest = columns.filter((column) => column.field !== DRAFT_FIELD);
257
+ return [rest[0], columns[index], ...rest.slice(1)];
258
+ };
259
+ const rowFor = (path, entry) => {
260
+ const cells = { [PATH_FIELD]: path };
261
+ for (const column of buildColumns()) {
262
+ if (column.field === PATH_FIELD) {
263
+ continue;
264
+ }
265
+ cells[column.field] = toCellValue(entry.frontmatter[column.field]);
266
+ }
267
+ return { cells, fingerprint: entry.rawText, key: path };
268
+ };
269
+ const writeEntry = async (path, entry, patches) => {
270
+ const platform = getPlatform();
271
+ const frontmatter = { ...entry.frontmatter };
272
+ for (const patch of patches) {
273
+ if (patch.value === null) {
274
+ delete frontmatter[patch.field];
275
+ } else {
276
+ frontmatter[patch.field] = patch.value;
277
+ }
278
+ }
279
+ const doc = entry.document;
280
+ const fullDoc = { ...frontmatter, ...doc, children: doc.children ?? [] };
281
+ const text = await formatSerialize(entry.formatName, fullDoc, { mode: "roundtrip" });
282
+ markLocalMutation(path);
283
+ await platform.writeFile(path, text);
284
+ entries.set(path, { ...entry, frontmatter, rawText: text });
285
+ };
286
+ return {
287
+ backingPaths: () => new Map([...entries.keys()].map((path) => [path, path])),
288
+ capabilities: { delete: true, insert: true, remotePaging: false, remoteSort: false },
289
+ async columns() {
290
+ await load();
291
+ return buildColumns();
292
+ },
293
+ async commit(batch) {
294
+ await load();
295
+ const platform = getPlatform();
296
+ const result = { cells: [], deletes: [], inserts: [] };
297
+ const byRow = new Map;
298
+ for (const cell of batch.cells) {
299
+ const list = byRow.get(cell.rowKey) ?? [];
300
+ list.push({ field: cell.field, value: cell.value });
301
+ byRow.set(cell.rowKey, list);
302
+ }
303
+ for (const [path, patches] of byRow) {
304
+ const outcome = (ok, error, stale) => {
305
+ for (const patch of patches) {
306
+ result.cells.push({ error, field: patch.field, ok, rowKey: path, stale });
307
+ }
308
+ };
309
+ const entry = entries.get(path);
310
+ if (!entry) {
311
+ outcome(false, "Entry no longer loaded — refresh the grid");
312
+ continue;
313
+ }
314
+ const openTab = openTabFor(path);
315
+ if (openTab?.doc.dirty) {
316
+ outcome(false, "Open in a tab with unsaved changes — save or close it first");
317
+ continue;
318
+ }
319
+ let onDisk = null;
320
+ try {
321
+ onDisk = await platform.readFile(path);
322
+ } catch {
323
+ onDisk = null;
324
+ }
325
+ if (onDisk !== entry.rawText && !isRecentLocal(path)) {
326
+ outcome(false, "File changed on disk — refresh to reload", true);
327
+ continue;
328
+ }
329
+ try {
330
+ await writeEntry(path, entry, patches);
331
+ outcome(true);
332
+ if (openTab) {
333
+ const { reloadFileInTab } = await import("./files-3kfkwhk4.js");
334
+ reloadFileInTab(path);
335
+ }
336
+ } catch (error) {
337
+ outcome(false, error instanceof Error ? error.message : String(error));
338
+ }
339
+ }
340
+ for (const insert of batch.inserts) {
341
+ const rawPath = insert.cells[PATH_FIELD];
342
+ if (typeof rawPath !== "string" || rawPath.trim() === "") {
343
+ result.inserts.push({ error: "Path is required", ok: false, tempKey: insert.tempKey });
344
+ continue;
345
+ }
346
+ const path = opts.resolveInsertPath(rawPath);
347
+ let exists = entries.has(path);
348
+ if (!exists) {
349
+ try {
350
+ await platform.readFile(path);
351
+ exists = true;
352
+ } catch {
353
+ exists = false;
354
+ }
355
+ }
356
+ if (exists) {
357
+ result.inserts.push({
358
+ error: `${path} already exists`,
359
+ ok: false,
360
+ tempKey: insert.tempKey
361
+ });
362
+ continue;
363
+ }
364
+ const formatName = opts.insertFormatName(path);
365
+ if (!formatName) {
366
+ result.inserts.push({
367
+ error: `No format can serialize ${path}`,
368
+ ok: false,
369
+ tempKey: insert.tempKey
370
+ });
371
+ continue;
372
+ }
373
+ try {
374
+ const frontmatter = {};
375
+ for (const [field, value] of Object.entries(insert.cells)) {
376
+ if (field !== PATH_FIELD && value !== null) {
377
+ frontmatter[field] = value;
378
+ }
379
+ }
380
+ const text = await formatSerialize(formatName, { ...frontmatter, children: [] }, { frontmatter: Object.keys(frontmatter).length > 0, mode: "roundtrip" });
381
+ markLocalMutation(path);
382
+ await platform.writeFile(path, text);
383
+ const parsed = await parseSourceForPath(path, text);
384
+ entries.set(path, {
385
+ document: parsed.document,
386
+ formatName: parsed.format.name,
387
+ frontmatter: parsed.frontmatter ?? {},
388
+ rawText: text
389
+ });
390
+ result.inserts.push({ newKey: path, ok: true, tempKey: insert.tempKey });
391
+ } catch (error) {
392
+ result.inserts.push({
393
+ error: error instanceof Error ? error.message : String(error),
394
+ ok: false,
395
+ tempKey: insert.tempKey
396
+ });
397
+ }
398
+ }
399
+ for (const del of batch.deletes) {
400
+ if (openTabFor(del.rowKey)) {
401
+ result.deletes.push({
402
+ error: "Open in a tab — close it first",
403
+ ok: false,
404
+ rowKey: del.rowKey
405
+ });
406
+ continue;
407
+ }
408
+ try {
409
+ markLocalMutation(del.rowKey);
410
+ await platform.deleteFile(del.rowKey);
411
+ entries.delete(del.rowKey);
412
+ result.deletes.push({ ok: true, rowKey: del.rowKey });
413
+ } catch (error) {
414
+ result.deletes.push({
415
+ error: error instanceof Error ? error.message : String(error),
416
+ ok: false,
417
+ rowKey: del.rowKey
418
+ });
419
+ }
420
+ }
421
+ return result;
422
+ },
423
+ id: opts.id,
424
+ label: opts.label,
425
+ async refresh() {
426
+ await load(true);
427
+ },
428
+ async rows() {
429
+ await load();
430
+ const listed = opts.drafts ? applyDraftFilter([...entries.entries()], ([, entry]) => entry.frontmatter, includingDrafts()) : [...entries.entries()];
431
+ const rows = listed.map(([path, entry]) => rowFor(path, entry));
432
+ return { rows, total: rows.length };
433
+ }
434
+ };
435
+ }
436
+ function createCollectionSource(typeName) {
437
+ const requireInfo = () => {
438
+ const info = collectionInfo(typeName);
439
+ if (!info) {
440
+ throw new Error(`No content collection named "${typeName}" in project.json`);
441
+ }
442
+ return info;
443
+ };
444
+ return createEntryFileSource({
445
+ drafts: true,
446
+ id: makeGridTabId({ kind: "collection", name: typeName }),
447
+ insertFormatName: (path) => {
448
+ const info = requireInfo();
449
+ return (info.def.format ? formatByName(info.def.format)?.name : undefined) ?? formatForPath(path)?.name ?? defaultContentFormat()?.name ?? null;
450
+ },
451
+ label: typeName,
452
+ list: () => {
453
+ const info = requireInfo();
454
+ return listEntryFiles(info.dir, [info.ext]);
455
+ },
456
+ resolveInsertPath: (raw) => {
457
+ const info = requireInfo();
458
+ let path = raw.trim().replace(/^\.\//, "").replace(/^\//, "");
459
+ if (!path.includes("/")) {
460
+ path = `${info.dir}/${path}`;
461
+ }
462
+ if (!path.endsWith(info.ext)) {
463
+ path = `${path}${info.ext}`;
464
+ }
465
+ return path;
466
+ },
467
+ schema: () => requireInfo().def.schema
468
+ });
469
+ }
470
+ function createPagesSource() {
471
+ const pageExts = () => {
472
+ const exts = documentExtensions("page").filter((ext) => ext !== ".json");
473
+ return exts.length > 0 ? exts : [".md"];
474
+ };
475
+ return createEntryFileSource({
476
+ id: makeGridTabId({ kind: "pages" }),
477
+ insertFormatName: (path) => formatForPath(path)?.name ?? null,
478
+ label: "Pages",
479
+ list: () => listEntryFiles("pages", pageExts()),
480
+ priorityFields: ["title", "description"],
481
+ resolveInsertPath: (raw) => {
482
+ let path = raw.trim().replace(/^\.\//, "").replace(/^\//, "");
483
+ if (!path.startsWith("pages/")) {
484
+ path = `pages/${path}`;
485
+ }
486
+ if (!pageExts().some((ext) => path.endsWith(ext))) {
487
+ path = `${path}${pageExts()[0]}`;
488
+ }
489
+ return path;
490
+ },
491
+ schema: () => null
492
+ });
493
+ }
494
+
495
+ export { DRAFT_FIELD, DRAFT_MEANING, isDraftEntry, hasDraftAxis, setIncludeDrafts, PATH_FIELD, collectionInfo, collectionDirs, listCollectionEntryIds, reloadDraftAwareGrids, createCollectionSource, createPagesSource };
496
+
497
+ //# debugId=EEA6C59DFC58D56B64756E2164756E21
498
+ //# sourceMappingURL=studio-b55y6ewx.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  projectState
3
- } from "./studio-cjm7fdjf.js";
3
+ } from "./studio-p4ngc046.js";
4
4
  import {
5
5
  getPlatform
6
- } from "./studio-sas7mt3k.js";
6
+ } from "./studio-9ab8gqsm.js";
7
7
 
8
8
  // src/files/components.ts
9
9
  var componentRegistry = [];
@@ -59,4 +59,4 @@ function computeRelativePath(fromDocPath, toCompPath) {
59
59
  export { componentRegistry, _componentRegistryLoaded, loadComponentRegistry, buildComponentInstance, computeRelativePath };
60
60
 
61
61
  //# debugId=37666BFABEF9083664756E2164756E21
62
- //# sourceMappingURL=studio-s519zc99.js.map
62
+ //# sourceMappingURL=studio-bgxt93ga.js.map
@@ -0,0 +1,119 @@
1
+ import {
2
+ errorMessage
3
+ } from "./studio-9n4mrmnb.js";
4
+ import {
5
+ getPlatform,
6
+ hasPlatform
7
+ } from "./studio-9ab8gqsm.js";
8
+
9
+ // src/services/references.ts
10
+ function usagesSupported() {
11
+ return hasPlatform() && typeof getPlatform().findReferences === "function";
12
+ }
13
+ function keyOf(query) {
14
+ return `${query.path ?? ""}\x00${query.tagName ?? ""}`;
15
+ }
16
+ var settled = new Map;
17
+ var inFlight = new Map;
18
+ function peekUsages(query) {
19
+ if (!usagesSupported()) {
20
+ return { status: "unsupported" };
21
+ }
22
+ return settled.get(keyOf(query)) ?? (inFlight.has(keyOf(query)) ? { status: "pending" } : null);
23
+ }
24
+ async function loadUsages(query) {
25
+ if (!usagesSupported()) {
26
+ return { status: "unsupported" };
27
+ }
28
+ if (!query.path && !query.tagName) {
29
+ return { status: "failed", message: "no target to look for" };
30
+ }
31
+ const key = keyOf(query);
32
+ const done = settled.get(key);
33
+ if (done) {
34
+ return done;
35
+ }
36
+ const running = inFlight.get(key);
37
+ if (running) {
38
+ return running;
39
+ }
40
+ const pending = (async () => {
41
+ try {
42
+ const result = await getPlatform().findReferences({
43
+ ...query.path === undefined ? {} : { path: query.path },
44
+ ...query.tagName === undefined ? {} : { tagName: query.tagName }
45
+ });
46
+ return { result, status: "ready" };
47
+ } catch (error) {
48
+ return { message: errorMessage(error), status: "failed" };
49
+ } finally {
50
+ inFlight.delete(key);
51
+ }
52
+ })();
53
+ inFlight.set(key, pending);
54
+ const state = await pending;
55
+ settled.set(key, state);
56
+ return state;
57
+ }
58
+ function retryUsages(query) {
59
+ settled.delete(keyOf(query));
60
+ return loadUsages(query);
61
+ }
62
+ function invalidateUsages() {
63
+ settled.clear();
64
+ }
65
+ function splitUsages(result) {
66
+ let pages = 0;
67
+ for (const file of result.files) {
68
+ if (file.path.startsWith("pages/")) {
69
+ pages += 1;
70
+ }
71
+ }
72
+ return { others: result.files.length - pages, pages };
73
+ }
74
+ function usageHeadline(result) {
75
+ const { others, pages } = splitUsages(result);
76
+ if (pages === 0 && others === 0) {
77
+ return "Not used yet";
78
+ }
79
+ const parts = [];
80
+ if (pages > 0) {
81
+ parts.push(`${pages} page${pages === 1 ? "" : "s"}`);
82
+ }
83
+ if (others > 0) {
84
+ parts.push(`${others} other file${others === 1 ? "" : "s"}`);
85
+ }
86
+ return `Used on ${parts.join(" and ")}`;
87
+ }
88
+ function usageWarning(state, verb) {
89
+ if (state.status === "unsupported") {
90
+ return null;
91
+ }
92
+ if (state.status === "pending") {
93
+ return "Counting references…";
94
+ }
95
+ if (state.status === "failed") {
96
+ return `References could not be counted (${state.message}) — this may break more than it appears to.`;
97
+ }
98
+ const { files, refsTotal } = state.result;
99
+ if (files.length === 0) {
100
+ return verb === "delete" ? "Nothing else in this project refers to it." : "Nothing else in this project refers to it, so nothing needs updating.";
101
+ }
102
+ const where = `${refsTotal} reference${refsTotal === 1 ? "" : "s"} in ${files.length} file${files.length === 1 ? "" : "s"}`;
103
+ const floor = state.result.errors.length > 0 ? " (at least — some documents could not be read)" : "";
104
+ if (verb === "delete") {
105
+ return `${where}${floor} will break. Those files stay on disk; the references in them stop resolving.`;
106
+ }
107
+ if (verb === "convert") {
108
+ return `${where}${floor} will be updated automatically to point at the new file.`;
109
+ }
110
+ return `${where}${floor} will be updated automatically. Nothing else changes.`;
111
+ }
112
+ function usageFiles(result) {
113
+ return result.files.toSorted((a, b) => b.count - a.count || a.path.localeCompare(b.path));
114
+ }
115
+
116
+ export { usagesSupported, peekUsages, loadUsages, retryUsages, invalidateUsages, splitUsages, usageHeadline, usageWarning, usageFiles };
117
+
118
+ //# debugId=F66D72E5CAE74C4664756E2164756E21
119
+ //# sourceMappingURL=studio-cft9r4r7.js.map