@master/css-language-server 2.0.0-rc.37 → 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,133 +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');
6
- var url = require('url');
5
+ var path = require('node:path');
7
6
  var CSSLanguageService = require('@master/css-language-service');
8
7
  var exploreConfig = require('@master/css-explore-config');
9
8
  var extend = require('@techor/extend');
10
9
  var settings = require('./settings.cjs');
11
- var interceptLogs = require('./utils/intercept-logs.cjs');
12
10
  var glob = require('fast-glob');
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
- const workspaceFolderCWD = this.fileURLToPath(workspaceFolderURI);
122
- const customWorkspaceFolderSettings = await this.connection.workspace.getConfiguration({
123
- scopeUri: workspaceFolderURI,
124
- section: 'masterCSS'
125
- });
143
+ const workspaceFolderCWD = vscodeUri.URI.parse(workspaceFolderURI).fsPath;
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');
131
- console.log(workspaceFolderCWD);
155
+ this.console.info(`Registered workspace folder ${workspaceFolderURI}`);
132
156
  if (workspaces === 'auto') {
133
157
  (await glob('**/master.css.*', {
134
158
  cwd: workspaceFolderCWD,
@@ -137,7 +161,7 @@ class CSSLanguageServer {
137
161
  ignore: [
138
162
  '**/node_modules/**'
139
163
  ]
140
- })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(workspaceFile)));
164
+ })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(path.resolve(workspaceFile))));
141
165
  } else if (workspaces?.length) {
142
166
  (await glob(workspaces, {
143
167
  cwd: workspaceFolderCWD,
@@ -146,44 +170,38 @@ class CSSLanguageServer {
146
170
  ignore: [
147
171
  '**/node_modules/**'
148
172
  ]
149
- })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(workspaceDir));
173
+ })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(path.resolve(workspaceDir)));
150
174
  }
