@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,13 +1,13 @@
1
1
  import querySyntaxCompletions from '../utils/query-syntax-completions.mjs';
2
2
 
3
- function suggestSyntax(document, position, context) {
3
+ function suggestSyntax(document, position, context, completionIndex) {
4
4
  const classPosition = this.getClassPosition(document, position);
5
5
  if (classPosition !== undefined) {
6
6
  const q = context?.triggerCharacter === ' ' ? '' : document.getText({
7
7
  start: document.positionAt(classPosition.range.start),
8
8
  end: position
9
9
  });
10
- return querySyntaxCompletions(q, this.css);
10
+ return querySyntaxCompletions(q, this.css, completionIndex);
11
11
  }
12
12
  // todo
13
13
  // else if (isInstance === true && checkConfigColorsBlock(document, position) === true) {
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  export { default as CSSLanguageService, default } from './core.mjs';
2
2
  export { default as settings } from './settings.mjs';
3
- export { AT_TRIGGER_CHARACTER, DECLARATION_SEPARATOR_TRIGGER_CHARACTER, GROUP_TRIGGER_CHARACTER, INVOKED_TRIGGER_CHARACTERS, QUERY_TRIGGER_CHARACTERS, SELECTOR_TRIGGER_CHARACTERS, SERVER_CAPABILITIES, VALUE_TRIGGER_CHARACTERS } from './common.mjs';
4
3
  export { default as inspectSyntax } from './features/inspect-syntax.mjs';
5
4
  export { default as renderSyntaxColors } from './features/render-syntax-colors.mjs';
6
5
  export { default as editSyntaxColors } from './features/edit-syntax-colors.mjs';
7
6
  export { default as suggestSyntax } from './features/suggest-syntax.mjs';
7
+ export { AT_TRIGGER_CHARACTER, DECLARATION_SEPARATOR_TRIGGER_CHARACTER, GROUP_TRIGGER_CHARACTER, INVOKED_TRIGGER_CHARACTERS, QUERY_TRIGGER_CHARACTERS, SELECTOR_TRIGGER_CHARACTERS, VALUE_TRIGGER_CHARACTERS } from '@master/css-language';
@@ -1,17 +1,14 @@
1
- import { Config } from '@master/css';
1
+ import { type LanguageSettings } from '@master/css-language';
2
+ import type { MasterCSSManifest } from '@master/css';
2
3
  /**
3
4
  * @example styles https://regex101.com/r/HLPdsw/1
4
5
  **/
5
6
  declare const settings: Settings;
6
7
  export default settings;
7
- export declare interface Settings {
8
+ export declare interface Settings extends LanguageSettings {
8
9
  includedLanguages?: string[];
9
- classAttributes?: string[];
10
- classFunctions?: string[];
11
- classDeclarations?: string[];
12
- classAttributeBindings?: Record<string, [string, string] | false>;
13
10
  exclude?: string[];
14
- config?: Config;
11
+ manifest?: MasterCSSManifest;
15
12
  suggestSyntax?: boolean;
16
13
  inspectSyntax?: boolean;
17
14
  renderSyntaxColors?: boolean;
package/dist/settings.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { CLASS_FUNCTIONS, CLASS_DECLARATIONS, CLASS_ATTRIBUTES } from '@master/css';
1
+ import { languageSettings } from '@master/css-language';
2
2
 
3
3
  /**
4
4
  * @example styles https://regex101.com/r/HLPdsw/1
@@ -10,6 +10,9 @@ import { CLASS_FUNCTIONS, CLASS_DECLARATIONS, CLASS_ATTRIBUTES } from '@master/c
10
10
  "typescript",
11
11
  "javascriptreact",
12
12
  "typescriptreact",
13
+ "css",
14
+ "scss",
15
+ "less",
13
16
  "vue",
14
17
  "svelte",
15
18
  "rust",
@@ -21,53 +24,20 @@ import { CLASS_FUNCTIONS, CLASS_DECLARATIONS, CLASS_ATTRIBUTES } from '@master/c
21
24
  /**
22
25
  * @example <div class="a b">
23
26
  * @example <div className="a b">
24
- */ classAttributes: CLASS_ATTRIBUTES,
27
+ */ classAttributes: languageSettings.classAttributes,
25
28
  /**
26
29
  * @example <div class={active ? 'a' : 'b'}>
27
30
  * @example <div className={active ? 'a' : 'b'}>
28
- */ classAttributeBindings: {
29
- "className": [
30
- "{",
31
- "}"
32
- ],
33
- "class": [
34
- "{",
35
- "}"
36
- ],
37
- "class:list": [
38
- "{",
39
- "}"
40
- ],
41
- ":class": [
42
- "\"",
43
- "\""
44
- ],
45
- "v-bind:class": [
46
- "\"",
47
- "\""
48
- ],
49
- "[class]": [
50
- "\"",
51
- "\""
52
- ],
53
- "[className]": [
54
- "\"",
55
- "\""
56
- ],
57
- "[ngClass]": [
58
- "\"",
59
- "\""
60
- ]
61
- },
31
+ */ classAttributeBindings: languageSettings.classAttributeBindings,
62
32
  /**
63
- * @example const components = 'a b'
64
- * @example { components: { btn: 'a b' } }
65
- */ classDeclarations: CLASS_DECLARATIONS,
33
+ * @example const classes = 'a b'
34
+ * @example { classes: { btn: 'a b' } }
35
+ */ classDeclarations: languageSettings.classDeclarations,
66
36
  /**
67
37
  * @example clsx('a b')
68
38
  * @example styled`a b`
69
39
  * @example .classList.add('a')
70
- */ classFunctions: CLASS_FUNCTIONS,
40
+ */ classFunctions: languageSettings.classFunctions,
71
41
  exclude: [
72
42
  "**/.git/**",
73
43
  "**/node_modules/**",
@@ -76,7 +46,8 @@ import { CLASS_FUNCTIONS, CLASS_DECLARATIONS, CLASS_ATTRIBUTES } from '@master/c
76
46
  suggestSyntax: true,
77
47
  inspectSyntax: true,
78
48
  renderSyntaxColors: true,
79
- editSyntaxColors: true
49
+ editSyntaxColors: true,
50
+ embeddedSyntaxHighlighting: 'active'
80
51
  };
81
52
 
82
53
  export { settings as default };
@@ -1,4 +1,4 @@
1
- import { css_beautify } from 'js-beautify/js/lib/beautify-css';
1
+ import { css_beautify } from 'js-beautify/js/lib/beautify-css.js';
2
2
 
3
3
  // @ts-expect-error
4
4
  function beautifyCSS(text) {
@@ -0,0 +1,38 @@
1
+ import { type CompletionItem } from 'vscode-languageserver-protocol';
2
+ import { type AtRule, type MasterCSS } from '@master/css-language';
3
+ import type { Variable } from '@master/css-language';
4
+ export interface ClassCompletionEntry extends CompletionItem {
5
+ documentationClassName?: string;
6
+ }
7
+ export interface PatternValueCandidate {
8
+ value: string;
9
+ }
10
+ export interface ScopedVariableCandidate {
11
+ name: string;
12
+ variable: Variable;
13
+ }
14
+ export interface AnimationUtilityCandidate {
15
+ detailPrefix?: string;
16
+ }
17
+ export interface SelectorVariantCandidate {
18
+ token: string;
19
+ selector: string;
20
+ }
21
+ export interface CompletionIndex {
22
+ classEntries: ClassCompletionEntry[];
23
+ componentNames: string[];
24
+ utilityNames: string[];
25
+ nativeUtilityKeys: Map<string, string>;
26
+ scopedVariablesByKey: Map<string, ScopedVariableCandidate[]>;
27
+ patternValuesByKey: Map<string, PatternValueCandidate[]>;
28
+ animationUtilitiesByKey: Map<string, AnimationUtilityCandidate[]>;
29
+ nativeVariableNamespacesByProperty: Map<string, string[]>;
30
+ variables: Variable[];
31
+ pseudoClassNames: string[];
32
+ pseudoClassSelectors: SelectorVariantCandidate[];
33
+ pseudoElementNames: string[];
34
+ pseudoElementSelectors: SelectorVariantCandidate[];
35
+ atRules: [string, AtRule][];
36
+ }
37
+ export declare function createCompletionIndex(css?: MasterCSS): CompletionIndex;
38
+ export declare function matchesIndexedName(field: string, name: string): boolean;
@@ -0,0 +1,268 @@
1
+ import { CompletionItemKind } from 'vscode-languageserver-protocol';
2
+ import { builtinNativeValueNamespaces, builtinKeyAliases } from '@master/css-engine';
3
+ import { UtilityType, getMdnPseudoElementNames, getMdnPseudoClassNames, createDefaultCSS } from '@master/css-language';
4
+ import getUtilityInfo from './get-utility-info.mjs';
5
+ import sortCompletionItems from './sort-completion-items.mjs';
6
+
7
+ const ANIMATION_REFERENCE_PROPERTIES = new Set([
8
+ 'animation',
9
+ 'animation-name'
10
+ ]);
11
+ function utilityMayReferenceAnimations(utility) {
12
+ const emit = utility.emit;
13
+ switch(emit.type){
14
+ case 'declarations':
15
+ return emit.declarations.some((property)=>ANIMATION_REFERENCE_PROPERTIES.has(property));
16
+ case 'property':
17
+ return ANIMATION_REFERENCE_PROPERTIES.has(emit.property);
18
+ case 'template':
19
+ return Object.keys(emit.declarations).some((property)=>ANIMATION_REFERENCE_PROPERTIES.has(property));
20
+ case 'static':
21
+ return emit.rules.some((rule)=>Object.keys(rule.declarations).some((property)=>ANIMATION_REFERENCE_PROPERTIES.has(property)));
22
+ default:
23
+ return false;
24
+ }
25
+ }
26
+ function isPureNativePropertyUtility(utility) {
27
+ return utility.emit.type === 'property' && utility.id === utility.emit.property && utility.name === utility.emit.property;
28
+ }
29
+ function addMapValue(map, key, value) {
30
+ const values = map.get(key);
31
+ if (values) {
32
+ values.push(value);
33
+ } else {
34
+ map.set(key, [
35
+ value
36
+ ]);
37
+ }
38
+ }
39
+ function collectClassEntries(css) {
40
+ const completionItems = [];
41
+ const addedKeys = new Set();
42
+ const addedCompletionLabels = new Set();
43
+ const propertyCompletionItem = {
44
+ kind: CompletionItemKind.Property,
45
+ command: {
46
+ title: 'triggerSuggest',
47
+ command: 'editor.action.triggerSuggest'
48
+ }
49
+ };
50
+ const addPropertyCompletionItem = (key, detail)=>{
51
+ const label = key + ':';
52
+ if (addedCompletionLabels.has(label)) return;
53
+ addedCompletionLabels.add(label);
54
+ completionItems.push({
55
+ ...propertyCompletionItem,
56
+ ...detail ? {
57
+ detail
58
+ } : {},
59
+ label,
60
+ sortText: key
61
+ });
62
+ };
63
+ const addSemanticCompletionItem = (label, detail)=>{
64
+ if (addedCompletionLabels.has(label)) return;
65
+ addedCompletionLabels.add(label);
66
+ completionItems.push({
67
+ label,
68
+ kind: CompletionItemKind.Value,
69
+ documentationClassName: label,
70
+ ...detail ? {
71
+ detail
72
+ } : {}
73
+ });
74
+ };
75
+ for (const eachDefinedUtility of css.definedUtilities){
76
+ if (eachDefinedUtility.type === UtilityType.Semantic) {
77
+ const isComponent = eachDefinedUtility.layer === 'components';
78
+ const { detail } = getUtilityInfo(eachDefinedUtility);
79
+ for (const matcher of eachDefinedUtility.matchers){
80
+ if (matcher.type === 'static') {
81
+ addSemanticCompletionItem(matcher.name, isComponent ? 'component' : detail);
82
+ } else if (matcher.type === 'pattern') {
83
+ for (const value of matcher.values){
84
+ addSemanticCompletionItem(matcher.prefix + value, isComponent ? 'component' : undefined);
85
+ }
86
+ }
87
+ }
88
+ } else {
89
+ for (const matcher of eachDefinedUtility.matchers){
90
+ if (matcher.type !== 'pattern') continue;
91
+ for (const value of matcher.values){
92
+ addSemanticCompletionItem(matcher.prefix + value);
93
+ }
94
+ }
95
+ eachDefinedUtility.keys?.forEach((key)=>{
96
+ addedKeys.delete(key);
97
+ addPropertyCompletionItem(key);
98
+ });
99
+ if (eachDefinedUtility.aliasGroups?.length) {
100
+ for (const aliasGroup of eachDefinedUtility.aliasGroups){
101
+ if (addedKeys.has(aliasGroup)) {
102
+ continue;
103
+ }
104
+ addedKeys.add(aliasGroup);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ for (const [key, canonicalKey] of Object.entries(builtinKeyAliases)){
110
+ addPropertyCompletionItem(key, canonicalKey);
111
+ }
112
+ for (const namespace of builtinNativeValueNamespaces){
113
+ for (const property of namespace.properties){
114
+ addPropertyCompletionItem(property);
115
+ }
116
+ }
117
+ addedKeys.forEach((aliasGroup)=>{
118
+ /**
119
+ * Ambiguous keys are added to the completion list
120
+ * @example text: t:
121
+ */ if (addedCompletionLabels.has(aliasGroup + ':')) return;
122
+ completionItems.push({
123
+ ...propertyCompletionItem,
124
+ detail: 'ambiguous key',
125
+ label: aliasGroup + ':',
126
+ sortText: aliasGroup
127
+ });
128
+ });
129
+ return sortCompletionItems(completionItems);
130
+ }
131
+ function createPseudoClassSelectors(css) {
132
+ const selectors = new Map([
133
+ [
134
+ ':of',
135
+ ':of'
136
+ ]
137
+ ]);
138
+ for (const [token, branches] of css.variants){
139
+ const selector = branches.find((branch)=>branch.selector)?.selector;
140
+ if (selector && token.startsWith(':') && !token.startsWith('::')) {
141
+ selectors.set(token, selector);
142
+ }
143
+ }
144
+ return Array.from(selectors, ([token, selector])=>({
145
+ token,
146
+ selector
147
+ }));
148
+ }
149
+ function createPseudoElementSelectors(css) {
150
+ const selectors = [];
151
+ for (const [token, branches] of css.variants){
152
+ const selector = branches.find((branch)=>branch.selector)?.selector;
153
+ if (selector && token.startsWith('::')) {
154
+ selectors.push({
155
+ token,
156
+ selector
157
+ });
158
+ }
159
+ }
160
+ return selectors;
161
+ }
162
+ function createNativeVariableNamespacesByProperty() {
163
+ const namespacesByProperty = new Map();
164
+ for (const namespace of builtinNativeValueNamespaces){
165
+ const variableNamespaces = (namespace.variableAliasRefs || []).map((ref)=>ref[0] === '=' || ref[0] === '~' ? ref.slice(1) : '').filter(Boolean);
166
+ if (!variableNamespaces.length) continue;
167
+ for (const property of namespace.properties){
168
+ const namespaces = namespacesByProperty.get(property);
169
+ if (namespaces) {
170
+ namespaces.push(...variableNamespaces);
171
+ } else {
172
+ namespacesByProperty.set(property, [
173
+ ...variableNamespaces
174
+ ]);
175
+ }
176
+ }
177
+ }
178
+ return namespacesByProperty;
179
+ }
180
+ function createCompletionIndex(css = createDefaultCSS()) {
181
+ const componentNames = [];
182
+ const utilityNames = [];
183
+ const nativeUtilityKeys = new Map();
184
+ const scopedVariablesByKey = new Map();
185
+ const patternValuesByKey = new Map();
186
+ const animationUtilitiesByKey = new Map();
187
+ for (const utility of css.definedUtilities){
188
+ const staticNames = utility.type === UtilityType.Semantic ? utilityNames : undefined;
189
+ for (const matcher of utility.matchers){
190
+ if (matcher.type === 'static') {
191
+ staticNames?.push(matcher.name);
192
+ if (utility.type === UtilityType.Semantic && utility.layer === 'components') {
193
+ componentNames.push(matcher.name);
194
+ }
195
+ } else if (matcher.type === 'pattern') {
196
+ const patternNames = matcher.values.map((value)=>matcher.prefix + value);
197
+ utilityNames.push(...patternNames);
198
+ if (utility.type === UtilityType.Semantic && utility.layer === 'components') {
199
+ componentNames.push(...patternNames);
200
+ }
201
+ if (matcher.prefix.endsWith(':')) {
202
+ const key = matcher.prefix.slice(0, -1);
203
+ for (const value of matcher.values){
204
+ addMapValue(patternValuesByKey, key, {
205
+ value
206
+ });
207
+ }
208
+ }
209
+ }
210
+ }
211
+ for (const key of utility.keys || []){
212
+ if (!nativeUtilityKeys.has(key)) {
213
+ nativeUtilityKeys.set(key, utility.emit.type === 'property' ? utility.emit.property : utility.id);
214
+ }
215
+ }
216
+ if (utility.variables?.size) {
217
+ const keys = new Set([
218
+ utility.key,
219
+ utility.subkey,
220
+ ...utility.keys || [],
221
+ ...utility.aliasGroups || []
222
+ ].filter((key)=>Boolean(key)));
223
+ for (const key of keys){
224
+ utility.variables.forEach((variable, name)=>{
225
+ addMapValue(scopedVariablesByKey, key, {
226
+ name,
227
+ variable
228
+ });
229
+ });
230
+ }
231
+ }
232
+ if (utility.keys?.length && utilityMayReferenceAnimations(utility)) {
233
+ const detailPrefix = isPureNativePropertyUtility(utility) ? utility.id : undefined;
234
+ for (const key of utility.keys){
235
+ addMapValue(animationUtilitiesByKey, key, {
236
+ detailPrefix
237
+ });
238
+ }
239
+ }
240
+ }
241
+ return {
242
+ classEntries: collectClassEntries(css),
243
+ componentNames,
244
+ utilityNames,
245
+ nativeUtilityKeys,
246
+ scopedVariablesByKey,
247
+ patternValuesByKey,
248
+ animationUtilitiesByKey,
249
+ nativeVariableNamespacesByProperty: createNativeVariableNamespacesByProperty(),
250
+ variables: Array.from(css.variables.values()),
251
+ pseudoClassNames: getMdnPseudoClassNames(),
252
+ pseudoClassSelectors: createPseudoClassSelectors(css),
253
+ pseudoElementNames: getMdnPseudoElementNames(),
254
+ pseudoElementSelectors: createPseudoElementSelectors(css),
255
+ atRules: Array.from(css.atRules.entries())
256
+ };
257
+ }
258
+ function matchesIndexedName(field, name) {
259
+ if (!field.startsWith(name)) return false;
260
+ const nextCharacter = field.charAt(name.length);
261
+ if (nextCharacter === '_') return true;
262
+ const lastCharacter = name.charAt(name.length - 1);
263
+ const lastIsWord = /\w/.test(lastCharacter);
264
+ const nextIsWord = /\w/.test(nextCharacter);
265
+ return lastIsWord !== nextIsWord;
266
+ }
267
+
268
+ export { createCompletionIndex, matchesIndexedName };
@@ -1,4 +1,4 @@
1
- import type { MasterCSS } from '@master/css';
1
+ import type { MasterCSS } from '@master/css-language';
2
2
  import type { ColorPresentationParams } from 'vscode-languageserver-protocol';
3
3
  export default function convertColorByToken(color: ColorPresentationParams['color'], colorToken: string, css: MasterCSS): string | undefined;
4
4
  export declare function normalizeCSSColorFunctionName(fn: string): string;
@@ -8,7 +8,7 @@ function convertColorByToken(color, colorToken, css) {
8
8
  outputSpace = valueComponent.name;
9
9
  break;
10
10
  case 'variable':
11
- outputSpace = valueComponent.variable?.space;
11
+ outputSpace = String(valueComponent.variable?.value || '').match(/^([a-zA-Z][\w-]*)\(/)?.[1] || outputSpace;
12
12
  break;
13
13
  case 'string':
14
14
  outputSpace = 'srgb';
@@ -0,0 +1,5 @@
1
+ export interface CSSMarkdownDocumentation {
2
+ kind: 'markdown';
3
+ value: string;
4
+ }
5
+ export default function createCSSMarkdownDocumentation(css: string): CSSMarkdownDocumentation | undefined;
@@ -0,0 +1,15 @@
1
+ import beautifyCSS from './beautify-css.mjs';
2
+
3
+ function createCSSMarkdownDocumentation(css) {
4
+ if (!css) return;
5
+ const cssLines = beautifyCSS(css).split('\n');
6
+ if (cssLines[0] === '') {
7
+ cssLines.shift();
8
+ }
9
+ return {
10
+ kind: 'markdown',
11
+ value: '```css\n' + cssLines.join('\n') + '\n```'
12
+ };
13
+ }
14
+
15
+ export { createCSSMarkdownDocumentation as default };
@@ -0,0 +1,4 @@
1
+ import { type CompletionItem } from 'vscode-languageserver-protocol';
2
+ import { MasterCSS } from '@master/css-language';
3
+ import { type CompletionIndex } from './completion-index';
4
+ export default function getClassCompletionItems(css?: MasterCSS, completionIndex?: CompletionIndex): CompletionItem[];
@@ -0,0 +1,20 @@
1
+ import { createDefaultCSS, generateCSS } from '@master/css-language';
2
+ import createCSSMarkdownDocumentation from './create-css-markdown-documentation.mjs';
3
+ import { createCompletionIndex } from './completion-index.mjs';
4
+
5
+ function createCompletionItem(css, entry) {
6
+ const { documentationClassName, ...completionItem } = entry;
7
+ return {
8
+ ...completionItem,
9
+ ...documentationClassName ? {
10
+ documentation: createCSSMarkdownDocumentation(generateCSS([
11
+ documentationClassName
12
+ ], css))
13
+ } : {}
14
+ };
15
+ }
16
+ function getClassCompletionItems(css = createDefaultCSS(), completionIndex = createCompletionIndex(css)) {
17
+ return completionIndex.classEntries.map((entry)=>createCompletionItem(css, entry));
18
+ }
19
+
20
+ export { getClassCompletionItems as default };
@@ -1,3 +1,3 @@
1
- import { MasterCSS } from '@master/css';
1
+ import { MasterCSS } from '@master/css-language';
2
2
  import { type CompletionItem } from 'vscode-languageserver-protocol';
3
3
  export default function getColorCompletionItems(css?: MasterCSS): CompletionItem[];
@@ -1,21 +1,18 @@
1
- import { createCSS } from '@master/css';
1
+ import { createDefaultCSS } from '@master/css-language';
2
2
  import { CompletionItemKind } from 'vscode-languageserver-protocol';
3
3
  import sortCompletionItems from './sort-completion-items.mjs';
4
4
 
5
- function getColorCompletionItems(css = createCSS()) {
5
+ function getColorCompletionItems(css = createDefaultCSS()) {
6
6
  const completionItems = [];
7
7
  css.variables.forEach((eachVariable, eachVariableName)=>{
8
- if (eachVariable.type === 'color') {
9
- // todo: packages/core should support getTextByVariable(variable)
10
- const valueToken = eachVariable.space && eachVariable.value ? `${eachVariable.space}(${eachVariable.value})` : eachVariable.value;
8
+ if (eachVariable.namespace?.startsWith('color')) {
9
+ const valueToken = eachVariable.value ?? eachVariable.name;
11
10
  completionItems.push({
12
11
  label: eachVariableName,
13
12
  // detail is shown in the detail pane
14
- // todo: eachVariable.token should be recorded as original config variable
15
- detail: valueToken,
13
+ detail: String(valueToken),
16
14
  // documentation is shown in the hover
17
- // todo: should convert and space to rgba
18
- documentation: eachVariable.space && eachVariable.value ? `${eachVariable.space}(${eachVariable.value.split(' ').join(',')})` : eachVariable.value,
15
+ documentation: String(valueToken),
19
16
  kind: CompletionItemKind.Color,
20
17
  sortText: eachVariableName.replace(/(.+?)-(\d+)/, (match, prefix, num)=>prefix + '-' + ('00000' + num).slice(-5))
21
18
  });
@@ -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 getPseudoClassCompletionItems(css: MasterCSS | undefined, syntax: string): CompletionItem[];
3
+ import { type CompletionIndex } from './completion-index';
4
+ export default function getPseudoClassCompletionItems(css: MasterCSS | undefined, syntax: string, completionIndex?: CompletionIndex): CompletionItem[];
@@ -1,61 +1,64 @@
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 getPseudoClassCompletionItems(css = createCSS(), syntax) {
9
- const pseudoClassDataList = cssDataProvider.providePseudoClasses().filter((data)=>{
10
- // exclude @page pseudo-classes
11
- if ([
12
- ':first',
13
- ':left',
14
- ':right',
15
- ':blank'
16
- ].includes(data.name)) return false;
17
- return true;
18
- });
19
- const completionItems = pseudoClassDataList.map((data)=>{
20
- // fix https://github.com/microsoft/vscode-custom-data/issues/78
21
- const name = /:(?:dir|has|is|nth-col|where)/.test(data.name) ? data.name + '()' : data.name;
8
+ const functionalPseudoClassNames = new Set([
9
+ ':current',
10
+ ':dir',
11
+ ':has',
12
+ ':has-slotted',
13
+ ':host',
14
+ ':host-context',
15
+ ':is',
16
+ ':lang',
17
+ ':local-link',
18
+ ':not',
19
+ ':nth',
20
+ ':nth-child',
21
+ ':nth-col',
22
+ ':nth-last',
23
+ ':nth-last-child',
24
+ ':nth-last-col',
25
+ ':nth-last-of-type',
26
+ ':nth-of-type',
27
+ ':of',
28
+ ':state',
29
+ ':where'
30
+ ]);
31
+ function normalizeFunctionalPseudoClass(name) {
32
+ return functionalPseudoClassNames.has(name) ? name + '()' : name;
33
+ }
34
+ function getPseudoClassCompletionItems(css = createDefaultCSS(), syntax, completionIndex = createCompletionIndex(css)) {
35
+ const completionItems = completionIndex.pseudoClassNames.map((pseudoClassName)=>{
36
+ const name = normalizeFunctionalPseudoClass(pseudoClassName);
22
37
  let sortText = name.startsWith(':-') ? 'yyyy' + name.slice(2) : 'yy' + name.replace(/^:/, '');
23
38
  if (sortText.endsWith('()')) sortText = 'y' + sortText;
24
39
  return {
25
40
  label: name,
26
41
  sortText,
27
- documentation: getCSSDataDocumentation(data, {
28
- generatedCSS: generateCSS([
29
- syntax + name.slice(1)
30
- ], css),
31
- docs: '/guide/selectors'
32
- }),
33
- kind,
34
- data
42
+ documentation: createCSSMarkdownDocumentation(generateCSS([
43
+ syntax + name.slice(1)
44
+ ], css)),
45
+ kind
35
46
  };
36
47
  });
37
- const selectors = {
38
- ...css.config.selectors,
39
- ':of': ':of'
40
- };
41
- for(const name in selectors){
48
+ for (const { token: name, selector } of completionIndex.pseudoClassSelectors){
42
49
  if (name.startsWith('::')) continue;
43
- const value = selectors[name];
44
- const data = pseudoClassDataList.find((data)=>value.startsWith(data.name));
45
- let sortText = name.startsWith(':-') ? 'yyyy' + name.slice(2) : 'yy' + name.replace(/^:/, '');
50
+ const value = selector.replace(/&/g, '');
51
+ const label = normalizeFunctionalPseudoClass(name);
52
+ let sortText = label.startsWith(':-') ? 'yyyy' + label.slice(2) : 'yy' + label.replace(/^:/, '');
46
53
  if (sortText.endsWith('()')) sortText = 'y' + sortText;
47
54
  const completionItem = {
48
- label: name,
49
- documentation: getCSSDataDocumentation(data, {
50
- generatedCSS: generateCSS([
51
- syntax + name.slice(1)
52
- ], css),
53
- docs: '/guide/selectors'
54
- }),
55
+ label,
56
+ documentation: createCSSMarkdownDocumentation(generateCSS([
57
+ syntax + label.slice(1)
58
+ ], css)),
55
59
  sortText,
56
60
  kind,
57
- detail: String(value),
58
- data
61
+ detail: String(value)
59
62
  };
60
63
  completionItems.push(completionItem);
61
64
  }