@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.
- package/README.md +57 -6
- package/dist/common.d.ts +1 -9
- package/dist/common.mjs +1 -48
- package/dist/core.d.ts +11 -10
- package/dist/core.mjs +70 -200
- package/dist/features/inspect-syntax.mjs +18 -32
- package/dist/features/render-semantic-tokens.d.ts +5 -0
- package/dist/features/render-semantic-tokens.mjs +10 -0
- package/dist/features/render-syntax-colors.mjs +23 -8
- package/dist/features/suggest-syntax.d.ts +2 -1
- package/dist/features/suggest-syntax.mjs +2 -2
- package/dist/index.mjs +1 -1
- package/dist/settings.d.ts +4 -7
- package/dist/settings.mjs +12 -41
- package/dist/utils/beautify-css.mjs +1 -1
- package/dist/utils/completion-index.d.ts +38 -0
- package/dist/utils/completion-index.mjs +268 -0
- package/dist/utils/convert-color-token.d.ts +1 -1
- package/dist/utils/convert-color-token.mjs +1 -1
- package/dist/utils/create-css-markdown-documentation.d.ts +5 -0
- package/dist/utils/create-css-markdown-documentation.mjs +15 -0
- package/dist/utils/get-class-completion-items.d.ts +4 -0
- package/dist/utils/get-class-completion-items.mjs +20 -0
- package/dist/utils/get-color-completion-items.d.ts +1 -1
- package/dist/utils/get-color-completion-items.mjs +6 -9
- package/dist/utils/get-pseudo-class-completion-items.d.ts +3 -2
- package/dist/utils/get-pseudo-class-completion-items.mjs +45 -42
- package/dist/utils/get-pseudo-element-completion-items.d.ts +3 -2
- package/dist/utils/get-pseudo-element-completion-items.mjs +17 -28
- package/dist/utils/get-query-completion-items.d.ts +3 -2
- package/dist/utils/get-query-completion-items.mjs +19 -32
- package/dist/utils/get-utility-info.d.ts +2 -5
- package/dist/utils/get-utility-info.mjs +4 -16
- package/dist/utils/get-value-completion-items.d.ts +3 -2
- package/dist/utils/get-value-completion-items.mjs +145 -123
- package/dist/utils/query-syntax-completions.d.ts +3 -2
- package/dist/utils/query-syntax-completions.mjs +25 -44
- package/package.json +1 -1
- package/dist/common.cjs +0 -57
- package/dist/core.cjs +0 -246
- package/dist/features/edit-syntax-colors.cjs +0 -19
- package/dist/features/inspect-syntax.cjs +0 -70
- package/dist/features/render-syntax-colors.cjs +0 -89
- package/dist/features/suggest-syntax.cjs +0 -20
- package/dist/index.cjs +0 -29
- package/dist/settings.cjs +0 -84
- package/dist/utils/beautify-css.cjs +0 -13
- package/dist/utils/convert-color-token.cjs +0 -60
- package/dist/utils/create-doc.cjs +0 -26
- package/dist/utils/css-data-provider.cjs +0 -9
- package/dist/utils/css-data-provider.d.ts +0 -3
- package/dist/utils/css-data-provider.mjs +0 -7
- package/dist/utils/find-matching-brackets.cjs +0 -29
- package/dist/utils/find-matching-brackets.d.ts +0 -1
- package/dist/utils/find-matching-brackets.mjs +0 -27
- package/dist/utils/get-color-completion-items.cjs +0 -29
- package/dist/utils/get-css-data-documentation.cjs +0 -88
- package/dist/utils/get-css-data-documentation.d.ts +0 -5
- package/dist/utils/get-css-data-documentation.mjs +0 -86
- package/dist/utils/get-main-completion-items.cjs +0 -106
- package/dist/utils/get-main-completion-items.d.ts +0 -3
- package/dist/utils/get-main-completion-items.mjs +0 -104
- package/dist/utils/get-position.cjs +0 -12
- package/dist/utils/get-pseudo-class-completion-items.cjs +0 -67
- package/dist/utils/get-pseudo-element-completion-items.cjs +0 -56
- package/dist/utils/get-query-completion-items.cjs +0 -92
- package/dist/utils/get-range.cjs +0 -23
- package/dist/utils/get-utility-info.cjs +0 -33
- package/dist/utils/get-value-completion-items.cjs +0 -183
- package/dist/utils/query-syntax-completions.cjs +0 -115
- package/dist/utils/regex.cjs +0 -5
- package/dist/utils/sort-completion-items.cjs +0 -13
package/README.md
CHANGED
|
@@ -48,16 +48,67 @@
|
|
|
48
48
|
<img alt="Follow @mastercorg" src="https://img.shields.io/static/v1?label=%20&message=twitter&color=f6f7f8&logo=twitter&style=for-the-badge">
|
|
49
49
|
</picture>
|
|
50
50
|
</a>
|
|
51
|
-
<a aria-label="Github Actions" href="https://github.com/master-co/css/actions/workflows/release.yml">
|
|
51
|
+
<a aria-label="Github Actions" href="https://github.com/master-co/css/actions/workflows/ci-release.yml">
|
|
52
52
|
<picture>
|
|
53
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
|
|
54
|
-
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
55
|
-
<img alt="Github release actions" src="https://img.shields.io/github/actions/workflow/status/master-co/css/release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
53
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=212022&logo=githubactions&style=for-the-badge">
|
|
54
|
+
<source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
55
|
+
<img alt="Github release actions" src="https://img.shields.io/github/actions/workflow/status/master-co/css/ci-release.yml?branch=rc&label=%20&message=twitter&color=f6f7f8&logo=githubactions&style=for-the-badge&logoColor=%23000">
|
|
56
56
|
</picture>
|
|
57
57
|
</a>
|
|
58
58
|
</p>
|
|
59
59
|
|
|
60
60
|
</div>
|
|
61
61
|
|
|
62
|
-
##
|
|
63
|
-
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install @master/css-language-service
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
import CSSLanguageService from '@master/css-language-service'
|
|
72
|
+
|
|
73
|
+
const languageService = new CSSLanguageService(customSettings)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`CSSLanguageService` provides stateful completion, hover, color, color presentation, and semantic token features around the editor-neutral primitives in `@master/css-language`.
|
|
77
|
+
|
|
78
|
+
### Semantic tokens
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const semanticTokens = languageService.renderSemanticTokens(textDocument)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Semantic tokens are generated with the project manifest, so custom variables, components, utilities, modes, and other manifest-dependent tokens can be classified after the caller loads the manifest.
|
|
85
|
+
|
|
86
|
+
Use `renderSemanticTokensAtPosition()` when a client wants active-only highlighting for the embedded class context at the current editor position.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const semanticTokens = languageService.renderSemanticTokensAtPosition(textDocument, position)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
CSS directive syntax in CSS-family documents is highlighted by the shared TextMate grammar. Semantic tokens are only added for directive class-list spans such as bare `@compose` preludes and quoted `@safelist` strings.
|
|
93
|
+
|
|
94
|
+
## Settings
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
import { settings } from '@master/css-language-service'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
| Setting | Type | Default | Description |
|
|
101
|
+
| --- | --- | --- | --- |
|
|
102
|
+
| `includedLanguages` | `string[]` | Common web and template languages | Language IDs that receive language-service features. |
|
|
103
|
+
| `exclude` | `string[]` | `["**/.git/**", "**/node_modules/**", "**/.hg/**"]` | Glob patterns excluded from all features. |
|
|
104
|
+
| `classAttributes` | `string[]` | `["class", "className"]` | Quoted markup attributes that contain Master CSS class strings. |
|
|
105
|
+
| `classAttributeBindings` | `Record<string, [string, string] \| false>` | Framework binding defaults | Bound attributes such as `:class`, `[ngClass]`, and `class:list`. |
|
|
106
|
+
| `classFunctions` | `string[]` | Common class helpers | Functions and methods whose string arguments contain classes, such as `clsx()` and `classList.add()`. |
|
|
107
|
+
| `classDeclarations` | `string[]` | `[]` | Variable declarations or object properties whose string values contain classes. |
|
|
108
|
+
| `suggestSyntax` | `boolean` | `true` | Enables syntax suggestions. |
|
|
109
|
+
| `inspectSyntax` | `boolean` | `true` | Enables hover inspection and generated CSS previews. |
|
|
110
|
+
| `renderSyntaxColors` | `boolean` | `true` | Enables color rendering. |
|
|
111
|
+
| `editSyntaxColors` | `boolean` | `true` | Enables color editing. |
|
|
112
|
+
| `embeddedSyntaxHighlighting` | `'active' \| 'always' \| 'off'` | `'active'` | Controls embedded semantic token highlighting. |
|
|
113
|
+
|
|
114
|
+
Use `@master/css-language` directly for browser helpers, Shiki integration, TextMate grammar assets, and raw class-position scanning.
|
package/dist/common.d.ts
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const INVOKED_TRIGGER_CHARACTERS: string[];
|
|
3
|
-
export declare const VALUE_TRIGGER_CHARACTERS: string[];
|
|
4
|
-
export declare const SELECTOR_TRIGGER_CHARACTERS: string[];
|
|
5
|
-
export declare const AT_TRIGGER_CHARACTER = "@";
|
|
6
|
-
export declare const QUERY_TRIGGER_CHARACTERS: string[];
|
|
7
|
-
export declare const GROUP_TRIGGER_CHARACTER = "{";
|
|
8
|
-
export declare const DECLARATION_SEPARATOR_TRIGGER_CHARACTER = ";";
|
|
9
|
-
export declare const SERVER_CAPABILITIES: ServerCapabilities;
|
|
1
|
+
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';
|
package/dist/common.mjs
CHANGED
|
@@ -1,48 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { QUERY_COMPARISON_OPERATORS, QUERY_LOGICAL_OPERATORS, SEPARATOR_SIGN, DELIMITER_SIGN, SELECTOR_SIGNS, AT_SIGN } from '@master/css';
|
|
3
|
-
|
|
4
|
-
const INVOKED_TRIGGER_CHARACTERS = [
|
|
5
|
-
'"',
|
|
6
|
-
' ',
|
|
7
|
-
'\''
|
|
8
|
-
];
|
|
9
|
-
const VALUE_TRIGGER_CHARACTERS = [
|
|
10
|
-
SEPARATOR_SIGN,
|
|
11
|
-
DELIMITER_SIGN
|
|
12
|
-
];
|
|
13
|
-
const SELECTOR_TRIGGER_CHARACTERS = SELECTOR_SIGNS;
|
|
14
|
-
const AT_TRIGGER_CHARACTER = AT_SIGN;
|
|
15
|
-
const QUERY_TRIGGER_CHARACTERS = [
|
|
16
|
-
...QUERY_COMPARISON_OPERATORS,
|
|
17
|
-
...QUERY_LOGICAL_OPERATORS
|
|
18
|
-
];
|
|
19
|
-
const GROUP_TRIGGER_CHARACTER = '{';
|
|
20
|
-
const DECLARATION_SEPARATOR_TRIGGER_CHARACTER = ';';
|
|
21
|
-
const SERVER_CAPABILITIES = {
|
|
22
|
-
textDocumentSync: TextDocumentSyncKind.Incremental,
|
|
23
|
-
// Tell the client that this server supports code completion.
|
|
24
|
-
completionProvider: {
|
|
25
|
-
resolveProvider: false,
|
|
26
|
-
workDoneProgress: false,
|
|
27
|
-
triggerCharacters: [
|
|
28
|
-
...new Set([
|
|
29
|
-
...INVOKED_TRIGGER_CHARACTERS,
|
|
30
|
-
...VALUE_TRIGGER_CHARACTERS,
|
|
31
|
-
...SELECTOR_TRIGGER_CHARACTERS,
|
|
32
|
-
...QUERY_TRIGGER_CHARACTERS,
|
|
33
|
-
DECLARATION_SEPARATOR_TRIGGER_CHARACTER,
|
|
34
|
-
AT_TRIGGER_CHARACTER,
|
|
35
|
-
GROUP_TRIGGER_CHARACTER
|
|
36
|
-
])
|
|
37
|
-
]
|
|
38
|
-
},
|
|
39
|
-
colorProvider: true,
|
|
40
|
-
hoverProvider: true,
|
|
41
|
-
workspace: {
|
|
42
|
-
workspaceFolders: {
|
|
43
|
-
supported: true
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
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 };
|
|
1
|
+
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';
|
package/dist/core.d.ts
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
import { MasterCSS } from '@master/css';
|
|
1
|
+
import { MasterCSS, type ClassPosition } from '@master/css-language';
|
|
2
2
|
import EventEmitter from 'node:events';
|
|
3
3
|
import type { Position } from 'vscode-languageserver-protocol';
|
|
4
4
|
import { type Settings } from './settings';
|
|
5
5
|
import inspectSyntax from './features/inspect-syntax';
|
|
6
6
|
import renderSyntaxColors from './features/render-syntax-colors';
|
|
7
7
|
import editSyntaxColors from './features/edit-syntax-colors';
|
|
8
|
+
import renderSemanticTokens, { renderSemanticTokensAtPosition } from './features/render-semantic-tokens';
|
|
8
9
|
import suggestSyntax from './features/suggest-syntax';
|
|
9
10
|
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
10
|
-
export
|
|
11
|
-
range: {
|
|
12
|
-
start: number;
|
|
13
|
-
end: number;
|
|
14
|
-
};
|
|
15
|
-
raw: string;
|
|
16
|
-
token: string;
|
|
17
|
-
}
|
|
11
|
+
export type { ClassPosition };
|
|
18
12
|
export default class CSSLanguageService extends EventEmitter {
|
|
19
13
|
customSettings?: Settings | undefined;
|
|
20
14
|
css: MasterCSS;
|
|
21
15
|
settings: Settings;
|
|
16
|
+
private completionIndex?;
|
|
17
|
+
private classPositionCache;
|
|
22
18
|
constructor(customSettings?: Settings | undefined);
|
|
19
|
+
private getCompletionIndex;
|
|
23
20
|
inspectSyntax(...params: Parameters<typeof inspectSyntax>): import("vscode-languageserver-protocol").Hover | undefined;
|
|
24
21
|
renderSyntaxColors(...params: Parameters<typeof renderSyntaxColors>): Promise<import("vscode-languageserver-protocol").ColorInformation[] | undefined> | undefined;
|
|
25
22
|
editSyntaxColors(...params: Parameters<typeof editSyntaxColors>): import("vscode-languageserver-protocol").ColorPresentation[] | undefined;
|
|
26
|
-
|
|
23
|
+
renderSemanticTokens(...params: Parameters<typeof renderSemanticTokens>): import("vscode-languageserver-protocol").SemanticTokens | undefined;
|
|
24
|
+
renderSemanticTokensAtPosition(...params: Parameters<typeof renderSemanticTokensAtPosition>): import("vscode-languageserver-protocol").SemanticTokens | undefined;
|
|
25
|
+
suggestSyntax(document: Parameters<typeof suggestSyntax>[0], position: Parameters<typeof suggestSyntax>[1], context: Parameters<typeof suggestSyntax>[2]): import("vscode-languageserver-protocol").CompletionItem[] | undefined;
|
|
26
|
+
getClassPositions(textDocument: TextDocument): ClassPosition[];
|
|
27
27
|
getClassPosition(textDocument: TextDocument, position: Position): ClassPosition | undefined;
|
|
28
|
+
getClassContextPositions(textDocument: TextDocument, position: Position): ClassPosition[];
|
|
28
29
|
isDocumentAccepted(doc: TextDocument): boolean;
|
|
29
30
|
}
|
package/dist/core.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ClassPositionCache, MasterCSS, matchesLanguageServiceNativeDeclaration, defaultManifest, getClassPositions } from '@master/css-language';
|
|
2
2
|
import extend from '@techor/extend';
|
|
3
3
|
import EventEmitter from 'node:events';
|
|
4
4
|
import settings from './settings.mjs';
|
|
@@ -6,18 +6,27 @@ import { minimatch } from 'minimatch';
|
|
|
6
6
|
import inspectSyntax from './features/inspect-syntax.mjs';
|
|
7
7
|
import renderSyntaxColors from './features/render-syntax-colors.mjs';
|
|
8
8
|
import editSyntaxColors from './features/edit-syntax-colors.mjs';
|
|
9
|
+
import renderSemanticTokens, { renderSemanticTokensAtPosition } from './features/render-semantic-tokens.mjs';
|
|
9
10
|
import suggestSyntax from './features/suggest-syntax.mjs';
|
|
10
|
-
import
|
|
11
|
-
import escapeRegexp from 'lodash.escaperegexp';
|
|
11
|
+
import { createCompletionIndex } from './utils/completion-index.mjs';
|
|
12
12
|
|
|
13
13
|
class CSSLanguageService extends EventEmitter {
|
|
14
14
|
customSettings;
|
|
15
15
|
css;
|
|
16
16
|
settings;
|
|
17
|
+
completionIndex;
|
|
18
|
+
classPositionCache = new ClassPositionCache();
|
|
17
19
|
constructor(customSettings){
|
|
18
20
|
super(), this.customSettings = customSettings;
|
|
19
21
|
this.settings = extend(settings, customSettings);
|
|
20
|
-
this.css =
|
|
22
|
+
this.css = MasterCSS.create({
|
|
23
|
+
manifest: this.settings.manifest || defaultManifest,
|
|
24
|
+
nativeDeclarationMatcher: matchesLanguageServiceNativeDeclaration
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
getCompletionIndex() {
|
|
28
|
+
this.completionIndex ??= createCompletionIndex(this.css);
|
|
29
|
+
return this.completionIndex;
|
|
21
30
|
}
|
|
22
31
|
inspectSyntax(...params) {
|
|
23
32
|
if (this.settings.inspectSyntax && this.isDocumentAccepted(params[0])) return inspectSyntax?.call(this, ...params);
|
|
@@ -28,207 +37,68 @@ class CSSLanguageService extends EventEmitter {
|
|
|
28
37
|
editSyntaxColors(...params) {
|
|
29
38
|
if (this.settings.editSyntaxColors && this.isDocumentAccepted(params[0])) return editSyntaxColors?.call(this, ...params);
|
|
30
39
|
}
|
|
31
|
-
|
|
32
|
-
if (this.
|
|
40
|
+
renderSemanticTokens(...params) {
|
|
41
|
+
if (this.isDocumentAccepted(params[0])) return renderSemanticTokens?.call(this, ...params);
|
|
33
42
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}) ?? undefined;
|
|
44
|
-
const text = textDocument.getText().substring(startIndex, endIndex);
|
|
45
|
-
const { classAttributeBindings, classAttributes, classDeclarations, classFunctions } = this.settings;
|
|
46
|
-
const normalizeClassNamePosition = (className, attrStart, escapeCharacter)=>{
|
|
47
|
-
/**
|
|
48
|
-
* Matching classes, including empty string after white space
|
|
49
|
-
* @example <div class="class-a class-b "></div>
|
|
50
|
-
* @url https://regex101.com/r/LnBLAV/1
|
|
51
|
-
*/ for (const eachClassMatch of className.matchAll(/(?:[^\s]+)?/g)){
|
|
52
|
-
if (eachClassMatch.index === undefined) continue;
|
|
53
|
-
const raw = eachClassMatch[0];
|
|
54
|
-
const classStartIndex = attrStart + eachClassMatch.index;
|
|
55
|
-
const classEndIndex = classStartIndex + raw.length;
|
|
56
|
-
if (classStartIndex <= positionIndex - startIndex && positionIndex - startIndex <= classEndIndex) {
|
|
57
|
-
return {
|
|
58
|
-
range: {
|
|
59
|
-
start: classStartIndex,
|
|
60
|
-
end: startIndex + classEndIndex
|
|
61
|
-
},
|
|
62
|
-
raw,
|
|
63
|
-
token: raw.replace(new RegExp('\\' + escapeCharacter, 'g'), escapeCharacter)
|
|
64
|
-
};
|
|
65
|
-
} else if (attrStart === classEndIndex) {
|
|
66
|
-
return {
|
|
67
|
-
range: {
|
|
68
|
-
start: attrStart,
|
|
69
|
-
end: attrStart
|
|
70
|
-
},
|
|
71
|
-
raw: '',
|
|
72
|
-
token: ''
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
const resolve = (classMatchers, handle)=>{
|
|
78
|
-
for (const eachClassMatcher of classMatchers){
|
|
79
|
-
let [eachPattern, start, end] = eachClassMatcher;
|
|
80
|
-
end = end ?? start;
|
|
81
|
-
for (const eachClassPostioinMatch of text.matchAll(new RegExp(`(?:\\s|\\.)${eachPattern}${escapeRegexp(start)}`, 'g'))){
|
|
82
|
-
if (eachClassPostioinMatch.index === undefined) continue;
|
|
83
|
-
const eachClassAttributeString = eachClassPostioinMatch[0];
|
|
84
|
-
const eachAttrStart = eachClassPostioinMatch.index + eachClassAttributeString.length;
|
|
85
|
-
const eachClassPositionEnd = findMatchingPairs(text, eachAttrStart, start, end);
|
|
86
|
-
if (!eachClassPositionEnd) continue;
|
|
87
|
-
if ((eachAttrStart <= positionIndex - startIndex && eachClassPositionEnd >= positionIndex - startIndex) === true) {
|
|
88
|
-
const classPosition = handle(eachAttrStart, eachClassPositionEnd, eachClassMatcher);
|
|
89
|
-
if (classPosition) return classPosition;
|
|
90
|
-
} else if (eachClassPostioinMatch.index > positionIndex - startIndex) {
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
const stringExpressions = [];
|
|
97
|
-
const assignmentExpressions = [];
|
|
98
|
-
classAttributes?.forEach((eachClassAttribute)=>{
|
|
99
|
-
stringExpressions.push([
|
|
100
|
-
eachClassAttribute + '=',
|
|
101
|
-
'"',
|
|
102
|
-
'"'
|
|
103
|
-
], [
|
|
104
|
-
eachClassAttribute + '=',
|
|
105
|
-
'\'',
|
|
106
|
-
'\''
|
|
107
|
-
]);
|
|
43
|
+
renderSemanticTokensAtPosition(...params) {
|
|
44
|
+
if (this.isDocumentAccepted(params[0])) return renderSemanticTokensAtPosition?.call(this, ...params);
|
|
45
|
+
}
|
|
46
|
+
suggestSyntax(document, position, context) {
|
|
47
|
+
if (this.settings.suggestSyntax && this.isDocumentAccepted(document)) return suggestSyntax?.call(this, document, position, context, this.getCompletionIndex());
|
|
48
|
+
}
|
|
49
|
+
getClassPositions(textDocument) {
|
|
50
|
+
return getClassPositions(textDocument, this.settings, {
|
|
51
|
+
cache: this.classPositionCache
|
|
108
52
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
53
|
+
}
|
|
54
|
+
getClassPosition(textDocument, position) {
|
|
55
|
+
const cachedOxcClassPosition = getClassPositions(textDocument, this.settings, {
|
|
56
|
+
position,
|
|
57
|
+
includeEmpty: true,
|
|
58
|
+
provider: 'oxc',
|
|
59
|
+
oxcMode: 'cache-only',
|
|
60
|
+
cache: this.classPositionCache
|
|
61
|
+
})[0];
|
|
62
|
+
if (cachedOxcClassPosition) return cachedOxcClassPosition;
|
|
63
|
+
const regexClassPosition = getClassPositions(textDocument, this.settings, {
|
|
64
|
+
position,
|
|
65
|
+
includeEmpty: true,
|
|
66
|
+
provider: 'regex'
|
|
67
|
+
})[0];
|
|
68
|
+
if (regexClassPosition && !regexClassPosition.raw.includes('${')) {
|
|
69
|
+
return regexClassPosition;
|
|
70
|
+
}
|
|
71
|
+
return getClassPositions(textDocument, this.settings, {
|
|
72
|
+
position,
|
|
73
|
+
includeEmpty: true,
|
|
74
|
+
provider: 'oxc',
|
|
75
|
+
cache: this.classPositionCache
|
|
76
|
+
})[0] ?? regexClassPosition;
|
|
77
|
+
}
|
|
78
|
+
getClassContextPositions(textDocument, position) {
|
|
79
|
+
const cachedOxcClassPositions = getClassPositions(textDocument, this.settings, {
|
|
80
|
+
position,
|
|
81
|
+
provider: 'oxc',
|
|
82
|
+
oxcMode: 'cache-only',
|
|
83
|
+
positionMatch: 'context',
|
|
84
|
+
cache: this.classPositionCache
|
|
128
85
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
'`',
|
|
135
|
-
'`'
|
|
136
|
-
]);
|
|
137
|
-
/**
|
|
138
|
-
* @example clsx('class-a class-b')
|
|
139
|
-
*/ assignmentExpressions.push([
|
|
140
|
-
eachClassFunction,
|
|
141
|
-
'(',
|
|
142
|
-
')'
|
|
143
|
-
]);
|
|
86
|
+
if (cachedOxcClassPositions.length) return cachedOxcClassPositions;
|
|
87
|
+
const regexClassPositions = getClassPositions(textDocument, this.settings, {
|
|
88
|
+
position,
|
|
89
|
+
provider: 'regex',
|
|
90
|
+
positionMatch: 'context'
|
|
144
91
|
});
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
* */ if (stringExpressions?.length) {
|
|
148
|
-
const classPosition = resolve(stringExpressions, (eachAttrStart, eachClassPositionEnd, [eachPattern, pair])=>{
|
|
149
|
-
const eachClassName = text.substring(eachAttrStart, eachClassPositionEnd);
|
|
150
|
-
/**
|
|
151
|
-
* @example <div class=""></div>
|
|
152
|
-
*/ if (eachClassName === undefined) {
|
|
153
|
-
return {
|
|
154
|
-
range: {
|
|
155
|
-
start: eachAttrStart,
|
|
156
|
-
end: eachAttrStart
|
|
157
|
-
},
|
|
158
|
-
token: '',
|
|
159
|
-
raw: ''
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
const classNameStart = eachAttrStart;
|
|
163
|
-
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, pair);
|
|
164
|
-
if (classPosition) return classPosition;
|
|
165
|
-
});
|
|
166
|
-
if (classPosition) return classPosition;
|
|
167
|
-
}
|
|
168
|
-
if (classAttributeBindings) {
|
|
169
|
-
for(const eachClassAttribute in classAttributeBindings){
|
|
170
|
-
const eachClassAttributeBinding = classAttributeBindings[eachClassAttribute];
|
|
171
|
-
if (eachClassAttributeBinding === false) continue;
|
|
172
|
-
assignmentExpressions.push([
|
|
173
|
-
eachClassAttribute + '=',
|
|
174
|
-
eachClassAttributeBinding[0],
|
|
175
|
-
eachClassAttributeBinding[1]
|
|
176
|
-
]);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* attribute binding
|
|
181
|
-
* @example <div className={''}></div>
|
|
182
|
-
* @example <div :class="isActive ? 'block' : 'hidden'"></div>
|
|
183
|
-
* */ if (assignmentExpressions?.length) {
|
|
184
|
-
const classPosition = resolve(assignmentExpressions, (eachAttrStart, eachClassPositionEnd, eachClassMatcher)=>{
|
|
185
|
-
const eachClassPositionExpression = text.substring(eachAttrStart, eachClassPositionEnd);
|
|
186
|
-
/**
|
|
187
|
-
* @example <div className={""}></div>
|
|
188
|
-
*/ if ([
|
|
189
|
-
'""',
|
|
190
|
-
'\'\'',
|
|
191
|
-
'``'
|
|
192
|
-
].includes(eachClassPositionExpression)) {
|
|
193
|
-
return {
|
|
194
|
-
range: {
|
|
195
|
-
start: eachAttrStart + 1,
|
|
196
|
-
end: eachAttrStart + 1
|
|
197
|
-
},
|
|
198
|
-
raw: '',
|
|
199
|
-
token: ''
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
// 1. "
|
|
203
|
-
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)"([\s\S]*?)(?<!\\)"/g)){
|
|
204
|
-
if (classExpressionMatch.index === undefined) continue;
|
|
205
|
-
const eachClassName = classExpressionMatch[1];
|
|
206
|
-
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // " length
|
|
207
|
-
;
|
|
208
|
-
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '"');
|
|
209
|
-
if (classPosition) return classPosition;
|
|
210
|
-
}
|
|
211
|
-
// 2. '
|
|
212
|
-
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)'([\s\S]*?)(?<!\\)'/g)){
|
|
213
|
-
if (classExpressionMatch.index === undefined) continue;
|
|
214
|
-
const eachClassName = classExpressionMatch[1];
|
|
215
|
-
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // ' length
|
|
216
|
-
;
|
|
217
|
-
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '\'');
|
|
218
|
-
if (classPosition) return classPosition;
|
|
219
|
-
}
|
|
220
|
-
// 3. `
|
|
221
|
-
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)`([\s\S]*?)(?<!\\)`/g)){
|
|
222
|
-
if (classExpressionMatch.index === undefined) continue;
|
|
223
|
-
const eachClassName = classExpressionMatch[1];
|
|
224
|
-
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // ` length
|
|
225
|
-
;
|
|
226
|
-
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '`');
|
|
227
|
-
if (classPosition) return classPosition;
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
if (classPosition) return classPosition;
|
|
92
|
+
if (regexClassPositions.length && regexClassPositions.every(({ raw })=>!raw.includes('${'))) {
|
|
93
|
+
return regexClassPositions;
|
|
231
94
|
}
|
|
95
|
+
const oxcClassPositions = getClassPositions(textDocument, this.settings, {
|
|
96
|
+
position,
|
|
97
|
+
provider: 'oxc',
|
|
98
|
+
positionMatch: 'context',
|
|
99
|
+
cache: this.classPositionCache
|
|
100
|
+
});
|
|
101
|
+
return oxcClassPositions.length ? oxcClassPositions : regexClassPositions;
|
|
232
102
|
}
|
|
233
103
|
isDocumentAccepted(doc) {
|
|
234
104
|
if (!this.settings.exclude) return true;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import cssDataProvider from '../utils/css-data-provider.mjs';
|
|
4
|
-
import getUtilityInfo from '../utils/get-utility-info.mjs';
|
|
1
|
+
import createCSSMarkdownDocumentation from '../utils/create-css-markdown-documentation.mjs';
|
|
2
|
+
import { UtilityType, generateCSS } from '@master/css-language';
|
|
5
3
|
|
|
6
4
|
function inspectSyntax(document, position) {
|
|
7
5
|
const classPosition = this.getClassPosition(document, position);
|
|
@@ -11,34 +9,27 @@ function inspectSyntax(document, position) {
|
|
|
11
9
|
start: document.positionAt(classPosition.range.start),
|
|
12
10
|
end: document.positionAt(classPosition.range.end)
|
|
13
11
|
};
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
docs: '/guide/components'
|
|
21
|
-
});
|
|
12
|
+
const utilities = this.css.generate(token);
|
|
13
|
+
const component = utilities.find((utility)=>utility.type === UtilityType.Semantic && utility.layerName === 'components');
|
|
14
|
+
if (component) {
|
|
15
|
+
const documentation = createCSSMarkdownDocumentation(generateCSS([
|
|
16
|
+
token
|
|
17
|
+
], this.css));
|
|
22
18
|
if (documentation) {
|
|
23
19
|
return {
|
|
24
20
|
contents: {
|
|
25
21
|
kind: documentation.kind,
|
|
26
|
-
value: `(
|
|
22
|
+
value: `(components) ` + documentation.value
|
|
27
23
|
}
|
|
28
24
|
};
|
|
29
25
|
}
|
|
30
26
|
} else {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
generatedCSS: generateCSS([
|
|
38
|
-
token
|
|
39
|
-
], this.css),
|
|
40
|
-
docs
|
|
41
|
-
});
|
|
27
|
+
const utility = utilities[0];
|
|
28
|
+
if (utility) {
|
|
29
|
+
if (utility.type === UtilityType.Semantic) {
|
|
30
|
+
const documentation = createCSSMarkdownDocumentation(generateCSS([
|
|
31
|
+
token
|
|
32
|
+
], this.css));
|
|
42
33
|
if (documentation) {
|
|
43
34
|
return {
|
|
44
35
|
contents: documentation,
|
|
@@ -46,14 +37,9 @@ function inspectSyntax(document, position) {
|
|
|
46
37
|
};
|
|
47
38
|
}
|
|
48
39
|
} else {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
generatedCSS: generateCSS([
|
|
53
|
-
token
|
|
54
|
-
], this.css),
|
|
55
|
-
docs: '/reference/' + (isCoreRule(rule.id) && rule.id)
|
|
56
|
-
});
|
|
40
|
+
const documentation = createCSSMarkdownDocumentation(generateCSS([
|
|
41
|
+
token
|
|
42
|
+
], this.css));
|
|
57
43
|
if (documentation) {
|
|
58
44
|
return {
|
|
59
45
|
contents: documentation,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type CSSLanguageService from '../core';
|
|
2
|
+
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
3
|
+
import type { SemanticTokens } from 'vscode-languageserver-protocol';
|
|
4
|
+
export declare function renderSemanticTokensAtPosition(this: CSSLanguageService, document: TextDocument, position: Parameters<CSSLanguageService['getClassPosition']>[1]): SemanticTokens | undefined;
|
|
5
|
+
export default function renderSemanticTokens(this: CSSLanguageService, document: TextDocument): SemanticTokens | undefined;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { renderSemanticTokens as renderSemanticTokens$1, renderSemanticTokensAtPosition as renderSemanticTokensAtPosition$1 } from '@master/css-language';
|
|
2
|
+
|
|
3
|
+
function renderSemanticTokensAtPosition(document, position) {
|
|
4
|
+
return renderSemanticTokensAtPosition$1(this.css, document, this.getClassContextPositions(document, position), position, this.settings);
|
|
5
|
+
}
|
|
6
|
+
function renderSemanticTokens(document) {
|
|
7
|
+
return renderSemanticTokens$1(this.css, document, this.getClassPositions(document), this.settings);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { renderSemanticTokens as default, renderSemanticTokensAtPosition };
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { instancePattern } from '../utils/regex.mjs';
|
|
2
2
|
import Color from 'colorjs.io';
|
|
3
|
-
import {
|
|
3
|
+
import { UtilityType } from '@master/css-language';
|
|
4
4
|
|
|
5
|
+
function resolveVariableColorValue(variable, variables) {
|
|
6
|
+
let current = variable;
|
|
7
|
+
for(let i = 0; i < 8; i++){
|
|
8
|
+
const value = current?.value;
|
|
9
|
+
if (value === undefined) return;
|
|
10
|
+
const text = String(value);
|
|
11
|
+
const alias = /^\$([a-zA-Z0-9-]+)(?: ?\/ ?.+?)?$|^var\(--([_a-zA-Z0-9-]+)\)$/.exec(text);
|
|
12
|
+
const aliasName = alias?.[1] ?? alias?.[2];
|
|
13
|
+
if (!aliasName) return text;
|
|
14
|
+
current = variables.get(aliasName);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
5
17
|
async function renderSyntaxColors(document) {
|
|
6
18
|
const text = document.getText() ?? '';
|
|
7
19
|
const colorInformations = [];
|
|
@@ -11,13 +23,13 @@ async function renderSyntaxColors(document) {
|
|
|
11
23
|
const instanceStartIndex = instanceMatch.index;
|
|
12
24
|
const syntax = instanceMatch[0];
|
|
13
25
|
const rule = this.css.generate(syntax)[0];
|
|
14
|
-
if (rule && rule.type !==
|
|
26
|
+
if (rule && rule.type !== UtilityType.Semantic) {
|
|
15
27
|
const keyTokenLength = rule.keyToken?.length ?? 0;
|
|
16
28
|
let currentLength = 0;
|
|
17
29
|
const resolveValueComponent = (valueComponent)=>{
|
|
18
30
|
if (valueComponent.text === undefined) return; // text is always existing, just for type
|
|
19
31
|
const startOffset = instanceStartIndex + keyTokenLength + currentLength;
|
|
20
|
-
// TODO: check number mt:
|
|
32
|
+
// TODO: check number mt:1.875rem
|
|
21
33
|
const valueComponentTokenLength = valueComponent.token.length;
|
|
22
34
|
let color;
|
|
23
35
|
switch(valueComponent.type){
|
|
@@ -41,8 +53,11 @@ async function renderSyntaxColors(document) {
|
|
|
41
53
|
}
|
|
42
54
|
break;
|
|
43
55
|
case 'variable':
|
|
44
|
-
if (valueComponent.variable?.
|
|
45
|
-
color = new Color(valueComponent.
|
|
56
|
+
if (valueComponent.variable?.namespace?.startsWith('color') && valueComponent.variable.value !== undefined) {
|
|
57
|
+
color = new Color(resolveVariableColorValue(valueComponent.variable, this.css.variables) || String(valueComponent.variable.value));
|
|
58
|
+
if (valueComponent.alpha !== undefined) {
|
|
59
|
+
color.alpha *= valueComponent.alpha;
|
|
60
|
+
}
|
|
46
61
|
}
|
|
47
62
|
break;
|
|
48
63
|
case 'string':
|
|
@@ -60,9 +75,9 @@ async function renderSyntaxColors(document) {
|
|
|
60
75
|
end: document.positionAt(startOffset + valueComponentTokenLength)
|
|
61
76
|
},
|
|
62
77
|
color: {
|
|
63
|
-
red: rgbaColor.r,
|
|
64
|
-
green: rgbaColor.g,
|
|
65
|
-
blue: rgbaColor.b,
|
|
78
|
+
red: rgbaColor.r ?? 0,
|
|
79
|
+
green: rgbaColor.g ?? 0,
|
|
80
|
+
blue: rgbaColor.b ?? 0,
|
|
66
81
|
alpha: Number(rgbaColor.alpha)
|
|
67
82
|
}
|
|
68
83
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CompletionItem, CompletionParams } from 'vscode-languageserver-protocol';
|
|
2
2
|
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
3
3
|
import CSSLanguageService from '../core';
|
|
4
|
-
|
|
4
|
+
import type { CompletionIndex } from '../utils/completion-index';
|
|
5
|
+
export default function suggestSyntax(this: CSSLanguageService, document: TextDocument, position: CompletionParams['position'], context: CompletionParams['context'], completionIndex?: CompletionIndex): CompletionItem[] | undefined;
|