@master/css-language-service 2.0.0-rc.26 → 2.0.0-rc.27

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 (111) hide show
  1. package/dist/common.cjs +57 -0
  2. package/dist/common.d.ts +9 -0
  3. package/dist/common.mjs +48 -0
  4. package/dist/core.cjs +188 -0
  5. package/dist/core.d.ts +30 -0
  6. package/dist/core.mjs +186 -0
  7. package/dist/features/edit-syntax-colors.cjs +19 -0
  8. package/dist/features/edit-syntax-colors.d.ts +4 -0
  9. package/dist/features/edit-syntax-colors.mjs +17 -0
  10. package/dist/features/inspect-syntax.cjs +70 -0
  11. package/dist/features/inspect-syntax.d.ts +4 -0
  12. package/dist/features/inspect-syntax.mjs +68 -0
  13. package/dist/features/render-syntax-colors.cjs +88 -0
  14. package/dist/features/render-syntax-colors.d.ts +4 -0
  15. package/dist/features/render-syntax-colors.mjs +86 -0
  16. package/dist/features/suggest-syntax.cjs +20 -0
  17. package/dist/features/suggest-syntax.d.ts +4 -0
  18. package/dist/features/suggest-syntax.mjs +18 -0
  19. package/dist/index.cjs +23 -15
  20. package/dist/index.d.ts +7 -5
  21. package/dist/index.mjs +7 -5
  22. package/dist/settings.cjs +130 -29
  23. package/dist/settings.d.ts +16 -8
  24. package/dist/settings.mjs +130 -29
  25. package/dist/utils/beautify-css.cjs +13 -0
  26. package/dist/utils/beautify-css.d.ts +1 -0
  27. package/dist/utils/beautify-css.mjs +11 -0
  28. package/dist/utils/convert-color-space.cjs +40 -0
  29. package/dist/utils/convert-color-space.d.ts +2 -0
  30. package/dist/utils/convert-color-space.mjs +38 -0
  31. package/dist/utils/convert-color-token.cjs +28 -0
  32. package/dist/utils/convert-color-token.d.ts +3 -0
  33. package/dist/utils/convert-color-token.mjs +26 -0
  34. package/dist/utils/create-doc.cjs +26 -0
  35. package/dist/utils/create-doc.d.ts +16 -0
  36. package/dist/utils/create-doc.mjs +21 -0
  37. package/dist/utils/css-data-provider.cjs +9 -0
  38. package/dist/utils/css-data-provider.d.ts +3 -0
  39. package/dist/utils/css-data-provider.mjs +7 -0
  40. package/dist/utils/find-matching-brackets.cjs +29 -0
  41. package/dist/utils/find-matching-brackets.d.ts +1 -0
  42. package/dist/utils/find-matching-brackets.mjs +27 -0
  43. package/dist/utils/get-color-completion-items.cjs +30 -0
  44. package/dist/utils/get-color-completion-items.d.ts +3 -0
  45. package/dist/utils/get-color-completion-items.mjs +28 -0
  46. package/dist/utils/get-css-data-documentation.cjs +90 -0
  47. package/dist/utils/get-css-data-documentation.d.ts +5 -0
  48. package/dist/utils/get-css-data-documentation.mjs +88 -0
  49. package/dist/utils/get-main-completion-items.cjs +105 -0
  50. package/dist/utils/get-main-completion-items.d.ts +3 -0
  51. package/dist/utils/get-main-completion-items.mjs +103 -0
  52. package/dist/utils/get-position.cjs +12 -0
  53. package/dist/utils/get-position.d.ts +1 -0
  54. package/dist/utils/get-position.mjs +10 -0
  55. package/dist/utils/get-pseudo-class-completion-items.cjs +65 -0
  56. package/dist/utils/get-pseudo-class-completion-items.d.ts +3 -0
  57. package/dist/utils/get-pseudo-class-completion-items.mjs +63 -0
  58. package/dist/utils/get-pseudo-element-completion-items.cjs +56 -0
  59. package/dist/utils/get-pseudo-element-completion-items.d.ts +3 -0
  60. package/dist/utils/get-pseudo-element-completion-items.mjs +54 -0
  61. package/dist/utils/get-query-completion-items.cjs +102 -0
  62. package/dist/utils/get-query-completion-items.d.ts +3 -0
  63. package/dist/utils/get-query-completion-items.mjs +100 -0
  64. package/dist/utils/get-range.cjs +21 -0
  65. package/dist/utils/get-range.d.ts +2 -0
  66. package/dist/utils/get-range.mjs +19 -0
  67. package/dist/utils/get-utility-info.cjs +32 -0
  68. package/dist/utils/get-utility-info.d.ts +7 -0
  69. package/dist/utils/get-utility-info.mjs +30 -0
  70. package/dist/utils/get-value-completion-items.cjs +185 -0
  71. package/dist/utils/get-value-completion-items.d.ts +3 -0
  72. package/dist/utils/get-value-completion-items.mjs +183 -0
  73. package/dist/utils/query-syntax-completions.cjs +115 -0
  74. package/dist/utils/query-syntax-completions.d.ts +3 -0
  75. package/dist/utils/query-syntax-completions.mjs +113 -0
  76. package/dist/utils/regex.cjs +1 -1
  77. package/dist/utils/regex.mjs +1 -1
  78. package/dist/utils/sort-completion-items.cjs +11 -0
  79. package/dist/utils/sort-completion-items.d.ts +2 -0
  80. package/dist/utils/sort-completion-items.mjs +9 -0
  81. package/package.json +1 -1
  82. package/dist/constant.cjs +0 -3064
  83. package/dist/constant.d.ts +0 -33
  84. package/dist/constant.mjs +0 -3055
  85. package/dist/position-check.cjs +0 -37
  86. package/dist/position-check.d.ts +0 -7
  87. package/dist/position-check.mjs +0 -35
  88. package/dist/providers/color.cjs +0 -319
  89. package/dist/providers/color.d.ts +0 -5
  90. package/dist/providers/color.mjs +0 -315
  91. package/dist/providers/completion.cjs +0 -309
  92. package/dist/providers/completion.d.ts +0 -14
  93. package/dist/providers/completion.mjs +0 -303
  94. package/dist/providers/hover.cjs +0 -65
  95. package/dist/providers/hover.d.ts +0 -2
  96. package/dist/providers/hover.mjs +0 -63
  97. package/dist/utils/get-css-entry-markdown-description.cjs +0 -77
  98. package/dist/utils/get-css-entry-markdown-description.d.ts +0 -1
  99. package/dist/utils/get-css-entry-markdown-description.mjs +0 -75
  100. package/dist/utils/hex-to-rgb.cjs +0 -13
  101. package/dist/utils/hex-to-rgb.d.ts +0 -2
  102. package/dist/utils/hex-to-rgb.mjs +0 -11
  103. package/dist/utils/oklab-to-rgb.cjs +0 -33
  104. package/dist/utils/oklab-to-rgb.d.ts +0 -1
  105. package/dist/utils/oklab-to-rgb.mjs +0 -31
  106. package/dist/utils/oklch-to-oklab.cjs +0 -11
  107. package/dist/utils/oklch-to-oklab.d.ts +0 -1
  108. package/dist/utils/oklch-to-oklab.mjs +0 -9
  109. package/dist/utils/to-two-digit-hex.cjs +0 -8
  110. package/dist/utils/to-two-digit-hex.d.ts +0 -1
  111. package/dist/utils/to-two-digit-hex.mjs +0 -6
