@master/css-language-server 2.0.0-rc.72 → 2.0.0-rc.74

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Aoyue Design LLC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/dist/core.d.ts CHANGED
@@ -1,60 +1,66 @@
1
- import { TextDocuments, InitializeParams, InitializeResult, WorkspaceFolder, Connection, ClientCapabilities, TextDocumentChangeEvent, DidChangeConfigurationParams, HoverParams, CompletionParams, DocumentColorParams, ColorPresentationParams, RemoteConsole, SemanticTokensParams, TextDocumentPositionParams } from 'vscode-languageserver/node';
2
- import { TextDocument } from 'vscode-languageserver-textdocument';
3
- import CSSLanguageService, { Settings as CSSLanguageServiceSettings } from '@master/css-language-service';
4
- import { Settings } from './settings';
5
- import { type MasterCSSWorkspacePackageResolution } from '@master/css-project/workspace';
6
- import { type CSSLanguageRuntime } from '@master/css-language';
7
- export declare interface Workspace {
8
- uri: string;
9
- openedTextDocuments: TextDocument[];
10
- languageService?: CSSLanguageService;
11
- languageServiceSettings: CSSLanguageServiceSettings;
12
- languageRuntime?: CSSLanguageRuntime;
13
- languageRuntimeResolution?: MasterCSSWorkspacePackageResolution;
14
- languageRuntimeSource?: 'workspace' | 'bundled';
15
- planEntries?: string[];
1
+ import { ClientCapabilities, ColorPresentationParams, CompletionParams, Connection, DidChangeConfigurationParams, DocumentColorParams, HoverParams, InitializeParams, InitializeResult, RemoteConsole, SemanticTokensParams, TextDocumentChangeEvent, TextDocumentPositionParams, TextDocuments, WorkspaceFolder } from "vscode-languageserver/node";
2
+ import { TextDocument } from "vscode-languageserver-textdocument";
3
+ import CSSLanguageService, { Settings } from "@master/css-language-service";
4
+ import { MasterCSSWorkspacePackageResolution } from "@master/css-project/workspace";
5
+ import { CSSLanguageRuntime } from "@master/css-language";
6
+ import { Settings as Settings$1 } from "./settings.js";
7
+
8
+ //#region src/core.d.ts
9
+ declare interface Workspace {
10
+ uri: string;
11
+ openedTextDocuments: TextDocument[];
12
+ languageService?: CSSLanguageService;
13
+ languageServiceSettings: Settings;
14
+ languageRuntime?: CSSLanguageRuntime;
15
+ languageRuntimeResolution?: MasterCSSWorkspacePackageResolution;
16
+ languageRuntimeSource?: 'workspace' | 'bundled';
17
+ planEntries?: string[];
16
18
  }
17
- export declare const ACTIVE_SEMANTIC_TOKENS_REQUEST = "masterCSS/renderActiveSemanticTokens";
18
- export declare const DOCUMENT_SEMANTIC_TOKENS_REQUEST = "masterCSS/renderDocumentSemanticTokens";
19
- export default class CSSLanguageServer {
20
- connection: Connection;
21
- customSettings?: Settings | undefined;
22
- workspaceFolders: WorkspaceFolder[];
23
- workspaces: Map<string, Workspace>;
24
- globalWorkspace: Workspace;
25
- documents: TextDocuments<TextDocument>;
26
- initializing?: Promise<void>;
27
- clientCapabilities: ClientCapabilities;
28
- settings?: Settings;
29
- console: RemoteConsole;
30
- private disposables;
31
- constructor(connection?: Connection, customSettings?: Settings | undefined);
32
- start(): void;
33
- init(): Promise<void>;
34
- onInitialize(params: InitializeParams): InitializeResult;
35
- onHover(params: HoverParams): Promise<import("vscode-languageserver-protocol").Hover | undefined>;
36
- onCompletion(params: CompletionParams): Promise<import("vscode-languageserver-protocol").CompletionItem[] | undefined>;
37
- onDocumentColor(params: DocumentColorParams): Promise<import("vscode-languageserver-protocol").ColorInformation[]>;
38
- onColorPresentation(params: ColorPresentationParams): Promise<import("vscode-languageserver-protocol").ColorPresentation[]>;
39
- onSemanticTokens(params: SemanticTokensParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
40
- onDocumentSemanticTokens(params: SemanticTokensParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
41
- onActiveSemanticTokens(params: TextDocumentPositionParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
42
- onDidOpen(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
43
- onDidChangeContent(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
44
- onDidClose(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
45
- onDidSave(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
46
- onDidChangeConfiguration({ settings: changedSettings }: DidChangeConfigurationParams): Promise<void>;
47
- private initWorkspaceFolder;
48
- initWorkspaceLanguageService(workspace: Workspace): Promise<void>;
49
- private loadWorkspacePlan;
50
- private loadWorkspaceLanguageRuntime;
51
- private importWorkspaceModule;
52
- destroyLanguageService(workspace: Workspace): void;
53
- findClosestWorkspace(textDocumentURI: string): Workspace;
54
- private publishCSSDirectiveDiagnostics;
55
- private createCSSDirectiveDiagnostic;
56
- private createCSSDirectiveRelatedInformation;
57
- private createCSSDirectiveRange;
58
- private refreshSemanticTokens;
59
- stop(): void;
19
+ declare const ACTIVE_SEMANTIC_TOKENS_REQUEST = "masterCSS/renderActiveSemanticTokens";
20
+ declare const DOCUMENT_SEMANTIC_TOKENS_REQUEST = "masterCSS/renderDocumentSemanticTokens";
21
+ declare class CSSLanguageServer {
22
+ connection: Connection;
23
+ customSettings?: Settings$1 | undefined;
24
+ workspaceFolders: WorkspaceFolder[];
25
+ workspaces: Map<string, Workspace>;
26
+ globalWorkspace: Workspace;
27
+ documents: TextDocuments<TextDocument>;
28
+ initializing?: Promise<void>;
29
+ clientCapabilities: ClientCapabilities;
30
+ settings?: Settings$1;
31
+ console: RemoteConsole;
32
+ private disposables;
33
+ constructor(connection?: Connection, customSettings?: Settings$1 | undefined);
34
+ start(): void;
35
+ init(): Promise<void>;
36
+ onInitialize(params: InitializeParams): InitializeResult;
37
+ onHover(params: HoverParams): Promise<import("vscode-languageserver-protocol").Hover | undefined>;
38
+ onCompletion(params: CompletionParams): Promise<import("vscode-languageserver-protocol").CompletionItem[] | undefined>;
39
+ onDocumentColor(params: DocumentColorParams): Promise<import("vscode-languageserver-protocol").ColorInformation[]>;
40
+ onColorPresentation(params: ColorPresentationParams): Promise<import("vscode-languageserver-protocol").ColorPresentation[]>;
41
+ onSemanticTokens(params: SemanticTokensParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
42
+ onDocumentSemanticTokens(params: SemanticTokensParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
43
+ onActiveSemanticTokens(params: TextDocumentPositionParams): Promise<import("vscode-languageserver-protocol").SemanticTokens>;
44
+ onDidOpen(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
45
+ onDidChangeContent(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
46
+ onDidClose(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
47
+ onDidSave(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
48
+ onDidChangeConfiguration({
49
+ settings: changedSettings
50
+ }: DidChangeConfigurationParams): Promise<void>;
51
+ private initWorkspaceFolder;
52
+ initWorkspaceLanguageService(workspace: Workspace): Promise<void>;
53
+ private loadWorkspacePlan;
54
+ private loadWorkspaceLanguageRuntime;
55
+ private importWorkspaceModule;
56
+ destroyLanguageService(workspace: Workspace): void;
57
+ findClosestWorkspace(textDocumentURI: string): Workspace;
58
+ private publishCSSDirectiveDiagnostics;
59
+ private createCSSDirectiveDiagnostic;
60
+ private createCSSDirectiveRelatedInformation;
61
+ private createCSSDirectiveRange;
62
+ private refreshSemanticTokens;
63
+ stop(): void;
60
64
  }
65
+ //#endregion
66
+ export { ACTIVE_SEMANTIC_TOKENS_REQUEST, DOCUMENT_SEMANTIC_TOKENS_REQUEST, Workspace, CSSLanguageServer as default };
package/dist/core.js ADDED
@@ -0,0 +1,480 @@
1
+ import settings$1 from "./settings.js";
2
+ import { DiagnosticSeverity, TextDocumentSyncKind, TextDocuments, createConnection } from "vscode-languageserver/node";
3
+ import { TextDocument } from "vscode-languageserver-textdocument";
4
+ import path from "node:path";
5
+ import { readFile } from "node:fs/promises";
6
+ import { pathToFileURL } from "node:url";
7
+ import CSSLanguageService from "@master/css-language-service";
8
+ import { compileCSSManifest } from "@master/css-compiler";
9
+ import { findCSSManifestEntryFiles, findMasterCSSWorkspaceDirectories } from "@master/css-project/entries";
10
+ import { loadProjectManifest } from "@master/css-project/manifest";
11
+ import { resolveMasterCSSWorkspacePackages } from "@master/css-project/workspace";
12
+ import { defu } from "defu";
13
+ import { 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-service/common";
14
+ import { SEMANTIC_TOKENS_LEGEND, defaultCSSLanguageRuntime, matchesLanguageServiceNativeDeclaration } from "@master/css-language";
15
+ import glob from "fast-glob";
16
+ import { URI } from "vscode-uri";
17
+ import { CSSDirectiveError } from "@master/css-schema/css-directives";
18
+ //#region src/core.ts
19
+ const ACTIVE_SEMANTIC_TOKENS_REQUEST = "masterCSS/renderActiveSemanticTokens";
20
+ const DOCUMENT_SEMANTIC_TOKENS_REQUEST = "masterCSS/renderDocumentSemanticTokens";
21
+ const SERVER_CAPABILITIES = {
22
+ textDocumentSync: TextDocumentSyncKind.Incremental,
23
+ completionProvider: {
24
+ resolveProvider: false,
25
+ workDoneProgress: false,
26
+ triggerCharacters: [.../* @__PURE__ */ new Set([
27
+ ...INVOKED_TRIGGER_CHARACTERS,
28
+ ...VALUE_TRIGGER_CHARACTERS,
29
+ ...SELECTOR_TRIGGER_CHARACTERS,
30
+ ...QUERY_TRIGGER_CHARACTERS,
31
+ DECLARATION_SEPARATOR_TRIGGER_CHARACTER,
32
+ AT_TRIGGER_CHARACTER,
33
+ GROUP_TRIGGER_CHARACTER
34
+ ])]
35
+ },
36
+ colorProvider: true,
37
+ hoverProvider: true,
38
+ semanticTokensProvider: {
39
+ legend: SEMANTIC_TOKENS_LEGEND,
40
+ full: true
41
+ },
42
+ workspace: { workspaceFolders: { supported: true } }
43
+ };
44
+ const CSS_DIAGNOSTIC_LANGUAGE_IDS = /* @__PURE__ */ new Set([
45
+ "css",
46
+ "scss",
47
+ "less"
48
+ ]);
49
+ const SFC_DIAGNOSTIC_LANGUAGE_IDS = /* @__PURE__ */ new Set([
50
+ "vue",
51
+ "svelte",
52
+ "astro"
53
+ ]);
54
+ const STYLE_BLOCK_RE = /<style\b([^>]*)>([\s\S]*?)<\/style>/gi;
55
+ function isCSSDiagnosticDocument(textDocument) {
56
+ return CSS_DIAGNOSTIC_LANGUAGE_IDS.has(textDocument.languageId) || SFC_DIAGNOSTIC_LANGUAGE_IDS.has(textDocument.languageId);
57
+ }
58
+ function getSFCStyleLanguage(attributes) {
59
+ const match = /\blang\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+))/i.exec(attributes);
60
+ return (match?.[1] || match?.[2] || match?.[3] || "css").toLowerCase();
61
+ }
62
+ function getCSSDiagnosticSources(textDocument) {
63
+ const text = textDocument.getText();
64
+ if (CSS_DIAGNOSTIC_LANGUAGE_IDS.has(textDocument.languageId)) return [{
65
+ source: text,
66
+ offset: 0
67
+ }];
68
+ if (!SFC_DIAGNOSTIC_LANGUAGE_IDS.has(textDocument.languageId)) return [];
69
+ const sources = [];
70
+ STYLE_BLOCK_RE.lastIndex = 0;
71
+ for (const match of text.matchAll(STYLE_BLOCK_RE)) {
72
+ const styleLanguage = getSFCStyleLanguage(match[1]);
73
+ if (!CSS_DIAGNOSTIC_LANGUAGE_IDS.has(styleLanguage)) continue;
74
+ const source = match[2];
75
+ const offset = (match.index || 0) + match[0].indexOf(source);
76
+ sources.push({
77
+ source,
78
+ offset
79
+ });
80
+ }
81
+ return sources;
82
+ }
83
+ function isCSSDirectiveError(error) {
84
+ return error instanceof CSSDirectiveError || !!error && typeof error === "object" && error.name === "CSSDirectiveError" && typeof error.code === "string";
85
+ }
86
+ function getInitializationSettings(initializationOptions) {
87
+ if (!initializationOptions || typeof initializationOptions !== "object") return;
88
+ const options = initializationOptions;
89
+ return options.masterCSS ?? options;
90
+ }
91
+ function isWindowsFilePath(fsPath) {
92
+ return /^[a-z]:[\\/]/i.test(fsPath) || fsPath.startsWith("\\\\") || fsPath.startsWith("//");
93
+ }
94
+ function getFilePathTools(...fsPaths) {
95
+ return fsPaths.some(isWindowsFilePath) ? path.win32 : path;
96
+ }
97
+ function toComparableFilePath(uri) {
98
+ const parsedURI = URI.parse(uri);
99
+ if (parsedURI.scheme !== "file") return;
100
+ const fsPath = parsedURI.fsPath;
101
+ if (!fsPath) return;
102
+ const resolvedPath = getFilePathTools(fsPath).resolve(fsPath);
103
+ return isWindowsFilePath(resolvedPath) ? resolvedPath.toLowerCase() : resolvedPath;
104
+ }
105
+ function containsFilePath(parentPath, childPath) {
106
+ const filePathTools = getFilePathTools(parentPath, childPath);
107
+ const relativePath = filePathTools.relative(parentPath, childPath);
108
+ return relativePath === "" || !!relativePath && relativePath !== ".." && !relativePath.startsWith(`..${filePathTools.sep}`) && !filePathTools.isAbsolute(relativePath);
109
+ }
110
+ var CSSLanguageServer = class {
111
+ connection;
112
+ customSettings;
113
+ workspaceFolders = [];
114
+ workspaces = /* @__PURE__ */ new Map();
115
+ globalWorkspace = {
116
+ uri: "",
117
+ openedTextDocuments: [],
118
+ languageServiceSettings: this.settings,
119
+ languageRuntime: defaultCSSLanguageRuntime,
120
+ languageRuntimeSource: "bundled"
121
+ };
122
+ documents;
123
+ initializing;
124
+ clientCapabilities = {};
125
+ settings;
126
+ console;
127
+ disposables = [];
128
+ constructor(connection = process.argv.includes("--stdio") ? createConnection(process.stdin, process.stdout) : createConnection(), customSettings) {
129
+ this.connection = connection;
130
+ this.customSettings = customSettings;
131
+ this.documents = new TextDocuments(TextDocument);
132
+ this.settings = defu(this.customSettings, settings$1);
133
+ this.globalWorkspace.languageServiceSettings = this.settings;
134
+ this.console = new Proxy(this.connection.console, { get: (target, prop) => {
135
+ if (!this.settings?.verbose) return () => {};
136
+ return this.connection.console[prop];
137
+ } });
138
+ }
139
+ 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()));
141
+ this.connection.listen();
142
+ }
143
+ init() {
144
+ if (this.initializing) return this.initializing;
145
+ return this.initializing = new Promise(async (resolve) => {
146
+ await Promise.all(this.workspaceFolders.map((folder) => this.initWorkspaceFolder(folder.uri)));
147
+ resolve();
148
+ });
149
+ }
150
+ onInitialize(params) {
151
+ this.clientCapabilities = params.capabilities;
152
+ const initializationSettings = getInitializationSettings(params.initializationOptions);
153
+ if (initializationSettings) {
154
+ this.customSettings = defu(initializationSettings, this.customSettings);
155
+ this.settings = defu(this.customSettings, settings$1);
156
+ this.globalWorkspace.languageServiceSettings = this.settings;
157
+ }
158
+ if (params.workspaceFolders?.length) this.workspaceFolders = params.workspaceFolders;
159
+ const capabilities = { ...SERVER_CAPABILITIES };
160
+ if (this.settings?.embeddedSyntaxHighlighting !== "always") delete capabilities.semanticTokensProvider;
161
+ return { capabilities };
162
+ }
163
+ async onHover(params) {
164
+ await this.init();
165
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
166
+ if (workspace?.languageService) {
167
+ const document = this.documents.get(params.textDocument.uri);
168
+ if (document) return workspace.languageService.inspectSyntax(document, params.position);
169
+ }
170
+ }
171
+ async onCompletion(params) {
172
+ await this.init();
173
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
174
+ if (workspace?.languageService) {
175
+ const document = this.documents.get(params.textDocument.uri);
176
+ if (document) return workspace.languageService.suggestSyntax(document, params.position, params.context);
177
+ }
178
+ }
179
+ async onDocumentColor(params) {
180
+ await this.init();
181
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
182
+ if (workspace?.languageService) {
183
+ const document = this.documents.get(params.textDocument.uri);
184
+ if (document) return await workspace.languageService.renderSyntaxColors(document) ?? [];
185
+ }
186
+ return [];
187
+ }
188
+ async onColorPresentation(params) {
189
+ await this.init();
190
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
191
+ if (workspace?.languageService) {
192
+ const document = this.documents.get(params.textDocument.uri);
193
+ if (document) return workspace.languageService.editSyntaxColors(document, params.color, params.range) ?? [];
194
+ }
195
+ return [];
196
+ }
197
+ async onSemanticTokens(params) {
198
+ await this.init();
199
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
200
+ if (workspace?.languageService) {
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
+ }
204
+ return { data: [] };
205
+ }
206
+ async onDocumentSemanticTokens(params) {
207
+ return this.onSemanticTokens(params);
208
+ }
209
+ async onActiveSemanticTokens(params) {
210
+ await this.init();
211
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
212
+ if (workspace?.languageService) {
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
+ }
216
+ return { data: [] };
217
+ }
218
+ async onDidOpen(params) {
219
+ await this.init();
220
+ const workspace = this.findClosestWorkspace(params.document.uri);
221
+ if (!workspace) return;
222
+ if (workspace.openedTextDocuments.includes(params.document)) {
223
+ this.publishCSSDirectiveDiagnostics(params.document, workspace);
224
+ return;
225
+ }
226
+ if (!workspace.openedTextDocuments.length) await this.initWorkspaceLanguageService(workspace);
227
+ workspace.openedTextDocuments.push(params.document);
228
+ this.publishCSSDirectiveDiagnostics(params.document, workspace);
229
+ }
230
+ async onDidChangeContent(params) {
231
+ await this.init();
232
+ const workspace = this.findClosestWorkspace(params.document.uri);
233
+ if (!workspace) return;
234
+ this.publishCSSDirectiveDiagnostics(params.document, workspace);
235
+ }
236
+ async onDidClose(params) {
237
+ await this.init();
238
+ const workspace = this.findClosestWorkspace(params.document.uri);
239
+ if (!workspace) return;
240
+ workspace.openedTextDocuments.splice(workspace.openedTextDocuments.indexOf(params.document), 1);
241
+ this.connection.sendDiagnostics({
242
+ uri: params.document.uri,
243
+ diagnostics: []
244
+ });
245
+ if (!workspace.openedTextDocuments.length) this.destroyLanguageService(workspace);
246
+ }
247
+ async onDidSave(params) {
248
+ await this.init();
249
+ const workspace = this.findClosestWorkspace(params.document.uri);
250
+ if (!workspace) return;
251
+ this.publishCSSDirectiveDiagnostics(params.document, workspace);
252
+ if (path.basename(URI.parse(params.document.uri).fsPath).endsWith(".css")) {
253
+ this.refreshSemanticTokens();
254
+ this.connection.sendRequest("masterCSS/restart", { title: "Updating Master CSS configuration" });
255
+ }
256
+ }
257
+ async onDidChangeConfiguration({ settings: changedSettings }) {
258
+ await this.init();
259
+ if (changedSettings?.masterCSS) {
260
+ this.connection.sendNotification("masterCSS/globalSettingsChanged", changedSettings.masterCSS);
261
+ this.customSettings = changedSettings.masterCSS;
262
+ this.settings = defu(this.customSettings, settings$1);
263
+ this.globalWorkspace.languageServiceSettings = this.settings;
264
+ this.refreshSemanticTokens();
265
+ 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.publishCSSDirectiveDiagnostics(document, workspace);
267
+ }
268
+ }
269
+ async initWorkspaceFolder(workspaceFolderURI) {
270
+ const workspaceFolderCWD = URI.parse(workspaceFolderURI).fsPath;
271
+ let customWorkspaceFolderSettings;
272
+ if (this.clientCapabilities.workspace?.configuration) customWorkspaceFolderSettings = await this.connection.workspace.getConfiguration({
273
+ scopeUri: workspaceFolderURI,
274
+ section: "masterCSS"
275
+ });
276
+ const { workspaces, ...languageServiceSettings } = defu(customWorkspaceFolderSettings, this.customSettings, settings$1);
277
+ const resolvedWorkspaceDirectories = /* @__PURE__ */ new Set([workspaceFolderCWD]);
278
+ if (workspaceFolderCWD) this.console.info(`Registered workspace folder ${workspaceFolderURI}`);
279
+ else this.console.info(`Registered global workspace folder`);
280
+ if (workspaces === "auto") for (const workspaceDir of await findMasterCSSWorkspaceDirectories(workspaceFolderCWD)) resolvedWorkspaceDirectories.add(workspaceDir);
281
+ else if (workspaces?.length) (await glob(workspaces, {
282
+ cwd: workspaceFolderCWD,
283
+ absolute: true,
284
+ onlyDirectories: true,
285
+ ignore: ["**/node_modules/**"]
286
+ })).forEach((workspaceDir) => resolvedWorkspaceDirectories.add(path.resolve(workspaceDir)));
287
+ for (const workspaceDir of resolvedWorkspaceDirectories) {
288
+ const workspaceURI = URI.file(workspaceDir).toString();
289
+ this.console.info(`Added workspace ${workspaceURI}`);
290
+ this.workspaces.set(workspaceURI, {
291
+ uri: workspaceURI,
292
+ openedTextDocuments: [],
293
+ languageServiceSettings,
294
+ planEntries: await findCSSManifestEntryFiles(workspaceDir)
295
+ });
296
+ }
297
+ }
298
+ async initWorkspaceLanguageService(workspace) {
299
+ workspace.languageRuntime = await this.loadWorkspaceLanguageRuntime(workspace);
300
+ let workspacePlan;
301
+ if (workspace !== this.globalWorkspace) {
302
+ try {
303
+ workspacePlan = await this.loadWorkspacePlan(workspace);
304
+ } catch (e) {
305
+ this.console.info(`Failed to load manifest from ${workspace.uri}`);
306
+ this.console.error(e instanceof Error ? e.stack : e.toString());
307
+ }
308
+ if (workspacePlan) this.console.info(`Initialized workspace ${workspace.planEntries?.length ? "(with manifest entry)" : "(with manifest)"} ${workspace.uri}`);
309
+ else this.console.info(`Initialized workspace ${workspace.uri}`);
310
+ }
311
+ workspace.languageService = new CSSLanguageService({
312
+ ...workspace.languageServiceSettings,
313
+ manifest: workspacePlan
314
+ }, { runtime: workspace.languageRuntime });
315
+ }
316
+ async loadWorkspacePlan(workspace) {
317
+ const result = await loadProjectManifest(workspace.uri ? URI.parse(workspace.uri).fsPath : process.cwd(), { baseManifest: (workspace.languageRuntime ?? defaultCSSLanguageRuntime).defaultManifest });
318
+ return result.entries.length ? result.manifest : workspace.languageServiceSettings.manifest;
319
+ }
320
+ async loadWorkspaceLanguageRuntime(workspace) {
321
+ if (workspace === this.globalWorkspace || !workspace.uri) {
322
+ workspace.languageRuntimeSource = "bundled";
323
+ return defaultCSSLanguageRuntime;
324
+ }
325
+ const cwd = URI.parse(workspace.uri).fsPath;
326
+ let resolution;
327
+ try {
328
+ resolution = resolveMasterCSSWorkspacePackages(cwd);
329
+ workspace.languageRuntimeResolution = resolution;
330
+ const missingPackages = [
331
+ !resolution.css && "@master/css",
332
+ !resolution.engine && "@master/css-engine",
333
+ !resolution.presetManifest && "@master/css-preset/default-manifest.json"
334
+ ].filter(Boolean);
335
+ if (missingPackages.length) throw new Error(`Missing workspace package(s): ${missingPackages.join(", ")}`);
336
+ const cssPackage = resolution.css;
337
+ const enginePackage = resolution.engine;
338
+ const presetManifestPackage = resolution.presetManifest;
339
+ if (!cssPackage || !enginePackage || !presetManifestPackage) throw new Error("Missing required workspace Master CSS runtime packages.");
340
+ const [cssModule, engineModule, utilityTypeModule] = await Promise.all([
341
+ this.importWorkspaceModule(cssPackage.entry),
342
+ this.importWorkspaceModule(enginePackage.entry),
343
+ resolution.utilityType ? this.importWorkspaceModule(resolution.utilityType.entry) : void 0
344
+ ]);
345
+ const MasterCSS = cssModule.MasterCSS || cssModule.default;
346
+ const builtinKeyAliases = engineModule.builtinKeyAliases;
347
+ const builtinNativeValueNamespaces = engineModule.builtinNativeValueNamespaces;
348
+ if (!MasterCSS) throw new Error(`Missing MasterCSS export from ${cssPackage.entry}`);
349
+ if (!builtinKeyAliases) throw new Error(`Missing builtinKeyAliases export from ${enginePackage.entry}`);
350
+ if (!builtinNativeValueNamespaces) throw new Error(`Missing builtinNativeValueNamespaces export from ${enginePackage.entry}`);
351
+ const manifest = JSON.parse(await readFile(presetManifestPackage.entry, "utf8"));
352
+ workspace.languageRuntimeSource = "workspace";
353
+ this.console.info(`Using workspace Master CSS runtime ${cssPackage.version ?? "(unknown version)"} from ${cssPackage.directory}`);
354
+ if (resolution.errors.length) this.console.info(`Workspace Master CSS runtime optional resolution warnings: ${resolution.errors.map(({ name, message }) => `${name}: ${message}`).join("; ")}`);
355
+ return {
356
+ MasterCSS,
357
+ UtilityType: utilityTypeModule?.UtilityType || utilityTypeModule?.default || defaultCSSLanguageRuntime.UtilityType,
358
+ defaultManifest: manifest,
359
+ builtinKeyAliases,
360
+ builtinNativeValueNamespaces,
361
+ nativeDeclarationMatcher: matchesLanguageServiceNativeDeclaration
362
+ };
363
+ } catch (error) {
364
+ workspace.languageRuntimeSource = "bundled";
365
+ this.console.info(`Using bundled Master CSS runtime for ${workspace.uri}`);
366
+ if (resolution?.errors.length) this.console.info(`Workspace Master CSS package resolution errors: ${resolution.errors.map(({ name, message }) => `${name}: ${message}`).join("; ")}`);
367
+ this.console.error(error instanceof Error ? error.stack || error.message : String(error));
368
+ return defaultCSSLanguageRuntime;
369
+ }
370
+ }
371
+ async importWorkspaceModule(path) {
372
+ return await import(pathToFileURL(path).href);
373
+ }
374
+ destroyLanguageService(workspace) {
375
+ this.console.info(`Destroyed workspace ${workspace.uri}`);
376
+ delete workspace.languageService;
377
+ }
378
+ findClosestWorkspace(textDocumentURI) {
379
+ const documentPath = toComparableFilePath(textDocumentURI);
380
+ if (!documentPath) {
381
+ this.console.info(`This is an external document ${textDocumentURI} with the global workspace`);
382
+ return this.globalWorkspace;
383
+ }
384
+ let foundWorkspace;
385
+ let foundWorkspacePath = "";
386
+ for (const [uri, workspace] of this.workspaces) {
387
+ if (!uri) continue;
388
+ const workspacePath = toComparableFilePath(uri);
389
+ if (!workspacePath) continue;
390
+ if (containsFilePath(workspacePath, documentPath) && workspacePath.length > foundWorkspacePath.length) {
391
+ foundWorkspace = workspace;
392
+ foundWorkspacePath = workspacePath;
393
+ }
394
+ }
395
+ if (foundWorkspace) return foundWorkspace;
396
+ this.console.info(`This is an external document ${textDocumentURI} with the global workspace`);
397
+ return this.globalWorkspace;
398
+ }
399
+ publishCSSDirectiveDiagnostics(textDocument, workspace) {
400
+ if (!isCSSDiagnosticDocument(textDocument)) return;
401
+ const diagnostics = [];
402
+ const documentFile = path.resolve(URI.parse(textDocument.uri).fsPath);
403
+ for (const { source, offset } of getCSSDiagnosticSources(textDocument)) try {
404
+ compileCSSManifest(source, {
405
+ from: documentFile,
406
+ baseManifest: (workspace.languageRuntime ?? defaultCSSLanguageRuntime).defaultManifest
407
+ });
408
+ } catch (error) {
409
+ if (!isCSSDirectiveError(error)) continue;
410
+ const diagnostic = this.createCSSDirectiveDiagnostic(error, textDocument, documentFile, offset);
411
+ if (diagnostic) diagnostics.push(diagnostic);
412
+ }
413
+ this.connection.sendDiagnostics({
414
+ uri: textDocument.uri,
415
+ diagnostics
416
+ });
417
+ }
418
+ createCSSDirectiveDiagnostic(error, textDocument, documentFile, sourceOffset) {
419
+ if (error.source?.file && path.resolve(error.source.file) !== documentFile) return;
420
+ return {
421
+ range: this.createCSSDirectiveRange(error.source, textDocument, documentFile, sourceOffset),
422
+ severity: DiagnosticSeverity.Error,
423
+ code: error.code,
424
+ source: "Master CSS",
425
+ message: error.message,
426
+ relatedInformation: this.createCSSDirectiveRelatedInformation(error.related, textDocument, documentFile, sourceOffset)
427
+ };
428
+ }
429
+ createCSSDirectiveRelatedInformation(related, textDocument, documentFile, sourceOffset) {
430
+ if (!related?.length) return;
431
+ return related.map(({ message, source }) => ({
432
+ message,
433
+ location: {
434
+ uri: source?.file ? URI.file(source.file).toString() : textDocument.uri,
435
+ range: this.createCSSDirectiveRange(source, textDocument, documentFile, sourceOffset)
436
+ }
437
+ }));
438
+ }
439
+ createCSSDirectiveRange(source, textDocument, documentFile, sourceOffset) {
440
+ if (source?.file && path.resolve(source.file) !== documentFile) return source.loc ? {
441
+ start: {
442
+ line: Math.max(0, source.loc.start.line - 1),
443
+ character: Math.max(0, source.loc.start.column - 1)
444
+ },
445
+ end: {
446
+ line: Math.max(0, source.loc.end.line - 1),
447
+ character: Math.max(0, source.loc.end.column - 1)
448
+ }
449
+ } : {
450
+ start: {
451
+ line: 0,
452
+ character: 0
453
+ },
454
+ end: {
455
+ line: 0,
456
+ character: 0
457
+ }
458
+ };
459
+ const start = Math.max(0, (source?.range.start || 0) + sourceOffset);
460
+ const end = Math.max(start, (source?.range.end || 0) + sourceOffset);
461
+ return {
462
+ start: textDocument.positionAt(start),
463
+ end: textDocument.positionAt(end)
464
+ };
465
+ }
466
+ refreshSemanticTokens() {
467
+ if (this.settings?.embeddedSyntaxHighlighting !== "always") return;
468
+ if (!this.clientCapabilities.workspace?.semanticTokens?.refreshSupport) return;
469
+ this.connection.languages.semanticTokens.refresh();
470
+ }
471
+ stop() {
472
+ this.connection.sendNotification("masterCSS/dispose");
473
+ this.disposables.forEach((disposable) => disposable.dispose());
474
+ this.disposables.length = 0;
475
+ this.connection.dispose();
476
+ this.initializing = void 0;
477
+ }
478
+ };
479
+ //#endregion
480
+ export { ACTIVE_SEMANTIC_TOKENS_REQUEST, DOCUMENT_SEMANTIC_TOKENS_REQUEST, CSSLanguageServer as default };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { default, default as CSSLanguageServer } from './core';
2
- export { ACTIVE_SEMANTIC_TOKENS_REQUEST, DOCUMENT_SEMANTIC_TOKENS_REQUEST } from './core';
3
- export { default as settings, type Settings } from './settings';
4
- export type { Workspace } from './core';
1
+ import settings, { Settings } from "./settings.js";
2
+ import CSSLanguageServer, { ACTIVE_SEMANTIC_TOKENS_REQUEST, DOCUMENT_SEMANTIC_TOKENS_REQUEST, Workspace, default as core_default } from "./core.js";
3
+ export { ACTIVE_SEMANTIC_TOKENS_REQUEST, CSSLanguageServer, DOCUMENT_SEMANTIC_TOKENS_REQUEST, type Settings, type Workspace, core_default as default, settings };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import settings from "./settings.js";
2
+ import CSSLanguageServer, { ACTIVE_SEMANTIC_TOKENS_REQUEST, DOCUMENT_SEMANTIC_TOKENS_REQUEST } from "./core.js";
3
+ export { ACTIVE_SEMANTIC_TOKENS_REQUEST, CSSLanguageServer, DOCUMENT_SEMANTIC_TOKENS_REQUEST, CSSLanguageServer as default, settings };
package/dist/server.d.ts CHANGED
@@ -1 +1 @@
1
- export {};
1
+ export { };
package/dist/server.js ADDED
@@ -0,0 +1,8 @@
1
+ import CSSLanguageServer from "./core.js";
2
+ //#region src/server.ts
3
+ new CSSLanguageServer(void 0, { verbose: true }).start();
4
+ process.on("unhandledRejection", (error) => {
5
+ console.error("Unhandled rejection", error);
6
+ });
7
+ //#endregion
8
+ export {};