@master/css-language-server 2.0.0-rc.74 → 2.0.0-rc.76
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 +11 -2
- package/dist/core.d.ts +10 -4
- package/dist/core.js +74 -21
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -73,7 +73,9 @@ import CSSLanguageServer from '@master/css-language-server'
|
|
|
73
73
|
const languageServer = new CSSLanguageServer(connection, customSettings)
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
`CSSLanguageServer` wraps `@master/css-language-service` with LSP workspace lifecycle, completion, hover, document color, color presentation,
|
|
76
|
+
`CSSLanguageServer` wraps `@master/css-language-service` with LSP workspace lifecycle, completion, hover, document color, color presentation, semantic token, and directive formatting handlers.
|
|
77
|
+
|
|
78
|
+
Diagnostics are intentionally limited to language-server-owned behavior: CSS directive diagnostics and project manifest loading diagnostics. Class syntax and policy rules such as sorting, canonical class preference, conflict detection, invalid classes, and raw-value approval are owned by `@master/eslint-plugin-css`.
|
|
77
79
|
|
|
78
80
|
## Semantic tokens
|
|
79
81
|
|
|
@@ -87,6 +89,12 @@ The language server supports full-document and active-position semantic tokens.
|
|
|
87
89
|
|
|
88
90
|
CSS directive syntax is highlighted by the shared TextMate grammar. Server semantic tokens cover Master CSS class-list spans and directive class-list spans such as `@compose` and `@safelist`.
|
|
89
91
|
|
|
92
|
+
## Formatting
|
|
93
|
+
|
|
94
|
+
The server advertises `documentFormattingProvider` and `documentRangeFormattingProvider` when `formatDirectives` is enabled. Formatting returns directive-only edits for CSS, SCSS, and LESS documents, plus CSS-family `<style>` blocks in Vue, Svelte, and Astro documents.
|
|
95
|
+
|
|
96
|
+
Directive formatting normalizes safe directive spacing and repairs class-list important markers such as `bg:transparent !` to `bg:transparent!`. It does not run the compiler and does not change generated CSS output.
|
|
97
|
+
|
|
90
98
|
## Settings
|
|
91
99
|
|
|
92
100
|
```js
|
|
@@ -97,6 +105,7 @@ import { settings } from '@master/css-language-server'
|
|
|
97
105
|
| --- | --- | --- | --- |
|
|
98
106
|
| `workspaces` | `FastGlobPattern[] \| 'auto'` | `'auto'` | Workspace roots where independent language services are created. The root workspace is always included. |
|
|
99
107
|
| `verbose` | `boolean` | `false` | Print server logs. |
|
|
108
|
+
| `formatDirectives` | `boolean` | `true` | Enables LSP document and range formatting for Master CSS directives. |
|
|
100
109
|
| `embeddedSyntaxHighlighting` | `'active' \| 'always' \| 'off'` | `'active'` | Inherited language-service semantic token mode. |
|
|
101
110
|
|
|
102
|
-
With `workspaces: 'auto'`, the server creates workspaces from CSS files containing `@master entry;`
|
|
111
|
+
With `workspaces: 'auto'`, the server creates workspaces from CSS files importing `@master/css`, CSS files containing the lightweight `@master entry;` marker, and `package.json` files that declare Master CSS package dependencies.
|
package/dist/core.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ClientCapabilities, ColorPresentationParams, CompletionParams, Connection, DidChangeConfigurationParams, DocumentColorParams, HoverParams, InitializeParams, InitializeResult, RemoteConsole, SemanticTokensParams, TextDocumentChangeEvent, TextDocumentPositionParams, TextDocuments, WorkspaceFolder } from "vscode-languageserver/node";
|
|
1
|
+
import { ClientCapabilities, ColorPresentationParams, CompletionParams, Connection, DidChangeConfigurationParams, DocumentColorParams, DocumentFormattingParams, DocumentRangeFormattingParams, HoverParams, InitializeParams, InitializeResult, RemoteConsole, SemanticTokensParams, TextDocumentChangeEvent, TextDocumentPositionParams, TextDocuments, TextEdit, WorkspaceFolder } from "vscode-languageserver/node";
|
|
2
2
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
3
|
-
import CSSLanguageService
|
|
3
|
+
import CSSLanguageService from "@master/css-language-service";
|
|
4
4
|
import { MasterCSSWorkspacePackageResolution } from "@master/css-project/workspace";
|
|
5
5
|
import { CSSLanguageRuntime } from "@master/css-language";
|
|
6
6
|
import { Settings as Settings$1 } from "./settings.js";
|
|
@@ -10,10 +10,11 @@ declare interface Workspace {
|
|
|
10
10
|
uri: string;
|
|
11
11
|
openedTextDocuments: TextDocument[];
|
|
12
12
|
languageService?: CSSLanguageService;
|
|
13
|
-
languageServiceSettings: Settings;
|
|
13
|
+
languageServiceSettings: Settings$1;
|
|
14
14
|
languageRuntime?: CSSLanguageRuntime;
|
|
15
15
|
languageRuntimeResolution?: MasterCSSWorkspacePackageResolution;
|
|
16
16
|
languageRuntimeSource?: 'workspace' | 'bundled';
|
|
17
|
+
manifestErrors?: unknown[];
|
|
17
18
|
planEntries?: string[];
|
|
18
19
|
}
|
|
19
20
|
declare const ACTIVE_SEMANTIC_TOKENS_REQUEST = "masterCSS/renderActiveSemanticTokens";
|
|
@@ -38,6 +39,9 @@ declare class CSSLanguageServer {
|
|
|
38
39
|
onCompletion(params: CompletionParams): Promise<import("vscode-languageserver-protocol").CompletionItem[] | undefined>;
|
|
39
40
|
onDocumentColor(params: DocumentColorParams): Promise<import("vscode-languageserver-protocol").ColorInformation[]>;
|
|
40
41
|
onColorPresentation(params: ColorPresentationParams): Promise<import("vscode-languageserver-protocol").ColorPresentation[]>;
|
|
42
|
+
private getWorkspaceDocument;
|
|
43
|
+
onDocumentFormatting(params: DocumentFormattingParams): Promise<TextEdit[]>;
|
|
44
|
+
onDocumentRangeFormatting(params: DocumentRangeFormattingParams): Promise<TextEdit[]>;
|
|
41
45
|
onSemanticTokens(params: SemanticTokensParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
|
|
42
46
|
onDocumentSemanticTokens(params: SemanticTokensParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
|
|
43
47
|
onActiveSemanticTokens(params: TextDocumentPositionParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
|
|
@@ -55,7 +59,9 @@ declare class CSSLanguageServer {
|
|
|
55
59
|
private importWorkspaceModule;
|
|
56
60
|
destroyLanguageService(workspace: Workspace): void;
|
|
57
61
|
findClosestWorkspace(textDocumentURI: string): Workspace;
|
|
58
|
-
private
|
|
62
|
+
private publishDiagnostics;
|
|
63
|
+
private createCSSDirectiveDiagnostics;
|
|
64
|
+
private createManifestLoadingDiagnostics;
|
|
59
65
|
private createCSSDirectiveDiagnostic;
|
|
60
66
|
private createCSSDirectiveRelatedInformation;
|
|
61
67
|
private createCSSDirectiveRange;
|
package/dist/core.js
CHANGED
|
@@ -35,6 +35,8 @@ const SERVER_CAPABILITIES = {
|
|
|
35
35
|
},
|
|
36
36
|
colorProvider: true,
|
|
37
37
|
hoverProvider: true,
|
|
38
|
+
documentFormattingProvider: true,
|
|
39
|
+
documentRangeFormattingProvider: true,
|
|
38
40
|
semanticTokensProvider: {
|
|
39
41
|
legend: SEMANTIC_TOKENS_LEGEND,
|
|
40
42
|
full: true
|
|
@@ -137,7 +139,7 @@ var CSSLanguageServer = class {
|
|
|
137
139
|
} });
|
|
138
140
|
}
|
|
139
141
|
start() {
|
|
140
|
-
this.disposables.push(this.documents.onDidSave(this.onDidSave.bind(this)), this.documents.onDidOpen(this.onDidOpen.bind(this)), this.documents.onDidChangeContent(this.onDidChangeContent.bind(this)), this.documents.onDidClose(this.onDidClose.bind(this)), this.documents.listen(this.connection), this.connection.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)), this.connection.onHover(this.onHover.bind(this)), this.connection.onCompletion(this.onCompletion.bind(this)), this.connection.onDocumentColor(this.onDocumentColor.bind(this)), this.connection.onColorPresentation(this.onColorPresentation.bind(this)), this.connection.languages.semanticTokens.on(this.onSemanticTokens.bind(this)), this.connection.onRequest(DOCUMENT_SEMANTIC_TOKENS_REQUEST, this.onDocumentSemanticTokens.bind(this)), this.connection.onRequest(ACTIVE_SEMANTIC_TOKENS_REQUEST, this.onActiveSemanticTokens.bind(this)), this.connection.onInitialize(this.onInitialize.bind(this)), this.connection.onInitialized(() => this.init()));
|
|
142
|
+
this.disposables.push(this.documents.onDidSave(this.onDidSave.bind(this)), this.documents.onDidOpen(this.onDidOpen.bind(this)), this.documents.onDidChangeContent(this.onDidChangeContent.bind(this)), this.documents.onDidClose(this.onDidClose.bind(this)), this.documents.listen(this.connection), this.connection.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)), this.connection.onHover(this.onHover.bind(this)), this.connection.onCompletion(this.onCompletion.bind(this)), this.connection.onDocumentColor(this.onDocumentColor.bind(this)), this.connection.onColorPresentation(this.onColorPresentation.bind(this)), this.connection.onDocumentFormatting(this.onDocumentFormatting.bind(this)), this.connection.onDocumentRangeFormatting(this.onDocumentRangeFormatting.bind(this)), this.connection.languages.semanticTokens.on(this.onSemanticTokens.bind(this)), this.connection.onRequest(DOCUMENT_SEMANTIC_TOKENS_REQUEST, this.onDocumentSemanticTokens.bind(this)), this.connection.onRequest(ACTIVE_SEMANTIC_TOKENS_REQUEST, this.onActiveSemanticTokens.bind(this)), this.connection.onInitialize(this.onInitialize.bind(this)), this.connection.onInitialized(() => this.init()));
|
|
141
143
|
this.connection.listen();
|
|
142
144
|
}
|
|
143
145
|
init() {
|
|
@@ -158,6 +160,10 @@ var CSSLanguageServer = class {
|
|
|
158
160
|
if (params.workspaceFolders?.length) this.workspaceFolders = params.workspaceFolders;
|
|
159
161
|
const capabilities = { ...SERVER_CAPABILITIES };
|
|
160
162
|
if (this.settings?.embeddedSyntaxHighlighting !== "always") delete capabilities.semanticTokensProvider;
|
|
163
|
+
if (!this.settings?.formatDirectives) {
|
|
164
|
+
delete capabilities.documentFormattingProvider;
|
|
165
|
+
delete capabilities.documentRangeFormattingProvider;
|
|
166
|
+
}
|
|
161
167
|
return { capabilities };
|
|
162
168
|
}
|
|
163
169
|
async onHover(params) {
|
|
@@ -194,13 +200,30 @@ var CSSLanguageServer = class {
|
|
|
194
200
|
}
|
|
195
201
|
return [];
|
|
196
202
|
}
|
|
203
|
+
getWorkspaceDocument(uri) {
|
|
204
|
+
const workspace = this.findClosestWorkspace(uri);
|
|
205
|
+
if (!workspace?.languageService) return;
|
|
206
|
+
const document = this.documents.get(uri) ?? workspace.openedTextDocuments.find((document) => document.uri === uri);
|
|
207
|
+
if (!document) return;
|
|
208
|
+
return {
|
|
209
|
+
workspace,
|
|
210
|
+
document
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async onDocumentFormatting(params) {
|
|
214
|
+
await this.init();
|
|
215
|
+
const context = this.getWorkspaceDocument(params.textDocument.uri);
|
|
216
|
+
return context?.workspace.languageService?.formatDirectives(context.document) ?? [];
|
|
217
|
+
}
|
|
218
|
+
async onDocumentRangeFormatting(params) {
|
|
219
|
+
await this.init();
|
|
220
|
+
const context = this.getWorkspaceDocument(params.textDocument.uri);
|
|
221
|
+
return context?.workspace.languageService?.formatDirectives(context.document, params.range) ?? [];
|
|
222
|
+
}
|
|
197
223
|
async onSemanticTokens(params) {
|
|
198
224
|
await this.init();
|
|
199
|
-
const
|
|
200
|
-
if (workspace?.
|
|
201
|
-
const document = this.documents.get(params.textDocument.uri) ?? workspace.openedTextDocuments.find((document) => document.uri === params.textDocument.uri);
|
|
202
|
-
if (document) return workspace.languageService.renderSemanticTokens(document) ?? { data: [] };
|
|
203
|
-
}
|
|
225
|
+
const context = this.getWorkspaceDocument(params.textDocument.uri);
|
|
226
|
+
if (context) return context.workspace.languageService?.renderSemanticTokens(context.document) ?? { data: [] };
|
|
204
227
|
return { data: [] };
|
|
205
228
|
}
|
|
206
229
|
async onDocumentSemanticTokens(params) {
|
|
@@ -208,11 +231,8 @@ var CSSLanguageServer = class {
|
|
|
208
231
|
}
|
|
209
232
|
async onActiveSemanticTokens(params) {
|
|
210
233
|
await this.init();
|
|
211
|
-
const
|
|
212
|
-
if (workspace?.
|
|
213
|
-
const document = this.documents.get(params.textDocument.uri) ?? workspace.openedTextDocuments.find((document) => document.uri === params.textDocument.uri);
|
|
214
|
-
if (document) return workspace.languageService.renderSemanticTokensAtPosition(document, params.position) ?? { data: [] };
|
|
215
|
-
}
|
|
234
|
+
const context = this.getWorkspaceDocument(params.textDocument.uri);
|
|
235
|
+
if (context) return context.workspace.languageService?.renderSemanticTokensAtPosition(context.document, params.position) ?? { data: [] };
|
|
216
236
|
return { data: [] };
|
|
217
237
|
}
|
|
218
238
|
async onDidOpen(params) {
|
|
@@ -220,18 +240,18 @@ var CSSLanguageServer = class {
|
|
|
220
240
|
const workspace = this.findClosestWorkspace(params.document.uri);
|
|
221
241
|
if (!workspace) return;
|
|
222
242
|
if (workspace.openedTextDocuments.includes(params.document)) {
|
|
223
|
-
this.
|
|
243
|
+
this.publishDiagnostics(params.document, workspace);
|
|
224
244
|
return;
|
|
225
245
|
}
|
|
226
246
|
if (!workspace.openedTextDocuments.length) await this.initWorkspaceLanguageService(workspace);
|
|
227
247
|
workspace.openedTextDocuments.push(params.document);
|
|
228
|
-
this.
|
|
248
|
+
this.publishDiagnostics(params.document, workspace);
|
|
229
249
|
}
|
|
230
250
|
async onDidChangeContent(params) {
|
|
231
251
|
await this.init();
|
|
232
252
|
const workspace = this.findClosestWorkspace(params.document.uri);
|
|
233
253
|
if (!workspace) return;
|
|
234
|
-
this.
|
|
254
|
+
this.publishDiagnostics(params.document, workspace);
|
|
235
255
|
}
|
|
236
256
|
async onDidClose(params) {
|
|
237
257
|
await this.init();
|
|
@@ -248,7 +268,7 @@ var CSSLanguageServer = class {
|
|
|
248
268
|
await this.init();
|
|
249
269
|
const workspace = this.findClosestWorkspace(params.document.uri);
|
|
250
270
|
if (!workspace) return;
|
|
251
|
-
this.
|
|
271
|
+
this.publishDiagnostics(params.document, workspace);
|
|
252
272
|
if (path.basename(URI.parse(params.document.uri).fsPath).endsWith(".css")) {
|
|
253
273
|
this.refreshSemanticTokens();
|
|
254
274
|
this.connection.sendRequest("masterCSS/restart", { title: "Updating Master CSS configuration" });
|
|
@@ -263,7 +283,7 @@ var CSSLanguageServer = class {
|
|
|
263
283
|
this.globalWorkspace.languageServiceSettings = this.settings;
|
|
264
284
|
this.refreshSemanticTokens();
|
|
265
285
|
this.connection.sendRequest("masterCSS/restart", { title: "Updating Master CSS settings" });
|
|
266
|
-
for (const workspace of [this.globalWorkspace, ...this.workspaces.values()]) for (const document of workspace.openedTextDocuments) this.
|
|
286
|
+
for (const workspace of [this.globalWorkspace, ...this.workspaces.values()]) for (const document of workspace.openedTextDocuments) this.publishDiagnostics(document, workspace);
|
|
267
287
|
}
|
|
268
288
|
}
|
|
269
289
|
async initWorkspaceFolder(workspaceFolderURI) {
|
|
@@ -298,10 +318,12 @@ var CSSLanguageServer = class {
|
|
|
298
318
|
async initWorkspaceLanguageService(workspace) {
|
|
299
319
|
workspace.languageRuntime = await this.loadWorkspaceLanguageRuntime(workspace);
|
|
300
320
|
let workspacePlan;
|
|
321
|
+
workspace.manifestErrors = [];
|
|
301
322
|
if (workspace !== this.globalWorkspace) {
|
|
302
323
|
try {
|
|
303
324
|
workspacePlan = await this.loadWorkspacePlan(workspace);
|
|
304
325
|
} catch (e) {
|
|
326
|
+
workspace.manifestErrors = [e];
|
|
305
327
|
this.console.info(`Failed to load manifest from ${workspace.uri}`);
|
|
306
328
|
this.console.error(e instanceof Error ? e.stack : e.toString());
|
|
307
329
|
}
|
|
@@ -396,8 +418,17 @@ var CSSLanguageServer = class {
|
|
|
396
418
|
this.console.info(`This is an external document ${textDocumentURI} with the global workspace`);
|
|
397
419
|
return this.globalWorkspace;
|
|
398
420
|
}
|
|
399
|
-
|
|
400
|
-
|
|
421
|
+
publishDiagnostics(textDocument, workspace) {
|
|
422
|
+
const diagnostics = [];
|
|
423
|
+
diagnostics.push(...this.createManifestLoadingDiagnostics(textDocument, workspace));
|
|
424
|
+
diagnostics.push(...this.createCSSDirectiveDiagnostics(textDocument, workspace));
|
|
425
|
+
this.connection.sendDiagnostics({
|
|
426
|
+
uri: textDocument.uri,
|
|
427
|
+
diagnostics
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
createCSSDirectiveDiagnostics(textDocument, workspace) {
|
|
431
|
+
if (!isCSSDiagnosticDocument(textDocument)) return [];
|
|
401
432
|
const diagnostics = [];
|
|
402
433
|
const documentFile = path.resolve(URI.parse(textDocument.uri).fsPath);
|
|
403
434
|
for (const { source, offset } of getCSSDiagnosticSources(textDocument)) try {
|
|
@@ -410,9 +441,31 @@ var CSSLanguageServer = class {
|
|
|
410
441
|
const diagnostic = this.createCSSDirectiveDiagnostic(error, textDocument, documentFile, offset);
|
|
411
442
|
if (diagnostic) diagnostics.push(diagnostic);
|
|
412
443
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
444
|
+
return diagnostics;
|
|
445
|
+
}
|
|
446
|
+
createManifestLoadingDiagnostics(textDocument, workspace) {
|
|
447
|
+
if (!workspace.manifestErrors?.length) return [];
|
|
448
|
+
const documentFile = path.resolve(URI.parse(textDocument.uri).fsPath);
|
|
449
|
+
return workspace.manifestErrors.map((error) => {
|
|
450
|
+
const directiveError = isCSSDirectiveError(error) ? error : void 0;
|
|
451
|
+
const source = directiveError?.source;
|
|
452
|
+
return {
|
|
453
|
+
range: source && (!source.file || path.resolve(source.file) === documentFile) ? this.createCSSDirectiveRange(source, textDocument, documentFile, 0) : {
|
|
454
|
+
start: {
|
|
455
|
+
line: 0,
|
|
456
|
+
character: 0
|
|
457
|
+
},
|
|
458
|
+
end: {
|
|
459
|
+
line: 0,
|
|
460
|
+
character: 0
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
severity: DiagnosticSeverity.Error,
|
|
464
|
+
code: "manifest-loading-error",
|
|
465
|
+
source: "Master CSS",
|
|
466
|
+
message: `Failed to load Master CSS manifest: ${error instanceof Error ? error.message : String(error)}`,
|
|
467
|
+
relatedInformation: directiveError ? this.createCSSDirectiveRelatedInformation(directiveError.related, textDocument, documentFile, 0) : void 0
|
|
468
|
+
};
|
|
416
469
|
});
|
|
417
470
|
}
|
|
418
471
|
createCSSDirectiveDiagnostic(error, textDocument, documentFile, sourceOffset) {
|
package/package.json
CHANGED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"vscode-languageserver": "^10.0.0",
|
|
18
18
|
"vscode-languageserver-textdocument": "^1.0.12",
|
|
19
19
|
"vscode-uri": "^3.1.0",
|
|
20
|
-
"@master/css": "^2.0.0-rc.
|
|
21
|
-
"@master/css
|
|
22
|
-
"@master/css-
|
|
23
|
-
"@master/css-project": "^2.0.0-rc.
|
|
24
|
-
"@master/css-language-service": "^2.0.0-rc.
|
|
25
|
-
"@master/css-schema": "^2.0.0-rc.
|
|
20
|
+
"@master/css-language": "^2.0.0-rc.76",
|
|
21
|
+
"@master/css": "^2.0.0-rc.76",
|
|
22
|
+
"@master/css-compiler": "^2.0.0-rc.76",
|
|
23
|
+
"@master/css-project": "^2.0.0-rc.76",
|
|
24
|
+
"@master/css-language-service": "^2.0.0-rc.76",
|
|
25
|
+
"@master/css-schema": "^2.0.0-rc.76"
|
|
26
26
|
},
|
|
27
27
|
"sideEffects": false,
|
|
28
28
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"access": "public",
|
|
50
50
|
"provenance": true
|
|
51
51
|
},
|
|
52
|
-
"version": "2.0.0-rc.
|
|
52
|
+
"version": "2.0.0-rc.76",
|
|
53
53
|
"scripts": {
|
|
54
54
|
"build": "tsdown --config ../../shared/tsdown-package.config.ts",
|
|
55
55
|
"dev": "tsdown --config ../../shared/tsdown-package.config.ts --watch",
|