@master/css-language-service 2.0.0-rc.4 → 2.0.0-rc.41
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/dist/common.cjs +57 -0
- package/dist/common.d.ts +9 -0
- package/dist/common.mjs +48 -0
- package/dist/core.cjs +248 -0
- package/dist/core.d.ts +30 -0
- package/dist/core.mjs +246 -0
- package/dist/features/edit-syntax-colors.cjs +19 -0
- package/dist/features/edit-syntax-colors.d.ts +4 -0
- package/dist/features/edit-syntax-colors.mjs +17 -0
- package/dist/features/inspect-syntax.cjs +70 -0
- package/dist/features/inspect-syntax.d.ts +4 -0
- package/dist/features/inspect-syntax.mjs +68 -0
- package/dist/features/render-syntax-colors.cjs +88 -0
- package/dist/features/render-syntax-colors.d.ts +4 -0
- package/dist/features/render-syntax-colors.mjs +86 -0
- package/dist/features/suggest-syntax.cjs +20 -0
- package/dist/features/suggest-syntax.d.ts +4 -0
- package/dist/features/suggest-syntax.mjs +18 -0
- package/dist/index.cjs +29 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.mjs +7 -0
- package/dist/settings.cjs +84 -0
- package/dist/settings.d.ts +18 -8
- package/dist/settings.mjs +82 -0
- package/dist/utils/beautify-css.cjs +13 -0
- package/dist/utils/beautify-css.d.ts +1 -0
- package/dist/utils/beautify-css.mjs +11 -0
- package/dist/utils/convert-color-space.cjs +40 -0
- package/dist/utils/convert-color-space.d.ts +2 -0
- package/dist/utils/convert-color-space.mjs +38 -0
- package/dist/utils/convert-color-token.cjs +28 -0
- package/dist/utils/convert-color-token.d.ts +3 -0
- package/dist/utils/convert-color-token.mjs +26 -0
- package/dist/utils/create-doc.cjs +26 -0
- package/dist/utils/create-doc.d.ts +16 -0
- package/dist/utils/create-doc.mjs +21 -0
- package/dist/utils/css-data-provider.cjs +9 -0
- package/dist/utils/css-data-provider.d.ts +3 -0
- package/dist/utils/css-data-provider.mjs +7 -0
- package/dist/utils/find-matching-brackets.cjs +29 -0
- package/dist/utils/find-matching-brackets.d.ts +1 -0
- package/dist/utils/find-matching-brackets.mjs +27 -0
- package/dist/utils/get-color-completion-items.cjs +30 -0
- package/dist/utils/get-color-completion-items.d.ts +3 -0
- package/dist/utils/get-color-completion-items.mjs +28 -0
- package/dist/utils/get-css-data-documentation.cjs +90 -0
- package/dist/utils/get-css-data-documentation.d.ts +5 -0
- package/dist/utils/get-css-data-documentation.mjs +88 -0
- package/dist/utils/get-main-completion-items.cjs +105 -0
- package/dist/utils/get-main-completion-items.d.ts +3 -0
- package/dist/utils/get-main-completion-items.mjs +103 -0
- package/dist/utils/get-position.cjs +12 -0
- package/dist/utils/get-position.d.ts +1 -0
- package/dist/utils/get-position.mjs +10 -0
- package/dist/utils/get-pseudo-class-completion-items.cjs +65 -0
- package/dist/utils/get-pseudo-class-completion-items.d.ts +3 -0
- package/dist/utils/get-pseudo-class-completion-items.mjs +63 -0
- package/dist/utils/get-pseudo-element-completion-items.cjs +56 -0
- package/dist/utils/get-pseudo-element-completion-items.d.ts +3 -0
- package/dist/utils/get-pseudo-element-completion-items.mjs +54 -0
- package/dist/utils/get-query-completion-items.cjs +102 -0
- package/dist/utils/get-query-completion-items.d.ts +3 -0
- package/dist/utils/get-query-completion-items.mjs +100 -0
- package/dist/utils/get-range.cjs +21 -0
- package/dist/utils/get-range.d.ts +2 -0
- package/dist/utils/get-range.mjs +19 -0
- package/dist/utils/get-utility-info.cjs +32 -0
- package/dist/utils/get-utility-info.d.ts +7 -0
- package/dist/utils/get-utility-info.mjs +30 -0
- package/dist/utils/get-value-completion-items.cjs +185 -0
- package/dist/utils/get-value-completion-items.d.ts +3 -0
- package/dist/utils/get-value-completion-items.mjs +183 -0
- package/dist/utils/query-syntax-completions.cjs +115 -0
- package/dist/utils/query-syntax-completions.d.ts +3 -0
- package/dist/utils/query-syntax-completions.mjs +113 -0
- package/dist/utils/regex.cjs +5 -0
- package/dist/utils/regex.mjs +3 -0
- package/dist/utils/sort-completion-items.cjs +11 -0
- package/dist/utils/sort-completion-items.d.ts +2 -0
- package/dist/utils/sort-completion-items.mjs +9 -0
- package/package.json +1 -1
- package/dist/constant.d.ts +0 -33
- package/dist/index.bundle.js +0 -33
- package/dist/position-check.d.ts +0 -20
- package/dist/providers/color.d.ts +0 -5
- package/dist/providers/completion.d.ts +0 -14
- package/dist/providers/hover.d.ts +0 -2
- package/dist/settings.bundle.js +0 -1
- package/dist/utils/get-css-entry-markdown-description.d.ts +0 -1
- package/dist/utils/hex-to-rgb.d.ts +0 -2
- package/dist/utils/oklab-to-rgb.d.ts +0 -1
- package/dist/utils/oklch-to-oklab.d.ts +0 -1
- package/dist/utils/to-two-digit-hex.d.ts +0 -1
package/dist/common.cjs
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vscodeLanguageserverProtocol = require('vscode-languageserver-protocol');
|
|
4
|
+
var css = require('@master/css');
|
|
5
|
+
|
|
6
|
+
const INVOKED_TRIGGER_CHARACTERS = [
|
|
7
|
+
'"',
|
|
8
|
+
' ',
|
|
9
|
+
'\''
|
|
10
|
+
];
|
|
11
|
+
const VALUE_TRIGGER_CHARACTERS = [
|
|
12
|
+
css.SEPARATOR_SIGN,
|
|
13
|
+
css.DELIMITER_SIGN
|
|
14
|
+
];
|
|
15
|
+
const SELECTOR_TRIGGER_CHARACTERS = css.SELECTOR_SIGNS;
|
|
16
|
+
const AT_TRIGGER_CHARACTER = css.AT_SIGN;
|
|
17
|
+
const QUERY_TRIGGER_CHARACTERS = [
|
|
18
|
+
...css.QUERY_COMPARISON_OPERATORS,
|
|
19
|
+
...css.QUERY_LOGICAL_OPERATORS
|
|
20
|
+
];
|
|
21
|
+
const GROUP_TRIGGER_CHARACTER = '{';
|
|
22
|
+
const DECLARATION_SEPARATOR_TRIGGER_CHARACTER = ';';
|
|
23
|
+
const SERVER_CAPABILITIES = {
|
|
24
|
+
textDocumentSync: vscodeLanguageserverProtocol.TextDocumentSyncKind.Incremental,
|
|
25
|
+
// Tell the client that this server supports code completion.
|
|
26
|
+
completionProvider: {
|
|
27
|
+
resolveProvider: false,
|
|
28
|
+
workDoneProgress: false,
|
|
29
|
+
triggerCharacters: [
|
|
30
|
+
...new Set([
|
|
31
|
+
...INVOKED_TRIGGER_CHARACTERS,
|
|
32
|
+
...VALUE_TRIGGER_CHARACTERS,
|
|
33
|
+
...SELECTOR_TRIGGER_CHARACTERS,
|
|
34
|
+
...QUERY_TRIGGER_CHARACTERS,
|
|
35
|
+
DECLARATION_SEPARATOR_TRIGGER_CHARACTER,
|
|
36
|
+
AT_TRIGGER_CHARACTER,
|
|
37
|
+
GROUP_TRIGGER_CHARACTER
|
|
38
|
+
])
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
colorProvider: true,
|
|
42
|
+
hoverProvider: true,
|
|
43
|
+
workspace: {
|
|
44
|
+
workspaceFolders: {
|
|
45
|
+
supported: true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
exports.AT_TRIGGER_CHARACTER = AT_TRIGGER_CHARACTER;
|
|
51
|
+
exports.DECLARATION_SEPARATOR_TRIGGER_CHARACTER = DECLARATION_SEPARATOR_TRIGGER_CHARACTER;
|
|
52
|
+
exports.GROUP_TRIGGER_CHARACTER = GROUP_TRIGGER_CHARACTER;
|
|
53
|
+
exports.INVOKED_TRIGGER_CHARACTERS = INVOKED_TRIGGER_CHARACTERS;
|
|
54
|
+
exports.QUERY_TRIGGER_CHARACTERS = QUERY_TRIGGER_CHARACTERS;
|
|
55
|
+
exports.SELECTOR_TRIGGER_CHARACTERS = SELECTOR_TRIGGER_CHARACTERS;
|
|
56
|
+
exports.SERVER_CAPABILITIES = SERVER_CAPABILITIES;
|
|
57
|
+
exports.VALUE_TRIGGER_CHARACTERS = VALUE_TRIGGER_CHARACTERS;
|
package/dist/common.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ServerCapabilities } from 'vscode-languageserver-protocol';
|
|
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;
|
package/dist/common.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { TextDocumentSyncKind } from 'vscode-languageserver-protocol';
|
|
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 };
|
package/dist/core.cjs
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var css = require('@master/css');
|
|
4
|
+
var extend = require('@techor/extend');
|
|
5
|
+
var EventEmitter = require('node:events');
|
|
6
|
+
var settings = require('./settings.cjs');
|
|
7
|
+
var minimatch = require('minimatch');
|
|
8
|
+
var inspectSyntax = require('./features/inspect-syntax.cjs');
|
|
9
|
+
var renderSyntaxColors = require('./features/render-syntax-colors.cjs');
|
|
10
|
+
var editSyntaxColors = require('./features/edit-syntax-colors.cjs');
|
|
11
|
+
var suggestSyntax = require('./features/suggest-syntax.cjs');
|
|
12
|
+
var findMatchingBrackets = require('./utils/find-matching-brackets.cjs');
|
|
13
|
+
var escapeRegexp = require('lodash.escaperegexp');
|
|
14
|
+
|
|
15
|
+
class CSSLanguageService extends EventEmitter {
|
|
16
|
+
customSettings;
|
|
17
|
+
css;
|
|
18
|
+
settings;
|
|
19
|
+
constructor(customSettings){
|
|
20
|
+
super();
|
|
21
|
+
this.customSettings = customSettings;
|
|
22
|
+
this.settings = extend(settings, customSettings);
|
|
23
|
+
this.css = new css.MasterCSS(this.settings.config);
|
|
24
|
+
}
|
|
25
|
+
inspectSyntax(...params) {
|
|
26
|
+
if (this.settings.inspectSyntax && this.isDocumentAccepted(params[0])) return inspectSyntax?.call(this, ...params);
|
|
27
|
+
}
|
|
28
|
+
renderSyntaxColors(...params) {
|
|
29
|
+
if (this.settings.renderSyntaxColors && this.isDocumentAccepted(params[0])) return renderSyntaxColors?.call(this, ...params);
|
|
30
|
+
}
|
|
31
|
+
editSyntaxColors(...params) {
|
|
32
|
+
if (this.settings.editSyntaxColors && this.isDocumentAccepted(params[0])) return editSyntaxColors?.call(this, ...params);
|
|
33
|
+
}
|
|
34
|
+
suggestSyntax(...params) {
|
|
35
|
+
if (this.settings.suggestSyntax && this.isDocumentAccepted(params[0])) return suggestSyntax?.call(this, ...params);
|
|
36
|
+
}
|
|
37
|
+
getClassPosition(textDocument, position) {
|
|
38
|
+
const positionIndex = textDocument.offsetAt(position);
|
|
39
|
+
const startIndex = textDocument.offsetAt({
|
|
40
|
+
line: position.line - 100,
|
|
41
|
+
character: 0
|
|
42
|
+
}) ?? 0;
|
|
43
|
+
const endIndex = textDocument.offsetAt({
|
|
44
|
+
line: position.line + 100,
|
|
45
|
+
character: 0
|
|
46
|
+
}) ?? undefined;
|
|
47
|
+
const text = textDocument.getText().substring(startIndex, endIndex);
|
|
48
|
+
const { classAttributeBindings, classAttributes, classDeclarations, classFunctions } = this.settings;
|
|
49
|
+
const normalizeClassNamePosition = (className, attrStart, escapeCharacter)=>{
|
|
50
|
+
/**
|
|
51
|
+
* Matching classes, including empty string after white space
|
|
52
|
+
* @example <div class="class-a class-b "></div>
|
|
53
|
+
* @url https://regex101.com/r/LnBLAV/1
|
|
54
|
+
*/ for (const eachClassMatch of className.matchAll(/(?:[^\s]+)?/g)){
|
|
55
|
+
if (eachClassMatch.index === undefined) continue;
|
|
56
|
+
const raw = eachClassMatch[0];
|
|
57
|
+
const classStartIndex = attrStart + eachClassMatch.index;
|
|
58
|
+
const classEndIndex = classStartIndex + raw.length;
|
|
59
|
+
if (classStartIndex <= positionIndex - startIndex && positionIndex - startIndex <= classEndIndex) {
|
|
60
|
+
return {
|
|
61
|
+
range: {
|
|
62
|
+
start: classStartIndex,
|
|
63
|
+
end: startIndex + classEndIndex
|
|
64
|
+
},
|
|
65
|
+
raw,
|
|
66
|
+
token: raw.replace(new RegExp('\\' + escapeCharacter, 'g'), escapeCharacter)
|
|
67
|
+
};
|
|
68
|
+
} else if (attrStart === classEndIndex) {
|
|
69
|
+
return {
|
|
70
|
+
range: {
|
|
71
|
+
start: attrStart,
|
|
72
|
+
end: attrStart
|
|
73
|
+
},
|
|
74
|
+
raw: '',
|
|
75
|
+
token: ''
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const resolve = (classMatchers, handle)=>{
|
|
81
|
+
for (const eachClassMatcher of classMatchers){
|
|
82
|
+
// eslint-disable-next-line prefer-const
|
|
83
|
+
let [eachPattern, start, end] = eachClassMatcher;
|
|
84
|
+
end = end ?? start;
|
|
85
|
+
for (const eachClassPostioinMatch of text.matchAll(new RegExp(`(?:\\s|\\.)${eachPattern}${escapeRegexp(start)}`, 'g'))){
|
|
86
|
+
if (eachClassPostioinMatch.index === undefined) continue;
|
|
87
|
+
const eachClassAttributeString = eachClassPostioinMatch[0];
|
|
88
|
+
const eachAttrStart = eachClassPostioinMatch.index + eachClassAttributeString.length;
|
|
89
|
+
const eachClassPositionEnd = findMatchingBrackets(text, eachAttrStart, start, end);
|
|
90
|
+
if (!eachClassPositionEnd) continue;
|
|
91
|
+
if ((eachAttrStart <= positionIndex - startIndex && eachClassPositionEnd >= positionIndex - startIndex) === true) {
|
|
92
|
+
const classPosition = handle(eachAttrStart, eachClassPositionEnd, eachClassMatcher);
|
|
93
|
+
if (classPosition) return classPosition;
|
|
94
|
+
} else if (eachClassPostioinMatch.index > positionIndex - startIndex) {
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const stringExpressions = [];
|
|
101
|
+
const assignmentExpressions = [];
|
|
102
|
+
classAttributes?.forEach((eachClassAttribute)=>{
|
|
103
|
+
stringExpressions.push([
|
|
104
|
+
eachClassAttribute + '=',
|
|
105
|
+
'"',
|
|
106
|
+
'"'
|
|
107
|
+
], [
|
|
108
|
+
eachClassAttribute + '=',
|
|
109
|
+
'\'',
|
|
110
|
+
'\''
|
|
111
|
+
]);
|
|
112
|
+
});
|
|
113
|
+
classDeclarations?.forEach((eachClassDeclaration)=>{
|
|
114
|
+
stringExpressions.push([
|
|
115
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
116
|
+
'"',
|
|
117
|
+
'"'
|
|
118
|
+
], [
|
|
119
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
120
|
+
'`',
|
|
121
|
+
'`'
|
|
122
|
+
], [
|
|
123
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
124
|
+
'\'',
|
|
125
|
+
'\''
|
|
126
|
+
]);
|
|
127
|
+
assignmentExpressions.push([
|
|
128
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
129
|
+
'{',
|
|
130
|
+
'}'
|
|
131
|
+
]);
|
|
132
|
+
});
|
|
133
|
+
classFunctions?.forEach((eachClassFunction)=>{
|
|
134
|
+
/**
|
|
135
|
+
* @example clsx`class-a class-b`
|
|
136
|
+
*/ stringExpressions.push([
|
|
137
|
+
eachClassFunction,
|
|
138
|
+
'`',
|
|
139
|
+
'`'
|
|
140
|
+
]);
|
|
141
|
+
/**
|
|
142
|
+
* @example clsx('class-a class-b')
|
|
143
|
+
*/ assignmentExpressions.push([
|
|
144
|
+
eachClassFunction,
|
|
145
|
+
'(',
|
|
146
|
+
')'
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
/**
|
|
150
|
+
* @example <div class=""></div>
|
|
151
|
+
* */ if (stringExpressions?.length) {
|
|
152
|
+
const classPosition = resolve(stringExpressions, (eachAttrStart, eachClassPositionEnd, [eachPattern, pair])=>{
|
|
153
|
+
const eachClassName = text.substring(eachAttrStart, eachClassPositionEnd);
|
|
154
|
+
/**
|
|
155
|
+
* @example <div class=""></div>
|
|
156
|
+
*/ if (eachClassName === undefined) {
|
|
157
|
+
return {
|
|
158
|
+
range: {
|
|
159
|
+
start: eachAttrStart,
|
|
160
|
+
end: eachAttrStart
|
|
161
|
+
},
|
|
162
|
+
token: '',
|
|
163
|
+
raw: ''
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const classNameStart = eachAttrStart;
|
|
167
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, pair);
|
|
168
|
+
if (classPosition) return classPosition;
|
|
169
|
+
});
|
|
170
|
+
if (classPosition) return classPosition;
|
|
171
|
+
}
|
|
172
|
+
if (classAttributeBindings) {
|
|
173
|
+
for(const eachClassAttribute in classAttributeBindings){
|
|
174
|
+
const eachClassAttributeBinding = classAttributeBindings[eachClassAttribute];
|
|
175
|
+
if (eachClassAttributeBinding === false) continue;
|
|
176
|
+
assignmentExpressions.push([
|
|
177
|
+
eachClassAttribute + '=',
|
|
178
|
+
eachClassAttributeBinding[0],
|
|
179
|
+
eachClassAttributeBinding[1]
|
|
180
|
+
]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* attribute binding
|
|
185
|
+
* @example <div className={''}></div>
|
|
186
|
+
* @example <div :class="isActive ? 'block' : 'hidden'"></div>
|
|
187
|
+
* */ if (assignmentExpressions?.length) {
|
|
188
|
+
const classPosition = resolve(assignmentExpressions, (eachAttrStart, eachClassPositionEnd, eachClassMatcher)=>{
|
|
189
|
+
const eachClassPositionExpression = text.substring(eachAttrStart, eachClassPositionEnd);
|
|
190
|
+
/**
|
|
191
|
+
* @example <div className={""}></div>
|
|
192
|
+
*/ if ([
|
|
193
|
+
'""',
|
|
194
|
+
'\'\'',
|
|
195
|
+
'``'
|
|
196
|
+
].includes(eachClassPositionExpression)) {
|
|
197
|
+
return {
|
|
198
|
+
range: {
|
|
199
|
+
start: eachAttrStart + 1,
|
|
200
|
+
end: eachAttrStart + 1
|
|
201
|
+
},
|
|
202
|
+
raw: '',
|
|
203
|
+
token: ''
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// 1. "
|
|
207
|
+
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)"([\s\S]*?)(?<!\\)"/g)){
|
|
208
|
+
if (classExpressionMatch.index === undefined) continue;
|
|
209
|
+
const eachClassName = classExpressionMatch[1];
|
|
210
|
+
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // " length
|
|
211
|
+
;
|
|
212
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '"');
|
|
213
|
+
if (classPosition) return classPosition;
|
|
214
|
+
}
|
|
215
|
+
// 2. '
|
|
216
|
+
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)'([\s\S]*?)(?<!\\)'/g)){
|
|
217
|
+
if (classExpressionMatch.index === undefined) continue;
|
|
218
|
+
const eachClassName = classExpressionMatch[1];
|
|
219
|
+
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // ' length
|
|
220
|
+
;
|
|
221
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '\'');
|
|
222
|
+
if (classPosition) return classPosition;
|
|
223
|
+
}
|
|
224
|
+
// 3. `
|
|
225
|
+
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)`([\s\S]*?)(?<!\\)`/g)){
|
|
226
|
+
if (classExpressionMatch.index === undefined) continue;
|
|
227
|
+
const eachClassName = classExpressionMatch[1];
|
|
228
|
+
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // ` length
|
|
229
|
+
;
|
|
230
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '`');
|
|
231
|
+
if (classPosition) return classPosition;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
if (classPosition) return classPosition;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
isDocumentAccepted(doc) {
|
|
238
|
+
if (!this.settings.exclude) return true;
|
|
239
|
+
for (const exclude of this.settings.exclude){
|
|
240
|
+
if (minimatch.minimatch(doc.uri, exclude)) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
module.exports = CSSLanguageService;
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { MasterCSS } from '@master/css';
|
|
3
|
+
import EventEmitter from 'node:events';
|
|
4
|
+
import type { Position } from 'vscode-languageserver-protocol';
|
|
5
|
+
import { type Settings } from './settings';
|
|
6
|
+
import inspectSyntax from './features/inspect-syntax';
|
|
7
|
+
import renderSyntaxColors from './features/render-syntax-colors';
|
|
8
|
+
import editSyntaxColors from './features/edit-syntax-colors';
|
|
9
|
+
import suggestSyntax from './features/suggest-syntax';
|
|
10
|
+
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
11
|
+
export type ClassPosition = {
|
|
12
|
+
range: {
|
|
13
|
+
start: number;
|
|
14
|
+
end: number;
|
|
15
|
+
};
|
|
16
|
+
raw: string;
|
|
17
|
+
token: string;
|
|
18
|
+
};
|
|
19
|
+
export default class CSSLanguageService extends EventEmitter {
|
|
20
|
+
customSettings?: Settings | undefined;
|
|
21
|
+
css: MasterCSS;
|
|
22
|
+
settings: Settings;
|
|
23
|
+
constructor(customSettings?: Settings | undefined);
|
|
24
|
+
inspectSyntax(...params: Parameters<typeof inspectSyntax>): import("vscode-languageserver-protocol").Hover | undefined;
|
|
25
|
+
renderSyntaxColors(...params: Parameters<typeof renderSyntaxColors>): Promise<import("vscode-languageserver-protocol").ColorInformation[] | undefined> | undefined;
|
|
26
|
+
editSyntaxColors(...params: Parameters<typeof editSyntaxColors>): import("vscode-languageserver-protocol").ColorPresentation[] | undefined;
|
|
27
|
+
suggestSyntax(...params: Parameters<typeof suggestSyntax>): import("vscode-languageserver-protocol").CompletionItem[] | undefined;
|
|
28
|
+
getClassPosition(textDocument: TextDocument, position: Position): ClassPosition | undefined;
|
|
29
|
+
isDocumentAccepted(doc: TextDocument): boolean;
|
|
30
|
+
}
|
package/dist/core.mjs
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { MasterCSS } from '@master/css';
|
|
2
|
+
import extend from '@techor/extend';
|
|
3
|
+
import EventEmitter from 'node:events';
|
|
4
|
+
import settings from './settings.mjs';
|
|
5
|
+
import { minimatch } from 'minimatch';
|
|
6
|
+
import inspectSyntax from './features/inspect-syntax.mjs';
|
|
7
|
+
import renderSyntaxColors from './features/render-syntax-colors.mjs';
|
|
8
|
+
import editSyntaxColors from './features/edit-syntax-colors.mjs';
|
|
9
|
+
import suggestSyntax from './features/suggest-syntax.mjs';
|
|
10
|
+
import findMatchingPairs from './utils/find-matching-brackets.mjs';
|
|
11
|
+
import escapeRegexp from 'lodash.escaperegexp';
|
|
12
|
+
|
|
13
|
+
class CSSLanguageService extends EventEmitter {
|
|
14
|
+
customSettings;
|
|
15
|
+
css;
|
|
16
|
+
settings;
|
|
17
|
+
constructor(customSettings){
|
|
18
|
+
super();
|
|
19
|
+
this.customSettings = customSettings;
|
|
20
|
+
this.settings = extend(settings, customSettings);
|
|
21
|
+
this.css = new MasterCSS(this.settings.config);
|
|
22
|
+
}
|
|
23
|
+
inspectSyntax(...params) {
|
|
24
|
+
if (this.settings.inspectSyntax && this.isDocumentAccepted(params[0])) return inspectSyntax?.call(this, ...params);
|
|
25
|
+
}
|
|
26
|
+
renderSyntaxColors(...params) {
|
|
27
|
+
if (this.settings.renderSyntaxColors && this.isDocumentAccepted(params[0])) return renderSyntaxColors?.call(this, ...params);
|
|
28
|
+
}
|
|
29
|
+
editSyntaxColors(...params) {
|
|
30
|
+
if (this.settings.editSyntaxColors && this.isDocumentAccepted(params[0])) return editSyntaxColors?.call(this, ...params);
|
|
31
|
+
}
|
|
32
|
+
suggestSyntax(...params) {
|
|
33
|
+
if (this.settings.suggestSyntax && this.isDocumentAccepted(params[0])) return suggestSyntax?.call(this, ...params);
|
|
34
|
+
}
|
|
35
|
+
getClassPosition(textDocument, position) {
|
|
36
|
+
const positionIndex = textDocument.offsetAt(position);
|
|
37
|
+
const startIndex = textDocument.offsetAt({
|
|
38
|
+
line: position.line - 100,
|
|
39
|
+
character: 0
|
|
40
|
+
}) ?? 0;
|
|
41
|
+
const endIndex = textDocument.offsetAt({
|
|
42
|
+
line: position.line + 100,
|
|
43
|
+
character: 0
|
|
44
|
+
}) ?? undefined;
|
|
45
|
+
const text = textDocument.getText().substring(startIndex, endIndex);
|
|
46
|
+
const { classAttributeBindings, classAttributes, classDeclarations, classFunctions } = this.settings;
|
|
47
|
+
const normalizeClassNamePosition = (className, attrStart, escapeCharacter)=>{
|
|
48
|
+
/**
|
|
49
|
+
* Matching classes, including empty string after white space
|
|
50
|
+
* @example <div class="class-a class-b "></div>
|
|
51
|
+
* @url https://regex101.com/r/LnBLAV/1
|
|
52
|
+
*/ for (const eachClassMatch of className.matchAll(/(?:[^\s]+)?/g)){
|
|
53
|
+
if (eachClassMatch.index === undefined) continue;
|
|
54
|
+
const raw = eachClassMatch[0];
|
|
55
|
+
const classStartIndex = attrStart + eachClassMatch.index;
|
|
56
|
+
const classEndIndex = classStartIndex + raw.length;
|
|
57
|
+
if (classStartIndex <= positionIndex - startIndex && positionIndex - startIndex <= classEndIndex) {
|
|
58
|
+
return {
|
|
59
|
+
range: {
|
|
60
|
+
start: classStartIndex,
|
|
61
|
+
end: startIndex + classEndIndex
|
|
62
|
+
},
|
|
63
|
+
raw,
|
|
64
|
+
token: raw.replace(new RegExp('\\' + escapeCharacter, 'g'), escapeCharacter)
|
|
65
|
+
};
|
|
66
|
+
} else if (attrStart === classEndIndex) {
|
|
67
|
+
return {
|
|
68
|
+
range: {
|
|
69
|
+
start: attrStart,
|
|
70
|
+
end: attrStart
|
|
71
|
+
},
|
|
72
|
+
raw: '',
|
|
73
|
+
token: ''
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const resolve = (classMatchers, handle)=>{
|
|
79
|
+
for (const eachClassMatcher of classMatchers){
|
|
80
|
+
// eslint-disable-next-line prefer-const
|
|
81
|
+
let [eachPattern, start, end] = eachClassMatcher;
|
|
82
|
+
end = end ?? start;
|
|
83
|
+
for (const eachClassPostioinMatch of text.matchAll(new RegExp(`(?:\\s|\\.)${eachPattern}${escapeRegexp(start)}`, 'g'))){
|
|
84
|
+
if (eachClassPostioinMatch.index === undefined) continue;
|
|
85
|
+
const eachClassAttributeString = eachClassPostioinMatch[0];
|
|
86
|
+
const eachAttrStart = eachClassPostioinMatch.index + eachClassAttributeString.length;
|
|
87
|
+
const eachClassPositionEnd = findMatchingPairs(text, eachAttrStart, start, end);
|
|
88
|
+
if (!eachClassPositionEnd) continue;
|
|
89
|
+
if ((eachAttrStart <= positionIndex - startIndex && eachClassPositionEnd >= positionIndex - startIndex) === true) {
|
|
90
|
+
const classPosition = handle(eachAttrStart, eachClassPositionEnd, eachClassMatcher);
|
|
91
|
+
if (classPosition) return classPosition;
|
|
92
|
+
} else if (eachClassPostioinMatch.index > positionIndex - startIndex) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const stringExpressions = [];
|
|
99
|
+
const assignmentExpressions = [];
|
|
100
|
+
classAttributes?.forEach((eachClassAttribute)=>{
|
|
101
|
+
stringExpressions.push([
|
|
102
|
+
eachClassAttribute + '=',
|
|
103
|
+
'"',
|
|
104
|
+
'"'
|
|
105
|
+
], [
|
|
106
|
+
eachClassAttribute + '=',
|
|
107
|
+
'\'',
|
|
108
|
+
'\''
|
|
109
|
+
]);
|
|
110
|
+
});
|
|
111
|
+
classDeclarations?.forEach((eachClassDeclaration)=>{
|
|
112
|
+
stringExpressions.push([
|
|
113
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
114
|
+
'"',
|
|
115
|
+
'"'
|
|
116
|
+
], [
|
|
117
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
118
|
+
'`',
|
|
119
|
+
'`'
|
|
120
|
+
], [
|
|
121
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
122
|
+
'\'',
|
|
123
|
+
'\''
|
|
124
|
+
]);
|
|
125
|
+
assignmentExpressions.push([
|
|
126
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
127
|
+
'{',
|
|
128
|
+
'}'
|
|
129
|
+
]);
|
|
130
|
+
});
|
|
131
|
+
classFunctions?.forEach((eachClassFunction)=>{
|
|
132
|
+
/**
|
|
133
|
+
* @example clsx`class-a class-b`
|
|
134
|
+
*/ stringExpressions.push([
|
|
135
|
+
eachClassFunction,
|
|
136
|
+
'`',
|
|
137
|
+
'`'
|
|
138
|
+
]);
|
|
139
|
+
/**
|
|
140
|
+
* @example clsx('class-a class-b')
|
|
141
|
+
*/ assignmentExpressions.push([
|
|
142
|
+
eachClassFunction,
|
|
143
|
+
'(',
|
|
144
|
+
')'
|
|
145
|
+
]);
|
|
146
|
+
});
|
|
147
|
+
/**
|
|
148
|
+
* @example <div class=""></div>
|
|
149
|
+
* */ if (stringExpressions?.length) {
|
|
150
|
+
const classPosition = resolve(stringExpressions, (eachAttrStart, eachClassPositionEnd, [eachPattern, pair])=>{
|
|
151
|
+
const eachClassName = text.substring(eachAttrStart, eachClassPositionEnd);
|
|
152
|
+
/**
|
|
153
|
+
* @example <div class=""></div>
|
|
154
|
+
*/ if (eachClassName === undefined) {
|
|
155
|
+
return {
|
|
156
|
+
range: {
|
|
157
|
+
start: eachAttrStart,
|
|
158
|
+
end: eachAttrStart
|
|
159
|
+
},
|
|
160
|
+
token: '',
|
|
161
|
+
raw: ''
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const classNameStart = eachAttrStart;
|
|
165
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, pair);
|
|
166
|
+
if (classPosition) return classPosition;
|
|
167
|
+
});
|
|
168
|
+
if (classPosition) return classPosition;
|
|
169
|
+
}
|
|
170
|
+
if (classAttributeBindings) {
|
|
171
|
+
for(const eachClassAttribute in classAttributeBindings){
|
|
172
|
+
const eachClassAttributeBinding = classAttributeBindings[eachClassAttribute];
|
|
173
|
+
if (eachClassAttributeBinding === false) continue;
|
|
174
|
+
assignmentExpressions.push([
|
|
175
|
+
eachClassAttribute + '=',
|
|
176
|
+
eachClassAttributeBinding[0],
|
|
177
|
+
eachClassAttributeBinding[1]
|
|
178
|
+
]);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* attribute binding
|
|
183
|
+
* @example <div className={''}></div>
|
|
184
|
+
* @example <div :class="isActive ? 'block' : 'hidden'"></div>
|
|
185
|
+
* */ if (assignmentExpressions?.length) {
|
|
186
|
+
const classPosition = resolve(assignmentExpressions, (eachAttrStart, eachClassPositionEnd, eachClassMatcher)=>{
|
|
187
|
+
const eachClassPositionExpression = text.substring(eachAttrStart, eachClassPositionEnd);
|
|
188
|
+
/**
|
|
189
|
+
* @example <div className={""}></div>
|
|
190
|
+
*/ if ([
|
|
191
|
+
'""',
|
|
192
|
+
'\'\'',
|
|
193
|
+
'``'
|
|
194
|
+
].includes(eachClassPositionExpression)) {
|
|
195
|
+
return {
|
|
196
|
+
range: {
|
|
197
|
+
start: eachAttrStart + 1,
|
|
198
|
+
end: eachAttrStart + 1
|
|
199
|
+
},
|
|
200
|
+
raw: '',
|
|
201
|
+
token: ''
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// 1. "
|
|
205
|
+
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)"([\s\S]*?)(?<!\\)"/g)){
|
|
206
|
+
if (classExpressionMatch.index === undefined) continue;
|
|
207
|
+
const eachClassName = classExpressionMatch[1];
|
|
208
|
+
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // " length
|
|
209
|
+
;
|
|
210
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '"');
|
|
211
|
+
if (classPosition) return classPosition;
|
|
212
|
+
}
|
|
213
|
+
// 2. '
|
|
214
|
+
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)'([\s\S]*?)(?<!\\)'/g)){
|
|
215
|
+
if (classExpressionMatch.index === undefined) continue;
|
|
216
|
+
const eachClassName = classExpressionMatch[1];
|
|
217
|
+
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // ' length
|
|
218
|
+
;
|
|
219
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '\'');
|
|
220
|
+
if (classPosition) return classPosition;
|
|
221
|
+
}
|
|
222
|
+
// 3. `
|
|
223
|
+
for (const classExpressionMatch of eachClassPositionExpression.matchAll(/(?<!\\)`([\s\S]*?)(?<!\\)`/g)){
|
|
224
|
+
if (classExpressionMatch.index === undefined) continue;
|
|
225
|
+
const eachClassName = classExpressionMatch[1];
|
|
226
|
+
const classNameStart = eachAttrStart + classExpressionMatch.index + 1 // ` length
|
|
227
|
+
;
|
|
228
|
+
const classPosition = normalizeClassNamePosition(eachClassName, classNameStart, '`');
|
|
229
|
+
if (classPosition) return classPosition;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
if (classPosition) return classPosition;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
isDocumentAccepted(doc) {
|
|
236
|
+
if (!this.settings.exclude) return true;
|
|
237
|
+
for (const exclude of this.settings.exclude){
|
|
238
|
+
if (minimatch(doc.uri, exclude)) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export { CSSLanguageService as default };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var convertColorToken = require('../utils/convert-color-token.cjs');
|
|
4
|
+
|
|
5
|
+
function editSyntaxColors(document, color, range) {
|
|
6
|
+
const colorPresentations = [];
|
|
7
|
+
const selectedColorToken = document.getText(range);
|
|
8
|
+
const targetColorToken = convertColorToken(color, selectedColorToken, this.css);
|
|
9
|
+
if (targetColorToken) colorPresentations.push({
|
|
10
|
+
label: targetColorToken,
|
|
11
|
+
textEdit: {
|
|
12
|
+
range,
|
|
13
|
+
newText: targetColorToken
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
return colorPresentations;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = editSyntaxColors;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
2
|
+
import CSSLanguageService from '../core';
|
|
3
|
+
import type { ColorPresentationParams, ColorPresentation } from 'vscode-languageserver-protocol';
|
|
4
|
+
export default function editSyntaxColors(this: CSSLanguageService, document: TextDocument, color: ColorPresentationParams['color'], range: ColorPresentationParams['range']): ColorPresentation[];
|