@@ -0,0 +1,183 @@
1
+ import { CompletionItemKind } from 'vscode-languageserver-protocol';
2
+ import cssDataProvider from './css-data-provider.mjs';
3
+ import { Layer, generateCSS, isCoreRule, MasterCSS } from '@master/css';
4
+ import { getCSSDataDocumentation } from './get-css-data-documentation.mjs';
5
+ import sortCompletionItems from './sort-completion-items.mjs';
6
+
7
+ const SCOPED_VARIABLE_PRIORITY = 'aaaa';
8
+ const AMBIGUOUS_PRIORITY = 'bbbb';
9
+ const NATIVE_PRIORITY = 'ccccc';
10
+ const GLOBAL_VARIABLE_PRIORITY = 'zzzz';
11
+ function getValueCompletionItems(css = new MasterCSS(), ruleKey) {
12
+ const nativeProperties = cssDataProvider.provideProperties();
13
+ const completionItems = [];
14
+ const nativeKey = css.Rules.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: eachNativePropertyData?.name || 'variables'
26
+ });
27
+ const completionItem = {
28
+ label: variable.name,
29
+ kind: CompletionItemKind.Value
30
+ };
31
+ const conflicted = completionItems.find(({ label })=>label === variable.name);
32
+ if (conflicted) {
33
+ completionItem.label = '$(' + completionItem.label + ')';
34
+ completionItem.documentation = getCSSDataDocumentation(eachNativePropertyData, {
35
+ generatedCSS: generateCSS([
36
+ ruleKey + ':' + completionItem.label
37
+ ], css),
38
+ docs: eachNativePropertyData?.name || 'variables'
39
+ });
40
+ } else {
41
+ completionItem.documentation = getCSSDataDocumentation(eachNativePropertyData, {
42
+ generatedCSS: generateCSS([
43
+ ruleKey + ':' + appliedValue
44
+ ], css),
45
+ docs: eachNativePropertyData?.name || 'variables'
46
+ });
47
+ }
48
+ if (variable.type === 'color') {
49
+ if (Object.keys(variable.modes || {}).length) {
50
+ completionItem.kind = CompletionItemKind.Color;
51
+ completionItem.detail = variable.name;
52
+ } else {
53
+ // todo: packages/css 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;
56
+ // detail is shown in the detail pane
57
+ // todo: variable.token should be recorded as original config variable
58
+ completionItem.detail = String(configKey);
59
+ completionItem.documentation = {
60
+ kind: 'markdown',
61
+ value: valueToken + '\n\n' + documentation?.value
62
+ };
63
+ completionItem.kind = CompletionItemKind.Color;
64
+ completionItem.sortText = 'color-' + variable.name.replace(/(.+?)-(\d+)/, (match, prefix, num)=>prefix + num.padStart(10, '0'));
65
+ }
66
+ } else if (variable.type === 'number') {
67
+ if (variable.name.startsWith('-') && eachNativePropertyData?.syntax?.includes('absolute')) return;
68
+ 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'));
70
+ } else {
71
+ completionItem.detail = String(variable.value || variable.name);
72
+ }
73
+ return completionItem;
74
+ };
75
+ for (const EachRule of css.Rules){
76
+ /**
77
+ * Scoped variables
78
+ * @example box: + content -> box-sizing:content
79
+ */ if (EachRule.definition.key === ruleKey || EachRule.definition.subkey === ruleKey || EachRule.definition.ambiguousKeys?.includes(ruleKey)) {
80
+ for(const variableName in EachRule.variables){
81
+ if (completionItems.find(({ label })=>label === variableName)) continue;
82
+ const variable = EachRule.variables[variableName];
83
+ const completionItem = generateVariableCompletionItem(variable, {
84
+ scoped: true
85
+ });
86
+ if (completionItem) {
87
+ completionItem.label = variableName;
88
+ completionItem.sortText = SCOPED_VARIABLE_PRIORITY + variableName;
89
+ completionItem.detail = '(scope) ' + completionItem.detail;
90
+ completionItems.push(completionItem);
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * @example animation:fade
96
+ */ if (EachRule.keys.includes(ruleKey) && EachRule.definition.includeAnimations) {
97
+ for(const animationName in css.animations){
98
+ const isNative = EachRule.definition.layer && [
99
+ Layer.Native,
100
+ Layer.NativeShorthand
101
+ ].includes(EachRule.definition.layer);
102
+ completionItems.push({
103
+ label: animationName,
104
+ kind: CompletionItemKind.Value,
105
+ documentation: getCSSDataDocumentation(undefined, {
106
+ generatedCSS: generateCSS([
107
+ ruleKey + ':' + animationName
108
+ ], css),
109
+ docs: isCoreRule(EachRule.id) && EachRule.id
110
+ }),
111
+ detail: isNative ? EachRule.id + ': ' + animationName : animationName
112
+ });
113
+ }
114
+ }
115
+ /**
116
+ * Ambiguous values
117
+ * @example text: -> center, left, right, justify
118
+ * @example t: -> center, left, right, justify
119
+ */ if (EachRule.definition.ambiguousKeys?.includes(ruleKey) && EachRule.definition.ambiguousValues?.length) {
120
+ const nativePropertyData = nativeProperties.find((x)=>x.name === EachRule.id);
121
+ for (const ambiguousValue of EachRule.definition.ambiguousValues){
122
+ if (typeof ambiguousValue !== 'string') continue;
123
+ const nativeValueData = nativePropertyData?.values?.find((x)=>x.name === ambiguousValue);
124
+ const isNative = EachRule.definition.layer && [
125
+ Layer.Native,
126
+ Layer.NativeShorthand
127
+ ].includes(EachRule.definition.layer);
128
+ completionItems.push({
129
+ label: ambiguousValue,
130
+ kind: CompletionItemKind.Value,
131
+ sortText: AMBIGUOUS_PRIORITY + ambiguousValue,
132
+ documentation: getCSSDataDocumentation({
133
+ ...nativeValueData || {},
134
+ // use nativePropertyData.reference because nativeValueData does not have references
135
+ references: nativePropertyData?.references
136
+ }, {
137
+ generatedCSS: generateCSS([
138
+ ruleKey + ':' + ambiguousValue
139
+ ], css),
140
+ docs: isCoreRule(EachRule.id) && EachRule.id
141
+ }),
142
+ detail: isNative ? EachRule.id + ': ' + ambiguousValue : ambiguousValue
143
+ });
144
+ }
145
+ }
146
+ }
147
+ /**
148
+ * Native values
149
+ */ if (nativeKey) {
150
+ nativePropertyData?.values?.forEach((value)=>{
151
+ if (completionItems.find((x)=>x.label === value.name) || nativePropertyData.name === 'font' && typeof +value.name === 'number' || value.name.includes(' ')) return;
152
+ completionItems.push({
153
+ label: value.name,
154
+ kind: CompletionItemKind.Value,
155
+ sortText: NATIVE_PRIORITY + (value.name.startsWith('-') ? 'zz' + value.name.slice(1) : value.name),
156
+ documentation: getCSSDataDocumentation({
157
+ ...value,
158
+ // use nativePropertyData.reference because nativeValueData does not have references
159
+ references: nativePropertyData?.references
160
+ }, {
161
+ generatedCSS: generateCSS([
162
+ ruleKey + ':' + value.name
163
+ ], css),
164
+ docs: nativeKey
165
+ }),
166
+ detail: nativeKey + ': ' + value.name
167
+ });
168
+ });
169
+ }
170
+ // global variables
171
+ for(const variableName in css.variables){
172
+ const variable = css.variables[variableName];
173
+ const completionItem = generateVariableCompletionItem(variable);
174
+ if (completionItem) {
175
+ completionItem.sortText = GLOBAL_VARIABLE_PRIORITY + (completionItem.sortText || completionItem.label);
176
+ completionItem.detail = '(global) ' + completionItem.detail;
177
+ completionItems.push(completionItem);
178
+ }
179
+ }
180
+ return sortCompletionItems(completionItems);
181
+ }
182
+
183
+ export { getValueCompletionItems as default };
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ var vscodeLanguageserverProtocol = require('vscode-languageserver-protocol');
4
+ var getPseudoClassCompletionItems = require('./get-pseudo-class-completion-items.cjs');
5
+ var getPseudoElementCompletionItems = require('./get-pseudo-element-completion-items.cjs');
6
+ var css = require('@master/css');
7
+ var common = require('../common.cjs');
8
+ var getMainCompletionItems = require('./get-main-completion-items.cjs');
9
+ var getValueCompletionItems = require('./get-value-completion-items.cjs');
10
+ var getQueryCompletionItems = require('./get-query-completion-items.cjs');
11
+ var getCssDataDocumentation = require('./get-css-data-documentation.cjs');
12
+
13
+ function querySyntaxCompletions(q = '', css$1 = new css.MasterCSS()) {
14
+ const fields = q.split(' ');
15
+ let field = fields[fields.length - 1];
16
+ const triggerCharacter = q.charAt(q.length - 1);
17
+ const invoked = triggerCharacter === ' ' || field.length === 0;
18
+ if (invoked || field === common.GROUP_TRIGGER_CHARACTER || triggerCharacter === ';') {
19
+ return getMainCompletionItems(css$1);
20
+ }
21
+ const isGroup = field.startsWith(common.GROUP_TRIGGER_CHARACTER);
22
+ if (isGroup) {
23
+ const declarationSeparatorMatches = Array.from(field.matchAll(/;(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/g));
24
+ if (declarationSeparatorMatches.length) {
25
+ field = field.slice(declarationSeparatorMatches[declarationSeparatorMatches.length - 1].index + 1);
26
+ } else {
27
+ field = field.slice(1);
28
+ }
29
+ }
30
+ const signs = css$1.Rules.filter(({ definition })=>definition.sign).map(({ definition })=>definition.sign);
31
+ const keyMatch = field.match(new RegExp(`^[^${signs}'":\\s]+:`));
32
+ const atMatches = Array.from(field.matchAll(/@(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/g));
33
+ const valueSeparatorMatch = field.match(/\|(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/g);
34
+ const atInvoked = atMatches.findIndex(({ index })=>index !== 0) !== -1;
35
+ const firstColonIndex = keyMatch ? keyMatch[0].length - 1 : -1;
36
+ const selectorInvokedRegex = new RegExp(`[${css.SELECTOR_SIGNS.join('')}](?=(?:[^'"]|'[^']*'|"[^"]*")*$)`);
37
+ const key = keyMatch ? keyMatch[0].slice(0, firstColonIndex) : undefined;
38
+ const styleNames = Object.keys(css$1.config.styles || {});
39
+ const utilityNames = Object.keys(css$1.config.utilities || {});
40
+ const isStyle = !!styleNames.find((eachStyleName)=>new RegExp(`^${eachStyleName}(?:\\b|_)`).test(field));
41
+ const isUtility = !!utilityNames.find((eachUtilityName)=>new RegExp(`^${eachUtilityName}(?:\\b|_)`).test(field));
42
+ // check by utilities and styles
43
+ if (!isStyle && !isUtility) {
44
+ if (key === undefined && !valueSeparatorMatch) {
45
+ /**
46
+ * The server capability sets '@' '~' as the trigger characters for at and adjacent selectors,
47
+ * but these two characters are also the prefix symbols of `animation` and `transition`,
48
+ * and should be filtered to prevent hints all completions items.
49
+ * @example class="@"
50
+ * @example class="~"
51
+ */ if (field.startsWith(css.ANIMATION_SIGN) || field.startsWith(css.TRANSITION_SIGN)) {
52
+ return getMainCompletionItems(css$1).filter((completionItem)=>completionItem.label.startsWith(field)).map((completionItem)=>({
53
+ ...completionItem,
54
+ label: completionItem.label.slice(1)
55
+ }));
56
+ }
57
+ return getMainCompletionItems(css$1);
58
+ }
59
+ if (!atInvoked && !selectorInvokedRegex.test(field.slice(firstColonIndex + 1))) {
60
+ if (field.startsWith(css.ANIMATION_SIGN) && firstColonIndex === -1) {
61
+ return getValueCompletionItems(css$1, 'animation');
62
+ } else if (field.startsWith(css.TRANSITION_SIGN) && firstColonIndex === -1) {
63
+ return getValueCompletionItems(css$1, 'transition');
64
+ } else if (key && firstColonIndex !== -1) {
65
+ return getValueCompletionItems(css$1, key);
66
+ }
67
+ }
68
+ }
69
+ /**
70
+ * Not support conditional btn:hover and group
71
+ */ if (isStyle || isGroup) return;
72
+ if (atInvoked && [
73
+ css.AT_SIGN,
74
+ ...css.QUERY_COMPARISON_OPERATORS,
75
+ ...css.QUERY_LOGICAL_OPERATORS
76
+ ].includes(triggerCharacter)) {
77
+ return getQueryCompletionItems(css$1, triggerCharacter, field);
78
+ }
79
+ if (!atInvoked && common.SELECTOR_TRIGGER_CHARACTERS.includes(triggerCharacter)) {
80
+ const pseudoElementCompletionItems = getPseudoElementCompletionItems(css$1, field);
81
+ if (field.endsWith('::')) {
82
+ /**
83
+ * Consider trigger characters and fix insertText.
84
+ * @incorrect class="text:center::" -> class="text:center::::after"
85
+ * @correct class="text:center::" -> class="text:center::after"
86
+ */ pseudoElementCompletionItems.forEach((completionItem)=>completionItem.insertText = completionItem.label.slice(2));
87
+ return pseudoElementCompletionItems;
88
+ } else {
89
+ const completionItems = getPseudoClassCompletionItems(css$1, field);
90
+ completionItems.push(...pseudoElementCompletionItems);
91
+ /**
92
+ * Consider trigger characters and fix insertText.
93
+ * @incorrect class="text:center:" -> class="text:center::active"
94
+ * @correct class="text:center:" -> class="text:center:active"
95
+ */ if (triggerCharacter === ':') {
96
+ completionItems.forEach((completionItem)=>completionItem.insertText = completionItem.label.slice(1));
97
+ } else {
98
+ completionItems.push({
99
+ label: '.<class>',
100
+ insertText: '.',
101
+ documentation: getCssDataDocumentation.getCSSDataDocumentation(undefined, {
102
+ generatedCSS: css.generateCSS([
103
+ field + '.class'
104
+ ], css$1),
105
+ docs: 'selectors'
106
+ }),
107
+ kind: vscodeLanguageserverProtocol.CompletionItemKind.Class
108
+ });
109
+ }
110
+ return completionItems;
111
+ }
112
+ }
113
+ }
114
+
115
+ module.exports = querySyntaxCompletions;
@@ -0,0 +1,3 @@
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;
@@ -0,0 +1,113 @@
1
+ import { CompletionItemKind } from 'vscode-languageserver-protocol';
2
+ import getPseudoClassCompletionItems from './get-pseudo-class-completion-items.mjs';
3
+ import getPseudoElementCompletionItems from './get-pseudo-element-completion-items.mjs';
4
+ import { SELECTOR_SIGNS, ANIMATION_SIGN, TRANSITION_SIGN, AT_SIGN, QUERY_COMPARISON_OPERATORS, QUERY_LOGICAL_OPERATORS, generateCSS, MasterCSS } from '@master/css';
5
+ import { GROUP_TRIGGER_CHARACTER, SELECTOR_TRIGGER_CHARACTERS } from '../common.mjs';
6
+ import getMainCompletionItems from './get-main-completion-items.mjs';
7
+ import getValueCompletionItems from './get-value-completion-items.mjs';
8
+ import getQueryCompletionItems from './get-query-completion-items.mjs';
9
+ import { getCSSDataDocumentation } from './get-css-data-documentation.mjs';
10
+
11
+ function querySyntaxCompletions(q = '', css = new MasterCSS()) {
12
+ const fields = q.split(' ');
13
+ let field = fields[fields.length - 1];
14
+ const triggerCharacter = q.charAt(q.length - 1);
15
+ const invoked = triggerCharacter === ' ' || field.length === 0;
16
+ if (invoked || field === GROUP_TRIGGER_CHARACTER || triggerCharacter === ';') {
17
+ return getMainCompletionItems(css);
18
+ }
19
+ const isGroup = field.startsWith(GROUP_TRIGGER_CHARACTER);
20
+ if (isGroup) {
21
+ const declarationSeparatorMatches = Array.from(field.matchAll(/;(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/g));
22
+ if (declarationSeparatorMatches.length) {
23
+ field = field.slice(declarationSeparatorMatches[declarationSeparatorMatches.length - 1].index + 1);
24
+ } else {
25
+ field = field.slice(1);
26
+ }
27
+ }
28
+ const signs = css.Rules.filter(({ definition })=>definition.sign).map(({ definition })=>definition.sign);
29
+ const keyMatch = field.match(new RegExp(`^[^${signs}'":\\s]+:`));
30
+ const atMatches = Array.from(field.matchAll(/@(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/g));
31
+ const valueSeparatorMatch = field.match(/\|(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/g);
32
+ const atInvoked = atMatches.findIndex(({ index })=>index !== 0) !== -1;
33
+ const firstColonIndex = keyMatch ? keyMatch[0].length - 1 : -1;
34
+ const selectorInvokedRegex = new RegExp(`[${SELECTOR_SIGNS.join('')}](?=(?:[^'"]|'[^']*'|"[^"]*")*$)`);
35
+ const key = keyMatch ? keyMatch[0].slice(0, firstColonIndex) : undefined;
36
+ const styleNames = Object.keys(css.config.styles || {});
37
+ const utilityNames = Object.keys(css.config.utilities || {});
38
+ const isStyle = !!styleNames.find((eachStyleName)=>new RegExp(`^${eachStyleName}(?:\\b|_)`).test(field));
39
+ const isUtility = !!utilityNames.find((eachUtilityName)=>new RegExp(`^${eachUtilityName}(?:\\b|_)`).test(field));
40
+ // check by utilities and styles
41
+ if (!isStyle && !isUtility) {
42
+ if (key === undefined && !valueSeparatorMatch) {
43
+ /**
44
+ * The server capability sets '@' '~' as the trigger characters for at and adjacent selectors,
45
+ * but these two characters are also the prefix symbols of `animation` and `transition`,
46
+ * and should be filtered to prevent hints all completions items.
47
+ * @example class="@"
48
+ * @example class="~"
49
+ */ if (field.startsWith(ANIMATION_SIGN) || field.startsWith(TRANSITION_SIGN)) {
50
+ return getMainCompletionItems(css).filter((completionItem)=>completionItem.label.startsWith(field)).map((completionItem)=>({
51
+ ...completionItem,
52
+ label: completionItem.label.slice(1)
53
+ }));
54
+ }
55
+ return getMainCompletionItems(css);
56
+ }
57
+ if (!atInvoked && !selectorInvokedRegex.test(field.slice(firstColonIndex + 1))) {
58
+ if (field.startsWith(ANIMATION_SIGN) && firstColonIndex === -1) {
59
+ return getValueCompletionItems(css, 'animation');
60
+ } else if (field.startsWith(TRANSITION_SIGN) && firstColonIndex === -1) {
61
+ return getValueCompletionItems(css, 'transition');
62
+ } else if (key && firstColonIndex !== -1) {
63
+ return getValueCompletionItems(css, key);
64
+ }
65
+ }
66
+ }
67
+ /**
68
+ * Not support conditional btn:hover and group
69
+ */ if (isStyle || isGroup) return;
70
+ if (atInvoked && [
71
+ AT_SIGN,
72
+ ...QUERY_COMPARISON_OPERATORS,
73
+ ...QUERY_LOGICAL_OPERATORS
74
+ ].includes(triggerCharacter)) {
75
+ return getQueryCompletionItems(css, triggerCharacter, field);
76
+ }
77
+ if (!atInvoked && SELECTOR_TRIGGER_CHARACTERS.includes(triggerCharacter)) {
78
+ const pseudoElementCompletionItems = getPseudoElementCompletionItems(css, field);
79
+ if (field.endsWith('::')) {
80
+ /**
81
+ * Consider trigger characters and fix insertText.
82
+ * @incorrect class="text:center::" -> class="text:center::::after"
83
+ * @correct class="text:center::" -> class="text:center::after"
84
+ */ pseudoElementCompletionItems.forEach((completionItem)=>completionItem.insertText = completionItem.label.slice(2));
85
+ return pseudoElementCompletionItems;
86
+ } else {
87
+ const completionItems = getPseudoClassCompletionItems(css, field);
88
+ completionItems.push(...pseudoElementCompletionItems);
89
+ /**
90
+ * Consider trigger characters and fix insertText.
91
+ * @incorrect class="text:center:" -> class="text:center::active"
92
+ * @correct class="text:center:" -> class="text:center:active"
93
+ */ if (triggerCharacter === ':') {
94
+ completionItems.forEach((completionItem)=>completionItem.insertText = completionItem.label.slice(1));
95
+ } else {
96
+ completionItems.push({
97
+ label: '.<class>',
98
+ insertText: '.',
99
+ documentation: getCSSDataDocumentation(undefined, {
100
+ generatedCSS: generateCSS([
101
+ field + '.class'
102
+ ], css),
103
+ docs: 'selectors'
104
+ }),
105
+ kind: CompletionItemKind.Class
106
+ });
107
+ }
108
+ return completionItems;
109
+ }
110
+ }
111
+ }
112
+
113
+ export { querySyntaxCompletions as default };
@@ -1,5 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const instancePattern = /[^\s:]+:\w*\(?((?<!\\)["'`])((?:\\\1|(?:(?!\1))[\S\s])*)((?<!\\)\1)\)?|[^\s"'`]+/g;
3
+ const instancePattern = /[^\s:]+:\w*\(?((?<!\\)["'`])((?:\\\1|(?:(?!\1))\S)*)((?<!\\)\1)\)?|[^\s"'`]+/g;
4
4
 
5
5
  exports.instancePattern = instancePattern;
@@ -1,3 +1,3 @@
1
- const instancePattern = /[^\s:]+:\w*\(?((?<!\\)["'`])((?:\\\1|(?:(?!\1))[\S\s])*)((?<!\\)\1)\)?|[^\s"'`]+/g;
1
+ const instancePattern = /[^\s:]+:\w*\(?((?<!\\)["'`])((?:\\\1|(?:(?!\1))\S)*)((?<!\\)\1)\)?|[^\s"'`]+/g;
2
2
 
3
3
  export { instancePattern };
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ /* localeCompare equals to the real vscode completion items sorting */ function sortCompletionItems(items) {
4
+ return items.sort((a, b)=>{
5
+ const sortTextA = a.sortText || a.label;
6
+ const sortTextB = b.sortText || b.label;
7
+ return sortTextA.localeCompare(sortTextB);
8
+ });
9
+ }
10
+
11
+ module.exports = sortCompletionItems;
@@ -0,0 +1,2 @@
1
+ import type { CompletionItem } from 'vscode-languageserver-protocol';
2
+ export default function sortCompletionItems(items: CompletionItem[]): CompletionItem[];
@@ -0,0 +1,9 @@
1
+ /* localeCompare equals to the real vscode completion items sorting */ function sortCompletionItems(items) {
2
+ return items.sort((a, b)=>{
3
+ const sortTextA = a.sortText || a.label;
4
+ const sortTextB = b.sortText || b.label;
5
+ return sortTextA.localeCompare(sortTextB);
6
+ });
7
+ }
8
+
9
+ export { sortCompletionItems as default };
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@master/css-language-service","type":"module","scripts":{"build":"techor build \"src/**/*.ts\"","dev":"pnpm build --watch","type-check":"tsc --noEmit","lint":"eslint src"},"description":"Master CSS Language Service","author":"Aoyue Design LLC.","license":"MIT","repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/language-service"},"dependencies":{"@babel/parser":"^7.23.9","@master/css":"^2.0.0-rc.26","color-convert":"^2.0.1","js-beautify":"^1.15.1","vscode-css-languageservice":"^6.2.12"},"devDependencies":{"@types/color-convert":"^2.0.3","vscode-languageserver-types":"^3.17.5"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.mjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs","types":"./dist/index.d.ts"},"./settings":{"import":"./dist/settings/index.mjs","require":"./dist/settings/index.cjs","types":"./dist/settings/index.d.ts"}},"typesVersions":{"*":{"./":["./dist/index.d.ts"],"./settings":["./dist/settings.d.ts"]}},"files":["dist"],"publishConfig":{"access":"public","provenance":true},"version":"2.0.0-rc.26"}
1
+ {"name":"@master/css-language-service","type":"module","scripts":{"build":"techor build \"src/**/*.ts\"","dev":"pnpm build --watch","type-check":"tsc --noEmit","lint":"eslint src","test":"jest"},"description":"Master CSS Language Service","author":"Aoyue Design LLC.","license":"MIT","repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/language-service"},"dependencies":{"@babel/parser":"^7.24.1","@master/css":"^2.0.0-rc.27","@techor/extend":"^3.0.18","color-convert":"^2.0.1","color-rgba":"^3.0.0","color-space":"^2.0.1","culori":"^4.0.1","js-beautify":"^1.15.1","lodash.escaperegexp":"^4.1.2","minimatch":"^9.0.3","pex-color":"^2.1.0","vscode-css-languageservice":"^6.2.13","vscode-languageserver-protocol":"^3.17.5","vscode-languageserver-textdocument":"^1.0.11"},"devDependencies":{"@types/chroma-js":"^2.4.4","@types/color-convert":"^2.0.3","@types/color-rgba":"^2.1.2","@types/culori":"^2.1.0","@types/lodash.escaperegexp":"^4.1.9","@types/vscode":"^1.87.0","@master/css-shared":"^2.0.0-rc.27","vscode-languageserver":"^7.0.0"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.mjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs","types":"./dist/index.d.ts"}},"files":["dist"],"publishConfig":{"access":"public","provenance":true},"version":"2.0.0-rc.27"}