@antelopejs/interface-dms-builder 0.3.1 → 0.4.1

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.
@@ -1,14 +1,18 @@
1
- # Page Operations
1
+ ---
2
+ title: "Page operations"
3
+ description: "The operations that list, create, configure, move and delete pages, categories and the blocks of a page, with their inputs and refusals."
4
+ mode: reference
5
+ ---
2
6
 
3
7
  ## Overview
4
8
 
5
- Page operations cover everything that lives in a page file: the pages themselves, the categories they hang from, and the block tree inside each page. Reads (`ListPages`, `ListCategories`, `GetPageStructure`) tell you what is there; mutations (`CreatePage`, `AddBlock`, `MoveBlock`, …) rewrite the source and return the staged `FileChange` list.
9
+ Page operations cover the pages, the categories that hold them, and the block tree inside each page. The reads are `ListPages`, `ListCategories` and `GetPageStructure`. The mutations, such as `CreatePage`, `AddBlock` and `MoveBlock`, rewrite the source and return the list of `FileChange` entries they wrote.
6
10
 
7
- Every mutation returns an `OpResult`, so branch on `ok` before touching `data`. The refs and shapes these operations trade in are described in [Addressing and Structure](./2.addressing-and-structure.md); the errors and warnings they return are described in [Results and Errors](./8.results-and-errors.md).
11
+ Every mutation returns an `OpResult`, so branch on `ok` before you read `data`. [Addressing and structure](./2.addressing-and-structure.md) describes the refs and shapes these operations take and return. [Results and errors](./8.results-and-errors.md) describes their errors and warnings.
8
12
 
9
- ## List Pages and Categories
13
+ ## List pages and categories
10
14
 
11
- `ListPages` and `ListCategories` are plain reads: they return arrays, not an `OpResult`.
15
+ `ListPages` and `ListCategories` are plain reads. They return arrays, not an `OpResult`.
12
16
 
13
17
  ```typescript
14
18
  import {
@@ -24,9 +28,9 @@ for (const page of pages) {
24
28
  }
25
29
  ```
26
30
 
27
- ## Read a Page's Structure
31
+ ## Read a page's structure
28
32
 
29
- `GetPageStructure(ref)` returns the page's metadata, its block tree and its queries, wrapped in an `OpResult<PageStructure>`. Being a read, its `changes` array is empty.
33
+ `GetPageStructure(ref)` returns the metadata, the block tree and the queries of the page in an `OpResult<PageStructure>`. Its `changes` array is empty, because the operation is a read.
30
34
 
31
35
  ```typescript
32
36
  import { GetPageStructure } from "@antelopejs/interface-dms-builder";
@@ -39,11 +43,11 @@ if (!result.ok) {
39
43
  const { page, blocks, queries, version } = result.data;
40
44
  ```
41
45
 
42
- Keep `version`: passing it as `expectedVersion` on the next mutation turns the write into a conditional one.
46
+ Keep `version`. Passed as `expectedVersion` on the next mutation, it makes the write conditional.
43
47
 
44
- ## Refresh the Source Index
48
+ ## Refresh the source index
45
49
 
46
- The builder keeps an index of the project's source. Mutations invalidate it themselves, so you only need `RefreshSourceIndex` after something *else* changed the files — a hand edit, a checkout, a generator run.
50
+ The builder keeps an index of the project's source and a cached catalog. Every mutation drops the index after it writes. A read also rescans by itself when a file the index read has changed or disappeared since the scan, after a hand edit or a checkout for example. The index does not see a new file until a file it already read changes, such as the barrel that imports the new file. It never drops the catalog. Call `RefreshSourceIndex` after such a change, and after a change to the components the catalog describes.
47
51
 
