Skip to content

Commit 26972ff

Browse files
authored
feat: cli improvements, block deletion (#2360)
* feat: cli improvements, block deletion * chore: fix codegen sdk tests * fix(document-api): prevent silent data loss and incorrect ordinals in blocks.delete/deleteRange * chore: fix cli testS
1 parent e232129 commit 26972ff

40 files changed

Lines changed: 2249 additions & 204 deletions

apps/cli/README.md

Lines changed: 128 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,112 @@ Stateful editing flow (recommended for multi-step edits):
3030

3131
```bash
3232
superdoc open ./contract.docx
33-
superdoc find --type text --pattern "termination"
34-
superdoc replace --target-json '{"blockId":"p1","range":{"start":0,"end":11}}' --text "expiration"
33+
34+
# Use query match to find a mutation-grade target
35+
superdoc query match --select-json '{"type":"text","pattern":"termination"}' --require exactlyOne
36+
37+
# Mutate using the returned target
38+
superdoc replace --target-json '{"kind":"text","blockId":"p1","range":{"start":0,"end":11}}' --text "expiration"
39+
3540
superdoc save --in-place
3641
superdoc close
3742
```
3843

39-
Legacy compatibility commands (v0.x behavior):
44+
## Choosing the Right Command
45+
46+
### Which command should I use?
47+
48+
| I want to... | Use this command |
49+
|--------------|------------------|
50+
| Find a mutation target (block ID, text range) | `query match` |
51+
| Search/browse document content | `find` |
52+
| Insert inline text within a block | `insert` |
53+
| Create a new standalone paragraph | `create paragraph` |
54+
| Create a new heading | `create heading` |
55+
| Insert a list item before/after another list item | `lists insert` |
56+
| Apply formatting to a text range | `format apply` or format helpers (`format bold`, etc.) |
57+
| Apply multiple changes in one operation | `mutations apply` |
58+
59+
### Mutation targeting workflow
60+
61+
Always use `query match` to discover targets before mutating:
4062

4163
```bash
42-
superdoc search "indemnification" ./contracts/*.docx
43-
superdoc replace-legacy "ACME Corp" "Globex Inc" ./merger/*.docx
44-
superdoc read ./proposal.docx
64+
# Step 1: Find the target
65+
superdoc query match --select-json '{"type":"text","pattern":"Introduction"}' --require exactlyOne
66+
67+
# Step 2: Use the returned address in a mutation
68+
superdoc replace --block-id <returned-blockId> --start <start> --end <end> --text "Overview"
4569
```
4670

71+
`find` is for content discovery and inspection. `query match` is for mutation targeting — it returns exact addresses with cardinality guarantees.
72+
73+
### Block-oriented editing workflow
74+
75+
Use `blocks list` for ordered inspection, then `blocks delete-range` for contiguous removal:
76+
77+
```bash
78+
superdoc open ./contract.docx
79+
80+
# 1. Inspect block order, IDs, and text previews
81+
superdoc blocks list --limit 30
82+
83+
# 2. Preview the deletion (no mutation, shows what would be removed)
84+
superdoc blocks delete-range \
85+
--start-json '{"kind":"block","nodeType":"paragraph","nodeId":"abc123"}' \
86+
--end-json '{"kind":"block","nodeType":"paragraph","nodeId":"def456"}' \
87+
--dry-run
88+
89+
# 3. Apply the deletion
90+
superdoc blocks delete-range \
91+
--start-json '{"kind":"block","nodeType":"paragraph","nodeId":"abc123"}' \
92+
--end-json '{"kind":"block","nodeType":"paragraph","nodeId":"def456"}'
93+
94+
superdoc save --in-place
95+
```
96+
97+
This replaces the pattern of calling `blocks delete` once per block. A 17-block removal becomes one command.
98+
99+
### Preview-before-apply workflow
100+
101+
Use `--dry-run` and `--expected-revision` for safe, auditable mutations:
102+
103+
```bash
104+
superdoc open ./contract.docx
105+
106+
# 1. Check session state
107+
superdoc status
108+
109+
# 2. Find the mutation target
110+
superdoc query match --select-json '{"type":"text","pattern":"termination"}' --require exactlyOne
111+
112+
# 3. Preview the change (validates input, shows what would change, no mutation)
113+
superdoc replace --block-id p1 --start 0 --end 11 --text "expiration" --dry-run
114+
115+
# 4. Apply with revision guard (fails if document changed since preview)
116+
superdoc replace --block-id p1 --start 0 --end 11 --text "expiration" --expected-revision 1
117+
118+
superdoc save --in-place
119+
```
120+
121+
### Common mistakes
122+
123+
1. **Do not use `find` output to construct mutation targets.** `find` returns discovery-grade data, not mutation-grade addresses. Use `query match` instead.
124+
2. **Do not use `insert --block-id` for sibling block insertion.** `insert` inserts inline text *within* a block. To create a new block adjacent to another, use `create paragraph`, `create heading`, or `lists insert`.
125+
3. **Do not use `create paragraph` to continue a list.** If you want to add a list item adjacent to existing list items, use `lists insert`. `create paragraph` creates a standalone (non-list) paragraph.
126+
47127
## Command Index
48128

49129
| Category | Commands |
50130
|----------|----------|
51-
| query | `find`, `get-node`, `get-node-by-id`, `info` |
52-
| mutation | `insert`, `replace`, `delete` |
53-
| format | `format bold` |
54-
| create | `create paragraph` |
55-
| lists | `lists list`, `lists get`, `lists insert`, `lists set-type`, `lists indent`, `lists outdent`, `lists restart`, `lists exit` |
56-
| comments | `comments add`, `comments edit`, `comments reply`, `comments move`, `comments resolve`, `comments remove`, `comments set-internal`, `comments set-active`, `comments go-to`, `comments get`, `comments list` |
131+
| query | `find`, `query match`, `get-node`, `get-node-by-id`, `get-text`, `info` |
132+
| mutation | `insert`, `replace`, `delete`, `blocks delete`, `blocks delete-range`, `blocks list`, `mutations apply`, `mutations preview` |
133+
| format | `format apply`, `format bold`, `format italic`, `format underline`, `format strikethrough` |
134+
| create | `create paragraph`, `create heading`, `create table-of-contents` |
135+
| lists | `lists list`, `lists get`, `lists insert`, `lists create`, `lists attach`, `lists detach`, `lists join`, `lists separate`, `lists set-level`, `lists indent`, `lists outdent`, `lists set-value`, `lists set-type`, `lists convert-to-text` |
136+
| comments | `comments add`, `comments reply`, `comments delete`, `comments get`, `comments list` |
57137
| trackChanges | `track-changes list`, `track-changes get`, `track-changes accept`, `track-changes reject`, `track-changes accept-all`, `track-changes reject-all` |
138+
| history | `history get`, `history undo`, `history redo` |
58139
| lifecycle | `open`, `save`, `close` |
59140
| session | `session list`, `session save`, `session close`, `session set-default`, `session use` |
60141
| introspection | `status`, `describe`, `describe command` |
@@ -65,6 +146,7 @@ For full command help and examples, run:
65146

66147
```bash
67148
superdoc --help
149+
superdoc describe command <command-name>
68150
```
69151

70152
## v1 Breaking Changes
@@ -73,7 +155,7 @@ This CLI replaces the previous `@superdoc-dev/cli` package surface with the v1 c
73155

74156
| Legacy command | v1 status | Migration |
75157
|---------------|-----------|-----------|
76-
| `superdoc replace <find> <to> <files...>` | Renamed to `replace-legacy` | Use `replace-legacy`, or use `find` + `replace --target-json` for the v1 workflow. |
158+
| `superdoc replace <find> <to> <files...>` | Renamed to `replace-legacy` | Use `replace-legacy`, or use `query match` + `replace --target-json` for the v1 workflow. |
77159

78160
Legacy compatibility is retained for `search`, `read`, and `replace-legacy`.
79161

@@ -116,7 +198,7 @@ superdoc status
116198
```bash
117199
superdoc open ./contract.docx
118200
superdoc status
119-
superdoc find --type text --pattern "termination"
201+
superdoc query match --select-json '{"type":"text","pattern":"termination"}' --require exactlyOne
120202
superdoc replace --target-json '{...}' --text "Updated clause"
121203
superdoc save --in-place
122204
superdoc close
@@ -140,28 +222,45 @@ superdoc session close <sessionId> [--discard]
140222

141223
```bash
142224
superdoc info [<doc>]
143-
superdoc find [<doc>] --type text --pattern "termination"
144-
superdoc find [<doc>] --type run
225+
superdoc find [<doc>] --type text --pattern "termination" --limit 5
226+
superdoc query match [<doc>] --select-json '{"type":"text","pattern":"termination"}' --require exactlyOne
145227
superdoc get-node [<doc>] --address-json '{"kind":"block","nodeType":"paragraph","nodeId":"p1"}'
146228
superdoc get-node-by-id [<doc>] --id p1 --node-type paragraph
147229
```
148230

149-
- Flat `find` flags are convenience syntax and are normalized into the canonical query object used by `editor.doc.find`.
150-
- Use `--query-json` / `--query-file` for complex or programmatic queries.
151-
- For text queries, use `result.context[*].textRanges[*]` as targets for `replace`, `comments add`, and formatting commands.
231+
- `find` returns discovery-grade results for content search and browsing.
232+
- `query match` returns mutation-grade addresses and text ranges — use this before any mutation.
233+
- For text queries, use the returned `blocks[].range` as targets for `replace`, `comments add`, and formatting commands.
152234

153235
## Mutating commands
154236

155237
```bash
156-
superdoc comments add [<doc>] --target-json '{...}' --text "Please revise" [--out ./with-comment.docx]
157238
superdoc replace [<doc>] --target-json '{...}' --text "Updated text" [--out ./updated.docx]
239+
superdoc insert [<doc>] --value "New text" [--out ./inserted.docx]
240+
superdoc blocks delete [<doc>] --node-type paragraph --node-id abc123
241+
superdoc blocks delete-range --start-json '{"kind":"block",...}' --end-json '{"kind":"block",...}'
242+
superdoc create paragraph [<doc>] --text "New paragraph" [--at-json '{"kind":"after","target":{"kind":"block","nodeType":"paragraph","nodeId":"p1"}}']
243+
superdoc lists insert [<doc>] --node-id li1 --position after --text "New item"
158244
superdoc format bold [<doc>] --target-json '{...}' [--out ./bolded.docx]
245+
superdoc comments add [<doc>] --block-id p1 --start 0 --end 10 --text "Please revise" [--out ./with-comment.docx]
159246
```
160247

161248
- In stateless mode (`<doc>` provided), mutating commands require `--out`.
162249
- In stateful mode (after `open`), mutating commands update the active working document and `--out` is optional.
250+
- Use `--dry-run` to preview any mutation without applying it.
163251
- Use `--expected-revision <n>` with stateful mutating commands for optimistic concurrency checks.
164252

253+
## Block inspection
254+
255+
```bash
256+
superdoc blocks list
257+
superdoc blocks list --limit 20 --offset 10
258+
superdoc blocks list --node-types-json '["paragraph","heading"]'
259+
```
260+
261+
- Returns ordered block metadata: ordinal, nodeId, nodeType, textPreview, isEmpty.
262+
- Use the returned nodeIds as targets for `blocks delete`, `blocks delete-range`, or other block-oriented commands.
263+
165264
## Low-level invocation
166265

167266
```bash
@@ -215,6 +314,7 @@ superdoc info ./contract.docx --pretty
215314
- `--query-json`, `--query-file`
216315
- `--address-json`, `--address-file`
217316
- `--target-json`, `--target-file`
317+
- `--at-json`, `--at-file` (for `create paragraph`)
218318

219319
## Stdin support
220320

@@ -249,8 +349,14 @@ Error:
249349
{
250350
"ok": false,
251351
"error": {
252-
"code": "VALIDATION_ERROR",
253-
"message": "..."
352+
"code": "INVALID_TARGET",
353+
"message": "Expected paragraph:abc123 but found listItem:abc123.",
354+
"details": {
355+
"requestedNodeType": "paragraph",
356+
"actualNodeType": "listItem",
357+
"nodeId": "abc123",
358+
"remediation": "Use lists.insert to add an item to a list sequence."
359+
}
254360
},
255361
"meta": {
256362
"version": "1.0.0",

0 commit comments

Comments
 (0)