@rslint/core 0.6.5 → 0.7.1
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/0~engine.js +109 -19
- package/dist/519.js +601 -0
- package/dist/cli.js +32 -983
- package/dist/config-loader.d.ts +175 -9
- package/dist/config-loader.js +3 -161
- package/dist/eslint-plugin/index.d.ts +25 -13
- package/dist/eslint-plugin/index.js +61 -27
- package/dist/eslint-plugin/lint-worker.js +61 -27
- package/dist/eslint-plugin/types.d.ts +19 -9
- package/dist/index.d.ts +38 -20
- package/dist/index.js +1326 -91
- package/dist/internal.d.ts +37 -3
- package/dist/internal.js +80 -18
- package/dist/service.d.ts +89 -4
- package/dist/service.js +116 -10
- package/package.json +10 -10
package/dist/internal.d.ts
CHANGED
|
@@ -15,6 +15,15 @@ declare interface Fix {
|
|
|
15
15
|
endPos: number;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/** Handler for a positive-id request frame sent by the Go peer. */
|
|
19
|
+
declare type InboundRequestHandler = (message: IpcMessage) => unknown;
|
|
20
|
+
|
|
21
|
+
declare interface IpcMessage {
|
|
22
|
+
id: number;
|
|
23
|
+
kind: string;
|
|
24
|
+
data: any;
|
|
25
|
+
}
|
|
26
|
+
|
|
18
27
|
/**
|
|
19
28
|
* One-shot convenience: spin up a Node-backed service, run a single lint
|
|
20
29
|
* request, then tear it down. This is an internal/tooling surface (the
|
|
@@ -26,8 +35,28 @@ export declare function lint(options: LintOptions): Promise<LintResponse>;
|
|
|
26
35
|
|
|
27
36
|
export declare interface LintOptions {
|
|
28
37
|
files?: string[];
|
|
38
|
+
canonicalFiles?: string[];
|
|
29
39
|
config?: Record<string, unknown>[];
|
|
40
|
+
/**
|
|
41
|
+
* Ask native Go to discover and route JS/TS configs for this lint request.
|
|
42
|
+
* `config` and `configDiscovery` are mutually exclusive. Browser/WASM
|
|
43
|
+
* backends intentionally do not advertise this host-filesystem capability.
|
|
44
|
+
*/
|
|
45
|
+
configDiscovery?: {
|
|
46
|
+
explicitConfigPath?: string;
|
|
47
|
+
/** Static glob roots; Go visits only branches leading to the supplied files. */
|
|
48
|
+
directories?: string[];
|
|
49
|
+
/** Parallel to `files`; true only for caller-literal file targets. */
|
|
50
|
+
explicitFiles?: boolean[];
|
|
51
|
+
/** Normalized API override entries appended to every selected config. */
|
|
52
|
+
overrideConfig?: Record<string, unknown>[];
|
|
53
|
+
};
|
|
54
|
+
eslintPlugins?: Array<{
|
|
55
|
+
prefix: string;
|
|
56
|
+
ruleNames: string[];
|
|
57
|
+
}>;
|
|
30
58
|
configDirectory?: string;
|
|
59
|
+
pluginConfigDirectory?: string;
|
|
31
60
|
workingDirectory?: string;
|
|
32
61
|
fileContents?: Record<string, string>;
|
|
33
62
|
includeEncodedSourceFiles?: boolean;
|
|
@@ -60,6 +89,8 @@ export declare class NodeRslintService implements RslintServiceInterface {
|
|
|
60
89
|
private expectedSize;
|
|
61
90
|
private dead;
|
|
62
91
|
private closing;
|
|
92
|
+
private inboundHandler;
|
|
93
|
+
private activeInboundRequests;
|
|
63
94
|
constructor(options?: RSlintOptions);
|
|
64
95
|
/**
|
|
65
96
|
* Keep the Node event loop alive only while a request is in flight. The
|
|
@@ -72,10 +103,14 @@ export declare class NodeRslintService implements RslintServiceInterface {
|
|
|
72
103
|
* them to Readable/Writable, so narrow via `instanceof Socket` to reach those.
|
|
73
104
|
*/
|
|
74
105
|
private setLoopActive;
|
|
106
|
+
private updateLoopActivity;
|
|
107
|
+
/** Install the handler for positive-id requests sent by the Go peer. */
|
|
108
|
+
setInboundHandler(handler: InboundRequestHandler | null): void;
|
|
75
109
|
/**
|
|
76
110
|
* Send a message to the rslint process
|
|
77
111
|
*/
|
|
78
112
|
sendMessage(kind: string, data: any): Promise<any>;
|
|
113
|
+
private writeMessage;
|
|
79
114
|
/**
|
|
80
115
|
* Handle incoming binary data chunks
|
|
81
116
|
*/
|
|
@@ -102,9 +137,6 @@ export declare class NodeRslintService implements RslintServiceInterface {
|
|
|
102
137
|
terminate(): void;
|
|
103
138
|
}
|
|
104
139
|
|
|
105
|
-
/**
|
|
106
|
-
* Shared types for rslint IPC protocol across all environments
|
|
107
|
-
*/
|
|
108
140
|
declare interface Position {
|
|
109
141
|
line: number;
|
|
110
142
|
column: number;
|
|
@@ -122,6 +154,8 @@ declare interface RSlintOptions {
|
|
|
122
154
|
|
|
123
155
|
declare interface RslintServiceInterface {
|
|
124
156
|
sendMessage(kind: string, data: any): Promise<any>;
|
|
157
|
+
/** Optional for one-way backends such as the current browser worker. */
|
|
158
|
+
setInboundHandler?(handler: InboundRequestHandler | null): void;
|
|
125
159
|
terminate(): void;
|
|
126
160
|
}
|
|
127
161
|
|
package/dist/internal.js
CHANGED
|
@@ -12,12 +12,16 @@ class NodeRslintService {
|
|
|
12
12
|
expectedSize;
|
|
13
13
|
dead;
|
|
14
14
|
closing;
|
|
15
|
+
inboundHandler;
|
|
16
|
+
activeInboundRequests;
|
|
15
17
|
constructor(options = {}){
|
|
16
18
|
this.nextMessageId = 1;
|
|
17
19
|
this.pendingMessages = new Map();
|
|
18
20
|
this.rslintPath = options.rslintPath || resolveRslintBinary();
|
|
19
21
|
this.dead = false;
|
|
20
22
|
this.closing = false;
|
|
23
|
+
this.inboundHandler = null;
|
|
24
|
+
this.activeInboundRequests = 0;
|
|
21
25
|
this.process = spawn(this.rslintPath, [
|
|
22
26
|
'--api'
|
|
23
27
|
], {
|
|
@@ -58,6 +62,12 @@ class NodeRslintService {
|
|
|
58
62
|
])if (stream instanceof Socket) if (active) stream.ref();
|
|
59
63
|
else stream.unref();
|
|
60
64
|
}
|
|
65
|
+
updateLoopActivity() {
|
|
66
|
+
this.setLoopActive(!this.dead && (this.pendingMessages.size > 0 || this.activeInboundRequests > 0));
|
|
67
|
+
}
|
|
68
|
+
setInboundHandler(handler) {
|
|
69
|
+
this.inboundHandler = handler;
|
|
70
|
+
}
|
|
61
71
|
async sendMessage(kind, data) {
|
|
62
72
|
return new Promise((resolve, reject)=>{
|
|
63
73
|
if (this.dead) return void reject(new Error('rslint service is no longer running'));
|
|
@@ -72,17 +82,26 @@ class NodeRslintService {
|
|
|
72
82
|
resolve,
|
|
73
83
|
reject
|
|
74
84
|
});
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
]));
|
|
85
|
+
this.updateLoopActivity();
|
|
86
|
+
try {
|
|
87
|
+
this.writeMessage(message);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
this.pendingMessages.delete(id);
|
|
90
|
+
this.updateLoopActivity();
|
|
91
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
92
|
+
}
|
|
84
93
|
});
|
|
85
94
|
}
|
|
95
|
+
writeMessage(message) {
|
|
96
|
+
if (this.dead) return;
|
|
97
|
+
const jsonBuffer = Buffer.from(JSON.stringify(message), 'utf8');
|
|
98
|
+
const length = Buffer.alloc(4);
|
|
99
|
+
length.writeUInt32LE(jsonBuffer.length, 0);
|
|
100
|
+
this.process.stdin.write(Buffer.concat([
|
|
101
|
+
length,
|
|
102
|
+
jsonBuffer
|
|
103
|
+
]));
|
|
104
|
+
}
|
|
86
105
|
handleChunk(chunk) {
|
|
87
106
|
this.chunks.push(chunk);
|
|
88
107
|
this.chunkSize += chunk.length;
|
|
@@ -114,22 +133,63 @@ class NodeRslintService {
|
|
|
114
133
|
}
|
|
115
134
|
handleMessage(message) {
|
|
116
135
|
const { id, kind, data } = message;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
136
|
+
if ('response' === kind || 'error' === kind) {
|
|
137
|
+
const pending = this.pendingMessages.get(id);
|
|
138
|
+
if (!pending) return;
|
|
139
|
+
this.pendingMessages.delete(id);
|
|
140
|
+
if ('error' === kind) pending.reject(new Error(data?.message ?? 'rslint request failed'));
|
|
141
|
+
else pending.resolve(data);
|
|
142
|
+
this.updateLoopActivity();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (id <= 0) return;
|
|
146
|
+
this.activeInboundRequests++;
|
|
147
|
+
this.updateLoopActivity();
|
|
148
|
+
Promise.resolve().then(async ()=>{
|
|
149
|
+
if (!this.inboundHandler) throw new Error(`no inbound handler registered (kind=${message.kind})`);
|
|
150
|
+
return this.inboundHandler(message);
|
|
151
|
+
}).then((result)=>{
|
|
152
|
+
try {
|
|
153
|
+
this.writeMessage({
|
|
154
|
+
id,
|
|
155
|
+
kind: 'response',
|
|
156
|
+
data: result
|
|
157
|
+
});
|
|
158
|
+
} catch (error) {
|
|
159
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
160
|
+
this.writeMessage({
|
|
161
|
+
id,
|
|
162
|
+
kind: 'error',
|
|
163
|
+
data: {
|
|
164
|
+
message: `failed to encode inbound response: ${detail}`
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}, (error)=>{
|
|
169
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
170
|
+
this.writeMessage({
|
|
171
|
+
id,
|
|
172
|
+
kind: 'error',
|
|
173
|
+
data: {
|
|
174
|
+
message: detail
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}).finally(()=>{
|
|
178
|
+
this.activeInboundRequests--;
|
|
179
|
+
this.updateLoopActivity();
|
|
180
|
+
}).catch(()=>{});
|
|
123
181
|
}
|
|
124
182
|
rejectAllPending(err) {
|
|
125
183
|
if (0 === this.pendingMessages.size) return;
|
|
126
184
|
for (const [, pending] of this.pendingMessages)pending.reject(err);
|
|
127
185
|
this.pendingMessages.clear();
|
|
186
|
+
this.updateLoopActivity();
|
|
128
187
|
}
|
|
129
188
|
resolveAllPending() {
|
|
130
189
|
if (0 === this.pendingMessages.size) return;
|
|
131
190
|
for (const [, pending] of this.pendingMessages)pending.resolve(null);
|
|
132
191
|
this.pendingMessages.clear();
|
|
192
|
+
this.updateLoopActivity();
|
|
133
193
|
}
|
|
134
194
|
terminate() {
|
|
135
195
|
this.dead = true;
|
|
@@ -144,8 +204,10 @@ async function lint(options) {
|
|
|
144
204
|
const service = new RSLintService(new NodeRslintService({
|
|
145
205
|
workingDirectory: options.workingDirectory
|
|
146
206
|
}));
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
207
|
+
try {
|
|
208
|
+
return await service.lint(options);
|
|
209
|
+
} finally{
|
|
210
|
+
await service.close();
|
|
211
|
+
}
|
|
150
212
|
}
|
|
151
213
|
export { NodeRslintService, lint };
|
package/dist/service.d.ts
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
/** Go's final effective-ID selection after ignore/ownership resolution. */
|
|
2
|
+
declare interface ActivateConfigsRequest {
|
|
3
|
+
protocolVersion: typeof CONFIG_DISCOVERY_PROTOCOL_VERSION;
|
|
4
|
+
transactionId: string;
|
|
5
|
+
effectiveConfigIds: string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Logical protocol shared by the native CLI, programmatic API, and LSP config
|
|
10
|
+
* discovery adapters. The transports differ (framed IPC versus JSON-RPC), but
|
|
11
|
+
* every adapter sends these payloads to the same Node-side module host.
|
|
12
|
+
*
|
|
13
|
+
* Paths in requests identify values selected by Go. Node may native-normalize
|
|
14
|
+
* configPath for local I/O, but configDirectory is an opaque routing identity
|
|
15
|
+
* and must retain its exact spelling. Load responses correlate only by opaque
|
|
16
|
+
* candidate ID. Activation responses contain only the transaction identity and
|
|
17
|
+
* plugin metadata consumed by Go; Node-only preparation data never crosses the
|
|
18
|
+
* transport boundary.
|
|
19
|
+
*/
|
|
20
|
+
declare const CONFIG_DISCOVERY_PROTOCOL_VERSION: 1;
|
|
21
|
+
|
|
22
|
+
declare interface ConfigModuleCandidate {
|
|
23
|
+
/** Opaque, transaction-local identity allocated by the Go coordinator. */
|
|
24
|
+
id: string;
|
|
25
|
+
/** Absolute path to the JS/TS config module Node must execute. */
|
|
26
|
+
configPath: string;
|
|
27
|
+
/** Go-authoritative directory used for config matching and plugin routing. */
|
|
28
|
+
configDirectory: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare type ConfigModuleLoadMode = 'cached' | 'fresh';
|
|
32
|
+
|
|
1
33
|
export declare interface Diagnostic {
|
|
2
34
|
ruleName: string;
|
|
3
35
|
message: string;
|
|
@@ -82,6 +114,9 @@ export declare interface GetAstInfoResponse {
|
|
|
82
114
|
flow?: FlowInfo;
|
|
83
115
|
}
|
|
84
116
|
|
|
117
|
+
/** Handler for a positive-id request frame sent by the Go peer. */
|
|
118
|
+
export declare type InboundRequestHandler = (message: IpcMessage) => unknown;
|
|
119
|
+
|
|
85
120
|
/**
|
|
86
121
|
* Index signature information
|
|
87
122
|
*/
|
|
@@ -97,10 +132,37 @@ export declare interface IpcMessage {
|
|
|
97
132
|
data: any;
|
|
98
133
|
}
|
|
99
134
|
|
|
135
|
+
/** Reverse-request handlers that are scoped to one outer lint request. */
|
|
136
|
+
export declare interface LintInboundHandlers {
|
|
137
|
+
pluginLint?: (request: unknown) => unknown;
|
|
138
|
+
loadConfigs?: (request: LoadConfigsRequest) => unknown;
|
|
139
|
+
activateConfigs?: (request: ActivateConfigsRequest) => unknown;
|
|
140
|
+
}
|
|
141
|
+
|
|
100
142
|
export declare interface LintOptions {
|
|
101
143
|
files?: string[];
|
|
144
|
+
canonicalFiles?: string[];
|
|
102
145
|
config?: Record<string, unknown>[];
|
|
146
|
+
/**
|
|
147
|
+
* Ask native Go to discover and route JS/TS configs for this lint request.
|
|
148
|
+
* `config` and `configDiscovery` are mutually exclusive. Browser/WASM
|
|
149
|
+
* backends intentionally do not advertise this host-filesystem capability.
|
|
150
|
+
*/
|
|
151
|
+
configDiscovery?: {
|
|
152
|
+
explicitConfigPath?: string;
|
|
153
|
+
/** Static glob roots; Go visits only branches leading to the supplied files. */
|
|
154
|
+
directories?: string[];
|
|
155
|
+
/** Parallel to `files`; true only for caller-literal file targets. */
|
|
156
|
+
explicitFiles?: boolean[];
|
|
157
|
+
/** Normalized API override entries appended to every selected config. */
|
|
158
|
+
overrideConfig?: Record<string, unknown>[];
|
|
159
|
+
};
|
|
160
|
+
eslintPlugins?: Array<{
|
|
161
|
+
prefix: string;
|
|
162
|
+
ruleNames: string[];
|
|
163
|
+
}>;
|
|
103
164
|
configDirectory?: string;
|
|
165
|
+
pluginConfigDirectory?: string;
|
|
104
166
|
workingDirectory?: string;
|
|
105
167
|
fileContents?: Record<string, string>;
|
|
106
168
|
includeEncodedSourceFiles?: boolean;
|
|
@@ -120,6 +182,21 @@ export declare interface LintResponse {
|
|
|
120
182
|
encodedSourceFiles?: Record<string, string>;
|
|
121
183
|
}
|
|
122
184
|
|
|
185
|
+
declare interface LoadConfigsRequest {
|
|
186
|
+
protocolVersion: typeof CONFIG_DISCOVERY_PROTOCOL_VERSION;
|
|
187
|
+
/** Isolates batches belonging to one discovery transaction. */
|
|
188
|
+
transactionId: string;
|
|
189
|
+
/**
|
|
190
|
+
* `cached` preserves one-shot CLI module-import semantics. `fresh` is used
|
|
191
|
+
* by long-lived API and editor refreshes; it cache-busts the entry module,
|
|
192
|
+
* while static transitive imports retain Node's normal module cache.
|
|
193
|
+
*/
|
|
194
|
+
loadMode: ConfigModuleLoadMode;
|
|
195
|
+
/** Serialize module evaluation when the CLI requested --singleThreaded. */
|
|
196
|
+
singleThreaded?: boolean;
|
|
197
|
+
candidates: ConfigModuleCandidate[];
|
|
198
|
+
}
|
|
199
|
+
|
|
123
200
|
/**
|
|
124
201
|
* Detailed information about an AST node
|
|
125
202
|
*/
|
|
@@ -224,9 +301,6 @@ export declare interface PendingMessage {
|
|
|
224
301
|
reject: (error: Error) => void;
|
|
225
302
|
}
|
|
226
303
|
|
|
227
|
-
/**
|
|
228
|
-
* Shared types for rslint IPC protocol across all environments
|
|
229
|
-
*/
|
|
230
304
|
declare interface Position {
|
|
231
305
|
line: number;
|
|
232
306
|
column: number;
|
|
@@ -249,24 +323,35 @@ export declare interface RSlintOptions {
|
|
|
249
323
|
*/
|
|
250
324
|
export declare class RSLintService {
|
|
251
325
|
private readonly service;
|
|
326
|
+
private activeLintHandlers;
|
|
327
|
+
private requestQueue;
|
|
328
|
+
private closeRequested;
|
|
329
|
+
private closePromise;
|
|
252
330
|
constructor(service: RslintServiceInterface);
|
|
253
331
|
/**
|
|
254
332
|
* Run the linter on specified files
|
|
255
333
|
*/
|
|
256
|
-
lint(options?: LintOptions): Promise<LintResponse>;
|
|
334
|
+
lint(options?: LintOptions, handlers?: LintInboundHandlers): Promise<LintResponse>;
|
|
335
|
+
private lintExclusive;
|
|
257
336
|
/**
|
|
258
337
|
* Get detailed AST information at a specific position
|
|
259
338
|
* Returns Node, Type, Symbol, Signature, and Flow information
|
|
260
339
|
*/
|
|
261
340
|
getAstInfo(options: GetAstInfoRequest): Promise<GetAstInfoResponse>;
|
|
341
|
+
private getAstInfoExclusive;
|
|
262
342
|
/**
|
|
263
343
|
* Close the service
|
|
264
344
|
*/
|
|
265
345
|
close(): Promise<void>;
|
|
346
|
+
private handshake;
|
|
347
|
+
private enqueue;
|
|
348
|
+
private handleInboundRequest;
|
|
266
349
|
}
|
|
267
350
|
|
|
268
351
|
export declare interface RslintServiceInterface {
|
|
269
352
|
sendMessage(kind: string, data: any): Promise<any>;
|
|
353
|
+
/** Optional for one-way backends such as the current browser worker. */
|
|
354
|
+
setInboundHandler?(handler: InboundRequestHandler | null): void;
|
|
270
355
|
terminate(): void;
|
|
271
356
|
}
|
|
272
357
|
|
package/dist/service.js
CHANGED
|
@@ -1,17 +1,45 @@
|
|
|
1
|
+
const API_REVERSE_PLUGIN_LINT_CAPABILITY = 'reversePluginLint';
|
|
2
|
+
const API_REVERSE_CONFIG_LOAD_CAPABILITY = 'reverseConfigLoadV1';
|
|
3
|
+
const EXIT_REQUEST_TIMEOUT_MS = 1000;
|
|
1
4
|
class RSLintService {
|
|
2
5
|
service;
|
|
6
|
+
activeLintHandlers = null;
|
|
7
|
+
requestQueue = Promise.resolve();
|
|
8
|
+
closeRequested = false;
|
|
9
|
+
closePromise = null;
|
|
3
10
|
constructor(service){
|
|
4
11
|
this.service = service;
|
|
12
|
+
this.service.setInboundHandler?.((message)=>this.handleInboundRequest(message));
|
|
5
13
|
}
|
|
6
|
-
async lint(options = {}) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
async lint(options = {}, handlers = {}) {
|
|
15
|
+
if (this.closeRequested) throw new Error('rslint service is closing');
|
|
16
|
+
return this.enqueue(async ()=>{
|
|
17
|
+
const hasLoadConfigs = Boolean(handlers.loadConfigs);
|
|
18
|
+
const hasActivateConfigs = Boolean(handlers.activateConfigs);
|
|
19
|
+
if (hasLoadConfigs !== hasActivateConfigs) throw new Error('reverse config discovery requires loadConfigs and activateConfigs handlers together');
|
|
20
|
+
if ((handlers.pluginLint || hasLoadConfigs || hasActivateConfigs) && !this.service.setInboundHandler) throw new Error('rslint backend does not support reverse lint requests');
|
|
21
|
+
this.activeLintHandlers = handlers;
|
|
22
|
+
try {
|
|
23
|
+
return await this.lintExclusive(options, {
|
|
24
|
+
pluginLint: Boolean(handlers.pluginLint),
|
|
25
|
+
configLoad: hasLoadConfigs && hasActivateConfigs
|
|
26
|
+
});
|
|
27
|
+
} finally{
|
|
28
|
+
this.activeLintHandlers = null;
|
|
29
|
+
}
|
|
10
30
|
});
|
|
31
|
+
}
|
|
32
|
+
async lintExclusive(options, requiredReverse) {
|
|
33
|
+
const { files, canonicalFiles, config, configDiscovery, eslintPlugins, configDirectory, pluginConfigDirectory, workingDirectory, fileContents, includeEncodedSourceFiles, fix } = options;
|
|
34
|
+
await this.handshake(requiredReverse);
|
|
11
35
|
return this.service.sendMessage('lint', {
|
|
12
36
|
files,
|
|
37
|
+
canonicalFiles,
|
|
13
38
|
config,
|
|
39
|
+
configDiscovery,
|
|
40
|
+
eslintPlugins,
|
|
14
41
|
configDirectory,
|
|
42
|
+
pluginConfigDirectory,
|
|
15
43
|
workingDirectory,
|
|
16
44
|
fileContents,
|
|
17
45
|
includeEncodedSourceFiles,
|
|
@@ -19,9 +47,17 @@ class RSLintService {
|
|
|
19
47
|
});
|
|
20
48
|
}
|
|
21
49
|
async getAstInfo(options) {
|
|
50
|
+
if (this.closeRequested) throw new Error('rslint service is closing');
|
|
51
|
+
return this.enqueue(async ()=>{
|
|
52
|
+
const response = await this.getAstInfoExclusive(options);
|
|
53
|
+
return response;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async getAstInfoExclusive(options) {
|
|
22
57
|
const { fileContent, position, end, kind, depth = 2, fileName, compilerOptions } = options;
|
|
23
|
-
await this.
|
|
24
|
-
|
|
58
|
+
await this.handshake({
|
|
59
|
+
pluginLint: false,
|
|
60
|
+
configLoad: false
|
|
25
61
|
});
|
|
26
62
|
return this.service.sendMessage('getAstInfo', {
|
|
27
63
|
fileContent,
|
|
@@ -34,10 +70,80 @@ class RSLintService {
|
|
|
34
70
|
});
|
|
35
71
|
}
|
|
36
72
|
async close() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
73
|
+
if (this.closePromise) return void await this.closePromise;
|
|
74
|
+
this.closeRequested = true;
|
|
75
|
+
let timedOut = false;
|
|
76
|
+
let timer;
|
|
77
|
+
const timeout = new Promise((resolve)=>{
|
|
78
|
+
timer = setTimeout(()=>{
|
|
79
|
+
timedOut = true;
|
|
80
|
+
resolve();
|
|
81
|
+
}, EXIT_REQUEST_TIMEOUT_MS);
|
|
82
|
+
});
|
|
83
|
+
const gracefulExit = this.enqueue(async ()=>{
|
|
84
|
+
if (timedOut) return;
|
|
85
|
+
try {
|
|
86
|
+
await this.service.sendMessage('exit', {});
|
|
87
|
+
} catch {}
|
|
88
|
+
});
|
|
89
|
+
this.closePromise = (async ()=>{
|
|
90
|
+
try {
|
|
91
|
+
await Promise.race([
|
|
92
|
+
gracefulExit,
|
|
93
|
+
timeout
|
|
94
|
+
]);
|
|
95
|
+
} finally{
|
|
96
|
+
timedOut = true;
|
|
97
|
+
if (timer) clearTimeout(timer);
|
|
98
|
+
this.service.terminate();
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
101
|
+
await this.closePromise;
|
|
102
|
+
}
|
|
103
|
+
async handshake(requiredReverse) {
|
|
104
|
+
const requestedCapabilities = [];
|
|
105
|
+
if (requiredReverse.pluginLint) requestedCapabilities.push(API_REVERSE_PLUGIN_LINT_CAPABILITY);
|
|
106
|
+
if (requiredReverse.configLoad) requestedCapabilities.push(API_REVERSE_CONFIG_LOAD_CAPABILITY);
|
|
107
|
+
const response = await this.service.sendMessage('handshake', {
|
|
108
|
+
version: "2.0.0",
|
|
109
|
+
capabilities: requestedCapabilities
|
|
110
|
+
});
|
|
111
|
+
if (null === response || 'object' != typeof response) throw new Error('rslint backend returned an invalid handshake response');
|
|
112
|
+
const handshake = response;
|
|
113
|
+
if (true !== handshake.ok || "2.0.0" !== handshake.version) throw new Error(`rslint API protocol mismatch: expected 2.0.0, received ${String(handshake.version)}`);
|
|
114
|
+
const capabilities = Array.isArray(handshake.capabilities) ? handshake.capabilities : [];
|
|
115
|
+
if (requiredReverse.pluginLint && !capabilities.includes(API_REVERSE_PLUGIN_LINT_CAPABILITY)) throw new Error('rslint backend does not support reverse pluginLint requests');
|
|
116
|
+
if (requiredReverse.configLoad && !capabilities.includes(API_REVERSE_CONFIG_LOAD_CAPABILITY)) throw new Error('rslint backend does not support reverse config loading');
|
|
117
|
+
}
|
|
118
|
+
async enqueue(operation) {
|
|
119
|
+
const result = this.requestQueue.then(operation, operation);
|
|
120
|
+
this.requestQueue = result.then(()=>void 0, ()=>void 0);
|
|
121
|
+
const value = await result;
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
handleInboundRequest(message) {
|
|
125
|
+
switch(message.kind){
|
|
126
|
+
case 'pluginLint':
|
|
127
|
+
{
|
|
128
|
+
const handler = this.activeLintHandlers?.pluginLint;
|
|
129
|
+
if (!handler) throw new Error('rslint service received pluginLint without an active plugin host');
|
|
130
|
+
return handler(message.data);
|
|
131
|
+
}
|
|
132
|
+
case 'loadConfigs':
|
|
133
|
+
{
|
|
134
|
+
const handler = this.activeLintHandlers?.loadConfigs;
|
|
135
|
+
if (!handler) throw new Error('rslint service received loadConfigs without an active config host');
|
|
136
|
+
return handler(message.data);
|
|
137
|
+
}
|
|
138
|
+
case 'activateConfigs':
|
|
139
|
+
{
|
|
140
|
+
const handler = this.activeLintHandlers?.activateConfigs;
|
|
141
|
+
if (!handler) throw new Error('rslint service received activateConfigs without an active config host');
|
|
142
|
+
return handler(message.data);
|
|
143
|
+
}
|
|
144
|
+
default:
|
|
145
|
+
throw new Error(`rslint service received unexpected inbound request '${message.kind}'`);
|
|
146
|
+
}
|
|
41
147
|
}
|
|
42
148
|
}
|
|
43
149
|
export { RSLintService };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rslint/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": {
|
|
6
6
|
"@typescript/source": "./src/index.ts",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"globals": "17.7.0",
|
|
65
65
|
"tinyglobby": "0.2.15",
|
|
66
66
|
"typescript": "5.9.3",
|
|
67
|
-
"@rslint/api": "0.
|
|
67
|
+
"@rslint/api": "0.7.1"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"jiti": "^2.0.0"
|
|
@@ -75,14 +75,14 @@
|
|
|
75
75
|
}
|
|
76
76
|
},
|
|
77
77
|
"optionalDependencies": {
|
|
78
|
-
"@rslint/native-darwin-
|
|
79
|
-
"@rslint/native-linux-arm64-gnu": "0.
|
|
80
|
-
"@rslint/native-
|
|
81
|
-
"@rslint/native-
|
|
82
|
-
"@rslint/native-
|
|
83
|
-
"@rslint/native-linux-x64-musl": "0.
|
|
84
|
-
"@rslint/native-
|
|
85
|
-
"@rslint/native-win32-x64-msvc": "0.
|
|
78
|
+
"@rslint/native-darwin-x64": "0.7.1",
|
|
79
|
+
"@rslint/native-linux-arm64-gnu": "0.7.1",
|
|
80
|
+
"@rslint/native-linux-x64-gnu": "0.7.1",
|
|
81
|
+
"@rslint/native-darwin-arm64": "0.7.1",
|
|
82
|
+
"@rslint/native-win32-arm64-msvc": "0.7.1",
|
|
83
|
+
"@rslint/native-linux-x64-musl": "0.7.1",
|
|
84
|
+
"@rslint/native-linux-arm64-musl": "0.7.1",
|
|
85
|
+
"@rslint/native-win32-x64-msvc": "0.7.1"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
88
|
"picomatch": "4.0.4"
|