vscode-css-languageservice 6.0.1 → 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.
Files changed (87) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/SECURITY.md +41 -0
  3. package/lib/esm/beautify/beautify-css.js +11 -4
  4. package/lib/esm/cssLanguageService.d.ts +38 -37
  5. package/lib/esm/cssLanguageService.js +73 -72
  6. package/lib/esm/cssLanguageTypes.d.ts +238 -238
  7. package/lib/esm/cssLanguageTypes.js +42 -42
  8. package/lib/esm/data/webCustomData.js +22089 -21959
  9. package/lib/esm/languageFacts/builtinData.js +142 -142
  10. package/lib/esm/languageFacts/colors.js +469 -469
  11. package/lib/esm/languageFacts/dataManager.js +88 -88
  12. package/lib/esm/languageFacts/dataProvider.js +73 -73
  13. package/lib/esm/languageFacts/entry.js +137 -137
  14. package/lib/esm/languageFacts/facts.js +8 -8
  15. package/lib/esm/parser/cssErrors.js +48 -48
  16. package/lib/esm/parser/cssNodes.js +1511 -1502
  17. package/lib/esm/parser/cssParser.js +1606 -1534
  18. package/lib/esm/parser/cssScanner.js +592 -592
  19. package/lib/esm/parser/cssSymbolScope.js +311 -311
  20. package/lib/esm/parser/lessParser.js +715 -714
  21. package/lib/esm/parser/lessScanner.js +57 -57
  22. package/lib/esm/parser/scssErrors.js +18 -18
  23. package/lib/esm/parser/scssParser.js +806 -796
  24. package/lib/esm/parser/scssScanner.js +95 -95
  25. package/lib/esm/services/cssCodeActions.js +77 -77
  26. package/lib/esm/services/cssCompletion.js +1054 -1054
  27. package/lib/esm/services/cssFolding.js +190 -190
  28. package/lib/esm/services/cssFormatter.js +136 -136
  29. package/lib/esm/services/cssHover.js +148 -148
  30. package/lib/esm/services/cssNavigation.js +441 -378
  31. package/lib/esm/services/cssSelectionRange.js +47 -47
  32. package/lib/esm/services/cssValidation.js +41 -41
  33. package/lib/esm/services/lessCompletion.js +378 -378
  34. package/lib/esm/services/lint.js +518 -518
  35. package/lib/esm/services/lintRules.js +76 -76
  36. package/lib/esm/services/lintUtil.js +196 -196
  37. package/lib/esm/services/pathCompletion.js +157 -157
  38. package/lib/esm/services/scssCompletion.js +354 -354
  39. package/lib/esm/services/scssNavigation.js +82 -82
  40. package/lib/esm/services/selectorPrinting.js +492 -492
  41. package/lib/esm/utils/arrays.js +40 -40
  42. package/lib/esm/utils/objects.js +11 -11
  43. package/lib/esm/utils/resources.js +11 -11
  44. package/lib/esm/utils/strings.js +102 -102
  45. package/lib/umd/beautify/beautify-css.js +11 -4
  46. package/lib/umd/cssLanguageService.d.ts +38 -37
  47. package/lib/umd/cssLanguageService.js +104 -99
  48. package/lib/umd/cssLanguageTypes.d.ts +238 -238
  49. package/lib/umd/cssLanguageTypes.js +89 -89
  50. package/lib/umd/data/webCustomData.js +22102 -21972
  51. package/lib/umd/languageFacts/builtinData.js +154 -154
  52. package/lib/umd/languageFacts/colors.js +492 -492
  53. package/lib/umd/languageFacts/dataManager.js +101 -101
  54. package/lib/umd/languageFacts/dataProvider.js +86 -86
  55. package/lib/umd/languageFacts/entry.js +152 -152
  56. package/lib/umd/languageFacts/facts.js +33 -29
  57. package/lib/umd/parser/cssErrors.js +61 -61
  58. package/lib/umd/parser/cssNodes.js +1597 -1587
  59. package/lib/umd/parser/cssParser.js +1619 -1547
  60. package/lib/umd/parser/cssScanner.js +606 -606
  61. package/lib/umd/parser/cssSymbolScope.js +328 -328
  62. package/lib/umd/parser/lessParser.js +728 -727
  63. package/lib/umd/parser/lessScanner.js +70 -70
  64. package/lib/umd/parser/scssErrors.js +31 -31
  65. package/lib/umd/parser/scssParser.js +819 -809
  66. package/lib/umd/parser/scssScanner.js +108 -108
  67. package/lib/umd/services/cssCodeActions.js +90 -90
  68. package/lib/umd/services/cssCompletion.js +1067 -1067
  69. package/lib/umd/services/cssFolding.js +203 -203
  70. package/lib/umd/services/cssFormatter.js +150 -150
  71. package/lib/umd/services/cssHover.js +161 -161
  72. package/lib/umd/services/cssNavigation.js +454 -391
  73. package/lib/umd/services/cssSelectionRange.js +60 -60
  74. package/lib/umd/services/cssValidation.js +54 -54
  75. package/lib/umd/services/lessCompletion.js +391 -391
  76. package/lib/umd/services/lint.js +531 -531
  77. package/lib/umd/services/lintRules.js +91 -91
  78. package/lib/umd/services/lintUtil.js +210 -210
  79. package/lib/umd/services/pathCompletion.js +171 -171
  80. package/lib/umd/services/scssCompletion.js +367 -367
  81. package/lib/umd/services/scssNavigation.js +95 -95
  82. package/lib/umd/services/selectorPrinting.js +510 -510
  83. package/lib/umd/utils/arrays.js +55 -55
  84. package/lib/umd/utils/objects.js +25 -25
  85. package/lib/umd/utils/resources.js +26 -26
  86. package/lib/umd/utils/strings.js +120 -120
  87. package/package.json +13 -12
