@master/css-language-server 2.0.0-rc.38 → 2.0.0-rc.39

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/core.cjs CHANGED
@@ -2,132 +2,157 @@
2
2
 
3
3
  var node = require('vscode-languageserver/node');
4
4
  var vscodeLanguageserverTextdocument = require('vscode-languageserver-textdocument');
5
- var path = require('path');
5
+ var path = require('node:path');
6
6
  var CSSLanguageService = require('@master/css-language-service');
7
7
  var exploreConfig = require('@master/css-explore-config');
8
8
  var extend = require('@techor/extend');
9
9
  var settings = require('./settings.cjs');
10
- var interceptLogs = require('./utils/intercept-logs.cjs');
11
10
  var glob = require('fast-glob');
12
11
  var vscodeUri = require('vscode-uri');
13
12
 
14
13
  class CSSLanguageServer {
14
+ connection;
15
15
  customSettings;
16
16
  workspaceFolders;
17
17
  workspaces;
18
- connection;
19
18
  documents;
20
19
  initializing;
20
+ clientCapabilities;
21
+ settings;
22
+ console;
21
23
  disposables;
22
- constructor(customSettings){
24
+ constructor(connection = process.argv.includes('--stdio') ? node.createConnection(process.stdin, process.stdout) : node.createConnection(), customSettings){
25
+ this.connection = connection;
23
26
  this.customSettings = customSettings;
24
27
  this.workspaceFolders = [];
25
- this.workspaces = new Set();
28
+ this.workspaces = [];
29
+ this.clientCapabilities = {};
26
30
  this.disposables = [];
27
- if (process.argv.includes('--stdio')) {
28
- this.connection = node.createConnection(process.stdin, process.stdout);
29
- } else {
30
- this.connection = node.createConnection();
31
- }
32
- interceptLogs(console, this.connection);
33
31
  this.documents = new node.TextDocuments(vscodeLanguageserverTextdocument.TextDocument);
32
+ this.settings = extend(settings, this.customSettings);
33
+ this.console = new Proxy(this.connection.console, {
34
+ get: (target, prop)=>{
35
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
36
+ if (!this.settings?.verbose) return ()=>{};
37
+ return this.connection.console[prop];
38
+ }
39
+ });
34
40
  }
35
41
  start() {
36
- this.disposables.push(this.documents.onDidSave(async (change)=>{
37
- // if the saved file is the master.css file, we need to refresh the css instance
38
- const name = path.parse(change.document.uri).name;
39
- if (name === 'master.css' || name.endsWith('.css')) {
40
- this.connection.sendRequest('masterCSS/restart', {
41
- title: 'Updating Master CSS configuration'
42
- });
43
- }
44
- }), this.documents.onDidOpen(async (params)=>{
45
- await this.initializing;
46
- const workspace = this.findClosestWorkspace(params.document.uri);
47
- if (workspace.openedTextDocuments.has(params.document)) return;
48
- if (!workspace.openedTextDocuments.size) {
49
- this.initCSSLanguageService(workspace);
50
- }
51
- workspace.openedTextDocuments.add(params.document);
52
- }), this.documents.onDidClose(async (params)=>{
53
- await this.initializing;
54
- const workspace = this.findClosestWorkspace(params.document.uri);
55
- workspace.openedTextDocuments.delete(params.document);
56
- if (!workspace.openedTextDocuments.size) {
57
- this.destroyCSSLanguageService(workspace);
58
- }
59
- }), this.documents.listen(this.connection), this.connection.onDidChangeConfiguration(async ({ settings })=>{
60
- await this.initializing;
61
- if (settings?.masterCSS) {
62
- this.connection.sendNotification('masterCSS/globalSettingsChanged', settings.masterCSS);
63
- this.customSettings = settings.masterCSS;
64
- this.connection.sendRequest('masterCSS/restart', {
65
- title: 'Updating Master CSS settings'
42
+ this.disposables.push(this.documents.onDidSave(this.onDidSave.bind(this)), this.documents.onDidOpen(this.onDidOpen.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.onInitialize(this.onInitialize.bind(this)), this.connection.onInitialized(()=>this.init()));
43
+ this.connection.listen();
44
+ }
45
+ init() {
46
+ if (this.initializing) return this.initializing;
47
+ // eslint-disable-next-line no-async-promise-executor
48
+ return this.initializing = new Promise(async (resolve)=>{
49
+ await Promise.all(this.workspaceFolders.map((folder)=>this.initWorkspaceFolder(folder.uri)));
50
+ resolve();
51
+ });
52
+ }
53
+ onInitialize(params) {
54
+ this.clientCapabilities = params.capabilities;
55
+ if (params.workspaceFolders?.length) {
56
+ this.workspaceFolders = params.workspaceFolders;
57
+ } else {
58
+ /**
59
+ * @deprecated — in favour of workspaceFolders
60
+ */ if (params.rootUri) {
61
+ this.workspaceFolders.push({
62
+ name: '',
63
+ uri: params.rootUri
66
64
  });
67
65
  }
68
- }), this.connection.onHover(async (params)=>{
69
- await this.initializing;
70
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
71
- if (workspace?.cssLanguageService) {
72
- const document = this.documents.get(params.textDocument.uri);
73
- if (document) return workspace.cssLanguageService.inspectSyntax(document, params.position);
74
- }
75
- }), this.connection.onCompletion(async (params)=>{
76
- await this.initializing;
77
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
78
- if (workspace?.cssLanguageService) {
79
- const document = this.documents.get(params.textDocument.uri);
80
- if (document) return workspace.cssLanguageService.suggestSyntax(document, params.position, params.context);
81
- }
82
- }), this.connection.onDocumentColor(async (params)=>{
83
- await this.initializing;
84
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
85
- if (workspace?.cssLanguageService) {
86
- const document = this.documents.get(params.textDocument.uri);
87
- if (document) return workspace.cssLanguageService.renderSyntaxColors(document);
88
- }
89
- }), this.connection.onColorPresentation(async (params)=>{
90
- await this.initializing;
91
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
92
- if (workspace?.cssLanguageService) {
93
- const document = this.documents.get(params.textDocument.uri);
94
- if (document) return workspace.cssLanguageService.editSyntaxColors(document, params.color, params.range);
95
- }
96
- }), // Make the text document manager listen on the connection
97
- // for open, change and close text document events
98
- this.connection.onInitialize((params)=>{
99
- if (params.workspaceFolders?.length) {
100
- this.workspaceFolders = params.workspaceFolders;
101
- } else {
102
- if (params.rootUri) {
103
- this.workspaceFolders.push({
104
- name: '',
105
- uri: params.rootUri
106
- });
107
- }
108
- }
109
- return {
110
- capabilities: CSSLanguageService.SERVER_CAPABILITIES
111
- };
112
- }), this.connection.onInitialized(async ()=>{
113
- this.initializing = Promise.all([
114
- ...this.workspaceFolders.map((folder)=>this.initWorkspaceFolder(folder.uri)),
115
- this.connection.client.register(node.DidChangeConfigurationNotification.type, undefined)
116
- ]);
117
- }));
118
- this.connection.listen();
66
+ }
67
+ return {
68
+ capabilities: CSSLanguageService.SERVER_CAPABILITIES
69
+ };
70
+ }
71
+ async onHover(params) {
72
+ await this.init();
73
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
74
+ if (workspace.languageService) {
75
+ const document = this.documents.get(params.textDocument.uri);
76
+ if (document) return workspace.languageService.inspectSyntax(document, params.position);
77
+ }
78
+ }
79
+ async onCompletion(params) {
80
+ await this.init();
81
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
82
+ if (workspace.languageService) {
83
+ const document = this.documents.get(params.textDocument.uri);
84
+ if (document) return workspace.languageService.suggestSyntax(document, params.position, params.context);
85
+ }
86
+ }
87
+ async onDocumentColor(params) {
88
+ await this.init();
89
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
90
+ if (workspace.languageService) {
91
+ const document = this.documents.get(params.textDocument.uri);
92
+ if (document) return workspace.languageService.renderSyntaxColors(document);
93
+ }
94
+ }
95
+ async onColorPresentation(params) {
96
+ await this.init();
97
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
98
+ if (workspace.languageService) {
99
+ const document = this.documents.get(params.textDocument.uri);
100
+ if (document) return workspace.languageService.editSyntaxColors(document, params.color, params.range);
101
+ }
102
+ }
103
+ async onDidOpen(params) {
104
+ await this.init();
105
+ const workspace = this.findClosestWorkspace(params.document.uri);
106
+ if (!workspace || workspace.openedTextDocuments.includes(params.document)) return;
107
+ if (!workspace.openedTextDocuments.length) {
108
+ this.initLanguageService(workspace);
109
+ }
110
+ workspace.openedTextDocuments.push(params.document);
111
+ }
112
+ async onDidClose(params) {
113
+ await this.init();
114
+ const workspace = this.findClosestWorkspace(params.document.uri);
115
+ if (!workspace) return;
116
+ workspace.openedTextDocuments.splice(workspace.openedTextDocuments.indexOf(params.document), 1);
117
+ if (!workspace.openedTextDocuments.length) {
118
+ this.destroyLanguageService(workspace);
119
+ }
120
+ }
121
+ async onDidSave(params) {
122
+ await this.init();
123
+ const workspace = this.findClosestWorkspace(params.document.uri);
124
+ if (!workspace) return;
125
+ const name = path.parse(params.document.uri).name;
126
+ if (name === 'master.css' || name.endsWith('.css')) {
127
+ this.connection.sendRequest('masterCSS/restart', {
128
+ title: 'Updating Master CSS configuration'
129
+ });
130
+ }
131
+ }
132
+ async onDidChangeConfiguration({ settings }) {
133
+ await this.init();
134
+ if (settings?.masterCSS) {
135
+ this.connection.sendNotification('masterCSS/globalSettingsChanged', settings.masterCSS);
136
+ this.customSettings = settings.masterCSS;
137
+ this.connection.sendRequest('masterCSS/restart', {
138
+ title: 'Updating Master CSS settings'
139
+ });
140
+ }
119
141
  }
120
142
  async initWorkspaceFolder(workspaceFolderURI) {
121
143
  const workspaceFolderCWD = vscodeUri.URI.parse(workspaceFolderURI).fsPath;
122
- const customWorkspaceFolderSettings = await this.connection.workspace.getConfiguration({
123
- scopeUri: workspaceFolderURI,
124
- section: 'masterCSS'
125
- });
144
+ let customWorkspaceFolderSettings;
145
+ if (this.clientCapabilities.workspace?.configuration) {
146
+ customWorkspaceFolderSettings = await this.connection.workspace.getConfiguration({
147
+ scopeUri: workspaceFolderURI,
148
+ section: 'masterCSS'
149
+ });
150
+ }
126
151
  const { workspaces, ...languageServiceSettings } = extend(settings, this.customSettings, customWorkspaceFolderSettings);
127
152
  const resolvedWorkspaceDirectories = new Set([
128
153
  workspaceFolderCWD
129
154
  ]);
130
- console.info('Registered workspace folder', workspaceFolderURI);
155
+ this.console.info(`Registered workspace folder ${workspaceFolderURI}`);
131
156
  if (workspaces === 'auto') {
132
157
  (await glob('**/master.css.*', {
133
158
  cwd: workspaceFolderCWD,
@@ -136,7 +161,7 @@ class CSSLanguageServer {
136
161
  ignore: [
137
162
  '**/node_modules/**'
138
163
  ]
139
- })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(workspaceFile)));
164
+ })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(path.resolve(workspaceFile))));
140
165
  } else if (workspaces?.length) {
141
166
  (await glob(workspaces, {
142
167
  cwd: workspaceFolderCWD,
@@ -145,39 +170,38 @@ class CSSLanguageServer {
145
170
  ignore: [
146
171
  '**/node_modules/**'
147
172
  ]
148
- })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(workspaceDir));
173
+ })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(path.resolve(workspaceDir)));
149
174
  }
150
175
  resolvedWorkspaceDirectories.forEach(async (workspaceDir)=>{
151
176
  const workspaceURI = vscodeUri.URI.file(workspaceDir).toString();
152
- console.info('Added workspace', workspaceURI);
153
- this.workspaces.add({
154
- path: workspaceDir,
177
+ this.console.info(`Added workspace ${workspaceURI}`);
178
+ this.workspaces.push({
155
179
  uri: workspaceURI,
156
- openedTextDocuments: new Set(),
180
+ openedTextDocuments: [],
157
181
  languageServiceSettings
158
182
  });
159
183
  });
160
184
  }
161
- initCSSLanguageService(workspace) {
185
+ initLanguageService(workspace) {
162
186
  let workspaceConfig;
163
187
  try {
164
188
  workspaceConfig = exploreConfig({
165
- cwd: workspace.path,
189
+ cwd: vscodeUri.URI.parse(workspace.uri).fsPath,
166
190
  found: undefined
167
191
  });
168
192
  } catch (e) {
169
- console.info('Failed to load config from', workspace);
170
- console.error(e);
193
+ this.console.info(`Failed to load config from ${workspace}`);
194
+ this.console.error(e);
171
195
  }
172
- console.info('Initialized workspace', workspaceConfig ? '(with config file)' : '', workspace.uri);
173
- workspace.cssLanguageService = new CSSLanguageService({
196
+ this.console.info(`Initialized workspace ${workspaceConfig ? '(with config file)' : ''} ${workspace.uri}`);
197
+ workspace.languageService = new CSSLanguageService({
174
198
  ...workspace.languageServiceSettings,
175
199
  config: workspaceConfig
176
200
  });
177
201
  }
178
- destroyCSSLanguageService(workspace) {
179
- console.info('Destroyed workspace', workspace.uri);
180
- delete workspace.cssLanguageService;
202
+ destroyLanguageService(workspace) {
203
+ this.console.info(`Destroyed workspace ${workspace.uri}`);
204
+ delete workspace.languageService;
181
205
  }
182
206
  findClosestWorkspace(textDocumentURI) {
183
207
  let foundWorkspace;
@@ -186,16 +210,20 @@ class CSSLanguageServer {
186
210
  foundWorkspace = workspace;
187
211
  }
188
212
  }
189
- if (!foundWorkspace) {
190
- throw new Error(`No workspace found for ${textDocumentURI}`);
213
+ if (process.env.DEBUG && !foundWorkspace) {
214
+ this.console.info(`This is an external document ${textDocumentURI} assigned to the first workspace`);
191
215
  }
192
- return foundWorkspace;
216
+ return foundWorkspace || this.workspaces[0];
217
+ }
218
+ getWorkspace(uri) {
219
+ return Array.from(this.workspaces).find((workspace)=>workspace.uri === uri);
193
220
  }
194
221
  stop() {
195
222
  this.connection.sendNotification('masterCSS/dispose');
196
223
  this.disposables.forEach((disposable)=>disposable.dispose());
197
224
  this.disposables.length = 0;
198
225
  this.connection.dispose();
226
+ this.initializing = undefined;
199
227
  }
200
228
  }
201
229
 
package/dist/core.d.ts CHANGED
@@ -1,28 +1,42 @@
1
- import { TextDocuments, WorkspaceFolder, Connection } from 'vscode-languageserver/node';
1
+ import { TextDocuments, InitializeParams, WorkspaceFolder, Connection, ClientCapabilities, TextDocumentChangeEvent, DidChangeConfigurationParams, HoverParams, CompletionParams, DocumentColorParams, ColorPresentationParams, RemoteConsole } from 'vscode-languageserver/node';
2
2
  import { TextDocument } from 'vscode-languageserver-textdocument';
3
3
  import CSSLanguageService, { Settings as CSSLanguageServiceSettings } from '@master/css-language-service';
4
4
  import { Settings } from './settings';
5
- declare type Workspace = {
6
- path: string;
5
+ export declare type Workspace = {
7
6
  uri: string;
8
- openedTextDocuments: Set<TextDocument>;
9
- cssLanguageService?: CSSLanguageService;
7
+ openedTextDocuments: TextDocument[];
8
+ languageService?: CSSLanguageService;
10
9
  languageServiceSettings: CSSLanguageServiceSettings;
11
10
  };
12
11
  export default class CSSLanguageServer {
12
+ connection: Connection;
13
13
  customSettings?: Settings | undefined;
14
14
  workspaceFolders: WorkspaceFolder[];
15
- workspaces: Set<Workspace>;
16
- connection: Connection;
15
+ workspaces: Workspace[];
17
16
  documents: TextDocuments<TextDocument>;
18
- initializing?: Promise<any[]>;
17
+ initializing?: Promise<void>;
18
+ clientCapabilities: ClientCapabilities;
19
+ settings?: Settings;
20
+ console: RemoteConsole;
19
21
  private disposables;
20
- constructor(customSettings?: Settings | undefined);
22
+ constructor(connection?: Connection, customSettings?: Settings | undefined);
21
23
  start(): void;
24
+ init(): Promise<void>;
25
+ onInitialize(params: InitializeParams): {
26
+ capabilities: import("vscode-languageserver/node").ServerCapabilities<any>;
27
+ };
28
+ onHover(params: HoverParams): Promise<import("vscode-languageserver/node").Hover | undefined>;
29
+ onCompletion(params: CompletionParams): Promise<import("vscode-languageserver/node").CompletionItem[] | undefined>;
30
+ onDocumentColor(params: DocumentColorParams): Promise<import("vscode-languageserver/node").ColorInformation[] | undefined>;
31
+ onColorPresentation(params: ColorPresentationParams): Promise<import("vscode-languageserver/node").ColorPresentation[] | undefined>;
32
+ onDidOpen(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
33
+ onDidClose(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
34
+ onDidSave(params: TextDocumentChangeEvent<TextDocument>): Promise<void>;
35
+ onDidChangeConfiguration({ settings }: DidChangeConfigurationParams): Promise<void>;
22
36
  private initWorkspaceFolder;
23
- initCSSLanguageService(workspace: Workspace): void;
24
- destroyCSSLanguageService(workspace: Workspace): void;
37
+ initLanguageService(workspace: Workspace): void;
38
+ destroyLanguageService(workspace: Workspace): void;
25
39
  findClosestWorkspace(textDocumentURI: string): Workspace;
40
+ getWorkspace(uri: string): Workspace | undefined;
26
41
  stop(): void;
27
42
  }
28
- export {};
package/dist/core.mjs CHANGED
@@ -1,131 +1,156 @@
1
- import { createConnection, TextDocuments, DidChangeConfigurationNotification } from 'vscode-languageserver/node';
1
+ import { TextDocuments, createConnection } from 'vscode-languageserver/node';
2
2
  import { TextDocument } from 'vscode-languageserver-textdocument';
3
- import path from 'path';
3
+ import path from 'node:path';
4
4
  import CSSLanguageService, { SERVER_CAPABILITIES } from '@master/css-language-service';
5
5
  import exploreConfig from '@master/css-explore-config';
6
6
  import extend from '@techor/extend';
7
7
  import settings from './settings.mjs';
8
- import interceptLogs from './utils/intercept-logs.mjs';
9
8
  import glob from 'fast-glob';
10
9
  import { URI } from 'vscode-uri';
11
10
 
12
11
  class CSSLanguageServer {
12
+ connection;
13
13
  customSettings;
14
14
  workspaceFolders;
15
15
  workspaces;
16
- connection;
17
16
  documents;
18
17
  initializing;
18
+ clientCapabilities;
19
+ settings;
20
+ console;
19
21
  disposables;
20
- constructor(customSettings){
22
+ constructor(connection = process.argv.includes('--stdio') ? createConnection(process.stdin, process.stdout) : createConnection(), customSettings){
23
+ this.connection = connection;
21
24
  this.customSettings = customSettings;
22
25
  this.workspaceFolders = [];
23
- this.workspaces = new Set();
26
+ this.workspaces = [];
27
+ this.clientCapabilities = {};
24
28
  this.disposables = [];
25
- if (process.argv.includes('--stdio')) {
26
- this.connection = createConnection(process.stdin, process.stdout);
27
- } else {
28
- this.connection = createConnection();
29
- }
30
- interceptLogs(console, this.connection);
31
29
  this.documents = new TextDocuments(TextDocument);
30
+ this.settings = extend(settings, this.customSettings);
31
+ this.console = new Proxy(this.connection.console, {
32
+ get: (target, prop)=>{
33
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
34
+ if (!this.settings?.verbose) return ()=>{};
35
+ return this.connection.console[prop];
36
+ }
37
+ });
32
38
  }
33
39
  start() {
34
- this.disposables.push(this.documents.onDidSave(async (change)=>{
35
- // if the saved file is the master.css file, we need to refresh the css instance
36
- const name = path.parse(change.document.uri).name;
37
- if (name === 'master.css' || name.endsWith('.css')) {
38
- this.connection.sendRequest('masterCSS/restart', {
39
- title: 'Updating Master CSS configuration'
40
- });
41
- }
42
- }), this.documents.onDidOpen(async (params)=>{
43
- await this.initializing;
44
- const workspace = this.findClosestWorkspace(params.document.uri);
45
- if (workspace.openedTextDocuments.has(params.document)) return;
46
- if (!workspace.openedTextDocuments.size) {
47
- this.initCSSLanguageService(workspace);
48
- }
49
- workspace.openedTextDocuments.add(params.document);
50
- }), this.documents.onDidClose(async (params)=>{
51
- await this.initializing;
52
- const workspace = this.findClosestWorkspace(params.document.uri);
53
- workspace.openedTextDocuments.delete(params.document);
54
- if (!workspace.openedTextDocuments.size) {
55
- this.destroyCSSLanguageService(workspace);
56
- }
57
- }), this.documents.listen(this.connection), this.connection.onDidChangeConfiguration(async ({ settings })=>{
58
- await this.initializing;
59
- if (settings?.masterCSS) {
60
- this.connection.sendNotification('masterCSS/globalSettingsChanged', settings.masterCSS);
61
- this.customSettings = settings.masterCSS;
62
- this.connection.sendRequest('masterCSS/restart', {
63
- title: 'Updating Master CSS settings'
40
+ this.disposables.push(this.documents.onDidSave(this.onDidSave.bind(this)), this.documents.onDidOpen(this.onDidOpen.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.onInitialize(this.onInitialize.bind(this)), this.connection.onInitialized(()=>this.init()));
41
+ this.connection.listen();
42
+ }
43
+ init() {
44
+ if (this.initializing) return this.initializing;
45
+ // eslint-disable-next-line no-async-promise-executor
46
+ return this.initializing = new Promise(async (resolve)=>{
47
+ await Promise.all(this.workspaceFolders.map((folder)=>this.initWorkspaceFolder(folder.uri)));
48
+ resolve();
49
+ });
50
+ }
51
+ onInitialize(params) {
52
+ this.clientCapabilities = params.capabilities;
53
+ if (params.workspaceFolders?.length) {
54
+ this.workspaceFolders = params.workspaceFolders;
55
+ } else {
56
+ /**
57
+ * @deprecated — in favour of workspaceFolders
58
+ */ if (params.rootUri) {
59
+ this.workspaceFolders.push({
60
+ name: '',
61
+ uri: params.rootUri
64
62
  });
65
63
  }
66
- }), this.connection.onHover(async (params)=>{
67
- await this.initializing;
68
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
69
- if (workspace?.cssLanguageService) {
70
- const document = this.documents.get(params.textDocument.uri);
71
- if (document) return workspace.cssLanguageService.inspectSyntax(document, params.position);
72
- }
73
- }), this.connection.onCompletion(async (params)=>{
74
- await this.initializing;
75
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
76
- if (workspace?.cssLanguageService) {
77
- const document = this.documents.get(params.textDocument.uri);
78
- if (document) return workspace.cssLanguageService.suggestSyntax(document, params.position, params.context);
79
- }
80
- }), this.connection.onDocumentColor(async (params)=>{
81
- await this.initializing;
82
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
83
- if (workspace?.cssLanguageService) {
84
- const document = this.documents.get(params.textDocument.uri);
85
- if (document) return workspace.cssLanguageService.renderSyntaxColors(document);
86
- }
87
- }), this.connection.onColorPresentation(async (params)=>{
88
- await this.initializing;
89
- const workspace = this.findClosestWorkspace(params.textDocument.uri);
90
- if (workspace?.cssLanguageService) {
91
- const document = this.documents.get(params.textDocument.uri);
92
- if (document) return workspace.cssLanguageService.editSyntaxColors(document, params.color, params.range);
93
- }
94
- }), // Make the text document manager listen on the connection
95
- // for open, change and close text document events
96
- this.connection.onInitialize((params)=>{
97
- if (params.workspaceFolders?.length) {
98
- this.workspaceFolders = params.workspaceFolders;
99
- } else {
100
- if (params.rootUri) {
101
- this.workspaceFolders.push({
102
- name: '',
103
- uri: params.rootUri
104
- });
105
- }
106
- }
107
- return {
108
- capabilities: SERVER_CAPABILITIES
109
- };
110
- }), this.connection.onInitialized(async ()=>{
111
- this.initializing = Promise.all([
112
- ...this.workspaceFolders.map((folder)=>this.initWorkspaceFolder(folder.uri)),
113
- this.connection.client.register(DidChangeConfigurationNotification.type, undefined)
114
- ]);
115
- }));
116
- this.connection.listen();
64
+ }
65
+ return {
66
+ capabilities: SERVER_CAPABILITIES
67
+ };
68
+ }
69
+ async onHover(params) {
70
+ await this.init();
71
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
72
+ if (workspace.languageService) {
73
+ const document = this.documents.get(params.textDocument.uri);
74
+ if (document) return workspace.languageService.inspectSyntax(document, params.position);
75
+ }
76
+ }
77
+ async onCompletion(params) {
78
+ await this.init();
79
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
80
+ if (workspace.languageService) {
81
+ const document = this.documents.get(params.textDocument.uri);
82
+ if (document) return workspace.languageService.suggestSyntax(document, params.position, params.context);
83
+ }
84
+ }
85
+ async onDocumentColor(params) {
86
+ await this.init();
87
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
88
+ if (workspace.languageService) {
89
+ const document = this.documents.get(params.textDocument.uri);
90
+ if (document) return workspace.languageService.renderSyntaxColors(document);
91
+ }
92
+ }
93
+ async onColorPresentation(params) {
94
+ await this.init();
95
+ const workspace = this.findClosestWorkspace(params.textDocument.uri);
96
+ if (workspace.languageService) {
97
+ const document = this.documents.get(params.textDocument.uri);
98
+ if (document) return workspace.languageService.editSyntaxColors(document, params.color, params.range);
99
+ }
100
+ }
101
+ async onDidOpen(params) {
102
+ await this.init();
103
+ const workspace = this.findClosestWorkspace(params.document.uri);
104
+ if (!workspace || workspace.openedTextDocuments.includes(params.document)) return;
105
+ if (!workspace.openedTextDocuments.length) {
106
+ this.initLanguageService(workspace);
107
+ }
108
+ workspace.openedTextDocuments.push(params.document);
109
+ }
110
+ async onDidClose(params) {
111
+ await this.init();
112
+ const workspace = this.findClosestWorkspace(params.document.uri);
113
+ if (!workspace) return;
114
+ workspace.openedTextDocuments.splice(workspace.openedTextDocuments.indexOf(params.document), 1);
115
+ if (!workspace.openedTextDocuments.length) {
116
+ this.destroyLanguageService(workspace);
117
+ }
118
+ }
119
+ async onDidSave(params) {
120
+ await this.init();
121
+ const workspace = this.findClosestWorkspace(params.document.uri);
122
+ if (!workspace) return;
123
+ const name = path.parse(params.document.uri).name;
124
+ if (name === 'master.css' || name.endsWith('.css')) {
125
+ this.connection.sendRequest('masterCSS/restart', {
126
+ title: 'Updating Master CSS configuration'
127
+ });
128
+ }
129
+ }
130
+ async onDidChangeConfiguration({ settings }) {
131
+ await this.init();
132
+ if (settings?.masterCSS) {
133
+ this.connection.sendNotification('masterCSS/globalSettingsChanged', settings.masterCSS);
134
+ this.customSettings = settings.masterCSS;
135
+ this.connection.sendRequest('masterCSS/restart', {
136
+ title: 'Updating Master CSS settings'
137
+ });
138
+ }
117
139
  }
118
140
  async initWorkspaceFolder(workspaceFolderURI) {
119
141
  const workspaceFolderCWD = URI.parse(workspaceFolderURI).fsPath;
120
- const customWorkspaceFolderSettings = await this.connection.workspace.getConfiguration({
121
- scopeUri: workspaceFolderURI,
122
- section: 'masterCSS'
123
- });
142
+ let customWorkspaceFolderSettings;
143
+ if (this.clientCapabilities.workspace?.configuration) {
144
+ customWorkspaceFolderSettings = await this.connection.workspace.getConfiguration({
145
+ scopeUri: workspaceFolderURI,
146
+ section: 'masterCSS'
147
+ });
148
+ }
124
149
  const { workspaces, ...languageServiceSettings } = extend(settings, this.customSettings, customWorkspaceFolderSettings);
125
150
  const resolvedWorkspaceDirectories = new Set([
126
151
  workspaceFolderCWD
127
152
  ]);
128
- console.info('Registered workspace folder', workspaceFolderURI);
153
+ this.console.info(`Registered workspace folder ${workspaceFolderURI}`);
129
154
  if (workspaces === 'auto') {
130
155
  (await glob('**/master.css.*', {
131
156
  cwd: workspaceFolderCWD,
@@ -134,7 +159,7 @@ class CSSLanguageServer {
134
159
  ignore: [
135
160
  '**/node_modules/**'
136
161
  ]
137
- })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(workspaceFile)));
162
+ })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(path.resolve(workspaceFile))));
138
163
  } else if (workspaces?.length) {
139
164
  (await glob(workspaces, {
140
165
  cwd: workspaceFolderCWD,
@@ -143,39 +168,38 @@ class CSSLanguageServer {
143
168
  ignore: [
144
169
  '**/node_modules/**'
145
170
  ]
146
- })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(workspaceDir));
171
+ })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(path.resolve(workspaceDir)));
147
172
  }
148
173
  resolvedWorkspaceDirectories.forEach(async (workspaceDir)=>{
149
174
  const workspaceURI = URI.file(workspaceDir).toString();
150
- console.info('Added workspace', workspaceURI);
151
- this.workspaces.add({
152
- path: workspaceDir,
175
+ this.console.info(`Added workspace ${workspaceURI}`);
176
+ this.workspaces.push({
153
177
  uri: workspaceURI,
154
- openedTextDocuments: new Set(),
178
+ openedTextDocuments: [],
155
179
  languageServiceSettings
156
180
  });
157
181
  });
158
182
  }
159
- initCSSLanguageService(workspace) {
183
+ initLanguageService(workspace) {
160
184
  let workspaceConfig;
161
185
  try {
162
186
  workspaceConfig = exploreConfig({
163
- cwd: workspace.path,
187
+ cwd: URI.parse(workspace.uri).fsPath,
164
188
  found: undefined
165
189
  });
166
190
  } catch (e) {
167
- console.info('Failed to load config from', workspace);
168
- console.error(e);
191
+ this.console.info(`Failed to load config from ${workspace}`);
192
+ this.console.error(e);
169
193
  }
170
- console.info('Initialized workspace', workspaceConfig ? '(with config file)' : '', workspace.uri);
171
- workspace.cssLanguageService = new CSSLanguageService({
194
+ this.console.info(`Initialized workspace ${workspaceConfig ? '(with config file)' : ''} ${workspace.uri}`);
195
+ workspace.languageService = new CSSLanguageService({
172
196
  ...workspace.languageServiceSettings,
173
197
  config: workspaceConfig
174
198
  });
175
199
  }
176
- destroyCSSLanguageService(workspace) {
177
- console.info('Destroyed workspace', workspace.uri);
178
- delete workspace.cssLanguageService;
200
+ destroyLanguageService(workspace) {
201
+ this.console.info(`Destroyed workspace ${workspace.uri}`);
202
+ delete workspace.languageService;
179
203
  }
180
204
  findClosestWorkspace(textDocumentURI) {
181
205
  let foundWorkspace;
@@ -184,16 +208,20 @@ class CSSLanguageServer {
184
208
  foundWorkspace = workspace;
185
209
  }
186
210
  }
187
- if (!foundWorkspace) {
188
- throw new Error(`No workspace found for ${textDocumentURI}`);
211
+ if (process.env.DEBUG && !foundWorkspace) {
212
+ this.console.info(`This is an external document ${textDocumentURI} assigned to the first workspace`);
189
213
  }
190
- return foundWorkspace;
214
+ return foundWorkspace || this.workspaces[0];
215
+ }
216
+ getWorkspace(uri) {
217
+ return Array.from(this.workspaces).find((workspace)=>workspace.uri === uri);
191
218
  }
192
219
  stop() {
193
220
  this.connection.sendNotification('masterCSS/dispose');
194
221
  this.disposables.forEach((disposable)=>disposable.dispose());
195
222
  this.disposables.length = 0;
196
223
  this.connection.dispose();
224
+ this.initializing = undefined;
197
225
  }
198
226
  }
199
227
 
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default, default as CSSLanguageServer } from './core';
2
2
  export { default as settings, type Settings } from './settings';
3
+ export type { Workspace } from './core';
package/dist/settings.cjs CHANGED
@@ -4,7 +4,8 @@ var CSSLanguageService = require('@master/css-language-service');
4
4
 
5
5
  const settings = {
6
6
  ...CSSLanguageService.settings,
7
- workspaces: 'auto'
7
+ workspaces: 'auto',
8
+ verbose: false
8
9
  };
9
10
 
10
11
  module.exports = settings;
@@ -2,5 +2,6 @@ import { type Settings as CSSLanguageServiceSettings } from '@master/css-languag
2
2
  declare const settings: Settings;
3
3
  export default settings;
4
4
  export declare type Settings = CSSLanguageServiceSettings & {
5
- workspaces: string[] | 'auto';
5
+ workspaces?: string[] | 'auto';
6
+ verbose?: boolean;
6
7
  };
package/dist/settings.mjs CHANGED
@@ -2,7 +2,8 @@ import { settings as settings$1 } from '@master/css-language-service';
2
2
 
3
3
  const settings = {
4
4
  ...settings$1,
5
- workspaces: 'auto'
5
+ workspaces: 'auto',
6
+ verbose: false
6
7
  };
7
8
 
8
9
  export { settings as default };
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ var vscodeLanguageserverTextdocument = require('vscode-languageserver-textdocument');
4
+ var nanoid = require('nanoid');
5
+ var path = require('path');
6
+ var vscodeUri = require('vscode-uri');
7
+
8
+ const extOfLang = {
9
+ typescript: 'ts',
10
+ typescriptreact: 'tsx',
11
+ javascript: 'js',
12
+ javascriptreact: 'jsx',
13
+ css: 'css',
14
+ scss: 'scss',
15
+ less: 'less',
16
+ html: 'html',
17
+ json: 'json',
18
+ vue: 'vue',
19
+ svelte: 'svelte',
20
+ astro: 'astro'
21
+ };
22
+ function createDocument(text, options) {
23
+ const lang = options?.lang || 'html';
24
+ const dir = options?.dir || './';
25
+ const filePath = path.join(dir, `${nanoid.nanoid()}.${extOfLang[lang]}`);
26
+ const fileURI = vscodeUri.URI.file(filePath).toString();
27
+ return vscodeLanguageserverTextdocument.TextDocument.create(fileURI, lang, 0, text);
28
+ }
29
+
30
+ module.exports = createDocument;
@@ -0,0 +1,5 @@
1
+ import { TextDocument } from 'vscode-languageserver-textdocument';
2
+ export default function createDocument(text: string, options?: {
3
+ lang?: string;
4
+ dir?: string;
5
+ }): TextDocument;
@@ -0,0 +1,28 @@
1
+ import { TextDocument } from 'vscode-languageserver-textdocument';
2
+ import { nanoid } from 'nanoid';
3
+ import path from 'path';
4
+ import { URI } from 'vscode-uri';
5
+
6
+ const extOfLang = {
7
+ typescript: 'ts',
8
+ typescriptreact: 'tsx',
9
+ javascript: 'js',
10
+ javascriptreact: 'jsx',
11
+ css: 'css',
12
+ scss: 'scss',
13
+ less: 'less',
14
+ html: 'html',
15
+ json: 'json',
16
+ vue: 'vue',
17
+ svelte: 'svelte',
18
+ astro: 'astro'
19
+ };
20
+ function createDocument(text, options) {
21
+ const lang = options?.lang || 'html';
22
+ const dir = options?.dir || './';
23
+ const filePath = path.join(dir, `${nanoid()}.${extOfLang[lang]}`);
24
+ const fileURI = URI.file(filePath).toString();
25
+ return TextDocument.create(fileURI, lang, 0, text);
26
+ }
27
+
28
+ export { createDocument as default };
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@master/css-language-server","type":"module","scripts":{"build":"techor build \"src/**/*.ts\"","dev":"pnpm build --watch","type-check":"tsc --noEmit","lint":"eslint src","test":"jest"},"description":"Master CSS Language Server","author":"Aoyue Design LLC.","license":"MIT","repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/language-server"},"dependencies":{"@master/css":"^2.0.0-rc.38","@master/css-explore-config":"^2.0.0-rc.38","@master/css-language-service":"^2.0.0-rc.38","@techor/extend":"^3.0.22","fast-glob":"^3.3.2","js-beautify":"^1.15.1","vscode-languageserver":"^9.0.1","vscode-languageserver-textdocument":"^1.0.11","vscode-uri":"^3.0.8"},"devDependencies":{"@master/css-shared":"^2.0.0-rc.38"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.mjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs","types":"./dist/index.d.ts"}},"files":["dist"],"publishConfig":{"access":"public","provenance":true},"version":"2.0.0-rc.38"}
1
+ {"name":"@master/css-language-server","type":"module","scripts":{"build":"techor build \"src/**/*.ts\"","dev":"pnpm build --watch","type-check":"tsc --noEmit","lint":"eslint src","test":"vitest"},"description":"Master CSS Language Server","author":"Aoyue Design LLC.","license":"MIT","repository":{"type":"git","url":"https://github.com/master-co/css.git","directory":"packages/language-server"},"dependencies":{"@master/css":"^2.0.0-rc.39","@master/css-explore-config":"^2.0.0-rc.39","@master/css-language-service":"^2.0.0-rc.39","@techor/extend":"^3.0.22","fast-glob":"^3.3.2","js-beautify":"^1.15.1","nanoid":"^5.0.6","vscode-languageserver":"^9.0.1","vscode-languageserver-textdocument":"^1.0.11","vscode-uri":"^3.0.8"},"devDependencies":{"@master/css-shared":"^2.0.0-rc.39"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.mjs","jsnext:main":"./dist/index.mjs","esnext":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs","types":"./dist/index.d.ts"}},"files":["dist"],"publishConfig":{"access":"public","provenance":true},"version":"2.0.0-rc.39"}
@@ -1,17 +0,0 @@
1
- 'use strict';
2
-
3
- var node_util = require('node:util');
4
-
5
- function formatMessages(params) {
6
- return params.map((item)=>node_util.format(item)).join(' ');
7
- }
8
- function interceptLogs(console, connection) {
9
- console.debug = (...params)=>connection.console.info(formatMessages(params));
10
- console.error = (...params)=>connection.console.error(formatMessages(params));
11
- console.warn = (...params)=>connection.console.warn(formatMessages(params));
12
- console.info = (...params)=>connection.console.info(formatMessages(params));
13
- console.log = (...params)=>connection.console.log(formatMessages(params));
14
- return console;
15
- }
16
-
17
- module.exports = interceptLogs;
@@ -1,2 +0,0 @@
1
- import type { Connection } from 'vscode-languageserver';
2
- export default function interceptLogs(console: Console, connection: Connection): Console;
@@ -1,15 +0,0 @@
1
- import { format } from 'node:util';
2
-
3
- function formatMessages(params) {
4
- return params.map((item)=>format(item)).join(' ');
5
- }
6
- function interceptLogs(console, connection) {
7
- console.debug = (...params)=>connection.console.info(formatMessages(params));
8
- console.error = (...params)=>connection.console.error(formatMessages(params));
9
- console.warn = (...params)=>connection.console.warn(formatMessages(params));
10
- console.info = (...params)=>connection.console.info(formatMessages(params));
11
- console.log = (...params)=>connection.console.log(formatMessages(params));
12
- return console;
13
- }
14
-
15
- export { interceptLogs as default };