Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/contextkey/test/common/scanner.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 { Scanner, Token, TokenType } from '../../common/scanner.js';
8
9
suite('Context Key Scanner', () => {
10
11
ensureNoDisposablesAreLeakedInTestSuite();
12
13
function tokenTypeToStr(token: Token) {
14
switch (token.type) {
15
case TokenType.LParen:
16
return '(';
17
case TokenType.RParen:
18
return ')';
19
case TokenType.Neg:
20
return '!';
21
case TokenType.Eq:
22
return token.isTripleEq ? '===' : '==';
23
case TokenType.NotEq:
24
return token.isTripleEq ? '!==' : '!=';
25
case TokenType.Lt:
26
return '<';
27
case TokenType.LtEq:
28
return '<=';
29
case TokenType.Gt:
30
return '>';
31
case TokenType.GtEq:
32
return '>=';
33
case TokenType.RegexOp:
34
return '=~';
35
case TokenType.RegexStr:
36
return 'RegexStr';
37
case TokenType.True:
38
return 'true';
39
case TokenType.False:
40
return 'false';
41
case TokenType.In:
42
return 'in';
43
case TokenType.Not:
44
return 'not';
45
case TokenType.And:
46
return '&&';
47
case TokenType.Or:
48
return '||';
49
case TokenType.Str:
50
return 'Str';
51
case TokenType.QuotedStr:
52
return 'QuotedStr';
53
case TokenType.Error:
54
return 'ErrorToken';
55
case TokenType.EOF:
56
return 'EOF';
57
}
58
59
}
60
61
function scan(input: string) {
62
return (new Scanner()).reset(input).scan().map((token: Token) => {
63
return 'lexeme' in token
64
? {
65
type: tokenTypeToStr(token),
66
offset: token.offset,
67
lexeme: token.lexeme
68
} : {
69
type: tokenTypeToStr(token),
70
offset: token.offset
71
};
72
});
73
}
74
75
suite('scanning various cases of context keys', () => {
76
77
test('foo.bar<C-shift+2>', () => {
78
const input = 'foo.bar<C-shift+2>';
79
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo.bar<C-shift+2>", offset: 0 }, { type: "EOF", offset: 18 }]));
80
});
81
82
test('!foo', () => {
83
const input = '!foo';
84
assert.deepStrictEqual(scan(input), ([{ type: "!", offset: 0 }, { type: "Str", lexeme: "foo", offset: 1 }, { type: "EOF", offset: 4 }]));
85
});
86
87
test('foo === bar', () => {
88
const input = 'foo === bar';
89
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "EOF", offset: 11 }]));
90
});
91
92
test('foo !== bar', () => {
93
const input = 'foo !== bar';
94
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "!==", offset: 5 }, { type: "Str", offset: 9, lexeme: "bar" }, { type: "EOF", offset: 12 }]));
95
});
96
97
test('!(foo && bar)', () => {
98
const input = '!(foo && bar)';
99
assert.deepStrictEqual(scan(input), ([{ type: "!", offset: 0 }, { type: "(", offset: 1 }, { type: "Str", lexeme: "foo", offset: 2 }, { type: "&&", offset: 6 }, { type: "Str", lexeme: "bar", offset: 9 }, { type: ")", offset: 12 }, { type: "EOF", offset: 13 }]));
100
});
101
102
test('=~ ', () => {
103
const input = '=~ ';
104
assert.deepStrictEqual(scan(input), ([{ type: "=~", offset: 0 }, { type: "EOF", offset: 3 }]));
105
});
106
107
test('foo =~ /bar/', () => {
108
const input = 'foo =~ /bar/';
109
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo", offset: 0 }, { type: "=~", offset: 4 }, { type: "RegexStr", lexeme: "/bar/", offset: 7 }, { type: "EOF", offset: 12 }]));
110
});
111
112
test('foo =~ /zee/i', () => {
113
const input = 'foo =~ /zee/i';
114
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo", offset: 0 }, { type: "=~", offset: 4 }, { type: "RegexStr", lexeme: "/zee/i", offset: 7 }, { type: "EOF", offset: 13 }]));
115
});
116
117
118
test('foo =~ /zee/gm', () => {
119
const input = 'foo =~ /zee/gm';
120
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo", offset: 0 }, { type: "=~", offset: 4 }, { type: "RegexStr", lexeme: "/zee/gm", offset: 7 }, { type: "EOF", offset: 14 }]));
121
});
122
123
test('foo in barrr ', () => {
124
const input = 'foo in barrr ';
125
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo", offset: 0 }, { type: "in", offset: 4 }, { type: "Str", lexeme: "barrr", offset: 7 }, { type: "EOF", offset: 14 }]));
126
});
127
128
test(`resource =~ //FileCabinet/(SuiteScripts|Templates/(E-mail%20Templates|Marketing%20Templates)|Web%20Site%20Hosting%20Files)(/.*)*$/`, () => {
129
const input = `resource =~ //FileCabinet/(SuiteScripts|Templates/(E-mail%20Templates|Marketing%20Templates)|Web%20Site%20Hosting%20Files)(/.*)*$/`;
130
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "resource" }, { type: "=~", offset: 9 }, { type: "RegexStr", offset: 12, lexeme: "//" }, { type: "Str", offset: 14, lexeme: "FileCabinet/" }, { type: "(", offset: 26 }, { type: "Str", offset: 27, lexeme: "SuiteScripts" }, { type: "ErrorToken", offset: 39, lexeme: "|" }, { type: "Str", offset: 40, lexeme: "Templates/" }, { type: "(", offset: 50 }, { type: "Str", offset: 51, lexeme: "E-mail%20Templates" }, { type: "ErrorToken", offset: 69, lexeme: "|" }, { type: "Str", offset: 70, lexeme: "Marketing%20Templates" }, { type: ")", offset: 91 }, { type: "ErrorToken", offset: 92, lexeme: "|" }, { type: "Str", offset: 93, lexeme: "Web%20Site%20Hosting%20Files" }, { type: ")", offset: 121 }, { type: "(", offset: 122 }, { type: "RegexStr", offset: 123, lexeme: "/.*)*$/" }, { type: "EOF", offset: 130 }]));
131
});
132
133
test('editorLangId in testely.supportedLangIds && resourceFilename =~ /^.+(.test.(\w+))$/gm', () => {
134
const input = 'editorLangId in testely.supportedLangIds && resourceFilename =~ /^.+(.test.(\w+))$/gm';
135
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "editorLangId", offset: 0 }, { type: "in", offset: 13 }, { type: "Str", lexeme: "testely.supportedLangIds", offset: 16 }, { type: "&&", offset: 41 }, { type: "Str", lexeme: "resourceFilename", offset: 44 }, { type: "=~", offset: 61 }, { type: "RegexStr", lexeme: "/^.+(.test.(w+))$/gm", offset: 64 }, { type: "EOF", offset: 84 }]));
136
});
137
138
test('!(foo && bar) && baz', () => {
139
const input = '!(foo && bar) && baz';
140
assert.deepStrictEqual(scan(input), ([{ type: "!", offset: 0 }, { type: "(", offset: 1 }, { type: "Str", lexeme: "foo", offset: 2 }, { type: "&&", offset: 6 }, { type: "Str", lexeme: "bar", offset: 9 }, { type: ")", offset: 12 }, { type: "&&", offset: 14 }, { type: "Str", lexeme: "baz", offset: 17 }, { type: "EOF", offset: 20 }]));
141
});
142
143
test('foo.bar:zed==completed - equality with no space', () => {
144
const input = 'foo.bar:zed==completed';
145
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo.bar:zed", offset: 0 }, { type: "==", offset: 11 }, { type: "Str", lexeme: "completed", offset: 13 }, { type: "EOF", offset: 22 }]));
146
});
147
148
test('a && b || c', () => {
149
const input = 'a && b || c';
150
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "a", offset: 0 }, { type: "&&", offset: 2 }, { type: "Str", lexeme: "b", offset: 5 }, { type: "||", offset: 7 }, { type: "Str", lexeme: "c", offset: 10 }, { type: "EOF", offset: 11 }]));
151
});
152
153
test('fooBar && baz.jar && fee.bee<K-loo+1>', () => {
154
const input = 'fooBar && baz.jar && fee.bee<K-loo+1>';
155
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "fooBar", offset: 0 }, { type: "&&", offset: 7 }, { type: "Str", lexeme: "baz.jar", offset: 10 }, { type: "&&", offset: 18 }, { type: "Str", lexeme: "fee.bee<K-loo+1>", offset: 21 }, { type: "EOF", offset: 37 }]));
156
});
157
158
test('foo.barBaz<C-r> < 2', () => {
159
const input = 'foo.barBaz<C-r> < 2';
160
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo.barBaz<C-r>", offset: 0 }, { type: "<", offset: 16 }, { type: "Str", lexeme: "2", offset: 18 }, { type: "EOF", offset: 19 }]));
161
});
162
163
test('foo.bar >= -1', () => {
164
const input = 'foo.bar >= -1';
165
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo.bar", offset: 0 }, { type: ">=", offset: 8 }, { type: "Str", lexeme: "-1", offset: 11 }, { type: "EOF", offset: 13 }]));
166
});
167
168
test('foo.bar <= -1', () => {
169
const input = 'foo.bar <= -1';
170
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo.bar", offset: 0 }, { type: "<=", offset: 8 }, { type: "Str", lexeme: "-1", offset: 11 }, { type: "EOF", offset: 13 }]));
171
});
172
173
test(`resource =~ /\\/Objects\\/.+\\.xml$/`, () => {
174
const input = `resource =~ /\\/Objects\\/.+\\.xml$/`;
175
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "resource", offset: 0 }, { type: "=~", offset: 9 }, { type: "RegexStr", lexeme: "/\\/Objects\\/.+\\.xml$/", offset: 12 }, { type: "EOF", offset: 33 }]));
176
});
177
178
test('view == vsc-packages-activitybar-foldersĀ && vsc-packages-folders-loaded', () => {
179
const input = `view == vsc-packages-activitybar-foldersĀ && vsc-packages-folders-loaded`;
180
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "view", offset: 0 }, { type: "==", offset: 5 }, { type: "Str", lexeme: "vsc-packages-activitybar-folders", offset: 8 }, { type: "&&", offset: 41 }, { type: "Str", lexeme: "vsc-packages-folders-loaded", offset: 44 }, { type: "EOF", offset: 71 }]));
181
});
182
183
test(`sfdx:project_opened && resource =~ /.*\\/functions\\/.*\\/[^\\/]+(\\/[^\\/]+\.(ts|js|java|json|toml))?$/ && resourceFilename != package.json && resourceFilename != package-lock.json && resourceFilename != tsconfig.json`, () => {
184
const input = `sfdx:project_opened && resource =~ /.*\\/functions\\/.*\\/[^\\/]+(\\/[^\\/]+\.(ts|js|java|json|toml))?$/ && resourceFilename != package.json && resourceFilename != package-lock.json && resourceFilename != tsconfig.json`;
185
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "sfdx:project_opened", offset: 0 }, { type: "&&", offset: 20 }, { type: "Str", lexeme: "resource", offset: 23 }, { type: "=~", offset: 32 }, { type: "RegexStr", lexeme: "/.*\\/functions\\/.*\\/[^\\/]+(\\/[^\\/]+.(ts|js|java|json|toml))?$/", offset: 35 }, { type: "&&", offset: 98 }, { type: "Str", lexeme: "resourceFilename", offset: 101 }, { type: "!=", offset: 118 }, { type: "Str", lexeme: "package.json", offset: 121 }, { type: "&&", offset: 134 }, { type: "Str", lexeme: "resourceFilename", offset: 137 }, { type: "!=", offset: 154 }, { type: "Str", lexeme: "package-lock.json", offset: 157 }, { type: "&&", offset: 175 }, { type: "Str", lexeme: "resourceFilename", offset: 178 }, { type: "!=", offset: 195 }, { type: "Str", lexeme: "tsconfig.json", offset: 198 }, { type: "EOF", offset: 211 }]));
186
});
187
188
test(`view =~ '/(servers)/' && viewItem =~ '/^(Starting|Started|Debugging|Stopping|Stopped)/'`, () => {
189
const input = `view =~ '/(servers)/' && viewItem =~ '/^(Starting|Started|Debugging|Stopping|Stopped)/'`;
190
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "view", offset: 0 }, { type: "=~", offset: 5 }, { type: "QuotedStr", lexeme: "/(servers)/", offset: 9 }, { type: "&&", offset: 22 }, { type: "Str", lexeme: "viewItem", offset: 25 }, { type: "=~", offset: 34 }, { type: "QuotedStr", lexeme: "/^(Starting|Started|Debugging|Stopping|Stopped)/", offset: 38 }, { type: "EOF", offset: 87 }]));
191
});
192
193
test(`resourcePath =~ /\.md(\.yml|\.txt)*$/gim`, () => {
194
const input = `resourcePath =~ /\.md(\.yml|\.txt)*$/gim`;
195
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "resourcePath" }, { type: "=~", offset: 13 }, { type: "RegexStr", offset: 16, lexeme: "/.md(.yml|.txt)*$/gim" }, { type: "EOF", offset: 37 }]));
196
});
197
});
198
199
test(`foo === bar'`, () => {
200
const input = `foo === bar'`;
201
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "ErrorToken", offset: 11, lexeme: "'" }, { type: "EOF", offset: 12 }]));
202
});
203
204
suite('handling lexical errors', () => {
205
206
test(`foo === '`, () => {
207
const input = `foo === '`;
208
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "ErrorToken", offset: 8, lexeme: "'" }, { type: "EOF", offset: 9 }]));
209
});
210
211
test(`foo && 'bar - unterminated single quote`, () => {
212
const input = `foo && 'bar`;
213
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo", offset: 0 }, { type: "&&", offset: 4 }, { type: "ErrorToken", offset: 7, lexeme: "'bar" }, { type: "EOF", offset: 11 }]));
214
});
215
216
test('vim<c-r> == 1 && vim<2 <= 3', () => {
217
const input = 'vim<c-r> == 1 && vim<2 <= 3';
218
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "vim<c-r>", offset: 0 }, { type: "==", offset: 9 }, { type: "Str", lexeme: "1", offset: 12 }, { type: "&&", offset: 14 }, { type: "Str", lexeme: "vim<2", offset: 17 }, { type: "<=", offset: 23 }, { type: "Str", lexeme: "3", offset: 26 }, { type: "EOF", offset: 27 }]));
219
});
220
221
test('vim<c-r>==1 && vim<2<=3', () => {
222
const input = 'vim<c-r>==1 && vim<2<=3';
223
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "vim<c-r>" }, { type: "==", offset: 8 }, { type: "Str", offset: 10, lexeme: "1" }, { type: "&&", offset: 12 }, { type: "Str", offset: 15, lexeme: "vim<2<" }, { type: "ErrorToken", offset: 21, lexeme: "=" }, { type: "Str", offset: 22, lexeme: "3" }, { type: "EOF", offset: 23 }]));
224
});
225
226
test(`foo|bar`, () => {
227
const input = `foo|bar`;
228
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "ErrorToken", offset: 3, lexeme: "|" }, { type: "Str", offset: 4, lexeme: "bar" }, { type: "EOF", offset: 7 }]));
229
});
230
231
test(`resource =~ //foo/(barr|door/(Foo-Bar%20Templates|Soo%20Looo)|Web%20Site%Jjj%20Llll)(/.*)*$/`, () => {
232
const input = `resource =~ //foo/(barr|door/(Foo-Bar%20Templates|Soo%20Looo)|Web%20Site%Jjj%20Llll)(/.*)*$/`;
233
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "resource" }, { type: "=~", offset: 9 }, { type: "RegexStr", offset: 12, lexeme: "//" }, { type: "Str", offset: 14, lexeme: "foo/" }, { type: "(", offset: 18 }, { type: "Str", offset: 19, lexeme: "barr" }, { type: "ErrorToken", offset: 23, lexeme: "|" }, { type: "Str", offset: 24, lexeme: "door/" }, { type: "(", offset: 29 }, { type: "Str", offset: 30, lexeme: "Foo-Bar%20Templates" }, { type: "ErrorToken", offset: 49, lexeme: "|" }, { type: "Str", offset: 50, lexeme: "Soo%20Looo" }, { type: ")", offset: 60 }, { type: "ErrorToken", offset: 61, lexeme: "|" }, { type: "Str", offset: 62, lexeme: "Web%20Site%Jjj%20Llll" }, { type: ")", offset: 83 }, { type: "(", offset: 84 }, { type: "RegexStr", offset: 85, lexeme: "/.*)*$/" }, { type: "EOF", offset: 92 }]));
234
});
235
236
test(`/((/foo/(?!bar)(.*)/)|((/src/).*/)).*$/`, () => {
237
const input = `/((/foo/(?!bar)(.*)/)|((/src/).*/)).*$/`;
238
assert.deepStrictEqual(scan(input), ([{ type: "RegexStr", offset: 0, lexeme: "/((/" }, { type: "Str", offset: 4, lexeme: "foo/" }, { type: "(", offset: 8 }, { type: "Str", offset: 9, lexeme: "?" }, { type: "!", offset: 10 }, { type: "Str", offset: 11, lexeme: "bar" }, { type: ")", offset: 14 }, { type: "(", offset: 15 }, { type: "Str", offset: 16, lexeme: ".*" }, { type: ")", offset: 18 }, { type: "RegexStr", offset: 19, lexeme: "/)|((/s" }, { type: "Str", offset: 26, lexeme: "rc/" }, { type: ")", offset: 29 }, { type: "Str", offset: 30, lexeme: ".*/" }, { type: ")", offset: 33 }, { type: ")", offset: 34 }, { type: "Str", offset: 35, lexeme: ".*$/" }, { type: "EOF", offset: 39 }]));
239
});
240
241
test(`resourcePath =~ //foo/barr// || resourcePath =~ //view/(jarrr|doooor|bees)/(web|templates)// && resourceExtname in foo.Bar`, () => {
242
const input = `resourcePath =~ //foo/barr// || resourcePath =~ //view/(jarrr|doooor|bees)/(web|templates)// && resourceExtname in foo.Bar`;
243
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "resourcePath" }, { type: "=~", offset: 13 }, { type: "RegexStr", offset: 16, lexeme: "//" }, { type: "Str", offset: 18, lexeme: "foo/barr//" }, { type: "||", offset: 29 }, { type: "Str", offset: 32, lexeme: "resourcePath" }, { type: "=~", offset: 45 }, { type: "RegexStr", offset: 48, lexeme: "//" }, { type: "Str", offset: 50, lexeme: "view/" }, { type: "(", offset: 55 }, { type: "Str", offset: 56, lexeme: "jarrr" }, { type: "ErrorToken", offset: 61, lexeme: "|" }, { type: "Str", offset: 62, lexeme: "doooor" }, { type: "ErrorToken", offset: 68, lexeme: "|" }, { type: "Str", offset: 69, lexeme: "bees" }, { type: ")", offset: 73 }, { type: "RegexStr", offset: 74, lexeme: "/(web|templates)/" }, { type: "ErrorToken", offset: 91, lexeme: "/ && resourceExtname in foo.Bar" }, { type: "EOF", offset: 122 }]));
244
});
245
246
test(`foo =~ /file:\// || bar`, () => {
247
const input = JSON.parse('"foo =~ /file:\// || bar"');
248
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "=~", offset: 4 }, { type: "RegexStr", offset: 7, lexeme: "/file:/" }, { type: "ErrorToken", offset: 14, lexeme: "/ || bar" }, { type: "EOF", offset: 22 }]));
249
});
250
});
251
});
252
253