Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/contextkey/test/common/parser.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import assert from 'assert';
6
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
7
import { Parser } from '../../common/contextkey.js';
8
9
function parseToStr(input: string): string {
10
const parser = new Parser();
11
12
const prints: string[] = [];
13
14
const print = (...ss: string[]) => { ss.forEach(s => prints.push(s)); };
15
16
const expr = parser.parse(input);
17
if (expr === undefined) {
18
if (parser.lexingErrors.length > 0) {
19
print('Lexing errors:', '\n\n');
20
parser.lexingErrors.forEach(lexingError => print(`Unexpected token '${lexingError.lexeme}' at offset ${lexingError.offset}. ${lexingError.additionalInfo}`, '\n'));
21
}
22
23
if (parser.parsingErrors.length > 0) {
24
if (parser.lexingErrors.length > 0) { print('\n --- \n'); }
25
print('Parsing errors:', '\n\n');
26
parser.parsingErrors.forEach(parsingError => print(`Unexpected '${parsingError.lexeme}' at offset ${parsingError.offset}.`, '\n'));
27
}
28
29
} else {
30
print(expr.serialize());
31
}
32
33
return prints.join('');
34
}
35
36
suite('Context Key Parser', () => {
37
38
ensureNoDisposablesAreLeakedInTestSuite();
39
40
test(' foo', () => {
41
const input = ' foo';
42
assert.deepStrictEqual(parseToStr(input), "foo");
43
});
44
45
test('!foo', () => {
46
const input = '!foo';
47
assert.deepStrictEqual(parseToStr(input), "!foo");
48
});
49
50
test('foo =~ /bar/', () => {
51
const input = 'foo =~ /bar/';
52
assert.deepStrictEqual(parseToStr(input), "foo =~ /bar/");
53
});
54
55
test(`foo || (foo =~ /bar/ && baz)`, () => {
56
const input = `foo || (foo =~ /bar/ && baz)`;
57
assert.deepStrictEqual(parseToStr(input), "foo || baz && foo =~ /bar/");
58
});
59
60
test('foo || (foo =~ /bar/ || baz)', () => {
61
const input = 'foo || (foo =~ /bar/ || baz)';
62
assert.deepStrictEqual(parseToStr(input), "baz || foo || foo =~ /bar/");
63
});
64
65
test(`(foo || bar) && (jee || jar)`, () => {
66
const input = `(foo || bar) && (jee || jar)`;
67
assert.deepStrictEqual(parseToStr(input), "bar && jar || bar && jee || foo && jar || foo && jee");
68
});
69
70
test('foo && foo =~ /zee/i', () => {
71
const input = 'foo && foo =~ /zee/i';
72
assert.deepStrictEqual(parseToStr(input), "foo && foo =~ /zee/i");
73
});
74
75
test('foo.bar==enabled', () => {
76
const input = 'foo.bar==enabled';
77
assert.deepStrictEqual(parseToStr(input), "foo.bar == 'enabled'");
78
});
79
80
test(`foo.bar == 'enabled'`, () => {
81
const input = `foo.bar == 'enabled'`;
82
assert.deepStrictEqual(parseToStr(input), `foo.bar == 'enabled'`);
83
});
84
85
test('foo.bar:zed==completed - equality with no space', () => {
86
const input = 'foo.bar:zed==completed';
87
assert.deepStrictEqual(parseToStr(input), "foo.bar:zed == 'completed'");
88
});
89
90
test('a && b || c', () => {
91
const input = 'a && b || c';
92
assert.deepStrictEqual(parseToStr(input), "c || a && b");
93
});
94
95
test('fooBar && baz.jar && fee.bee<K-loo+1>', () => {
96
const input = 'fooBar && baz.jar && fee.bee<K-loo+1>';
97
assert.deepStrictEqual(parseToStr(input), "baz.jar && fee.bee<K-loo+1> && fooBar");
98
});
99
100
test('foo.barBaz<C-r> < 2', () => {
101
const input = 'foo.barBaz<C-r> < 2';
102
assert.deepStrictEqual(parseToStr(input), `foo.barBaz<C-r> < 2`);
103
});
104
105
test('foo.bar >= -1', () => {
106
const input = 'foo.bar >= -1';
107
assert.deepStrictEqual(parseToStr(input), "foo.bar >= -1");
108
});
109
110
test(`key contains &nbsp: view == vsc-packages-activitybar-folders && vsc-packages-folders-loaded`, () => {
111
const input = `view == vsc-packages-activitybar-folders && vsc-packages-folders-loaded`;
112
assert.deepStrictEqual(parseToStr(input), "vsc-packages-folders-loaded && view == 'vsc-packages-activitybar-folders'");
113
});
114
115
test('foo.bar <= -1', () => {
116
const input = 'foo.bar <= -1';
117
assert.deepStrictEqual(parseToStr(input), `foo.bar <= -1`);
118
});
119
120
test('!cmake:hideBuildCommand \u0026\u0026 cmake:enableFullFeatureSet', () => {
121
const input = '!cmake:hideBuildCommand \u0026\u0026 cmake:enableFullFeatureSet';
122
assert.deepStrictEqual(parseToStr(input), "cmake:enableFullFeatureSet && !cmake:hideBuildCommand");
123
});
124
125
test('!(foo && bar)', () => {
126
const input = '!(foo && bar)';
127
assert.deepStrictEqual(parseToStr(input), "!bar || !foo");
128
});
129
130
test('!(foo && bar || boar) || deer', () => {
131
const input = '!(foo && bar || boar) || deer';
132
assert.deepStrictEqual(parseToStr(input), "deer || !bar && !boar || !boar && !foo");
133
});
134
135
test(`!(!foo)`, () => {
136
const input = `!(!foo)`;
137
assert.deepStrictEqual(parseToStr(input), "foo");
138
});
139
140
suite('controversial', () => {
141
/*
142
new parser KEEPS old one's behavior:
143
144
old parser output: { key: 'debugState', op: '==', value: '"stopped"' }
145
new parser output: { key: 'debugState', op: '==', value: '"stopped"' }
146
147
TODO@ulugbekna: we should consider breaking old parser's behavior, and not take double quotes as part of the `value` because that's not what user expects.
148
*/
149
test(`debugState == "stopped"`, () => {
150
const input = `debugState == "stopped"`;
151
assert.deepStrictEqual(parseToStr(input), "debugState == '\"stopped\"'");
152
});
153
154
/*
155
new parser BREAKS old one's behavior:
156
157
old parser output: { key: 'viewItem', op: '==', value: 'VSCode WorkSpace' }
158
new parser output: { key: 'viewItem', op: '==', value: 'VSCode' }
159
160
TODO@ulugbekna: since this's breaking, we can have hacky code that tries detecting such cases and replicate old parser's behavior.
161
*/
162
test(` viewItem == VSCode WorkSpace`, () => {
163
const input = ` viewItem == VSCode WorkSpace`;
164
assert.deepStrictEqual(parseToStr(input), "Parsing errors:\n\nUnexpected 'WorkSpace' at offset 20.\n");
165
});
166
167
168
});
169
170
suite('regex', () => {
171
172
test(`resource =~ //foo/(barr|door/(Foo-Bar%20Templates|Soo%20Looo)|Web%20Site%Jjj%20Llll)(/.*)*$/`, () => {
173
const input = `resource =~ //foo/(barr|door/(Foo-Bar%20Templates|Soo%20Looo)|Web%20Site%Jjj%20Llll)(/.*)*$/`;
174
assert.deepStrictEqual(parseToStr(input), "resource =~ /\\/foo\\/(barr|door\\/(Foo-Bar%20Templates|Soo%20Looo)|Web%20Site%Jjj%20Llll)(\\/.*)*$/");
175
});
176
177
test(`resource =~ /((/scratch/(?!update)(.*)/)|((/src/).*/)).*$/`, () => {
178
const input = `resource =~ /((/scratch/(?!update)(.*)/)|((/src/).*/)).*$/`;
179
assert.deepStrictEqual(parseToStr(input), "resource =~ /((\\/scratch\\/(?!update)(.*)\\/)|((\\/src\\/).*\\/)).*$/");
180
});
181
182
test(`resourcePath =~ /\.md(\.yml|\.txt)*$/giym`, () => {
183
const input = `resourcePath =~ /\.md(\.yml|\.txt)*$/giym`;
184
assert.deepStrictEqual(parseToStr(input), "resourcePath =~ /.md(.yml|.txt)*$/im");
185
});
186
187
});
188
189
suite('error handling', () => {
190
191
test(`/foo`, () => {
192
const input = `/foo`;
193
assert.deepStrictEqual(parseToStr(input), "Lexing errors:\n\nUnexpected token '/foo' at offset 0. Did you forget to escape the '/' (slash) character? Put two backslashes before it to escape, e.g., '\\\\/'.\n\n --- \nParsing errors:\n\nUnexpected '/foo' at offset 0.\n");
194
});
195
196
test(`!b == 'true'`, () => {
197
const input = `!b == 'true'`;
198
assert.deepStrictEqual(parseToStr(input), "Parsing errors:\n\nUnexpected '==' at offset 3.\n");
199
});
200
201
test('!foo && in bar', () => {
202
const input = '!foo && in bar';
203
assert.deepStrictEqual(parseToStr(input), "Parsing errors:\n\nUnexpected 'in' at offset 9.\n");
204
});
205
206
test('vim<c-r> == 1 && vim<2<=3', () => {
207
const input = 'vim<c-r> == 1 && vim<2<=3';
208
assert.deepStrictEqual(parseToStr(input), "Lexing errors:\n\nUnexpected token '=' at offset 23. Did you mean == or =~?\n\n --- \nParsing errors:\n\nUnexpected '=' at offset 23.\n"); // FIXME
209
});
210
211
test(`foo && 'bar`, () => {
212
const input = `foo && 'bar`;
213
assert.deepStrictEqual(parseToStr(input), "Lexing errors:\n\nUnexpected token ''bar' at offset 7. Did you forget to open or close the quote?\n\n --- \nParsing errors:\n\nUnexpected ''bar' at offset 7.\n");
214
});
215
216
test(`config.foo && &&bar =~ /^foo$|^bar-foo$|^joo$|^jar$/ && !foo`, () => {
217
const input = `config.foo && &&bar =~ /^foo$|^bar-foo$|^joo$|^jar$/ && !foo`;
218
assert.deepStrictEqual(parseToStr(input), "Parsing errors:\n\nUnexpected '&&' at offset 15.\n");
219
});
220
221
test(`!foo == 'test'`, () => {
222
const input = `!foo == 'test'`;
223
assert.deepStrictEqual(parseToStr(input), "Parsing errors:\n\nUnexpected '==' at offset 5.\n");
224
});
225
226
test(`!!foo`, function () {
227
const input = `!!foo`;
228
assert.deepStrictEqual(parseToStr(input), "Parsing errors:\n\nUnexpected '!' at offset 1.\n");
229
});
230
231
});
232
233
});
234
235