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