@master/css-language-service 2.0.0-rc.6 → 2.0.0-rc.61
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 +63 -0
- package/dist/common.cjs +57 -0
- package/dist/common.d.ts +9 -0
- package/dist/common.mjs +48 -0
- package/dist/core.cjs +246 -0
- package/dist/core.d.ts +29 -0
- package/dist/core.mjs +244 -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 +19 -9
- 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 +29 -0
- package/dist/utils/get-color-completion-items.d.ts +3 -0
- package/dist/utils/get-color-completion-items.mjs +27 -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 +106 -0
- package/dist/utils/get-main-completion-items.d.ts +3 -0
- package/dist/utils/get-main-completion-items.mjs +104 -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 +184 -0
- package/dist/utils/get-value-completion-items.d.ts +3 -0
- package/dist/utils/get-value-completion-items.mjs +182 -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/core.mjs
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
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(), this.customSettings = customSettings;
|
|
19
|
+
this.settings = extend(settings, customSettings);
|
|
20
|
+
this.css = new MasterCSS(this.settings.config);
|
|
21
|
+
}
|
|
22
|
+
inspectSyntax(...params) {
|
|
23
|
+
if (this.settings.inspectSyntax && this.isDocumentAccepted(params[0])) return inspectSyntax?.call(this, ...params);
|
|
24
|
+
}
|
|
25
|
+
renderSyntaxColors(...params) {
|
|
26
|
+
if (this.settings.renderSyntaxColors && this.isDocumentAccepted(params[0])) return renderSyntaxColors?.call(this, ...params);
|
|
27
|
+
}
|
|
28
|
+
editSyntaxColors(...params) {
|
|
29
|
+
if (this.settings.editSyntaxColors && this.isDocumentAccepted(params[0])) return editSyntaxColors?.call(this, ...params);
|
|
30
|
+
}
|
|
31
|
+
suggestSyntax(...params) {
|
|
32
|
+
if (this.settings.suggestSyntax && this.isDocumentAccepted(params[0])) return suggestSyntax?.call(this, ...params);
|
|
33
|
+
}
|
|
34
|
+
getClassPosition(textDocument, position) {
|
|
35
|
+
const positionIndex = textDocument.offsetAt(position);
|
|
36
|
+
const startIndex = textDocument.offsetAt({
|
|
37
|
+
line: position.line - 100,
|
|
38
|
+
character: 0
|
|
39
|
+
}) ?? 0;
|
|
40
|
+
const endIndex = textDocument.offsetAt({
|
|
41
|
+
line: position.line + 100,
|
|
42
|
+
character: 0
|
|
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
|
+
]);
|
|
108
|
+
});
|
|
109
|
+
classDeclarations?.forEach((eachClassDeclaration)=>{
|
|
110
|
+
stringExpressions.push([
|
|
111
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
112
|
+
'"',
|
|
113
|
+
'"'
|
|
114
|
+
], [
|
|
115
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
116
|
+
'`',
|
|
117
|
+
'`'
|
|
118
|
+
], [
|
|
119
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
120
|
+
'\'',
|
|
121
|
+
'\''
|
|
122
|
+
]);
|
|
123
|
+
assignmentExpressions.push([
|
|
124
|
+
eachClassDeclaration + '(?:\\s+)?(?::|=)(?:\\s+)?',
|
|
125
|
+
'{',
|
|
126
|
+
'}'
|
|
127
|
+
]);
|
|
128
|
+
});
|
|
129
|
+
classFunctions?.forEach((eachClassFunction)=>{
|
|
130
|
+
/**
|
|
131
|
+
* @example clsx`class-a class-b`
|
|
132
|
+
*/ stringExpressions.push([
|
|
133
|
+
eachClassFunction,
|
|
134
|
+
'`',
|
|
135
|
+
'`'
|
|
136
|
+
]);
|
|
137
|
+
/**
|
|
138
|
+
* @example clsx('class-a class-b')
|
|
139
|
+
*/ assignmentExpressions.push([
|
|
140
|
+
eachClassFunction,
|
|
141
|
+
'(',
|
|
142
|
+
')'
|
|
143
|
+
]);
|
|
144
|
+
});
|
|
145
|
+
/**
|
|
146
|
+
* @example <div class=""></div>
|
|
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;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
isDocumentAccepted(doc) {
|
|
234
|
+
if (!this.settings.exclude) return true;
|
|
235
|
+
for (const exclude of this.settings.exclude){
|
|
236
|
+
if (minimatch(doc.uri, exclude)) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
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[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import convertColorByToken from '../utils/convert-color-token.mjs';
|
|
2
|
+
|
|
3
|
+
function editSyntaxColors(document, color, range) {
|
|
4
|
+
const colorPresentations = [];
|
|
5
|
+
const selectedColorToken = document.getText(range);
|
|
6
|
+
const targetColorToken = convertColorByToken(color, selectedColorToken, this.css);
|
|
7
|
+
if (targetColorToken) colorPresentations.push({
|
|
8
|
+
label: targetColorToken,
|
|
9
|
+
textEdit: {
|
|
10
|
+
range,
|
|
11
|
+
newText: targetColorToken
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
return colorPresentations;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { editSyntaxColors as default };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var getCssDataDocumentation = require('../utils/get-css-data-documentation.cjs');
|
|
4
|
+
var css = require('@master/css');
|
|
5
|
+
var cssDataProvider = require('../utils/css-data-provider.cjs');
|
|
6
|
+
var getUtilityInfo = require('../utils/get-utility-info.cjs');
|
|
7
|
+
|
|
8
|
+
function inspectSyntax(document, position) {
|
|
9
|
+
const classPosition = this.getClassPosition(document, position);
|
|
10
|
+
if (!classPosition) return;
|
|
11
|
+
const { token } = classPosition;
|
|
12
|
+
const range = {
|
|
13
|
+
start: document.positionAt(classPosition.range.start),
|
|
14
|
+
end: document.positionAt(classPosition.range.end)
|
|
15
|
+
};
|
|
16
|
+
const componentClasses = this.css.components.get(token);
|
|
17
|
+
if (componentClasses) {
|
|
18
|
+
const documentation = getCssDataDocumentation.getCSSDataDocumentation({}, {
|
|
19
|
+
generatedCSS: css.generateCSS([
|
|
20
|
+
token
|
|
21
|
+
], this.css),
|
|
22
|
+
docs: '/guide/components'
|
|
23
|
+
});
|
|
24
|
+
if (documentation) {
|
|
25
|
+
return {
|
|
26
|
+
contents: {
|
|
27
|
+
kind: documentation.kind,
|
|
28
|
+
value: `(style) ` + componentClasses.join(' ') + '\n' + documentation.value
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
const rules = this.css.generate(token);
|
|
34
|
+
const rule = rules[0];
|
|
35
|
+
if (rule) {
|
|
36
|
+
if (rule.type === css.SyntaxRuleType.Utility) {
|
|
37
|
+
const { data, docs } = getUtilityInfo(rule.registeredSyntax, this.css);
|
|
38
|
+
const documentation = getCssDataDocumentation.getCSSDataDocumentation(data, {
|
|
39
|
+
generatedCSS: css.generateCSS([
|
|
40
|
+
token
|
|
41
|
+
], this.css),
|
|
42
|
+
docs
|
|
43
|
+
});
|
|
44
|
+
if (documentation) {
|
|
45
|
+
return {
|
|
46
|
+
contents: documentation,
|
|
47
|
+
range
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
const nativeProperties = cssDataProvider.provideProperties();
|
|
52
|
+
const nativeCSSPropertyData = nativeProperties.find(({ name })=>name === rule.id);
|
|
53
|
+
const documentation = getCssDataDocumentation.getCSSDataDocumentation(nativeCSSPropertyData, {
|
|
54
|
+
generatedCSS: css.generateCSS([
|
|
55
|
+
token
|
|
56
|
+
], this.css),
|
|
57
|
+
docs: '/reference/' + (css.isCoreRule(rule.id) && rule.id)
|
|
58
|
+
});
|
|
59
|
+
if (documentation) {
|
|
60
|
+
return {
|
|
61
|
+
contents: documentation,
|
|
62
|
+
range
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = inspectSyntax;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Hover, HoverParams } from 'vscode-languageserver-protocol';
|
|
2
|
+
import type CSSLanguageService from '../core';
|
|
3
|
+
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
4
|
+
export default function inspectSyntax(this: CSSLanguageService, document: TextDocument, position: HoverParams['position']): Hover | undefined;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getCSSDataDocumentation } from '../utils/get-css-data-documentation.mjs';
|
|
2
|
+
import { generateCSS, SyntaxRuleType, isCoreRule } from '@master/css';
|
|
3
|
+
import cssDataProvider from '../utils/css-data-provider.mjs';
|
|
4
|
+
import getUtilityInfo from '../utils/get-utility-info.mjs';
|
|
5
|
+
|
|
6
|
+
function inspectSyntax(document, position) {
|
|
7
|
+
const classPosition = this.getClassPosition(document, position);
|
|
8
|
+
if (!classPosition) return;
|
|
9
|
+
const { token } = classPosition;
|
|
10
|
+
const range = {
|
|
11
|
+
start: document.positionAt(classPosition.range.start),
|
|
12
|
+
end: document.positionAt(classPosition.range.end)
|
|
13
|
+
};
|
|
14
|
+
const componentClasses = this.css.components.get(token);
|
|
15
|
+
if (componentClasses) {
|
|
16
|
+
const documentation = getCSSDataDocumentation({}, {
|
|
17
|
+
generatedCSS: generateCSS([
|
|
18
|
+
token
|
|
19
|
+
], this.css),
|
|
20
|
+
docs: '/guide/components'
|
|
21
|
+
});
|
|
22
|
+
if (documentation) {
|
|
23
|
+
return {
|
|
24
|
+
contents: {
|
|
25
|
+
kind: documentation.kind,
|
|
26
|
+
value: `(style) ` + componentClasses.join(' ') + '\n' + documentation.value
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
const rules = this.css.generate(token);
|
|
32
|
+
const rule = rules[0];
|
|
33
|
+
if (rule) {
|
|
34
|
+
if (rule.type === SyntaxRuleType.Utility) {
|
|
35
|
+
const { data, docs } = getUtilityInfo(rule.registeredSyntax, this.css);
|
|
36
|
+
const documentation = getCSSDataDocumentation(data, {
|
|
37
|
+
generatedCSS: generateCSS([
|
|
38
|
+
token
|
|
39
|
+
], this.css),
|
|
40
|
+
docs
|
|
41
|
+
});
|
|
42
|
+
if (documentation) {
|
|
43
|
+
return {
|
|
44
|
+
contents: documentation,
|
|
45
|
+
range
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
const nativeProperties = cssDataProvider.provideProperties();
|
|
50
|
+
const nativeCSSPropertyData = nativeProperties.find(({ name })=>name === rule.id);
|
|
51
|
+
const documentation = getCSSDataDocumentation(nativeCSSPropertyData, {
|
|
52
|
+
generatedCSS: generateCSS([
|
|
53
|
+
token
|
|
54
|
+
], this.css),
|
|
55
|
+
docs: '/reference/' + (isCoreRule(rule.id) && rule.id)
|
|
56
|
+
});
|
|
57
|
+
if (documentation) {
|
|
58
|
+
return {
|
|
59
|
+
contents: documentation,
|
|
60
|
+
range
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { inspectSyntax as default };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var regex = require('../utils/regex.cjs');
|
|
4
|
+
var culori = require('culori');
|
|
5
|
+
var css = require('@master/css');
|
|
6
|
+
|
|
7
|
+
async function renderSyntaxColors(document) {
|
|
8
|
+
const text = document.getText() ?? '';
|
|
9
|
+
const colorInformations = [];
|
|
10
|
+
for (const instanceMatch of text.matchAll(regex.instancePattern)){
|
|
11
|
+
if (instanceMatch.index === undefined) break;
|
|
12
|
+
const instanceStartIndex = instanceMatch.index;
|
|
13
|
+
const syntax = instanceMatch[0];
|
|
14
|
+
const rule = this.css.generate(syntax)[0];
|
|
15
|
+
if (rule && rule.type !== css.SyntaxRuleType.Utility) {
|
|
16
|
+
const keyTokenLength = rule.keyToken?.length ?? 0;
|
|
17
|
+
let currentLength = 0;
|
|
18
|
+
const resolveValueComponent = (valueComponent)=>{
|
|
19
|
+
if (valueComponent.text === undefined) return; // text is always existing, just for type
|
|
20
|
+
const startOffset = instanceStartIndex + keyTokenLength + currentLength;
|
|
21
|
+
// TODO: check number mt:30
|
|
22
|
+
const valueComponentTokenLength = valueComponent.token.length;
|
|
23
|
+
let color;
|
|
24
|
+
switch(valueComponent.type){
|
|
25
|
+
case 'function':
|
|
26
|
+
if ([
|
|
27
|
+
'rgb',
|
|
28
|
+
'rgba',
|
|
29
|
+
'hsl',
|
|
30
|
+
'hsla',
|
|
31
|
+
'hwb',
|
|
32
|
+
'lab',
|
|
33
|
+
'lch',
|
|
34
|
+
'oklab',
|
|
35
|
+
'oklch',
|
|
36
|
+
'color'
|
|
37
|
+
].includes(valueComponent.name)) {
|
|
38
|
+
color = culori.parse(valueComponent.text);
|
|
39
|
+
} else if (valueComponent.children.length) {
|
|
40
|
+
currentLength += valueComponent.name.length + 1 // function name + '('
|
|
41
|
+
;
|
|
42
|
+
valueComponent.children.forEach(resolveValueComponent);
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
case 'variable':
|
|
46
|
+
if (valueComponent.variable?.type === 'color') {
|
|
47
|
+
color = culori.parse(valueComponent.text);
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 'string':
|
|
51
|
+
if (valueComponent.text !== '#' && valueComponent.text?.startsWith('#')) {
|
|
52
|
+
color = culori.parse(valueComponent.text);
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
// check if rgba is valid
|
|
57
|
+
if (color) {
|
|
58
|
+
const rgbaColor = color.mode !== 'rgb' ? culori.converter('rgb')(color) : color;
|
|
59
|
+
colorInformations.push({
|
|
60
|
+
range: {
|
|
61
|
+
start: document.positionAt(startOffset),
|
|
62
|
+
end: document.positionAt(startOffset + valueComponentTokenLength)
|
|
63
|
+
},
|
|
64
|
+
color: {
|
|
65
|
+
red: rgbaColor.r,
|
|
66
|
+
green: rgbaColor.g,
|
|
67
|
+
blue: rgbaColor.b,
|
|
68
|
+
alpha: rgbaColor.alpha === undefined ? 1 : rgbaColor.alpha
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
currentLength += valueComponentTokenLength || 0;
|
|
73
|
+
};
|
|
74
|
+
rule.valueComponents.forEach(resolveValueComponent);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const colorIndexSet = new Set();
|
|
78
|
+
return colorInformations.filter((item)=>{
|
|
79
|
+
if (colorIndexSet.has(item.range.start)) {
|
|
80
|
+
return false;
|
|
81
|
+
} else {
|
|
82
|
+
colorIndexSet.add(item.range.start);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = renderSyntaxColors;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ColorInformation } from 'vscode-languageserver-protocol';
|
|
2
|
+
import CSSLanguageService from '../core';
|
|
3
|
+
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
4
|
+
export default function renderSyntaxColors(this: CSSLanguageService, document: TextDocument): Promise<ColorInformation[] | undefined>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { instancePattern } from '../utils/regex.mjs';
|
|
2
|
+
import { parse, converter } from 'culori';
|
|
3
|
+
import { SyntaxRuleType } from '@master/css';
|
|
4
|
+
|
|
5
|
+
async function renderSyntaxColors(document) {
|
|
6
|
+
const text = document.getText() ?? '';
|
|
7
|
+
const colorInformations = [];
|
|
8
|
+
for (const instanceMatch of text.matchAll(instancePattern)){
|
|
9
|
+
if (instanceMatch.index === undefined) break;
|
|
10
|
+
const instanceStartIndex = instanceMatch.index;
|
|
11
|
+
const syntax = instanceMatch[0];
|
|
12
|
+
const rule = this.css.generate(syntax)[0];
|
|
13
|
+
if (rule && rule.type !== SyntaxRuleType.Utility) {
|
|
14
|
+
const keyTokenLength = rule.keyToken?.length ?? 0;
|
|
15
|
+
let currentLength = 0;
|
|
16
|
+
const resolveValueComponent = (valueComponent)=>{
|
|
17
|
+
if (valueComponent.text === undefined) return; // text is always existing, just for type
|
|
18
|
+
const startOffset = instanceStartIndex + keyTokenLength + currentLength;
|
|
19
|
+
// TODO: check number mt:30
|
|
20
|
+
const valueComponentTokenLength = valueComponent.token.length;
|
|
21
|
+
let color;
|
|
22
|
+
switch(valueComponent.type){
|
|
23
|
+
case 'function':
|
|
24
|
+
if ([
|
|
25
|
+
'rgb',
|
|
26
|
+
'rgba',
|
|
27
|
+
'hsl',
|
|
28
|
+
'hsla',
|
|
29
|
+
'hwb',
|
|
30
|
+
'lab',
|
|
31
|
+
'lch',
|
|
32
|
+
'oklab',
|
|
33
|
+
'oklch',
|
|
34
|
+
'color'
|
|
35
|
+
].includes(valueComponent.name)) {
|
|
36
|
+
color = parse(valueComponent.text);
|
|
37
|
+
} else if (valueComponent.children.length) {
|
|
38
|
+
currentLength += valueComponent.name.length + 1 // function name + '('
|
|
39
|
+
;
|
|
40
|
+
valueComponent.children.forEach(resolveValueComponent);
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
case 'variable':
|
|
44
|
+
if (valueComponent.variable?.type === 'color') {
|
|
45
|
+
color = parse(valueComponent.text);
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
case 'string':
|
|
49
|
+
if (valueComponent.text !== '#' && valueComponent.text?.startsWith('#')) {
|
|
50
|
+
color = parse(valueComponent.text);
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
// check if rgba is valid
|
|
55
|
+
if (color) {
|
|
56
|
+
const rgbaColor = color.mode !== 'rgb' ? converter('rgb')(color) : color;
|
|
57
|
+
colorInformations.push({
|
|
58
|
+
range: {
|
|
59
|
+
start: document.positionAt(startOffset),
|
|
60
|
+
end: document.positionAt(startOffset + valueComponentTokenLength)
|
|
61
|
+
},
|
|
62
|
+
color: {
|
|
63
|
+
red: rgbaColor.r,
|
|
64
|
+
green: rgbaColor.g,
|
|
65
|
+
blue: rgbaColor.b,
|
|
66
|
+
alpha: rgbaColor.alpha === undefined ? 1 : rgbaColor.alpha
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
currentLength += valueComponentTokenLength || 0;
|
|
71
|
+
};
|
|
72
|
+
rule.valueComponents.forEach(resolveValueComponent);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const colorIndexSet = new Set();
|
|
76
|
+
return colorInformations.filter((item)=>{
|
|
77
|
+
if (colorIndexSet.has(item.range.start)) {
|
|
78
|
+
return false;
|
|
79
|
+
} else {
|
|
80
|
+
colorIndexSet.add(item.range.start);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { renderSyntaxColors as default };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var querySyntaxCompletions = require('../utils/query-syntax-completions.cjs');
|
|
4
|
+
|
|
5
|
+
function suggestSyntax(document, position, context) {
|
|
6
|
+
const classPosition = this.getClassPosition(document, position);
|
|
7
|
+
if (classPosition !== undefined) {
|
|
8
|
+
const q = context?.triggerCharacter === ' ' ? '' : document.getText({
|
|
9
|
+
start: document.positionAt(classPosition.range.start),
|
|
10
|
+
end: position
|
|
11
|
+
});
|
|
12
|
+
return querySyntaxCompletions(q, this.css);
|
|
13
|
+
}
|
|
14
|
+
// todo
|
|
15
|
+
// else if (isInstance === true && checkConfigColorsBlock(document, position) === true) {
|
|
16
|
+
// return getColorCompletionItems(this.css)
|
|
17
|
+
// }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = suggestSyntax;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompletionItem, CompletionParams } from 'vscode-languageserver-protocol';
|
|
2
|
+
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
3
|
+
import CSSLanguageService from '../core';
|
|
4
|
+
export default function suggestSyntax(this: CSSLanguageService, document: TextDocument, position: CompletionParams['position'], context: CompletionParams['context']): CompletionItem[] | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import querySyntaxCompletions from '../utils/query-syntax-completions.mjs';
|
|
2
|
+
|
|
3
|
+
function suggestSyntax(document, position, context) {
|
|
4
|
+
const classPosition = this.getClassPosition(document, position);
|
|
5
|
+
if (classPosition !== undefined) {
|
|
6
|
+
const q = context?.triggerCharacter === ' ' ? '' : document.getText({
|
|
7
|
+
start: document.positionAt(classPosition.range.start),
|
|
8
|
+
end: position
|
|
9
|
+
});
|
|
10
|
+
return querySyntaxCompletions(q, this.css);
|
|
11
|
+
}
|
|
12
|
+
// todo
|
|
13
|
+
// else if (isInstance === true && checkConfigColorsBlock(document, position) === true) {
|
|
14
|
+
// return getColorCompletionItems(this.css)
|
|
15
|
+
// }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { suggestSyntax as default };
|