@master/css-language-service 2.0.0-rc.69 → 2.0.0-rc.70

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.
Files changed (72) hide show
  1. package/README.md +57 -6
  2. package/dist/common.d.ts +1 -9
  3. package/dist/common.mjs +1 -48
  4. package/dist/core.d.ts +11 -10
  5. package/dist/core.mjs +70 -200
  6. package/dist/features/inspect-syntax.mjs +18 -32
  7. package/dist/features/render-semantic-tokens.d.ts +5 -0
  8. package/dist/features/render-semantic-tokens.mjs +10 -0
  9. package/dist/features/render-syntax-colors.mjs +23 -8
  10. package/dist/features/suggest-syntax.d.ts +2 -1
  11. package/dist/features/suggest-syntax.mjs +2 -2
  12. package/dist/index.mjs +1 -1
  13. package/dist/settings.d.ts +4 -7
  14. package/dist/settings.mjs +12 -41
  15. package/dist/utils/beautify-css.mjs +1 -1
  16. package/dist/utils/completion-index.d.ts +38 -0
  17. package/dist/utils/completion-index.mjs +268 -0
  18. package/dist/utils/convert-color-token.d.ts +1 -1
  19. package/dist/utils/convert-color-token.mjs +1 -1
  20. package/dist/utils/create-css-markdown-documentation.d.ts +5 -0
  21. package/dist/utils/create-css-markdown-documentation.mjs +15 -0
  22. package/dist/utils/get-class-completion-items.d.ts +4 -0
  23. package/dist/utils/get-class-completion-items.mjs +20 -0
  24. package/dist/utils/get-color-completion-items.d.ts +1 -1
  25. package/dist/utils/get-color-completion-items.mjs +6 -9
  26. package/dist/utils/get-pseudo-class-completion-items.d.ts +3 -2
  27. package/dist/utils/get-pseudo-class-completion-items.mjs +45 -42
  28. package/dist/utils/get-pseudo-element-completion-items.d.ts +3 -2
  29. package/dist/utils/get-pseudo-element-completion-items.mjs +17 -28
  30. package/dist/utils/get-query-completion-items.d.ts +3 -2
  31. package/dist/utils/get-query-completion-items.mjs +19 -32
  32. package/dist/utils/get-utility-info.d.ts +2 -5
  33. package/dist/utils/get-utility-info.mjs +4 -16
  34. package/dist/utils/get-value-completion-items.d.ts +3 -2
  35. package/dist/utils/get-value-completion-items.mjs +145 -123
  36. package/dist/utils/query-syntax-completions.d.ts +3 -2
  37. package/dist/utils/query-syntax-completions.mjs +25 -44
  38. package/package.json +1 -1
  39. package/dist/common.cjs +0 -57
  40. package/dist/core.cjs +0 -246
  41. package/dist/features/edit-syntax-colors.cjs +0 -19
  42. package/dist/features/inspect-syntax.cjs +0 -70
  43. package/dist/features/render-syntax-colors.cjs +0 -89
  44. package/dist/features/suggest-syntax.cjs +0 -20
  45. package/dist/index.cjs +0 -29
  46. package/dist/settings.cjs +0 -84
  47. package/dist/utils/beautify-css.cjs +0 -13
  48. package/dist/utils/convert-color-token.cjs +0 -60
  49. package/dist/utils/create-doc.cjs +0 -26
  50. package/dist/utils/css-data-provider.cjs +0 -9
  51. package/dist/utils/css-data-provider.d.ts +0 -3
  52. package/dist/utils/css-data-provider.mjs +0 -7
  53. package/dist/utils/find-matching-brackets.cjs +0 -29
  54. package/dist/utils/find-matching-brackets.d.ts +0 -1
  55. package/dist/utils/find-matching-brackets.mjs +0 -27
  56. package/dist/utils/get-color-completion-items.cjs +0 -29
  57. package/dist/utils/get-css-data-documentation.cjs +0 -88
  58. package/dist/utils/get-css-data-documentation.d.ts +0 -5
  59. package/dist/utils/get-css-data-documentation.mjs +0 -86
  60. package/dist/utils/get-main-completion-items.cjs +0 -106
  61. package/dist/utils/get-main-completion-items.d.ts +0 -3
  62. package/dist/utils/get-main-completion-items.mjs +0 -104
  63. package/dist/utils/get-position.cjs +0 -12
  64. package/dist/utils/get-pseudo-class-completion-items.cjs +0 -67
  65. package/dist/utils/get-pseudo-element-completion-items.cjs +0 -56
  66. package/dist/utils/get-query-completion-items.cjs +0 -92
  67. package/dist/utils/get-range.cjs +0 -23
  68. package/dist/utils/get-utility-info.cjs +0 -33
  69. package/dist/utils/get-value-completion-items.cjs +0 -183
  70. package/dist/utils/query-syntax-completions.cjs +0 -115
  71. package/dist/utils/regex.cjs +0 -5
  72. package/dist/utils/sort-completion-items.cjs +0 -13
