vscode-css-languageservice 6.1.1 → 6.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +4 -3
- package/lib/esm/beautify/beautify-css.js +1 -1
- package/lib/esm/cssLanguageService.d.ts +2 -1
- package/lib/esm/cssLanguageService.js +1 -0
- package/lib/esm/cssLanguageTypes.d.ts +2 -2
- package/lib/esm/data/webCustomData.js +3502 -310
- package/lib/esm/languageFacts/builtinData.js +1 -1
- package/lib/esm/languageFacts/colors.js +6 -7
- package/lib/esm/parser/cssErrors.js +34 -35
- package/lib/esm/parser/cssNodes.js +4 -4
- package/lib/esm/parser/cssParser.js +16 -16
- package/lib/esm/parser/scssErrors.js +4 -5
- package/lib/esm/parser/scssParser.js +3 -0
- package/lib/esm/services/cssCodeActions.js +2 -3
- package/lib/esm/services/cssCompletion.js +13 -4
- package/lib/esm/services/cssNavigation.js +19 -7
- package/lib/esm/services/lessCompletion.js +58 -59
- package/lib/esm/services/lint.js +64 -18
- package/lib/esm/services/lintRules.js +21 -22
- package/lib/esm/services/scssCompletion.js +107 -107
- package/lib/esm/services/selectorPrinting.js +2 -3
- package/lib/umd/beautify/beautify-css.js +1 -1
- package/lib/umd/cssLanguageService.d.ts +2 -1
- package/lib/umd/cssLanguageService.js +1 -0
- package/lib/umd/cssLanguageTypes.d.ts +2 -2
- package/lib/umd/data/webCustomData.js +3502 -310
- package/lib/umd/languageFacts/builtinData.js +1 -1
- package/lib/umd/languageFacts/colors.js +7 -8
- package/lib/umd/parser/cssErrors.js +35 -36
- package/lib/umd/parser/cssNodes.js +4 -4
- package/lib/umd/parser/cssParser.js +16 -16
- package/lib/umd/parser/scssErrors.js +5 -6
- package/lib/umd/parser/scssParser.js +3 -0
- package/lib/umd/services/cssCodeActions.js +3 -4
- package/lib/umd/services/cssCompletion.js +14 -5
- package/lib/umd/services/cssNavigation.js +20 -8
- package/lib/umd/services/lessCompletion.js +59 -60
- package/lib/umd/services/lint.js +65 -19
- package/lib/umd/services/lintRules.js +22 -23
- package/lib/umd/services/scssCompletion.js +108 -108
- package/lib/umd/services/selectorPrinting.js +3 -4
- package/package.json +15 -18
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
'use strict';
|
|
6
6
|
import { CSSCompletion } from './cssCompletion';
|
|
7
7
|
import { CompletionItemKind, InsertTextFormat, TextEdit } from '../cssLanguageTypes';
|
|
8
|
-
import * as
|
|
9
|
-
const localize = nls.loadMessageBundle();
|
|
8
|
+
import * as l10n from '@vscode/l10n';
|
|
10
9
|
export class LESSCompletion extends CSSCompletion {
|
|
11
10
|
constructor(lsOptions, cssDataManager) {
|
|
12
11
|
super('@', lsOptions, cssDataManager);
|
|
@@ -50,156 +49,156 @@ LESSCompletion.builtInProposals = [
|
|
|
50
49
|
{
|
|
51
50
|
'name': 'if',
|
|
52
51
|
'example': 'if(condition, trueValue [, falseValue]);',
|
|
53
|
-
'description':
|
|
52
|
+
'description': l10n.t('returns one of two values depending on a condition.')
|
|
54
53
|
},
|
|
55
54
|
{
|
|
56
55
|
'name': 'boolean',
|
|
57
56
|
'example': 'boolean(condition);',
|
|
58
|
-
'description':
|
|
57
|
+
'description': l10n.t('"store" a boolean test for later evaluation in a guard or if().')
|
|
59
58
|
},
|
|
60
59
|
// List functions
|
|
61
60
|
{
|
|
62
61
|
'name': 'length',
|
|
63
62
|
'example': 'length(@list);',
|
|
64
|
-
'description':
|
|
63
|
+
'description': l10n.t('returns the number of elements in a value list')
|
|
65
64
|
},
|
|
66
65
|
{
|
|
67
66
|
'name': 'extract',
|
|
68
67
|
'example': 'extract(@list, index);',
|
|
69
|
-
'description':
|
|
68
|
+
'description': l10n.t('returns a value at the specified position in the list')
|
|
70
69
|
},
|
|
71
70
|
{
|
|
72
71
|
'name': 'range',
|
|
73
72
|
'example': 'range([start, ] end [, step]);',
|
|
74
|
-
'description':
|
|
73
|
+
'description': l10n.t('generate a list spanning a range of values')
|
|
75
74
|
},
|
|
76
75
|
{
|
|
77
76
|
'name': 'each',
|
|
78
77
|
'example': 'each(@list, ruleset);',
|
|
79
|
-
'description':
|
|
78
|
+
'description': l10n.t('bind the evaluation of a ruleset to each member of a list.')
|
|
80
79
|
},
|
|
81
80
|
// Other built-ins
|
|
82
81
|
{
|
|
83
82
|
'name': 'escape',
|
|
84
83
|
'example': 'escape(@string);',
|
|
85
|
-
'description':
|
|
84
|
+
'description': l10n.t('URL encodes a string')
|
|
86
85
|
},
|
|
87
86
|
{
|
|
88
87
|
'name': 'e',
|
|
89
88
|
'example': 'e(@string);',
|
|
90
|
-
'description':
|
|
89
|
+
'description': l10n.t('escape string content')
|
|
91
90
|
},
|
|
92
91
|
{
|
|
93
92
|
'name': 'replace',
|
|
94
93
|
'example': 'replace(@string, @pattern, @replacement[, @flags]);',
|
|
95
|
-
'description':
|
|
94
|
+
'description': l10n.t('string replace')
|
|
96
95
|
},
|
|
97
96
|
{
|
|
98
97
|
'name': 'unit',
|
|
99
98
|
'example': 'unit(@dimension, [@unit: \'\']);',
|
|
100
|
-
'description':
|
|
99
|
+
'description': l10n.t('remove or change the unit of a dimension')
|
|
101
100
|
},
|
|
102
101
|
{
|
|
103
102
|
'name': 'color',
|
|
104
103
|
'example': 'color(@string);',
|
|
105
|
-
'description':
|
|
104
|
+
'description': l10n.t('parses a string to a color'),
|
|
106
105
|
'type': 'color'
|
|
107
106
|
},
|
|
108
107
|
{
|
|
109
108
|
'name': 'convert',
|
|
110
109
|
'example': 'convert(@value, unit);',
|
|
111
|
-
'description':
|
|
110
|
+
'description': l10n.t('converts numbers from one type into another')
|
|
112
111
|
},
|
|
113
112
|
{
|
|
114
113
|
'name': 'data-uri',
|
|
115
114
|
'example': 'data-uri([mimetype,] url);',
|
|
116
|
-
'description':
|
|
115
|
+
'description': l10n.t('inlines a resource and falls back to `url()`'),
|
|
117
116
|
'type': 'url'
|
|
118
117
|
},
|
|
119
118
|
{
|
|
120
119
|
'name': 'abs',
|
|
121
|
-
'description':
|
|
120
|
+
'description': l10n.t('absolute value of a number'),
|
|
122
121
|
'example': 'abs(number);'
|
|
123
122
|
},
|
|
124
123
|
{
|
|
125
124
|
'name': 'acos',
|
|
126
|
-
'description':
|
|
125
|
+
'description': l10n.t('arccosine - inverse of cosine function'),
|
|
127
126
|
'example': 'acos(number);'
|
|
128
127
|
},
|
|
129
128
|
{
|
|
130
129
|
'name': 'asin',
|
|
131
|
-
'description':
|
|
130
|
+
'description': l10n.t('arcsine - inverse of sine function'),
|
|
132
131
|
'example': 'asin(number);'
|
|
133
132
|
},
|
|
134
133
|
{
|
|
135
134
|
'name': 'ceil',
|
|
136
135
|
'example': 'ceil(@number);',
|
|
137
|
-
'description':
|
|
136
|
+
'description': l10n.t('rounds up to an integer')
|
|
138
137
|
},
|
|
139
138
|
{
|
|
140
139
|
'name': 'cos',
|
|
141
|
-
'description':
|
|
140
|
+
'description': l10n.t('cosine function'),
|
|
142
141
|
'example': 'cos(number);'
|
|
143
142
|
},
|
|
144
143
|
{
|
|
145
144
|
'name': 'floor',
|
|
146
|
-
'description':
|
|
145
|
+
'description': l10n.t('rounds down to an integer'),
|
|
147
146
|
'example': 'floor(@number);'
|
|
148
147
|
},
|
|
149
148
|
{
|
|
150
149
|
'name': 'percentage',
|
|
151
|
-
'description':
|
|
150
|
+
'description': l10n.t('converts to a %, e.g. 0.5 > 50%'),
|
|
152
151
|
'example': 'percentage(@number);',
|
|
153
152
|
'type': 'percentage'
|
|
154
153
|
},
|
|
155
154
|
{
|
|
156
155
|
'name': 'round',
|
|
157
|
-
'description':
|
|
156
|
+
'description': l10n.t('rounds a number to a number of places'),
|
|
158
157
|
'example': 'round(number, [places: 0]);'
|
|
159
158
|
},
|
|
160
159
|
{
|
|
161
160
|
'name': 'sqrt',
|
|
162
|
-
'description':
|
|
161
|
+
'description': l10n.t('calculates square root of a number'),
|
|
163
162
|
'example': 'sqrt(number);'
|
|
164
163
|
},
|
|
165
164
|
{
|
|
166
165
|
'name': 'sin',
|
|
167
|
-
'description':
|
|
166
|
+
'description': l10n.t('sine function'),
|
|
168
167
|
'example': 'sin(number);'
|
|
169
168
|
},
|
|
170
169
|
{
|
|
171
170
|
'name': 'tan',
|
|
172
|
-
'description':
|
|
171
|
+
'description': l10n.t('tangent function'),
|
|
173
172
|
'example': 'tan(number);'
|
|
174
173
|
},
|
|
175
174
|
{
|
|
176
175
|
'name': 'atan',
|
|
177
|
-
'description':
|
|
176
|
+
'description': l10n.t('arctangent - inverse of tangent function'),
|
|
178
177
|
'example': 'atan(number);'
|
|
179
178
|
},
|
|
180
179
|
{
|
|
181
180
|
'name': 'pi',
|
|
182
|
-
'description':
|
|
181
|
+
'description': l10n.t('returns pi'),
|
|
183
182
|
'example': 'pi();'
|
|
184
183
|
},
|
|
185
184
|
{
|
|
186
185
|
'name': 'pow',
|
|
187
|
-
'description':
|
|
186
|
+
'description': l10n.t('first argument raised to the power of the second argument'),
|
|
188
187
|
'example': 'pow(@base, @exponent);'
|
|
189
188
|
},
|
|
190
189
|
{
|
|
191
190
|
'name': 'mod',
|
|
192
|
-
'description':
|
|
191
|
+
'description': l10n.t('first argument modulus second argument'),
|
|
193
192
|
'example': 'mod(number, number);'
|
|
194
193
|
},
|
|
195
194
|
{
|
|
196
195
|
'name': 'min',
|
|
197
|
-
'description':
|
|
196
|
+
'description': l10n.t('returns the lowest of one or more values'),
|
|
198
197
|
'example': 'min(@x, @y);'
|
|
199
198
|
},
|
|
200
199
|
{
|
|
201
200
|
'name': 'max',
|
|
202
|
-
'description':
|
|
201
|
+
'description': l10n.t('returns the lowest of one or more values'),
|
|
203
202
|
'example': 'max(@x, @y);'
|
|
204
203
|
}
|
|
205
204
|
];
|
|
@@ -207,137 +206,137 @@ LESSCompletion.colorProposals = [
|
|
|
207
206
|
{
|
|
208
207
|
'name': 'argb',
|
|
209
208
|
'example': 'argb(@color);',
|
|
210
|
-
'description':
|
|
209
|
+
'description': l10n.t('creates a #AARRGGBB')
|
|
211
210
|
},
|
|
212
211
|
{
|
|
213
212
|
'name': 'hsl',
|
|
214
213
|
'example': 'hsl(@hue, @saturation, @lightness);',
|
|
215
|
-
'description':
|
|
214
|
+
'description': l10n.t('creates a color')
|
|
216
215
|
},
|
|
217
216
|
{
|
|
218
217
|
'name': 'hsla',
|
|
219
218
|
'example': 'hsla(@hue, @saturation, @lightness, @alpha);',
|
|
220
|
-
'description':
|
|
219
|
+
'description': l10n.t('creates a color')
|
|
221
220
|
},
|
|
222
221
|
{
|
|
223
222
|
'name': 'hsv',
|
|
224
223
|
'example': 'hsv(@hue, @saturation, @value);',
|
|
225
|
-
'description':
|
|
224
|
+
'description': l10n.t('creates a color')
|
|
226
225
|
},
|
|
227
226
|
{
|
|
228
227
|
'name': 'hsva',
|
|
229
228
|
'example': 'hsva(@hue, @saturation, @value, @alpha);',
|
|
230
|
-
'description':
|
|
229
|
+
'description': l10n.t('creates a color')
|
|
231
230
|
},
|
|
232
231
|
{
|
|
233
232
|
'name': 'hue',
|
|
234
233
|
'example': 'hue(@color);',
|
|
235
|
-
'description':
|
|
234
|
+
'description': l10n.t('returns the `hue` channel of `@color` in the HSL space')
|
|
236
235
|
},
|
|
237
236
|
{
|
|
238
237
|
'name': 'saturation',
|
|
239
238
|
'example': 'saturation(@color);',
|
|
240
|
-
'description':
|
|
239
|
+
'description': l10n.t('returns the `saturation` channel of `@color` in the HSL space')
|
|
241
240
|
},
|
|
242
241
|
{
|
|
243
242
|
'name': 'lightness',
|
|
244
243
|
'example': 'lightness(@color);',
|
|
245
|
-
'description':
|
|
244
|
+
'description': l10n.t('returns the `lightness` channel of `@color` in the HSL space')
|
|
246
245
|
},
|
|
247
246
|
{
|
|
248
247
|
'name': 'hsvhue',
|
|
249
248
|
'example': 'hsvhue(@color);',
|
|
250
|
-
'description':
|
|
249
|
+
'description': l10n.t('returns the `hue` channel of `@color` in the HSV space')
|
|
251
250
|
},
|
|
252
251
|
{
|
|
253
252
|
'name': 'hsvsaturation',
|
|
254
253
|
'example': 'hsvsaturation(@color);',
|
|
255
|
-
'description':
|
|
254
|
+
'description': l10n.t('returns the `saturation` channel of `@color` in the HSV space')
|
|
256
255
|
},
|
|
257
256
|
{
|
|
258
257
|
'name': 'hsvvalue',
|
|
259
258
|
'example': 'hsvvalue(@color);',
|
|
260
|
-
'description':
|
|
259
|
+
'description': l10n.t('returns the `value` channel of `@color` in the HSV space')
|
|
261
260
|
},
|
|
262
261
|
{
|
|
263
262
|
'name': 'red',
|
|
264
263
|
'example': 'red(@color);',
|
|
265
|
-
'description':
|
|
264
|
+
'description': l10n.t('returns the `red` channel of `@color`')
|
|
266
265
|
},
|
|
267
266
|
{
|
|
268
267
|
'name': 'green',
|
|
269
268
|
'example': 'green(@color);',
|
|
270
|
-
'description':
|
|
269
|
+
'description': l10n.t('returns the `green` channel of `@color`')
|
|
271
270
|
},
|
|
272
271
|
{
|
|
273
272
|
'name': 'blue',
|
|
274
273
|
'example': 'blue(@color);',
|
|
275
|
-
'description':
|
|
274
|
+
'description': l10n.t('returns the `blue` channel of `@color`')
|
|
276
275
|
},
|
|
277
276
|
{
|
|
278
277
|
'name': 'alpha',
|
|
279
278
|
'example': 'alpha(@color);',
|
|
280
|
-
'description':
|
|
279
|
+
'description': l10n.t('returns the `alpha` channel of `@color`')
|
|
281
280
|
},
|
|
282
281
|
{
|
|
283
282
|
'name': 'luma',
|
|
284
283
|
'example': 'luma(@color);',
|
|
285
|
-
'description':
|
|
284
|
+
'description': l10n.t('returns the `luma` value (perceptual brightness) of `@color`')
|
|
286
285
|
},
|
|
287
286
|
{
|
|
288
287
|
'name': 'saturate',
|
|
289
288
|
'example': 'saturate(@color, 10%);',
|
|
290
|
-
'description':
|
|
289
|
+
'description': l10n.t('return `@color` 10% points more saturated')
|
|
291
290
|
},
|
|
292
291
|
{
|
|
293
292
|
'name': 'desaturate',
|
|
294
293
|
'example': 'desaturate(@color, 10%);',
|
|
295
|
-
'description':
|
|
294
|
+
'description': l10n.t('return `@color` 10% points less saturated')
|
|
296
295
|
},
|
|
297
296
|
{
|
|
298
297
|
'name': 'lighten',
|
|
299
298
|
'example': 'lighten(@color, 10%);',
|
|
300
|
-
'description':
|
|
299
|
+
'description': l10n.t('return `@color` 10% points lighter')
|
|
301
300
|
},
|
|
302
301
|
{
|
|
303
302
|
'name': 'darken',
|
|
304
303
|
'example': 'darken(@color, 10%);',
|
|
305
|
-
'description':
|
|
304
|
+
'description': l10n.t('return `@color` 10% points darker')
|
|
306
305
|
},
|
|
307
306
|
{
|
|
308
307
|
'name': 'fadein',
|
|
309
308
|
'example': 'fadein(@color, 10%);',
|
|
310
|
-
'description':
|
|
309
|
+
'description': l10n.t('return `@color` 10% points less transparent')
|
|
311
310
|
},
|
|
312
311
|
{
|
|
313
312
|
'name': 'fadeout',
|
|
314
313
|
'example': 'fadeout(@color, 10%);',
|
|
315
|
-
'description':
|
|
314
|
+
'description': l10n.t('return `@color` 10% points more transparent')
|
|
316
315
|
},
|
|
317
316
|
{
|
|
318
317
|
'name': 'fade',
|
|
319
318
|
'example': 'fade(@color, 50%);',
|
|
320
|
-
'description':
|
|
319
|
+
'description': l10n.t('return `@color` with 50% transparency')
|
|
321
320
|
},
|
|
322
321
|
{
|
|
323
322
|
'name': 'spin',
|
|
324
323
|
'example': 'spin(@color, 10);',
|
|
325
|
-
'description':
|
|
324
|
+
'description': l10n.t('return `@color` with a 10 degree larger in hue')
|
|
326
325
|
},
|
|
327
326
|
{
|
|
328
327
|
'name': 'mix',
|
|
329
328
|
'example': 'mix(@color1, @color2, [@weight: 50%]);',
|
|
330
|
-
'description':
|
|
329
|
+
'description': l10n.t('return a mix of `@color1` and `@color2`')
|
|
331
330
|
},
|
|
332
331
|
{
|
|
333
332
|
'name': 'greyscale',
|
|
334
333
|
'example': 'greyscale(@color);',
|
|
335
|
-
'description':
|
|
334
|
+
'description': l10n.t('returns a grey, 100% desaturated color'),
|
|
336
335
|
},
|
|
337
336
|
{
|
|
338
337
|
'name': 'contrast',
|
|
339
338
|
'example': 'contrast(@color1, [@darkcolor: black], [@lightcolor: white], [@threshold: 43%]);',
|
|
340
|
-
'description':
|
|
339
|
+
'description': l10n.t('return `@darkcolor` if `@color1 is> 43% luma` otherwise return `@lightcolor`, see notes')
|
|
341
340
|
},
|
|
342
341
|
{
|
|
343
342
|
'name': 'multiply',
|
package/lib/esm/services/lint.js
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
'use strict';
|
|
6
|
-
import * as
|
|
6
|
+
import * as l10n from '@vscode/l10n';
|
|
7
7
|
import * as languageFacts from '../languageFacts/facts';
|
|
8
8
|
import * as nodes from '../parser/cssNodes';
|
|
9
9
|
import { union } from '../utils/arrays';
|
|
10
10
|
import { Rules, Settings } from './lintRules';
|
|
11
11
|
import calculateBoxModel, { Element } from './lintUtil';
|
|
12
|
-
const localize = nls.loadMessageBundle();
|
|
13
12
|
class NodesByRootMap {
|
|
14
13
|
constructor() {
|
|
15
14
|
this.data = {};
|
|
@@ -27,6 +26,12 @@ class NodesByRootMap {
|
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
28
|
export class LintVisitor {
|
|
29
|
+
static entries(node, document, settings, cssDataManager, entryFilter) {
|
|
30
|
+
const visitor = new LintVisitor(document, settings, cssDataManager);
|
|
31
|
+
node.acceptVisitor(visitor);
|
|
32
|
+
visitor.completeValidations();
|
|
33
|
+
return visitor.getEntries(entryFilter);
|
|
34
|
+
}
|
|
30
35
|
constructor(document, settings, cssDataManager) {
|
|
31
36
|
this.cssDataManager = cssDataManager;
|
|
32
37
|
this.warnings = [];
|
|
@@ -46,12 +51,6 @@ export class LintVisitor {
|
|
|
46
51
|
});
|
|
47
52
|
}
|
|
48
53
|
}
|
|
49
|
-
static entries(node, document, settings, cssDataManager, entryFilter) {
|
|
50
|
-
const visitor = new LintVisitor(document, settings, cssDataManager);
|
|
51
|
-
node.acceptVisitor(visitor);
|
|
52
|
-
visitor.completeValidations();
|
|
53
|
-
return visitor.getEntries(entryFilter);
|
|
54
|
-
}
|
|
55
54
|
isValidPropertyDeclaration(element) {
|
|
56
55
|
const propertyName = element.fullPropertyName;
|
|
57
56
|
return this.validProperties[propertyName];
|
|
@@ -109,10 +108,10 @@ export class LintVisitor {
|
|
|
109
108
|
const curr = expectedClone[i];
|
|
110
109
|
if (curr) {
|
|
111
110
|
if (result === null) {
|
|
112
|
-
result =
|
|
111
|
+
result = l10n.t("'{0}'", curr);
|
|
113
112
|
}
|
|
114
113
|
else {
|
|
115
|
-
result =
|
|
114
|
+
result = l10n.t("{0}, '{1}'", result, curr);
|
|
116
115
|
}
|
|
117
116
|
}
|
|
118
117
|
}
|
|
@@ -183,11 +182,11 @@ export class LintVisitor {
|
|
|
183
182
|
if (missingVendorSpecific || needsStandard) {
|
|
184
183
|
for (const node of this.keyframes.data[name].nodes) {
|
|
185
184
|
if (needsStandard) {
|
|
186
|
-
const message =
|
|
185
|
+
const message = l10n.t("Always define standard rule '@keyframes' when defining keyframes.");
|
|
187
186
|
this.addEntry(node, Rules.IncludeStandardPropertyWhenUsingVendorPrefix, message);
|
|
188
187
|
}
|
|
189
188
|
if (missingVendorSpecific) {
|
|
190
|
-
const message =
|
|
189
|
+
const message = l10n.t("Always include all vendor specific rules: Missing: {0}", missingVendorSpecific);
|
|
191
190
|
this.addEntry(node, Rules.AllVendorPrefixes, message);
|
|
192
191
|
}
|
|
193
192
|
}
|
|
@@ -286,7 +285,7 @@ export class LintVisitor {
|
|
|
286
285
|
const node = elem[index].node;
|
|
287
286
|
const value = node.getValue();
|
|
288
287
|
if (value && !value.matches('none')) {
|
|
289
|
-
this.addEntry(node, Rules.PropertyIgnoredDueToDisplay,
|
|
288
|
+
this.addEntry(node, Rules.PropertyIgnoredDueToDisplay, l10n.t("inline-block is ignored due to the float. If 'float' has a value other than 'none', the box is floated and 'display' is treated as 'block'"));
|
|
290
289
|
}
|
|
291
290
|
}
|
|
292
291
|
}
|
|
@@ -295,7 +294,7 @@ export class LintVisitor {
|
|
|
295
294
|
if (displayElems.length > 0) {
|
|
296
295
|
const elem = this.fetch(propertyTable, 'vertical-align');
|
|
297
296
|
for (let index = 0; index < elem.length; index++) {
|
|
298
|
-
this.addEntry(elem[index].node, Rules.PropertyIgnoredDueToDisplay,
|
|
297
|
+
this.addEntry(elem[index].node, Rules.PropertyIgnoredDueToDisplay, l10n.t("Property is ignored due to the display. With 'display: block', vertical-align should not be used."));
|
|
299
298
|
}
|
|
300
299
|
}
|
|
301
300
|
/////////////////////////////////////////////////////////////
|
|
@@ -358,7 +357,7 @@ export class LintVisitor {
|
|
|
358
357
|
// _property and *property might be contributed via custom data
|
|
359
358
|
if (!this.cssDataManager.isKnownProperty(fullName) && !this.cssDataManager.isKnownProperty(name)) {
|
|
360
359
|
if (!this.validProperties[name]) {
|
|
361
|
-
this.addEntry(decl.getProperty(), Rules.UnknownProperty,
|
|
360
|
+
this.addEntry(decl.getProperty(), Rules.UnknownProperty, l10n.t("Unknown property: '{0}'", decl.getFullPropertyName()));
|
|
362
361
|
}
|
|
363
362
|
}
|
|
364
363
|
propertiesBySuffix.add(name, name, null); // don't pass the node as we don't show errors on the standard
|
|
@@ -376,6 +375,23 @@ export class LintVisitor {
|
|
|
376
375
|
if (!needsStandard && actual.length === 1) {
|
|
377
376
|
continue; // only the non-vendor specific rule is used, that's fine, no warning
|
|
378
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* We should ignore missing standard properties, if there's an explicit contextual reference to a
|
|
380
|
+
* vendor specific pseudo-element selector with the same vendor (prefix)
|
|
381
|
+
*
|
|
382
|
+
* (See https://github.com/microsoft/vscode/issues/164350)
|
|
383
|
+
*/
|
|
384
|
+
const entriesThatNeedStandard = new Set(needsStandard ? entry.nodes : []);
|
|
385
|
+
if (needsStandard) {
|
|
386
|
+
const pseudoElements = this.getContextualVendorSpecificPseudoElements(node);
|
|
387
|
+
for (const node of entry.nodes) {
|
|
388
|
+
const propertyName = node.getName();
|
|
389
|
+
const prefix = propertyName.substring(0, propertyName.length - suffix.length);
|
|
390
|
+
if (pseudoElements.some(x => x.startsWith(prefix))) {
|
|
391
|
+
entriesThatNeedStandard.delete(node);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
379
395
|
const expected = [];
|
|
380
396
|
for (let i = 0, len = LintVisitor.prefixes.length; i < len; i++) {
|
|
381
397
|
const prefix = LintVisitor.prefixes[i];
|
|
@@ -386,12 +402,12 @@ export class LintVisitor {
|
|
|
386
402
|
const missingVendorSpecific = this.getMissingNames(expected, actual);
|
|
387
403
|
if (missingVendorSpecific || needsStandard) {
|
|
388
404
|
for (const node of entry.nodes) {
|
|
389
|
-
if (needsStandard) {
|
|
390
|
-
const message =
|
|
405
|
+
if (needsStandard && entriesThatNeedStandard.has(node)) {
|
|
406
|
+
const message = l10n.t("Also define the standard property '{0}' for compatibility", suffix);
|
|
391
407
|
this.addEntry(node, Rules.IncludeStandardPropertyWhenUsingVendorPrefix, message);
|
|
392
408
|
}
|
|
393
409
|
if (missingVendorSpecific) {
|
|
394
|
-
const message =
|
|
410
|
+
const message = l10n.t("Always include all vendor specific properties: Missing: {0}", missingVendorSpecific);
|
|
395
411
|
this.addEntry(node, Rules.AllVendorPrefixes, message);
|
|
396
412
|
}
|
|
397
413
|
}
|
|
@@ -401,6 +417,36 @@ export class LintVisitor {
|
|
|
401
417
|
}
|
|
402
418
|
return true;
|
|
403
419
|
}
|
|
420
|
+
/**
|
|
421
|
+
* Walks up the syntax tree (starting from given `node`) and captures vendor
|
|
422
|
+
* specific pseudo-element selectors.
|
|
423
|
+
* @returns An array of vendor specific pseudo-elements; or empty if none
|
|
424
|
+
* was found.
|
|
425
|
+
*/
|
|
426
|
+
getContextualVendorSpecificPseudoElements(node) {
|
|
427
|
+
function walkDown(s, n) {
|
|
428
|
+
for (const child of n.getChildren()) {
|
|
429
|
+
if (child.type === nodes.NodeType.PseudoSelector) {
|
|
430
|
+
const pseudoElement = child.getChildren()[0]?.getText();
|
|
431
|
+
if (pseudoElement) {
|
|
432
|
+
s.add(pseudoElement);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
walkDown(s, child);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function walkUp(s, n) {
|
|
439
|
+
if (n.type === nodes.NodeType.Ruleset) {
|
|
440
|
+
for (const selector of n.getSelectors().getChildren()) {
|
|
441
|
+
walkDown(s, selector);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return n.parent ? walkUp(s, n.parent) : undefined;
|
|
445
|
+
}
|
|
446
|
+
const result = new Set();
|
|
447
|
+
walkUp(result, node);
|
|
448
|
+
return Array.from(result);
|
|
449
|
+
}
|
|
404
450
|
visitPrio(node) {
|
|
405
451
|
/////////////////////////////////////////////////////////////
|
|
406
452
|
// Don't use !important
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
'use strict';
|
|
6
6
|
import * as nodes from '../parser/cssNodes';
|
|
7
|
-
import * as
|
|
8
|
-
const localize = nls.loadMessageBundle();
|
|
7
|
+
import * as l10n from '@vscode/l10n';
|
|
9
8
|
const Warning = nodes.Level.Warning;
|
|
10
9
|
const Error = nodes.Level.Error;
|
|
11
10
|
const Ignore = nodes.Level.Ignore;
|
|
@@ -26,28 +25,28 @@ export class Setting {
|
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
27
|
export const Rules = {
|
|
29
|
-
AllVendorPrefixes: new Rule('compatibleVendorPrefixes',
|
|
30
|
-
IncludeStandardPropertyWhenUsingVendorPrefix: new Rule('vendorPrefix',
|
|
31
|
-
DuplicateDeclarations: new Rule('duplicateProperties',
|
|
32
|
-
EmptyRuleSet: new Rule('emptyRules',
|
|
33
|
-
ImportStatemement: new Rule('importStatement',
|
|
34
|
-
BewareOfBoxModelSize: new Rule('boxModel',
|
|
35
|
-
UniversalSelector: new Rule('universalSelector',
|
|
36
|
-
ZeroWithUnit: new Rule('zeroUnits',
|
|
37
|
-
RequiredPropertiesForFontFace: new Rule('fontFaceProperties',
|
|
38
|
-
HexColorLength: new Rule('hexColorLength',
|
|
39
|
-
ArgsInColorFunction: new Rule('argumentsInColorFunction',
|
|
40
|
-
UnknownProperty: new Rule('unknownProperties',
|
|
41
|
-
UnknownAtRules: new Rule('unknownAtRules',
|
|
42
|
-
IEStarHack: new Rule('ieHack',
|
|
43
|
-
UnknownVendorSpecificProperty: new Rule('unknownVendorSpecificProperties',
|
|
44
|
-
PropertyIgnoredDueToDisplay: new Rule('propertyIgnoredDueToDisplay',
|
|
45
|
-
AvoidImportant: new Rule('important',
|
|
46
|
-
AvoidFloat: new Rule('float',
|
|
47
|
-
AvoidIdSelector: new Rule('idSelector',
|
|
28
|
+
AllVendorPrefixes: new Rule('compatibleVendorPrefixes', l10n.t("When using a vendor-specific prefix make sure to also include all other vendor-specific properties"), Ignore),
|
|
29
|
+
IncludeStandardPropertyWhenUsingVendorPrefix: new Rule('vendorPrefix', l10n.t("When using a vendor-specific prefix also include the standard property"), Warning),
|
|
30
|
+
DuplicateDeclarations: new Rule('duplicateProperties', l10n.t("Do not use duplicate style definitions"), Ignore),
|
|
31
|
+
EmptyRuleSet: new Rule('emptyRules', l10n.t("Do not use empty rulesets"), Warning),
|
|
32
|
+
ImportStatemement: new Rule('importStatement', l10n.t("Import statements do not load in parallel"), Ignore),
|
|
33
|
+
BewareOfBoxModelSize: new Rule('boxModel', l10n.t("Do not use width or height when using padding or border"), Ignore),
|
|
34
|
+
UniversalSelector: new Rule('universalSelector', l10n.t("The universal selector (*) is known to be slow"), Ignore),
|
|
35
|
+
ZeroWithUnit: new Rule('zeroUnits', l10n.t("No unit for zero needed"), Ignore),
|
|
36
|
+
RequiredPropertiesForFontFace: new Rule('fontFaceProperties', l10n.t("@font-face rule must define 'src' and 'font-family' properties"), Warning),
|
|
37
|
+
HexColorLength: new Rule('hexColorLength', l10n.t("Hex colors must consist of three, four, six or eight hex numbers"), Error),
|
|
38
|
+
ArgsInColorFunction: new Rule('argumentsInColorFunction', l10n.t("Invalid number of parameters"), Error),
|
|
39
|
+
UnknownProperty: new Rule('unknownProperties', l10n.t("Unknown property."), Warning),
|
|
40
|
+
UnknownAtRules: new Rule('unknownAtRules', l10n.t("Unknown at-rule."), Warning),
|
|
41
|
+
IEStarHack: new Rule('ieHack', l10n.t("IE hacks are only necessary when supporting IE7 and older"), Ignore),
|
|
42
|
+
UnknownVendorSpecificProperty: new Rule('unknownVendorSpecificProperties', l10n.t("Unknown vendor specific property."), Ignore),
|
|
43
|
+
PropertyIgnoredDueToDisplay: new Rule('propertyIgnoredDueToDisplay', l10n.t("Property is ignored due to the display."), Warning),
|
|
44
|
+
AvoidImportant: new Rule('important', l10n.t("Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored."), Ignore),
|
|
45
|
+
AvoidFloat: new Rule('float', l10n.t("Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes."), Ignore),
|
|
46
|
+
AvoidIdSelector: new Rule('idSelector', l10n.t("Selectors should not contain IDs because these rules are too tightly coupled with the HTML."), Ignore),
|
|
48
47
|
};
|
|
49
48
|
export const Settings = {
|
|
50
|
-
ValidProperties: new Setting('validProperties',
|
|
49
|
+
ValidProperties: new Setting('validProperties', l10n.t("A list of properties that are not validated against the `unknownProperties` rule."), [])
|
|
51
50
|
};
|
|
52
51
|
export class LintConfigurationSettings {
|
|
53
52
|
constructor(conf = {}) {
|