@knip/language-server 1.2.2 → 2.0.0

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/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@knip/language-server",
3
- "version": "1.2.2",
3
+ "version": "2.0.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/webpro-nl/knip.git",
7
7
  "directory": "packages/language-server"
8
8
  },
9
9
  "type": "module",
10
+ "bin": {
11
+ "knip-language-server": "./src/cli.js"
12
+ },
10
13
  "exports": {
11
14
  ".": {
12
15
  "types": "./src/types.d.ts",
@@ -17,7 +20,7 @@
17
20
  "dependencies": {
18
21
  "vscode-languageserver": "^9.0.1",
19
22
  "vscode-languageserver-textdocument": "^1.0.12",
20
- "knip": "^5.83.1"
23
+ "knip": "^5.84.0"
21
24
  },
22
25
  "engines": {
23
26
  "node": ">=18.20.0"
package/src/cli.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import './index.js';
package/src/index.js CHANGED
@@ -1,3 +1,6 @@
1
1
  import { LanguageServer } from './server.js';
2
2
 
3
+ const transports = ['--stdio', '--socket', '--node-ipc', '--pipe'];
4
+ if (!process.argv.some(arg => transports.includes(arg))) process.argv.push('--stdio');
5
+
3
6
  new LanguageServer();
package/src/server.js CHANGED
@@ -26,6 +26,21 @@ import { issueToDiagnostic } from './diagnostics.js';
26
26
 
27
27
  const RESTART_FOR = new Set(['package.json', ...KNIP_CONFIG_LOCATIONS]);
28
28
 
29
+ /** @type {Config} */
30
+ const DEFAULT_CONFIG = {
31
+ deferSession: false,
32
+ editor: {
33
+ exports: {
34
+ codelens: { enabled: true },
35
+ hover: { enabled: true, includeImportLocationSnippet: false, maxSnippets: 10, timeout: 300 },
36
+ quickfix: { enabled: true },
37
+ highlight: { dimExports: false, dimTypes: false },
38
+ },
39
+ },
40
+ imports: { enabled: true },
41
+ exports: { enabled: true, contention: { enabled: true } },
42
+ };
43
+
29
44
  /** @param {string} value */
30
45
  const toPosix = value => value.split(path.sep).join(path.posix.sep);
31
46
 
@@ -77,9 +92,16 @@ export class LanguageServer {
77
92
  /** @type TextDocuments<TextDocument> */
78
93
  documents;
79
94
 
95
+ /** @type {Config | undefined} */
96
+ initConfig;
97
+
80
98
  constructor() {
81
99
  this.connection = createConnection(ProposedFeatures.all);
82
100
  this.documents = new TextDocuments(TextDocument);
101
+ console.log = this.connection.console.log.bind(this.connection.console);
102
+ console.warn = this.connection.console.warn.bind(this.connection.console);
103
+ console.error = this.connection.console.error.bind(this.connection.console);
104
+ console.info = this.connection.console.info.bind(this.connection.console);
83
105
  this.setupHandlers();
84
106
  this.documents.listen(this.connection);
85
107
  this.connection.listen();
@@ -93,6 +115,8 @@ export class LanguageServer {
93
115
 
94
116
  this.cwd = fileURLToPath(uri);
95
117
 
118
+ this.initConfig = params.initializationOptions?.config;
119
+
96
120
  const capabilities = {
97
121
  codeActionProvider: {
98
122
  codeActionKinds: [CodeActionKind.QuickFix],
@@ -108,7 +132,10 @@ export class LanguageServer {
108
132
  };
109
133
  });
110
134
 
111
- this.connection.onInitialized(() => {});
135
+ this.connection.onInitialized(async () => {
136
+ const config = await this.getConfig();
137
+ if (config?.deferSession !== true) this.start();
138
+ });
112
139
 
113
140
  this.connection.onRequest(REQUEST_START, () => this.start());
114
141
 
@@ -135,7 +162,11 @@ export class LanguageServer {
135
162
 
136
163
  /** @returns {Promise<Config>} */
137
164
  async getConfig() {
138
- return await this.connection.workspace.getConfiguration('knip');
165
+ try {
166
+ const config = await this.connection.workspace.getConfiguration('knip');
167
+ if (config?.editor) return config;
168
+ } catch {}
169
+ return this.initConfig ?? DEFAULT_CONFIG;
139
170
  }
140
171
 
141
172
  /**
@@ -181,17 +212,13 @@ export class LanguageServer {
181
212
 
182
213
  try {
183
214
  const config = await this.getConfig();
184
- if (!config?.enabled) return;
185
215
 
186
- const configFilePath = config.configFilePath
216
+ const configFilePath = config?.configFilePath
187
217
  ? path.isAbsolute(config.configFilePath)
188
218
  ? config.configFilePath
189
219
  : path.resolve(this.cwd ?? process.cwd(), config.configFilePath)
190
220
  : undefined;
191
221
 
192
- if (configFilePath) this.cwd = path.dirname(configFilePath);
193
- if (this.cwd) process.chdir(this.cwd);
194
-
195
222
  this.connection.console.log('Creating options');
196
223
  const options = await createOptions({ cwd: this.cwd, isSession: true, args: { config: configFilePath } });
197
224
  this.rules = options.rules;
@@ -235,23 +262,29 @@ export class LanguageServer {
235
262
  this.packageJsonCache = undefined;
236
263
  if (!this.session) return;
237
264
 
265
+ const cwd = this.cwd ?? process.cwd();
266
+
238
267
  /** @type {{ type: "added" | "deleted" | "modified"; filePath: string }[]} */
239
268
  const changes = [];
240
269
  for (const change of params.changes) {
270
+ if (!change.uri.startsWith('file:')) continue;
241
271
  const filePath = fileURLToPath(change.uri);
272
+ if (!filePath.startsWith(cwd) || filePath.includes('/.git/')) continue;
242
273
  if (RESTART_FOR.has(path.basename(change.uri))) return this.restart();
243
274
  const type = FILE_CHANGE_TYPES.get(change.type);
244
275
  if (!type) continue;
245
276
  changes.push({ type, filePath });
246
277
  }
247
278
 
279
+ if (changes.length === 0) return;
280
+
248
281
  const result = await this.session.handleFileChanges(changes);
249
282
 
250
- if (result) {
251
- this.connection.console.log(
252
- `Module graph updated (${Math.floor(result.duration)}ms • ${(result.mem / 1024 / 1024).toFixed(2)}M)`
253
- );
254
- }
283
+ if (!result) return;
284
+
285
+ this.connection.console.log(
286
+ `Module graph updated (${Math.floor(result.duration)}ms • ${(result.mem / 1024 / 1024).toFixed(2)}M)`
287
+ );
255
288
 
256
289
  const config = await this.getConfig();
257
290
  this.publishDiagnostics(this.buildDiagnostics(this.session.getIssues().issues, config, this.rules));
package/src/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Issue, IssueType } from 'knip/session';
2
2
 
3
3
  export type Config = {
4
- enabled: boolean;
4
+ deferSession: boolean;
5
5
  configFilePath?: string;
6
6
  editor: {
7
7
  exports: {