feat: expose permanent trash deletion in sdk

This commit is contained in:
mirivlad 2026-07-10 08:27:34 +08:00
parent 2b3c6d0557
commit dd9168dad5
10 changed files with 26 additions and 5 deletions

View File

@ -13,7 +13,7 @@ for that host-provided object:
- `commands.register/execute/executeFor` - `commands.register/execute/executeFor`
- `contributions.list` - `contributions.list`
- `events.publish/subscribe` - `events.publish/subscribe`
- `files.list/metadata/readText/readBytes/writeText/createFolder/move/trash/listTrash/restoreTrash` - `files.list/metadata/readText/readBytes/writeText/createFolder/move/trash/listTrash/restoreTrash/deleteTrash`
- `workbench.openResource/editResource` - `workbench.openResource/editResource`
- optional `dispose` - optional `dispose`

View File

@ -116,6 +116,7 @@ export interface VerstakPluginAPI {
trash(relativePath: string): Promise<TrashResult>; trash(relativePath: string): Promise<TrashResult>;
listTrash(): Promise<TrashEntry[]>; listTrash(): Promise<TrashEntry[]>;
restoreTrash(trashId: string, options?: RestoreTrashOptions): Promise<string>; restoreTrash(trashId: string, options?: RestoreTrashOptions): Promise<string>;
deleteTrash(trashId: string): Promise<void>;
openExternal(relativePath: string): Promise<void>; openExternal(relativePath: string): Promise<void>;
showInFolder(relativePath: string): Promise<void>; showInFolder(relativePath: string): Promise<void>;
}; };

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"version":3,"file":"plugin-api.js","sourceRoot":"","sources":["../src/plugin-api.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,8EAA8E;AAC9E,gDAAgD;AAqLhD,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;AACtF,CAAC"} {"version":3,"file":"plugin-api.js","sourceRoot":"","sources":["../src/plugin-api.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,8EAA8E;AAC9E,gDAAgD;AAsLhD,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;AACtF,CAAC"}

View File

@ -1 +1 @@
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,KAAK,EAAwB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQ3E,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,4BAA4B,CAAC;CAC9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAetF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CASnF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,SAAgB,EAAE,OAAO,GAAE,oBAAyB,GAAG,gBAAgB,CAqWlH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAgCxF;AAGD,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,EAAE,EAAE,CAAC"} {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,KAAK,EAAwB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQ3E,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,4BAA4B,CAAC;CAC9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAetF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CASnF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,SAAgB,EAAE,OAAO,GAAE,oBAAyB,GAAG,gBAAgB,CA2WlH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAgCxF;AAGD,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,EAAE,EAAE,CAAC"}

7
dist/test-utils.js vendored
View File

@ -363,6 +363,13 @@ export function createMockPluginAPI(pluginId = 'test.plugin', options = {}) {
trashEntries.splice(index, 1); trashEntries.splice(index, 1);
return target; return target;
}), }),
deleteTrash: vi.fn(async (trashId) => {
const index = trashEntries.findIndex((item) => item.trashId === trashId);
if (index < 0)
throw new Error(`not-found: trash entry ${trashId}`);
trashEntries.splice(index, 1);
trashPayloads.delete(trashId);
}),
openExternal: vi.fn(async (relativePath) => { openExternal: vi.fn(async (relativePath) => {
const path = normalizePath(relativePath); const path = normalizePath(relativePath);
if (!files.has(path)) if (!files.has(path))

File diff suppressed because one or more lines are too long

View File

@ -35,6 +35,7 @@ describe('VerstakPluginAPI contract', () => {
expect(typeof api.files.trash).toBe('function'); expect(typeof api.files.trash).toBe('function');
expect(typeof api.files.listTrash).toBe('function'); expect(typeof api.files.listTrash).toBe('function');
expect(typeof api.files.restoreTrash).toBe('function'); expect(typeof api.files.restoreTrash).toBe('function');
expect(typeof api.files.deleteTrash).toBe('function');
expect(typeof api.files.openExternal).toBe('function'); expect(typeof api.files.openExternal).toBe('function');
expect(typeof api.files.showInFolder).toBe('function'); expect(typeof api.files.showInFolder).toBe('function');
expect(typeof api.workbench.openResource).toBe('function'); expect(typeof api.workbench.openResource).toBe('function');
@ -359,6 +360,11 @@ describe('VerstakPluginAPI contract', () => {
expect.objectContaining({ relativePath: 'PlatformTest/image.bin', type: 'file' }), expect.objectContaining({ relativePath: 'PlatformTest/image.bin', type: 'file' }),
])); ]));
await expect(api.files.listTrash()).resolves.toEqual([]); await expect(api.files.listTrash()).resolves.toEqual([]);
const permanentlyDeleted = await api.files.trash('PlatformTest/two.txt');
await expect(api.files.deleteTrash(permanentlyDeleted.trashId)).resolves.toBeUndefined();
await expect(api.files.listTrash()).resolves.toEqual([]);
await expect(api.files.readText('PlatformTest/two.txt')).rejects.toThrow('not-found: PlatformTest/two.txt');
}); });
test('files mock rejects non-canonical and reserved paths', async () => { test('files mock rejects non-canonical and reserved paths', async () => {

View File

@ -157,6 +157,7 @@ export interface VerstakPluginAPI {
trash(relativePath: string): Promise<TrashResult>; trash(relativePath: string): Promise<TrashResult>;
listTrash(): Promise<TrashEntry[]>; listTrash(): Promise<TrashEntry[]>;
restoreTrash(trashId: string, options?: RestoreTrashOptions): Promise<string>; restoreTrash(trashId: string, options?: RestoreTrashOptions): Promise<string>;
deleteTrash(trashId: string): Promise<void>;
openExternal(relativePath: string): Promise<void>; openExternal(relativePath: string): Promise<void>;
showInFolder(relativePath: string): Promise<void>; showInFolder(relativePath: string): Promise<void>;
}; };

View File

@ -348,6 +348,12 @@ export function createMockPluginAPI(pluginId = 'test.plugin', options: MockPlugi
if (index >= 0) trashEntries.splice(index, 1); if (index >= 0) trashEntries.splice(index, 1);
return target; return target;
}), }),
deleteTrash: vi.fn(async (trashId: string) => {
const index = trashEntries.findIndex((item) => item.trashId === trashId);
if (index < 0) throw new Error(`not-found: trash entry ${trashId}`);
trashEntries.splice(index, 1);
trashPayloads.delete(trashId);
}),
openExternal: vi.fn(async (relativePath: string) => { openExternal: vi.fn(async (relativePath: string) => {
const path = normalizePath(relativePath); const path = normalizePath(relativePath);
if (!files.has(path)) throw new Error(`not-found: ${path}`); if (!files.has(path)) throw new Error(`not-found: ${path}`);