@workbench-kit/adapters 0.0.2-prototype.0.2.4 → 0.0.2-prototype.0.2.6
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.
- package/package.json +4 -4
- package/src/index.ts +8 -8
- package/src/library.ts +145 -145
- package/src/persistence.ts +26 -26
- package/src/runtime.ts +97 -97
- package/src/widget-studio-asset-package.ts +65 -65
- package/src/widget-studio-assets.ts +328 -328
- package/src/workbench-demo-config.ts +68 -68
- package/src/workbench-demo.ts +271 -271
- package/src/workspace.ts +126 -126
package/src/workspace.ts
CHANGED
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
import { normalizeWorkspacePath } from '@workbench-kit/workspace';
|
|
2
|
-
import type {
|
|
3
|
-
CreateWorkspaceFileInput,
|
|
4
|
-
WriteWorkspaceFileInput,
|
|
5
|
-
WorkspaceFile,
|
|
6
|
-
} from '@workbench-kit/workspace';
|
|
7
|
-
import type { SaveInput, WorkspaceFileRepository } from '@workbench-kit/contracts';
|
|
8
|
-
|
|
9
|
-
export interface WorkspaceFileRepositoryCallbacks {
|
|
10
|
-
createFile: (file: CreateWorkspaceFileInput) => void;
|
|
11
|
-
deleteFile: (path: string) => void;
|
|
12
|
-
saveFile: (path: string, file: WriteWorkspaceFileInput) => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface WorkspaceFileAdapterState {
|
|
16
|
-
getFiles: () => WorkspaceFile[];
|
|
17
|
-
files: WorkspaceFile[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const cloneFile = (file: WorkspaceFile): WorkspaceFile => ({ ...file });
|
|
21
|
-
|
|
22
|
-
function normalizeInputPath(path: string) {
|
|
23
|
-
return normalizeWorkspacePath(path.trim());
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class InMemoryWorkspaceFileRepository implements WorkspaceFileRepository {
|
|
27
|
-
private readonly files = new Map<string, WorkspaceFile>();
|
|
28
|
-
|
|
29
|
-
private readonly onCreateFile?: (file: CreateWorkspaceFileInput) => void;
|
|
30
|
-
private readonly onDeleteFile?: (path: string) => void;
|
|
31
|
-
private readonly onSaveFile?: (path: string, file: WriteWorkspaceFileInput) => void;
|
|
32
|
-
|
|
33
|
-
constructor(
|
|
34
|
-
files: readonly WorkspaceFile[] = [],
|
|
35
|
-
callbacks: {
|
|
36
|
-
onCreateFile?: (file: CreateWorkspaceFileInput) => void;
|
|
37
|
-
onDeleteFile?: (path: string) => void;
|
|
38
|
-
onSaveFile?: (path: string, file: WriteWorkspaceFileInput) => void;
|
|
39
|
-
} = {},
|
|
40
|
-
) {
|
|
41
|
-
files.forEach((file) => {
|
|
42
|
-
const path = normalizeWorkspacePath(file.path);
|
|
43
|
-
if (!path) return;
|
|
44
|
-
this.files.set(path, { ...file, path });
|
|
45
|
-
});
|
|
46
|
-
this.onCreateFile = callbacks.onCreateFile;
|
|
47
|
-
this.onDeleteFile = callbacks.onDeleteFile;
|
|
48
|
-
this.onSaveFile = callbacks.onSaveFile;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async deleteFile(path: string): Promise<void> {
|
|
52
|
-
const normalizedPath = normalizeInputPath(path);
|
|
53
|
-
if (!normalizedPath) return;
|
|
54
|
-
if (!this.files.has(normalizedPath)) return;
|
|
55
|
-
|
|
56
|
-
this.files.delete(normalizedPath);
|
|
57
|
-
this.onDeleteFile?.(normalizedPath);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async getFile(path: string): Promise<WorkspaceFile | null> {
|
|
61
|
-
const normalizedPath = normalizeInputPath(path);
|
|
62
|
-
if (!normalizedPath) return null;
|
|
63
|
-
|
|
64
|
-
const file = this.files.get(normalizedPath);
|
|
65
|
-
return file ? { ...file } : null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async listFiles(): Promise<readonly WorkspaceFile[]> {
|
|
69
|
-
return [...this.files.values()].map(cloneFile);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async writeFile(input: SaveInput): Promise<WorkspaceFile> {
|
|
73
|
-
const normalizedPath = normalizeInputPath(input.path);
|
|
74
|
-
if (!normalizedPath) {
|
|
75
|
-
throw new Error('Invalid workspace path.');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const current = await this.getFile(normalizedPath);
|
|
79
|
-
if (current && input.expectedUpdatedAt && current.updatedAt !== input.expectedUpdatedAt) {
|
|
80
|
-
throw new Error('Stale file version.');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const next: WorkspaceFile = {
|
|
84
|
-
content: input.content,
|
|
85
|
-
mimeType: input.mimeType ?? current?.mimeType,
|
|
86
|
-
path: normalizedPath,
|
|
87
|
-
source: input.source ?? current?.source,
|
|
88
|
-
updatedAt: input.updatedAt ?? current?.updatedAt,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
this.files.set(normalizedPath, next);
|
|
92
|
-
|
|
93
|
-
if (current) {
|
|
94
|
-
this.onSaveFile?.(normalizedPath, {
|
|
95
|
-
content: input.content,
|
|
96
|
-
source: input.source,
|
|
97
|
-
updatedAt: input.updatedAt,
|
|
98
|
-
});
|
|
99
|
-
} else {
|
|
100
|
-
this.onCreateFile?.({
|
|
101
|
-
content: input.content,
|
|
102
|
-
mimeType: input.mimeType,
|
|
103
|
-
path: normalizedPath,
|
|
104
|
-
source: input.source,
|
|
105
|
-
updatedAt: input.updatedAt,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return next;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function createWorkspaceFileRepository({
|
|
114
|
-
createFile,
|
|
115
|
-
deleteFile,
|
|
116
|
-
files,
|
|
117
|
-
saveFile,
|
|
118
|
-
}: WorkspaceFileRepositoryCallbacks & {
|
|
119
|
-
files: WorkspaceFile[];
|
|
120
|
-
}): WorkspaceFileRepository {
|
|
121
|
-
return new InMemoryWorkspaceFileRepository(files, {
|
|
122
|
-
onCreateFile: createFile,
|
|
123
|
-
onDeleteFile: deleteFile,
|
|
124
|
-
onSaveFile: (path, file) => saveFile(path, file),
|
|
125
|
-
});
|
|
126
|
-
}
|
|
1
|
+
import { normalizeWorkspacePath } from '@workbench-kit/workspace';
|
|
2
|
+
import type {
|
|
3
|
+
CreateWorkspaceFileInput,
|
|
4
|
+
WriteWorkspaceFileInput,
|
|
5
|
+
WorkspaceFile,
|
|
6
|
+
} from '@workbench-kit/workspace';
|
|
7
|
+
import type { SaveInput, WorkspaceFileRepository } from '@workbench-kit/contracts';
|
|
8
|
+
|
|
9
|
+
export interface WorkspaceFileRepositoryCallbacks {
|
|
10
|
+
createFile: (file: CreateWorkspaceFileInput) => void;
|
|
11
|
+
deleteFile: (path: string) => void;
|
|
12
|
+
saveFile: (path: string, file: WriteWorkspaceFileInput) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface WorkspaceFileAdapterState {
|
|
16
|
+
getFiles: () => WorkspaceFile[];
|
|
17
|
+
files: WorkspaceFile[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const cloneFile = (file: WorkspaceFile): WorkspaceFile => ({ ...file });
|
|
21
|
+
|
|
22
|
+
function normalizeInputPath(path: string) {
|
|
23
|
+
return normalizeWorkspacePath(path.trim());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class InMemoryWorkspaceFileRepository implements WorkspaceFileRepository {
|
|
27
|
+
private readonly files = new Map<string, WorkspaceFile>();
|
|
28
|
+
|
|
29
|
+
private readonly onCreateFile?: (file: CreateWorkspaceFileInput) => void;
|
|
30
|
+
private readonly onDeleteFile?: (path: string) => void;
|
|
31
|
+
private readonly onSaveFile?: (path: string, file: WriteWorkspaceFileInput) => void;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
files: readonly WorkspaceFile[] = [],
|
|
35
|
+
callbacks: {
|
|
36
|
+
onCreateFile?: (file: CreateWorkspaceFileInput) => void;
|
|
37
|
+
onDeleteFile?: (path: string) => void;
|
|
38
|
+
onSaveFile?: (path: string, file: WriteWorkspaceFileInput) => void;
|
|
39
|
+
} = {},
|
|
40
|
+
) {
|
|
41
|
+
files.forEach((file) => {
|
|
42
|
+
const path = normalizeWorkspacePath(file.path);
|
|
43
|
+
if (!path) return;
|
|
44
|
+
this.files.set(path, { ...file, path });
|
|
45
|
+
});
|
|
46
|
+
this.onCreateFile = callbacks.onCreateFile;
|
|
47
|
+
this.onDeleteFile = callbacks.onDeleteFile;
|
|
48
|
+
this.onSaveFile = callbacks.onSaveFile;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async deleteFile(path: string): Promise<void> {
|
|
52
|
+
const normalizedPath = normalizeInputPath(path);
|
|
53
|
+
if (!normalizedPath) return;
|
|
54
|
+
if (!this.files.has(normalizedPath)) return;
|
|
55
|
+
|
|
56
|
+
this.files.delete(normalizedPath);
|
|
57
|
+
this.onDeleteFile?.(normalizedPath);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async getFile(path: string): Promise<WorkspaceFile | null> {
|
|
61
|
+
const normalizedPath = normalizeInputPath(path);
|
|
62
|
+
if (!normalizedPath) return null;
|
|
63
|
+
|
|
64
|
+
const file = this.files.get(normalizedPath);
|
|
65
|
+
return file ? { ...file } : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async listFiles(): Promise<readonly WorkspaceFile[]> {
|
|
69
|
+
return [...this.files.values()].map(cloneFile);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async writeFile(input: SaveInput): Promise<WorkspaceFile> {
|
|
73
|
+
const normalizedPath = normalizeInputPath(input.path);
|
|
74
|
+
if (!normalizedPath) {
|
|
75
|
+
throw new Error('Invalid workspace path.');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const current = await this.getFile(normalizedPath);
|
|
79
|
+
if (current && input.expectedUpdatedAt && current.updatedAt !== input.expectedUpdatedAt) {
|
|
80
|
+
throw new Error('Stale file version.');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const next: WorkspaceFile = {
|
|
84
|
+
content: input.content,
|
|
85
|
+
mimeType: input.mimeType ?? current?.mimeType,
|
|
86
|
+
path: normalizedPath,
|
|
87
|
+
source: input.source ?? current?.source,
|
|
88
|
+
updatedAt: input.updatedAt ?? current?.updatedAt,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
this.files.set(normalizedPath, next);
|
|
92
|
+
|
|
93
|
+
if (current) {
|
|
94
|
+
this.onSaveFile?.(normalizedPath, {
|
|
95
|
+
content: input.content,
|
|
96
|
+
source: input.source,
|
|
97
|
+
updatedAt: input.updatedAt,
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
this.onCreateFile?.({
|
|
101
|
+
content: input.content,
|
|
102
|
+
mimeType: input.mimeType,
|
|
103
|
+
path: normalizedPath,
|
|
104
|
+
source: input.source,
|
|
105
|
+
updatedAt: input.updatedAt,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return next;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function createWorkspaceFileRepository({
|
|
114
|
+
createFile,
|
|
115
|
+
deleteFile,
|
|
116
|
+
files,
|
|
117
|
+
saveFile,
|
|
118
|
+
}: WorkspaceFileRepositoryCallbacks & {
|
|
119
|
+
files: WorkspaceFile[];
|
|
120
|
+
}): WorkspaceFileRepository {
|
|
121
|
+
return new InMemoryWorkspaceFileRepository(files, {
|
|
122
|
+
onCreateFile: createFile,
|
|
123
|
+
onDeleteFile: deleteFile,
|
|
124
|
+
onSaveFile: (path, file) => saveFile(path, file),
|
|
125
|
+
});
|
|
126
|
+
}
|