Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/snippet/test/browser/snippetController2.old.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 { mock } from '../../../../../base/test/common/mock.js';
7
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
8
import { ICodeEditor } from '../../../../browser/editorBrowser.js';
9
import { Position } from '../../../../common/core/position.js';
10
import { Selection } from '../../../../common/core/selection.js';
11
import { LanguageFeaturesService } from '../../../../common/services/languageFeaturesService.js';
12
import { SnippetController2 } from '../../browser/snippetController2.js';
13
import { ITestCodeEditor, withTestCodeEditor } from '../../../../test/browser/testCodeEditor.js';
14
import { TestLanguageConfigurationService } from '../../../../test/common/modes/testLanguageConfigurationService.js';
15
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
16
import { ServiceCollection } from '../../../../../platform/instantiation/common/serviceCollection.js';
17
import { ILabelService } from '../../../../../platform/label/common/label.js';
18
import { NullLogService } from '../../../../../platform/log/common/log.js';
19
import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js';
20
21
class TestSnippetController extends SnippetController2 {
22
23
private _testLanguageConfigurationService: TestLanguageConfigurationService;
24
25
constructor(
26
editor: ICodeEditor,
27
@IContextKeyService private readonly _contextKeyService: IContextKeyService
28
) {
29
const testLanguageConfigurationService = new TestLanguageConfigurationService();
30
super(editor, new NullLogService(), new LanguageFeaturesService(), _contextKeyService, testLanguageConfigurationService);
31
this._testLanguageConfigurationService = testLanguageConfigurationService;
32
}
33
34
override dispose(): void {
35
super.dispose();
36
this._testLanguageConfigurationService.dispose();
37
}
38
39
isInSnippetMode(): boolean {
40
return SnippetController2.InSnippetMode.getValue(this._contextKeyService)!;
41
}
42
}
43
44
suite('SnippetController', () => {
45
46
ensureNoDisposablesAreLeakedInTestSuite();
47
48
function snippetTest(cb: (editor: ITestCodeEditor, template: string, snippetController: TestSnippetController) => void, lines?: string[]): void {
49
50
if (!lines) {
51
lines = [
52
'function test() {',
53
'\tvar x = 3;',
54
'\tvar arr = [];',
55
'\t',
56
'}'
57
];
58
}
59
60
const serviceCollection = new ServiceCollection(
61
[ILabelService, new class extends mock<ILabelService>() { }],
62
[IWorkspaceContextService, new class extends mock<IWorkspaceContextService>() { }],
63
);
64
65
withTestCodeEditor(lines, { serviceCollection }, (editor) => {
66
editor.getModel()!.updateOptions({
67
insertSpaces: false
68
});
69
const snippetController = editor.registerAndInstantiateContribution(TestSnippetController.ID, TestSnippetController);
70
const template = [
71
'for (var ${1:index}; $1 < ${2:array}.length; $1++) {',
72
'\tvar element = $2[$1];',
73
'\t$0',
74
'}'
75
].join('\n');
76
77
cb(editor, template, snippetController);
78
snippetController.dispose();
79
});
80
}
81
82
test('Simple accepted', () => {
83
snippetTest((editor, template, snippetController) => {
84
editor.setPosition({ lineNumber: 4, column: 2 });
85
86
snippetController.insert(template);
87
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {');
88
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];');
89
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
90
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
91
92
editor.trigger('test', 'type', { text: 'i' });
93
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var i; i < array.length; i++) {');
94
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = array[i];');
95
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
96
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
97
98
snippetController.next();
99
editor.trigger('test', 'type', { text: 'arr' });
100
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var i; i < arr.length; i++) {');
101
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = arr[i];');
102
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
103
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
104
105
snippetController.prev();
106
editor.trigger('test', 'type', { text: 'j' });
107
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var j; j < arr.length; j++) {');
108
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = arr[j];');
109
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
110
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
111
112
snippetController.next();
113
snippetController.next();
114
assert.deepStrictEqual(editor.getPosition(), new Position(6, 3));
115
});
116
});
117
118
test('Simple canceled', () => {
119
snippetTest((editor, template, snippetController) => {
120
editor.setPosition({ lineNumber: 4, column: 2 });
121
122
snippetController.insert(template);
123
assert.strictEqual(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {');
124
assert.strictEqual(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];');
125
assert.strictEqual(editor.getModel()!.getLineContent(6), '\t\t');
126
assert.strictEqual(editor.getModel()!.getLineContent(7), '\t}');
127
128
snippetController.cancel();
129
assert.deepStrictEqual(editor.getPosition(), new Position(4, 16));
130
});
131
});
132
133
// test('Stops when deleting lines above', () => {
134
// snippetTest((editor, codeSnippet, snippetController) => {
135
// editor.setPosition({ lineNumber: 4, column: 2 });
136
// snippetController.insert(codeSnippet, 0, 0);
137
138
// editor.getModel()!.applyEdits([{
139
// forceMoveMarkers: false,
140
// identifier: null,
141
// isAutoWhitespaceEdit: false,
142
// range: new Range(1, 1, 3, 1),
143
// text: null
144
// }]);
145
146
// assert.strictEqual(snippetController.isInSnippetMode(), false);
147
// });
148
// });
149
150
// test('Stops when deleting lines below', () => {
151
// snippetTest((editor, codeSnippet, snippetController) => {
152
// editor.setPosition({ lineNumber: 4, column: 2 });
153
// snippetController.run(codeSnippet, 0, 0);
154
155
// editor.getModel()!.applyEdits([{
156
// forceMoveMarkers: false,
157
// identifier: null,
158
// isAutoWhitespaceEdit: false,
159
// range: new Range(8, 1, 8, 100),
160
// text: null
161
// }]);
162
163
// assert.strictEqual(snippetController.isInSnippetMode(), false);
164
// });
165
// });
166
167
// test('Stops when inserting lines above', () => {
168
// snippetTest((editor, codeSnippet, snippetController) => {
169
// editor.setPosition({ lineNumber: 4, column: 2 });
170
// snippetController.run(codeSnippet, 0, 0);
171
172
// editor.getModel()!.applyEdits([{
173
// forceMoveMarkers: false,
174
// identifier: null,
175
// isAutoWhitespaceEdit: false,
176
// range: new Range(1, 100, 1, 100),
177
// text: '\nHello'
178
// }]);
179
180
// assert.strictEqual(snippetController.isInSnippetMode(), false);
181
// });
182
// });
183
184
// test('Stops when inserting lines below', () => {
185
// snippetTest((editor, codeSnippet, snippetController) => {
186
// editor.setPosition({ lineNumber: 4, column: 2 });
187
// snippetController.run(codeSnippet, 0, 0);
188
189
// editor.getModel()!.applyEdits([{
190
// forceMoveMarkers: false,
191
// identifier: null,
192
// isAutoWhitespaceEdit: false,
193
// range: new Range(8, 100, 8, 100),
194
// text: '\nHello'
195
// }]);
196
197
// assert.strictEqual(snippetController.isInSnippetMode(), false);
198
// });
199
// });
200
201
test('Stops when calling model.setValue()', () => {
202
snippetTest((editor, codeSnippet, snippetController) => {
203
editor.setPosition({ lineNumber: 4, column: 2 });
204
snippetController.insert(codeSnippet);
205
206
editor.getModel()!.setValue('goodbye');
207
208
assert.strictEqual(snippetController.isInSnippetMode(), false);
209
});
210
});
211
212
test('Stops when undoing', () => {
213
snippetTest((editor, codeSnippet, snippetController) => {
214
editor.setPosition({ lineNumber: 4, column: 2 });
215
snippetController.insert(codeSnippet);
216
217
editor.getModel()!.undo();
218
219
assert.strictEqual(snippetController.isInSnippetMode(), false);
220
});
221
});
222
223
test('Stops when moving cursor outside', () => {
224
snippetTest((editor, codeSnippet, snippetController) => {
225
editor.setPosition({ lineNumber: 4, column: 2 });
226
snippetController.insert(codeSnippet);
227
228
editor.setPosition({ lineNumber: 1, column: 1 });
229
230
assert.strictEqual(snippetController.isInSnippetMode(), false);
231
});
232
});
233
234
test('Stops when disconnecting editor model', () => {
235
snippetTest((editor, codeSnippet, snippetController) => {
236
editor.setPosition({ lineNumber: 4, column: 2 });
237
snippetController.insert(codeSnippet);
238
239
editor.setModel(null);
240
241
assert.strictEqual(snippetController.isInSnippetMode(), false);
242
});
243
});
244
245
test('Stops when disposing editor', () => {
246
snippetTest((editor, codeSnippet, snippetController) => {
247
editor.setPosition({ lineNumber: 4, column: 2 });
248
snippetController.insert(codeSnippet);
249
250
snippetController.dispose();
251
252
assert.strictEqual(snippetController.isInSnippetMode(), false);
253
});
254
});
255
256
test('Final tabstop with multiple selections', () => {
257
snippetTest((editor, codeSnippet, snippetController) => {
258
editor.setSelections([
259
new Selection(1, 1, 1, 1),
260
new Selection(2, 1, 2, 1),
261
]);
262
263
codeSnippet = 'foo$0';
264
snippetController.insert(codeSnippet);
265
266
assert.strictEqual(editor.getSelections()!.length, 2);
267
const [first, second] = editor.getSelections()!;
268
assert.ok(first.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), first.toString());
269
assert.ok(second.equalsRange({ startLineNumber: 2, startColumn: 4, endLineNumber: 2, endColumn: 4 }), second.toString());
270
});
271
272
snippetTest((editor, codeSnippet, snippetController) => {
273
editor.setSelections([
274
new Selection(1, 1, 1, 1),
275
new Selection(2, 1, 2, 1),
276
]);
277
278
codeSnippet = 'foo$0bar';
279
snippetController.insert(codeSnippet);
280
281
assert.strictEqual(editor.getSelections()!.length, 2);
282
const [first, second] = editor.getSelections()!;
283
assert.ok(first.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), first.toString());
284
assert.ok(second.equalsRange({ startLineNumber: 2, startColumn: 4, endLineNumber: 2, endColumn: 4 }), second.toString());
285
});
286
287
snippetTest((editor, codeSnippet, snippetController) => {
288
editor.setSelections([
289
new Selection(1, 1, 1, 1),
290
new Selection(1, 5, 1, 5),
291
]);
292
293
codeSnippet = 'foo$0bar';
294
snippetController.insert(codeSnippet);
295
296
assert.strictEqual(editor.getSelections()!.length, 2);
297
const [first, second] = editor.getSelections()!;
298
assert.ok(first.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), first.toString());
299
assert.ok(second.equalsRange({ startLineNumber: 1, startColumn: 14, endLineNumber: 1, endColumn: 14 }), second.toString());
300
});
301
302
snippetTest((editor, codeSnippet, snippetController) => {
303
editor.setSelections([
304
new Selection(1, 1, 1, 1),
305
new Selection(1, 5, 1, 5),
306
]);
307
308
codeSnippet = 'foo\n$0\nbar';
309
snippetController.insert(codeSnippet);
310
311
assert.strictEqual(editor.getSelections()!.length, 2);
312
const [first, second] = editor.getSelections()!;
313
assert.ok(first.equalsRange({ startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 }), first.toString());
314
assert.ok(second.equalsRange({ startLineNumber: 4, startColumn: 1, endLineNumber: 4, endColumn: 1 }), second.toString());
315
});
316
317
snippetTest((editor, codeSnippet, snippetController) => {
318
editor.setSelections([
319
new Selection(1, 1, 1, 1),
320
new Selection(1, 5, 1, 5),
321
]);
322
323
codeSnippet = 'foo\n$0\nbar';
324
snippetController.insert(codeSnippet);
325
326
assert.strictEqual(editor.getSelections()!.length, 2);
327
const [first, second] = editor.getSelections()!;
328
assert.ok(first.equalsRange({ startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 }), first.toString());
329
assert.ok(second.equalsRange({ startLineNumber: 4, startColumn: 1, endLineNumber: 4, endColumn: 1 }), second.toString());
330
});
331
332
snippetTest((editor, codeSnippet, snippetController) => {
333
editor.setSelections([
334
new Selection(2, 7, 2, 7),
335
]);
336
337
codeSnippet = 'xo$0r';
338
snippetController.insert(codeSnippet, { overwriteBefore: 1 });
339
340
assert.strictEqual(editor.getSelections()!.length, 1);
341
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 8, endColumn: 8, endLineNumber: 2 }));
342
});
343
});
344
345
test('Final tabstop, #11742 simple', () => {
346
snippetTest((editor, codeSnippet, controller) => {
347
348
editor.setSelection(new Selection(1, 19, 1, 19));
349
350
codeSnippet = '{{% url_**$1** %}}';
351
controller.insert(codeSnippet, { overwriteBefore: 2 });
352
353
assert.strictEqual(editor.getSelections()!.length, 1);
354
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 1, startColumn: 27, endLineNumber: 1, endColumn: 27 }));
355
assert.strictEqual(editor.getModel()!.getValue(), 'example example {{% url_**** %}}');
356
357
}, ['example example sc']);
358
359
snippetTest((editor, codeSnippet, controller) => {
360
361
editor.setSelection(new Selection(1, 3, 1, 3));
362
363
codeSnippet = [
364
'afterEach((done) => {',
365
'\t${1}test',
366
'});'
367
].join('\n');
368
369
controller.insert(codeSnippet, { overwriteBefore: 2 });
370
371
assert.strictEqual(editor.getSelections()!.length, 1);
372
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 2, endLineNumber: 2, endColumn: 2 }), editor.getSelection()!.toString());
373
assert.strictEqual(editor.getModel()!.getValue(), 'afterEach((done) => {\n\ttest\n});');
374
375
}, ['af']);
376
377
snippetTest((editor, codeSnippet, controller) => {
378
379
editor.setSelection(new Selection(1, 3, 1, 3));
380
381
codeSnippet = [
382
'afterEach((done) => {',
383
'${1}\ttest',
384
'});'
385
].join('\n');
386
387
controller.insert(codeSnippet, { overwriteBefore: 2 });
388
389
assert.strictEqual(editor.getSelections()!.length, 1);
390
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 }), editor.getSelection()!.toString());
391
assert.strictEqual(editor.getModel()!.getValue(), 'afterEach((done) => {\n\ttest\n});');
392
393
}, ['af']);
394
395
snippetTest((editor, codeSnippet, controller) => {
396
397
editor.setSelection(new Selection(1, 9, 1, 9));
398
399
codeSnippet = [
400
'aft${1}er'
401
].join('\n');
402
403
controller.insert(codeSnippet, { overwriteBefore: 8 });
404
405
assert.strictEqual(editor.getModel()!.getValue(), 'after');
406
assert.strictEqual(editor.getSelections()!.length, 1);
407
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 1, startColumn: 4, endLineNumber: 1, endColumn: 4 }), editor.getSelection()!.toString());
408
409
}, ['afterone']);
410
});
411
412
test('Final tabstop, #11742 different indents', () => {
413
414
snippetTest((editor, codeSnippet, controller) => {
415
416
editor.setSelections([
417
new Selection(2, 4, 2, 4),
418
new Selection(1, 3, 1, 3)
419
]);
420
421
codeSnippet = [
422
'afterEach((done) => {',
423
'\t${0}test',
424
'});'
425
].join('\n');
426
427
controller.insert(codeSnippet, { overwriteBefore: 2 });
428
429
assert.strictEqual(editor.getSelections()!.length, 2);
430
const [first, second] = editor.getSelections()!;
431
432
assert.ok(first.equalsRange({ startLineNumber: 5, startColumn: 3, endLineNumber: 5, endColumn: 3 }), first.toString());
433
assert.ok(second.equalsRange({ startLineNumber: 2, startColumn: 2, endLineNumber: 2, endColumn: 2 }), second.toString());
434
435
}, ['af', '\taf']);
436
});
437
438
test('Final tabstop, #11890 stay at the beginning', () => {
439
440
snippetTest((editor, codeSnippet, controller) => {
441
442
editor.setSelections([
443
new Selection(1, 5, 1, 5)
444
]);
445
446
codeSnippet = [
447
'afterEach((done) => {',
448
'${1}\ttest',
449
'});'
450
].join('\n');
451
452
controller.insert(codeSnippet, { overwriteBefore: 2 });
453
454
assert.strictEqual(editor.getSelections()!.length, 1);
455
const [first] = editor.getSelections()!;
456
457
assert.ok(first.equalsRange({ startLineNumber: 2, startColumn: 3, endLineNumber: 2, endColumn: 3 }), first.toString());
458
459
}, [' af']);
460
});
461
462
test('Final tabstop, no tabstop', () => {
463
464
snippetTest((editor, codeSnippet, controller) => {
465
466
editor.setSelections([
467
new Selection(1, 3, 1, 3)
468
]);
469
470
codeSnippet = 'afterEach';
471
472
controller.insert(codeSnippet, { overwriteBefore: 2 });
473
474
assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 1, startColumn: 10, endLineNumber: 1, endColumn: 10 }));
475
476
}, ['af', '\taf']);
477
});
478
479
test('Multiple cursor and overwriteBefore/After, issue #11060', () => {
480
481
snippetTest((editor, codeSnippet, controller) => {
482
483
editor.setSelections([
484
new Selection(1, 7, 1, 7),
485
new Selection(2, 4, 2, 4)
486
]);
487
488
codeSnippet = '_foo';
489
controller.insert(codeSnippet, { overwriteBefore: 1 });
490
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc_foo');
491
492
}, ['this._', 'abc']);
493
494
snippetTest((editor, codeSnippet, controller) => {
495
496
editor.setSelections([
497
new Selection(1, 7, 1, 7),
498
new Selection(2, 4, 2, 4)
499
]);
500
501
codeSnippet = 'XX';
502
controller.insert(codeSnippet, { overwriteBefore: 1 });
503
assert.strictEqual(editor.getModel()!.getValue(), 'this.XX\nabcXX');
504
505
}, ['this._', 'abc']);
506
507
snippetTest((editor, codeSnippet, controller) => {
508
509
editor.setSelections([
510
new Selection(1, 7, 1, 7),
511
new Selection(2, 4, 2, 4),
512
new Selection(3, 5, 3, 5)
513
]);
514
515
codeSnippet = '_foo';
516
controller.insert(codeSnippet, { overwriteBefore: 1 });
517
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc_foo\ndef_foo');
518
519
}, ['this._', 'abc', 'def_']);
520
521
snippetTest((editor, codeSnippet, controller) => {
522
523
editor.setSelections([
524
new Selection(1, 7, 1, 7), // primary at `this._`
525
new Selection(2, 4, 2, 4),
526
new Selection(3, 6, 3, 6)
527
]);
528
529
codeSnippet = '._foo';
530
controller.insert(codeSnippet, { overwriteBefore: 2 });
531
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo');
532
533
}, ['this._', 'abc', 'def._']);
534
535
snippetTest((editor, codeSnippet, controller) => {
536
537
editor.setSelections([
538
new Selection(3, 6, 3, 6), // primary at `def._`
539
new Selection(1, 7, 1, 7),
540
new Selection(2, 4, 2, 4),
541
]);
542
543
codeSnippet = '._foo';
544
controller.insert(codeSnippet, { overwriteBefore: 2 });
545
assert.strictEqual(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo');
546
547
}, ['this._', 'abc', 'def._']);
548
549
snippetTest((editor, codeSnippet, controller) => {
550
551
editor.setSelections([
552
new Selection(2, 4, 2, 4), // primary at `abc`
553
new Selection(3, 6, 3, 6),
554
new Selection(1, 7, 1, 7),
555
]);
556
557
codeSnippet = '._foo';
558
controller.insert(codeSnippet, { overwriteBefore: 2 });
559
assert.strictEqual(editor.getModel()!.getValue(), 'this._._foo\na._foo\ndef._._foo');
560
561
}, ['this._', 'abc', 'def._']);
562
563
});
564
565
test('Multiple cursor and overwriteBefore/After, #16277', () => {
566
snippetTest((editor, codeSnippet, controller) => {
567
568
editor.setSelections([
569
new Selection(1, 5, 1, 5),
570
new Selection(2, 5, 2, 5),
571
]);
572
573
codeSnippet = 'document';
574
controller.insert(codeSnippet, { overwriteBefore: 3 });
575
assert.strictEqual(editor.getModel()!.getValue(), '{document}\n{document && true}');
576
577
}, ['{foo}', '{foo && true}']);
578
});
579
580
test('Insert snippet twice, #19449', () => {
581
582
snippetTest((editor, codeSnippet, controller) => {
583
584
editor.setSelections([
585
new Selection(1, 1, 1, 1)
586
]);
587
588
codeSnippet = 'for (var ${1:i}=0; ${1:i}<len; ${1:i}++) { $0 }';
589
controller.insert(codeSnippet);
590
assert.strictEqual(editor.getModel()!.getValue(), 'for (var i=0; i<len; i++) { }for (var i=0; i<len; i++) { }');
591
592
}, ['for (var i=0; i<len; i++) { }']);
593
594
595
snippetTest((editor, codeSnippet, controller) => {
596
597
editor.setSelections([
598
new Selection(1, 1, 1, 1)
599
]);
600
601
codeSnippet = 'for (let ${1:i}=0; ${1:i}<len; ${1:i}++) { $0 }';
602
controller.insert(codeSnippet);
603
assert.strictEqual(editor.getModel()!.getValue(), 'for (let i=0; i<len; i++) { }for (var i=0; i<len; i++) { }');
604
605
}, ['for (var i=0; i<len; i++) { }']);
606
607
});
608
});
609
610