@workbench-kit/workbench-config 0.0.1-prototype.0

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.
Files changed (2) hide show
  1. package/package.json +35 -0
  2. package/src/index.ts +202 -0
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@workbench-kit/workbench-config",
3
+ "version": "0.0.1-prototype.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./src/index.ts"
8
+ },
9
+ "dependencies": {
10
+ "@workbench-kit/base": "0.0.1-prototype.0",
11
+ "@workbench-kit/platform": "0.0.1-prototype.0"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "!src/**/*.test.ts",
16
+ "!src/**/*.test.tsx",
17
+ "!src/**/*.stories.ts",
18
+ "!src/**/*.stories.tsx"
19
+ ],
20
+ "description": "Workbench workspace configuration parsing and validation for .workbench files.",
21
+ "publishConfig": {
22
+ "access": "public",
23
+ "tag": "prototype",
24
+ "provenance": true
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/NewChoBo/workbench-kit.git",
29
+ "directory": "packages/workbench-config"
30
+ },
31
+ "scripts": {
32
+ "test": "vitest run src",
33
+ "typecheck": "tsc -p tsconfig.json --noEmit"
34
+ }
35
+ }
package/src/index.ts ADDED
@@ -0,0 +1,202 @@
1
+ export const WORKBENCH_KIT_WORKBENCH_CONFIG_VERSION = '0.0.0' as const;
2
+
3
+ export const WORKBENCH_CONFIG_DIR = '.workbench' as const;
4
+
5
+ export type WorkbenchConfigFileName =
6
+ | 'workspace.json'
7
+ | 'settings.json'
8
+ | 'keybindings.json'
9
+ | 'extensions.json'
10
+ | 'extensions.lock.json'
11
+ | 'layout.default.json'
12
+ | 'tasks.json';
13
+
14
+ export interface WorkbenchExtensionsConfig {
15
+ enabled: readonly string[];
16
+ recommendations: readonly string[];
17
+ }
18
+
19
+ export interface WorkbenchLayoutConfig {
20
+ readonly activityBar: {
21
+ readonly visible: boolean;
22
+ };
23
+ readonly panel: {
24
+ readonly visible: boolean;
25
+ };
26
+ readonly sideBar: {
27
+ readonly activeViewContainer?: string;
28
+ readonly visible: boolean;
29
+ };
30
+ }
31
+
32
+ export type WorkbenchLayoutConfigInput = Partial<{
33
+ activityBar: Partial<WorkbenchLayoutConfig['activityBar']>;
34
+ panel: Partial<WorkbenchLayoutConfig['panel']>;
35
+ sideBar: Partial<WorkbenchLayoutConfig['sideBar']>;
36
+ }>;
37
+
38
+ export const DEFAULT_WORKBENCH_LAYOUT_CONFIG: WorkbenchLayoutConfig = {
39
+ activityBar: {
40
+ visible: true,
41
+ },
42
+ panel: {
43
+ visible: false,
44
+ },
45
+ sideBar: {
46
+ visible: true,
47
+ },
48
+ };
49
+
50
+ export class WorkbenchConfigValidationError extends Error {
51
+ constructor(message: string) {
52
+ super(message);
53
+ this.name = 'WorkbenchConfigValidationError';
54
+ }
55
+ }
56
+
57
+ export function parseWorkbenchExtensionsConfig(input: unknown): WorkbenchExtensionsConfig {
58
+ const record = assertRecord(input, 'extensions config');
59
+
60
+ return {
61
+ enabled: readOptionalStringArray(record, 'enabled'),
62
+ recommendations: readOptionalStringArray(record, 'recommendations'),
63
+ };
64
+ }
65
+
66
+ export function parseWorkbenchExtensionsConfigJson(jsonText: string): WorkbenchExtensionsConfig {
67
+ try {
68
+ return parseWorkbenchExtensionsConfig(JSON.parse(jsonText) as unknown);
69
+ } catch (error) {
70
+ if (error instanceof WorkbenchConfigValidationError) {
71
+ throw error;
72
+ }
73
+
74
+ throw new WorkbenchConfigValidationError('Expected extensions config to be valid JSON.');
75
+ }
76
+ }
77
+
78
+ export function parseWorkbenchLayoutConfig(input: unknown): WorkbenchLayoutConfig {
79
+ const record = assertRecord(input, 'layout config');
80
+ assertKnownKeys(record, ['activityBar', 'panel', 'sideBar'], 'layout config');
81
+
82
+ const activityBar = readOptionalRecord(record, 'activityBar');
83
+ const panel = readOptionalRecord(record, 'panel');
84
+ const sideBar = readOptionalRecord(record, 'sideBar');
85
+
86
+ assertKnownKeys(activityBar, ['visible'], 'layout config activityBar');
87
+ assertKnownKeys(panel, ['visible'], 'layout config panel');
88
+ assertKnownKeys(sideBar, ['activeViewContainer', 'visible'], 'layout config sideBar');
89
+
90
+ return {
91
+ activityBar: {
92
+ visible: readOptionalBoolean(
93
+ activityBar,
94
+ 'visible',
95
+ DEFAULT_WORKBENCH_LAYOUT_CONFIG.activityBar.visible,
96
+ ),
97
+ },
98
+ panel: {
99
+ visible: readOptionalBoolean(panel, 'visible', DEFAULT_WORKBENCH_LAYOUT_CONFIG.panel.visible),
100
+ },
101
+ sideBar: {
102
+ ...readOptionalLayoutId(sideBar, 'activeViewContainer'),
103
+ visible: readOptionalBoolean(
104
+ sideBar,
105
+ 'visible',
106
+ DEFAULT_WORKBENCH_LAYOUT_CONFIG.sideBar.visible,
107
+ ),
108
+ },
109
+ };
110
+ }
111
+
112
+ export function parseWorkbenchLayoutConfigJson(jsonText: string): WorkbenchLayoutConfig {
113
+ try {
114
+ return parseWorkbenchLayoutConfig(JSON.parse(jsonText) as unknown);
115
+ } catch (error) {
116
+ if (error instanceof WorkbenchConfigValidationError) {
117
+ throw error;
118
+ }
119
+
120
+ throw new WorkbenchConfigValidationError('Expected layout config to be valid JSON.');
121
+ }
122
+ }
123
+
124
+ function assertRecord(value: unknown, label: string): Record<string, unknown> {
125
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
126
+ throw new WorkbenchConfigValidationError(`Expected ${label} to be an object.`);
127
+ }
128
+
129
+ return value as Record<string, unknown>;
130
+ }
131
+
132
+ function readOptionalRecord(record: Record<string, unknown>, key: string): Record<string, unknown> {
133
+ const value = record[key];
134
+ if (value === undefined) {
135
+ return {};
136
+ }
137
+
138
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
139
+ throw new WorkbenchConfigValidationError(`Expected "${key}" to be an object.`);
140
+ }
141
+
142
+ return value as Record<string, unknown>;
143
+ }
144
+
145
+ function readOptionalStringArray(
146
+ record: Record<string, unknown>,
147
+ key: keyof WorkbenchExtensionsConfig,
148
+ ): readonly string[] {
149
+ const value = record[key];
150
+ if (value === undefined) {
151
+ return [];
152
+ }
153
+
154
+ if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
155
+ throw new WorkbenchConfigValidationError(`Expected "${key}" to be an array of strings.`);
156
+ }
157
+
158
+ return [...value];
159
+ }
160
+
161
+ function readOptionalBoolean(
162
+ record: Record<string, unknown>,
163
+ key: string,
164
+ fallback: boolean,
165
+ ): boolean {
166
+ const value = record[key];
167
+ if (value === undefined) {
168
+ return fallback;
169
+ }
170
+
171
+ if (typeof value !== 'boolean') {
172
+ throw new WorkbenchConfigValidationError(`Expected "${key}" to be a boolean.`);
173
+ }
174
+
175
+ return value;
176
+ }
177
+
178
+ function readOptionalLayoutId(
179
+ record: Record<string, unknown>,
180
+ key: string,
181
+ ): { readonly activeViewContainer?: string } {
182
+ const value = record[key];
183
+ if (value === undefined) {
184
+ return {};
185
+ }
186
+
187
+ if (typeof value !== 'string' || value.trim().length === 0) {
188
+ throw new WorkbenchConfigValidationError(`Expected "${key}" to be a non-empty string.`);
189
+ }
190
+
191
+ return {
192
+ activeViewContainer: value,
193
+ };
194
+ }
195
+
196
+ function assertKnownKeys(record: Record<string, unknown>, keys: readonly string[], label: string) {
197
+ const knownKeys = new Set(keys);
198
+ const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key));
199
+ if (unknownKeys.length > 0) {
200
+ throw new WorkbenchConfigValidationError(`Unexpected ${label} field "${unknownKeys[0]}".`);
201
+ }
202
+ }