48
52
  ```typescript
49
53
  import { RefreshSourceIndex } from "@antelopejs/interface-dms-builder";
@@ -56,15 +60,15 @@ await RefreshSourceIndex({ page: "/dashboard" }); // source index only
56
60
 
57
61
  | Option | Type | Description |
58
62
  | --- | --- | --- |
59
- | `page` | `PageRef` | Keep the cached catalog. Omit the scope entirely to drop the catalog as well. |
63
+ | `page` | `PageRef` | Keep the cached catalog. Without `page`, the call drops the catalog as well. |
60
64
 
61
- The scope does not narrow the source index: it is invalidated in full either way, and naming a page only spares the catalog cache. Pass a page when you know the change was confined to page source and left the component catalog alone — it saves rescanning the catalog, not the project.
65
+ The scope does not narrow the source index. The call drops the whole index either way, and a `page` only spares the catalog cache. Pass a page when the change touched page source and left the component catalog alone. It saves a rebuild of the catalog, not a rescan of the project.
62
66
 
63
- Invalidating is not rescanning. The call only drops the cache; the cost lands on the next read, which rescans the project in full and memoizes the result. Two refreshes in a row therefore cost nothing extra, but refreshing before every read costs a full scan every time. The operation returns `void`, not an `OpResult`.
67
+ The call only drops the caches. The next read pays the cost, because it rescans the project in full and keeps the result. Two refreshes in a row cost nothing extra, and a refresh before every read costs a full scan every time. The operation returns `void`, not an `OpResult`.
64
68
 
65
- ## Create a Page
69
+ ## Create a page
66
70
 
67
- `CreatePage(input)` writes a new page file, wires it into the nearest barrel, and returns the ref it assigned along with the file it created.
71
+ `CreatePage(input)` writes a new page file and wires it into the nearest barrel. It returns the ref it assigned and the file it created. The new page uses `DefaultLayout({ fullWidth: true })`.
68
72
 
69
73
  ```typescript
70
74
  import { CreatePage } from "@antelopejs/interface-dms-builder";
