Skip to content

Commit 43e83c5

Browse files
committed
Fix the conflict in user settings, add tests
1 parent 5117be6 commit 43e83c5

File tree

3 files changed

+406
-41
lines changed

3 files changed

+406
-41
lines changed

packages/jupyterlab-lsp/schema/plugin.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"language_servers": {
3333
"title": "Language Server",
3434
"description": "Language-server specific configuration, keyed by implementation, e.g: \n\npyls: {\n serverSettings: {\n pyls: {\n plugins: {\n pydocstyle: {\n enabled: true\n },\n pyflakes: {\n enabled: false\n },\n flake8: {\n enabled: true\n }\n }\n }\n }\n}\n\nAlternatively, using dotted naming convention:\n\npyls: {\n serverSettings: {\n \"pyls.plugins.pydocstyle.enabled\": true,\n \"pyls.plugins.pyflakes.enabled\": false,\n \"pyls.plugins.flake8.enabled\": true\n }\n}",
35+
"type": "object",
3536
"default": {
3637
"pyright": {
3738
"serverSettings": {

packages/jupyterlab-lsp/src/settings.spec.ts

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,257 @@
11
import { SettingsSchemaManager } from './settings';
2+
import { ISettingRegistry } from '@jupyterlab/settingregistry';
3+
import { LanguageServerManager } from '@jupyterlab/lsp';
4+
import { JSONExt } from '@lumino/coreutils';
25

36
const DEAULT_SERVER_PRIORITY = 50;
47

8+
const SCHEMA: ISettingRegistry.ISchema = {
9+
type: 'object',
10+
definitions: {
11+
'language-server': {
12+
type: 'object',
13+
default: {},
14+
properties: {
15+
priority: {
16+
title: 'Priority of the server',
17+
type: 'number',
18+
default: 50,
19+
minimum: 1
20+
},
21+
serverSettings: {
22+
title: 'Language Server Configurations',
23+
type: 'object',
24+
default: {},
25+
additionalProperties: true
26+
}
27+
}
28+
}
29+
},
30+
properties: {
31+
language_servers: {
32+
title: 'Language Server',
33+
type: 'object',
34+
default: {
35+
pyright: {
36+
serverSettings: {
37+
'python.analysis.useLibraryCodeForTypes': true
38+
}
39+
},
40+
'bash-language-server': {
41+
serverSettings: {
42+
'bashIde.enableSourceErrorDiagnostics': true
43+
}
44+
}
45+
},
46+
patternProperties: {
47+
'.*': {
48+
$ref: '#/definitions/language-server'
49+
}
50+
},
51+
additionalProperties: {
52+
$ref: '#/definitions/language-server'
53+
}
54+
}
55+
}
56+
};
57+
58+
const PYRIGHT_SCHEMA = {
59+
$schema: 'http://json-schema.org/draft-07/schema#',
60+
title: 'Pyright Language Server Configuration',
61+
description:
62+
'Pyright Configuration Schema. Distributed under MIT License, Copyright (c) Microsoft Corporation.',
63+
type: 'object',
64+
properties: {
65+
'python.analysis.diagnosticSeverityOverrides': {
66+
type: 'object',
67+
description:
68+
'Allows a user to override the severity levels for individual diagnostics.',
69+
scope: 'resource',
70+
properties: {
71+
reportGeneralTypeIssues: {
72+
type: 'string',
73+
description:
74+
'Diagnostics for general type inconsistencies, unsupported operations, argument/parameter mismatches, etc. Covers all of the basic type-checking rules not covered by other rules. Does not include syntax errors.',
75+
default: 'error',
76+
enum: ['none', 'information', 'warning', 'error']
77+
},
78+
reportPropertyTypeMismatch: {
79+
type: 'string',
80+
description:
81+
'Diagnostics for property whose setter and getter have mismatched types.',
82+
default: 'none',
83+
enum: ['none', 'information', 'warning', 'error']
84+
},
85+
reportFunctionMemberAccess: {
86+
type: 'string',
87+
description: 'Diagnostics for member accesses on functions.',
88+
default: 'none',
89+
enum: ['none', 'information', 'warning', 'error']
90+
},
91+
reportMissingImports: {
92+
type: 'string',
93+
description:
94+
'Diagnostics for imports that have no corresponding imported python file or type stub file.',
95+
default: 'error',
96+
enum: ['none', 'information', 'warning', 'error']
97+
},
98+
reportUnusedImport: {
99+
type: 'string',
100+
description:
101+
'Diagnostics for an imported symbol that is not referenced within that file.',
102+
default: 'none',
103+
enum: ['none', 'information', 'warning', 'error']
104+
},
105+
reportUnusedClass: {
106+
type: 'string',
107+
description:
108+
'Diagnostics for a class with a private name (starting with an underscore) that is not accessed.',
109+
default: 'none',
110+
enum: ['none', 'information', 'warning', 'error']
111+
}
112+
}
113+
},
114+
'python.analysis.logLevel': {
115+
type: 'string',
116+
default: 'Information',
117+
description: 'Specifies the level of logging for the Output panel',
118+
enum: ['Error', 'Warning', 'Information', 'Trace']
119+
},
120+
'python.analysis.useLibraryCodeForTypes': {
121+
type: 'boolean',
122+
default: false,
123+
description:
124+
'Use library implementations to extract type information when type stub is not present.',
125+
scope: 'resource'
126+
},
127+
'python.pythonPath': {
128+
type: 'string',
129+
default: 'python',
130+
description: 'Path to Python, you can use a custom version of Python.',
131+
scope: 'resource'
132+
}
133+
}
134+
};
135+
136+
const COLLAPSED_PYRIGHT_SETTINGS = {
137+
pyright: {
138+
priority: 50,
139+
serverSettings: {
140+
'python.analysis.autoImportCompletions': false,
141+
'python.analysis.extraPaths': [],
142+
'python.analysis.stubPath': 'typings',
143+
'python.pythonPath': 'python',
144+
'python.analysis.diagnosticSeverityOverrides.reportGeneralTypeIssues':
145+
'error',
146+
'python.analysis.diagnosticSeverityOverrides.reportPropertyTypeMismatch':
147+
'none',
148+
'python.analysis.diagnosticSeverityOverrides.reportFunctionMemberAccess':
149+
'none',
150+
'python.analysis.diagnosticSeverityOverrides.reportMissingImports': 'none'
151+
}
152+
}
153+
};
154+
155+
function map(object: Object) {
156+
return new Map(Object.entries(object));
157+
}
158+
159+
const AVAILABLE_SESSIONS = map({
160+
pyright: null as any,
161+
pylsp: null as any
162+
}) as LanguageServerManager['sessions'];
163+
5164
describe('SettingsSchemaManager', () => {
165+
describe('#expandDottedAsNeeded()', () => {
166+
it('should uncollapse pyright defaults', () => {
167+
const partiallyExpaneded = SettingsSchemaManager.expandDottedAsNeeded({
168+
dottedSettings: COLLAPSED_PYRIGHT_SETTINGS,
169+
specs: map({
170+
pyright: {
171+
display_name: 'pyright',
172+
// server-specific defaults and allowed values
173+
config_schema: PYRIGHT_SCHEMA
174+
}
175+
}) as LanguageServerManager['specs']
176+
});
177+
expect(partiallyExpaneded).toEqual({
178+
pyright: {
179+
priority: 50,
180+
serverSettings: {
181+
'python.analysis.autoImportCompletions': false,
182+
'python.analysis.diagnosticSeverityOverrides': {
183+
reportFunctionMemberAccess: 'none',
184+
reportGeneralTypeIssues: 'error',
185+
reportMissingImports: 'none',
186+
reportPropertyTypeMismatch: 'none'
187+
},
188+
'python.analysis.extraPaths': [],
189+
'python.analysis.stubPath': 'typings',
190+
'python.pythonPath': 'python'
191+
}
192+
}
193+
});
194+
});
195+
});
196+
197+
describe('#transformSchemas()', () => {
198+
it('should merge dotted defaults', () => {
199+
const schema = JSONExt.deepCopy(SCHEMA) as any;
200+
201+
// Set a few defaults as if these came from `overrides.json`:
202+
// - using fully dotted name
203+
schema.properties.language_servers.default.pyright.serverSettings[
204+
'python.analysis.diagnosticSeverityOverrides.reportGeneralTypeIssues'
205+
] = 'warning';
206+
// - using nesting on final level (as defined in source pyright schema)
207+
schema.properties.language_servers.default.pyright.serverSettings[
208+
'python.analysis.diagnosticSeverityOverrides'
209+
] = {
210+
reportPropertyTypeMismatch: 'warning'
211+
};
212+
213+
const { defaults } = SettingsSchemaManager.transformSchemas({
214+
// plugin schema which includes overrides from `overrides.json`
215+
schema,
216+
specs: map({
217+
pyright: {
218+
display_name: 'pyright',
219+
// server-specific defaults and allowed values
220+
config_schema: PYRIGHT_SCHEMA,
221+
// overrides defined in specs files e.g. `jupyter_server_config.py`
222+
workspace_configuration: {
223+
// using fully dotted name
224+
'python.analysis.diagnosticSeverityOverrides.reportFunctionMemberAccess':
225+
'warning',
226+
// using nesting on final level (as defined in source pyright schema)
227+
'python.analysis.diagnosticSeverityOverrides': {
228+
reportUnusedImport: 'warning'
229+
}
230+
}
231+
}
232+
}) as LanguageServerManager['specs'],
233+
sessions: AVAILABLE_SESSIONS
234+
});
235+
const defaultOverrides =
236+
defaults.pyright.serverSettings[
237+
'python.analysis.diagnosticSeverityOverrides'
238+
];
239+
expect(defaultOverrides).toEqual({
240+
// `overrides.json`:
241+
// - should provide `reportGeneralTypeIssues` defined with fully dotted key
242+
reportGeneralTypeIssues: 'warning',
243+
// - should provide `reportPropertyTypeMismatch` defined with nesting on final level
244+
// `jupyter_server_config.py`:
245+
reportPropertyTypeMismatch: 'warning',
246+
// - should provide `reportFunctionMemberAccess` defined with fully dotted key
247+
reportFunctionMemberAccess: 'warning',
248+
// - should provide `reportUnusedImport` defined with nesting on final level
249+
reportUnusedImport: 'warning'
250+
// should NOT include `reportUnusedClass` default defined in server schema
251+
});
252+
});
253+
});
254+
6255
describe('#mergeByServer()', () => {
7256
it('prioritises user `priority` over the default', () => {
8257
const defaults = {

0 commit comments

Comments
 (0)