vscode-css-languageservice 6.2.5 → 6.2.6

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.
@@ -117,7 +117,7 @@ export const basicShapeFunctions = {
117
117
  'polygon()': 'Defines a polygon.'
118
118
  };
119
119
  export const units = {
120
- 'length': ['cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb', 'dvh', 'dvi', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb', 'lvh', 'lvi', 'lvw', 'mm', 'pc', 'pt', 'px', 'q', 'rem', 'svb', 'svh', 'svi', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'],
120
+ 'length': ['cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb', 'dvh', 'dvi', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb', 'lvh', 'lvi', 'lvw', 'mm', 'pc', 'pt', 'px', 'q', 'rcap', 'rch', 'rem', 'rex', 'ric', 'rlh', 'svb', 'svh', 'svi', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'],
121
121
  'angle': ['deg', 'rad', 'grad', 'turn'],
122
122
  'time': ['ms', 's'],
123
123
  'frequency': ['Hz', 'kHz'],
@@ -4,13 +4,130 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as nodes from '../parser/cssNodes';
6
6
  import * as l10n from '@vscode/l10n';
7
+ const hexColorRegExp = /(^#([0-9A-F]{3}){1,2}$)|(^#([0-9A-F]{4}){1,2}$)/i;
7
8
  export const colorFunctions = [
8
- { func: 'rgb($red, $green, $blue)', desc: l10n.t('Creates a Color from red, green, and blue values.') },
9
- { func: 'rgba($red, $green, $blue, $alpha)', desc: l10n.t('Creates a Color from red, green, blue, and alpha values.') },
10
- { func: 'hsl($hue, $saturation, $lightness)', desc: l10n.t('Creates a Color from hue, saturation, and lightness values.') },
11
- { func: 'hsla($hue, $saturation, $lightness, $alpha)', desc: l10n.t('Creates a Color from hue, saturation, lightness, and alpha values.') },
12
- { func: 'hwb($hue $white $black)', desc: l10n.t('Creates a Color from hue, white and black.') }
9
+ {
10
+ label: 'rgb',
11
+ func: 'rgb($red, $green, $blue)',
12
+ insertText: 'rgb(${1:red}, ${2:green}, ${3:blue})',
13
+ desc: l10n.t('Creates a Color from red, green, and blue values.')
14
+ },
15
+ {
16
+ label: 'rgba',
17
+ func: 'rgba($red, $green, $blue, $alpha)',
18
+ insertText: 'rgba(${1:red}, ${2:green}, ${3:blue}, ${4:alpha})',
19
+ desc: l10n.t('Creates a Color from red, green, blue, and alpha values.')
20
+ },
21
+ {
22
+ label: 'rgb relative',
23
+ func: 'rgb(from $color $red $green $blue)',
24
+ insertText: 'rgb(from ${1:color} ${2:r} ${3:g} ${4:b})',
25
+ desc: l10n.t('Creates a Color from the red, green, and blue values of another Color.')
26
+ },
27
+ {
28
+ label: 'hsl',
29
+ func: 'hsl($hue, $saturation, $lightness)',
30
+ insertText: 'hsl(${1:hue}, ${2:saturation}, ${3:lightness})',
31
+ desc: l10n.t('Creates a Color from hue, saturation, and lightness values.')
32
+ },
33
+ {
34
+ label: 'hsla',
35
+ func: 'hsla($hue, $saturation, $lightness, $alpha)',
36
+ insertText: 'hsla(${1:hue}, ${2:saturation}, ${3:lightness}, ${4:alpha})',
37
+ desc: l10n.t('Creates a Color from hue, saturation, lightness, and alpha values.')
38
+ },
39
+ {
40
+ label: 'hsl relative',
41
+ func: 'hsl(from $color $hue $saturation $lightness)',
42
+ insertText: 'hsl(from ${1:color} ${2:h} ${3:s} ${4:l})',
43
+ desc: l10n.t('Creates a Color from the hue, saturation, and lightness values of another Color.')
44
+ },
45
+ {
46
+ label: 'hwb',
47
+ func: 'hwb($hue $white $black)',
48
+ insertText: 'hwb(${1:hue} ${2:white} ${3:black})',
49
+ desc: l10n.t('Creates a Color from hue, white, and black values.')
50
+ },
51
+ {
52
+ label: 'hwb relative',
53
+ func: 'hwb(from $color $hue $white $black)',
54
+ insertText: 'hwb(from ${1:color} ${2:h} ${3:w} ${4:b})',
55
+ desc: l10n.t('Creates a Color from the hue, white, and black values of another Color.')
56
+ },
57
+ {
58
+ label: 'lab',
59
+ func: 'lab($lightness $a $b)',
60
+ insertText: 'lab(${1:lightness} ${2:a} ${3:b})',
61
+ desc: l10n.t('Creates a Color from lightness, a, and b values.')
62
+ },
63
+ {
64
+ label: 'lab relative',
65
+ func: 'lab(from $color $lightness $a $b)',
66
+ insertText: 'lab(from ${1:color} ${2:l} ${3:a} ${4:b})',
67
+ desc: l10n.t('Creates a Color from the lightness, a, and b values of another Color.')
68
+ },
69
+ {
70
+ label: 'oklab',
71
+ func: 'oklab($lightness $a $b)',
72
+ insertText: 'oklab(${1:lightness} ${2:a} ${3:b})',
73
+ desc: l10n.t('Creates a Color from lightness, a, and b values.')
74
+ },
75
+ {
76
+ label: 'oklab relative',
77
+ func: 'oklab(from $color $lightness $a $b)',
78
+ insertText: 'oklab(from ${1:color} ${2:l} ${3:a} ${4:b})',
79
+ desc: l10n.t('Creates a Color from the lightness, a, and b values of another Color.')
80
+ },
81
+ {
82
+ label: 'lch',
83
+ func: 'lch($lightness $chroma $hue)',
84
+ insertText: 'lch(${1:lightness} ${2:chroma} ${3:hue})',
85
+ desc: l10n.t('Creates a Color from lightness, chroma, and hue values.')
86
+ },
87
+ {
88
+ label: 'lch relative',
89
+ func: 'lch(from $color $lightness $chroma $hue)',
90
+ insertText: 'lch(from ${1:color} ${2:l} ${3:c} ${4:h})',
91
+ desc: l10n.t('Creates a Color from the lightness, chroma, and hue values of another Color.')
92
+ },
93
+ {
94
+ label: 'oklch',
95
+ func: 'oklch($lightness $chroma $hue)',
96
+ insertText: 'oklch(${1:lightness} ${2:chroma} ${3:hue})',
97
+ desc: l10n.t('Creates a Color from lightness, chroma, and hue values.')
98
+ },
99
+ {
100
+ label: 'oklch relative',
101
+ func: 'oklch(from $color $lightness $chroma $hue)',
102
+ insertText: 'oklch(from ${1:color} ${2:l} ${3:c} ${4:h})',
103
+ desc: l10n.t('Creates a Color from the lightness, chroma, and hue values of another Color.')
104
+ },
105
+ {
106
+ label: 'color',
107
+ func: 'color($color-space $red $green $blue)',
108
+ insertText: 'color(${1|srgb,srgb-linear,display-p3,a98-rgb,prophoto-rgb,rec2020,xyx,xyz-d50,xyz-d65|} ${2:red} ${3:green} ${4:blue})',
109
+ desc: l10n.t('Creates a Color in a specific color space from red, green, and blue values.')
110
+ },
111
+ {
112
+ label: 'color relative',
113
+ func: 'color(from $color $color-space $red $green $blue)',
114
+ insertText: 'color(from ${1:color} ${2|srgb,srgb-linear,display-p3,a98-rgb,prophoto-rgb,rec2020,xyx,xyz-d50,xyz-d65|} ${3:r} ${4:g} ${5:b})',
115
+ desc: l10n.t('Creates a Color in a specific color space from the red, green, and blue values of another Color.')
116
+ },
117
+ {
118
+ label: 'color-mix',
119
+ func: 'color-mix(in $color-space, $color $percentage, $color $percentage)',
120
+ insertText: 'color-mix(in ${1|srgb,srgb-linear,lab,oklab,xyz,xyz-d50,xyz-d65|}, ${3:color} ${4:percentage}, ${5:color} ${6:percentage})',
121
+ desc: l10n.t('Mix two colors together in a rectangular color space.')
122
+ },
123
+ {
124
+ label: 'color-mix hue',
125
+ func: 'color-mix(in $color-space $interpolation-method hue, $color $percentage, $color $percentage)',
126
+ insertText: 'color-mix(in ${1|hsl,hwb,lch,oklch|} ${2|shorter hue,longer hue,increasing hue,decreasing hue|}, ${3:color} ${4:percentage}, ${5:color} ${6:percentage})',
127
+ desc: l10n.t('Mix two colors together in a polar color space.')
128
+ },
13
129
  ];
130
+ const colorFunctionNameRegExp = /^(rgb|rgba|hsl|hsla|hwb)$/i;
14
131
  export const colors = {
15
132
  aliceblue: '#f0f8ff',
16
133
  antiquewhite: '#faebd7',
@@ -161,10 +278,12 @@ export const colors = {
161
278
  yellow: '#ffff00',
162
279
  yellowgreen: '#9acd32'
163
280
  };
281
+ const colorsRegExp = new RegExp(`^(${Object.keys(colors).join('|')})$`, "i");
164
282
  export const colorKeywords = {
165
283
  'currentColor': 'The value of the \'color\' property. The computed value of the \'currentColor\' keyword is the computed value of the \'color\' property. If the \'currentColor\' keyword is set on the \'color\' property itself, it is treated as \'color:inherit\' at parse time.',
166
284
  'transparent': 'Fully transparent. This keyword can be considered a shorthand for rgba(0,0,0,0) which is its computed value.',
167
285
  };
286
+ const colorKeywordsRegExp = new RegExp(`^(${Object.keys(colorKeywords).join('|')})$`, "i");
168
287
  function getNumericValue(node, factor) {
169
288
  const val = node.getText();
170
289
  const m = val.match(/^([-+]?[0-9]*\.?[0-9]+)(%?)$/);
@@ -205,7 +324,10 @@ export function isColorConstructor(node) {
205
324
  if (!name) {
206
325
  return false;
207
326
  }
208
- return /^(rgb|rgba|hsl|hsla|hwb)$/gi.test(name);
327
+ return colorFunctionNameRegExp.test(name);
328
+ }
329
+ export function isColorString(s) {
330
+ return hexColorRegExp.test(s) || colorsRegExp.test(s) || colorKeywordsRegExp.test(s);
209
331
  }
210
332
  /**
211
333
  * Returns true if the node is a color value - either
@@ -1197,7 +1197,7 @@ export class MixinContentDeclaration extends BodyDeclaration {
1197
1197
  super(offset, length);
1198
1198
  }
1199
1199
  get type() {
1200
- return NodeType.MixinContentReference;
1200
+ return NodeType.MixinContentDeclaration;
1201
1201
  }
1202
1202
  getParameters() {
1203
1203
  if (!this.parameters) {
@@ -271,7 +271,7 @@ export class Parser {
271
271
  || this._parseFontFace()
272
272
  || this._parseKeyframe()
273
273
  || this._parseSupports(isNested)
274
- || this._parseLayer()
274
+ || this._parseLayer(isNested)
275
275
  || this._parsePropertyAtRule()
276
276
  || this._parseViewPort()
277
277
  || this._parseNamespace()
@@ -306,15 +306,20 @@ export class Parser {
306
306
  return this._parseBody(node, this._parseRuleSetDeclaration.bind(this));
307
307
  }
308
308
  _parseRuleSetDeclarationAtStatement() {
309
- return this._parseUnknownAtRule();
309
+ return this._parseMedia(true)
310
+ || this._parseSupports(true)
311
+ || this._parseLayer(true)
312
+ || this._parseUnknownAtRule();
310
313
  }
311
314
  _parseRuleSetDeclaration() {
312
315
  // https://www.w3.org/TR/css-syntax-3/#consume-a-list-of-declarations
313
316
  if (this.peek(TokenType.AtKeyword)) {
314
317
  return this._parseRuleSetDeclarationAtStatement();
315
318
  }
316
- return (!this.peek(TokenType.Ident) && this._tryParseRuleset(true))
317
- || this._parseDeclaration();
319
+ if (!this.peek(TokenType.Ident)) {
320
+ return this._parseRuleset(true);
321
+ }
322
+ return this._tryParseRuleset(true) || this._parseDeclaration();
318
323
  }
319
324
  _needsSemicolonAfter(node) {
320
325
  switch (node.type) {
@@ -396,9 +401,9 @@ export class Parser {
396
401
  return hasContent ? this.finish(node) : null;
397
402
  }
398
403
  _parseDeclaration(stopTokens) {
399
- const custonProperty = this._tryParseCustomPropertyDeclaration(stopTokens);
400
- if (custonProperty) {
401
- return custonProperty;
404
+ const customProperty = this._tryParseCustomPropertyDeclaration(stopTokens);
405
+ if (customProperty) {
406
+ return customProperty;
402
407
  }
403
408
  const node = this.create(nodes.Declaration);
404
409
  if (!node.setProperty(this._parseProperty())) {
@@ -733,7 +738,7 @@ export class Parser {
733
738
  }
734
739
  return this._parseBody(node, this._parseDeclaration.bind(this));
735
740
  }
736
- _parseLayer() {
741
+ _parseLayer(isNested = false) {
737
742
  // @layer layer-name {rules}
738
743
  // @layer layer-name;
739
744
  // @layer layer-name, layer-name, layer-name;
@@ -748,13 +753,22 @@ export class Parser {
748
753
  node.setNames(names);
749
754
  }
750
755
  if ((!names || names.getChildren().length === 1) && this.peek(TokenType.CurlyL)) {
751
- return this._parseBody(node, this._parseStylesheetStatement.bind(this));
756
+ return this._parseBody(node, this._parseLayerDeclaration.bind(this, isNested));
752
757
  }
753
758
  if (!this.accept(TokenType.SemiColon)) {
754
759
  return this.finish(node, ParseError.SemiColonExpected);
755
760
  }
756
761
  return this.finish(node);
757
762
  }
763
+ _parseLayerDeclaration(isNested = false) {
764
+ if (isNested) {
765
+ // if nested, the body can contain rulesets, but also declarations
766
+ return this._tryParseRuleset(true)
767
+ || this._tryToParseDeclaration()
768
+ || this._parseStylesheetStatement(true);
769
+ }
770
+ return this._parseStylesheetStatement(false);
771
+ }
758
772
  _parseLayerNameList() {
759
773
  const node = this.createNode(nodes.NodeType.LayerNameList);
760
774
  if (!node.addChild(this._parseLayerName())) {
@@ -404,7 +404,7 @@ export class CSSCompletion {
404
404
  kind: CompletionItemKind.Variable,
405
405
  sortText: SortTexts.Variable
406
406
  };
407
- if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
407
+ if (typeof completionItem.documentation === 'string' && languageFacts.isColorString(completionItem.documentation)) {
408
408
  completionItem.kind = CompletionItemKind.Color;
409
409
  }
410
410
  if (symbol.node.type === nodes.NodeType.FunctionParameter) {
@@ -429,7 +429,7 @@ export class CSSCompletion {
429
429
  textEdit: TextEdit.replace(this.getCompletionRange(null), symbol.name),
430
430
  kind: CompletionItemKind.Variable
431
431
  };
432
- if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
432
+ if (typeof completionItem.documentation === 'string' && languageFacts.isColorString(completionItem.documentation)) {
433
433
  completionItem.kind = CompletionItemKind.Color;
434
434
  }
435
435
  result.items.push(completionItem);
@@ -517,14 +517,11 @@ export class CSSCompletion {
517
517
  });
518
518
  }
519
519
  for (const p of languageFacts.colorFunctions) {
520
- let tabStop = 1;
521
- const replaceFunction = (_match, p1) => '${' + tabStop++ + ':' + p1 + '}';
522
- const insertText = p.func.replace(/\[?\$(\w+)\]?/g, replaceFunction);
523
520
  result.items.push({
524
- label: p.func.substr(0, p.func.indexOf('(')),
521
+ label: p.label,
525
522
  detail: p.func,
526
523
  documentation: p.desc,
527
- textEdit: TextEdit.replace(this.getCompletionRange(existingNode), insertText),
524
+ textEdit: TextEdit.replace(this.getCompletionRange(existingNode), p.insertText),
528
525
  insertTextFormat: SnippetFormat,
529
526
  kind: CompletionItemKind.Function
530
527
  });
@@ -1057,7 +1054,3 @@ function getCurrentWord(document, offset) {
1057
1054
  }
1058
1055
  return text.substring(i + 1, offset);
1059
1056
  }
1060
- function isColorString(s) {
1061
- // From https://stackoverflow.com/questions/8027423/how-to-check-if-a-string-is-a-valid-hex-color-representation/8027444
1062
- return (s.toLowerCase() in languageFacts.colors) || /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(s);
1063
- }
@@ -128,7 +128,7 @@
128
128
  'polygon()': 'Defines a polygon.'
129
129
  };
130
130
  exports.units = {
131
- 'length': ['cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb', 'dvh', 'dvi', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb', 'lvh', 'lvi', 'lvw', 'mm', 'pc', 'pt', 'px', 'q', 'rem', 'svb', 'svh', 'svi', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'],
131
+ 'length': ['cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb', 'dvh', 'dvi', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb', 'lvh', 'lvi', 'lvw', 'mm', 'pc', 'pt', 'px', 'q', 'rcap', 'rch', 'rem', 'rex', 'ric', 'rlh', 'svb', 'svh', 'svi', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'],
132
132
  'angle': ['deg', 'rad', 'grad', 'turn'],
133
133
  'time': ['ms', 's'],
134
134
  'frequency': ['Hz', 'kHz'],
@@ -13,16 +13,133 @@
13
13
  })(function (require, exports) {
14
14
  "use strict";
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.getColorValue = exports.hwbFromColor = exports.colorFromHWB = exports.hslFromColor = exports.colorFromHSL = exports.colorFrom256RGB = exports.colorFromHex = exports.hexDigit = exports.isColorValue = exports.isColorConstructor = exports.colorKeywords = exports.colors = exports.colorFunctions = void 0;
16
+ exports.getColorValue = exports.hwbFromColor = exports.colorFromHWB = exports.hslFromColor = exports.colorFromHSL = exports.colorFrom256RGB = exports.colorFromHex = exports.hexDigit = exports.isColorValue = exports.isColorString = exports.isColorConstructor = exports.colorKeywords = exports.colors = exports.colorFunctions = void 0;
17
17
  const nodes = require("../parser/cssNodes");
18
18
  const l10n = require("@vscode/l10n");
19
+ const hexColorRegExp = /(^#([0-9A-F]{3}){1,2}$)|(^#([0-9A-F]{4}){1,2}$)/i;
19
20
  exports.colorFunctions = [
20
- { func: 'rgb($red, $green, $blue)', desc: l10n.t('Creates a Color from red, green, and blue values.') },
21
- { func: 'rgba($red, $green, $blue, $alpha)', desc: l10n.t('Creates a Color from red, green, blue, and alpha values.') },
22
- { func: 'hsl($hue, $saturation, $lightness)', desc: l10n.t('Creates a Color from hue, saturation, and lightness values.') },
23
- { func: 'hsla($hue, $saturation, $lightness, $alpha)', desc: l10n.t('Creates a Color from hue, saturation, lightness, and alpha values.') },
24
- { func: 'hwb($hue $white $black)', desc: l10n.t('Creates a Color from hue, white and black.') }
21
+ {
22
+ label: 'rgb',
23
+ func: 'rgb($red, $green, $blue)',
24
+ insertText: 'rgb(${1:red}, ${2:green}, ${3:blue})',
25
+ desc: l10n.t('Creates a Color from red, green, and blue values.')
26
+ },
27
+ {
28
+ label: 'rgba',
29
+ func: 'rgba($red, $green, $blue, $alpha)',
30
+ insertText: 'rgba(${1:red}, ${2:green}, ${3:blue}, ${4:alpha})',
31
+ desc: l10n.t('Creates a Color from red, green, blue, and alpha values.')
32
+ },
33
+ {
34
+ label: 'rgb relative',
35
+ func: 'rgb(from $color $red $green $blue)',
36
+ insertText: 'rgb(from ${1:color} ${2:r} ${3:g} ${4:b})',
37
+ desc: l10n.t('Creates a Color from the red, green, and blue values of another Color.')
38
+ },
39
+ {
40
+ label: 'hsl',
41
+ func: 'hsl($hue, $saturation, $lightness)',
42
+ insertText: 'hsl(${1:hue}, ${2:saturation}, ${3:lightness})',
43
+ desc: l10n.t('Creates a Color from hue, saturation, and lightness values.')
44
+ },
45
+ {
46
+ label: 'hsla',
47
+ func: 'hsla($hue, $saturation, $lightness, $alpha)',
48
+ insertText: 'hsla(${1:hue}, ${2:saturation}, ${3:lightness}, ${4:alpha})',
49
+ desc: l10n.t('Creates a Color from hue, saturation, lightness, and alpha values.')
50
+ },
51
+ {
52
+ label: 'hsl relative',
53
+ func: 'hsl(from $color $hue $saturation $lightness)',
54
+ insertText: 'hsl(from ${1:color} ${2:h} ${3:s} ${4:l})',
55
+ desc: l10n.t('Creates a Color from the hue, saturation, and lightness values of another Color.')
56
+ },
57
+ {
58
+ label: 'hwb',
59
+ func: 'hwb($hue $white $black)',
60
+ insertText: 'hwb(${1:hue} ${2:white} ${3:black})',
61
+ desc: l10n.t('Creates a Color from hue, white, and black values.')
62
+ },
63
+ {
64
+ label: 'hwb relative',
65
+ func: 'hwb(from $color $hue $white $black)',
66
+ insertText: 'hwb(from ${1:color} ${2:h} ${3:w} ${4:b})',
67
+ desc: l10n.t('Creates a Color from the hue, white, and black values of another Color.')
68
+ },
69
+ {
70
+ label: 'lab',
71
+ func: 'lab($lightness $a $b)',
72
+ insertText: 'lab(${1:lightness} ${2:a} ${3:b})',
73
+ desc: l10n.t('Creates a Color from lightness, a, and b values.')
74
+ },
75
+ {
76
+ label: 'lab relative',
77
+ func: 'lab(from $color $lightness $a $b)',
78
+ insertText: 'lab(from ${1:color} ${2:l} ${3:a} ${4:b})',
79
+ desc: l10n.t('Creates a Color from the lightness, a, and b values of another Color.')
80
+ },
81
+ {
82
+ label: 'oklab',
83
+ func: 'oklab($lightness $a $b)',
84
+ insertText: 'oklab(${1:lightness} ${2:a} ${3:b})',
85
+ desc: l10n.t('Creates a Color from lightness, a, and b values.')
86
+ },
87
+ {
88
+ label: 'oklab relative',
89
+ func: 'oklab(from $color $lightness $a $b)',
90
+ insertText: 'oklab(from ${1:color} ${2:l} ${3:a} ${4:b})',
91
+ desc: l10n.t('Creates a Color from the lightness, a, and b values of another Color.')
92
+ },
93
+ {
94
+ label: 'lch',
95
+ func: 'lch($lightness $chroma $hue)',
96
+ insertText: 'lch(${1:lightness} ${2:chroma} ${3:hue})',
97
+ desc: l10n.t('Creates a Color from lightness, chroma, and hue values.')
98
+ },
99
+ {
100
+ label: 'lch relative',
101
+ func: 'lch(from $color $lightness $chroma $hue)',
102
+ insertText: 'lch(from ${1:color} ${2:l} ${3:c} ${4:h})',
103
+ desc: l10n.t('Creates a Color from the lightness, chroma, and hue values of another Color.')
104
+ },
105
+ {
106
+ label: 'oklch',
107
+ func: 'oklch($lightness $chroma $hue)',
108
+ insertText: 'oklch(${1:lightness} ${2:chroma} ${3:hue})',
109
+ desc: l10n.t('Creates a Color from lightness, chroma, and hue values.')
110
+ },
111
+ {
112
+ label: 'oklch relative',
113
+ func: 'oklch(from $color $lightness $chroma $hue)',
114
+ insertText: 'oklch(from ${1:color} ${2:l} ${3:c} ${4:h})',
115
+ desc: l10n.t('Creates a Color from the lightness, chroma, and hue values of another Color.')
116
+ },
117
+ {
118
+ label: 'color',
119
+ func: 'color($color-space $red $green $blue)',
120
+ insertText: 'color(${1|srgb,srgb-linear,display-p3,a98-rgb,prophoto-rgb,rec2020,xyx,xyz-d50,xyz-d65|} ${2:red} ${3:green} ${4:blue})',
121
+ desc: l10n.t('Creates a Color in a specific color space from red, green, and blue values.')
122
+ },
123
+ {
124
+ label: 'color relative',
125
+ func: 'color(from $color $color-space $red $green $blue)',
126
+ insertText: 'color(from ${1:color} ${2|srgb,srgb-linear,display-p3,a98-rgb,prophoto-rgb,rec2020,xyx,xyz-d50,xyz-d65|} ${3:r} ${4:g} ${5:b})',
127
+ desc: l10n.t('Creates a Color in a specific color space from the red, green, and blue values of another Color.')
128
+ },
129
+ {
130
+ label: 'color-mix',
131
+ func: 'color-mix(in $color-space, $color $percentage, $color $percentage)',
132
+ insertText: 'color-mix(in ${1|srgb,srgb-linear,lab,oklab,xyz,xyz-d50,xyz-d65|}, ${3:color} ${4:percentage}, ${5:color} ${6:percentage})',
133
+ desc: l10n.t('Mix two colors together in a rectangular color space.')
134
+ },
135
+ {
136
+ label: 'color-mix hue',
137
+ func: 'color-mix(in $color-space $interpolation-method hue, $color $percentage, $color $percentage)',
138
+ insertText: 'color-mix(in ${1|hsl,hwb,lch,oklch|} ${2|shorter hue,longer hue,increasing hue,decreasing hue|}, ${3:color} ${4:percentage}, ${5:color} ${6:percentage})',
139
+ desc: l10n.t('Mix two colors together in a polar color space.')
140
+ },
25
141
  ];
142
+ const colorFunctionNameRegExp = /^(rgb|rgba|hsl|hsla|hwb)$/i;
26
143
  exports.colors = {
27
144
  aliceblue: '#f0f8ff',
28
145
  antiquewhite: '#faebd7',
@@ -173,10 +290,12 @@
173
290
  yellow: '#ffff00',
174
291
  yellowgreen: '#9acd32'
175
292
  };
293
+ const colorsRegExp = new RegExp(`^(${Object.keys(exports.colors).join('|')})$`, "i");
176
294
  exports.colorKeywords = {
177
295
  'currentColor': 'The value of the \'color\' property. The computed value of the \'currentColor\' keyword is the computed value of the \'color\' property. If the \'currentColor\' keyword is set on the \'color\' property itself, it is treated as \'color:inherit\' at parse time.',
178
296
  'transparent': 'Fully transparent. This keyword can be considered a shorthand for rgba(0,0,0,0) which is its computed value.',
179
297
  };
298
+ const colorKeywordsRegExp = new RegExp(`^(${Object.keys(exports.colorKeywords).join('|')})$`, "i");
180
299
  function getNumericValue(node, factor) {
181
300
  const val = node.getText();
182
301
  const m = val.match(/^([-+]?[0-9]*\.?[0-9]+)(%?)$/);
@@ -217,9 +336,13 @@
217
336
  if (!name) {
218
337
  return false;
219
338
  }
220
- return /^(rgb|rgba|hsl|hsla|hwb)$/gi.test(name);
339
+ return colorFunctionNameRegExp.test(name);
221
340
  }
222
341
  exports.isColorConstructor = isColorConstructor;
342
+ function isColorString(s) {
343
+ return hexColorRegExp.test(s) || colorsRegExp.test(s) || colorKeywordsRegExp.test(s);
344
+ }
345
+ exports.isColorString = isColorString;
223
346
  /**
224
347
  * Returns true if the node is a color value - either
225
348
  * defined a hex number, as rgb or rgba function, or
@@ -1273,7 +1273,7 @@
1273
1273
  super(offset, length);
1274
1274
  }
1275
1275
  get type() {
1276
- return NodeType.MixinContentReference;
1276
+ return NodeType.MixinContentDeclaration;
1277
1277
  }
1278
1278
  getParameters() {
1279
1279
  if (!this.parameters) {
@@ -282,7 +282,7 @@
282
282
  || this._parseFontFace()
283
283
  || this._parseKeyframe()
284
284
  || this._parseSupports(isNested)
285
- || this._parseLayer()
285
+ || this._parseLayer(isNested)
286
286
  || this._parsePropertyAtRule()
287
287
  || this._parseViewPort()
288
288
  || this._parseNamespace()
@@ -317,15 +317,20 @@
317
317
  return this._parseBody(node, this._parseRuleSetDeclaration.bind(this));
318
318
  }
319
319
  _parseRuleSetDeclarationAtStatement() {
320
- return this._parseUnknownAtRule();
320
+ return this._parseMedia(true)
321
+ || this._parseSupports(true)
322
+ || this._parseLayer(true)
323
+ || this._parseUnknownAtRule();
321
324
  }
322
325
  _parseRuleSetDeclaration() {
323
326
  // https://www.w3.org/TR/css-syntax-3/#consume-a-list-of-declarations
324
327
  if (this.peek(cssScanner_1.TokenType.AtKeyword)) {
325
328
  return this._parseRuleSetDeclarationAtStatement();
326
329
  }
327
- return (!this.peek(cssScanner_1.TokenType.Ident) && this._tryParseRuleset(true))
328
- || this._parseDeclaration();
330
+ if (!this.peek(cssScanner_1.TokenType.Ident)) {
331
+ return this._parseRuleset(true);
332
+ }
333
+ return this._tryParseRuleset(true) || this._parseDeclaration();
329
334
  }
330
335
  _needsSemicolonAfter(node) {
331
336
  switch (node.type) {
@@ -407,9 +412,9 @@
407
412
  return hasContent ? this.finish(node) : null;
408
413
  }
409
414
  _parseDeclaration(stopTokens) {
410
- const custonProperty = this._tryParseCustomPropertyDeclaration(stopTokens);
411
- if (custonProperty) {
412
- return custonProperty;
415
+ const customProperty = this._tryParseCustomPropertyDeclaration(stopTokens);
416
+ if (customProperty) {
417
+ return customProperty;
413
418
  }
414
419
  const node = this.create(nodes.Declaration);
415
420
  if (!node.setProperty(this._parseProperty())) {
@@ -744,7 +749,7 @@
744
749
  }
745
750
  return this._parseBody(node, this._parseDeclaration.bind(this));
746
751
  }
747
- _parseLayer() {
752
+ _parseLayer(isNested = false) {
748
753
  // @layer layer-name {rules}
749
754
  // @layer layer-name;
750
755
  // @layer layer-name, layer-name, layer-name;
@@ -759,13 +764,22 @@
759
764
  node.setNames(names);
760
765
  }
761
766
  if ((!names || names.getChildren().length === 1) && this.peek(cssScanner_1.TokenType.CurlyL)) {
762
- return this._parseBody(node, this._parseStylesheetStatement.bind(this));
767
+ return this._parseBody(node, this._parseLayerDeclaration.bind(this, isNested));
763
768
  }
764
769
  if (!this.accept(cssScanner_1.TokenType.SemiColon)) {
765
770
  return this.finish(node, cssErrors_1.ParseError.SemiColonExpected);
766
771
  }
767
772
  return this.finish(node);
768
773
  }
774
+ _parseLayerDeclaration(isNested = false) {
775
+ if (isNested) {
776
+ // if nested, the body can contain rulesets, but also declarations
777
+ return this._tryParseRuleset(true)
778
+ || this._tryToParseDeclaration()
779
+ || this._parseStylesheetStatement(true);
780
+ }
781
+ return this._parseStylesheetStatement(false);
782
+ }
769
783
  _parseLayerNameList() {
770
784
  const node = this.createNode(nodes.NodeType.LayerNameList);
771
785
  if (!node.addChild(this._parseLayerName())) {
@@ -415,7 +415,7 @@
415
415
  kind: cssLanguageTypes_1.CompletionItemKind.Variable,
416
416
  sortText: SortTexts.Variable
417
417
  };
418
- if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
418
+ if (typeof completionItem.documentation === 'string' && languageFacts.isColorString(completionItem.documentation)) {
419
419
  completionItem.kind = cssLanguageTypes_1.CompletionItemKind.Color;
420
420
  }
421
421
  if (symbol.node.type === nodes.NodeType.FunctionParameter) {
@@ -440,7 +440,7 @@
440
440
  textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(null), symbol.name),
441
441
  kind: cssLanguageTypes_1.CompletionItemKind.Variable
442
442
  };
443
- if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
443
+ if (typeof completionItem.documentation === 'string' && languageFacts.isColorString(completionItem.documentation)) {
444
444
  completionItem.kind = cssLanguageTypes_1.CompletionItemKind.Color;
445
445
  }
446
446
  result.items.push(completionItem);
@@ -528,14 +528,11 @@
528
528
  });
529
529
  }
530
530
  for (const p of languageFacts.colorFunctions) {
531
- let tabStop = 1;
532
- const replaceFunction = (_match, p1) => '${' + tabStop++ + ':' + p1 + '}';
533
- const insertText = p.func.replace(/\[?\$(\w+)\]?/g, replaceFunction);
534
531
  result.items.push({
535
- label: p.func.substr(0, p.func.indexOf('(')),
532
+ label: p.label,
536
533
  detail: p.func,
537
534
  documentation: p.desc,
538
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
535
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), p.insertText),
539
536
  insertTextFormat: SnippetFormat,
540
537
  kind: cssLanguageTypes_1.CompletionItemKind.Function
541
538
  });
@@ -1069,8 +1066,4 @@
1069
1066
  }
1070
1067
  return text.substring(i + 1, offset);
1071
1068
  }
1072
- function isColorString(s) {
1073
- // From https://stackoverflow.com/questions/8027423/how-to-check-if-a-string-is-a-valid-hex-color-representation/8027444
1074
- return (s.toLowerCase() in languageFacts.colors) || /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(s);
1075
- }
1076
1069
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vscode-css-languageservice",
3
- "version": "6.2.5",
3
+ "version": "6.2.6",
4
4
  "description": "Language service for CSS, LESS and SCSS",
5
5
  "main": "./lib/umd/cssLanguageService.js",
6
6
  "typings": "./lib/umd/cssLanguageService",
@@ -17,18 +17,18 @@
17
17
  "devDependencies": {
18
18
  "@types/mocha": "^10.0.1",
19
19
  "@types/node": "16.x",
20
- "@typescript-eslint/eslint-plugin": "^5.59.0",
21
- "@typescript-eslint/parser": "^5.59.0",
20
+ "@typescript-eslint/eslint-plugin": "^5.59.7",
21
+ "@typescript-eslint/parser": "^5.59.7",
22
22
  "@vscode/web-custom-data": "^0.4.6",
23
- "eslint": "^8.39.0",
23
+ "eslint": "^8.41.0",
24
24
  "js-beautify": "^1.14.7",
25
25
  "mocha": "^10.2.0",
26
- "rimraf": "^5.0.0",
26
+ "rimraf": "^5.0.1",
27
27
  "source-map-support": "^0.5.21",
28
28
  "typescript": "^5.0.4"
29
29
  },
30
30
  "dependencies": {
31
- "@vscode/l10n": "^0.0.13",
31
+ "@vscode/l10n": "^0.0.14",
32
32
  "vscode-languageserver-textdocument": "^1.0.8",
33
33
  "vscode-languageserver-types": "^3.17.3",
34
34
  "vscode-uri": "^3.0.7"