vscode-css-languageservice 6.2.10 → 6.2.11

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/README.md CHANGED
@@ -39,8 +39,8 @@ Development
39
39
  -----------
40
40
 
41
41
 
42
- - clone this repo, run yarn
43
- - `yarn test` to compile and run tests
42
+ - clone this repo, run `npm install``
43
+ - `npm test` to compile and run tests
44
44
 
45
45
  How can I run and debug the service?
46
46
 
@@ -53,8 +53,8 @@ How can I run and debug the service?
53
53
  How can I run and debug the service inside an instance of VSCode?
54
54
 
55
55
  - run VSCode out of sources setup as described here: https://github.com/Microsoft/vscode/wiki/How-to-Contribute
56
- - run `yarn link` in the folder of `vscode-css-languageservice`
57
- - use `yarn link vscode-css-languageservice` in `vscode/extensions/css-language-features/server` to run VSCode with the latest changes from `vscode-css-languageservice`
56
+ - run `npm link` in the folder of `vscode-css-languageservice`
57
+ - use `npm link vscode-css-languageservice` in `vscode/extensions/css-language-features/server` to run VSCode with the latest changes from `vscode-css-languageservice`
58
58
  - run VSCode out of source (`vscode/scripts/code.sh|bat`) and open a `.css` file
59
59
  - in VSCode window that is open on the `vscode-css-languageservice` sources, run command `Debug: Attach to Node process` and pick the `code-oss` process with the `css-language-features` path
60
60
  ![image](https://user-images.githubusercontent.com/6461412/94242567-842b1200-ff16-11ea-8f85-3ebb72d06ba8.png)
@@ -1,5 +1,5 @@
1
1
  // copied from js-beautify/js/lib/beautify-css.js
2
- // version: 1.14.9
2
+ // version: 1.14.11
3
3
  /* AUTO-GENERATED. DO NOT MODIFY. */
4
4
  /*
5
5
 
@@ -1280,13 +1280,11 @@ Beautifier.prototype.beautify = function() {
1280
1280
 
1281
1281
  if (variable.match(/[ :]$/)) {
1282
1282
  // we have a variable or pseudo-class, add it and insert one space before continuing
1283
- variable = this.eatString(": ").replace(/\s$/, '');
1283
+ variable = this.eatString(": ").replace(/\s+$/, '');
1284
1284
  this.print_string(variable);
1285
1285
  this._output.space_before_token = true;
1286
1286
  }
1287
1287
 
1288
- variable = variable.replace(/\s$/, '');
1289
-
1290
1288
  // might be sass variable
1291
1289
  if (parenLevel === 0 && variable.indexOf(':') !== -1) {
1292
1290
  insidePropertyValue = true;
@@ -1306,13 +1304,11 @@ Beautifier.prototype.beautify = function() {
1306
1304
 
1307
1305
  if (variableOrRule.match(/[ :]$/)) {
1308
1306
  // we have a variable or pseudo-class, add it and insert one space before continuing
1309
- variableOrRule = this.eatString(": ").replace(/\s$/, '');
1307
+ variableOrRule = this.eatString(": ").replace(/\s+$/, '');
1310
1308
  this.print_string(variableOrRule);
1311
1309
  this._output.space_before_token = true;
1312
1310
  }
1313
1311
 
1314
- variableOrRule = variableOrRule.replace(/\s$/, '');
1315
-
1316
1312
  // might be less variable
1317
1313
  if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
1318
1314
  insidePropertyValue = true;
@@ -33,6 +33,7 @@ function createFacade(parser, completion, hover, navigation, codeActions, valida
33
33
  validation.configure(settings);
34
34
  completion.configure(settings?.completion);
35
35
  hover.configure(settings?.hover);
36
+ navigation.configure(settings?.importAliases);
36
37
  },
37
38
  setDataProviders: cssDataManager.setDataProviders.bind(cssDataManager),
38
39
  doValidation: validation.doValidation.bind(validation),
@@ -13,6 +13,10 @@ export interface LanguageSettings {
13
13
  lint?: LintSettings;
14
14
  completion?: CompletionSettings;
15
15
  hover?: HoverSettings;
16
+ importAliases?: AliasSettings;
17
+ }
18
+ export interface AliasSettings {
19
+ [key: string]: string;
16
20
  }
17
21
  export interface HoverSettings {
18
22
  documentation?: boolean;
@@ -616,6 +616,9 @@ export class Parser {
616
616
  if (!node.addChild(this._parseURILiteral()) && !node.addChild(this._parseStringLiteral())) {
617
617
  return this.finish(node, ParseError.URIOrStringExpected);
618
618
  }
619
+ return this._completeParseImport(node);
620
+ }
621
+ _completeParseImport(node) {
619
622
  if (this.acceptIdent('layer')) {
620
623
  if (this.accept(TokenType.ParenthesisL)) {
621
624
  if (!node.addChild(this._parseLayerName())) {
@@ -812,11 +815,10 @@ export class Parser {
812
815
  }
813
816
  _parseLayerName() {
814
817
  // <layer-name> = <ident> [ '.' <ident> ]*
815
- if (!this.peek(TokenType.Ident)) {
818
+ const node = this.createNode(nodes.NodeType.LayerName);
819
+ if (!node.addChild(this._parseIdent())) {
816
820
  return null;
817
821
  }
818
- const node = this.createNode(nodes.NodeType.LayerName);
819
- node.addChild(this._parseIdent());
820
822
  while (!this.hasWhitespace() && this.acceptDelim('.')) {
821
823
  if (this.hasWhitespace() || !node.addChild(this._parseIdent())) {
822
824
  return this.finish(node, ParseError.IdentifierExpected);
@@ -47,8 +47,8 @@ export var TokenType;
47
47
  TokenType[TokenType["Comment"] = 39] = "Comment";
48
48
  TokenType[TokenType["SingleLineComment"] = 40] = "SingleLineComment";
49
49
  TokenType[TokenType["EOF"] = 41] = "EOF";
50
- TokenType[TokenType["CustomToken"] = 42] = "CustomToken";
51
- TokenType[TokenType["ContainerQueryLength"] = 43] = "ContainerQueryLength";
50
+ TokenType[TokenType["ContainerQueryLength"] = 42] = "ContainerQueryLength";
51
+ TokenType[TokenType["CustomToken"] = 43] = "CustomToken"; // must be last token type
52
52
  })(TokenType || (TokenType = {}));
53
53
  export class MultiLineStream {
54
54
  constructor(source) {
@@ -53,7 +53,7 @@ export class LESSParser extends cssParser.Parser {
53
53
  if (!this.peek(TokenType.SemiColon) && !this.peek(TokenType.EOF)) {
54
54
  node.setMedialist(this._parseMediaQueryList());
55
55
  }
56
- return this.finish(node);
56
+ return this._completeParseImport(node);
57
57
  }
58
58
  _parsePlugin() {
59
59
  if (!this.peekKeyword('@plugin')) {
@@ -46,10 +46,7 @@ export class SCSSParser extends cssParser.Parser {
46
46
  return this.finish(node, ParseError.URIOrStringExpected);
47
47
  }
48
48
  }
49
- if (!this.peek(TokenType.SemiColon) && !this.peek(TokenType.EOF)) {
50
- node.setMedialist(this._parseMediaQueryList());
51
- }
52
- return this.finish(node);
49
+ return this._completeParseImport(node);
53
50
  }
54
51
  // scss variables: $font-size: 12px;
55
52
  _parseVariableDeclaration(panic = []) {
@@ -101,6 +98,9 @@ export class SCSSParser extends cssParser.Parser {
101
98
  _parseKeyframeSelector() {
102
99
  return this._tryParseKeyframeSelector()
103
100
  || this._parseControlStatement(this._parseKeyframeSelector.bind(this))
101
+ || this._parseWarnAndDebug() // @warn, @debug and @error statements
102
+ || this._parseMixinReference() // @include
103
+ || this._parseFunctionDeclaration() // @function
104
104
  || this._parseVariableDeclaration()
105
105
  || this._parseMixinContent();
106
106
  }
@@ -17,6 +17,9 @@ export class CSSNavigation {
17
17
  this.fileSystemProvider = fileSystemProvider;
18
18
  this.resolveModuleReferences = resolveModuleReferences;
19
19
  }
20
+ configure(settings) {
21
+ this.defaultSettings = settings;
22
+ }
20
23
  findDefinition(document, position, stylesheet) {
21
24
  const symbols = new Symbols(stylesheet);
22
25
  const offset = document.offsetAt(position);
@@ -334,7 +337,7 @@ export class CSSNavigation {
334
337
  async mapReference(target, isRawLink) {
335
338
  return target;
336
339
  }
337
- async resolveReference(target, documentUri, documentContext, isRawLink = false) {
340
+ async resolveReference(target, documentUri, documentContext, isRawLink = false, settings = this.defaultSettings) {
338
341
  // Following [css-loader](https://github.com/webpack-contrib/css-loader#url)
339
342
  // and [sass-loader's](https://github.com/webpack-contrib/sass-loader#imports)
340
343
  // convention, if an import path starts with ~ then use node module resolution
@@ -357,6 +360,24 @@ export class CSSNavigation {
357
360
  return moduleReference;
358
361
  }
359
362
  }
363
+ // Try resolving the reference from the language configuration alias settings
364
+ if (ref && !(await this.fileExists(ref))) {
365
+ const rootFolderUri = documentContext.resolveReference('/', documentUri);
366
+ if (settings && rootFolderUri) {
367
+ // Specific file reference
368
+ if (target in settings) {
369
+ return this.mapReference(joinPath(rootFolderUri, settings[target]), isRawLink);
370
+ }
371
+ // Reference folder
372
+ const firstSlash = target.indexOf('/');
373
+ const prefix = `${target.substring(0, firstSlash)}/`;
374
+ if (prefix in settings) {
375
+ const aliasPath = (settings[prefix]).slice(0, -1);
376
+ let newPath = joinPath(rootFolderUri, aliasPath);
377
+ return this.mapReference(newPath = joinPath(newPath, target.substring(prefix.length - 1)), isRawLink);
378
+ }
379
+ }
380
+ }
360
381
  // fall back. it might not exists
361
382
  return ref;
362
383
  }
@@ -35,15 +35,15 @@ export class SCSSNavigation extends CSSNavigation {
35
35
  }
36
36
  }
37
37
  function toPathVariations(target) {
38
- // No variation for links that ends with suffix
39
- if (target.endsWith('.scss') || target.endsWith('.css')) {
38
+ // No variation for links that ends with .css suffix
39
+ if (target.endsWith('.css')) {
40
40
  return [target];
41
41
  }
42
42
  // If a link is like a/, try resolving a/index.scss and a/_index.scss
43
43
  if (target.endsWith('/')) {
44
44
  return [target + 'index.scss', target + '_index.scss'];
45
45
  }
46
- const targetUri = URI.parse(target);
46
+ const targetUri = URI.parse(target.replace(/\.scss$/, ''));
47
47
  const basename = Utils.basename(targetUri);
48
48
  const dirname = Utils.dirname(targetUri);
49
49
  if (basename.startsWith('_')) {
@@ -6,6 +6,7 @@
6
6
  import * as nodes from '../parser/cssNodes';
7
7
  import { Scanner } from '../parser/cssScanner';
8
8
  import * as l10n from '@vscode/l10n';
9
+ import { Parser } from '../parser/cssParser';
9
10
  export class Element {
10
11
  constructor() {
11
12
  this.parent = null;
@@ -402,10 +403,9 @@ export class SelectorPrinting {
402
403
  specificity.tag += mostSpecificListItem.tag;
403
404
  continue elementLoop;
404
405
  }
405
- if (text.match(/^:(?:nth-child|nth-last-child|host|host-context)/i) && childElements.length > 0) {
406
+ if (text.match(/^:(?:host|host-context)/i) && childElements.length > 0) {
406
407
  // The specificity of :host() is that of a pseudo-class, plus the specificity of its argument.
407
408
  // The specificity of :host-context() is that of a pseudo-class, plus the specificity of its argument.
408
- // The specificity of an :nth-child() or :nth-last-child() selector is the specificity of the pseudo class itself (counting as one pseudo-class selector) plus the specificity of the most specific complex selector in its selector list argument.
409
409
  specificity.attr++;
410
410
  let mostSpecificListItem = calculateMostSpecificListItem(childElements);
411
411
  specificity.id += mostSpecificListItem.id;
@@ -413,6 +413,42 @@ export class SelectorPrinting {
413
413
  specificity.tag += mostSpecificListItem.tag;
414
414
  continue elementLoop;
415
415
  }
416
+ if (text.match(/^:(?:nth-child|nth-last-child)/i) && childElements.length > 0) {
417
+ /* 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 */
418
+ // https://www.w3.org/TR/selectors-4/#the-nth-child-pseudo
419
+ specificity.attr++;
420
+ // 23 = Binary Expression.
421
+ if (childElements.length === 3 && childElements[1].type === 23) {
422
+ let mostSpecificListItem = calculateMostSpecificListItem(childElements[2].getChildren());
423
+ specificity.id += mostSpecificListItem.id;
424
+ specificity.attr += mostSpecificListItem.attr;
425
+ specificity.tag += mostSpecificListItem.tag;
426
+ continue elementLoop;
427
+ }
428
+ // Edge case: 'n' without integer prefix A, with B integer non-existent, is not regarded as a binary expression token.
429
+ const parser = new Parser();
430
+ const pseudoSelectorText = childElements[1].getText();
431
+ parser.scanner.setSource(pseudoSelectorText);
432
+ const firstToken = parser.scanner.scan();
433
+ const secondToken = parser.scanner.scan();
434
+ if (firstToken.text === 'n' || firstToken.text === '-n' && secondToken.text === 'of') {
435
+ const complexSelectorListNodes = [];
436
+ const complexSelectorText = pseudoSelectorText.slice(secondToken.offset + 2);
437
+ const complexSelectorArray = complexSelectorText.split(',');
438
+ for (const selector of complexSelectorArray) {
439
+ const node = parser.internalParse(selector, parser._parseSelector);
440
+ if (node) {
441
+ complexSelectorListNodes.push(node);
442
+ }
443
+ }
444
+ let mostSpecificListItem = calculateMostSpecificListItem(complexSelectorListNodes);
445
+ specificity.id += mostSpecificListItem.id;
446
+ specificity.attr += mostSpecificListItem.attr;
447
+ specificity.tag += mostSpecificListItem.tag;
448
+ continue elementLoop;
449
+ }
450
+ continue elementLoop;
451
+ }
416
452
  specificity.attr++; //pseudo class
417
453
  continue elementLoop;
418
454
  }
@@ -1,5 +1,5 @@
1
1
  // copied from js-beautify/js/lib/beautify-css.js
2
- // version: 1.14.9
2
+ // version: 1.14.11
3
3
  /* AUTO-GENERATED. DO NOT MODIFY. */
4
4
  /*
5
5
 
@@ -1283,13 +1283,11 @@ Beautifier.prototype.beautify = function() {
1283
1283
 
1284
1284
  if (variable.match(/[ :]$/)) {
1285
1285
  // we have a variable or pseudo-class, add it and insert one space before continuing
1286
- variable = this.eatString(": ").replace(/\s$/, '');
1286
+ variable = this.eatString(": ").replace(/\s+$/, '');
1287
1287
  this.print_string(variable);
1288
1288
  this._output.space_before_token = true;
1289
1289
  }
1290
1290
 
1291
- variable = variable.replace(/\s$/, '');
1292
-
1293
1291
  // might be sass variable
1294
1292
  if (parenLevel === 0 && variable.indexOf(':') !== -1) {
1295
1293
  insidePropertyValue = true;
@@ -1309,13 +1307,11 @@ Beautifier.prototype.beautify = function() {
1309
1307
 
1310
1308
  if (variableOrRule.match(/[ :]$/)) {
1311
1309
  // we have a variable or pseudo-class, add it and insert one space before continuing
1312
- variableOrRule = this.eatString(": ").replace(/\s$/, '');
1310
+ variableOrRule = this.eatString(": ").replace(/\s+$/, '');
1313
1311
  this.print_string(variableOrRule);
1314
1312
  this._output.space_before_token = true;
1315
1313
  }
1316
1314
 
1317
- variableOrRule = variableOrRule.replace(/\s$/, '');
1318
-
1319
1315
  // might be less variable
1320
1316
  if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
1321
1317
  insidePropertyValue = true;
@@ -60,6 +60,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
60
60
  validation.configure(settings);
61
61
  completion.configure(settings?.completion);
62
62
  hover.configure(settings?.hover);
63
+ navigation.configure(settings?.importAliases);
63
64
  },
64
65
  setDataProviders: cssDataManager.setDataProviders.bind(cssDataManager),
65
66
  doValidation: validation.doValidation.bind(validation),
@@ -13,6 +13,10 @@ export interface LanguageSettings {
13
13
  lint?: LintSettings;
14
14
  completion?: CompletionSettings;
15
15
  hover?: HoverSettings;
16
+ importAliases?: AliasSettings;
17
+ }
18
+ export interface AliasSettings {
19
+ [key: string]: string;
16
20
  }
17
21
  export interface HoverSettings {
18
22
  documentation?: boolean;
@@ -627,6 +627,9 @@
627
627
  if (!node.addChild(this._parseURILiteral()) && !node.addChild(this._parseStringLiteral())) {
628
628
  return this.finish(node, cssErrors_1.ParseError.URIOrStringExpected);
629
629
  }
630
+ return this._completeParseImport(node);
631
+ }
632
+ _completeParseImport(node) {
630
633
  if (this.acceptIdent('layer')) {
631
634
  if (this.accept(cssScanner_1.TokenType.ParenthesisL)) {
632
635
  if (!node.addChild(this._parseLayerName())) {
@@ -823,11 +826,10 @@
823
826
  }
824
827
  _parseLayerName() {
825
828
  // <layer-name> = <ident> [ '.' <ident> ]*
826
- if (!this.peek(cssScanner_1.TokenType.Ident)) {
829
+ const node = this.createNode(nodes.NodeType.LayerName);
830
+ if (!node.addChild(this._parseIdent())) {
827
831
  return null;
828
832
  }
829
- const node = this.createNode(nodes.NodeType.LayerName);
830
- node.addChild(this._parseIdent());
831
833
  while (!this.hasWhitespace() && this.acceptDelim('.')) {
832
834
  if (this.hasWhitespace() || !node.addChild(this._parseIdent())) {
833
835
  return this.finish(node, cssErrors_1.ParseError.IdentifierExpected);
@@ -58,8 +58,8 @@
58
58
  TokenType[TokenType["Comment"] = 39] = "Comment";
59
59
  TokenType[TokenType["SingleLineComment"] = 40] = "SingleLineComment";
60
60
  TokenType[TokenType["EOF"] = 41] = "EOF";
61
- TokenType[TokenType["CustomToken"] = 42] = "CustomToken";
62
- TokenType[TokenType["ContainerQueryLength"] = 43] = "ContainerQueryLength";
61
+ TokenType[TokenType["ContainerQueryLength"] = 42] = "ContainerQueryLength";
62
+ TokenType[TokenType["CustomToken"] = 43] = "CustomToken"; // must be last token type
63
63
  })(TokenType || (exports.TokenType = TokenType = {}));
64
64
  class MultiLineStream {
65
65
  constructor(source) {
@@ -64,7 +64,7 @@
64
64
  if (!this.peek(cssScanner_1.TokenType.SemiColon) && !this.peek(cssScanner_1.TokenType.EOF)) {
65
65
  node.setMedialist(this._parseMediaQueryList());
66
66
  }
67
- return this.finish(node);
67
+ return this._completeParseImport(node);
68
68
  }
69
69
  _parsePlugin() {
70
70
  if (!this.peekKeyword('@plugin')) {
@@ -57,10 +57,7 @@
57
57
  return this.finish(node, cssErrors_1.ParseError.URIOrStringExpected);
58
58
  }
59
59
  }
60
- if (!this.peek(cssScanner_1.TokenType.SemiColon) && !this.peek(cssScanner_1.TokenType.EOF)) {
61
- node.setMedialist(this._parseMediaQueryList());
62
- }
63
- return this.finish(node);
60
+ return this._completeParseImport(node);
64
61
  }
65
62
  // scss variables: $font-size: 12px;
66
63
  _parseVariableDeclaration(panic = []) {
@@ -112,6 +109,9 @@
112
109
  _parseKeyframeSelector() {
113
110
  return this._tryParseKeyframeSelector()
114
111
  || this._parseControlStatement(this._parseKeyframeSelector.bind(this))
112
+ || this._parseWarnAndDebug() // @warn, @debug and @error statements
113
+ || this._parseMixinReference() // @include
114
+ || this._parseFunctionDeclaration() // @function
115
115
  || this._parseVariableDeclaration()
116
116
  || this._parseMixinContent();
117
117
  }
@@ -28,6 +28,9 @@
28
28
  this.fileSystemProvider = fileSystemProvider;
29
29
  this.resolveModuleReferences = resolveModuleReferences;
30
30
  }
31
+ configure(settings) {
32
+ this.defaultSettings = settings;
33
+ }
31
34
  findDefinition(document, position, stylesheet) {
32
35
  const symbols = new cssSymbolScope_1.Symbols(stylesheet);
33
36
  const offset = document.offsetAt(position);
@@ -345,7 +348,7 @@
345
348
  async mapReference(target, isRawLink) {
346
349
  return target;
347
350
  }
348
- async resolveReference(target, documentUri, documentContext, isRawLink = false) {
351
+ async resolveReference(target, documentUri, documentContext, isRawLink = false, settings = this.defaultSettings) {
349
352
  // Following [css-loader](https://github.com/webpack-contrib/css-loader#url)
350
353
  // and [sass-loader's](https://github.com/webpack-contrib/sass-loader#imports)
351
354
  // convention, if an import path starts with ~ then use node module resolution
@@ -368,6 +371,24 @@
368
371
  return moduleReference;
369
372
  }
370
373
  }
374
+ // Try resolving the reference from the language configuration alias settings
375
+ if (ref && !(await this.fileExists(ref))) {
376
+ const rootFolderUri = documentContext.resolveReference('/', documentUri);
377
+ if (settings && rootFolderUri) {
378
+ // Specific file reference
379
+ if (target in settings) {
380
+ return this.mapReference((0, resources_1.joinPath)(rootFolderUri, settings[target]), isRawLink);
381
+ }
382
+ // Reference folder
383
+ const firstSlash = target.indexOf('/');
384
+ const prefix = `${target.substring(0, firstSlash)}/`;
385
+ if (prefix in settings) {
386
+ const aliasPath = (settings[prefix]).slice(0, -1);
387
+ let newPath = (0, resources_1.joinPath)(rootFolderUri, aliasPath);
388
+ return this.mapReference(newPath = (0, resources_1.joinPath)(newPath, target.substring(prefix.length - 1)), isRawLink);
389
+ }
390
+ }
391
+ }
371
392
  // fall back. it might not exists
372
393
  return ref;
373
394
  }
@@ -47,15 +47,15 @@
47
47
  }
48
48
  exports.SCSSNavigation = SCSSNavigation;
49
49
  function toPathVariations(target) {
50
- // No variation for links that ends with suffix
51
- if (target.endsWith('.scss') || target.endsWith('.css')) {
50
+ // No variation for links that ends with .css suffix
51
+ if (target.endsWith('.css')) {
52
52
  return [target];
53
53
  }
54
54
  // If a link is like a/, try resolving a/index.scss and a/_index.scss
55
55
  if (target.endsWith('/')) {
56
56
  return [target + 'index.scss', target + '_index.scss'];
57
57
  }
58
- const targetUri = vscode_uri_1.URI.parse(target);
58
+ const targetUri = vscode_uri_1.URI.parse(target.replace(/\.scss$/, ''));
59
59
  const basename = vscode_uri_1.Utils.basename(targetUri);
60
60
  const dirname = vscode_uri_1.Utils.dirname(targetUri);
61
61
  if (basename.startsWith('_')) {
@@ -4,7 +4,7 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "../parser/cssNodes", "../parser/cssScanner", "@vscode/l10n"], factory);
7
+ define(["require", "exports", "../parser/cssNodes", "../parser/cssScanner", "@vscode/l10n", "../parser/cssParser"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  /*---------------------------------------------------------------------------------------------
@@ -17,6 +17,7 @@
17
17
  const nodes = require("../parser/cssNodes");
18
18
  const cssScanner_1 = require("../parser/cssScanner");
19
19
  const l10n = require("@vscode/l10n");
20
+ const cssParser_1 = require("../parser/cssParser");
20
21
  class Element {
21
22
  constructor() {
22
23
  this.parent = null;
@@ -417,10 +418,9 @@
417
418
  specificity.tag += mostSpecificListItem.tag;
418
419
  continue elementLoop;
419
420
  }
420
- if (text.match(/^:(?:nth-child|nth-last-child|host|host-context)/i) && childElements.length > 0) {
421
+ if (text.match(/^:(?:host|host-context)/i) && childElements.length > 0) {
421
422
  // The specificity of :host() is that of a pseudo-class, plus the specificity of its argument.
422
423
  // The specificity of :host-context() is that of a pseudo-class, plus the specificity of its argument.
423
- // The specificity of an :nth-child() or :nth-last-child() selector is the specificity of the pseudo class itself (counting as one pseudo-class selector) plus the specificity of the most specific complex selector in its selector list argument.
424
424
  specificity.attr++;
425
425
  let mostSpecificListItem = calculateMostSpecificListItem(childElements);
426
426
  specificity.id += mostSpecificListItem.id;
@@ -428,6 +428,42 @@
428
428
  specificity.tag += mostSpecificListItem.tag;
429
429
  continue elementLoop;
430
430
  }
431
+ if (text.match(/^:(?:nth-child|nth-last-child)/i) && childElements.length > 0) {
432
+ /* 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 */
433
+ // https://www.w3.org/TR/selectors-4/#the-nth-child-pseudo
434
+ specificity.attr++;
435
+ // 23 = Binary Expression.
436
+ if (childElements.length === 3 && childElements[1].type === 23) {
437
+ let mostSpecificListItem = calculateMostSpecificListItem(childElements[2].getChildren());
438
+ specificity.id += mostSpecificListItem.id;
439
+ specificity.attr += mostSpecificListItem.attr;
440
+ specificity.tag += mostSpecificListItem.tag;
441
+ continue elementLoop;
442
+ }
443
+ // Edge case: 'n' without integer prefix A, with B integer non-existent, is not regarded as a binary expression token.
444
+ const parser = new cssParser_1.Parser();
445
+ const pseudoSelectorText = childElements[1].getText();
446
+ parser.scanner.setSource(pseudoSelectorText);
447
+ const firstToken = parser.scanner.scan();
448
+ const secondToken = parser.scanner.scan();
449
+ if (firstToken.text === 'n' || firstToken.text === '-n' && secondToken.text === 'of') {
450
+ const complexSelectorListNodes = [];
451
+ const complexSelectorText = pseudoSelectorText.slice(secondToken.offset + 2);
452
+ const complexSelectorArray = complexSelectorText.split(',');
453
+ for (const selector of complexSelectorArray) {
454
+ const node = parser.internalParse(selector, parser._parseSelector);
455
+ if (node) {
456
+ complexSelectorListNodes.push(node);
457
+ }
458
+ }
459
+ let mostSpecificListItem = calculateMostSpecificListItem(complexSelectorListNodes);
460
+ specificity.id += mostSpecificListItem.id;
461
+ specificity.attr += mostSpecificListItem.attr;
462
+ specificity.tag += mostSpecificListItem.tag;
463
+ continue elementLoop;
464
+ }
465
+ continue elementLoop;
466
+ }
431
467
  specificity.attr++; //pseudo class
432
468
  continue elementLoop;
433
469
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vscode-css-languageservice",
3
- "version": "6.2.10",
3
+ "version": "6.2.11",
4
4
  "description": "Language service for CSS, LESS and SCSS",
5
5
  "main": "./lib/umd/cssLanguageService.js",
6
6
  "typings": "./lib/umd/cssLanguageService",
@@ -15,13 +15,13 @@
15
15
  "url": "https://github.com/Microsoft/vscode-css-languageservice"
16
16
  },
17
17
  "devDependencies": {
18
- "@types/mocha": "^10.0.2",
18
+ "@types/mocha": "^10.0.6",
19
19
  "@types/node": "16.x",
20
- "@typescript-eslint/eslint-plugin": "^6.7.4",
21
- "@typescript-eslint/parser": "^6.7.4",
20
+ "@typescript-eslint/eslint-plugin": "^6.13.0",
21
+ "@typescript-eslint/parser": "^6.13.0",
22
22
  "@vscode/web-custom-data": "^0.4.8",
23
- "eslint": "^8.50.0",
24
- "js-beautify": "^1.14.9",
23
+ "eslint": "^8.54.0",
24
+ "js-beautify": "^1.14.11",
25
25
  "mocha": "^10.2.0",
26
26
  "rimraf": "^5.0.5",
27
27
  "source-map-support": "^0.5.21",
@@ -44,10 +44,10 @@
44
44
  "mocha": "mocha --require source-map-support/register",
45
45
  "coverage": "npm run compile && npx nyc --reporter=html --reporter=text mocha",
46
46
  "lint": "eslint src/**/*.ts",
47
- "update-data": "yarn add @vscode/web-custom-data -D && node ./build/generateData.js",
48
- "install-types-next": "yarn add vscode-languageserver-types@next -f -S && yarn add vscode-languageserver-textdocument@next -f -S",
47
+ "update-data": "npm install @vscode/web-custom-data -D && node ./build/generateData.js",
48
+ "install-types-next": "npm install vscode-languageserver-types@next -f -S && npm install vscode-languageserver-textdocument@next -f -S",
49
49
  "copy-jsbeautify": "node ./build/copy-jsbeautify.js",
50
- "update-jsbeautify": "yarn add js-beautify && node ./build/update-jsbeautify.js",
51
- "update-jsbeautify-next": "yarn add js-beautify@next && node ./build/update-jsbeautify.js"
50
+ "update-jsbeautify": "npm install js-beautify && node ./build/update-jsbeautify.js",
51
+ "update-jsbeautify-next": "npm install js-beautify@next && node ./build/update-jsbeautify.js"
52
52
  }
53
53
  }
@@ -1,29 +0,0 @@
1
- THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
2
-
3
- vscode-css-languageservice incorporates third party material from the projects listed below. The original copyright
4
- notice and the license under which Microsoft received such third party material are set forth below. Microsoft
5
- reserves all other rights not expressly granted, whether by implication, estoppel or otherwise.
6
-
7
- 1. JS Beautifier (https://github.com/beautify-web/js-beautify)
8
-
9
- The MIT License (MIT)
10
-
11
- Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
12
-
13
- Permission is hereby granted, free of charge, to any person obtaining a copy
14
- of this software and associated documentation files (the "Software"), to deal
15
- in the Software without restriction, including without limitation the rights
16
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- copies of the Software, and to permit persons to whom the Software is
18
- furnished to do so, subject to the following conditions:
19
-
20
- The above copyright notice and this permission notice shall be included in
21
- all copies or substantial portions of the Software.
22
-
23
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
- THE SOFTWARE.