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.
- package/lib/esm/languageFacts/colors.js +198 -3
- package/lib/esm/parser/cssNodes.js +10 -0
- package/lib/esm/parser/cssParser.js +28 -3
- package/lib/esm/parser/cssScanner.js +11 -5
- package/lib/esm/services/cssNavigation.js +17 -1
- package/lib/esm/services/selectorPrinting.js +4 -3
- package/lib/umd/languageFacts/colors.js +207 -3
- package/lib/umd/parser/cssNodes.js +12 -1
- package/lib/umd/parser/cssParser.js +28 -3
- package/lib/umd/parser/cssScanner.js +11 -5
- package/lib/umd/services/cssNavigation.js +16 -0
- package/lib/umd/services/selectorPrinting.js +4 -3
- package/package.json +1 -1
|
@@ -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 >=
|
|
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.
|
|
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
|
-
|
|
1528
|
-
|
|
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
|
|
397
|
-
|
|
398
|
-
|
|
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
|
-
|
|
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 ||
|
|
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
|
-
|
|
427
|
-
if (childElements.length
|
|
428
|
-
|
|
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 >=
|
|
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.
|
|
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
|
-
|
|
1539
|
-
|
|
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
|
|
409
|
-
|
|
410
|
-
|
|
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
|
-
|
|
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 ||
|
|
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
|
-
|
|
443
|
-
if (childElements.length
|
|
444
|
-
|
|
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