@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 +1 -5
- package/src/index.ts +59 -37
- package/src/keybindings-config.ts +8 -47
- package/src/parse-helpers.ts +61 -0
- package/src/preference-scopes.ts +0 -5
- package/src/settings-config.ts +17 -10
- package/src/user-commands-config.ts +8 -47
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.
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
} catch (error) {
|
|
78
|
-
if (error instanceof WorkbenchConfigValidationError) {
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
86
|
+
return parseConfigJson(jsonText, parseWorkbenchExtensionsConfig, 'extensions config');
|
|
87
|
+
}
|
|
81
88
|
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|
package/src/preference-scopes.ts
CHANGED
|
@@ -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',
|
package/src/settings-config.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|