Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/cli/scripts/export-sdk-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const INTENT_NAMES = {
'doc.insert': 'insert_content',
'doc.replace': 'replace_content',
'doc.delete': 'delete_content',
'doc.blocks.delete': 'delete_block',
'doc.format.apply': 'format_apply',
'doc.format.fontSize': 'format_font_size',
'doc.format.fontFamily': 'format_font_family',
Expand Down
17 changes: 17 additions & 0 deletions apps/cli/src/__tests__/conformance/scenarios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,23 @@ export const SUCCESS_SCENARIOS = {
],
};
},
'doc.blocks.delete': async (harness: ConformanceHarness): Promise<ScenarioInvocation> => {
const stateDir = await harness.createStateDir('doc-blocks-delete-success');
const docPath = await harness.copyFixtureDoc('doc-blocks-delete');
const block = await harness.firstBlockMatch(docPath, stateDir);
return {
stateDir,
args: [
'blocks',
'delete',
docPath,
'--target-json',
JSON.stringify({ kind: 'block', nodeType: block.nodeType, nodeId: block.nodeId }),
'--out',
harness.createOutputPath('doc-blocks-delete-output'),
],
};
},
'doc.lists.list': async (harness: ConformanceHarness): Promise<ScenarioInvocation> => {
const stateDir = await harness.createStateDir('doc-lists-list-success');
const docPath = await harness.copyListFixtureDoc('doc-lists-list');
Expand Down
14 changes: 14 additions & 0 deletions apps/cli/src/__tests__/help-regression.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { describe, expect, test } from 'bun:test';
import { CLI_COMMAND_SPECS, CLI_HELP } from '../cli/commands';

describe('CLI help regression coverage', () => {
test('includes blocks.delete in help output', () => {
const blocksDeleteCommand = CLI_COMMAND_SPECS.find(
(spec) => !spec.alias && spec.operationId === 'doc.blocks.delete',
);

expect(blocksDeleteCommand).toBeDefined();
expect(CLI_HELP).toContain('blocks:');
expect(CLI_HELP).toContain(blocksDeleteCommand!.key);
});
});
16 changes: 16 additions & 0 deletions apps/cli/src/__tests__/lib/error-mapping.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { describe, expect, test } from 'bun:test';
import { mapInvokeError } from '../../lib/error-mapping';

describe('mapInvokeError', () => {
test('maps blocks.delete INVALID_INPUT errors to INVALID_ARGUMENT', () => {
const error = Object.assign(new Error('blocks.delete requires a target.'), {
code: 'INVALID_INPUT',
details: { field: 'target' },
});

const mapped = mapInvokeError('blocks.delete', error);
expect(mapped.code).toBe('INVALID_ARGUMENT');
expect(mapped.message).toBe('blocks.delete requires a target.');
expect(mapped.details).toEqual({ operationId: 'blocks.delete', details: { field: 'target' } });
});
});
1 change: 1 addition & 0 deletions apps/cli/src/cli/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ function buildHelpText(): string {
'mutation',
'format',
'create',
'blocks',
'lists',
'comments',
'trackChanges',
Expand Down
14 changes: 13 additions & 1 deletion apps/cli/src/cli/operation-hints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const SUCCESS_VERB: Record<CliExposedOperationId, string> = {
insert: 'inserted text',
replace: 'replaced text',
delete: 'deleted text',
'blocks.delete': 'deleted block',
'format.apply': 'applied style',
'format.fontSize': 'set font size',
'format.fontFamily': 'set font family',
Expand Down Expand Up @@ -96,6 +97,7 @@ export const OUTPUT_FORMAT: Record<CliExposedOperationId, OutputFormat> = {
insert: 'mutationReceipt',
replace: 'mutationReceipt',
delete: 'mutationReceipt',
'blocks.delete': 'plain',
'format.apply': 'mutationReceipt',
'format.fontSize': 'mutationReceipt',
'format.fontFamily': 'mutationReceipt',
Expand Down Expand Up @@ -145,6 +147,7 @@ export const RESPONSE_ENVELOPE_KEY: Record<CliExposedOperationId, string | null>
insert: null,
replace: null,
delete: null,
'blocks.delete': 'result',
'format.apply': null,
'format.fontSize': null,
'format.fontFamily': null,
Expand Down Expand Up @@ -204,7 +207,15 @@ export const RESPONSE_VALIDATION_KEY: Partial<Record<CliExposedOperationId, stri
* Operation family — determines which error-mapping rules apply.
* Explicit Record for compile-time completeness (no string-prefix heuristics).
*/
export type OperationFamily = 'trackChanges' | 'comments' | 'lists' | 'textMutation' | 'create' | 'query' | 'general';
export type OperationFamily =
| 'trackChanges'
| 'comments'
| 'lists'
| 'textMutation'
| 'create'
| 'blocks'
| 'query'
| 'general';

export const OPERATION_FAMILY: Record<CliExposedOperationId, OperationFamily> = {
find: 'query',
Expand All @@ -215,6 +226,7 @@ export const OPERATION_FAMILY: Record<CliExposedOperationId, OperationFamily> =
insert: 'textMutation',
replace: 'textMutation',
delete: 'textMutation',
'blocks.delete': 'blocks',
'format.apply': 'textMutation',
'format.fontSize': 'textMutation',
'format.fontFamily': 'textMutation',
Expand Down
4 changes: 4 additions & 0 deletions apps/cli/src/cli/operation-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,10 @@ const EXTRA_CLI_PARAMS: Partial<Record<string, CliOperationParamSpec[]>> = {
...LIST_TARGET_FLAT_PARAMS,
],
'doc.lists.exit': [{ name: 'input', kind: 'jsonFlag', flag: 'input-json', type: 'json' }, ...LIST_TARGET_FLAT_PARAMS],
'doc.blocks.delete': [
{ name: 'nodeType', kind: 'flag', flag: 'node-type', type: 'string' },
{ name: 'nodeId', kind: 'flag', flag: 'node-id', type: 'string' },
],
'doc.create.paragraph': [{ name: 'input', kind: 'jsonFlag', flag: 'input-json', type: 'json' }],
'doc.create.heading': [{ name: 'input', kind: 'jsonFlag', flag: 'input-json', type: 'json' }],
};
Expand Down
1 change: 1 addition & 0 deletions apps/cli/src/cli/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export type CliCategory =
| 'mutation'
| 'format'
| 'create'
| 'blocks'
| 'lists'
| 'comments'
| 'trackChanges'
Expand Down
47 changes: 46 additions & 1 deletion apps/cli/src/lib/error-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,46 @@ function mapCreateError(operationId: CliExposedOperationId, error: unknown, code
return new CliError('INVALID_ARGUMENT', message, { operationId, details });
}

if (code === 'TRACK_CHANGE_COMMAND_UNAVAILABLE' || code === 'CAPABILITY_UNAVAILABLE') {
if (code === 'TRACK_CHANGE_COMMAND_UNAVAILABLE') {
return new CliError('TRACK_CHANGE_COMMAND_UNAVAILABLE', message, { operationId, details });
}

if (code === 'CAPABILITY_UNAVAILABLE') {
const reason = (details as { reason?: string } | undefined)?.reason;
if (reason === 'tracked_mode_unsupported') {
return new CliError('TRACK_CHANGE_COMMAND_UNAVAILABLE', message, { operationId, details });
}
return new CliError('COMMAND_FAILED', message, { operationId, details });
}

if (code === 'COMMAND_UNAVAILABLE') {
return new CliError('COMMAND_FAILED', message, { operationId, details });
}

if (error instanceof CliError) return error;
return new CliError('COMMAND_FAILED', message, { operationId, details });
}

function mapBlocksError(operationId: CliExposedOperationId, error: unknown, code: string | undefined): CliError {
const message = extractErrorMessage(error);
const details = extractErrorDetails(error);

if (code === 'TARGET_NOT_FOUND') {
return new CliError('TARGET_NOT_FOUND', message, { operationId, details });
}

if (code === 'AMBIGUOUS_TARGET' || code === 'INVALID_TARGET' || code === 'INVALID_INPUT') {
return new CliError('INVALID_ARGUMENT', message, { operationId, details });
}

if (code === 'CAPABILITY_UNAVAILABLE') {
const reason = (details as { reason?: string } | undefined)?.reason;
if (reason === 'tracked_mode_unsupported') {
return new CliError('TRACK_CHANGE_COMMAND_UNAVAILABLE', message, { operationId, details });
}
return new CliError('COMMAND_FAILED', message, { operationId, details });
}

if (code === 'COMMAND_UNAVAILABLE') {
return new CliError('COMMAND_FAILED', message, { operationId, details });
}
Expand Down Expand Up @@ -170,6 +206,7 @@ const FAMILY_MAPPERS: Record<
lists: mapListsError,
textMutation: mapTextMutationError,
create: mapCreateError,
blocks: mapBlocksError,
query: mapQueryError,
general: (operationId, error) => {
if (error instanceof CliError) return error;
Expand Down Expand Up @@ -272,6 +309,14 @@ export function mapFailedReceipt(operationId: CliExposedOperationId, result: unk
return new CliError('COMMAND_FAILED', failureMessage, { operationId, failure });
}

// Blocks family
if (family === 'blocks') {
if (failureCode === 'INVALID_TARGET') {
return new CliError('INVALID_ARGUMENT', failureMessage, { operationId, failure });
}
return new CliError('COMMAND_FAILED', failureMessage, { operationId, failure });
}

// Create family
if (family === 'create') {
if (failureCode === 'TRACK_CHANGE_COMMAND_UNAVAILABLE') {
Expand Down
14 changes: 14 additions & 0 deletions apps/cli/src/lib/invoke-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,20 @@ function normalizeFlatTargetFlags(operationId: CliExposedOperationId, apiInput:
return apiInput;
}

// --- Block delete (nodeType + nodeId → block target) ---
if (operationId === 'blocks.delete') {
const nodeType = apiInput.nodeType;
const nodeId = apiInput.nodeId;
if (typeof nodeType === 'string' && typeof nodeId === 'string') {
const { nodeType: _, nodeId: _n, ...rest } = apiInput;
return {
...rest,
target: { kind: 'block', nodeType, nodeId },
};
}
return apiInput;
}

// --- List operations (nodeId → listItem block target) ---
if (LIST_TARGET_OPERATIONS.has(operationId)) {
const nodeId = apiInput.nodeId;
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/document-api/available-operations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Use the tables below to see what operations are available and where each one is

| Namespace | Canonical ops | Aliases | Total surface | Reference |
| --- | --- | --- | --- | --- |
| Blocks | 1 | 0 | 1 | [Reference](/document-api/reference/blocks/index) |
| Capabilities | 1 | 0 | 1 | [Reference](/document-api/reference/capabilities/index) |
| Comments | 5 | 0 | 5 | [Reference](/document-api/reference/comments/index) |
| Core | 8 | 0 | 8 | [Reference](/document-api/reference/core/index) |
Expand All @@ -26,6 +27,7 @@ Use the tables below to see what operations are available and where each one is

| Editor method | Operation |
| --- | --- |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><code>editor.doc.blocks.delete(...)</code></span> | [`blocks.delete`](/document-api/reference/blocks/delete) |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><code>editor.doc.capabilities()</code></span> | [`capabilities.get`](/document-api/reference/capabilities/get) |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><code>editor.doc.comments.create(...)</code></span> | [`comments.create`](/document-api/reference/comments/create) |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><code>editor.doc.comments.patch(...)</code></span> | [`comments.patch`](/document-api/reference/comments/patch) |
Expand Down
11 changes: 10 additions & 1 deletion apps/docs/document-api/reference/_generated-manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"contractVersion": "0.1.0",
"files": [
"apps/docs/document-api/reference/blocks/delete.mdx",
"apps/docs/document-api/reference/blocks/index.mdx",
"apps/docs/document-api/reference/capabilities/get.mdx",
"apps/docs/document-api/reference/capabilities/index.mdx",
"apps/docs/document-api/reference/comments/create.mdx",
Expand Down Expand Up @@ -56,6 +58,13 @@
"pagePath": "apps/docs/document-api/reference/core/index.mdx",
"title": "Core"
},
{
"aliasMemberPaths": [],
"key": "blocks",
"operationIds": ["blocks.delete"],
"pagePath": "apps/docs/document-api/reference/blocks/index.mdx",
"title": "Blocks"
},
{
"aliasMemberPaths": [],
"key": "capabilities",
Expand Down Expand Up @@ -123,5 +132,5 @@
}
],
"marker": "{/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */}",
"sourceHash": "80b39063fa1bd5bf9ba81bada2ad7e8602d0851ba76d002258aae2328f207cfe"
"sourceHash": "f1dc053325c2b7209ee7484bcbf22071c725163fb5ab3f23a71ce1f6f7328896"
}
Loading
Loading