vscode-css-languageservice 6.3.2 → 6.3.3-1

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.
@@ -126,8 +126,32 @@ export const colorFunctions = [
126
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
127
  desc: l10n.t('Mix two colors together in a polar color space.')
128
128
  },
129
+ {
130
+ label: 'lab',
131
+ func: 'lab($lightness $channel_a $channel_b $alpha)',
132
+ insertText: 'lab(${1:lightness} ${2:a} ${3:b} ${4:alpha})',
133
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Channel a, Channel b and alpha values.')
134
+ },
135
+ {
136
+ label: 'lab relative',
137
+ func: 'lab(from $color $lightness $channel_a $channel_b $alpha)',
138
+ insertText: 'lab(from ${1:color} ${2:lightness} ${3:channel_a} ${4:channel_b} ${5:alpha})',
139
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Channel a, Channel b and alpha values of another Color.')
140
+ },
141
+ {
142
+ label: 'lch',
143
+ func: 'lch($lightness $chrome $hue $alpha)',
144
+ insertText: 'lch(${1:lightness} ${2:chrome} ${3:hue} ${4:alpha})',
145
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Chroma, Hue and alpha values.')
146
+ },
147
+ {
148
+ label: 'lch relative',
149
+ func: 'lch(from $color $lightness $chrome $hue $alpha)',
150
+ insertText: 'lch(from ${1:color} ${2:lightness} ${3:chrome} ${4:hue} ${5:alpha})',
151
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Chroma, Hue and alpha values of another Color.')
152
+ }
129
153
  ];