@@ -1,3 +1,4 @@
1
- import { MasterCSS } from '@master/css';
1
+ import { MasterCSS } from '@master/css-language';
2
2
  import { type CompletionItem } from 'vscode-languageserver-protocol';
3
- export default function getPseudoElementCompletionItems(css: MasterCSS | undefined, syntax: string): CompletionItem[];
3
+ import { type CompletionIndex } from './completion-index';
4
+ export default function getPseudoElementCompletionItems(css: MasterCSS | undefined, syntax: string, completionIndex?: CompletionIndex): CompletionItem[];
@@ -1,50 +1,39 @@
1
- import { createCSS, generateCSS } from '@master/css';
2
- import cssDataProvider from './css-data-provider.mjs';
1
+ import { generateCSS, createDefaultCSS } from '@master/css-language';
3
2
  import { CompletionItemKind } from 'vscode-languageserver-protocol';
4
3
  import sortCompletionItems from './sort-completion-items.mjs';
5
- import { getCSSDataDocumentation } from './get-css-data-documentation.mjs';
4
+ import createCSSMarkdownDocumentation from './create-css-markdown-documentation.mjs';
5
+ import { createCompletionIndex } from './completion-index.mjs';
6
6
 
7
7
  const kind = CompletionItemKind.Function;
8
- function getPseudoElementCompletionItems(css = createCSS(), syntax) {
9
- const pseudoElementDataList = cssDataProvider.providePseudoElements();
10
- const completionItems = pseudoElementDataList.map((data)=>{
11
- // fix https://github.com/microsoft/vscode-custom-data/issues/78
12
- const name = /::(?:part|slotted)/.test(data.name) ? data.name + '()' : data.name;
8
+ function getPseudoElementCompletionItems(css = createDefaultCSS(), syntax, completionIndex = createCompletionIndex(css)) {
9
+ const completionItems = completionIndex.pseudoElementNames.map((pseudoElementName)=>{
10
+ const name = /::(?:part|slotted)/.test(pseudoElementName) ? pseudoElementName + '()' : pseudoElementName;
13
11
  let sortText = name.startsWith('::-') ? 'zzzz' + name.slice(3) : 'zz' + name.replace(/^::/, '');
14
12
  if (sortText.endsWith('()')) sortText = 'z' + sortText;
15
13
  return {
16
14
  label: name,
17
15
  sortText,
18
- documentation: getCSSDataDocumentation(data, {
19
- generatedCSS: generateCSS([
20
- syntax + name.slice(2)
21
- ], css),
22
- docs: '/guide/selectors'
23
- }),
24
- kind,
25
- data
16
+ documentation: createCSSMarkdownDocumentation(generateCSS([
17
+ syntax + name.slice(2)
18
+ ], css)),
19
+ kind
26
20
  };
27
21
  });
28
- for(const selectorName in css.config.selectors){
29
- if (!selectorName.startsWith('::')) continue;
30
- const selectorValue = css.config.selectors[selectorName];
22
+ for (const variant of completionIndex.pseudoElementSelectors){
23
+ const selectorName = variant.token;
24
+ const selectorValue = variant.selector.replace(/&/g, '');
31
25
  const name = selectorName.endsWith('(') ? selectorName + ')' : selectorName;
32
26
  const value = typeof selectorValue === 'string' ? selectorValue.endsWith('(') ? selectorValue + ')' : selectorValue : selectorValue;
33
- const data = pseudoElementDataList.find((data)=>typeof value === 'string' ? value.startsWith(data.name) : false);
34
27
  let sortText = name.startsWith('::-') ? 'zzzz' + name.slice(3) : 'zz' + name.replace(/^::/, '');
35
28
  if (sortText.endsWith('()')) sortText = 'z' + sortText;
36
29
  const completionItem = {
37
30
  label: name,
38
- documentation: getCSSDataDocumentation(data, {
39
- generatedCSS: generateCSS([
40
- syntax + name.slice(2)
41
- ], css),
42
- docs: '/guide/selectors'
43
- }),
31
+ documentation: createCSSMarkdownDocumentation(generateCSS([
32
+ syntax + name.slice(2)
33
+ ], css)),
44
34
  sortText,
45
35
  kind,
46
- detail: String(value),
47
- data
36
+ detail: String(value)
48
37
  };
49
38
  completionItems.push(completionItem);
50
39
  }
@@ -1,3 +1,4 @@
1
- import { MasterCSS } from '@master/css';
1
+ import { MasterCSS } from '@master/css-language';
2
2
  import { CompletionItem } from 'vscode-languageserver-protocol';
3
- export default function getQueryCompletionItems(css: MasterCSS | undefined, triggerCharacter: string | undefined, syntax: string): CompletionItem[];
3
+ import { type CompletionIndex } from './completion-index';
4
+ export default function getQueryCompletionItems(css: MasterCSS | undefined, triggerCharacter: string | undefined, syntax: string, completionIndex?: CompletionIndex): CompletionItem[];
@@ -1,11 +1,10 @@
1
- import { createCSS, AT_SIGN, QUERY_COMPARISON_OPERATORS, generateCSS, QUERY_LOGICAL_OPERATORS, generateAt, parseAt, getSingleAtNumberRuleNode } from '@master/css';
1
+ import { AT_SIGN, QUERY_COMPARISON_OPERATORS, generateCSS, QUERY_LOGICAL_OPERATORS, generateAt, parseAt, createDefaultCSS, getSingleAtNumberRuleNode } from '@master/css-language';
2
2
  import { CompletionItemKind } from 'vscode-languageserver-protocol';
3
3
  import sortCompletionItems from './sort-completion-items.mjs';
4
- import { getCSSDataDocumentation } from './get-css-data-documentation.mjs';
5
- import cssDataProvider from './css-data-provider.mjs';
4
+ import createCSSMarkdownDocumentation from './create-css-markdown-documentation.mjs';
5
+ import { createCompletionIndex } from './completion-index.mjs';
6
6
 
7
- function getQueryCompletionItems(css = createCSS(), triggerCharacter = AT_SIGN, syntax) {
8
- const atDataList = cssDataProvider.provideAtDirectives();
7
+ function getQueryCompletionItems(css = createDefaultCSS(), triggerCharacter = AT_SIGN, syntax, completionIndex = createCompletionIndex(css)) {
9
8
  const completionItems = [];
10
9
  if (!QUERY_COMPARISON_OPERATORS.includes(triggerCharacter)) {
11
10
  [
@@ -18,12 +17,9 @@ function getQueryCompletionItems(css = createCSS(), triggerCharacter = AT_SIGN,
18
17
  filterText: name + '()',
19
18
  insertText: name + '()',
20
19
  sortText: name + '()',
21
- documentation: getCSSDataDocumentation(atDataList.find(({ name })=>name === '@' + name), {
22
- generatedCSS: generateCSS([
23
- syntax + name + '()'
24
- ], css),
25
- docs: '/guide/at'
26
- })
20
+ documentation: createCSSMarkdownDocumentation(generateCSS([
21
+ syntax + name + '()'
22
+ ], css))
27
23
  });
28
24
  });
29
25
  }
@@ -40,32 +36,26 @@ function getQueryCompletionItems(css = createCSS(), triggerCharacter = AT_SIGN,
40
36
  insertText: token,
41
37
  detail: text,
42
38
  kind: CompletionItemKind.Keyword,
43
- documentation: getCSSDataDocumentation(undefined, {
44
- generatedCSS: generateCSS([
45
- syntax + token
46
- ], css),
47
- docs: '/guide/at'
48
- })
39
+ documentation: createCSSMarkdownDocumentation(generateCSS([
40
+ syntax + token
41
+ ], css))
49
42
  });
50
43
  return true;
51
44
  }
52
45
  };
53
- css.atRules.forEach((atRule, token)=>{
46
+ for (const [token, atRule] of completionIndex.atRules){
54
47
  const completionItem = {
55
48
  filterText: token,
56
49
  insertText: token,
57
- documentation: getCSSDataDocumentation(undefined, {
58
- generatedCSS: generateCSS([
59
- syntax + token
60
- ], css),
61
- docs: '/guide/at'
62
- })
50
+ documentation: createCSSMarkdownDocumentation(generateCSS([
51
+ syntax + token
52
+ ], css))
63
53
  };
64
54
  if ([
65
55
  AT_SIGN,
66
56
  ...QUERY_LOGICAL_OPERATORS
67
57
  ].includes(triggerCharacter)) {
68
- if (handleNumberNodes(atRule, token)) return;
58
+ if (handleNumberNodes(atRule, token)) continue;
69
59
  const text = generateAt(parseAt(triggerCharacter + token, css));
70
60
  completionItems.push({
71
61
  ...completionItem,
@@ -73,17 +63,14 @@ function getQueryCompletionItems(css = createCSS(), triggerCharacter = AT_SIGN,
73
63
  detail: text,
74
64
  sortText: CompletionItemKind.Keyword + token,
75
65
  kind: CompletionItemKind.Keyword,
76
- documentation: getCSSDataDocumentation(undefined, {
77
- generatedCSS: generateCSS([
78
- syntax + token
79
- ], css),
80
- docs: '/guide/at'
81
- })
66
+ documentation: createCSSMarkdownDocumentation(generateCSS([
67
+ syntax + token
68
+ ], css))
82
69
  });
83
70
  } else if (QUERY_COMPARISON_OPERATORS.includes(triggerCharacter)) {
84
71
  handleNumberNodes(atRule, token);
85
72
  }
86
- });
73
+ }
87
74
  return sortCompletionItems(completionItems);
88
75
  }
89
76
 
@@ -1,7 +1,4 @@
1
- import { DefinedRule } from '@master/css';
2
- import type { IPropertyData } from 'vscode-css-languageservice';
3
- export default function getUtilityInfo(syntax: DefinedRule, css?: import("@master/css").MasterCSS): {
4
- docs: string;
5
- data: IPropertyData | undefined;
1
+ import { type CompiledUtility } from '@master/css-language';
2
+ export default function getUtilityInfo(utility: CompiledUtility): {
6
3
  detail: string | undefined;
7
4
  };
@@ -1,29 +1,17 @@
1
- import { createCSS } from '@master/css';
2
- import cssDataProvider from './css-data-provider.mjs';
1
+ import { getStaticUtilityDeclarations } from '@master/css-language';
3
2
 
4
- function getUtilityInfo(syntax, css = createCSS()) {
5
- const nativeProperties = cssDataProvider.provideProperties();
6
- const declarations = syntax.definition.declarations;
3
+ function getUtilityInfo(utility) {
4
+ const declarations = getStaticUtilityDeclarations(utility);
7
5
  const propsLength = Object.keys(declarations || {}).length;
8
6
  const propName = Object.keys(declarations || {})[0];
9
7
  const propValue = declarations?.[propName];
10
- let data;
11
8
  let detail;
12
9
  /**
13
10
  * Remaps to native CSS properties when only one property is declared
14
11
  * */ if (propsLength === 1) {
15
- const nativeCSSPropertyData = nativeProperties.find(({ name })=>name === propName);
16
- data = nativeCSSPropertyData?.values?.find(({ name })=>name === propValue || name.replace(/^-(ms|moz)-/, '') === propValue);
17
- if (data) {
18
- detail = `${propName}: ${propValue}`;
19
- } else {
20
- data = nativeCSSPropertyData;
21
- detail = nativeCSSPropertyData?.syntax;
22
- }
12
+ detail = `${propName}: ${propValue}`;
23
13
  }
24
14
  return {
25
- docs: '/reference/' + (data ? propName : 'utilities'),
26
- data,
27
15
  detail
28
16
  };
29
17
  }
@@ -1,3 +1,4 @@
1
1
  import { type CompletionItem } from 'vscode-languageserver-protocol';
2
- import { MasterCSS } from '@master/css';
3
- export default function getValueCompletionItems(css: MasterCSS | undefined, ruleKey: string): CompletionItem[];
2
+ import { MasterCSS } from '@master/css-language';
3
+ import { type CompletionIndex } from './completion-index';
4
+ export default function getValueCompletionItems(css: MasterCSS | undefined, ruleKey: string, valuePrefix?: string, completionIndex?: CompletionIndex): CompletionItem[];
@@ -1,58 +1,78 @@
1
1
  import { CompletionItemKind } from 'vscode-languageserver-protocol';
2
- import cssDataProvider from './css-data-provider.mjs';
3
- import { createCSS, SyntaxRuleType, isCoreRule, generateCSS } from '@master/css';
4
- import { getCSSDataDocumentation } from './get-css-data-documentation.mjs';
2
+ import { getMdnPropertySyntax, getMdnPropertyValueNames, generateCSS, createDefaultCSS } from '@master/css-language';
3
+ import { builtinKeyAliases } from '@master/css-engine';
4
+ import createCSSMarkdownDocumentation from './create-css-markdown-documentation.mjs';
5
5
  import sortCompletionItems from './sort-completion-items.mjs';
6
+ import { createCompletionIndex } from './completion-index.mjs';
6
7
 
7
8
  const SCOPED_VARIABLE_PRIORITY = 'aaaa';
8
- const AMBIGUOUS_PRIORITY = 'bbbb';
9
9
  const NATIVE_PRIORITY = 'ccccc';
10
10
  const GLOBAL_VARIABLE_PRIORITY = 'zzzz';
11
- function getValueCompletionItems(css = createCSS(), ruleKey) {
12
- const nativeProperties = cssDataProvider.provideProperties();
11
+ const ANIMATION_REFERENCE_PROPERTIES = new Set([
12
+ 'animation',
13
+ 'animation-name'
14
+ ]);
15
+ function getNumericSortValue(variable, rootSize) {
16
+ if (variable.numeric) {
17
+ switch(variable.numeric.unit){
18
+ case 'rem':
19
+ return variable.numeric.value * rootSize;
20
+ case undefined:
21
+ case '':
22
+ case 'px':
23
+ return variable.numeric.value;
24
+ }
25
+ }
26
+ return typeof variable.value === 'number' ? variable.value : 0;
27
+ }
28
+ function getVariableKeyByNamespace(variableName, namespace) {
29
+ const negative = variableName.startsWith('-');
30
+ const positiveName = negative ? variableName.slice(1) : variableName;
31
+ if (positiveName !== namespace && !positiveName.startsWith(namespace + '-')) return;
32
+ const key = positiveName === namespace ? '' : positiveName.slice(namespace.length + 1);
33
+ return negative ? '-' + key : key;
34
+ }
35
+ function getValueCompletionItems(css = createDefaultCSS(), ruleKey, valuePrefix = '', completionIndex = createCompletionIndex(css)) {
13
36
  const completionItems = [];
14
- const nativeKey = css.definedRules.find(({ keys })=>keys.includes(ruleKey))?.id;
15
- const nativePropertyData = nativeProperties.find(({ name })=>name === nativeKey);
16
- const generateVariableCompletionItem = (variable, { scoped } = {
17
- scoped: false
18
- })=>{
19
- const eachNativePropertyData = nativeProperties.find((x)=>x.name === variable.group) || nativePropertyData;
20
- const appliedValue = scoped ? variable.key : variable.name;
21
- const documentation = getCSSDataDocumentation(eachNativePropertyData, {
22
- generatedCSS: generateCSS([
23
- ruleKey + ':' + appliedValue
24
- ], css),
25
- docs: '/reference/' + (eachNativePropertyData?.name || 'variables')
26
- });
37
+ const addedLabels = new Set();
38
+ const canonicalRuleKey = builtinKeyAliases[ruleKey] || ruleKey;
39
+ const nativeUtilityKey = completionIndex.nativeUtilityKeys.get(canonicalRuleKey);
40
+ const nativeKey = nativeUtilityKey || (getMdnPropertySyntax(canonicalRuleKey) ? canonicalRuleKey : undefined);
41
+ const nativePropertyValues = getMdnPropertyValueNames(nativeKey);
42
+ const pushCompletionItem = (completionItem)=>{
43
+ completionItems.push(completionItem);
44
+ addedLabels.add(completionItem.label);
45
+ };
46
+ const generateVariableCompletionItem = (variable, { appliedValue, label, negative, scoped } = {})=>{
47
+ const nativePropertySyntax = getMdnPropertySyntax(variable.namespace) || getMdnPropertySyntax(nativeKey);
48
+ if (variable.type === 'number' && variable.name.startsWith('-') && nativePropertySyntax?.includes('absolute')) return;
49
+ const valueToken = appliedValue ?? (scoped ? variable.key : variable.name);
50
+ const documentation = createCSSMarkdownDocumentation(generateCSS([
51
+ ruleKey + ':' + valueToken
52
+ ], css));
53
+ const completionItemLabel = label ?? variable.name;
54
+ const conflicted = addedLabels.has(completionItemLabel);
27
55
  const completionItem = {
28
- label: variable.name,
56
+ label: conflicted ? 'var(--' + completionItemLabel + ')' : completionItemLabel,
29
57
  kind: CompletionItemKind.Value
30
58
  };
31
- const conflicted = completionItems.find(({ label })=>label === variable.name);
32
59
  if (conflicted) {
33
- completionItem.label = '$(' + completionItem.label + ')';
34
- completionItem.documentation = getCSSDataDocumentation(eachNativePropertyData, {
35
- generatedCSS: generateCSS([
36
- ruleKey + ':' + completionItem.label
37
- ], css),
38
- docs: '/reference/' + (eachNativePropertyData?.name || 'variables')
39
- });
60
+ completionItem.documentation = createCSSMarkdownDocumentation(generateCSS([
61
+ ruleKey + ':' + completionItem.label
62
+ ], css));
40
63
  } else {
41
- completionItem.documentation = getCSSDataDocumentation(eachNativePropertyData, {
42
- generatedCSS: generateCSS([
43
- ruleKey + ':' + appliedValue
44
- ], css),
45
- docs: '/reference/' + (eachNativePropertyData?.name || 'variables')
46
- });
64
+ completionItem.documentation = createCSSMarkdownDocumentation(generateCSS([
65
+ ruleKey + ':' + valueToken
66
+ ], css));
47
67
  }
48
- if (variable.type === 'color') {
68
+ if (variable.namespace?.startsWith('color')) {
49
69
  if (Object.keys(variable.modes || {}).length) {
50
70
  completionItem.kind = CompletionItemKind.Color;
51
71
  completionItem.detail = variable.name;
52
72
  } else {
53
73
  // todo: packages/core should support getTextByVariable(variable)
54
- const configKey = 'variables.' + (variable.group ? variable.group + '.' + variable.key : variable.name);
55
- const valueToken = variable.space && variable.value ? `${variable.space}(${variable.value.split(' ').join(',')})` : variable.value;
74
+ const configKey = 'variables.' + (variable.namespace ? variable.namespace + '.' + variable.key : variable.name);
75
+ const valueToken = variable.value ?? variable.name;
56
76
  // detail is shown in the detail pane
57
77
  // todo: variable.token should be recorded as original config variable
58
78
  completionItem.detail = String(configKey);
@@ -64,115 +84,117 @@ function getValueCompletionItems(css = createCSS(), ruleKey) {
64
84
  completionItem.sortText = 'color-' + variable.name.replace(/(.+?)-(\d+)/, (match, prefix, num)=>prefix + num.padStart(10, '0'));
65
85
  }
66
86
  } else if (variable.type === 'number') {
67
- if (variable.name.startsWith('-') && eachNativePropertyData?.syntax?.includes('absolute')) return;
68
87
  completionItem.detail = String(variable.name);
69
- completionItem.sortText = (variable.group || '') + (variable.value >= 0 ? String(variable.value).padStart(10, '0') : '-' + String(Math.abs(variable.value)).padStart(10, '0'));
88
+ const value = getNumericSortValue(variable, css.settings.rootSize);
89
+ const sortValue = negative ? -Math.abs(value) : value;
90
+ completionItem.sortText = (variable.namespace || '') + (sortValue >= 0 ? String(sortValue).padStart(10, '0') : '-' + String(Math.abs(sortValue)).padStart(10, '0'));
70
91
  } else {
71
92
  completionItem.detail = String(variable.value || variable.name);
72
93
  }
73
94
  return completionItem;
74
95
  };
75
- for (const eachDefinedRule of css.definedRules){
76
- /**
77
- * Scoped variables
78
- * @example box: + content -> box-sizing:content
79
- */ if (eachDefinedRule.definition.key === ruleKey || eachDefinedRule.definition.subkey === ruleKey || eachDefinedRule.definition.aliasGroups?.includes(ruleKey)) {
80
- eachDefinedRule.variables?.forEach((variable, variableName)=>{
81
- if (completionItems.find(({ label })=>label === variableName)) return;
82
- const completionItem = generateVariableCompletionItem(variable, {
83
- scoped: true
84
- });
85
- if (completionItem) {
86
- completionItem.label = variableName;
87
- completionItem.sortText = SCOPED_VARIABLE_PRIORITY + variableName;
88
- completionItem.detail = '(scope) ' + completionItem.detail;
89
- completionItems.push(completionItem);
90
- }
91
- });
96
+ const addScopedVariableCompletionItem = (variable, variableName)=>{
97
+ if (addedLabels.has(variableName)) return;
98
+ const completionItem = generateVariableCompletionItem(variable, {
99
+ scoped: true
100
+ });
101
+ if (completionItem) {
102
+ completionItem.label = variableName;
103
+ completionItem.sortText = SCOPED_VARIABLE_PRIORITY + (completionItem.sortText || variableName);
104
+ completionItem.detail = '(scope) ' + completionItem.detail;
105
+ pushCompletionItem(completionItem);
92
106
  }
93
- /**
94
- * @example animation:fade
95
- */ if (eachDefinedRule.keys.includes(ruleKey) && eachDefinedRule.definition.includeAnimations) {
96
- css.animations.forEach((_, animationName)=>{
97
- const isNative = eachDefinedRule.definition.type && [
98
- SyntaxRuleType.Native,
99
- SyntaxRuleType.NativeShorthand
100
- ].includes(eachDefinedRule.definition.type);
101
- completionItems.push({
102
- label: animationName,
103
- kind: CompletionItemKind.Value,
104
- documentation: getCSSDataDocumentation(undefined, {
105
- generatedCSS: generateCSS([
106
- ruleKey + ':' + animationName
107
- ], css),
108
- docs: '/reference/' + isCoreRule(eachDefinedRule.id) && eachDefinedRule.id
109
- }),
110
- detail: isNative ? eachDefinedRule.id + ': ' + animationName : animationName
111
- });
107
+ const negativeVariableName = '-' + variableName;
108
+ if (valuePrefix.startsWith('-') && variableName[0] !== '-' && variable.type === 'number' && !addedLabels.has(negativeVariableName)) {
109
+ const negativeCompletionItem = generateVariableCompletionItem(variable, {
110
+ appliedValue: negativeVariableName,
111
+ label: negativeVariableName,
112
+ negative: true,
113
+ scoped: true
112
114
  });
113
- }
114
- /**
115
- * Ambiguous values
116
- * @example text: -> center, left, right, justify
117
- * @example t: -> center, left, right, justify
118
- */ if (eachDefinedRule.definition.aliasGroups?.includes(ruleKey) && eachDefinedRule.definition.values?.length) {
119
- const nativePropertyData = nativeProperties.find((x)=>x.name === eachDefinedRule.id);
120
- for (const value of eachDefinedRule.definition.values){
121
- if (typeof value !== 'string') continue;
122
- const nativeValueData = nativePropertyData?.values?.find((x)=>x.name === value);
123
- const isNative = eachDefinedRule.definition.type && [
124
- SyntaxRuleType.Native,
125
- SyntaxRuleType.NativeShorthand
126
- ].includes(eachDefinedRule.definition.type);
127
- completionItems.push({
128
- label: value,
129
- kind: CompletionItemKind.Value,
130
- sortText: AMBIGUOUS_PRIORITY + value,
131
- documentation: getCSSDataDocumentation({
132
- ...nativeValueData || {},
133
- // use nativePropertyData.reference because nativeValueData does not have references
134
- references: nativePropertyData?.references
135
- }, {
136
- generatedCSS: generateCSS([
137
- ruleKey + ':' + value
138
- ], css),
139
- docs: '/reference/' + isCoreRule(eachDefinedRule.id) && eachDefinedRule.id
140
- }),
141
- detail: isNative ? eachDefinedRule.id + ': ' + value : value
142
- });
115
+ if (negativeCompletionItem) {
116
+ negativeCompletionItem.sortText = SCOPED_VARIABLE_PRIORITY + (negativeCompletionItem.sortText || negativeVariableName);
117
+ negativeCompletionItem.detail = '(scope) ' + negativeCompletionItem.detail;
118
+ pushCompletionItem(negativeCompletionItem);
143
119
  }
144
120
  }
121
+ };
122
+ /**
123
+ * Scoped variables
124
+ * @example box: + content -> box-sizing:content
125
+ */ for (const { name, variable } of completionIndex.scopedVariablesByKey.get(canonicalRuleKey) || []){
126
+ addScopedVariableCompletionItem(variable, name);
127
+ }
128
+ for (const { value } of completionIndex.patternValuesByKey.get(canonicalRuleKey) || []){
129
+ if (addedLabels.has(value)) continue;
130
+ pushCompletionItem({
131
+ label: value,
132
+ kind: CompletionItemKind.Value,
133
+ documentation: createCSSMarkdownDocumentation(generateCSS([
134
+ ruleKey + ':' + value
135
+ ], css)),
136
+ detail: canonicalRuleKey + ': ' + value
137
+ });
138
+ }
139
+ /**
140
+ * @example animation:fade|fast animate:fade animation-name:fade
141
+ */ for (const animationUtility of completionIndex.animationUtilitiesByKey.get(canonicalRuleKey) || []){
142
+ css.animations.forEach((_, animationName)=>{
143
+ pushCompletionItem({
144
+ label: animationName,
145
+ kind: CompletionItemKind.Value,
146
+ documentation: createCSSMarkdownDocumentation(generateCSS([
147
+ ruleKey + ':' + animationName
148
+ ], css)),
149
+ detail: animationUtility.detailPrefix ? animationUtility.detailPrefix + ': ' + animationName : animationName
150
+ });
151
+ });
152
+ }
153
+ if (ANIMATION_REFERENCE_PROPERTIES.has(canonicalRuleKey)) {
154
+ css.animations.forEach((_, animationName)=>{
155
+ if (addedLabels.has(animationName)) return;
156
+ pushCompletionItem({
157
+ label: animationName,
158
+ kind: CompletionItemKind.Value,
159
+ documentation: createCSSMarkdownDocumentation(generateCSS([
160
+ ruleKey + ':' + animationName
161
+ ], css)),
162
+ detail: canonicalRuleKey + ': ' + animationName
163
+ });
164
+ });
165
+ }
166
+ const usedKeys = new Set();
167
+ for (const variableNamespace of completionIndex.nativeVariableNamespacesByProperty.get(canonicalRuleKey) || []){
168
+ for (const variable of completionIndex.variables){
169
+ const variableName = getVariableKeyByNamespace(variable.name, variableNamespace);
170
+ if (variableName === undefined || usedKeys.has(variableName)) continue;
171
+ usedKeys.add(variableName);
172
+ addScopedVariableCompletionItem(variable, variableName);
173
+ }
145
174
  }
146
175
  /**
147
176
  * Native values
148
177
  */ if (nativeKey) {
149
- nativePropertyData?.values?.forEach((value)=>{
150
- if (completionItems.find((x)=>x.label === value.name) || nativePropertyData.name === 'font' && typeof +value.name === 'number' || value.name.includes(' ')) return;
151
- completionItems.push({
152
- label: value.name,
178
+ nativePropertyValues.forEach((value)=>{
179
+ if (addedLabels.has(value) || nativeKey === 'font' && typeof +value === 'number' || value.includes(' ')) return;
180
+ pushCompletionItem({
181
+ label: value,
153
182
  kind: CompletionItemKind.Value,
154
- sortText: NATIVE_PRIORITY + (value.name.startsWith('-') ? 'zz' + value.name.slice(1) : value.name),
155
- documentation: getCSSDataDocumentation({
156
- ...value,
157
- // use nativePropertyData.reference because nativeValueData does not have references
158
- references: nativePropertyData?.references
159
- }, {
160
- generatedCSS: generateCSS([
161
- ruleKey + ':' + value.name
162
- ], css),
163
- docs: '/reference/' + nativeKey
164
- }),
165
- detail: nativeKey + ': ' + value.name
183
+ sortText: NATIVE_PRIORITY + (value.startsWith('-') ? 'zz' + value.slice(1) : value),
184
+ documentation: createCSSMarkdownDocumentation(generateCSS([
185
+ ruleKey + ':' + value
186
+ ], css)),
187
+ detail: nativeKey + ': ' + value
166
188
  });
167
189
  });
168
190
  }
169
191
  // global variables
170
- css.variables.forEach((variable)=>{
192
+ completionIndex.variables.forEach((variable)=>{
171
193
  const completionItem = generateVariableCompletionItem(variable);
172
194
  if (completionItem) {
173
195
  completionItem.sortText = GLOBAL_VARIABLE_PRIORITY + (completionItem.sortText || completionItem.label);
174
196
  completionItem.detail = '(global) ' + completionItem.detail;
175
- completionItems.push(completionItem);
197
+ pushCompletionItem(completionItem);
176
198
  }
177
199
  });
178
200
  return sortCompletionItems(completionItems);
@@ -1,3 +1,4 @@
1
1
  import { type CompletionItem } from 'vscode-languageserver-protocol';
2
- import { MasterCSS } from '@master/css';
3
- export default function querySyntaxCompletions(q?: string, css?: MasterCSS): CompletionItem[] | undefined;
2
+ import { MasterCSS } from '@master/css-language';
3
+ import { type CompletionIndex } from './completion-index';
4
+ export default function querySyntaxCompletions(q?: string, css?: MasterCSS, completionIndex?: CompletionIndex): CompletionItem[] | undefined;