@theia/preferences 1.76.0-next.6 → 1.76.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.
- package/lib/browser/preference-frontend-contribution.d.ts +18 -0
- package/lib/browser/preference-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/preference-frontend-contribution.js +48 -12
- package/lib/browser/preference-frontend-contribution.js.map +1 -1
- package/lib/browser/preference-frontend-contribution.spec.d.ts +2 -0
- package/lib/browser/preference-frontend-contribution.spec.d.ts.map +1 -0
- package/lib/browser/preference-frontend-contribution.spec.js +76 -0
- package/lib/browser/preference-frontend-contribution.spec.js.map +1 -0
- package/lib/browser/preference-frontend-module.d.ts.map +1 -1
- package/lib/browser/preference-frontend-module.js +4 -0
- package/lib/browser/preference-frontend-module.js.map +1 -1
- package/lib/browser/preference-tree-model.d.ts +38 -1
- package/lib/browser/preference-tree-model.d.ts.map +1 -1
- package/lib/browser/preference-tree-model.js +136 -3
- package/lib/browser/preference-tree-model.js.map +1 -1
- package/lib/browser/preference-tree-model.spec.d.ts +2 -0
- package/lib/browser/preference-tree-model.spec.d.ts.map +1 -0
- package/lib/browser/preference-tree-model.spec.js +320 -0
- package/lib/browser/preference-tree-model.spec.js.map +1 -0
- package/lib/browser/session-preference-remote-cli-contribution.d.ts +17 -0
- package/lib/browser/session-preference-remote-cli-contribution.d.ts.map +1 -0
- package/lib/browser/session-preference-remote-cli-contribution.js +54 -0
- package/lib/browser/session-preference-remote-cli-contribution.js.map +1 -0
- package/lib/browser/session-preference-remote-cli-contribution.spec.d.ts +2 -0
- package/lib/browser/session-preference-remote-cli-contribution.spec.d.ts.map +1 -0
- package/lib/browser/session-preference-remote-cli-contribution.spec.js +50 -0
- package/lib/browser/session-preference-remote-cli-contribution.spec.js.map +1 -0
- package/lib/browser/views/preference-editor-widget.d.ts +29 -7
- package/lib/browser/views/preference-editor-widget.d.ts.map +1 -1
- package/lib/browser/views/preference-editor-widget.js +119 -15
- package/lib/browser/views/preference-editor-widget.js.map +1 -1
- package/lib/browser/views/preference-widget.d.ts +1 -2
- package/lib/browser/views/preference-widget.d.ts.map +1 -1
- package/lib/browser/views/preference-widget.js +0 -2
- package/lib/browser/views/preference-widget.js.map +1 -1
- package/lib/common/cli-preferences.d.ts +28 -0
- package/lib/common/cli-preferences.d.ts.map +1 -1
- package/lib/common/cli-preferences.js +66 -1
- package/lib/common/cli-preferences.js.map +1 -1
- package/lib/common/cli-preferences.spec.d.ts +2 -0
- package/lib/common/cli-preferences.spec.d.ts.map +1 -0
- package/lib/common/cli-preferences.spec.js +64 -0
- package/lib/common/cli-preferences.spec.js.map +1 -0
- package/lib/node/preference-cli-contribution.d.ts.map +1 -1
- package/lib/node/preference-cli-contribution.js +3 -22
- package/lib/node/preference-cli-contribution.js.map +1 -1
- package/package.json +9 -9
- package/src/browser/preference-frontend-contribution.spec.ts +92 -0
- package/src/browser/preference-frontend-contribution.ts +50 -13
- package/src/browser/preference-frontend-module.ts +4 -0
- package/src/browser/preference-tree-model.spec.ts +362 -0
- package/src/browser/preference-tree-model.ts +144 -3
- package/src/browser/session-preference-remote-cli-contribution.spec.ts +59 -0
- package/src/browser/session-preference-remote-cli-contribution.ts +49 -0
- package/src/browser/style/index.css +6 -0
- package/src/browser/views/preference-editor-widget.ts +124 -23
- package/src/browser/views/preference-widget.tsx +1 -4
- package/src/common/cli-preferences.spec.ts +73 -0
- package/src/common/cli-preferences.ts +75 -0
- package/src/node/preference-cli-contribution.ts +3 -22
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { expect } from 'chai';
|
|
18
|
+
import { CliPreferenceEntry } from './cli-preferences';
|
|
19
|
+
|
|
20
|
+
describe('CliPreferenceEntry.parse', () => {
|
|
21
|
+
|
|
22
|
+
it('parses a KEY=JSONVALUE assignment', () => {
|
|
23
|
+
expect(CliPreferenceEntry.parse('editor.fontSize=14')).to.deep.equal(['editor.fontSize', 14]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('parses boolean and string JSON values', () => {
|
|
27
|
+
expect(CliPreferenceEntry.parse('foo.enabled=true')).to.deep.equal(['foo.enabled', true]);
|
|
28
|
+
expect(CliPreferenceEntry.parse('foo.label="hello"')).to.deep.equal(['foo.label', 'hello']);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('keeps "=" characters that are part of the value', () => {
|
|
32
|
+
expect(CliPreferenceEntry.parse('foo.expr="a=b"')).to.deep.equal(['foo.expr', 'a=b']);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('decodes a base64-encoded value', () => {
|
|
36
|
+
// base64 of the JSON value `42`
|
|
37
|
+
expect(CliPreferenceEntry.parse('foo.num=base64:NDI=')).to.deep.equal(['foo.num', 42]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('returns undefined when there is no key', () => {
|
|
41
|
+
expect(CliPreferenceEntry.parse('=1')).to.be.undefined;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('returns undefined when there is no "="', () => {
|
|
45
|
+
expect(CliPreferenceEntry.parse('noequals')).to.be.undefined;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('returns undefined for an invalid JSON value', () => {
|
|
49
|
+
expect(CliPreferenceEntry.parse('foo.bar=not json')).to.be.undefined;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('parseAll', () => {
|
|
53
|
+
it('parses and filters a list, dropping invalid entries', () => {
|
|
54
|
+
const result = CliPreferenceEntry.parseAll(['a=1', 'bad', 'b="x"']);
|
|
55
|
+
expect(result).to.deep.equal([['a', 1], ['b', 'x']]);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('toArg', () => {
|
|
60
|
+
it('formats an entry as a base64-encoded CLI argument', () => {
|
|
61
|
+
// base64 of the JSON value `42`
|
|
62
|
+
expect(CliPreferenceEntry.toArg('session-preference', ['foo.num', 42])).to.equal('--session-preference=foo.num=base64:NDI=');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('round-trips a value with shell-special characters through toArg + parse', () => {
|
|
66
|
+
const entry: [string, unknown] = ['foo.expr', '$HOME && "quoted"'];
|
|
67
|
+
const arg = CliPreferenceEntry.toArg('session-preference', entry);
|
|
68
|
+
// The value part of `--session-preference=<value>` must parse back to the original entry.
|
|
69
|
+
const value = arg.substring('--session-preference='.length);
|
|
70
|
+
expect(CliPreferenceEntry.parse(value)).to.deep.equal(entry);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -21,3 +21,78 @@ export interface CliPreferences {
|
|
|
21
21
|
getPreferences(): Promise<[string, unknown][]>;
|
|
22
22
|
getSessionPreferences(): Promise<[string, unknown][]>;
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
export namespace CliPreferenceEntry {
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Sink for warnings about malformed entries. Callers running in an Inversify context should
|
|
29
|
+
* pass their named `ILogger`, since these helpers live in `common` and cannot inject one
|
|
30
|
+
* themselves. Defaults to `console.warn`.
|
|
31
|
+
*/
|
|
32
|
+
export type WarningSink = (message: string) => void;
|
|
33
|
+
|
|
34
|
+
const defaultWarn: WarningSink = message => console.warn(message);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Parses a single `KEY=JSONVALUE` preference assignment as accepted by `--set-preference`
|
|
38
|
+
* and `--session-preference`. The value may be `base64:`-prefixed (used when forwarding
|
|
39
|
+
* values that must survive shell/URL transport intact). Returns `undefined` (after logging a
|
|
40
|
+
* warning to {@link warn}) when the entry has no key or the value is not valid JSON.
|
|
41
|
+
*/
|
|
42
|
+
export function parse(entry: string, warn: WarningSink = defaultWarn): [string, unknown] | undefined {
|
|
43
|
+
const firstEqualIndex = entry.indexOf('=');
|
|
44
|
+
if (firstEqualIndex <= 0) {
|
|
45
|
+
warn(`Ignoring preference CLI argument "${entry}": expected KEY=JSONVALUE.`);
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const rawValue = entry.substring(firstEqualIndex + 1);
|
|
49
|
+
try {
|
|
50
|
+
// Decoding happens inside the `try` so that a malformed `base64:` payload is reported
|
|
51
|
+
// like any other invalid value instead of throwing out of `parse`.
|
|
52
|
+
const value = rawValue.startsWith('base64:') ? decodeBase64(rawValue.substring('base64:'.length)) : rawValue;
|
|
53
|
+
return [entry.substring(0, firstEqualIndex), JSON.parse(value)];
|
|
54
|
+
} catch (e) {
|
|
55
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
56
|
+
warn(`Ignoring preference CLI argument "${entry}": value is not valid JSON (${reason}).`);
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Formats a preference entry as a CLI argument of the form
|
|
63
|
+
* `--<optionName>=<key>=base64:<base64(JSON(value))>`, the inverse of {@link parse}.
|
|
64
|
+
*
|
|
65
|
+
* The value is base64-encoded so it survives shell/URL transport intact (e.g. when the
|
|
66
|
+
* argument is passed to a remote backend over an SSH command line).
|
|
67
|
+
*/
|
|
68
|
+
export function toArg(optionName: string, [key, value]: [string, unknown]): string {
|
|
69
|
+
return `--${optionName}=${key}=base64:${encodeBase64(JSON.stringify(value))}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Parses a list of `KEY=JSONVALUE` assignments, dropping any invalid entries and reporting
|
|
74
|
+
* them to {@link warn}.
|
|
75
|
+
*/
|
|
76
|
+
export function parseAll(entries: readonly string[], warn: WarningSink = defaultWarn): [string, unknown][] {
|
|
77
|
+
const result: [string, unknown][] = [];
|
|
78
|
+
for (const entry of entries) {
|
|
79
|
+
const parsed = parse(entry, warn);
|
|
80
|
+
if (parsed) {
|
|
81
|
+
result.push(parsed);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// `Buffer` is available on the backend and is polyfilled into the frontend bundle by the
|
|
88
|
+
// esbuild generator, so a single implementation covers both. It also handles UTF-8 directly,
|
|
89
|
+
// unlike `atob`/`btoa`, which only deal in binary strings.
|
|
90
|
+
|
|
91
|
+
function decodeBase64(value: string): string {
|
|
92
|
+
return Buffer.from(value, 'base64').toString('utf-8');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function encodeBase64(value: string): string {
|
|
96
|
+
return Buffer.from(value, 'utf-8').toString('base64');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -18,7 +18,7 @@ import { injectable, inject, named } from '@theia/core/shared/inversify';
|
|
|
18
18
|
import { Argv } from '@theia/core/shared/yargs';
|
|
19
19
|
import { CliContribution } from '@theia/core/lib/node/cli';
|
|
20
20
|
import { RemoteCliContext, RemoteCliContribution } from '@theia/core/lib/node/remote/remote-cli-contribution';
|
|
21
|
-
import { CliPreferences } from '../common/cli-preferences';
|
|
21
|
+
import { CliPreferences, CliPreferenceEntry } from '../common/cli-preferences';
|
|
22
22
|
import { ILogger } from '@theia/core';
|
|
23
23
|
|
|
24
24
|
@injectable()
|
|
@@ -52,23 +52,7 @@ export class PreferenceCliContribution implements CliContribution, CliPreference
|
|
|
52
52
|
|
|
53
53
|
protected parseInto(raw: unknown, target: [string, unknown][]): void {
|
|
54
54
|
const entries: string[] = raw instanceof Array ? raw : [raw as string];
|
|
55
|
-
|
|
56
|
-
const firstEqualIndex = entry.indexOf('=');
|
|
57
|
-
if (firstEqualIndex <= 0) {
|
|
58
|
-
this.logger.warn(`Ignoring preference CLI argument "${entry}": expected KEY=JSONVALUE.`);
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
let rawValue = entry.substring(firstEqualIndex + 1);
|
|
62
|
-
if (rawValue.startsWith('base64:')) {
|
|
63
|
-
rawValue = Buffer.from(rawValue.substring('base64:'.length), 'base64').toString('utf-8');
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
target.push([entry.substring(0, firstEqualIndex), JSON.parse(rawValue)]);
|
|
67
|
-
} catch (e) {
|
|
68
|
-
const reason = e instanceof Error ? e.message : String(e);
|
|
69
|
-
this.logger.warn(`Ignoring preference CLI argument "${entry}": value is not valid JSON (${reason}).`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
55
|
+
target.push(...CliPreferenceEntry.parseAll(entries, message => this.logger.warn(message)));
|
|
72
56
|
}
|
|
73
57
|
|
|
74
58
|
async getPreferences(): Promise<[string, unknown][]> {
|
|
@@ -85,10 +69,7 @@ export class PreferenceCliContribution implements CliContribution, CliPreference
|
|
|
85
69
|
* shell argument parsing intact.
|
|
86
70
|
*/
|
|
87
71
|
enhanceArgs(_context: RemoteCliContext): string[] {
|
|
88
|
-
return this.sessionPreferences.map((
|
|
89
|
-
const encoded = Buffer.from(JSON.stringify(value), 'utf-8').toString('base64');
|
|
90
|
-
return `--session-preference=${key}=base64:${encoded}`;
|
|
91
|
-
});
|
|
72
|
+
return this.sessionPreferences.map(entry => CliPreferenceEntry.toArg('session-preference', entry));
|
|
92
73
|
}
|
|
93
74
|
|
|
94
75
|
}
|