Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -1090,5 +1090,5 @@
}
],
"marker": "{/* GENERATED FILE: DO NOT EDIT. Regenerate via `pnpm run docapi:sync`. */}",
"sourceHash": "b7a0382edb33e88b28f1af627a89d6a0b441890883e30993390a76c756214e4c"
"sourceHash": "b03f74e26212692ef1ae1b4fd5a6f497588c8524a993267c43ea79338cf5733b"
}
6 changes: 3 additions & 3 deletions apps/docs/document-api/reference/capabilities/get.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4394,12 +4394,12 @@ _No fields._
"tables.deleteColumn": {
"available": true,
"dryRun": true,
"tracked": true
"tracked": false
},
"tables.deleteRow": {
"available": true,
"dryRun": true,
"tracked": true
"tracked": false
},
"tables.distributeColumns": {
"available": true,
Expand Down Expand Up @@ -4439,7 +4439,7 @@ _No fields._
"tables.insertColumn": {
"available": true,
"dryRun": true,
"tracked": true
"tracked": false
},
"tables.insertRow": {
"available": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Delete a column from the target table.
- API member path: `editor.doc.tables.deleteColumn(...)`
- Mutates document: `yes`
- Idempotency: `conditional`
- Supports tracked mode: `yes`
- Supports tracked mode: `no`
- Supports dry run: `yes`
- Deterministic target resolution: `yes`

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/document-api/reference/tables/delete-row.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Delete a row from the target table.
- API member path: `editor.doc.tables.deleteRow(...)`
- Mutates document: `yes`
- Idempotency: `conditional`
- Supports tracked mode: `yes`
- Supports tracked mode: `no`
- Supports dry run: `yes`
- Deterministic target resolution: `yes`

Expand Down
6 changes: 3 additions & 3 deletions apps/docs/document-api/reference/tables/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ For non-destructive table-targeted mutations, reuse `result.table.nodeId` from t
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/convert-to-text"><code>tables.convertToText</code></a></span> | `tables.convertToText` | Yes | `conditional` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/set-layout"><code>tables.setLayout</code></a></span> | `tables.setLayout` | Yes | `idempotent` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/insert-row"><code>tables.insertRow</code></a></span> | `tables.insertRow` | Yes | `non-idempotent` | Yes | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/delete-row"><code>tables.deleteRow</code></a></span> | `tables.deleteRow` | Yes | `conditional` | Yes | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/delete-row"><code>tables.deleteRow</code></a></span> | `tables.deleteRow` | Yes | `conditional` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/set-row-height"><code>tables.setRowHeight</code></a></span> | `tables.setRowHeight` | Yes | `idempotent` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/distribute-rows"><code>tables.distributeRows</code></a></span> | `tables.distributeRows` | Yes | `conditional` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/set-row-options"><code>tables.setRowOptions</code></a></span> | `tables.setRowOptions` | Yes | `idempotent` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/insert-column"><code>tables.insertColumn</code></a></span> | `tables.insertColumn` | Yes | `non-idempotent` | Yes | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/delete-column"><code>tables.deleteColumn</code></a></span> | `tables.deleteColumn` | Yes | `conditional` | Yes | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/insert-column"><code>tables.insertColumn</code></a></span> | `tables.insertColumn` | Yes | `non-idempotent` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/delete-column"><code>tables.deleteColumn</code></a></span> | `tables.deleteColumn` | Yes | `conditional` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/set-column-width"><code>tables.setColumnWidth</code></a></span> | `tables.setColumnWidth` | Yes | `idempotent` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/distribute-columns"><code>tables.distributeColumns</code></a></span> | `tables.distributeColumns` | Yes | `conditional` | No | Yes |
| <span style={{ whiteSpace: 'nowrap', wordBreak: 'normal', overflowWrap: 'normal' }}><a href="/document-api/reference/tables/insert-cell"><code>tables.insertCell</code></a></span> | `tables.insertCell` | Yes | `non-idempotent` | No | Yes |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Insert a new column into the target table. The new column is cloned from an adja
- API member path: `editor.doc.tables.insertColumn(...)`
- Mutates document: `yes`
- Idempotency: `non-idempotent`
- Supports tracked mode: `yes`
- Supports tracked mode: `no`
- Supports dry run: `yes`
- Deterministic target resolution: `yes`

Expand Down
20 changes: 17 additions & 3 deletions packages/document-api/src/contract/operation-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@
// ---------------------------------------------------------------------------
const NONE_FAILURES: readonly ReceiptFailureCode[] = [];
const NONE_THROWS: readonly PreApplyThrowCode[] = [];
const INVALID_FRAGMENT_FAILURES: readonly ReceiptFailureCode[] = ['INVALID_FRAGMENT'];

Check warning on line 509 in packages/document-api/src/contract/operation-definitions.ts

View workflow job for this annotation

GitHub Actions / build

'INVALID_FRAGMENT_FAILURES' is assigned a value but never used. Allowed unused vars must match /^_/u
const FOOTNOTE_MUTATION_FAILURES: readonly ReceiptFailureCode[] = ['INVALID_FRAGMENT', 'CAPABILITY_UNAVAILABLE'];
function readOperation(
options: {
Expand Down Expand Up @@ -2852,7 +2852,13 @@
metadata: mutationOperation({
idempotency: 'conditional',
supportsDryRun: true,
supportsTrackedMode: true,
// Row-level structural deletion cannot be represented as a decidable
// tracked change in the current review model (only whole-table
// insert/delete is decidable; see structuralRowChanges.js). Reported as
// unsupported so a tracked call is rejected loudly rather than silently
// applied as a direct (untracked) deletion, which would be data loss in
// suggesting mode.
supportsTrackedMode: false,
possibleFailureCodes: ['INVALID_TARGET', 'NO_OP'],
throws: [...T_NOT_FOUND_COMMAND, 'INVALID_TARGET'],
}),
Expand Down Expand Up @@ -2922,7 +2928,11 @@
metadata: mutationOperation({
idempotency: 'non-idempotent',
supportsDryRun: true,
supportsTrackedMode: true,
// Column structure changes have no structural tracked-change
// representation (OOXML tracks rows, not columns, via <w:ins>/<w:del> in
// <w:trPr>). Reported as unsupported so a tracked call is rejected loudly
// rather than silently applied directly.
supportsTrackedMode: false,
possibleFailureCodes: ['INVALID_TARGET'],
throws: [...T_NOT_FOUND_COMMAND, 'INVALID_TARGET'],
}),
Expand All @@ -2939,7 +2949,11 @@
metadata: mutationOperation({
idempotency: 'conditional',
supportsDryRun: true,
supportsTrackedMode: true,
// Column structure changes have no structural tracked-change
// representation (OOXML tracks rows, not columns). Reported as
// unsupported so a tracked call is rejected loudly rather than silently
// applied as a direct (untracked) deletion.
supportsTrackedMode: false,
possibleFailureCodes: ['INVALID_TARGET', 'NO_OP'],
throws: [...T_NOT_FOUND_COMMAND, 'INVALID_TARGET'],
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12214,6 +12214,12 @@ describe('document-api adapter conformance', () => {
'tables.setRowOptions',
'tables.setColumnWidth',
'tables.distributeColumns',
// Row/column structural ops cannot produce a decidable tracked change in
// the review model (only whole-table insert/delete is decidable), so they
// report supportsTrackedMode: false and reject changeMode: 'tracked'.
'tables.deleteRow',
'tables.insertColumn',
'tables.deleteColumn',
'tables.convertFromText',
'tables.split',
'tables.convertToText',
Expand Down Expand Up @@ -12254,10 +12260,9 @@ describe('document-api adapter conformance', () => {
const trackedTableOps: OperationId[] = [
'create.table',
'tables.delete',
// tables.insertRow stamps a structural rowInsert revision that exports as
// <w:ins>; the row/column structural ops do not support tracked mode.
'tables.insertRow',
'tables.deleteRow',
'tables.insertColumn',
'tables.deleteColumn',
] as OperationId[];

for (const opId of trackedTableOps) {
Expand All @@ -12283,28 +12288,45 @@ describe('document-api adapter conformance', () => {
{ changeMode: 'tracked' },
);
expect(insertRowResult.success).toBe(true);
});

// tables.deleteRow with tracked mode
const deleteRowResult = tablesDeleteRowWrapper(editor, { nodeId: 'table-1', rowIndex: 0 } as any, {
changeMode: 'tracked',
});
expect(deleteRowResult.success).toBe(true);
it('rejects changeMode=tracked with CAPABILITY_UNAVAILABLE for row/column structural ops', () => {
// deleteRow/insertColumn/deleteColumn cannot produce a decidable tracked
// change in the review model, so they must fail loudly rather than silently
// applying directly (which for the deletes is data loss in suggesting mode).
const editor = makeTableEditor({ insertTrackedChange: vi.fn(() => true) });
(editor as any).options = { user: { name: 'Agent', email: 'agent@test.com' } };
initRevision(editor);

// tables.insertColumn with tracked mode
const insertColResult = tablesInsertColumnWrapper(
editor,
{ nodeId: 'table-1', columnIndex: 0, position: 'right' },
{ changeMode: 'tracked' },
);
expect(insertColResult.success).toBe(true);
const expectCapabilityUnavailable = (fn: () => unknown, opId: string) => {
let capturedCode: string | null = null;
try {
fn();
} catch (error) {
capturedCode = (error as { code?: string }).code ?? null;
}
expect(capturedCode, `${opId} should throw CAPABILITY_UNAVAILABLE in tracked mode`).toBe(
'CAPABILITY_UNAVAILABLE',
);
};

// tables.deleteColumn with tracked mode
const deleteColResult = tablesDeleteColumnWrapper(
editor,
{ nodeId: 'table-1', columnIndex: 0 },
{ changeMode: 'tracked' },
expectCapabilityUnavailable(
() => tablesDeleteRowWrapper(editor, { nodeId: 'table-1', rowIndex: 0 } as any, { changeMode: 'tracked' }),
'tables.deleteRow',
);
expectCapabilityUnavailable(
() =>
tablesInsertColumnWrapper(
editor,
{ nodeId: 'table-1', columnIndex: 0, position: 'right' },
{ changeMode: 'tracked' },
),
'tables.insertColumn',
);
expectCapabilityUnavailable(
() => tablesDeleteColumnWrapper(editor, { nodeId: 'table-1', columnIndex: 0 }, { changeMode: 'tracked' }),
'tables.deleteColumn',
);
expect(deleteColResult.success).toBe(true);
});

// ---------------------------------------------------------------------------
Expand Down
Loading
Loading