@@ -85,16 +89,17 @@ if (result.ok) {
85
89
 
86
90
  | Option | Type | Description |
87
91
  | --- | --- | --- |
88
- | `name` | `string` | The page's route id/slug. Required. A duplicate fails with `duplicate_name`. |
92
+ | `name` | `string` | The page id and route segment. Required. It must be lowercase letters, digits and single dashes, or the call fails with `invalid_config`. A duplicate fails with `duplicate_name`. |
89
93
  | `displayName` | `string` | The label shown in the menu. Required. |
90
- | `category` | `CategoryRef` | The category to attach to. Required, and it must already exist. |
91
- | `icon` | `string` | Icon name. |
94
+ | `category` | `CategoryRef` | The category to attach to. Required. An unknown category fails with `not_found`. |
95
+ | `icon` | `string` | The icon name. |
92
96
  | `order` | `number` | Sort order within the category. |
93
97
  | `description` | `string` | The page's description. |
94
98
  | `permission` | `PagePermission` | The permission guarding the page. |
95
- | `dir` | `string` | Explicit folder, relative to the src root, overriding the default category-relative placement. |
99
+ | `dir` | `string` | A folder relative to the `src` root, which replaces the placement beside the category. |
100
+ | `module` | `string` | The project module to write into, by its id in the project configuration. Without it, the builder writes into the project's own module. The module must be a local module with an `src/index.ts`, and the page may only use declarations from that same module. A category declared in another module fails with `invalid_config`. |
96
101
 
97
- Without `dir`, the page lands at `<category-folder>/<name>/page.ts` when the category is declared in the project's source and has a barrel beside it, and at `src/<name>.ts` otherwise. With `dir`, it lands at `src/<dir>/<name>/page.ts`. Either way the nearest barrel above the file is wired, keeping a relative import chain up to `src/index.ts`. `dir` must stay inside the src tree; a `dir` that escapes it, or a project with no barrel to wire, fails with `unsupported`.
102
+ Without `dir`, the page goes to `<category-folder>/<name>/page.ts` when the project's source declares the category and an `index.ts` barrel sits beside it. Otherwise it goes to `src/<name>.ts`, next to the root barrel. With `dir`, it goes to `src/<dir>/<name>/page.ts`. In each case the builder wires the nearest barrel above the file, which keeps a relative import chain up to `src/index.ts`. `dir` must stay inside the `src` tree. A `dir` that leaves it, or a project with no barrel to wire, fails with `unsupported`.
98
103
 
99
104
  ```typescript
100
105
  import { CreatePage } from "@antelopejs/interface-dms-builder";
@@ -107,9 +112,9 @@ await CreatePage({
107
112
  });
108
113
  ```
109
114
 
110
- ## Configure a Page
115
+ ## Configure a page
111
116
 
112
- `ConfigurePage(ref, patch, opts?)` patches the page's metadata in place. The patch is a `Partial<EditablePageMeta>`; keys you leave out are untouched, and a key set to `undefined` is removed from the page's options.
117
+ `ConfigurePage(ref, patch, opts?)` patches the metadata of the page in place and returns its ref and the `version` of the page file it wrote. A draft held across the patch saves against that version. The patch is a `Partial<EditablePageMeta>`. Keys left out stay untouched, and a key set to `undefined` or `null` is removed from the options of the page. A page whose options are not a plain object literal fails with `unsupported`, because the builder needs a literal to rewrite.
113
118
 
114
119
  ```typescript
115
120
  import { ConfigurePage } from "@antelopejs/interface-dms-builder";
@@ -121,11 +126,11 @@ const result = await ConfigurePage("/revenue", {
121
126
  });
122
127
  ```
123
128
 
124
- ### Move a Page Between Categories
129
+ ### Move a page between categories
125
130
 
126
- A page's category decides its route, so patching `category` moves the page rather than editing a field. `ConfigurePage` rewrites the `category` option and its import, moves the file to the directory beside the new category — where `CreatePage` would have put it — and moves the registration with it, so each directory's barrel still lists what it holds. Relative imports inside the page are re-anchored to its new location.
131
+ The category of a page decides its route, so a patch of `category` moves the page. `ConfigurePage` rewrites the `category` option and its import. When the new category has an `index.ts` barrel beside it, the builder also moves the file to the folder where `CreatePage` would have put it, and moves the registration with it, so each barrel still lists what its folder holds. The builder rewrites the relative imports inside the page for its new location.
127
132
 
128
- The result carries the page's new `ref`, and a `route_changed` warning naming the old one. **Nothing redirects the old route**: links and bookmarks to it break.
133
+ The result carries the new `ref` of the page, and a `route_changed` warning names the old one. Nothing redirects the old route, so links and bookmarks to it break.
129
134
 
130
135
  ```typescript
131
136
  import { ConfigurePage } from "@antelopejs/interface-dms-builder";
@@ -134,20 +139,24 @@ const moved = await ConfigurePage("/form/revenue", { category: "pages.reports" }
134
139
  if (moved.ok) {
135
140
  console.log(moved.data.ref); // "/reports/revenue"
136
141
  for (const warning of moved.warnings ?? []) {
137
- console.log(warning.code, warning.message); // "route_changed", …
142
+ console.log(warning.code, warning.message); // "route_changed" and its message
138
143
  }
139
144
  }
140
145
  ```
141
146
 
142
- The move is refused when the target category is unknown (`not_found`), when it is built-in or not declared in source so a page cannot reference it (`unsupported`), or when the destination already holds a page of that name (`duplicate_name`). A page whose options are not a plain object literal fails with `unsupported` too — the builder rewrites source, so it needs a literal to rewrite.
147
+ The builder refuses the move in three cases:
148
+
149
+ - The target category is unknown. The call fails with `not_found`.
150
+ - The target category is built in or not declared in source, so a page cannot reference it. The call fails with `unsupported`.
151
+ - The destination already holds a page of that name. The call fails with `duplicate_name`.
143
152
 
144
153
  `opts` is a `MutationOpts`, so `expectedVersion` makes the write conditional.
145
154
 
146
- ## Delete a Page
155
+ ## Delete a page
147
156
 
148
- `DeletePage(ref, opts?)` removes the page file and unwires every import of it.
157
+ `DeletePage(ref, opts?)` removes the page class, with the constants, imports and generated model methods that only the page used. The builder deletes the file and removes its barrel import only when nothing but imports is left in it, because a hand-written page file can also declare a category that other pages import. `opts` is a `MutationOpts`.
149
158
 
150
- ```typescript
159
+ ```typescript fragment
151
160
  import { DeletePage } from "@antelopejs/interface-dms-builder";
152
161
 
153
162
  const result = await DeletePage("/revenue", { expectedVersion: version });
@@ -156,9 +165,9 @@ if (!result.ok && result.error.code === "stale") {
156
165
  }
157
166
  ```
158
167
 
159
- ## Create a Category
168
+ ## Create a category
160
169
 
161
- `CreateCategory(input)` declares a new category and registers it in the root barrel.
170
+ `CreateCategory(input)` writes the new category to `<name>.category.ts` beside the root barrel and imports that file from the barrel. A project with no root barrel fails with `unsupported`.
162
171
 
163
172
  ```typescript
164
173
  import { CreateCategory } from "@antelopejs/interface-dms-builder";
@@ -177,15 +186,16 @@ const result = await CreateCategory({
177
186
 
178
187
  | Option | Type | Description |
179
188
  | --- | --- | --- |
180
- | `name` | `string` | The category's id segment. Required. A duplicate fails with `duplicate_name`. |
189
+ | `name` | `string` | The id segment of the category. Required. It must be lowercase letters, digits and single dashes, or the call fails with `invalid_config`. A duplicate fails with `duplicate_name`. |
181
190
  | `displayName` | `string` | The label shown in the menu. Required. |
182
191
  | `parent` | `CategoryRef` | The parent category. Omit for a category under the root `pages`. |
183
- | `icon` | `string` | Icon name. |
192
+ | `icon` | `string` | The icon name. |
184
193
  | `order` | `number` | Sort order among siblings. |
194
+ | `module` | `string` | The project module to write into, as `CreatePageInput.module`. |
185
195
 
186
196
  A `parent` that does not exist fails with `not_found`.
187
197
 
188
- ## Configure a Category
198
+ ## Configure a category
189
199
 
190
200
  `ConfigureCategory(ref, patch)` patches an existing category. It takes no options argument.
191
201
 
@@ -198,11 +208,15 @@ await ConfigureCategory("pages.reports", {
198
208
  });
199
209
  ```
200
210
 
201
- Two refusals, both `unsupported`: re-parenting (a patch carrying `parent`), and a category that is built in or otherwise not declared in editable source.
211
+ An unknown category fails with `not_found`. Three refusals fail with `unsupported`:
212
+
213
+ - a patch that carries `parent`,
214
+ - a category that is built in or not declared in editable source,
215
+ - a category whose options are not a plain object literal.
202
216
 
203
- ## Delete a Category
217
+ ## Delete a category
204
218
 
205
- `DeleteCategory(ref)` removes the category declaration, and deletes its file when nothing but imports is left in it.
219
+ `DeleteCategory(ref)` removes the category declaration. When nothing but imports is left in its file, the builder deletes the file and the imports of it.
206
220
 
207
221
  ```typescript
208
222
  import { DeleteCategory } from "@antelopejs/interface-dms-builder";
@@ -213,11 +227,11 @@ if (!result.ok && result.error.code === "referential_integrity") {
213
227
  }
214
228
  ```
215
229
 
216
- A category that still holds pages or child categories fails with `referential_integrity`, and `blockedBy` lists the refs standing in the way. Empty it first.
230
+ A category that still holds pages, directly or through its subcategories, or that has child categories, fails with `referential_integrity`. `blockedBy` lists the refs of those pages and child categories. A built-in category, or one not declared in editable source, fails with `unsupported`.
217
231
 
218
- ## Add a Block
232
+ ## Add a block
219
233
 
220
- `AddBlock(input, opts?)` emits a factory call into the page and returns the `BlockPath` of the new block.
234
+ `AddBlock(input, opts?)` writes a factory call into the page and returns the `BlockPath` of the new block.
221
235
 
222
236
  ```typescript
223
237
  import { AddBlock } from "@antelopejs/interface-dms-builder";
@@ -243,18 +257,18 @@ if (result.ok) {
243
257
  | `page` | `PageRef` | The page to add to. Required. |
244
258
  | `name` | `string` | The block's name, unique among its siblings. Required. A duplicate fails with `duplicate_name`. |
245
259
  | `type` | `string` | A `BlockTypeDescriptor.type` from the catalog. Required. An unknown type fails with `unsupported`. |
246
- | `config` | `Record<string, unknown>` | The factory's options object. Required. |
260
+ | `config` | `ConfigObject` | The factory's options object. Required. |
247
261
  | `parent` | `BlockPath` | The container to nest under. Omit to add a top-level block. |
248
262
  | `slot` | `string` | The slot within the parent container. |
249
263
  | `index` | `number` | Position among siblings. Defaults to appending. |
250
- | `meta` | `Record<string, unknown>` | Child metadata emitted alongside `slot` in the third argument of `.child()`, such as `{ colSpan: 2 }`. Ignored for top-level blocks. |
264
+ | `meta` | `ConfigObject` | Child metadata emitted alongside `slot` in the third argument of `.child()`, such as `{ colSpan: 2 }`. Ignored for top-level blocks. |
251
265
  | `controller` | `ResourceRef` | The resource whose DataAPI class is the leading argument, for controller-leading block types. |
252
266
 
253
- `config` is plain JSON by default; values that are not literals — a DataType instance, a reference to a generated class — use the sentinel encodings in [Value Encodings](./7.values.md).
267
+ `config` is plain JSON by default. A value that is not a literal, such as a DataType instance or a reference to a generated class, uses the encodings in [Value encodings](./7.values.md).
254
268
 
255
- Nesting requires an editable container: a `parent` that resolves to an opaque block fails with `opaque_target`, and one that does not resolve at all fails with `not_found`. An out-of-range `index` is clamped, and the result carries an `index_clamped` warning.
269
+ A nested block needs an editable container. A `parent` that resolves to an opaque block fails with `opaque_target`, and a `parent` that does not resolve fails with `not_found`. The builder clamps an `index` out of range, and the result carries an `index_clamped` warning.
256
270
 
257
- Controller-leading types (catalog `controllerArg: true`, e.g. `TableView`) require `controller`; passing it for any other type is rejected. Both mismatches fail with `invalid_config`.
271
+ A block type whose catalog entry has `controllerArg: true`, such as `TableView`, requires `controller`. Any other type refuses it. Both mismatches fail with `invalid_config`.
258
272
 
259
273
  ```typescript
260
274
  import { AddBlock } from "@antelopejs/interface-dms-builder";
@@ -268,9 +282,9 @@ await AddBlock({
268
282
  });
269
283
  ```
270
284
 
271
- ## Configure a Block
285
+ ## Configure a block
272
286
 
273
- `ConfigureBlock(path, patch, opts?)` rewrites a block's options object. By default the patch merges: listed keys are replaced, unlisted keys survive, and a key set to `undefined` is removed.
287
+ `ConfigureBlock(path, patch, opts?)` rewrites the options object of a block. By default the patch merges. Listed keys are replaced, other keys stay, and a key set to `undefined` is removed.
274
288
 
275
289
  ```typescript
276
290
  import { ConfigureBlock } from "@antelopejs/interface-dms-builder";
@@ -287,9 +301,9 @@ await ConfigureBlock("/revenue#total", {
287
301
  | --- | --- | --- |
288
302
  | `replace` | `boolean` | Replace the whole options object instead of merging into it. |
289
303
  | `expectedVersion` | `string` | The `PageStructure.version` you last read. A mismatch fails with `stale`. |
290
- | `meta` | `Record<string, unknown>` | Patch child metadata (`slot`, `colSpan`, …). A key set to `undefined` is removed. Rejected for a top-level block, which has no `.child()` call. |
304
+ | `meta` | `ConfigObject` | A patch of the child metadata, such as `slot` or `colSpan`. A key set to `undefined` is removed. A top-level block has no `.child()` call to carry it, so it fails with `unsupported`. |
291
305
 
292
- Read the version before changing an existing child. Here `/revenue#grid/total` must already be a child of the page's grid:
306
+ The following example reads the version before it changes an existing child. `/revenue#grid/total` must already be a child of the grid of the page.
293
307
 
294
308
  ```ts docs-check
295
309
  import { ConfigureBlock, GetPageStructure } from "@antelopejs/interface-dms-builder";
@@ -306,9 +320,9 @@ export async function resizeRevenueCard() {
306
320
  }
307
321
  ```
308
322
 
309
- An opaque block fails with `opaque_target`: the builder can read it but not rewrite it.
323
+ An opaque block fails with `opaque_target`, because the builder can read it but cannot rewrite it.
310
324
 
311
- ## Move a Block
325
+ ## Move a block
312
326
 
313
327
  `MoveBlock(path, dest, opts?)` moves a child block within its container or into another one.
314
328
 
@@ -325,15 +339,15 @@ await MoveBlock("/revenue#grid/row/total", {
325
339
 
326
340
  | Option | Type | Description |
327
341
  | --- | --- | --- |
328
- | `parent` | `BlockPath` | The destination container. |
329
- | `slot` | `string` | The slot within the destination container. |
342
+ | `parent` | `BlockPath` | The destination container. Optional in the type, and required by the operation. |
343
+ | `slot` | `string` | Declared in the type, but `MoveBlock` does not read it. The block lands among the destination's children. |
330
344
  | `index` | `number` | Position among the destination's children. Required. |
331
345
 
332
- The move is a child-into-container operation: the path must address a nested block, and `dest.parent` must name a container. Anything else — a top-level block, a destination without a `parent` — fails with `unsupported`. An out-of-range `index` is clamped with an `index_clamped` warning, and a destination that is opaque or missing fails with `opaque_target` or `not_found`.
346
+ The path must address a nested block. A top-level block, or a destination without a `parent`, fails with `unsupported`. The builder clamps an `index` out of range and adds an `index_clamped` warning. An opaque destination fails with `opaque_target`, and a missing one fails with `not_found`.
333
347
 
334
- ## Remove a Block
348
+ ## Remove a block
335
349
 
336
- `RemoveBlock(path, opts?)` deletes a block. A top-level block is removed as a static member; a nested one is dropped from its parent's `.child()` chain.
350
+ `RemoveBlock(path, opts?)` deletes a block. The builder removes a top-level block as a static member, and drops a nested one from the `.child()` chain of its parent.
337
351
 
338
352
  ```typescript
339
353
  import { RemoveBlock } from "@antelopejs/interface-dms-builder";
@@ -344,7 +358,7 @@ if (result.ok) {
344
358
  }
345
359
  ```
346
360
 
347
- ## Next Steps
361
+ ## Next steps
348
362
 
349
- - [Resources](./5.resources.md) - Generate the tables and DataAPI controllers a page reads from
350
- - [Drafts and Preview](./9.drafts-and-preview.md) - Write a page's whole block tree in one transaction
363
+ - [Resources](./5.resources.md) generates the tables and DataAPI controllers a page reads from.
364
+ - [Drafts and preview](./9.drafts-and-preview.md) writes the whole block tree of a page in one transaction.