@@ -1,391 +1,454 @@
1
- (function (factory) {
2
- if (typeof module === "object" && typeof module.exports === "object") {
3
- var v = factory(require, exports);
4
- if (v !== undefined) module.exports = v;
5
- }
6
- else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "../cssLanguageTypes", "vscode-nls", "../parser/cssNodes", "../parser/cssSymbolScope", "../languageFacts/facts", "../utils/strings", "../utils/resources"], factory);
8
- }
9
- })(function (require, exports) {
10
- /*---------------------------------------------------------------------------------------------
11
- * Copyright (c) Microsoft Corporation. All rights reserved.
12
- * Licensed under the MIT License. See License.txt in the project root for license information.
13
- *--------------------------------------------------------------------------------------------*/
14
- 'use strict';
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.CSSNavigation = void 0;
17
- const cssLanguageTypes_1 = require("../cssLanguageTypes");
18
- const nls = require("vscode-nls");
19
- const nodes = require("../parser/cssNodes");
20
- const cssSymbolScope_1 = require("../parser/cssSymbolScope");
21
- const facts_1 = require("../languageFacts/facts");
22
- const strings_1 = require("../utils/strings");
23
- const resources_1 = require("../utils/resources");
24
- const localize = nls.loadMessageBundle();
25
- const startsWithSchemeRegex = /^\w+:\/\//;
26
- const startsWithData = /^data:/;
27
- class CSSNavigation {
28
- constructor(fileSystemProvider, resolveModuleReferences) {
29
- this.fileSystemProvider = fileSystemProvider;
30
- this.resolveModuleReferences = resolveModuleReferences;
31
- }
32
- findDefinition(document, position, stylesheet) {
33
- const symbols = new cssSymbolScope_1.Symbols(stylesheet);
34
- const offset = document.offsetAt(position);
35
- const node = nodes.getNodeAtOffset(stylesheet, offset);
36
- if (!node) {
37
- return null;
38
- }
39
- const symbol = symbols.findSymbolFromNode(node);
40
- if (!symbol) {
41
- return null;
42
- }
43
- return {
44
- uri: document.uri,
45
- range: getRange(symbol.node, document)
46
- };
47
- }
48
- findReferences(document, position, stylesheet) {
49
- const highlights = this.findDocumentHighlights(document, position, stylesheet);
50
- return highlights.map(h => {
51
- return {
52
- uri: document.uri,
53
- range: h.range
54
- };
55
- });
56
- }
57
- findDocumentHighlights(document, position, stylesheet) {
58
- const result = [];
59
- const offset = document.offsetAt(position);
60
- let node = nodes.getNodeAtOffset(stylesheet, offset);
61
- if (!node || node.type === nodes.NodeType.Stylesheet || node.type === nodes.NodeType.Declarations) {
62
- return result;
63
- }
64
- if (node.type === nodes.NodeType.Identifier && node.parent && node.parent.type === nodes.NodeType.ClassSelector) {
65
- node = node.parent;
66
- }
67
- const symbols = new cssSymbolScope_1.Symbols(stylesheet);
68
- const symbol = symbols.findSymbolFromNode(node);
69
- const name = node.getText();
70
- stylesheet.accept(candidate => {
71
- if (symbol) {
72
- if (symbols.matchesSymbol(candidate, symbol)) {
73
- result.push({
74
- kind: getHighlightKind(candidate),
75
- range: getRange(candidate, document)
76
- });
77
- return false;
78
- }
79
- }
80
- else if (node && node.type === candidate.type && candidate.matches(name)) {
81
- // Same node type and data
82
- result.push({
83
- kind: getHighlightKind(candidate),
84
- range: getRange(candidate, document)
85
- });
86
- }
87
- return true;
88
- });
89
- return result;
90
- }
91
- isRawStringDocumentLinkNode(node) {
92
- return node.type === nodes.NodeType.Import;
93
- }
94
- findDocumentLinks(document, stylesheet, documentContext) {
95
- const linkData = this.findUnresolvedLinks(document, stylesheet);
96
- const resolvedLinks = [];
97
- for (let data of linkData) {
98
- const link = data.link;
99
- const target = link.target;
100
- if (!target || startsWithData.test(target)) {
101
- // no links for data:
102
- }
103
- else if (startsWithSchemeRegex.test(target)) {
104
- resolvedLinks.push(link);
105
- }
106
- else {
107
- const resolved = documentContext.resolveReference(target, document.uri);
108
- if (resolved) {
109
- link.target = resolved;
110
- }
111
- resolvedLinks.push(link);
112
- }
113
- }
114
- return resolvedLinks;
115
- }
116
- async findDocumentLinks2(document, stylesheet, documentContext) {
117
- const linkData = this.findUnresolvedLinks(document, stylesheet);
118
- const resolvedLinks = [];
119
- for (let data of linkData) {
120
- const link = data.link;
121
- const target = link.target;
122
- if (!target || startsWithData.test(target)) {
123
- // no links for data:
124
- }
125
- else if (startsWithSchemeRegex.test(target)) {
126
- resolvedLinks.push(link);
127
- }
128
- else {
129
- const resolvedTarget = await this.resolveRelativeReference(target, document.uri, documentContext, data.isRawLink);
130
- if (resolvedTarget !== undefined) {
131
- link.target = resolvedTarget;
132
- resolvedLinks.push(link);
133
- }
134
- }
135
- }
136
- return resolvedLinks;
137
- }
138
- findUnresolvedLinks(document, stylesheet) {
139
- const result = [];
140
- const collect = (uriStringNode) => {
141
- let rawUri = uriStringNode.getText();
142
- const range = getRange(uriStringNode, document);
143
- // Make sure the range is not empty
144
- if (range.start.line === range.end.line && range.start.character === range.end.character) {
145
- return;
146
- }
147
- if ((0, strings_1.startsWith)(rawUri, `'`) || (0, strings_1.startsWith)(rawUri, `"`)) {
148
- rawUri = rawUri.slice(1, -1);
149
- }
150
- const isRawLink = uriStringNode.parent ? this.isRawStringDocumentLinkNode(uriStringNode.parent) : false;
151
- result.push({ link: { target: rawUri, range }, isRawLink });
152
- };
153
- stylesheet.accept(candidate => {
154
- if (candidate.type === nodes.NodeType.URILiteral) {
155
- const first = candidate.getChild(0);
156
- if (first) {
157
- collect(first);
158
- }
159
- return false;
160
- }
161
- /**
162
- * In @import, it is possible to include links that do not use `url()`
163
- * For example, `@import 'foo.css';`
164
- */
165
- if (candidate.parent && this.isRawStringDocumentLinkNode(candidate.parent)) {
166
- const rawText = candidate.getText();
167
- if ((0, strings_1.startsWith)(rawText, `'`) || (0, strings_1.startsWith)(rawText, `"`)) {
168
- collect(candidate);
169
- }
170
- return false;
171
- }
172
- return true;
173
- });
174
- return result;
175
- }
176
- findDocumentSymbols(document, stylesheet) {
177
- const result = [];
178
- stylesheet.accept((node) => {
179
- const entry = {
180
- name: null,
181
- kind: cssLanguageTypes_1.SymbolKind.Class,
182
- location: null
183
- };
184
- let locationNode = node;
185
- if (node instanceof nodes.Selector) {
186
- entry.name = node.getText();
187
- locationNode = node.findAParent(nodes.NodeType.Ruleset, nodes.NodeType.ExtendsReference);
188
- if (locationNode) {
189
- entry.location = cssLanguageTypes_1.Location.create(document.uri, getRange(locationNode, document));
190
- result.push(entry);
191
- }
192
- return false;
193
- }
194
- else if (node instanceof nodes.VariableDeclaration) {
195
- entry.name = node.getName();
196
- entry.kind = cssLanguageTypes_1.SymbolKind.Variable;
197
- }
198
- else if (node instanceof nodes.MixinDeclaration) {
199
- entry.name = node.getName();
200
- entry.kind = cssLanguageTypes_1.SymbolKind.Method;
201
- }
202
- else if (node instanceof nodes.FunctionDeclaration) {
203
- entry.name = node.getName();
204
- entry.kind = cssLanguageTypes_1.SymbolKind.Function;
205
- }
206
- else if (node instanceof nodes.Keyframe) {
207
- entry.name = localize('literal.keyframes', "@keyframes {0}", node.getName());
208
- }
209
- else if (node instanceof nodes.FontFace) {
210
- entry.name = localize('literal.fontface', "@font-face");
211
- }
212
- else if (node instanceof nodes.Media) {
213
- const mediaList = node.getChild(0);
214
- if (mediaList instanceof nodes.Medialist) {
215
- entry.name = '@media ' + mediaList.getText();
216
- entry.kind = cssLanguageTypes_1.SymbolKind.Module;
217
- }
218
- }
219
- if (entry.name) {
220
- entry.location = cssLanguageTypes_1.Location.create(document.uri, getRange(locationNode, document));
221
- result.push(entry);
222
- }
223
- return true;
224
- });
225
- return result;
226
- }
227
- findDocumentColors(document, stylesheet) {
228
- const result = [];
229
- stylesheet.accept((node) => {
230
- const colorInfo = getColorInformation(node, document);
231
- if (colorInfo) {
232
- result.push(colorInfo);
233
- }
234
- return true;
235
- });
236
- return result;
237
- }
238
- getColorPresentations(document, stylesheet, color, range) {
239
- const result = [];
240
- const red256 = Math.round(color.red * 255), green256 = Math.round(color.green * 255), blue256 = Math.round(color.blue * 255);
241
- let label;
242
- if (color.alpha === 1) {
243
- label = `rgb(${red256}, ${green256}, ${blue256})`;
244
- }
245
- else {
246
- label = `rgba(${red256}, ${green256}, ${blue256}, ${color.alpha})`;
247
- }
248
- result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
249
- if (color.alpha === 1) {
250
- label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}`;
251
- }
252
- else {
253
- label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}${toTwoDigitHex(Math.round(color.alpha * 255))}`;
254
- }
255
- result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
256
- const hsl = (0, facts_1.hslFromColor)(color);
257
- if (hsl.a === 1) {
258
- label = `hsl(${hsl.h}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%)`;
259
- }
260
- else {
261
- label = `hsla(${hsl.h}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%, ${hsl.a})`;
262
- }
263
- result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
264
- const hwb = (0, facts_1.hwbFromColor)(color);
265
- if (hwb.a === 1) {
266
- label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}%)`;
267
- }
268
- else {
269
- label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}% / ${hwb.a})`;
270
- }
271
- result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
272
- return result;
273
- }
274
- doRename(document, position, newName, stylesheet) {
275
- const highlights = this.findDocumentHighlights(document, position, stylesheet);
276
- const edits = highlights.map(h => cssLanguageTypes_1.TextEdit.replace(h.range, newName));
277
- return {
278
- changes: { [document.uri]: edits }
279
- };
280
- }
281
- async resolveModuleReference(ref, documentUri, documentContext) {
282
- if ((0, strings_1.startsWith)(documentUri, 'file://')) {
283
- const moduleName = getModuleNameFromPath(ref);
284
- const rootFolderUri = documentContext.resolveReference('/', documentUri);
285
- const documentFolderUri = (0, resources_1.dirname)(documentUri);
286
- const modulePath = await this.resolvePathToModule(moduleName, documentFolderUri, rootFolderUri);
287
- if (modulePath) {
288
- const pathWithinModule = ref.substring(moduleName.length + 1);
289
- return (0, resources_1.joinPath)(modulePath, pathWithinModule);
290
- }
291
- }
292
- return undefined;
293
- }
294
- async resolveRelativeReference(ref, documentUri, documentContext, isRawLink) {
295
- const relativeReference = documentContext.resolveReference(ref, documentUri);
296
- // Following [css-loader](https://github.com/webpack-contrib/css-loader#url)
297
- // and [sass-loader's](https://github.com/webpack-contrib/sass-loader#imports)
298
- // convention, if an import path starts with ~ then use node module resolution
299
- // *unless* it starts with "~/" as this refers to the user's home directory.
300
- if (ref[0] === '~' && ref[1] !== '/' && this.fileSystemProvider) {
301
- ref = ref.substring(1);
302
- return await this.resolveModuleReference(ref, documentUri, documentContext) || relativeReference;
303
- }
304
- // Following [less-loader](https://github.com/webpack-contrib/less-loader#imports)
305
- // and [sass-loader's](https://github.com/webpack-contrib/sass-loader#resolving-import-at-rules)
306
- // new resolving import at-rules (~ is deprecated). The loader will first try to resolve @import as a relative path. If it cannot be resolved,
307
- // then the loader will try to resolve @import inside node_modules.
308
- if (this.resolveModuleReferences) {
309
- if (relativeReference && await this.fileExists(relativeReference)) {
310
- return relativeReference;
311
- }
312
- else {
313
- return await this.resolveModuleReference(ref, documentUri, documentContext) || relativeReference;
314
- }
315
- }
316
- return relativeReference;
317
- }
318
- async resolvePathToModule(_moduleName, documentFolderUri, rootFolderUri) {
319
- // resolve the module relative to the document. We can't use `require` here as the code is webpacked.
320
- const packPath = (0, resources_1.joinPath)(documentFolderUri, 'node_modules', _moduleName, 'package.json');
321
- if (await this.fileExists(packPath)) {
322
- return (0, resources_1.dirname)(packPath);
323
- }
324
- else if (rootFolderUri && documentFolderUri.startsWith(rootFolderUri) && (documentFolderUri.length !== rootFolderUri.length)) {
325
- return this.resolvePathToModule(_moduleName, (0, resources_1.dirname)(documentFolderUri), rootFolderUri);
326
- }
327
- return undefined;
328
- }
329
- async fileExists(uri) {
330
- if (!this.fileSystemProvider) {
331
- return false;
332
- }
333
- try {
334
- const stat = await this.fileSystemProvider.stat(uri);
335
- if (stat.type === cssLanguageTypes_1.FileType.Unknown && stat.size === -1) {
336
- return false;
337
- }
338
- return true;
339
- }
340
- catch (err) {
341
- return false;
342
- }
343
- }
344
- }
345
- exports.CSSNavigation = CSSNavigation;
346
- function getColorInformation(node, document) {
347
- const color = (0, facts_1.getColorValue)(node);
348
- if (color) {
349
- const range = getRange(node, document);
350
- return { color, range };
351
- }
352
- return null;
353
- }
354
- function getRange(node, document) {
355
- return cssLanguageTypes_1.Range.create(document.positionAt(node.offset), document.positionAt(node.end));
356
- }
357
- function getHighlightKind(node) {
358
- if (node.type === nodes.NodeType.Selector) {
359
- return cssLanguageTypes_1.DocumentHighlightKind.Write;
360
- }
361
- if (node instanceof nodes.Identifier) {
362
- if (node.parent && node.parent instanceof nodes.Property) {
363
- if (node.isCustomProperty) {
364
- return cssLanguageTypes_1.DocumentHighlightKind.Write;
365
- }
366
- }
367
- }
368
- if (node.parent) {
369
- switch (node.parent.type) {
370
- case nodes.NodeType.FunctionDeclaration:
371
- case nodes.NodeType.MixinDeclaration:
372
- case nodes.NodeType.Keyframe:
373
- case nodes.NodeType.VariableDeclaration:
374
- case nodes.NodeType.FunctionParameter:
375
- return cssLanguageTypes_1.DocumentHighlightKind.Write;
376
- }
377
- }
378
- return cssLanguageTypes_1.DocumentHighlightKind.Read;
379
- }
380
- function toTwoDigitHex(n) {
381
- const r = n.toString(16);
382
- return r.length !== 2 ? '0' + r : r;
383
- }
384
- function getModuleNameFromPath(path) {
385
- // If a scoped module (starts with @) then get up until second instance of '/', otherwise get until first instance of '/'
386
- if (path[0] === '@') {
387
- return path.substring(0, path.indexOf('/', path.indexOf('/') + 1));
388
- }
389
- return path.substring(0, path.indexOf('/'));
390
- }
391
- });
1
+ (function (factory) {
2
+ if (typeof module === "object" && typeof module.exports === "object") {
3
+ var v = factory(require, exports);
4
+ if (v !== undefined) module.exports = v;
5
+ }
6
+ else if (typeof define === "function" && define.amd) {
7
+ define(["require", "exports", "../cssLanguageTypes", "vscode-nls", "../parser/cssNodes", "../parser/cssSymbolScope", "../languageFacts/facts", "../utils/strings", "../utils/resources"], factory);
8
+ }
9
+ })(function (require, exports) {
10
+ /*---------------------------------------------------------------------------------------------
11
+ * Copyright (c) Microsoft Corporation. All rights reserved.
12
+ * Licensed under the MIT License. See License.txt in the project root for license information.
13
+ *--------------------------------------------------------------------------------------------*/
14
+ 'use strict';
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.CSSNavigation = void 0;
17
+ const cssLanguageTypes_1 = require("../cssLanguageTypes");
18
+ const nls = require("vscode-nls");
19
+ const nodes = require("../parser/cssNodes");
20
+ const cssSymbolScope_1 = require("../parser/cssSymbolScope");
21
+ const facts_1 = require("../languageFacts/facts");
22
+ const strings_1 = require("../utils/strings");
23
+ const resources_1 = require("../utils/resources");
24
+ const localize = nls.loadMessageBundle();
25
+ const startsWithSchemeRegex = /^\w+:\/\//;
26
+ const startsWithData = /^data:/;
27
+ class CSSNavigation {
28
+ constructor(fileSystemProvider, resolveModuleReferences) {
29
+ this.fileSystemProvider = fileSystemProvider;
30
+ this.resolveModuleReferences = resolveModuleReferences;
31
+ }
32
+ findDefinition(document, position, stylesheet) {
33
+ const symbols = new cssSymbolScope_1.Symbols(stylesheet);
34
+ const offset = document.offsetAt(position);
35
+ const node = nodes.getNodeAtOffset(stylesheet, offset);
36
+ if (!node) {
37
+ return null;
38
+ }
39
+ const symbol = symbols.findSymbolFromNode(node);
40
+ if (!symbol) {
41
+ return null;
42
+ }
43
+ return {
44
+ uri: document.uri,
45
+ range: getRange(symbol.node, document)
46
+ };
47
+ }
48
+ findReferences(document, position, stylesheet) {
49
+ const highlights = this.findDocumentHighlights(document, position, stylesheet);
50
+ return highlights.map(h => {
51
+ return {
52
+ uri: document.uri,
53
+ range: h.range
54
+ };
55
+ });
56
+ }
57
+ findDocumentHighlights(document, position, stylesheet) {
58
+ const result = [];
59
+ const offset = document.offsetAt(position);
60
+ let node = nodes.getNodeAtOffset(stylesheet, offset);
61
+ if (!node || node.type === nodes.NodeType.Stylesheet || node.type === nodes.NodeType.Declarations) {
62
+ return result;
63
+ }
64
+ if (node.type === nodes.NodeType.Identifier && node.parent && node.parent.type === nodes.NodeType.ClassSelector) {
65
+ node = node.parent;
66
+ }
67
+ const symbols = new cssSymbolScope_1.Symbols(stylesheet);
68
+ const symbol = symbols.findSymbolFromNode(node);
69
+ const name = node.getText();
70
+ stylesheet.accept(candidate => {
71
+ if (symbol) {
72
+ if (symbols.matchesSymbol(candidate, symbol)) {
73
+ result.push({
74
+ kind: getHighlightKind(candidate),
75
+ range: getRange(candidate, document)
76
+ });
77
+ return false;
78
+ }
79
+ }
80
+ else if (node && node.type === candidate.type && candidate.matches(name)) {
81
+ // Same node type and data
82
+ result.push({
83
+ kind: getHighlightKind(candidate),
84
+ range: getRange(candidate, document)
85
+ });
86
+ }
87
+ return true;
88
+ });
89
+ return result;
90
+ }
91
+ isRawStringDocumentLinkNode(node) {
92
+ return node.type === nodes.NodeType.Import;
93
+ }
94
+ findDocumentLinks(document, stylesheet, documentContext) {
95
+ const linkData = this.findUnresolvedLinks(document, stylesheet);
96
+ const resolvedLinks = [];
97
+ for (let data of linkData) {
98
+ const link = data.link;
99
+ const target = link.target;
100
+ if (!target || startsWithData.test(target)) {
101
+ // no links for data:
102
+ }
103
+ else if (startsWithSchemeRegex.test(target)) {
104
+ resolvedLinks.push(link);
105
+ }
106
+ else {
107
+ const resolved = documentContext.resolveReference(target, document.uri);
108
+ if (resolved) {
109
+ link.target = resolved;
110
+ }
111
+ resolvedLinks.push(link);
112
+ }
113
+ }
114
+ return resolvedLinks;
115
+ }
116
+ async findDocumentLinks2(document, stylesheet, documentContext) {
117
+ const linkData = this.findUnresolvedLinks(document, stylesheet);
118
+ const resolvedLinks = [];
119
+ for (let data of linkData) {
120
+ const link = data.link;
121
+ const target = link.target;
122
+ if (!target || startsWithData.test(target)) {
123
+ // no links for data:
124
+ }
125
+ else if (startsWithSchemeRegex.test(target)) {
126
+ resolvedLinks.push(link);
127
+ }
128
+ else {
129
+ const resolvedTarget = await this.resolveRelativeReference(target, document.uri, documentContext, data.isRawLink);
130
+ if (resolvedTarget !== undefined) {
131
+ link.target = resolvedTarget;
132
+ resolvedLinks.push(link);
133
+ }
134
+ }
135
+ }
136
+ return resolvedLinks;
137
+ }
138
+ findUnresolvedLinks(document, stylesheet) {
139
+ const result = [];
140
+ const collect = (uriStringNode) => {
141
+ let rawUri = uriStringNode.getText();
142
+ const range = getRange(uriStringNode, document);
143
+ // Make sure the range is not empty
144
+ if (range.start.line === range.end.line && range.start.character === range.end.character) {
145
+ return;
146
+ }
147
+ if ((0, strings_1.startsWith)(rawUri, `'`) || (0, strings_1.startsWith)(rawUri, `"`)) {
148
+ rawUri = rawUri.slice(1, -1);
149
+ }
150
+ const isRawLink = uriStringNode.parent ? this.isRawStringDocumentLinkNode(uriStringNode.parent) : false;
151
+ result.push({ link: { target: rawUri, range }, isRawLink });
152
+ };
153
+ stylesheet.accept(candidate => {
154
+ if (candidate.type === nodes.NodeType.URILiteral) {
155
+ const first = candidate.getChild(0);
156
+ if (first) {
157
+ collect(first);
158
+ }
159
+ return false;
160
+ }
161
+ /**
162
+ * In @import, it is possible to include links that do not use `url()`
163
+ * For example, `@import 'foo.css';`
164
+ */
165
+ if (candidate.parent && this.isRawStringDocumentLinkNode(candidate.parent)) {
166
+ const rawText = candidate.getText();
167
+ if ((0, strings_1.startsWith)(rawText, `'`) || (0, strings_1.startsWith)(rawText, `"`)) {
168
+ collect(candidate);
169
+ }
170
+ return false;
171
+ }
172
+ return true;
173
+ });
174
+ return result;
175
+ }
176
+ findSymbolInformations(document, stylesheet) {
177
+ const result = [];
178
+ const addSymbolInformation = (name, kind, symbolNodeOrRange) => {
179
+ const range = symbolNodeOrRange instanceof nodes.Node ? getRange(symbolNodeOrRange, document) : symbolNodeOrRange;
180
+ const entry = {
181
+ name,
182
+ kind,
183
+ location: cssLanguageTypes_1.Location.create(document.uri, range)
184
+ };
185
+ result.push(entry);
186
+ };
187
+ this.collectDocumentSymbols(document, stylesheet, addSymbolInformation);
188
+ return result;
189
+ }
190
+ findDocumentSymbols(document, stylesheet) {
191
+ const result = [];
192
+ const parents = [];
193
+ const addDocumentSymbol = (name, kind, symbolNodeOrRange, nameNodeOrRange, bodyNode) => {
194
+ const range = symbolNodeOrRange instanceof nodes.Node ? getRange(symbolNodeOrRange, document) : symbolNodeOrRange;
195
+ const selectionRange = (nameNodeOrRange instanceof nodes.Node ? getRange(nameNodeOrRange, document) : nameNodeOrRange) ?? cssLanguageTypes_1.Range.create(range.start, range.start);
196
+ const entry = {
197
+ name,
198
+ kind,
199
+ range,
200
+ selectionRange
201
+ };
202
+ let top = parents.pop();
203
+ while (top && !containsRange(top[1], range)) {
204
+ top = parents.pop();
205
+ }
206
+ if (top) {
207
+ const topSymbol = top[0];
208
+ if (!topSymbol.children) {
209
+ topSymbol.children = [];
210
+ }
211
+ topSymbol.children.push(entry);
212
+ parents.push(top); // put back top
213
+ }
214
+ else {
215
+ result.push(entry);
216
+ }
217
+ if (bodyNode) {
218
+ parents.push([entry, getRange(bodyNode, document)]);
219
+ }
220
+ };
221
+ this.collectDocumentSymbols(document, stylesheet, addDocumentSymbol);
222
+ return result;
223
+ }
224
+ collectDocumentSymbols(document, stylesheet, collect) {
225
+ stylesheet.accept(node => {
226
+ if (node instanceof nodes.RuleSet) {
227
+ for (const selector of node.getSelectors().getChildren()) {
228
+ if (selector instanceof nodes.Selector) {
229
+ const range = cssLanguageTypes_1.Range.create(document.positionAt(selector.offset), document.positionAt(node.end));
230
+ collect(selector.getText(), cssLanguageTypes_1.SymbolKind.Class, range, selector, node.getDeclarations());
231
+ }
232
+ }
233
+ }
234
+ else if (node instanceof nodes.VariableDeclaration) {
235
+ collect(node.getName(), cssLanguageTypes_1.SymbolKind.Variable, node, node.getVariable(), undefined);
236
+ }
237
+ else if (node instanceof nodes.MixinDeclaration) {
238
+ collect(node.getName(), cssLanguageTypes_1.SymbolKind.Method, node, node.getIdentifier(), node.getDeclarations());
239
+ }
240
+ else if (node instanceof nodes.FunctionDeclaration) {
241
+ collect(node.getName(), cssLanguageTypes_1.SymbolKind.Function, node, node.getIdentifier(), node.getDeclarations());
242
+ }
243
+ else if (node instanceof nodes.Keyframe) {
244
+ const name = localize('literal.keyframes', "@keyframes {0}", node.getName());
245
+ collect(name, cssLanguageTypes_1.SymbolKind.Class, node, node.getIdentifier(), node.getDeclarations());
246
+ }
247
+ else if (node instanceof nodes.FontFace) {
248
+ const name = localize('literal.fontface', "@font-face");
249
+ collect(name, cssLanguageTypes_1.SymbolKind.Class, node, undefined, node.getDeclarations());
250
+ }
251
+ else if (node instanceof nodes.Media) {
252
+ const mediaList = node.getChild(0);
253
+ if (mediaList instanceof nodes.Medialist) {
254
+ const name = '@media ' + mediaList.getText();
255
+ collect(name, cssLanguageTypes_1.SymbolKind.Module, node, mediaList, node.getDeclarations());
256
+ }
257
+ }
258
+ return true;
259
+ });
260
+ }
261
+ findDocumentColors(document, stylesheet) {
262
+ const result = [];
263
+ stylesheet.accept((node) => {
264
+ const colorInfo = getColorInformation(node, document);
265
+ if (colorInfo) {
266
+ result.push(colorInfo);
267
+ }
268
+ return true;
269
+ });
270
+ return result;
271
+ }
272
+ getColorPresentations(document, stylesheet, color, range) {
273
+ const result = [];
274
+ const red256 = Math.round(color.red * 255), green256 = Math.round(color.green * 255), blue256 = Math.round(color.blue * 255);
275
+ let label;
276
+ if (color.alpha === 1) {
277
+ label = `rgb(${red256}, ${green256}, ${blue256})`;
278
+ }
279
+ else {
280
+ label = `rgba(${red256}, ${green256}, ${blue256}, ${color.alpha})`;
281
+ }
282
+ result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
283
+ if (color.alpha === 1) {
284
+ label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}`;
285
+ }
286
+ else {
287
+ label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}${toTwoDigitHex(Math.round(color.alpha * 255))}`;
288
+ }
289
+ result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
290
+ const hsl = (0, facts_1.hslFromColor)(color);
291
+ if (hsl.a === 1) {
292
+ label = `hsl(${hsl.h}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%)`;
293
+ }
294
+ else {
295
+ label = `hsla(${hsl.h}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%, ${hsl.a})`;
296
+ }
297
+ result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
298
+ const hwb = (0, facts_1.hwbFromColor)(color);
299
+ if (hwb.a === 1) {
300
+ label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}%)`;
301
+ }
302
+ else {
303
+ label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}% / ${hwb.a})`;
304
+ }
305
+ result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
306
+ return result;
307
+ }
308
+ doRename(document, position, newName, stylesheet) {
309
+ const highlights = this.findDocumentHighlights(document, position, stylesheet);
310
+ const edits = highlights.map(h => cssLanguageTypes_1.TextEdit.replace(h.range, newName));
311
+ return {
312
+ changes: { [document.uri]: edits }
313
+ };
314
+ }
315
+ async resolveModuleReference(ref, documentUri, documentContext) {
316
+ if ((0, strings_1.startsWith)(documentUri, 'file://')) {
317
+ const moduleName = getModuleNameFromPath(ref);
318
+ const rootFolderUri = documentContext.resolveReference('/', documentUri);
319
+ const documentFolderUri = (0, resources_1.dirname)(documentUri);
320
+ const modulePath = await this.resolvePathToModule(moduleName, documentFolderUri, rootFolderUri);
321
+ if (modulePath) {
322
+ const pathWithinModule = ref.substring(moduleName.length + 1);
323
+ return (0, resources_1.joinPath)(modulePath, pathWithinModule);
324
+ }
325
+ }
326
+ return undefined;
327
+ }
328
+ async resolveRelativeReference(ref, documentUri, documentContext, isRawLink) {
329
+ const relativeReference = documentContext.resolveReference(ref, documentUri);
330
+ // Following [css-loader](https://github.com/webpack-contrib/css-loader#url)
331
+ // and [sass-loader's](https://github.com/webpack-contrib/sass-loader#imports)
332
+ // convention, if an import path starts with ~ then use node module resolution
333
+ // *unless* it starts with "~/" as this refers to the user's home directory.
334
+ if (ref[0] === '~' && ref[1] !== '/' && this.fileSystemProvider) {
335
+ ref = ref.substring(1);
336
+ return await this.resolveModuleReference(ref, documentUri, documentContext) || relativeReference;
337
+ }
338
+ // Following [less-loader](https://github.com/webpack-contrib/less-loader#imports)
339
+ // and [sass-loader's](https://github.com/webpack-contrib/sass-loader#resolving-import-at-rules)
340
+ // new resolving import at-rules (~ is deprecated). The loader will first try to resolve @import as a relative path. If it cannot be resolved,
341
+ // then the loader will try to resolve @import inside node_modules.
342
+ if (this.resolveModuleReferences) {
343
+ if (relativeReference && await this.fileExists(relativeReference)) {
344
+ return relativeReference;
345
+ }
346
+ else {
347
+ return await this.resolveModuleReference(ref, documentUri, documentContext) || relativeReference;
348
+ }
349
+ }
350
+ return relativeReference;
351
+ }
352
+ async resolvePathToModule(_moduleName, documentFolderUri, rootFolderUri) {
353
+ // resolve the module relative to the document. We can't use `require` here as the code is webpacked.
354
+ const packPath = (0, resources_1.joinPath)(documentFolderUri, 'node_modules', _moduleName, 'package.json');
355
+ if (await this.fileExists(packPath)) {
356
+ return (0, resources_1.dirname)(packPath);
357
+ }
358
+ else if (rootFolderUri && documentFolderUri.startsWith(rootFolderUri) && (documentFolderUri.length !== rootFolderUri.length)) {
359
+ return this.resolvePathToModule(_moduleName, (0, resources_1.dirname)(documentFolderUri), rootFolderUri);
360
+ }
361
+ return undefined;
362
+ }
363
+ async fileExists(uri) {
364
+ if (!this.fileSystemProvider) {
365
+ return false;
366
+ }
367
+ try {
368
+ const stat = await this.fileSystemProvider.stat(uri);
369
+ if (stat.type === cssLanguageTypes_1.FileType.Unknown && stat.size === -1) {
370
+ return false;
371
+ }
372
+ return true;
373
+ }
374
+ catch (err) {
375
+ return false;
376
+ }
377
+ }
378
+ }
379
+ exports.CSSNavigation = CSSNavigation;
380
+ function getColorInformation(node, document) {
381
+ const color = (0, facts_1.getColorValue)(node);
382
+ if (color) {
383
+ const range = getRange(node, document);
384
+ return { color, range };
385
+ }
386
+ return null;
387
+ }
388
+ function getRange(node, document) {
389
+ return cssLanguageTypes_1.Range.create(document.positionAt(node.offset), document.positionAt(node.end));
390
+ }
391
+ /**
392
+ * Test if `otherRange` is in `range`. If the ranges are equal, will return true.
393
+ */
394
+ function containsRange(range, otherRange) {
395
+ const otherStartLine = otherRange.start.line, otherEndLine = otherRange.end.line;
396
+ const rangeStartLine = range.start.line, rangeEndLine = range.end.line;
397
+ if (otherStartLine < rangeStartLine || otherEndLine < rangeStartLine) {
398
+ return false;
399
+ }
400
+ if (otherStartLine > rangeEndLine || otherEndLine > rangeEndLine) {
401
+ return false;
402
+ }
403
+ if (otherStartLine === rangeStartLine && otherRange.start.character < range.start.character) {
404
+ return false;
405
+ }
406
+ if (otherEndLine === rangeEndLine && otherRange.end.character > range.end.character) {
407
+ return false;
408
+ }
409
+ return true;
410
+ }
411
+ function getHighlightKind(node) {
412
+ if (node.type === nodes.NodeType.Selector) {
413
+ return cssLanguageTypes_1.DocumentHighlightKind.Write;
414
+ }
415
+ if (node instanceof nodes.Identifier) {
416
+ if (node.parent && node.parent instanceof nodes.Property) {
417
+ if (node.isCustomProperty) {
418
+ return cssLanguageTypes_1.DocumentHighlightKind.Write;
419
+ }
420
+ }
421
+ }
422
+ if (node.parent) {
423
+ switch (node.parent.type) {
424
+ case nodes.NodeType.FunctionDeclaration:
425
+ case nodes.NodeType.MixinDeclaration:
426
+ case nodes.NodeType.Keyframe:
427
+ case nodes.NodeType.VariableDeclaration:
428
+ case nodes.NodeType.FunctionParameter:
429
+ return cssLanguageTypes_1.DocumentHighlightKind.Write;
430
+ }
431
+ }
432
+ return cssLanguageTypes_1.DocumentHighlightKind.Read;
433
+ }
434
+ function toTwoDigitHex(n) {
435
+ const r = n.toString(16);
436
+ return r.length !== 2 ? '0' + r : r;
437
+ }
438
+ function getModuleNameFromPath(path) {
439
+ const firstSlash = path.indexOf('/');
440
+ if (firstSlash === -1) {
441
+ return '';
442
+ }
443
+ // If a scoped module (starts with @) then get up until second instance of '/', or to the end of the string for root-level imports.
444
+ if (path[0] === '@') {
445
+ const secondSlash = path.indexOf('/', firstSlash + 1);
446
+ if (secondSlash === -1) {
447
+ return path;
448
+ }
449
+ return path.substring(0, secondSlash);
450
+ }
451
+ // Otherwise get until first instance of '/'
452
+ return path.substring(0, firstSlash);
453
+ }
454
+ });