151
175
  resolvedWorkspaceDirectories.forEach(async (workspaceDir)=>{
152
- console.info('Added workspace');
153
- console.log(workspaceDir);
154
- this.workspaces.add({
155
- path: workspaceDir,
156
- uri: url.pathToFileURL(workspaceDir).href,
157
- openedTextDocuments: new Set(),
176
+ const workspaceURI = vscodeUri.URI.file(workspaceDir).toString();
177
+ this.console.info(`Added workspace ${workspaceURI}`);
178
+ this.workspaces.push({
179
+ uri: workspaceURI,
180
+ openedTextDocuments: [],
158
181
  languageServiceSettings
159
182
  });
160
183
  });
161
184
  }
162
- initCSSLanguageService(workspace) {
185
+ initLanguageService(workspace) {
163
186
  let workspaceConfig;
164
187
  try {
165
188
  workspaceConfig = exploreConfig({
166
- cwd: workspace.path,
189
+ cwd: vscodeUri.URI.parse(workspace.uri).fsPath,
167
190
  found: undefined
168
191
  });
169
192
  } catch (e) {
170
- console.info('Failed to load config from', workspace);
171
- console.error(e);
193
+ this.console.info(`Failed to load config from ${workspace}`);
194
+ this.console.error(e);
172
195
  }
173
- console.info('Initialized workspace', workspaceConfig ? '(with config file)' : '');
174
- console.log(workspace.path);
175
- workspace.cssLanguageService = new CSSLanguageService({
196
+ this.console.info(`Initialized workspace ${workspaceConfig ? '(with config file)' : ''} ${workspace.uri}`);
197
+ workspace.languageService = new CSSLanguageService({
176
198
  ...workspace.languageServiceSettings,
177
199
  config: workspaceConfig
178
200
  });
179
201
  }
180
- destroyCSSLanguageService(workspace) {
181
- console.info('Destroyed workspace');
182
- console.log(workspace.path);
183
- delete workspace.cssLanguageService;
184
- }
185
- fileURLToPath(workspaceURI) {
186
- return url.fileURLToPath(workspaceURI.replace('%3A', ':'));
202
+ destroyLanguageService(workspace) {
203
+ this.console.info(`Destroyed workspace ${workspace.uri}`);
204
+ delete workspace.languageService;
187
205
  }
188
206
  findClosestWorkspace(textDocumentURI) {
189
207
  let foundWorkspace;
@@ -192,16 +210,20 @@ class CSSLanguageServer {
192
210
  foundWorkspace = workspace;
193
211
  }
194
212
  }
195
- if (!foundWorkspace) {
196
- 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`);
197
215
  }
198
- return foundWorkspace;
216
+ return foundWorkspace || this.workspaces[0];
217
+ }
218
+ getWorkspace(uri) {
219
+ return Array.from(this.workspaces).find((workspace)=>workspace.uri === uri);
199
220
  }
200
221
  stop() {
201
222
  this.connection.sendNotification('masterCSS/dispose');
202
223
  this.disposables.forEach((disposable)=>disposable.dispose());
203
224
  this.disposables.length = 0;
204
225
  this.connection.dispose();
226
+ this.initializing = undefined;
205
227
  }
206
228
  }
207
229
 
package/dist/core.d.ts CHANGED
@@ -1,29 +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;
25
- fileURLToPath(workspaceURI: string): string;
37
+ initLanguageService(workspace: Workspace): void;
38
+ destroyLanguageService(workspace: Workspace): void;
26
39
  findClosestWorkspace(textDocumentURI: string): Workspace;
40
+ getWorkspace(uri: string): Workspace | undefined;
27
41
  stop(): void;
28
42
  }
29
- export {};
package/dist/core.mjs CHANGED
@@ -1,132 +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';
4
- import { pathToFileURL, fileURLToPath } from 'url';
3
+ import path from 'node:path';
5
4
  import CSSLanguageService, { SERVER_CAPABILITIES } from '@master/css-language-service';
6
5
  import exploreConfig from '@master/css-explore-config';
7
6
  import extend from '@techor/extend';
8
7
  import settings from './settings.mjs';
9
- import interceptLogs from './utils/intercept-logs.mjs';
10
8
  import glob from 'fast-glob';
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
- const workspaceFolderCWD = this.fileURLToPath(workspaceFolderURI);
120
- const customWorkspaceFolderSettings = await this.connection.workspace.getConfiguration({
121
- scopeUri: workspaceFolderURI,
122
- section: 'masterCSS'
123
- });
141
+ const workspaceFolderCWD = URI.parse(workspaceFolderURI).fsPath;
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');
129
- console.log(workspaceFolderCWD);
153
+ this.console.info(`Registered workspace folder ${workspaceFolderURI}`);
130
154
  if (workspaces === 'auto') {
131
155
  (await glob('**/master.css.*', {
132
156
  cwd: workspaceFolderCWD,
@@ -135,7 +159,7 @@ class CSSLanguageServer {
135
159
  ignore: [
136
160
  '**/node_modules/**'
137
161
  ]
138
- })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(workspaceFile)));
162
+ })).forEach((workspaceFile)=>resolvedWorkspaceDirectories.add(path.dirname(path.resolve(workspaceFile))));
139
163
  } else if (workspaces?.length) {
140
164
  (await glob(workspaces, {
141
165
  cwd: workspaceFolderCWD,
@@ -144,44 +168,38 @@ class CSSLanguageServer {
144
168
  ignore: [
145
169
  '**/node_modules/**'
146
170
  ]
147
- })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(workspaceDir));
171
+ })).forEach((workspaceDir)=>resolvedWorkspaceDirectories.add(path.resolve(workspaceDir)));
148
172
  }
149
173
  resolvedWorkspaceDirectories.forEach(async (workspaceDir)=>{
150
- console.info('Added workspace');
151
- console.log(workspaceDir);
152
- this.workspaces.add({
153
- path: workspaceDir,
154
- uri: pathToFileURL(workspaceDir).href,
155
- openedTextDocuments: new Set(),
174
+ const workspaceURI = URI.file(workspaceDir).toString();
175
+ this.console.info(`Added workspace ${workspaceURI}`);
176
+ this.workspaces.push({
177
+ uri: workspaceURI,
178
+ openedTextDocuments: [],
156
179
  languageServiceSettings
157
180
  });
158
181
  });
159
182
  }
160
- initCSSLanguageService(workspace) {
183
+ initLanguageService(workspace) {
161
184
  let workspaceConfig;
162
185
  try {
163
186
  workspaceConfig = exploreConfig({
164
- cwd: workspace.path,
187
+ cwd: URI.parse(workspace.uri).fsPath,
165
188
  found: undefined
166
189
  });
167
190
  } catch (e) {
168
- console.info('Failed to load config from', workspace);
169
- console.error(e);
191
+ this.console.info(`Failed to load config from ${workspace}`);
192
+ this.console.error(e);
170
193
  }
171
- console.info('Initialized workspace', workspaceConfig ? '(with config file)' : '');
172
- console.log(workspace.path);
173
- workspace.cssLanguageService = new CSSLanguageService({
194
+ this.console.info(`Initialized workspace ${workspaceConfig ? '(with config file)' : ''} ${workspace.uri}`);
195
+ workspace.languageService = new CSSLanguageService({
174
196
  ...workspace.languageServiceSettings,
175
197
  config: workspaceConfig
176
198
  });
177
199
  }
178
- destroyCSSLanguageService(workspace) {
179
- console.info('Destroyed workspace');
180
- console.log(workspace.path);
181
- delete workspace.cssLanguageService;
182
- }
183
- fileURLToPath(workspaceURI) {
184
- return fileURLToPath(workspaceURI.replace('%3A', ':'));
200
+ destroyLanguageService(workspace) {
201
+ this.console.info(`Destroyed workspace ${workspace.uri}`);
202
+ delete workspace.languageService;
185
203
  }
186
204
  findClosestWorkspace(textDocumentURI) {
187
205
  let foundWorkspace;
@@ -190,16 +208,20 @@ class CSSLanguageServer {
190
208
  foundWorkspace = workspace;
191
209
  }
192
210
  }
193
- if (!foundWorkspace) {
194
- 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`);
195
213
  }
196
- return foundWorkspace;
214
+ return foundWorkspace || this.workspaces[0];
215
+ }
216
+ getWorkspace(uri) {
217
+ return Array.from(this.workspaces).find((workspace)=>workspace.uri === uri);
197
218
  }
198
219
  stop() {
199
220
  this.connection.sendNotification('masterCSS/dispose');
200
221
  this.disposables.forEach((disposable)=>disposable.dispose());
201
222
  this.disposables.length = 0;
202
223
  this.connection.dispose();
224
+ this.initializing = undefined;
203
225
  }
204
226
  }
205
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.37","@master/css-explore-config":"^2.0.0-rc.37","@master/css-language-service":"^2.0.0-rc.37","@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"},"devDependencies":{"@master/css-shared":"^2.0.0-rc.37"},"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.37"}
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 };