tsondb 0.7.7 → 0.7.9

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 (49) hide show
  1. package/dist/src/node/server/api/git.js +156 -24
  2. package/dist/src/node/server/index.js +4 -0
  3. package/dist/src/node/utils/instanceOperations.d.ts +1 -1
  4. package/dist/src/node/utils/instanceOperations.js +2 -2
  5. package/dist/src/shared/api.d.ts +17 -1
  6. package/dist/src/shared/utils/git.d.ts +4 -0
  7. package/dist/src/shared/utils/git.js +6 -1
  8. package/dist/src/shared/utils/markdown.d.ts +36 -17
  9. package/dist/src/shared/utils/markdown.js +79 -23
  10. package/dist/src/shared/utils/object.d.ts +1 -0
  11. package/dist/src/shared/utils/object.js +1 -0
  12. package/dist/src/web/api/git.d.ts +5 -1
  13. package/dist/src/web/api/git.js +6 -2
  14. package/dist/src/web/components/ContextProviderWrapper.d.ts +7 -0
  15. package/dist/src/web/components/ContextProviderWrapper.js +5 -0
  16. package/dist/src/web/components/InstanceRouteSkeleton.d.ts +1 -0
  17. package/dist/src/web/components/InstanceRouteSkeleton.js +8 -4
  18. package/dist/src/web/components/LoadingOverlay.d.ts +1 -0
  19. package/dist/src/web/components/LoadingOverlay.js +3 -0
  20. package/dist/src/web/components/ModalDialog.js +4 -3
  21. package/dist/src/web/components/git/Git.js +47 -0
  22. package/dist/src/web/components/git/GitBranchManager.d.ts +7 -0
  23. package/dist/src/web/components/git/GitBranchManager.js +17 -0
  24. package/dist/src/web/components/git/GitFileList.d.ts +17 -0
  25. package/dist/src/web/components/git/GitFileList.js +11 -0
  26. package/dist/src/web/components/git/GitFileManager.d.ts +8 -0
  27. package/dist/src/web/components/git/GitFileManager.js +34 -0
  28. package/dist/src/web/components/git/GitStatusIndicator.d.ts +7 -0
  29. package/dist/src/web/components/git/GitStatusIndicator.js +6 -0
  30. package/dist/src/web/components/typeInputs/StringTypeInput.js +1 -1
  31. package/dist/src/web/context/entities.d.ts +6 -5
  32. package/dist/src/web/context/git.d.ts +2 -1
  33. package/dist/src/web/context/gitClient.d.ts +2 -0
  34. package/dist/src/web/context/gitClient.js +2 -0
  35. package/dist/src/web/hooks/useGitClient.d.ts +37 -0
  36. package/dist/src/web/hooks/useGitClient.js +313 -0
  37. package/dist/src/web/index.js +6 -2
  38. package/dist/src/web/routes/CreateInstance.js +2 -1
  39. package/dist/src/web/routes/Entity.js +10 -4
  40. package/dist/src/web/routes/Instance.js +2 -1
  41. package/dist/src/web/signals/loading.d.ts +2 -0
  42. package/dist/src/web/signals/loading.js +11 -0
  43. package/dist/src/web/utils/BlockMarkdown.js +1 -1
  44. package/dist/src/web/utils/debug.d.ts +1 -0
  45. package/dist/src/web/utils/debug.js +4 -0
  46. package/package.json +3 -3
  47. package/public/css/styles.css +319 -229
  48. package/dist/src/web/components/Git.js +0 -164
  49. /package/dist/src/web/components/{Git.d.ts → git/Git.d.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  import Debug from "debug";
2
2
  import express, {} from "express";
3
3
  import { join } from "node:path";
4
- import { hasFileChanges } from "../../../shared/utils/git.js";
4
+ import { hasFileChanges, splitBranchName } from "../../../shared/utils/git.js";
5
5
  import { getInstanceContainerOverview } from "../../../shared/utils/instances.js";
6
6
  import { attachGitStatusToInstancesByEntityName } from "../../utils/instances.js";
7
7
  import { reinit } from "../init.js";
@@ -10,12 +10,18 @@ const debug = Debug("tsondb:server:api:git");
10
10
  export const gitApi = express.Router();
11
11
  gitApi.use((req, res, next) => {
12
12
  debug(req.path);
13
- if (req.gitRoot === undefined) {
14
- res.status(500).send("Git repository not found");
13
+ if (req.path !== "/" && req.gitRoot === undefined) {
14
+ res.status(400).send("Git repository not found");
15
15
  return;
16
16
  }
17
17
  next();
18
18
  });
19
+ gitApi.get("/", (req, res) => {
20
+ const body = {
21
+ isRepo: req.gitRoot !== undefined,
22
+ };
23
+ res.json(body);
24
+ });
19
25
  gitApi.get("/status", async (req, res) => {
20
26
  const status = await req.git.status();
21
27
  attachGitStatusToInstancesByEntityName(req.instancesByEntityName, req.dataRoot,
@@ -23,6 +29,8 @@ gitApi.get("/status", async (req, res) => {
23
29
  req.gitRoot, status);
24
30
  const getChildInstancesForInstanceId = createChildInstancesForInstanceIdGetter(req);
25
31
  const body = {
32
+ currentBranch: status.current,
33
+ trackingBranch: status.tracking,
26
34
  commitsAhead: status.ahead,
27
35
  commitsBehind: status.behind,
28
36
  instances: Object.fromEntries(Object.entries(req.instancesByEntityName).map(([entityName, instances]) => [
@@ -36,62 +44,94 @@ gitApi.get("/status", async (req, res) => {
36
44
  };
37
45
  res.json(body);
38
46
  });
47
+ gitApi.post("/fetch", async (req, res) => {
48
+ try {
49
+ await req.git.fetch(["--all", "-p"]);
50
+ res.set("Content-Type", "text/plain");
51
+ res.status(200).send("Fetched all remotes");
52
+ }
53
+ catch (error) {
54
+ debug(`${req.path}: ${error.message}`);
55
+ res.set("Content-Type", "text/plain");
56
+ res.status(500).send(error instanceof Error ? error.message : "Fetching all remotes failed");
57
+ }
58
+ });
39
59
  gitApi.post("/stage", async (req, res) => {
40
60
  try {
41
61
  await req.git.add(req.dataRoot);
62
+ res.set("Content-Type", "text/plain");
42
63
  res.status(200).send("Added all database files to index");
43
64
  }
44
65
  catch (error) {
45
66
  debug(`${req.path}: ${error.message}`);
46
- res.status(500).send("Adding all database files to index failed");
67
+ res.set("Content-Type", "text/plain");
68
+ res
69
+ .status(500)
70
+ .send(error instanceof Error ? error.message : "Adding all database files to index failed");
47
71
  }
48
72
  });
49
73
  gitApi.post("/stage/:entityName", async (req, res) => {
50
74
  try {
51
75
  await req.git.add(join(req.dataRoot, req.params.entityName));
76
+ res.set("Content-Type", "text/plain");
52
77
  res.status(200).send(`Added all database files for entity ${req.params.entityName} to index`);
53
78
  }
54
79
  catch (error) {
55
80
  debug(`${req.path}: ${error.message}`);
81
+ res.set("Content-Type", "text/plain");
56
82
  res
57
83
  .status(500)
58
- .send(`Adding all database files for entity ${req.params.entityName} to index failed`);
84
+ .send(error instanceof Error
85
+ ? error.message
86
+ : `Adding all database files for entity ${req.params.entityName} to index failed`);
59
87
  }
60
88
  });
61
89
  gitApi.post("/stage/:entityName/:instanceId", async (req, res) => {
62
90
  try {
63
91
  await req.git.add(join(req.dataRoot, req.params.entityName, `${req.params.instanceId}.json`));
92
+ res.set("Content-Type", "text/plain");
64
93
  res
65
94
  .status(200)
66
95
  .send(`Added database file ${req.params.instanceId} for entity ${req.params.entityName} to index`);
67
96
  }
68
97
  catch (error) {
69
98
  debug(`${req.path}: ${error.message}`);
99
+ res.set("Content-Type", "text/plain");
70
100
  res
71
101
  .status(500)
72
- .send(`Adding database file ${req.params.instanceId} for entity ${req.params.entityName} to index failed`);
102
+ .send(error instanceof Error
103
+ ? error.message
104
+ : `Adding database file ${req.params.instanceId} for entity ${req.params.entityName} to index failed`);
73
105
  }
74
106
  });
75
107
  gitApi.post("/unstage", async (req, res) => {
76
108
  try {
77
109
  await req.git.reset(["HEAD", "--", req.dataRoot]);
110
+ res.set("Content-Type", "text/plain");
78
111
  res.status(200).send("Removed all database files to index");
79
112
  }
80
113
  catch (error) {
81
114
  debug(`${req.path}: ${error.message}`);
82
- res.status(500).send("Removing all database files to index failed");
115
+ res.set("Content-Type", "text/plain");
116
+ res
117
+ .status(500)
118
+ .send(error instanceof Error ? error.message : "Removing all database files to index failed");
83
119
  }
84
120
  });
85
121
  gitApi.post("/unstage/:entityName", async (req, res) => {
86
122
  try {
87
123
  await req.git.reset(["HEAD", "--", join(req.dataRoot, req.params.entityName)]);
124
+ res.set("Content-Type", "text/plain");
88
125
  res.status(200).send(`Removed all database files for entity ${req.params.entityName} to index`);
89
126
  }
90
127
  catch (error) {
91
128
  debug(`${req.path}: ${error.message}`);
129
+ res.set("Content-Type", "text/plain");
92
130
  res
93
131
  .status(500)
94
- .send(`Removing all database files for entity ${req.params.entityName} to index failed`);
132
+ .send(error instanceof Error
133
+ ? error.message
134
+ : `Removing all database files for entity ${req.params.entityName} to index failed`);
95
135
  }
96
136
  });
97
137
  gitApi.post("/unstage/:entityName/:instanceId", async (req, res) => {
@@ -101,78 +141,170 @@ gitApi.post("/unstage/:entityName/:instanceId", async (req, res) => {
101
141
  "--",
102
142
  join(req.dataRoot, req.params.entityName, `${req.params.instanceId}.json`),
103
143
  ]);
144
+ res.set("Content-Type", "text/plain");
104
145
  res
105
146
  .status(200)
106
147
  .send(`Removed database file ${req.params.instanceId} for entity ${req.params.entityName} to index`);
107
148
  }
108
149
  catch (error) {
109
150
  debug(`${req.path}: ${error.message}`);
151
+ res.set("Content-Type", "text/plain");
110
152
  res
111
153
  .status(500)
112
- .send(`Removing database file ${req.params.instanceId} for entity ${req.params.entityName} to index failed`);
154
+ .send(error instanceof Error
155
+ ? error.message
156
+ : `Removing database file ${req.params.instanceId} for entity ${req.params.entityName} to index failed`);
157
+ }
158
+ });
159
+ gitApi.post("/reset", async (req, res) => {
160
+ try {
161
+ await req.git.raw(["restore", "--", req.dataRoot]);
162
+ res.set("Content-Type", "text/plain");
163
+ res.status(200).send("Removed all database files to index");
164
+ }
165
+ catch (error) {
166
+ debug(`${req.path}: ${error.message}`);
167
+ res.set("Content-Type", "text/plain");
168
+ res
169
+ .status(500)
170
+ .send(error instanceof Error ? error.message : "Removing all database files to index failed");
171
+ }
172
+ });
173
+ gitApi.post("/reset/:entityName/:instanceId", async (req, res) => {
174
+ try {
175
+ await req.git.raw([
176
+ "restore",
177
+ "--",
178
+ join(req.dataRoot, req.params.entityName, `${req.params.instanceId}.json`),
179
+ ]);
180
+ await reinit(req);
181
+ res.set("Content-Type", "text/plain");
182
+ res
183
+ .status(200)
184
+ .send(`Removed database file ${req.params.instanceId} for entity ${req.params.entityName} to index`);
185
+ }
186
+ catch (error) {
187
+ debug(`${req.path}: ${error.message}`);
188
+ res.set("Content-Type", "text/plain");
189
+ res
190
+ .status(500)
191
+ .send(error instanceof Error
192
+ ? error.message
193
+ : `Removing database file ${req.params.instanceId} for entity ${req.params.entityName} to index failed`);
113
194
  }
114
195
  });
115
196
  gitApi.post("/commit", async (req, res) => {
116
197
  const message = req.body.message;
117
198
  if (typeof message !== "string" || message.length === 0) {
199
+ res.set("Content-Type", "text/plain");
118
200
  res.status(400).send("Invalid commit message");
119
201
  return;
120
202
  }
121
203
  try {
122
204
  await req.git.commit(message);
205
+ res.set("Content-Type", "text/plain");
123
206
  res.status(200).send("Commit successful");
124
207
  }
125
- catch {
126
- res.status(500).send("Commit failed");
208
+ catch (error) {
209
+ res.set("Content-Type", "text/plain");
210
+ res.status(500).send(error instanceof Error ? error.message : "Commit failed");
127
211
  }
128
212
  });
129
213
  gitApi.post("/push", async (req, res) => {
130
214
  try {
131
- await req.git.push();
215
+ const status = await req.git.status();
216
+ const remotes = await req.git.getRemotes();
217
+ await req.git.push(remotes[0]?.name, status.current ?? undefined);
218
+ res.set("Content-Type", "text/plain");
132
219
  res.status(200).send("Push successful");
133
220
  }
134
- catch {
135
- res.status(500).send("Push failed");
221
+ catch (error) {
222
+ res.set("Content-Type", "text/plain");
223
+ res.status(500).send(error instanceof Error ? error.message : "Push failed");
136
224
  }
137
225
  });
138
226
  gitApi.post("/pull", async (req, res) => {
139
227
  try {
140
- await req.git.pull();
228
+ const status = await req.git.status();
229
+ const remotes = await req.git.getRemotes();
230
+ await req.git.pull(remotes[0]?.name, status.current ?? undefined);
231
+ res.set("Content-Type", "text/plain");
141
232
  res.status(200).send("Pull successful");
142
233
  }
143
- catch {
144
- res.status(500).send("Pull failed");
234
+ catch (error) {
235
+ res.set("Content-Type", "text/plain");
236
+ res.status(500).send(error instanceof Error ? error.message : "Pull failed");
145
237
  }
146
238
  });
147
239
  gitApi.get("/branch", async (req, res) => {
148
- const branchSummary = await req.git.branchLocal();
240
+ const branchSummary = await req.git.branch();
149
241
  const body = {
150
242
  allBranches: branchSummary.all,
151
243
  currentBranch: branchSummary.current,
244
+ isDetached: branchSummary.detached,
245
+ branches: branchSummary.branches,
152
246
  };
153
247
  res.json(body);
154
248
  });
155
249
  gitApi.post("/branch", async (req, res) => {
156
250
  const branchName = req.body.branchName;
157
251
  if (typeof branchName !== "string" || branchName.length === 0) {
252
+ res.set("Content-Type", "text/plain");
158
253
  res.status(400).send("Invalid branch name");
159
254
  return;
160
255
  }
161
256
  try {
162
257
  await req.git.checkoutLocalBranch(branchName);
163
258
  await reinit(req);
259
+ res.set("Content-Type", "text/plain");
164
260
  res.status(200).send(`Creation of branch "${branchName}" successful`);
165
261
  }
166
- catch {
167
- res.status(500).send(`Creation of branch "${branchName}" failed`);
262
+ catch (error) {
263
+ res.set("Content-Type", "text/plain");
264
+ res
265
+ .status(500)
266
+ .send(error instanceof Error ? error.message : `Creation of branch "${branchName}" failed`);
168
267
  }
169
268
  });
170
269
  gitApi.post("/branch/:branchName", async (req, res) => {
270
+ const branchName = decodeURIComponent(req.params.branchName);
171
271
  try {
172
- await req.git.checkout(req.params.branchName);
173
- res.status(200).send(`Switch to branch "${req.params.branchName}" successful`);
272
+ const { remote, name: actualBranch } = splitBranchName(branchName);
273
+ if (remote) {
274
+ debug(`Switch to remote branch "${remote}/${actualBranch}"`);
275
+ }
276
+ else {
277
+ debug(`Switch to local branch "${actualBranch}"`);
278
+ }
279
+ await req.git.raw("switch", actualBranch);
280
+ await reinit(req);
281
+ res.set("Content-Type", "text/plain");
282
+ res.status(200).send(`Switch to branch "${branchName}" successful`);
283
+ }
284
+ catch (error) {
285
+ res.set("Content-Type", "text/plain");
286
+ res
287
+ .status(500)
288
+ .send(error instanceof Error ? error.message : `Switch to branch "${branchName}" failed`);
174
289
  }
175
- catch {
176
- res.status(500).send(`Switch to branch "${req.params.branchName}" failed`);
290
+ });
291
+ gitApi.delete("/branch/:branchName", async (req, res) => {
292
+ const branchName = decodeURIComponent(req.params.branchName);
293
+ try {
294
+ const branchSummary = await req.git.branchLocal();
295
+ if (branchSummary.current === branchName) {
296
+ res.set("Content-Type", "text/plain");
297
+ res.status(400).send("Cannot delete the branch currently checked out");
298
+ return;
299
+ }
300
+ await req.git.deleteLocalBranch(branchName, true);
301
+ res.set("Content-Type", "text/plain");
302
+ res.status(200).send(`Deletion of branch "${branchName}" successful`);
303
+ }
304
+ catch (error) {
305
+ res.set("Content-Type", "text/plain");
306
+ res
307
+ .status(500)
308
+ .send(error instanceof Error ? error.message : `Deletion of branch "${branchName}" failed`);
177
309
  }
178
310
  });
@@ -21,6 +21,8 @@ export const createServer = async (schema, dataRootPath, instancesByEntityName,
21
21
  const app = express();
22
22
  app.use(express.static(join(import.meta.dirname, "../../../../public")));
23
23
  app.use("/js/node_modules/preact", staticNodeModule("preact"));
24
+ app.use("/js/node_modules/@preact/signals", staticNodeModule("@preact/signals"));
25
+ app.use("/js/node_modules/@preact/signals-core", staticNodeModule("@preact/signals-core"));
24
26
  app.use("/js/node_modules/preact-iso", staticNodeModule("preact-iso"));
25
27
  app.use("/js/client", express.static(join(import.meta.dirname, "../../../../dist/src/web")));
26
28
  app.use("/js/shared", express.static(join(import.meta.dirname, "../../../../dist/src/shared")));
@@ -42,6 +44,8 @@ export const createServer = async (schema, dataRootPath, instancesByEntityName,
42
44
  "preact/hooks": "/js/node_modules/preact/hooks/dist/hooks.module.js",
43
45
  "preact/jsx-runtime": "/js/node_modules/preact/jsx-runtime/dist/jsxRuntime.module.js",
44
46
  "preact-iso": "/js/node_modules/preact-iso/src/index.js",
47
+ "@preact/signals": "/js/node_modules/@preact/signals/dist/signals.module.js",
48
+ "@preact/signals-core": "/js/node_modules/@preact/signals-core/dist/signals-core.module.js",
45
49
  },
46
50
  }, null, 2);
47
51
  const customStylesheetLinkHeader = customStylesheetPath
@@ -2,7 +2,7 @@ import type { InstancesByEntityName } from "../../shared/utils/instances.ts";
2
2
  import { type Result } from "../../shared/utils/result.ts";
3
3
  import type { EntityDecl } from "../schema/declarations/EntityDecl.js";
4
4
  import { type ReferencesToInstances } from "./references.ts";
5
- export declare const createNewId: () => string;
5
+ export declare const createNewId: () => `${string}-${string}-${string}-${string}-${string}`;
6
6
  export declare const checkCreateInstancePossible: (localeEntity: EntityDecl | undefined, instancesByEntityName: InstancesByEntityName, entity: EntityDecl, instanceContent: unknown, customId: unknown) => Result<string, [code: number, message: string]>;
7
7
  export declare const createInstance: (dataRoot: string, localeEntity: EntityDecl | undefined, instancesByEntityName: InstancesByEntityName, entity: EntityDecl, instanceContent: unknown, customId: unknown) => Promise<Result<string, [code: number, message: string]>>;
8
8
  export declare const checkUpdateInstancePossible: (instancesByEntityName: InstancesByEntityName, entity: EntityDecl, instanceContent: unknown) => Result<void, [code: number, message: string]>;
@@ -1,10 +1,10 @@
1
- import { v4 as uuidv4 } from "uuid";
1
+ import { randomUUID } from "node:crypto";
2
2
  import { error, isOk, map, ok } from "../../shared/utils/result.js";
3
3
  import { createValidators, validateEntityDecl } from "../schema/index.js";
4
4
  import { getErrorMessageForDisplay } from "./error.js";
5
5
  import * as Files from "./files.js";
6
6
  import { isReferencedByOtherInstances } from "./references.js";
7
- export const createNewId = () => uuidv4();
7
+ export const createNewId = () => randomUUID();
8
8
  export const checkCreateInstancePossible = (localeEntity, instancesByEntityName, entity, instanceContent, customId) => {
9
9
  const newInstanceId = entity === localeEntity ? customId : createNewId();
10
10
  if (typeof newInstanceId !== "string") {
@@ -53,16 +53,32 @@ export interface GetAllInstancesResponseBody {
53
53
  }[];
54
54
  };
55
55
  }
56
+ export interface IsRepoResponseBody {
57
+ isRepo: boolean;
58
+ }
56
59
  export interface GitStatusResponseBody {
60
+ currentBranch: string | null;
61
+ trackingBranch: string | null;
57
62
  commitsAhead: number;
58
63
  commitsBehind: number;
59
64
  instances: {
60
65
  [entity: string]: InstanceContainerOverview[];
61
66
  };
62
67
  }
68
+ export interface GetAllGitBranchesResponseBodyBranchSummary {
69
+ current: boolean;
70
+ name: string;
71
+ commit: string;
72
+ label: string;
73
+ linkedWorkTree: boolean;
74
+ }
63
75
  export interface GetAllGitBranchesResponseBody {
64
- allBranches: string[];
76
+ isDetached: boolean;
65
77
  currentBranch: string;
78
+ allBranches: string[];
79
+ branches: {
80
+ [key: string]: GetAllGitBranchesResponseBodyBranchSummary;
81
+ };
66
82
  }
67
83
  export interface CreateCommitRequestBody {
68
84
  message: string;
@@ -10,3 +10,7 @@ export type GitFileStatusForDisplay = "U" | "M" | "A" | "D" | "R" | undefined;
10
10
  export declare const hasFileChanges: (fileStatus: GitFileStatus | undefined) => boolean;
11
11
  export declare const getGitStatusForDisplay: (fileStatus: GitFileStatus | undefined) => GitFileStatusForDisplay;
12
12
  export declare const getLabelForGitStatus: (status: GitFileStatusForDisplay) => string;
13
+ export declare const splitBranchName: (branch: string) => {
14
+ remote?: string;
15
+ name: string;
16
+ };
@@ -87,7 +87,7 @@ export const getLabelForGitStatus = (status) => {
87
87
  case "M":
88
88
  return "modified";
89
89
  case "A":
90
- return "sdded";
90
+ return "added";
91
91
  case "D":
92
92
  return "deleted";
93
93
  case "R":
@@ -96,3 +96,8 @@ export const getLabelForGitStatus = (status) => {
96
96
  return "";
97
97
  }
98
98
  };
99
+ const remotePattern = /^remotes\/(\w+?)\/(.+)$/;
100
+ export const splitBranchName = (branch) => {
101
+ const [_, remote, actualBranch] = branch.match(remotePattern) ?? ["", undefined, branch];
102
+ return { remote, name: actualBranch };
103
+ };
@@ -2,50 +2,69 @@ type TextNode = {
2
2
  kind: "text";
3
3
  content: string;
4
4
  };
5
- export type InlineMarkdownNode = {
6
- kind: "bold" | "italic";
5
+ type BoldMarkdownNode = {
6
+ kind: "bold";
7
7
  content: InlineMarkdownNode[];
8
- } | {
8
+ };
9
+ type ItalicMarkdownNode = {
10
+ kind: "italic";
11
+ content: InlineMarkdownNode[];
12
+ };
13
+ type CodeMarkdownNode = {
9
14
  kind: "code";
10
15
  content: string;
11
- } | {
16
+ };
17
+ type LinkMarkdownNode = {
12
18
  kind: "link";
13
19
  href: string;
14
20
  content: InlineMarkdownNode[];
15
- } | {
21
+ };
22
+ type AttributedStringMarkdownNode = {
16
23
  kind: "attributed";
17
24
  attributes: Record<string, string | number | boolean>;
18
25
  content: InlineMarkdownNode[];
19
- } | TextNode;
20
- export type BlockMarkdownNode = {
26
+ };
27
+ export type InlineMarkdownNode = BoldMarkdownNode | ItalicMarkdownNode | CodeMarkdownNode | LinkMarkdownNode | AttributedStringMarkdownNode | TextNode;
28
+ type ParagraphBlockNode = {
21
29
  kind: "paragraph";
22
30
  content: InlineMarkdownNode[];
23
- } | {
31
+ };
32
+ type HeadingBlockNode = {
24
33
  kind: "heading";
25
34
  level: number;
26
35
  content: InlineMarkdownNode[];
27
- } | {
36
+ };
37
+ type ListBlockNode = {
28
38
  kind: "list";
29
39
  ordered: boolean;
30
- content: {
31
- kind: "listitem";
32
- content: InlineMarkdownNode[];
33
- }[];
34
- } | {
40
+ content: ListItemNode[];
41
+ };
42
+ type ListItemNode = {
43
+ kind: "listitem";
44
+ content: InlineMarkdownNode[];
45
+ };
46
+ type TableBlockNode = {
35
47
  kind: "table";
48
+ caption?: InlineMarkdownNode[];
36
49
  header: InlineMarkdownNode[][];
37
50
  rows: InlineMarkdownNode[][][];
38
51
  };
39
- export type BlockSyntaxMarkdownNode = InlineMarkdownNode | {
52
+ export type BlockMarkdownNode = ParagraphBlockNode | HeadingBlockNode | ListBlockNode | TableBlockNode;
53
+ type ListItemMarkerSyntaxNode = {
40
54
  kind: "listitemmarker";
41
55
  content: string;
42
- } | {
56
+ };
57
+ type TableMarkerSyntaxNode = {
43
58
  kind: "tablemarker";
44
59
  content: string;
45
- } | {
60
+ };
61
+ type HeadingMarkerSyntaxNode = {
46
62
  kind: "headingmarker";
47
63
  content: string;
48
64
  };
65
+ type SyntaxNode = ListItemMarkerSyntaxNode | TableMarkerSyntaxNode | HeadingMarkerSyntaxNode;
66
+ export type BlockSyntaxMarkdownNode = InlineMarkdownNode | SyntaxNode;
49
67
  export declare const parseBlockMarkdown: (text: string) => BlockMarkdownNode[];
50
68
  export declare const parseBlockMarkdownForSyntaxHighlighting: (text: string) => BlockSyntaxMarkdownNode[];
69
+ export declare const reduceSyntaxNodes: <T extends BlockSyntaxMarkdownNode>(nodes: T[]) => T[];
51
70
  export {};