1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { closeAllEditors, withRandomFileEditor } from './testUtils';
import * as vscode from 'vscode';
import { parsePartialStylesheet, getFlatNode } from '../util';
import { isValidLocationForEmmetAbbreviation } from '../abbreviationActions';
suite('Tests for partial parse of Stylesheets', () => {
teardown(closeAllEditors);
function isValid(doc: vscode.TextDocument, range: vscode.Range, syntax: string): boolean {
const rootNode = parsePartialStylesheet(doc, range.end);
const endOffset = doc.offsetAt(range.end);
const currentNode = getFlatNode(rootNode, endOffset, true);
return isValidLocationForEmmetAbbreviation(doc, rootNode, currentNode, syntax, endOffset, range);
}
test('Ignore block comment inside rule', function (): any {
const cssContents = `
p {
margin: p ;
/*dn: none; p */ p
p
p.
} p
`;
return withRandomFileEditor(cssContents, '.css', (_, doc) => {
let rangesForEmmet = [
new vscode.Range(3, 18, 3, 19), // Same line after block comment
new vscode.Range(4, 1, 4, 2), // p after block comment
new vscode.Range(5, 1, 5, 3) // p. after block comment
];
let rangesNotEmmet = [
new vscode.Range(1, 0, 1, 1), // Selector
new vscode.Range(2, 9, 2, 10), // Property value
new vscode.Range(3, 3, 3, 5), // dn inside block comment
new vscode.Range(3, 13, 3, 14), // p just before ending of block comment
new vscode.Range(6, 2, 6, 3) // p after ending of block
];
rangesForEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'css'), true);
});
rangesNotEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'css'), false);
});
return Promise.resolve();
});
});
test('Ignore commented braces', function (): any {
const sassContents = `
.foo
// .foo { brs
/* .foo { op.3
dn {
*/
bgc
} bg
`;
return withRandomFileEditor(sassContents, '.scss', (_, doc) => {
let rangesNotEmmet = [
new vscode.Range(1, 0, 1, 4), // Selector
new vscode.Range(2, 3, 2, 7), // Line commented selector
new vscode.Range(3, 3, 3, 7), // Block commented selector
new vscode.Range(4, 0, 4, 2), // dn inside block comment
new vscode.Range(6, 1, 6, 2), // bgc inside a rule whose opening brace is commented
new vscode.Range(7, 2, 7, 4) // bg after ending of badly constructed block
];
rangesNotEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), false);
});
return Promise.resolve();
});
});
test('Block comment between selector and open brace', function (): any {
const cssContents = `
p
/* First line
of a multiline
comment */
{
margin: p ;
/*dn: none; p */ p
p
p.
} p
`;
return withRandomFileEditor(cssContents, '.css', (_, doc) => {
let rangesForEmmet = [
new vscode.Range(7, 18, 7, 19), // Same line after block comment
new vscode.Range(8, 1, 8, 2), // p after block comment
new vscode.Range(9, 1, 9, 3) // p. after block comment
];
let rangesNotEmmet = [
new vscode.Range(1, 2, 1, 3), // Selector
new vscode.Range(3, 3, 3, 4), // Inside multiline comment
new vscode.Range(5, 0, 5, 1), // Opening Brace
new vscode.Range(6, 9, 6, 10), // Property value
new vscode.Range(7, 3, 7, 5), // dn inside block comment
new vscode.Range(7, 13, 7, 14), // p just before ending of block comment
new vscode.Range(10, 2, 10, 3) // p after ending of block
];
rangesForEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'css'), true);
});
rangesNotEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'css'), false);
});
return Promise.resolve();
});
});
test('Nested and consecutive rulesets with errors', function (): any {
const sassContents = `
.foo{
a
a
}}{ p
}
.bar{
@
.rudi {
@
}
}}}
`;
return withRandomFileEditor(sassContents, '.scss', (_, doc) => {
let rangesForEmmet = [
new vscode.Range(2, 1, 2, 2), // Inside a ruleset before errors
new vscode.Range(3, 1, 3, 2), // Inside a ruleset after no serious error
new vscode.Range(7, 1, 7, 2), // @ inside a so far well structured ruleset
new vscode.Range(9, 2, 9, 3), // @ inside a so far well structured nested ruleset
];
let rangesNotEmmet = [
new vscode.Range(4, 4, 4, 5), // p inside ruleset without proper selector
new vscode.Range(6, 3, 6, 4) // In selector
];
rangesForEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), true);
});
rangesNotEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), false);
});
return Promise.resolve();
});
});
test('One liner sass', function (): any {
const sassContents = `
.foo{dn}.bar{.boo{dn}dn}.comd{/*{dn*/p{div{dn}} }.foo{.other{dn}} dn
`;
return withRandomFileEditor(sassContents, '.scss', (_, doc) => {
let rangesForEmmet = [
new vscode.Range(1, 5, 1, 7), // Inside a ruleset
new vscode.Range(1, 18, 1, 20), // Inside a nested ruleset
new vscode.Range(1, 21, 1, 23), // Inside ruleset after nested one.
new vscode.Range(1, 43, 1, 45), // Inside nested ruleset after comment
new vscode.Range(1, 61, 1, 63) // Inside nested ruleset
];
let rangesNotEmmet = [
new vscode.Range(1, 3, 1, 4), // In foo selector
new vscode.Range(1, 10, 1, 11), // In bar selector
new vscode.Range(1, 15, 1, 16), // In boo selector
new vscode.Range(1, 28, 1, 29), // In comd selector
new vscode.Range(1, 33, 1, 34), // In commented dn
new vscode.Range(1, 37, 1, 38), // In p selector
new vscode.Range(1, 39, 1, 42), // In div selector
new vscode.Range(1, 66, 1, 68) // Outside any ruleset
];
rangesForEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), true);
});
rangesNotEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), false);
});
return Promise.resolve();
});
});
test('Variables and interpolation', function (): any {
const sassContents = `
p.#{dn} {
p.3
#{$attr}-color: blue;
dn
} op
.foo{nes{ted}} {
dn
}
`;
return withRandomFileEditor(sassContents, '.scss', (_, doc) => {
let rangesForEmmet = [
new vscode.Range(2, 1, 2, 4), // p.3 inside a ruleset whose selector uses interpolation
new vscode.Range(4, 1, 4, 3) // dn inside ruleset after property with variable
];
let rangesNotEmmet = [
new vscode.Range(1, 0, 1, 1), // In p in selector
new vscode.Range(1, 2, 1, 3), // In # in selector
new vscode.Range(1, 4, 1, 6), // In dn inside variable in selector
new vscode.Range(3, 7, 3, 8), // r of attr inside variable
new vscode.Range(5, 2, 5, 4), // op after ruleset
new vscode.Range(7, 1, 7, 3), // dn inside ruleset whose selector uses nested interpolation
new vscode.Range(3, 1, 3, 2), // # inside ruleset
];
rangesForEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), true);
});
rangesNotEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), false);
});
return Promise.resolve();
});
});
test('Comments in sass', function (): any {
const sassContents = `
.foo{
/* p // p */ brs6-2p
dn
}
p
/* c
om
ment */{
m10
}
.boo{
op.3
}
`;
return withRandomFileEditor(sassContents, '.scss', (_, doc) => {
let rangesForEmmet = [
new vscode.Range(2, 14, 2, 21), // brs6-2p with a block commented line comment ('/* */' overrides '//')
new vscode.Range(3, 1, 3, 3), // dn after a line with combined comments inside a ruleset
new vscode.Range(9, 1, 9, 4), // m10 inside ruleset whose selector is before a comment
new vscode.Range(12, 1, 12, 5) // op3 inside a ruleset with commented extra braces
];
let rangesNotEmmet = [
new vscode.Range(2, 4, 2, 5), // In p inside block comment
new vscode.Range(2, 9, 2, 10), // In p inside block comment and after line comment
new vscode.Range(6, 3, 6, 4) // In c inside block comment
];
rangesForEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), true);
});
rangesNotEmmet.forEach(range => {
assert.strictEqual(isValid(doc, range, 'scss'), false);
});
return Promise.resolve();
});
});
});
|