vscode-css-languageservice 6.3.3-0 → 6.3.3-2

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,8 @@ 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";
103
+ NodeType[NodeType["StartingStyleAtRule"] = 90] = "StartingStyleAtRule";
102
104
  })(NodeType || (NodeType = {}));
103
105
  export var ReferenceType;
104
106
  (function (ReferenceType) {
@@ -910,6 +912,14 @@ export class PropertyAtRule extends BodyDeclaration {
910
912
  return this.name;
911
913
  }
912
914
  }
915
+ export class StartingStyleAtRule extends BodyDeclaration {
916
+ constructor(offset, length) {
917
+ super(offset, length);
918
+ }
919
+ get type() {
920
+ return NodeType.StartingStyleAtRule;
921
+ }
922
+ }
913
923
  export class Document extends BodyDeclaration {
914
924
  constructor(offset, length) {
915
925
  super(offset, length);
@@ -277,6 +277,7 @@ export class Parser {
277
277
  || this._parseNamespace()
278
278
  || this._parseDocument()
279
279
  || this._parseContainer(isNested)
280
+ || this._parseStartingStyleAtRule(isNested)
280
281
  || this._parseUnknownAtRule();
281
282
  }
282
283
  _tryParseRuleset(isNested) {
@@ -311,6 +312,7 @@ export class Parser {
311
312
  || this._parseSupports(true)
312
313
  || this._parseLayer(true)
313
314
  || this._parseContainer(true)
315
+ || this._parseStartingStyleAtRule(true)
314
316
  || this._parseUnknownAtRule();
315
317
  }
316
318
  _parseRuleSetDeclaration() {
@@ -771,6 +773,26 @@ export class Parser {
771
773
  }
772
774
  return this._parseBody(node, this._parseDeclaration.bind(this));
773
775
  }
776
+ _parseStartingStyleAtRule(isNested = false) {
777
+ if (!this.peekKeyword("@starting-style")) {
778
+ return null;
779
+ }
780
+ const node = this.create(nodes.StartingStyleAtRule);
781
+ this.consumeToken(); // @starting-style
782
+ return this._parseBody(node, this._parseStartingStyleDeclaration.bind(this, isNested));
783
+ }
784
+ // this method is the same as ._parseContainerDeclaration()
785
+ // which is the same as ._parseMediaDeclaration(),
786
+ // _parseSupportsDeclaration, and ._parseLayerDeclaration()
787
+ _parseStartingStyleDeclaration(isNested = false) {
788
+ if (isNested) {
789
+ // if nested, the body can contain rulesets, but also declarations
790
+ return this._tryParseRuleset(true)
791
+ || this._tryToParseDeclaration()
792
+ || this._parseStylesheetStatement(true);
793
+ }
794
+ return this._parseStylesheetStatement(false);
795
+ }
774
796
  _parseLayer(isNested = false) {
775
797
  // @layer layer-name {rules}
776
798
  // @layer layer-name;
@@ -1510,7 +1532,7 @@ export class Parser {
1510
1532
  if (node) {
1511
1533
  if (!this.hasWhitespace() && this.accept(TokenType.ParenthesisL)) {
1512
1534
  const tryAsSelector = () => {
1513
- const selectors = this.create(nodes.Node);
1535
+ const selectors = this.createNode(nodes.NodeType.SelectorList);
1514
1536
  if (!selectors.addChild(this._parseSelector(true))) {
1515
1537
  return null;
1516
1538
  }
@@ -1524,8 +1546,11 @@ export class Parser {
1524
1546
  };
1525
1547
  let hasSelector = node.addChild(this.try(tryAsSelector));
1526
1548
  if (!hasSelector) {
1527
- if (node.addChild(this._parseBinaryExpr()) &&
1528
- this.acceptIdent('of') &&
1549
+ // accept the <an+b> syntax (not a proper expression) https://drafts.csswg.org/css-syntax/#anb
1550
+ while (!this.peekIdent('of') && (node.addChild(this._parseTerm()) || node.addChild(this._parseOperator()))) {
1551
+ // loop
1552
+ }
1553
+ if (this.acceptIdent('of') &&
1529
1554
  !node.addChild(this.try(tryAsSelector))) {
1530
1555
  return this.finish(node, ParseError.SelectorExpected);
1531
1556
  }
@@ -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
@@ -13,7 +13,7 @@
13
13
  *--------------------------------------------------------------------------------------------*/
14
14
  'use strict';
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.ParseErrorCollector = exports.Marker = exports.Level = exports.Module = exports.GuardCondition = exports.LessGuard = exports.ListEntry = exports.UnknownAtRule = exports.MixinDeclaration = exports.MixinReference = exports.MixinContentDeclaration = exports.MixinContentReference = exports.ExtendsReference = exports.Variable = exports.Interpolation = exports.VariableDeclaration = exports.NumericValue = exports.RatioValue = exports.HexColorValue = exports.Operator = exports.AttributeSelector = exports.Term = exports.BinaryExpression = exports.Expression = exports.PageBoxMarginBox = exports.Page = exports.SupportsCondition = exports.MediaFeature = exports.MediaCondition = exports.MediaQuery = exports.Medialist = exports.Container = exports.Document = exports.PropertyAtRule = exports.Layer = exports.Supports = exports.Media = exports.Namespace = exports.ForwardVisibility = exports.Forward = exports.ModuleConfiguration = exports.Use = exports.Import = exports.KeyframeSelector = exports.Keyframe = exports.NestedProperties = exports.FontFace = exports.ViewPort = exports.FunctionDeclaration = exports.ElseStatement = exports.WhileStatement = exports.EachStatement = exports.ForStatement = exports.IfStatement = exports.FunctionArgument = exports.FunctionParameter = exports.Function = exports.Invocation = exports.Property = exports.CustomPropertyDeclaration = exports.Declaration = exports.CustomPropertySet = exports.AbstractDeclaration = exports.AtApplyRule = exports.SimpleSelector = exports.Selector = exports.RuleSet = exports.BodyDeclaration = exports.Declarations = exports.Stylesheet = exports.Identifier = exports.UnicodeRange = exports.Nodelist = exports.Node = exports.ReferenceType = exports.NodeType = void 0;
16
+ exports.ParseErrorCollector = exports.Marker = exports.Level = exports.Module = exports.GuardCondition = exports.LessGuard = exports.ListEntry = exports.UnknownAtRule = exports.MixinDeclaration = exports.MixinReference = exports.MixinContentDeclaration = exports.MixinContentReference = exports.ExtendsReference = exports.Variable = exports.Interpolation = exports.VariableDeclaration = exports.NumericValue = exports.RatioValue = exports.HexColorValue = exports.Operator = exports.AttributeSelector = exports.Term = exports.BinaryExpression = exports.Expression = exports.PageBoxMarginBox = exports.Page = exports.SupportsCondition = exports.MediaFeature = exports.MediaCondition = exports.MediaQuery = exports.Medialist = exports.Container = exports.Document = exports.StartingStyleAtRule = exports.PropertyAtRule = exports.Layer = exports.Supports = exports.Media = exports.Namespace = exports.ForwardVisibility = exports.Forward = exports.ModuleConfiguration = exports.Use = exports.Import = exports.KeyframeSelector = exports.Keyframe = exports.NestedProperties = exports.FontFace = exports.ViewPort = exports.FunctionDeclaration = exports.ElseStatement = exports.WhileStatement = exports.EachStatement = exports.ForStatement = exports.IfStatement = exports.FunctionArgument = exports.FunctionParameter = exports.Function = exports.Invocation = exports.Property = exports.CustomPropertyDeclaration = exports.Declaration = exports.CustomPropertySet = exports.AbstractDeclaration = exports.AtApplyRule = exports.SimpleSelector = exports.Selector = exports.RuleSet = exports.BodyDeclaration = exports.Declarations = exports.Stylesheet = exports.Identifier = exports.UnicodeRange = exports.Nodelist = exports.Node = exports.ReferenceType = exports.NodeType = void 0;
17
17
  exports.getNodeAtOffset = getNodeAtOffset;
18
18
  exports.getNodePath = getNodePath;
19
19
  exports.getParentDeclaration = getParentDeclaration;
@@ -113,6 +113,8 @@
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";
117
+ NodeType[NodeType["StartingStyleAtRule"] = 90] = "StartingStyleAtRule";
116
118
  })(NodeType || (exports.NodeType = NodeType = {}));
117
119
  var ReferenceType;
118
120
  (function (ReferenceType) {
@@ -965,6 +967,15 @@
965
967
  }
966
968
  }
967
969
  exports.PropertyAtRule = PropertyAtRule;
970
+ class StartingStyleAtRule extends BodyDeclaration {
971
+ constructor(offset, length) {
972
+ super(offset, length);
973
+ }
974
+ get type() {
975
+ return NodeType.StartingStyleAtRule;
976
+ }
977
+ }
978
+ exports.StartingStyleAtRule = StartingStyleAtRule;
968
979
  class Document extends BodyDeclaration {
969
980
  constructor(offset, length) {
970
981
  super(offset, length);
@@ -288,6 +288,7 @@
288
288
  || this._parseNamespace()
289
289
  || this._parseDocument()
290
290
  || this._parseContainer(isNested)
291
+ || this._parseStartingStyleAtRule(isNested)
291
292
  || this._parseUnknownAtRule();
292
293
  }
293
294
  _tryParseRuleset(isNested) {
@@ -322,6 +323,7 @@
322
323
  || this._parseSupports(true)
323
324
  || this._parseLayer(true)
324
325
  || this._parseContainer(true)
326
+ || this._parseStartingStyleAtRule(true)
325
327
  || this._parseUnknownAtRule();
326
328
  }
327
329
  _parseRuleSetDeclaration() {
@@ -782,6 +784,26 @@
782
784
  }
783
785
  return this._parseBody(node, this._parseDeclaration.bind(this));
784
786
  }
787
+ _parseStartingStyleAtRule(isNested = false) {
788
+ if (!this.peekKeyword("@starting-style")) {
789
+ return null;
790
+ }
791
+ const node = this.create(nodes.StartingStyleAtRule);
792
+ this.consumeToken(); // @starting-style
793
+ return this._parseBody(node, this._parseStartingStyleDeclaration.bind(this, isNested));
794
+ }
795
+ // this method is the same as ._parseContainerDeclaration()
796
+ // which is the same as ._parseMediaDeclaration(),
797
+ // _parseSupportsDeclaration, and ._parseLayerDeclaration()
798
+ _parseStartingStyleDeclaration(isNested = false) {
799
+ if (isNested) {
800
+ // if nested, the body can contain rulesets, but also declarations
801
+ return this._tryParseRuleset(true)
802
+ || this._tryToParseDeclaration()
803
+ || this._parseStylesheetStatement(true);
804
+ }
805
+ return this._parseStylesheetStatement(false);
806
+ }
785
807
  _parseLayer(isNested = false) {
786
808
  // @layer layer-name {rules}
787
809
  // @layer layer-name;
@@ -1521,7 +1543,7 @@
1521
1543
  if (node) {
1522
1544
  if (!this.hasWhitespace() && this.accept(cssScanner_1.TokenType.ParenthesisL)) {
1523
1545
  const tryAsSelector = () => {
1524
- const selectors = this.create(nodes.Node);
1546
+ const selectors = this.createNode(nodes.NodeType.SelectorList);
1525
1547
  if (!selectors.addChild(this._parseSelector(true))) {
1526
1548
  return null;
1527
1549
  }
@@ -1535,8 +1557,11 @@
1535
1557
  };
1536
1558
  let hasSelector = node.addChild(this.try(tryAsSelector));
1537
1559
  if (!hasSelector) {
1538
- if (node.addChild(this._parseBinaryExpr()) &&
1539
- this.acceptIdent('of') &&
1560
+ // accept the <an+b> syntax (not a proper expression) https://drafts.csswg.org/css-syntax/#anb
1561
+ while (!this.peekIdent('of') && (node.addChild(this._parseTerm()) || node.addChild(this._parseOperator()))) {
1562
+ // loop
1563
+ }
1564
+ if (this.acceptIdent('of') &&
1540
1565
  !node.addChild(this.try(tryAsSelector))) {
1541
1566
  return this.finish(node, cssErrors_1.ParseError.SelectorExpected);
1542
1567
  }
@@ -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.3-0",
3
+ "version": "6.3.3-2",
4
4
  "description": "Language service for CSS, LESS and SCSS",
5
5
  "main": "./lib/umd/cssLanguageService.js",
6
6
  "typings": "./lib/umd/cssLanguageService",