vscode-css-languageservice 5.4.2 → 6.1.0
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 +7 -1
- package/SECURITY.md +41 -0
- package/lib/esm/beautify/beautify-css.js +11 -4
- package/lib/esm/cssLanguageService.d.ts +2 -1
- package/lib/esm/cssLanguageService.js +15 -17
- package/lib/esm/cssLanguageTypes.js +2 -2
- package/lib/esm/data/webCustomData.js +356 -232
- package/lib/esm/languageFacts/builtinData.js +15 -15
- package/lib/esm/languageFacts/colors.js +66 -69
- package/lib/esm/languageFacts/dataManager.js +38 -42
- package/lib/esm/languageFacts/dataProvider.js +17 -23
- package/lib/esm/languageFacts/entry.js +22 -23
- package/lib/esm/parser/cssErrors.js +5 -7
- package/lib/esm/parser/cssNodes.js +869 -1377
- package/lib/esm/parser/cssParser.js +419 -376
- package/lib/esm/parser/cssScanner.js +168 -175
- package/lib/esm/parser/cssSymbolScope.js +107 -137
- package/lib/esm/parser/lessParser.js +177 -202
- package/lib/esm/parser/lessScanner.js +22 -43
- package/lib/esm/parser/scssErrors.js +5 -7
- package/lib/esm/parser/scssParser.js +196 -208
- package/lib/esm/parser/scssScanner.js +33 -54
- package/lib/esm/services/cssCodeActions.js +36 -40
- package/lib/esm/services/cssCompletion.js +300 -395
- package/lib/esm/services/cssFolding.js +32 -35
- package/lib/esm/services/cssFormatter.js +22 -22
- package/lib/esm/services/cssHover.js +30 -33
- package/lib/esm/services/cssNavigation.js +260 -289
- package/lib/esm/services/cssSelectionRange.js +6 -6
- package/lib/esm/services/cssValidation.js +13 -16
- package/lib/esm/services/lessCompletion.js +351 -370
- package/lib/esm/services/lint.js +161 -175
- package/lib/esm/services/lintRules.js +20 -27
- package/lib/esm/services/lintUtil.js +19 -28
- package/lib/esm/services/pathCompletion.js +84 -158
- package/lib/esm/services/scssCompletion.js +283 -307
- package/lib/esm/services/scssNavigation.js +65 -137
- package/lib/esm/services/selectorPrinting.js +131 -175
- package/lib/esm/utils/arrays.js +6 -12
- package/lib/esm/utils/objects.js +1 -1
- package/lib/esm/utils/resources.js +3 -16
- package/lib/esm/utils/strings.js +10 -12
- package/lib/umd/beautify/beautify-css.js +11 -4
- package/lib/umd/cssLanguageService.d.ts +2 -1
- package/lib/umd/cssLanguageService.js +34 -32
- package/lib/umd/cssLanguageTypes.js +4 -3
- package/lib/umd/data/webCustomData.js +355 -231
- package/lib/umd/languageFacts/colors.js +65 -68
- package/lib/umd/languageFacts/dataManager.js +41 -44
- package/lib/umd/languageFacts/dataProvider.js +17 -22
- package/lib/umd/languageFacts/entry.js +22 -23
- package/lib/umd/languageFacts/facts.js +5 -1
- package/lib/umd/parser/cssErrors.js +5 -6
- package/lib/umd/parser/cssNodes.js +870 -1307
- package/lib/umd/parser/cssParser.js +424 -380
- package/lib/umd/parser/cssScanner.js +168 -173
- package/lib/umd/parser/cssSymbolScope.js +109 -134
- package/lib/umd/parser/lessParser.js +182 -206
- package/lib/umd/parser/lessScanner.js +22 -42
- package/lib/umd/parser/scssErrors.js +5 -6
- package/lib/umd/parser/scssParser.js +202 -213
- package/lib/umd/parser/scssScanner.js +25 -45
- package/lib/umd/services/cssCodeActions.js +41 -44
- package/lib/umd/services/cssCompletion.js +308 -402
- package/lib/umd/services/cssFolding.js +35 -38
- package/lib/umd/services/cssFormatter.js +25 -25
- package/lib/umd/services/cssHover.js +36 -38
- package/lib/umd/services/cssNavigation.js +267 -295
- package/lib/umd/services/cssSelectionRange.js +8 -8
- package/lib/umd/services/cssValidation.js +17 -19
- package/lib/umd/services/lessCompletion.js +354 -372
- package/lib/umd/services/lint.js +167 -180
- package/lib/umd/services/lintRules.js +20 -24
- package/lib/umd/services/lintUtil.js +20 -28
- package/lib/umd/services/pathCompletion.js +87 -160
- package/lib/umd/services/scssCompletion.js +287 -310
- package/lib/umd/services/scssNavigation.js +69 -140
- package/lib/umd/services/selectorPrinting.js +134 -174
- package/lib/umd/utils/arrays.js +6 -12
- package/lib/umd/utils/objects.js +1 -1
- package/lib/umd/utils/resources.js +4 -17
- package/lib/umd/utils/strings.js +10 -12
- package/package.json +16 -15
package/lib/esm/services/lint.js
CHANGED
|
@@ -9,13 +9,13 @@ 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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const localize = nls.loadMessageBundle();
|
|
13
|
+
class NodesByRootMap {
|
|
14
|
+
constructor() {
|
|
15
15
|
this.data = {};
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
add(root, name, node) {
|
|
18
|
+
let entry = this.data[root];
|
|
19
19
|
if (!entry) {
|
|
20
20
|
entry = { nodes: [], names: [] };
|
|
21
21
|
this.data[root] = entry;
|
|
@@ -24,94 +24,89 @@ var NodesByRootMap = /** @class */ (function () {
|
|
|
24
24
|
if (node) {
|
|
25
25
|
entry.nodes.push(node);
|
|
26
26
|
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
function LintVisitor(document, settings, cssDataManager) {
|
|
32
|
-
var _this = this;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class LintVisitor {
|
|
30
|
+
constructor(document, settings, cssDataManager) {
|
|
33
31
|
this.cssDataManager = cssDataManager;
|
|
34
32
|
this.warnings = [];
|
|
35
33
|
this.settings = settings;
|
|
36
34
|
this.documentText = document.getText();
|
|
37
35
|
this.keyframes = new NodesByRootMap();
|
|
38
36
|
this.validProperties = {};
|
|
39
|
-
|
|
37
|
+
const properties = settings.getSetting(Settings.ValidProperties);
|
|
40
38
|
if (Array.isArray(properties)) {
|
|
41
|
-
properties.forEach(
|
|
39
|
+
properties.forEach((p) => {
|
|
42
40
|
if (typeof p === 'string') {
|
|
43
|
-
|
|
41
|
+
const name = p.trim().toLowerCase();
|
|
44
42
|
if (name.length) {
|
|
45
|
-
|
|
43
|
+
this.validProperties[name] = true;
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
46
|
});
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
static entries(node, document, settings, cssDataManager, entryFilter) {
|
|
50
|
+
const visitor = new LintVisitor(document, settings, cssDataManager);
|
|
53
51
|
node.acceptVisitor(visitor);
|
|
54
52
|
visitor.completeValidations();
|
|
55
53
|
return visitor.getEntries(entryFilter);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
}
|
|
55
|
+
isValidPropertyDeclaration(element) {
|
|
56
|
+
const propertyName = element.fullPropertyName;
|
|
59
57
|
return this.validProperties[propertyName];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
for (
|
|
64
|
-
var curr = input_1[_i];
|
|
58
|
+
}
|
|
59
|
+
fetch(input, s) {
|
|
60
|
+
const elements = [];
|
|
61
|
+
for (const curr of input) {
|
|
65
62
|
if (curr.fullPropertyName === s) {
|
|
66
63
|
elements.push(curr);
|
|
67
64
|
}
|
|
68
65
|
}
|
|
69
66
|
return elements;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (
|
|
74
|
-
var inputElement = input_2[_i];
|
|
67
|
+
}
|
|
68
|
+
fetchWithValue(input, s, v) {
|
|
69
|
+
const elements = [];
|
|
70
|
+
for (const inputElement of input) {
|
|
75
71
|
if (inputElement.fullPropertyName === s) {
|
|
76
|
-
|
|
72
|
+
const expression = inputElement.node.getValue();
|
|
77
73
|
if (expression && this.findValueInExpression(expression, v)) {
|
|
78
74
|
elements.push(inputElement);
|
|
79
75
|
}
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
78
|
return elements;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
expression.accept(
|
|
79
|
+
}
|
|
80
|
+
findValueInExpression(expression, v) {
|
|
81
|
+
let found = false;
|
|
82
|
+
expression.accept(node => {
|
|
87
83
|
if (node.type === nodes.NodeType.Identifier && node.matches(v)) {
|
|
88
84
|
found = true;
|
|
89
85
|
}
|
|
90
86
|
return !found;
|
|
91
87
|
});
|
|
92
88
|
return found;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return this.warnings.filter(function (entry) {
|
|
89
|
+
}
|
|
90
|
+
getEntries(filter = (nodes.Level.Warning | nodes.Level.Error)) {
|
|
91
|
+
return this.warnings.filter(entry => {
|
|
97
92
|
return (entry.getLevel() & filter) !== 0;
|
|
98
93
|
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
}
|
|
95
|
+
addEntry(node, rule, details) {
|
|
96
|
+
const entry = new nodes.Marker(node, rule, this.settings.getRule(rule), details);
|
|
102
97
|
this.warnings.push(entry);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
for (
|
|
107
|
-
|
|
98
|
+
}
|
|
99
|
+
getMissingNames(expected, actual) {
|
|
100
|
+
const expectedClone = expected.slice(0); // clone
|
|
101
|
+
for (let i = 0; i < actual.length; i++) {
|
|
102
|
+
const k = expectedClone.indexOf(actual[i]);
|
|
108
103
|
if (k !== -1) {
|
|
109
104
|
expectedClone[k] = null;
|
|
110
105
|
}
|
|
111
106
|
}
|
|
112
|
-
|
|
113
|
-
for (
|
|
114
|
-
|
|
107
|
+
let result = null;
|
|
108
|
+
for (let i = 0; i < expectedClone.length; i++) {
|
|
109
|
+
const curr = expectedClone[i];
|
|
115
110
|
if (curr) {
|
|
116
111
|
if (result === null) {
|
|
117
112
|
result = localize('namelist.single', "'{0}'", curr);
|
|
@@ -122,8 +117,8 @@ var LintVisitor = /** @class */ (function () {
|
|
|
122
117
|
}
|
|
123
118
|
}
|
|
124
119
|
return result;
|
|
125
|
-
}
|
|
126
|
-
|
|
120
|
+
}
|
|
121
|
+
visitNode(node) {
|
|
127
122
|
switch (node.type) {
|
|
128
123
|
case nodes.NodeType.UnknownAtRule:
|
|
129
124
|
return this.visitUnknownAtRule(node);
|
|
@@ -149,87 +144,86 @@ var LintVisitor = /** @class */ (function () {
|
|
|
149
144
|
return this.visitIdentifierSelector(node);
|
|
150
145
|
}
|
|
151
146
|
return true;
|
|
152
|
-
}
|
|
153
|
-
|
|
147
|
+
}
|
|
148
|
+
completeValidations() {
|
|
154
149
|
this.validateKeyframes();
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
150
|
+
}
|
|
151
|
+
visitUnknownAtRule(node) {
|
|
152
|
+
const atRuleName = node.getChild(0);
|
|
158
153
|
if (!atRuleName) {
|
|
159
154
|
return false;
|
|
160
155
|
}
|
|
161
|
-
|
|
156
|
+
const atDirective = this.cssDataManager.getAtDirective(atRuleName.getText());
|
|
162
157
|
if (atDirective) {
|
|
163
158
|
return false;
|
|
164
159
|
}
|
|
165
|
-
this.addEntry(atRuleName, Rules.UnknownAtRules,
|
|
160
|
+
this.addEntry(atRuleName, Rules.UnknownAtRules, `Unknown at rule ${atRuleName.getText()}`);
|
|
166
161
|
return true;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
162
|
+
}
|
|
163
|
+
visitKeyframe(node) {
|
|
164
|
+
const keyword = node.getKeyword();
|
|
170
165
|
if (!keyword) {
|
|
171
166
|
return false;
|
|
172
167
|
}
|
|
173
|
-
|
|
168
|
+
const text = keyword.getText();
|
|
174
169
|
this.keyframes.add(node.getName(), text, (text !== '@keyframes') ? keyword : null);
|
|
175
170
|
return true;
|
|
176
|
-
}
|
|
177
|
-
|
|
171
|
+
}
|
|
172
|
+
validateKeyframes() {
|
|
178
173
|
// @keyframe and it's vendor specific alternatives
|
|
179
174
|
// @keyframe should be included
|
|
180
|
-
|
|
181
|
-
for (
|
|
182
|
-
|
|
183
|
-
|
|
175
|
+
const expected = ['@-webkit-keyframes', '@-moz-keyframes', '@-o-keyframes'];
|
|
176
|
+
for (const name in this.keyframes.data) {
|
|
177
|
+
const actual = this.keyframes.data[name].names;
|
|
178
|
+
const needsStandard = (actual.indexOf('@keyframes') === -1);
|
|
184
179
|
if (!needsStandard && actual.length === 1) {
|
|
185
180
|
continue; // only the non-vendor specific keyword is used, that's fine, no warning
|
|
186
181
|
}
|
|
187
|
-
|
|
182
|
+
const missingVendorSpecific = this.getMissingNames(expected, actual);
|
|
188
183
|
if (missingVendorSpecific || needsStandard) {
|
|
189
|
-
for (
|
|
190
|
-
var node = _a[_i];
|
|
184
|
+
for (const node of this.keyframes.data[name].nodes) {
|
|
191
185
|
if (needsStandard) {
|
|
192
|
-
|
|
186
|
+
const message = localize('keyframes.standardrule.missing', "Always define standard rule '@keyframes' when defining keyframes.");
|
|
193
187
|
this.addEntry(node, Rules.IncludeStandardPropertyWhenUsingVendorPrefix, message);
|
|
194
188
|
}
|
|
195
189
|
if (missingVendorSpecific) {
|
|
196
|
-
|
|
190
|
+
const message = localize('keyframes.vendorspecific.missing', "Always include all vendor specific rules: Missing: {0}", missingVendorSpecific);
|
|
197
191
|
this.addEntry(node, Rules.AllVendorPrefixes, message);
|
|
198
192
|
}
|
|
199
193
|
}
|
|
200
194
|
}
|
|
201
195
|
}
|
|
202
196
|
return true;
|
|
203
|
-
}
|
|
204
|
-
|
|
197
|
+
}
|
|
198
|
+
visitSimpleSelector(node) {
|
|
205
199
|
/////////////////////////////////////////////////////////////
|
|
206
200
|
// Lint - The universal selector (*) is known to be slow.
|
|
207
201
|
/////////////////////////////////////////////////////////////
|
|
208
|
-
|
|
202
|
+
const firstChar = this.documentText.charAt(node.offset);
|
|
209
203
|
if (node.length === 1 && firstChar === '*') {
|
|
210
204
|
this.addEntry(node, Rules.UniversalSelector);
|
|
211
205
|
}
|
|
212
206
|
return true;
|
|
213
|
-
}
|
|
214
|
-
|
|
207
|
+
}
|
|
208
|
+
visitIdentifierSelector(node) {
|
|
215
209
|
/////////////////////////////////////////////////////////////
|
|
216
210
|
// Lint - Avoid id selectors
|
|
217
211
|
/////////////////////////////////////////////////////////////
|
|
218
212
|
this.addEntry(node, Rules.AvoidIdSelector);
|
|
219
213
|
return true;
|
|
220
|
-
}
|
|
221
|
-
|
|
214
|
+
}
|
|
215
|
+
visitImport(node) {
|
|
222
216
|
/////////////////////////////////////////////////////////////
|
|
223
217
|
// Lint - Import statements shouldn't be used, because they aren't offering parallel downloads.
|
|
224
218
|
/////////////////////////////////////////////////////////////
|
|
225
219
|
this.addEntry(node, Rules.ImportStatemement);
|
|
226
220
|
return true;
|
|
227
|
-
}
|
|
228
|
-
|
|
221
|
+
}
|
|
222
|
+
visitRuleSet(node) {
|
|
229
223
|
/////////////////////////////////////////////////////////////
|
|
230
224
|
// Lint - Don't use empty rulesets.
|
|
231
225
|
/////////////////////////////////////////////////////////////
|
|
232
|
-
|
|
226
|
+
const declarations = node.getDeclarations();
|
|
233
227
|
if (!declarations) {
|
|
234
228
|
// syntax error
|
|
235
229
|
return false;
|
|
@@ -237,9 +231,8 @@ var LintVisitor = /** @class */ (function () {
|
|
|
237
231
|
if (!declarations.hasChildren()) {
|
|
238
232
|
this.addEntry(node.getSelectors(), Rules.EmptyRuleSet);
|
|
239
233
|
}
|
|
240
|
-
|
|
241
|
-
for (
|
|
242
|
-
var element = _a[_i];
|
|
234
|
+
const propertyTable = [];
|
|
235
|
+
for (const element of declarations.getChildren()) {
|
|
243
236
|
if (element instanceof nodes.Declaration) {
|
|
244
237
|
propertyTable.push(new Element(element));
|
|
245
238
|
}
|
|
@@ -251,9 +244,9 @@ var LintVisitor = /** @class */ (function () {
|
|
|
251
244
|
// No error when box-sizing property is specified, as it assumes the user knows what he's doing.
|
|
252
245
|
// see https://github.com/CSSLint/csslint/wiki/Beware-of-box-model-size
|
|
253
246
|
/////////////////////////////////////////////////////////////
|
|
254
|
-
|
|
247
|
+
const boxModel = calculateBoxModel(propertyTable);
|
|
255
248
|
if (boxModel.width) {
|
|
256
|
-
|
|
249
|
+
let properties = [];
|
|
257
250
|
if (boxModel.right.value) {
|
|
258
251
|
properties = union(properties, boxModel.right.properties);
|
|
259
252
|
}
|
|
@@ -261,15 +254,14 @@ var LintVisitor = /** @class */ (function () {
|
|
|
261
254
|
properties = union(properties, boxModel.left.properties);
|
|
262
255
|
}
|
|
263
256
|
if (properties.length !== 0) {
|
|
264
|
-
for (
|
|
265
|
-
var item = properties_1[_b];
|
|
257
|
+
for (const item of properties) {
|
|
266
258
|
this.addEntry(item.node, Rules.BewareOfBoxModelSize);
|
|
267
259
|
}
|
|
268
260
|
this.addEntry(boxModel.width.node, Rules.BewareOfBoxModelSize);
|
|
269
261
|
}
|
|
270
262
|
}
|
|
271
263
|
if (boxModel.height) {
|
|
272
|
-
|
|
264
|
+
let properties = [];
|
|
273
265
|
if (boxModel.top.value) {
|
|
274
266
|
properties = union(properties, boxModel.top.properties);
|
|
275
267
|
}
|
|
@@ -277,8 +269,7 @@ var LintVisitor = /** @class */ (function () {
|
|
|
277
269
|
properties = union(properties, boxModel.bottom.properties);
|
|
278
270
|
}
|
|
279
271
|
if (properties.length !== 0) {
|
|
280
|
-
for (
|
|
281
|
-
var item = properties_2[_c];
|
|
272
|
+
for (const item of properties) {
|
|
282
273
|
this.addEntry(item.node, Rules.BewareOfBoxModelSize);
|
|
283
274
|
}
|
|
284
275
|
this.addEntry(boxModel.height.node, Rules.BewareOfBoxModelSize);
|
|
@@ -288,31 +279,31 @@ var LintVisitor = /** @class */ (function () {
|
|
|
288
279
|
// Properties ignored due to display
|
|
289
280
|
/////////////////////////////////////////////////////////////
|
|
290
281
|
// With 'display: inline-block', 'float' has no effect
|
|
291
|
-
|
|
282
|
+
let displayElems = this.fetchWithValue(propertyTable, 'display', 'inline-block');
|
|
292
283
|
if (displayElems.length > 0) {
|
|
293
|
-
|
|
294
|
-
for (
|
|
295
|
-
|
|
296
|
-
|
|
284
|
+
const elem = this.fetch(propertyTable, 'float');
|
|
285
|
+
for (let index = 0; index < elem.length; index++) {
|
|
286
|
+
const node = elem[index].node;
|
|
287
|
+
const value = node.getValue();
|
|
297
288
|
if (value && !value.matches('none')) {
|
|
298
|
-
this.addEntry(
|
|
289
|
+
this.addEntry(node, Rules.PropertyIgnoredDueToDisplay, localize('rule.propertyIgnoredDueToDisplayInlineBlock', "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'"));
|
|
299
290
|
}
|
|
300
291
|
}
|
|
301
292
|
}
|
|
302
293
|
// With 'display: block', 'vertical-align' has no effect
|
|
303
294
|
displayElems = this.fetchWithValue(propertyTable, 'display', 'block');
|
|
304
295
|
if (displayElems.length > 0) {
|
|
305
|
-
|
|
306
|
-
for (
|
|
296
|
+
const elem = this.fetch(propertyTable, 'vertical-align');
|
|
297
|
+
for (let index = 0; index < elem.length; index++) {
|
|
307
298
|
this.addEntry(elem[index].node, Rules.PropertyIgnoredDueToDisplay, localize('rule.propertyIgnoredDueToDisplayBlock', "Property is ignored due to the display. With 'display: block', vertical-align should not be used."));
|
|
308
299
|
}
|
|
309
300
|
}
|
|
310
301
|
/////////////////////////////////////////////////////////////
|
|
311
302
|
// Avoid 'float'
|
|
312
303
|
/////////////////////////////////////////////////////////////
|
|
313
|
-
|
|
314
|
-
for (
|
|
315
|
-
|
|
304
|
+
const elements = this.fetch(propertyTable, 'float');
|
|
305
|
+
for (let index = 0; index < elements.length; index++) {
|
|
306
|
+
const element = elements[index];
|
|
316
307
|
if (!this.isValidPropertyDeclaration(element)) {
|
|
317
308
|
this.addEntry(element.node, Rules.AvoidFloat);
|
|
318
309
|
}
|
|
@@ -320,16 +311,16 @@ var LintVisitor = /** @class */ (function () {
|
|
|
320
311
|
/////////////////////////////////////////////////////////////
|
|
321
312
|
// Don't use duplicate declarations.
|
|
322
313
|
/////////////////////////////////////////////////////////////
|
|
323
|
-
for (
|
|
324
|
-
|
|
314
|
+
for (let i = 0; i < propertyTable.length; i++) {
|
|
315
|
+
const element = propertyTable[i];
|
|
325
316
|
if (element.fullPropertyName !== 'background' && !this.validProperties[element.fullPropertyName]) {
|
|
326
|
-
|
|
317
|
+
const value = element.node.getValue();
|
|
327
318
|
if (value && this.documentText.charAt(value.offset) !== '-') {
|
|
328
|
-
|
|
329
|
-
if (
|
|
330
|
-
for (
|
|
331
|
-
|
|
332
|
-
if (
|
|
319
|
+
const elements = this.fetch(propertyTable, element.fullPropertyName);
|
|
320
|
+
if (elements.length > 1) {
|
|
321
|
+
for (let k = 0; k < elements.length; k++) {
|
|
322
|
+
const value = elements[k].node.getValue();
|
|
323
|
+
if (value && this.documentText.charAt(value.offset) !== '-' && elements[k] !== element) {
|
|
333
324
|
this.addEntry(element.node, Rules.DuplicateDeclarations);
|
|
334
325
|
}
|
|
335
326
|
}
|
|
@@ -340,27 +331,26 @@ var LintVisitor = /** @class */ (function () {
|
|
|
340
331
|
/////////////////////////////////////////////////////////////
|
|
341
332
|
// Unknown propery & When using a vendor-prefixed gradient, make sure to use them all.
|
|
342
333
|
/////////////////////////////////////////////////////////////
|
|
343
|
-
|
|
334
|
+
const isExportBlock = node.getSelectors().matches(":export");
|
|
344
335
|
if (!isExportBlock) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
for (
|
|
348
|
-
|
|
349
|
-
var decl = element.node;
|
|
336
|
+
const propertiesBySuffix = new NodesByRootMap();
|
|
337
|
+
let containsUnknowns = false;
|
|
338
|
+
for (const element of propertyTable) {
|
|
339
|
+
const decl = element.node;
|
|
350
340
|
if (this.isCSSDeclaration(decl)) {
|
|
351
|
-
|
|
352
|
-
|
|
341
|
+
let name = element.fullPropertyName;
|
|
342
|
+
const firstChar = name.charAt(0);
|
|
353
343
|
if (firstChar === '-') {
|
|
354
344
|
if (name.charAt(1) !== '-') { // avoid css variables
|
|
355
345
|
if (!this.cssDataManager.isKnownProperty(name) && !this.validProperties[name]) {
|
|
356
346
|
this.addEntry(decl.getProperty(), Rules.UnknownVendorSpecificProperty);
|
|
357
347
|
}
|
|
358
|
-
|
|
348
|
+
const nonPrefixedName = decl.getNonPrefixedPropertyName();
|
|
359
349
|
propertiesBySuffix.add(nonPrefixedName, name, decl.getProperty());
|
|
360
350
|
}
|
|
361
351
|
}
|
|
362
352
|
else {
|
|
363
|
-
|
|
353
|
+
const fullName = name;
|
|
364
354
|
if (firstChar === '*' || firstChar === '_') {
|
|
365
355
|
this.addEntry(decl.getProperty(), Rules.IEStarHack);
|
|
366
356
|
name = name.substr(1);
|
|
@@ -379,31 +369,30 @@ var LintVisitor = /** @class */ (function () {
|
|
|
379
369
|
}
|
|
380
370
|
}
|
|
381
371
|
if (!containsUnknowns) { // don't perform this test if there are
|
|
382
|
-
for (
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
372
|
+
for (const suffix in propertiesBySuffix.data) {
|
|
373
|
+
const entry = propertiesBySuffix.data[suffix];
|
|
374
|
+
const actual = entry.names;
|
|
375
|
+
const needsStandard = this.cssDataManager.isStandardProperty(suffix) && (actual.indexOf(suffix) === -1);
|
|
386
376
|
if (!needsStandard && actual.length === 1) {
|
|
387
377
|
continue; // only the non-vendor specific rule is used, that's fine, no warning
|
|
388
378
|
}
|
|
389
|
-
|
|
390
|
-
for (
|
|
391
|
-
|
|
379
|
+
const expected = [];
|
|
380
|
+
for (let i = 0, len = LintVisitor.prefixes.length; i < len; i++) {
|
|
381
|
+
const prefix = LintVisitor.prefixes[i];
|
|
392
382
|
if (this.cssDataManager.isStandardProperty(prefix + suffix)) {
|
|
393
383
|
expected.push(prefix + suffix);
|
|
394
384
|
}
|
|
395
385
|
}
|
|
396
|
-
|
|
386
|
+
const missingVendorSpecific = this.getMissingNames(expected, actual);
|
|
397
387
|
if (missingVendorSpecific || needsStandard) {
|
|
398
|
-
for (
|
|
399
|
-
var node_2 = _f[_e];
|
|
388
|
+
for (const node of entry.nodes) {
|
|
400
389
|
if (needsStandard) {
|
|
401
|
-
|
|
402
|
-
this.addEntry(
|
|
390
|
+
const message = localize('property.standard.missing', "Also define the standard property '{0}' for compatibility", suffix);
|
|
391
|
+
this.addEntry(node, Rules.IncludeStandardPropertyWhenUsingVendorPrefix, message);
|
|
403
392
|
}
|
|
404
393
|
if (missingVendorSpecific) {
|
|
405
|
-
|
|
406
|
-
this.addEntry(
|
|
394
|
+
const message = localize('property.vendorspecific.missing', "Always include all vendor specific properties: Missing: {0}", missingVendorSpecific);
|
|
395
|
+
this.addEntry(node, Rules.AllVendorPrefixes, message);
|
|
407
396
|
}
|
|
408
397
|
}
|
|
409
398
|
}
|
|
@@ -411,27 +400,27 @@ var LintVisitor = /** @class */ (function () {
|
|
|
411
400
|
}
|
|
412
401
|
}
|
|
413
402
|
return true;
|
|
414
|
-
}
|
|
415
|
-
|
|
403
|
+
}
|
|
404
|
+
visitPrio(node) {
|
|
416
405
|
/////////////////////////////////////////////////////////////
|
|
417
406
|
// Don't use !important
|
|
418
407
|
/////////////////////////////////////////////////////////////
|
|
419
408
|
this.addEntry(node, Rules.AvoidImportant);
|
|
420
409
|
return true;
|
|
421
|
-
}
|
|
422
|
-
|
|
410
|
+
}
|
|
411
|
+
visitNumericValue(node) {
|
|
423
412
|
/////////////////////////////////////////////////////////////
|
|
424
413
|
// 0 has no following unit
|
|
425
414
|
/////////////////////////////////////////////////////////////
|
|
426
|
-
|
|
415
|
+
const funcDecl = node.findParent(nodes.NodeType.Function);
|
|
427
416
|
if (funcDecl && funcDecl.getName() === 'calc') {
|
|
428
417
|
return true;
|
|
429
418
|
}
|
|
430
|
-
|
|
419
|
+
const decl = node.findParent(nodes.NodeType.Declaration);
|
|
431
420
|
if (decl) {
|
|
432
|
-
|
|
421
|
+
const declValue = decl.getValue();
|
|
433
422
|
if (declValue) {
|
|
434
|
-
|
|
423
|
+
const value = node.getValue();
|
|
435
424
|
if (!value.unit || languageFacts.units.length.indexOf(value.unit.toLowerCase()) === -1) {
|
|
436
425
|
return true;
|
|
437
426
|
}
|
|
@@ -441,19 +430,18 @@ var LintVisitor = /** @class */ (function () {
|
|
|
441
430
|
}
|
|
442
431
|
}
|
|
443
432
|
return true;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
433
|
+
}
|
|
434
|
+
visitFontFace(node) {
|
|
435
|
+
const declarations = node.getDeclarations();
|
|
447
436
|
if (!declarations) {
|
|
448
437
|
// syntax error
|
|
449
438
|
return false;
|
|
450
439
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
for (
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
var name = node_3.getProperty().getName().toLowerCase();
|
|
440
|
+
let definesSrc = false, definesFontFamily = false;
|
|
441
|
+
let containsUnknowns = false;
|
|
442
|
+
for (const node of declarations.getChildren()) {
|
|
443
|
+
if (this.isCSSDeclaration(node)) {
|
|
444
|
+
const name = node.getProperty().getName().toLowerCase();
|
|
457
445
|
if (name === 'src') {
|
|
458
446
|
definesSrc = true;
|
|
459
447
|
}
|
|
@@ -469,36 +457,36 @@ var LintVisitor = /** @class */ (function () {
|
|
|
469
457
|
this.addEntry(node, Rules.RequiredPropertiesForFontFace);
|
|
470
458
|
}
|
|
471
459
|
return true;
|
|
472
|
-
}
|
|
473
|
-
|
|
460
|
+
}
|
|
461
|
+
isCSSDeclaration(node) {
|
|
474
462
|
if (node instanceof nodes.Declaration) {
|
|
475
463
|
if (!node.getValue()) {
|
|
476
464
|
return false;
|
|
477
465
|
}
|
|
478
|
-
|
|
466
|
+
const property = node.getProperty();
|
|
479
467
|
if (!property) {
|
|
480
468
|
return false;
|
|
481
469
|
}
|
|
482
|
-
|
|
470
|
+
const identifier = property.getIdentifier();
|
|
483
471
|
if (!identifier || identifier.containsInterpolation()) {
|
|
484
472
|
return false;
|
|
485
473
|
}
|
|
486
474
|
return true;
|
|
487
475
|
}
|
|
488
476
|
return false;
|
|
489
|
-
}
|
|
490
|
-
|
|
477
|
+
}
|
|
478
|
+
visitHexColorValue(node) {
|
|
491
479
|
// Rule: #eeff0011 or #eeff00 or #ef01 or #ef0
|
|
492
|
-
|
|
480
|
+
const length = node.length;
|
|
493
481
|
if (length !== 9 && length !== 7 && length !== 5 && length !== 4) {
|
|
494
482
|
this.addEntry(node, Rules.HexColorLength);
|
|
495
483
|
}
|
|
496
484
|
return false;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
485
|
+
}
|
|
486
|
+
visitFunction(node) {
|
|
487
|
+
const fnName = node.getName().toLowerCase();
|
|
488
|
+
let expectedAttrCount = -1;
|
|
489
|
+
let actualAttrCount = 0;
|
|
502
490
|
switch (fnName) {
|
|
503
491
|
case 'rgb(':
|
|
504
492
|
case 'hsl(':
|
|
@@ -510,7 +498,7 @@ var LintVisitor = /** @class */ (function () {
|
|
|
510
498
|
break;
|
|
511
499
|
}
|
|
512
500
|
if (expectedAttrCount !== -1) {
|
|
513
|
-
node.getArguments().accept(
|
|
501
|
+
node.getArguments().accept(n => {
|
|
514
502
|
if (n instanceof nodes.BinaryExpression) {
|
|
515
503
|
actualAttrCount += 1;
|
|
516
504
|
return false;
|
|
@@ -522,11 +510,9 @@ var LintVisitor = /** @class */ (function () {
|
|
|
522
510
|
}
|
|
523
511
|
}
|
|
524
512
|
return true;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}());
|
|
532
|
-
export { LintVisitor };
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
LintVisitor.prefixes = [
|
|
516
|
+
'-ms-', '-moz-', '-o-', '-webkit-', // Quite common
|
|
517
|
+
// '-xv-', '-atsc-', '-wap-', '-khtml-', 'mso-', 'prince-', '-ah-', '-hp-', '-ro-', '-rim-', '-tc-' // Quite un-common
|
|
518
|
+
];
|