130
- const colorFunctionNameRegExp = /^(rgb|rgba|hsl|hsla|hwb)$/i;
154
+ const colorFunctionNameRegExp = /^(rgb|rgba|hsl|hsla|hwb|lab|lch)$/i;
131
155
  export const colors = {
132
156
  aliceblue: '#f0f8ff',
133
157
  antiquewhite: '#faebd7',
@@ -284,7 +308,7 @@ export const colorKeywords = {
284
308
  'transparent': 'Fully transparent. This keyword can be considered a shorthand for rgba(0,0,0,0) which is its computed value.',
285
309
  };
286
310
  const colorKeywordsRegExp = new RegExp(`^(${Object.keys(colorKeywords).join('|')})$`, "i");
287
- function getNumericValue(node, factor) {
311
+ function getNumericValue(node, factor, lowerLimit = 0, upperLimit = 1) {
288
312
  const val = node.getText();
289
313
  const m = val.match(/^([-+]?[0-9]*\.?[0-9]+)(%?)$/);
290
314
  if (m) {
@@ -292,7 +316,7 @@ function getNumericValue(node, factor) {
292
316
  factor = 100.0;
293
317
  }
294
318
  const result = parseFloat(m[1]) / factor;
295
- if (result >= 0 && result <= 1) {
319
+ if (result >= lowerLimit && result <= upperLimit) {
296
320
  return result;
297
321
  }
298
322
  }
@@ -511,6 +535,163 @@ export function hwbFromColor(rgba) {
511
535
  a: hsl.a
512
536
  };
513
537
  }
538
+ export function xyzFromLAB(lab) {
539
+ const xyz = {
540
+ x: 0,
541
+ y: 0,
542
+ z: 0,
543
+ alpha: lab.alpha ?? 1
544
+ };
545
+ xyz.y = (lab.l + 16.0) / 116.0;
546
+ xyz.x = (lab.a / 500.0) + xyz.y;
547
+ xyz.z = xyz.y - (lab.b / 200.0);
548
+ let key;
549
+ for (key in xyz) {
550
+ let pow = xyz[key] * xyz[key] * xyz[key];
551
+ if (pow > 0.008856) {
552
+ xyz[key] = pow;
553
+ }
554
+ else {
555
+ xyz[key] = (xyz[key] - 16.0 / 116.0) / 7.787;
556
+ }
557
+ }
558
+ xyz.x = xyz.x * 95.047;
559
+ xyz.y = xyz.y * 100.0;
560
+ xyz.z = xyz.z * 108.883;
561
+ return xyz;
562
+ }
563
+ export function xyzToRGB(xyz) {
564
+ const x = xyz.x / 100;
565
+ const y = xyz.y / 100;
566
+ const z = xyz.z / 100;
567
+ const r = 3.2406254773200533 * x - 1.5372079722103187 * y - 0.4986285986982479 * z;
568
+ const g = -0.9689307147293197 * x + 1.8757560608852415 * y + 0.041517523842953964 * z;
569
+ const b = 0.055710120445510616 * x + -0.2040210505984867 * y + 1.0569959422543882 * z;
570
+ const compand = (c) => {
571
+ return c <= 0.0031308 ?
572
+ 12.92 * c :
573
+ Math.min(1.055 * Math.pow(c, 1 / 2.4) - 0.055, 1);
574
+ };
575
+ return {
576
+ red: Math.round(compand(r) * 255.0),
577
+ blue: Math.round(compand(b) * 255.0),
578
+ green: Math.round(compand(g) * 255.0),
579
+ alpha: xyz.alpha
580
+ };
581
+ }
582
+ export function RGBtoXYZ(rgba) {
583
+ let r = rgba.red, g = rgba.green, b = rgba.blue;
584
+ if (r > 0.04045) {
585
+ r = Math.pow((r + 0.055) / 1.055, 2.4);
586
+ }
587
+ else {
588
+ r = r / 12.92;
589
+ }
590
+ if (g > 0.04045) {
591
+ g = Math.pow((g + 0.055) / 1.055, 2.4);
592
+ }
593
+ else {
594
+ g = g / 12.92;
595
+ }
596
+ if (b > 0.04045) {
597
+ b = Math.pow((b + 0.055) / 1.055, 2.4);
598
+ }
599
+ else {
600
+ b = b / 12.92;
601
+ }
602
+ r = r * 100;
603
+ g = g * 100;
604
+ b = b * 100;
605
+ //Observer = 2°, Illuminant = D65
606
+ const x = r * 0.4124 + g * 0.3576 + b * 0.1805;
607
+ const y = r * 0.2126 + g * 0.7152 + b * 0.0722;
608
+ const z = r * 0.0193 + g * 0.1192 + b * 0.9505;
609
+ return { x, y, z, alpha: rgba.alpha };
610
+ }
611
+ export function XYZtoLAB(xyz, round = true) {
612
+ const ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883;
613
+ let x = xyz.x / ref_X, y = xyz.y / ref_Y, z = xyz.z / ref_Z;
614
+ if (x > 0.008856) {
615
+ x = Math.pow(x, 1 / 3);
616
+ }
617
+ else {
618
+ x = (7.787 * x) + (16 / 116);
619
+ }
620
+ if (y > 0.008856) {
621
+ y = Math.pow(y, 1 / 3);
622
+ }
623
+ else {
624
+ y = (7.787 * y) + (16 / 116);
625
+ }
626
+ if (z > 0.008856) {
627
+ z = Math.pow(z, 1 / 3);
628
+ }
629
+ else {
630
+ z = (7.787 * z) + (16 / 116);
631
+ }
632
+ const l = (116 * y) - 16, a = 500 * (x - y), b = 200 * (y - z);
633
+ if (round) {
634
+ return {
635
+ l: Math.round((l + Number.EPSILON) * 100) / 100,
636
+ a: Math.round((a + Number.EPSILON) * 100) / 100,
637
+ b: Math.round((b + Number.EPSILON) * 100) / 100,
638
+ alpha: xyz.alpha
639
+ };
640
+ }
641
+ else {
642
+ return {
643
+ l, a, b,
644
+ alpha: xyz.alpha
645
+ };
646
+ }
647
+ }
648
+ export function labFromColor(rgba, round = true) {
649
+ const xyz = RGBtoXYZ(rgba);
650
+ const lab = XYZtoLAB(xyz, round);
651
+ return lab;
652
+ }
653
+ export function lchFromColor(rgba) {
654
+ const lab = labFromColor(rgba, false);
655
+ const c = Math.sqrt(Math.pow(lab.a, 2) + Math.pow(lab.b, 2));
656
+ let h = Math.atan2(lab.b, lab.a) * (180 / Math.PI);
657
+ while (h < 0) {
658
+ h = h + 360;
659
+ }
660
+ return {
661
+ l: Math.round((lab.l + Number.EPSILON) * 100) / 100,
662
+ c: Math.round((c + Number.EPSILON) * 100) / 100,
663
+ h: Math.round((h + Number.EPSILON) * 100) / 100,
664
+ alpha: lab.alpha
665
+ };
666
+ }
667
+ export function colorFromLAB(l, a, b, alpha = 1.0) {
668
+ const lab = {
669
+ l,
670
+ a,
671
+ b,
672
+ alpha
673
+ };
674
+ const xyz = xyzFromLAB(lab);
675
+ const rgb = xyzToRGB(xyz);
676
+ return {
677
+ red: (rgb.red >= 0 ? (rgb.red <= 255 ? rgb.red : 255) : 0) / 255.0,
678
+ green: (rgb.green >= 0 ? (rgb.green <= 255 ? rgb.green : 255) : 0) / 255.0,
679
+ blue: (rgb.blue >= 0 ? (rgb.blue <= 255 ? rgb.blue : 255) : 0) / 255.0,
680
+ alpha
681
+ };
682
+ }
683
+ export function labFromLCH(l, c, h, alpha = 1.0) {
684
+ return {
685
+ l: l,
686
+ a: c * Math.cos(h * (Math.PI / 180)),
687
+ b: c * Math.sin(h * (Math.PI / 180)),
688
+ alpha: alpha
689
+ };
690
+ }
691
+ export function colorFromLCH(l, c, h, alpha = 1.0) {
692
+ const lab = labFromLCH(l, c, h, alpha);
693
+ return colorFromLAB(lab.l, lab.a, lab.b, alpha);
694
+ }
514
695
  export function getColorValue(node) {
515
696
  if (node.type === nodes.NodeType.HexColorValue) {
516
697
  const text = node.getText();
@@ -560,6 +741,20 @@ export function getColorValue(node) {
560
741
  const b = getNumericValue(colorValues[2], 100.0);
561
742
  return colorFromHWB(h, w, b, alpha);
562
743
  }
744
+ else if (name === 'lab') {
745
+ // Reference: https://mina86.com/2021/srgb-lab-lchab-conversions/
746
+ const l = getNumericValue(colorValues[0], 100.0);
747
+ // Since these two values can be negative, a lower limit of -1 has been added
748
+ const a = getNumericValue(colorValues[1], 125.0, -1);
749
+ const b = getNumericValue(colorValues[2], 125.0, -1);
750
+ return colorFromLAB(l * 100, a * 125, b * 125, alpha);
751
+ }
752
+ else if (name === 'lch') {
753
+ const l = getNumericValue(colorValues[0], 100.0);
754
+ const c = getNumericValue(colorValues[1], 230.0);
755
+ const h = getAngle(colorValues[2]);
756
+ return colorFromLCH(l * 100, c * 230, h, alpha);
757
+ }
563
758
  }
564
759
  catch (e) {
565
760
  // parse error on numeric value
@@ -99,6 +99,7 @@ export var NodeType;
99
99
  NodeType[NodeType["PropertyAtRule"] = 86] = "PropertyAtRule";
100
100
  NodeType[NodeType["Container"] = 87] = "Container";
101
101
  NodeType[NodeType["ModuleConfig"] = 88] = "ModuleConfig";
102
+ NodeType[NodeType["SelectorList"] = 89] = "SelectorList";
102
103
  })(NodeType || (NodeType = {}));
103
104
  export var ReferenceType;
104
105
  (function (ReferenceType) {
@@ -1510,7 +1510,7 @@ export class Parser {
1510
1510
  if (node) {
1511
1511
  if (!this.hasWhitespace() && this.accept(TokenType.ParenthesisL)) {
1512
1512
  const tryAsSelector = () => {
1513
- const selectors = this.create(nodes.Node);
1513
+ const selectors = this.createNode(nodes.NodeType.SelectorList);
1514
1514
  if (!selectors.addChild(this._parseSelector(true))) {
1515
1515
  return null;
1516
1516
  }
@@ -1524,8 +1524,11 @@ export class Parser {
1524
1524
  };
1525
1525
  let hasSelector = node.addChild(this.try(tryAsSelector));
1526
1526
  if (!hasSelector) {
1527
- if (node.addChild(this._parseBinaryExpr()) &&
1528
- this.acceptIdent('of') &&
1527
+ // accept the <an+b> syntax (not a proper expression) https://drafts.csswg.org/css-syntax/#anb
1528
+ while (!this.peekIdent('of') && (node.addChild(this._parseTerm()) || node.addChild(this._parseOperator()))) {
1529
+ // loop
1530
+ }
1531
+ if (this.acceptIdent('of') &&
1529
1532
  !node.addChild(this.try(tryAsSelector))) {
1530
1533
  return this.finish(node, ParseError.SelectorExpected);
1531
1534
  }
@@ -393,15 +393,21 @@ export class Scanner {
393
393
  return false;
394
394
  }
395
395
  _number() {
396
- let npeek = 0, ch;
397
- if (this.stream.peekChar() === _DOT) {
398
- npeek = 1;
396
+ let npeek = 0;
397
+ let hasDot = false;
398
+ const peekFirst = this.stream.peekChar();
399
+ if (peekFirst === _PLS || peekFirst === _MIN) {
400
+ npeek++;
399
401
  }
400
- ch = this.stream.peekChar(npeek);
402
+ if (this.stream.peekChar(npeek) === _DOT) {
403
+ npeek++;
404
+ hasDot = true;
405
+ }
406
+ const ch = this.stream.peekChar(npeek);
401
407
  if (ch >= _0 && ch <= _9) {
402
408
  this.stream.advance(npeek + 1);
403
409
  this.stream.advanceWhileChar((ch) => {
404
- return ch >= _0 && ch <= _9 || npeek === 0 && ch === _DOT;
410
+ return ch >= _0 && ch <= _9 || !hasDot && ch === _DOT;
405
411
  });
406
412
  return true;
407
413
  }
@@ -7,7 +7,7 @@ import { DocumentHighlightKind, Location, Range, SymbolKind, TextEdit, FileType
7
7
  import * as l10n from '@vscode/l10n';
8
8
  import * as nodes from '../parser/cssNodes';
9
9
  import { Symbols } from '../parser/cssSymbolScope';
10
- import { getColorValue, hslFromColor, hwbFromColor } from '../languageFacts/facts';
10
+ import { getColorValue, hslFromColor, hwbFromColor, labFromColor, lchFromColor } from '../languageFacts/facts';
11
11
  import { startsWith } from '../utils/strings';
12
12
  import { dirname, joinPath } from '../utils/resources';
13
13
  const startsWithSchemeRegex = /^\w+:\/\//;
@@ -304,6 +304,22 @@ export class CSSNavigation {
304
304
  label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}% / ${hwb.a})`;
305
305
  }
306
306
  result.push({ label: label, textEdit: TextEdit.replace(range, label) });
307
+ const lab = labFromColor(color);
308
+ if (lab.alpha === 1) {
309
+ label = `lab(${lab.l}% ${lab.a} ${lab.b})`;
310
+ }
311
+ else {
312
+ label = `lab(${lab.l}% ${lab.a} ${lab.b} / ${lab.alpha})`;
313
+ }
314
+ result.push({ label: label, textEdit: TextEdit.replace(range, label) });
315
+ const lch = lchFromColor(color);
316
+ if (lab.alpha === 1) {
317
+ label = `lch(${lch.l}% ${lch.c} ${lch.h})`;
318
+ }
319
+ else {
320
+ label = `lch(${lch.l}% ${lch.c} ${lch.h} / ${lch.alpha})`;
321
+ }
322
+ result.push({ label: label, textEdit: TextEdit.replace(range, label) });
307
323
  return result;
308
324
  }
309
325
  prepareRename(document, position, stylesheet) {
@@ -423,9 +423,10 @@ export class SelectorPrinting {
423
423
  /* The specificity of the :nth-child(An+B [of S]?) pseudo-class is the specificity of a single pseudo-class plus, if S is specified, the specificity of the most specific complex selector in S */
424
424
  // https://www.w3.org/TR/selectors-4/#the-nth-child-pseudo
425
425
  specificity.attr++;
426
- // 23 = Binary Expression.
427
- if (childElements.length === 3 && childElements[1].type === 23) {
428
- let mostSpecificListItem = calculateMostSpecificListItem(childElements[2].getChildren());
426
+ const lastChild = childElements[childElements.length - 1];
427
+ if (childElements.length > 2 && lastChild.type === nodes.NodeType.SelectorList) {
428
+ // e.g :nth-child(-n+3 of li.important)
429
+ let mostSpecificListItem = calculateMostSpecificListItem(lastChild.getChildren());
429
430
  specificity.id += mostSpecificListItem.id;
430
431
  specificity.attr += mostSpecificListItem.attr;
431
432
  specificity.tag += mostSpecificListItem.tag;
@@ -24,6 +24,15 @@
24
24
  exports.hslFromColor = hslFromColor;
25
25
  exports.colorFromHWB = colorFromHWB;
26
26
  exports.hwbFromColor = hwbFromColor;
27
+ exports.xyzFromLAB = xyzFromLAB;
28
+ exports.xyzToRGB = xyzToRGB;
29
+ exports.RGBtoXYZ = RGBtoXYZ;
30
+ exports.XYZtoLAB = XYZtoLAB;
31
+ exports.labFromColor = labFromColor;
32
+ exports.lchFromColor = lchFromColor;
33
+ exports.colorFromLAB = colorFromLAB;
34
+ exports.labFromLCH = labFromLCH;
35
+ exports.colorFromLCH = colorFromLCH;
27
36
  exports.getColorValue = getColorValue;
28
37
  const nodes = require("../parser/cssNodes");
29
38
  const l10n = require("@vscode/l10n");
@@ -149,8 +158,32 @@
149
158
  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})',
150
159
  desc: l10n.t('Mix two colors together in a polar color space.')
151
160
  },
161
+ {
162
+ label: 'lab',
163
+ func: 'lab($lightness $channel_a $channel_b $alpha)',
164
+ insertText: 'lab(${1:lightness} ${2:a} ${3:b} ${4:alpha})',
165
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Channel a, Channel b and alpha values.')
166
+ },
167
+ {
168
+ label: 'lab relative',
169
+ func: 'lab(from $color $lightness $channel_a $channel_b $alpha)',
170
+ insertText: 'lab(from ${1:color} ${2:lightness} ${3:channel_a} ${4:channel_b} ${5:alpha})',
171
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Channel a, Channel b and alpha values of another Color.')
172
+ },
173
+ {
174
+ label: 'lch',
175
+ func: 'lch($lightness $chrome $hue $alpha)',
176
+ insertText: 'lch(${1:lightness} ${2:chrome} ${3:hue} ${4:alpha})',
177
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Chroma, Hue and alpha values.')
178
+ },
179
+ {
180
+ label: 'lch relative',
181
+ func: 'lch(from $color $lightness $chrome $hue $alpha)',
182
+ insertText: 'lch(from ${1:color} ${2:lightness} ${3:chrome} ${4:hue} ${5:alpha})',
183
+ desc: l10n.t('css.builtin.lab', 'Creates a Color from Lightness, Chroma, Hue and alpha values of another Color.')
184
+ }
152
185
  ];
153
- const colorFunctionNameRegExp = /^(rgb|rgba|hsl|hsla|hwb)$/i;
186
+ const colorFunctionNameRegExp = /^(rgb|rgba|hsl|hsla|hwb|lab|lch)$/i;
154
187
  exports.colors = {
155
188
  aliceblue: '#f0f8ff',
156
189
  antiquewhite: '#faebd7',
@@ -307,7 +340,7 @@
307
340
  'transparent': 'Fully transparent. This keyword can be considered a shorthand for rgba(0,0,0,0) which is its computed value.',
308
341
  };
309
342
  const colorKeywordsRegExp = new RegExp(`^(${Object.keys(exports.colorKeywords).join('|')})$`, "i");
310
- function getNumericValue(node, factor) {
343
+ function getNumericValue(node, factor, lowerLimit = 0, upperLimit = 1) {
311
344
  const val = node.getText();
312
345
  const m = val.match(/^([-+]?[0-9]*\.?[0-9]+)(%?)$/);
313
346
  if (m) {
@@ -315,7 +348,7 @@
315
348
  factor = 100.0;
316
349
  }
317
350
  const result = parseFloat(m[1]) / factor;
318
- if (result >= 0 && result <= 1) {
351
+ if (result >= lowerLimit && result <= upperLimit) {
319
352
  return result;
320
353
  }
321
354
  }
@@ -534,6 +567,163 @@
534
567
  a: hsl.a
535
568
  };
536
569
  }
570
+ function xyzFromLAB(lab) {
571
+ const xyz = {
572
+ x: 0,
573
+ y: 0,
574
+ z: 0,
575
+ alpha: lab.alpha ?? 1
576
+ };
577
+ xyz.y = (lab.l + 16.0) / 116.0;
578
+ xyz.x = (lab.a / 500.0) + xyz.y;
579
+ xyz.z = xyz.y - (lab.b / 200.0);
580
+ let key;
581
+ for (key in xyz) {
582
+ let pow = xyz[key] * xyz[key] * xyz[key];
583
+ if (pow > 0.008856) {
584
+ xyz[key] = pow;
585
+ }
586
+ else {
587
+ xyz[key] = (xyz[key] - 16.0 / 116.0) / 7.787;
588
+ }
589
+ }
590
+ xyz.x = xyz.x * 95.047;
591
+ xyz.y = xyz.y * 100.0;
592
+ xyz.z = xyz.z * 108.883;
593
+ return xyz;
594
+ }
595
+ function xyzToRGB(xyz) {
596
+ const x = xyz.x / 100;
597
+ const y = xyz.y / 100;
598
+ const z = xyz.z / 100;
599
+ const r = 3.2406254773200533 * x - 1.5372079722103187 * y - 0.4986285986982479 * z;
600
+ const g = -0.9689307147293197 * x + 1.8757560608852415 * y + 0.041517523842953964 * z;
601
+ const b = 0.055710120445510616 * x + -0.2040210505984867 * y + 1.0569959422543882 * z;
602
+ const compand = (c) => {
603
+ return c <= 0.0031308 ?
604
+ 12.92 * c :
605
+ Math.min(1.055 * Math.pow(c, 1 / 2.4) - 0.055, 1);
606
+ };
607
+ return {
608
+ red: Math.round(compand(r) * 255.0),
609
+ blue: Math.round(compand(b) * 255.0),
610
+ green: Math.round(compand(g) * 255.0),
611
+ alpha: xyz.alpha
612
+ };
613
+ }
614
+ function RGBtoXYZ(rgba) {
615
+ let r = rgba.red, g = rgba.green, b = rgba.blue;
616
+ if (r > 0.04045) {
617
+ r = Math.pow((r + 0.055) / 1.055, 2.4);
618
+ }
619
+ else {
620
+ r = r / 12.92;
621
+ }
622
+ if (g > 0.04045) {
623
+ g = Math.pow((g + 0.055) / 1.055, 2.4);
624
+ }
625
+ else {
626
+ g = g / 12.92;
627
+ }
628
+ if (b > 0.04045) {
629
+ b = Math.pow((b + 0.055) / 1.055, 2.4);
630
+ }
631
+ else {
632
+ b = b / 12.92;
633
+ }
634
+ r = r * 100;
635
+ g = g * 100;
636
+ b = b * 100;
637
+ //Observer = 2°, Illuminant = D65
638
+ const x = r * 0.4124 + g * 0.3576 + b * 0.1805;
639
+ const y = r * 0.2126 + g * 0.7152 + b * 0.0722;
640
+ const z = r * 0.0193 + g * 0.1192 + b * 0.9505;
641
+ return { x, y, z, alpha: rgba.alpha };
642
+ }
643
+ function XYZtoLAB(xyz, round = true) {
644
+ const ref_X = 95.047, ref_Y = 100.000, ref_Z = 108.883;
645
+ let x = xyz.x / ref_X, y = xyz.y / ref_Y, z = xyz.z / ref_Z;
646
+ if (x > 0.008856) {
647
+ x = Math.pow(x, 1 / 3);
648
+ }
649
+ else {
650
+ x = (7.787 * x) + (16 / 116);
651
+ }
652
+ if (y > 0.008856) {
653
+ y = Math.pow(y, 1 / 3);
654
+ }
655
+ else {
656
+ y = (7.787 * y) + (16 / 116);
657
+ }
658
+ if (z > 0.008856) {
659
+ z = Math.pow(z, 1 / 3);
660
+ }
661
+ else {
662
+ z = (7.787 * z) + (16 / 116);
663
+ }
664
+ const l = (116 * y) - 16, a = 500 * (x - y), b = 200 * (y - z);
665
+ if (round) {
666
+ return {
667
+ l: Math.round((l + Number.EPSILON) * 100) / 100,
668
+ a: Math.round((a + Number.EPSILON) * 100) / 100,
669
+ b: Math.round((b + Number.EPSILON) * 100) / 100,
670
+ alpha: xyz.alpha
671
+ };
672
+ }
673
+ else {
674
+ return {
675
+ l, a, b,
676
+ alpha: xyz.alpha
677
+ };
678
+ }
679
+ }
680
+ function labFromColor(rgba, round = true) {
681
+ const xyz = RGBtoXYZ(rgba);
682
+ const lab = XYZtoLAB(xyz, round);
683
+ return lab;
684
+ }
685
+ function lchFromColor(rgba) {
686
+ const lab = labFromColor(rgba, false);
687
+ const c = Math.sqrt(Math.pow(lab.a, 2) + Math.pow(lab.b, 2));
688
+ let h = Math.atan2(lab.b, lab.a) * (180 / Math.PI);
689
+ while (h < 0) {
690
+ h = h + 360;
691
+ }
692
+ return {
693
+ l: Math.round((lab.l + Number.EPSILON) * 100) / 100,
694
+ c: Math.round((c + Number.EPSILON) * 100) / 100,
695
+ h: Math.round((h + Number.EPSILON) * 100) / 100,
696
+ alpha: lab.alpha
697
+ };
698
+ }
699
+ function colorFromLAB(l, a, b, alpha = 1.0) {
700
+ const lab = {
701
+ l,
702
+ a,
703
+ b,
704
+ alpha
705
+ };
706
+ const xyz = xyzFromLAB(lab);
707
+ const rgb = xyzToRGB(xyz);
708
+ return {
709
+ red: (rgb.red >= 0 ? (rgb.red <= 255 ? rgb.red : 255) : 0) / 255.0,
710
+ green: (rgb.green >= 0 ? (rgb.green <= 255 ? rgb.green : 255) : 0) / 255.0,
711
+ blue: (rgb.blue >= 0 ? (rgb.blue <= 255 ? rgb.blue : 255) : 0) / 255.0,
712
+ alpha
713
+ };
714
+ }
715
+ function labFromLCH(l, c, h, alpha = 1.0) {
716
+ return {
717
+ l: l,
718
+ a: c * Math.cos(h * (Math.PI / 180)),
719
+ b: c * Math.sin(h * (Math.PI / 180)),
720
+ alpha: alpha
721
+ };
722
+ }
723
+ function colorFromLCH(l, c, h, alpha = 1.0) {
724
+ const lab = labFromLCH(l, c, h, alpha);
725
+ return colorFromLAB(lab.l, lab.a, lab.b, alpha);
726
+ }
537
727
  function getColorValue(node) {
538
728
  if (node.type === nodes.NodeType.HexColorValue) {
539
729
  const text = node.getText();
@@ -583,6 +773,20 @@
583
773
  const b = getNumericValue(colorValues[2], 100.0);
584
774
  return colorFromHWB(h, w, b, alpha);
585
775
  }
776
+ else if (name === 'lab') {
777
+ // Reference: https://mina86.com/2021/srgb-lab-lchab-conversions/
778
+ const l = getNumericValue(colorValues[0], 100.0);
779
+ // Since these two values can be negative, a lower limit of -1 has been added
780
+ const a = getNumericValue(colorValues[1], 125.0, -1);
781
+ const b = getNumericValue(colorValues[2], 125.0, -1);
782
+ return colorFromLAB(l * 100, a * 125, b * 125, alpha);
783
+ }
784
+ else if (name === 'lch') {
785
+ const l = getNumericValue(colorValues[0], 100.0);
786
+ const c = getNumericValue(colorValues[1], 230.0);
787
+ const h = getAngle(colorValues[2]);
788
+ return colorFromLCH(l * 100, c * 230, h, alpha);
789
+ }
586
790
  }
587
791
  catch (e) {
588
792
  // parse error on numeric value
@@ -113,6 +113,7 @@
113
113
  NodeType[NodeType["PropertyAtRule"] = 86] = "PropertyAtRule";
114
114
  NodeType[NodeType["Container"] = 87] = "Container";
115
115
  NodeType[NodeType["ModuleConfig"] = 88] = "ModuleConfig";
116
+ NodeType[NodeType["SelectorList"] = 89] = "SelectorList";
116
117
  })(NodeType || (exports.NodeType = NodeType = {}));
117
118
  var ReferenceType;
118
119
  (function (ReferenceType) {
@@ -1521,7 +1521,7 @@
1521
1521
  if (node) {
1522
1522
  if (!this.hasWhitespace() && this.accept(cssScanner_1.TokenType.ParenthesisL)) {
1523
1523
  const tryAsSelector = () => {
1524
- const selectors = this.create(nodes.Node);
1524
+ const selectors = this.createNode(nodes.NodeType.SelectorList);
1525
1525
  if (!selectors.addChild(this._parseSelector(true))) {
1526
1526
  return null;
1527
1527
  }
@@ -1535,8 +1535,11 @@
1535
1535
  };
1536
1536
  let hasSelector = node.addChild(this.try(tryAsSelector));
1537
1537
  if (!hasSelector) {
1538
- if (node.addChild(this._parseBinaryExpr()) &&
1539
- this.acceptIdent('of') &&
1538
+ // accept the <an+b> syntax (not a proper expression) https://drafts.csswg.org/css-syntax/#anb
1539
+ while (!this.peekIdent('of') && (node.addChild(this._parseTerm()) || node.addChild(this._parseOperator()))) {
1540
+ // loop
1541
+ }
1542
+ if (this.acceptIdent('of') &&
1540
1543
  !node.addChild(this.try(tryAsSelector))) {
1541
1544
  return this.finish(node, cssErrors_1.ParseError.SelectorExpected);
1542
1545
  }
@@ -405,15 +405,21 @@
405
405
  return false;
406
406
  }
407
407
  _number() {
408
- let npeek = 0, ch;
409
- if (this.stream.peekChar() === _DOT) {
410
- npeek = 1;
408
+ let npeek = 0;
409
+ let hasDot = false;
410
+ const peekFirst = this.stream.peekChar();
411
+ if (peekFirst === _PLS || peekFirst === _MIN) {
412
+ npeek++;
411
413
  }
412
- ch = this.stream.peekChar(npeek);
414
+ if (this.stream.peekChar(npeek) === _DOT) {
415
+ npeek++;
416
+ hasDot = true;
417
+ }
418
+ const ch = this.stream.peekChar(npeek);
413
419
  if (ch >= _0 && ch <= _9) {
414
420
  this.stream.advance(npeek + 1);
415
421
  this.stream.advanceWhileChar((ch) => {
416
- return ch >= _0 && ch <= _9 || npeek === 0 && ch === _DOT;
422
+ return ch >= _0 && ch <= _9 || !hasDot && ch === _DOT;
417
423
  });
418
424
  return true;
419
425
  }
@@ -316,6 +316,22 @@
316
316
  label = `hwb(${hwb.h} ${Math.round(hwb.w * 100)}% ${Math.round(hwb.b * 100)}% / ${hwb.a})`;
317
317
  }
318
318
  result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
319
+ const lab = (0, facts_1.labFromColor)(color);
320
+ if (lab.alpha === 1) {
321
+ label = `lab(${lab.l}% ${lab.a} ${lab.b})`;
322
+ }
323
+ else {
324
+ label = `lab(${lab.l}% ${lab.a} ${lab.b} / ${lab.alpha})`;
325
+ }
326
+ result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
327
+ const lch = (0, facts_1.lchFromColor)(color);
328
+ if (lab.alpha === 1) {
329
+ label = `lch(${lch.l}% ${lch.c} ${lch.h})`;
330
+ }
331
+ else {
332
+ label = `lch(${lch.l}% ${lch.c} ${lch.h} / ${lch.alpha})`;
333
+ }
334
+ result.push({ label: label, textEdit: cssLanguageTypes_1.TextEdit.replace(range, label) });
319
335
  return result;
320
336
  }
321
337
  prepareRename(document, position, stylesheet) {
@@ -439,9 +439,10 @@
439
439
  /* The specificity of the :nth-child(An+B [of S]?) pseudo-class is the specificity of a single pseudo-class plus, if S is specified, the specificity of the most specific complex selector in S */
440
440
  // https://www.w3.org/TR/selectors-4/#the-nth-child-pseudo
441
441
  specificity.attr++;
442
- // 23 = Binary Expression.
443
- if (childElements.length === 3 && childElements[1].type === 23) {
444
- let mostSpecificListItem = calculateMostSpecificListItem(childElements[2].getChildren());
442
+ const lastChild = childElements[childElements.length - 1];
443
+ if (childElements.length > 2 && lastChild.type === nodes.NodeType.SelectorList) {
444
+ // e.g :nth-child(-n+3 of li.important)
445
+ let mostSpecificListItem = calculateMostSpecificListItem(lastChild.getChildren());
445
446
  specificity.id += mostSpecificListItem.id;
446
447
  specificity.attr += mostSpecificListItem.attr;
447
448
  specificity.tag += mostSpecificListItem.tag;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vscode-css-languageservice",
3
- "version": "6.3.2",
3
+ "version": "6.3.3-1",
4
4
  "description": "Language service for CSS, LESS and SCSS",
5
5
  "main": "./lib/umd/cssLanguageService.js",
6
6
  "typings": "./lib/umd/cssLanguageService",