@workbench-kit/workbench-config 0.0.2-prototype.0.2.4 → 0.0.2-prototype.0.2.40

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 CHANGED
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "name": "@workbench-kit/workbench-config",
3
- "version": "0.0.2-prototype.0.2.4",
3
+ "version": "0.0.2-prototype.0.2.40",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./src/index.ts"
8
8
  },
9
- "dependencies": {
10
- "@workbench-kit/base": "0.0.2-prototype.0.2.4",
11
- "@workbench-kit/platform": "0.0.2-prototype.0.2.4"
12
- },
13
9
  "files": [
14
10
  "src",
15
11
  "!src/**/*.test.ts",
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
+ import { assertKnownKeys, assertRecord, parseConfigJson } from './parse-helpers.js';
1
2
  import { WorkbenchConfigValidationError } from './validation-error.js';
2
3
 
3
- export const WORKBENCH_KIT_WORKBENCH_CONFIG_VERSION = '0.0.0' as const;
4
-
5
4
  export const WORKBENCH_CONFIG_DIR = '.workbench' as const;
6
5
 
7
6
  export type WorkbenchConfigFileName =
@@ -19,6 +18,16 @@ export interface WorkbenchExtensionsConfig {
19
18
  recommendations: readonly string[];
20
19
  }
21
20
 
21
+ export interface WorkbenchExtensionsLockEntry {
22
+ readonly integrity?: string | undefined;
23
+ readonly version: string;
24
+ }
25
+
26
+ export interface WorkbenchExtensionsLock {
27
+ readonly extensions: Readonly<Record<string, WorkbenchExtensionsLockEntry>>;
28
+ readonly lockfileVersion: number;
29
+ }
30
+
22
31
  export interface WorkbenchLayoutConfig {
23
32
  readonly activityBar: {
24
33
  readonly hiddenItemIds?: readonly string[];
@@ -29,6 +38,8 @@ export interface WorkbenchLayoutConfig {
29
38
  readonly visible: boolean;
30
39
  };
31
40
  readonly panel: {
41
+ readonly activeViewContainer?: string;
42
+ readonly sizePercent?: number;
32
43
  readonly visible: boolean;
33
44
  };
34
45
  readonly sideBar: {
@@ -72,15 +83,50 @@ export function parseWorkbenchExtensionsConfig(input: unknown): WorkbenchExtensi
72
83
  }
73
84
 
74
85
  export function parseWorkbenchExtensionsConfigJson(jsonText: string): WorkbenchExtensionsConfig {
75
- try {
76
- return parseWorkbenchExtensionsConfig(JSON.parse(jsonText) as unknown);
77
- } catch (error) {
78
- if (error instanceof WorkbenchConfigValidationError) {
79
- throw error;
80
- }
86
+ return parseConfigJson(jsonText, parseWorkbenchExtensionsConfig, 'extensions config');
87
+ }
81
88
 
82
- throw new WorkbenchConfigValidationError('Expected extensions config to be valid JSON.');
89
+ export function parseWorkbenchExtensionsLock(input: unknown): WorkbenchExtensionsLock {
90
+ const record = assertRecord(input, 'extensions lock');
91
+ const lockfileVersion = record.lockfileVersion;
92
+ if (
93
+ typeof lockfileVersion !== 'number' ||
94
+ !Number.isInteger(lockfileVersion) ||
95
+ lockfileVersion < 1
96
+ ) {
97
+ throw new WorkbenchConfigValidationError(
98
+ 'Expected extensions lock "lockfileVersion" to be a positive integer.',
99
+ );
83
100
  }
101
+
102
+ const extensionsRecord = assertRecord(record.extensions ?? {}, 'extensions lock extensions');
103
+ const extensions: Record<string, WorkbenchExtensionsLockEntry> = {};
104
+ for (const [extensionId, rawEntry] of Object.entries(extensionsRecord)) {
105
+ const entry = assertRecord(rawEntry, `extensions lock entry "${extensionId}"`);
106
+ if (typeof entry.version !== 'string' || entry.version.trim().length === 0) {
107
+ throw new WorkbenchConfigValidationError(
108
+ `Expected extensions lock entry "${extensionId}" to include a non-empty version.`,
109
+ );
110
+ }
111
+ if (entry.integrity !== undefined && typeof entry.integrity !== 'string') {
112
+ throw new WorkbenchConfigValidationError(
113
+ `Expected extensions lock entry "${extensionId}" integrity to be a string.`,
114
+ );
115
+ }
116
+ extensions[extensionId] = {
117
+ integrity: typeof entry.integrity === 'string' ? entry.integrity : undefined,
118
+ version: entry.version.trim(),
119
+ };
120
+ }
121
+
122
+ return {
123
+ extensions,
124
+ lockfileVersion,
125
+ };
126
+ }
127
+
128
+ export function parseWorkbenchExtensionsLockJson(jsonText: string): WorkbenchExtensionsLock {
129
+ return parseConfigJson(jsonText, parseWorkbenchExtensionsLock, 'extensions lock');
84
130
  }
85
131
 
86
132
  export function parseWorkbenchLayoutConfig(input: unknown): WorkbenchLayoutConfig {
@@ -98,7 +144,7 @@ export function parseWorkbenchLayoutConfig(input: unknown): WorkbenchLayoutConfi
98
144
  'layout config activityBar',
99
145
  );
100
146
  assertKnownKeys(auxiliaryBar, ['visible'], 'layout config auxiliaryBar');
101
- assertKnownKeys(panel, ['visible'], 'layout config panel');
147
+ assertKnownKeys(panel, ['activeViewContainer', 'sizePercent', 'visible'], 'layout config panel');
102
148
  assertKnownKeys(
103
149
  sideBar,
104
150
  ['activeViewContainer', 'sizePercent', 'visible'],
@@ -123,6 +169,8 @@ export function parseWorkbenchLayoutConfig(input: unknown): WorkbenchLayoutConfi
123
169
  ),
124
170
  },
125
171
  panel: {
172
+ ...readOptionalLayoutId(panel, 'activeViewContainer'),
173
+ ...readOptionalSizePercent(panel, 'sizePercent'),
126
174
  visible: readOptionalBoolean(panel, 'visible', DEFAULT_WORKBENCH_LAYOUT_CONFIG.panel.visible),
127
175
  },
128
176
  sideBar: {
@@ -138,15 +186,7 @@ export function parseWorkbenchLayoutConfig(input: unknown): WorkbenchLayoutConfi
138
186
  }
139
187
 
140
188
  export function parseWorkbenchLayoutConfigJson(jsonText: string): WorkbenchLayoutConfig {
141
- try {
142
- return parseWorkbenchLayoutConfig(JSON.parse(jsonText) as unknown);
143
- } catch (error) {
144
- if (error instanceof WorkbenchConfigValidationError) {
145
- throw error;
146
- }
147
-
148
- throw new WorkbenchConfigValidationError('Expected layout config to be valid JSON.');
149
- }
189
+ return parseConfigJson(jsonText, parseWorkbenchLayoutConfig, 'layout config');
150
190
  }
151
191
 
152
192
  export {
@@ -161,12 +201,10 @@ export {
161
201
  } from './settings-config.js';
162
202
  export {
163
203
  createEmptyPreferenceValuesByScope,
164
- FUTURE_PREFERENCE_SCOPES,
165
204
  isPreferenceScope,
166
205
  mergePreferenceValuesByScope,
167
206
  mergeScopedPreferences,
168
207
  PREFERENCE_SCOPE_MERGE_ORDER,
169
- type FuturePreferenceScope,
170
208
  type PreferenceScope,
171
209
  type PreferenceValuesByScope,
172
210
  type ScopedPreferenceLayer,
@@ -181,14 +219,6 @@ export {
181
219
  type WorkbenchUserCommandsConfig,
182
220
  } from './user-commands-config.js';
183
221
 
184
- function assertRecord(value: unknown, label: string): Record<string, unknown> {
185
- if (typeof value !== 'object' || value === null || Array.isArray(value)) {
186
- throw new WorkbenchConfigValidationError(`Expected ${label} to be an object.`);
187
- }
188
-
189
- return value as Record<string, unknown>;
190
- }
191
-
192
222
  function readOptionalRecord(record: Record<string, unknown>, key: string): Record<string, unknown> {
193
223
  const value = record[key];
194
224
  if (value === undefined) {
@@ -290,11 +320,3 @@ function readOptionalSizePercent(
290
320
  function clampLayoutSizePercent(value: number): number {
291
321
  return Math.min(90, Math.max(10, value));
292
322
  }
293
-
294
- function assertKnownKeys(record: Record<string, unknown>, keys: readonly string[], label: string) {
295
- const knownKeys = new Set(keys);
296
- const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key));
297
- if (unknownKeys.length > 0) {
298
- throw new WorkbenchConfigValidationError(`Unexpected ${label} field "${unknownKeys[0]}".`);
299
- }
300
- }
@@ -1,3 +1,10 @@
1
+ import {
2
+ assertKnownKeys,
3
+ assertRecord,
4
+ parseConfigJson,
5
+ readOptionalString,
6
+ readRequiredString,
7
+ } from './parse-helpers.js';
1
8
  import { WorkbenchConfigValidationError } from './validation-error.js';
2
9
 
3
10
  export interface WorkbenchKeybindingDefinition {
@@ -20,15 +27,7 @@ export function parseWorkbenchKeybindingsConfig(
20
27
  export function parseWorkbenchKeybindingsConfigJson(
21
28
  jsonText: string,
22
29
  ): readonly WorkbenchKeybindingDefinition[] {
23
- try {
24
- return parseWorkbenchKeybindingsConfig(JSON.parse(jsonText) as unknown);
25
- } catch (error) {
26
- if (error instanceof WorkbenchConfigValidationError) {
27
- throw error;
28
- }
29
-
30
- throw new WorkbenchConfigValidationError('Expected keybindings config to be valid JSON.');
31
- }
30
+ return parseConfigJson(jsonText, parseWorkbenchKeybindingsConfig, 'keybindings config');
32
31
  }
33
32
 
34
33
  function parseWorkbenchKeybindingDefinition(
@@ -48,36 +47,6 @@ function parseWorkbenchKeybindingDefinition(
48
47
  };
49
48
  }
50
49
 
51
- function assertRecord(value: unknown, label: string): Record<string, unknown> {
52
- if (typeof value !== 'object' || value === null || Array.isArray(value)) {
53
- throw new WorkbenchConfigValidationError(`Expected ${label} to be an object.`);
54
- }
55
-
56
- return value as Record<string, unknown>;
57
- }
58
-
59
- function readRequiredString(record: Record<string, unknown>, key: string): string {
60
- const value = record[key];
61
- if (typeof value !== 'string' || value.trim().length === 0) {
62
- throw new WorkbenchConfigValidationError(`Expected "${key}" to be a non-empty string.`);
63
- }
64
-
65
- return value.trim();
66
- }
67
-
68
- function readOptionalString(record: Record<string, unknown>, key: string): string | undefined {
69
- const value = record[key];
70
- if (value === undefined) {
71
- return undefined;
72
- }
73
-
74
- if (typeof value !== 'string' || value.trim().length === 0) {
75
- throw new WorkbenchConfigValidationError(`Expected "${key}" to be a non-empty string.`);
76
- }
77
-
78
- return value.trim();
79
- }
80
-
81
50
  function readOptionalArgs(record: Record<string, unknown>): readonly unknown[] | undefined {
82
51
  const value = record.args;
83
52
  if (value === undefined) {
@@ -90,11 +59,3 @@ function readOptionalArgs(record: Record<string, unknown>): readonly unknown[] |
90
59
 
91
60
  return [...value];
92
61
  }
93
-
94
- function assertKnownKeys(record: Record<string, unknown>, keys: readonly string[], label: string) {
95
- const knownKeys = new Set(keys);
96
- const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key));
97
- if (unknownKeys.length > 0) {
98
- throw new WorkbenchConfigValidationError(`Unexpected ${label} field "${unknownKeys[0]}".`);
99
- }
100
- }
@@ -0,0 +1,61 @@
1
+ import { WorkbenchConfigValidationError } from './validation-error.js';
2
+
3
+ export function assertRecord(value: unknown, label: string): Record<string, unknown> {
4
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
5
+ throw new WorkbenchConfigValidationError(`Expected ${label} to be an object.`);
6
+ }
7
+
8
+ return value as Record<string, unknown>;
9
+ }
10
+
11
+ export function parseConfigJson<T>(
12
+ jsonText: string,
13
+ parseConfig: (input: unknown) => T,
14
+ configLabel: string,
15
+ ): T {
16
+ try {
17
+ return parseConfig(JSON.parse(jsonText) as unknown);
18
+ } catch (error) {
19
+ if (error instanceof WorkbenchConfigValidationError) {
20
+ throw error;
21
+ }
22
+ throw new WorkbenchConfigValidationError(`Expected ${configLabel} to be valid JSON.`);
23
+ }
24
+ }
25
+
26
+ export function readRequiredString(record: Record<string, unknown>, key: string): string {
27
+ const value = record[key];
28
+ if (typeof value !== 'string' || value.trim().length === 0) {
29
+ throw new WorkbenchConfigValidationError(`Expected "${key}" to be a non-empty string.`);
30
+ }
31
+
32
+ return value.trim();
33
+ }
34
+
35
+ export function readOptionalString(
36
+ record: Record<string, unknown>,
37
+ key: string,
38
+ ): string | undefined {
39
+ const value = record[key];
40
+ if (value === undefined) {
41
+ return undefined;
42
+ }
43
+
44
+ if (typeof value !== 'string' || value.trim().length === 0) {
45
+ throw new WorkbenchConfigValidationError(`Expected "${key}" to be a non-empty string.`);
46
+ }
47
+
48
+ return value.trim();
49
+ }
50
+
51
+ export function assertKnownKeys(
52
+ record: Record<string, unknown>,
53
+ keys: readonly string[],
54
+ label: string,
55
+ ) {
56
+ const knownKeys = new Set(keys);
57
+ const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key));
58
+ if (unknownKeys.length > 0) {
59
+ throw new WorkbenchConfigValidationError(`Unexpected ${label} field "${unknownKeys[0]}".`);
60
+ }
61
+ }
@@ -3,11 +3,6 @@ import type { WorkbenchSettingsConfig } from './settings-config.js';
3
3
  /** Runtime preference scopes supported in v1. */
4
4
  export type PreferenceScope = 'default' | 'workspace' | 'local';
5
5
 
6
- /** Documented future scopes — not merged or persisted yet. */
7
- export const FUTURE_PREFERENCE_SCOPES = ['user', 'resource', 'secret'] as const;
8
-
9
- export type FuturePreferenceScope = (typeof FUTURE_PREFERENCE_SCOPES)[number];
10
-
11
6
  /** Lower index = lower precedence when merging effective values. */
12
7
  export const PREFERENCE_SCOPE_MERGE_ORDER: readonly PreferenceScope[] = [
13
8
  'default',
@@ -1,3 +1,4 @@
1
+ import { parseConfigJson } from './parse-helpers.js';
1
2
  import { WorkbenchConfigValidationError } from './validation-error.js';
2
3
 
3
4
  export type WorkbenchSettingsConfig = Readonly<Record<string, unknown>>;
@@ -7,17 +8,23 @@ export function parseWorkbenchSettingsConfig(input: unknown): WorkbenchSettingsC
7
8
  throw new WorkbenchConfigValidationError('Expected settings config to be an object.');
8
9
  }
9
10
 
10
- return { ...(input as Record<string, unknown>) };
11
+ const settings = { ...(input as Record<string, unknown>) };
12
+ const colorTheme = settings['workbench.colorTheme'];
13
+ if (colorTheme !== undefined && typeof colorTheme !== 'string') {
14
+ throw new WorkbenchConfigValidationError('Expected workbench.colorTheme to be a string.');
15
+ }
16
+
17
+ const editorFontSize = settings['editor.fontSize'];
18
+ if (
19
+ editorFontSize !== undefined &&
20
+ (typeof editorFontSize !== 'number' || !Number.isFinite(editorFontSize) || editorFontSize < 1)
21
+ ) {
22
+ throw new WorkbenchConfigValidationError('Expected editor.fontSize to be a number >= 1.');
23
+ }
24
+
25
+ return settings;
11
26
  }
12
27
 
13
28
  export function parseWorkbenchSettingsConfigJson(jsonText: string): WorkbenchSettingsConfig {
14
- try {
15
- return parseWorkbenchSettingsConfig(JSON.parse(jsonText) as unknown);
16
- } catch (error) {
17
- if (error instanceof WorkbenchConfigValidationError) {
18
- throw error;
19
- }
20
-
21
- throw new WorkbenchConfigValidationError('Expected settings config to be valid JSON.');
22
- }
29
+ return parseConfigJson(jsonText, parseWorkbenchSettingsConfig, 'settings config');
23
30
  }
@@ -1,3 +1,10 @@
1
+ import {
2
+ assertKnownKeys,
3
+ assertRecord,
4
+ parseConfigJson,
5
+ readOptionalString,
6
+ readRequiredString,
7
+ } from './parse-helpers.js';
1
8
  import { WorkbenchConfigValidationError } from './validation-error.js';
2
9
 
3
10
  export interface WorkbenchUserCommandExecuteAction {
@@ -46,15 +53,7 @@ export function parseWorkbenchUserCommandsConfig(input: unknown): WorkbenchUserC
46
53
  export function parseWorkbenchUserCommandsConfigJson(
47
54
  jsonText: string,
48
55
  ): WorkbenchUserCommandsConfig {
49
- try {
50
- return parseWorkbenchUserCommandsConfig(JSON.parse(jsonText) as unknown);
51
- } catch (error) {
52
- if (error instanceof WorkbenchConfigValidationError) {
53
- throw error;
54
- }
55
-
56
- throw new WorkbenchConfigValidationError('Expected user commands config to be valid JSON.');
57
- }
56
+ return parseConfigJson(jsonText, parseWorkbenchUserCommandsConfig, 'user commands config');
58
57
  }
59
58
 
60
59
  function parseUserCommandDefinition(input: unknown, index: number): WorkbenchUserCommandDefinition {
@@ -102,36 +101,6 @@ function parseUserCommandAction(input: unknown, label: string): WorkbenchUserCom
102
101
  throw new WorkbenchConfigValidationError(`Unexpected ${label} type "${type}".`);
103
102
  }
104
103
 
105
- function assertRecord(value: unknown, label: string): Record<string, unknown> {
106
- if (typeof value !== 'object' || value === null || Array.isArray(value)) {
107
- throw new WorkbenchConfigValidationError(`Expected ${label} to be an object.`);
108
- }
109
-
110
- return value as Record<string, unknown>;
111
- }
112
-
113
- function readRequiredString(record: Record<string, unknown>, key: string): string {
114
- const value = record[key];
115
- if (typeof value !== 'string' || value.trim().length === 0) {
116
- throw new WorkbenchConfigValidationError(`Expected "${key}" to be a non-empty string.`);
117
- }
118
-
119
- return value.trim();
120
- }
121
-
122
- function readOptionalString(record: Record<string, unknown>, key: string): string | undefined {
123
- const value = record[key];
124
- if (value === undefined) {
125
- return undefined;
126
- }
127
-
128
- if (typeof value !== 'string' || value.trim().length === 0) {
129
- throw new WorkbenchConfigValidationError(`Expected "${key}" to be a non-empty string.`);
130
- }
131
-
132
- return value.trim();
133
- }
134
-
135
104
  function readOptionalNumber(record: Record<string, unknown>, key: string): number | undefined {
136
105
  const value = record[key];
137
106
  if (value === undefined) {
@@ -144,11 +113,3 @@ function readOptionalNumber(record: Record<string, unknown>, key: string): numbe
144
113
 
145
114
  return value;
146
115
  }
147
-
148
- function assertKnownKeys(record: Record<string, unknown>, keys: readonly string[], label: string) {
149
- const knownKeys = new Set(keys);
150
- const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key));
151
- if (unknownKeys.length > 0) {
152
- throw new WorkbenchConfigValidationError(`Unexpected ${label} field "${unknownKeys[0]}".`);
153
- }
154
- }