Implement global workspace pull
This commit is contained in:
Родитель
25f9d089dd
Коммит
301224db3c
|
@ -1,5 +1,9 @@
|
|||
{
|
||||
"extends": "../.eslintrc.base.json",
|
||||
"parserOptions": {
|
||||
"project": ["src/browser/tsconfig.json", "src/common/tsconfig.json", "src/node/tsconfig.json"]
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-floating-promises": "error"
|
||||
}
|
||||
}
|
|
@ -294,7 +294,7 @@ class DefaultErrorHandler implements ErrorHandler {
|
|||
} else {
|
||||
let diff = this.restarts[this.restarts.length - 1] - this.restarts[0];
|
||||
if (diff <= 3 * 60 * 1000) {
|
||||
Window.showErrorMessage(`The ${this.name} server crashed ${this.maxRestartCount+1} times in the last 3 minutes. The server will not be restarted.`);
|
||||
void Window.showErrorMessage(`The ${this.name} server crashed ${this.maxRestartCount+1} times in the last 3 minutes. The server will not be restarted.`);
|
||||
return CloseAction.DoNotRestart;
|
||||
} else {
|
||||
this.restarts.shift();
|
||||
|
@ -1105,13 +1105,13 @@ class DidChangeTextDocumentFeature implements DidChangeTextDocumentFeatureShape
|
|||
this.forceDelivery();
|
||||
this._changeDelayer.uri = event.document.uri.toString();
|
||||
}
|
||||
this._changeDelayer.delayer.trigger(() => doSend(event));
|
||||
void this._changeDelayer.delayer.trigger(() => doSend(event));
|
||||
} else {
|
||||
this._changeDelayer = {
|
||||
uri: event.document.uri.toString(),
|
||||
delayer: new Delayer<void>(200)
|
||||
};
|
||||
this._changeDelayer.delayer.trigger(() => doSend(event), -1);
|
||||
void this._changeDelayer.delayer.trigger(() => doSend(event), -1);
|
||||
}
|
||||
};
|
||||
if (middleware.didChange) {
|
||||
|
@ -2992,7 +2992,7 @@ export abstract class BaseLanguageClient {
|
|||
sendNotification: false,
|
||||
traceFormat: this._traceFormat
|
||||
});
|
||||
});
|
||||
}, () => this.info(`Setting trace value failed`, undefined, false));
|
||||
}, () => {
|
||||
});
|
||||
}
|
||||
|
@ -3045,7 +3045,7 @@ export abstract class BaseLanguageClient {
|
|||
}
|
||||
|
||||
private showNotificationMessage() {
|
||||
Window.showInformationMessage('A request has failed. See the output for more information.', 'Go to output').then(() => {
|
||||
void Window.showInformationMessage('A request has failed. See the output for more information.', 'Go to output').then(() => {
|
||||
this.outputChannel.show(true);
|
||||
});
|
||||
}
|
||||
|
@ -3119,16 +3119,16 @@ export abstract class BaseLanguageClient {
|
|||
connection.onShowMessage((message) => {
|
||||
switch (message.type) {
|
||||
case MessageType.Error:
|
||||
Window.showErrorMessage(message.message);
|
||||
void Window.showErrorMessage(message.message);
|
||||
break;
|
||||
case MessageType.Warning:
|
||||
Window.showWarningMessage(message.message);
|
||||
void Window.showWarningMessage(message.message);
|
||||
break;
|
||||
case MessageType.Info:
|
||||
Window.showInformationMessage(message.message);
|
||||
void Window.showInformationMessage(message.message);
|
||||
break;
|
||||
default:
|
||||
Window.showInformationMessage(message.message);
|
||||
void Window.showInformationMessage(message.message);
|
||||
}
|
||||
});
|
||||
connection.onRequest(ShowMessageRequest.type, (params) => {
|
||||
|
@ -3190,11 +3190,13 @@ export abstract class BaseLanguageClient {
|
|||
this.state = ClientState.StartFailed;
|
||||
this._onReadyCallbacks.reject(error);
|
||||
this.error('Starting client failed', error);
|
||||
Window.showErrorMessage(`Couldn't start client ${this._name}`);
|
||||
void Window.showErrorMessage(`Couldn't start client ${this._name}`);
|
||||
});
|
||||
return new Disposable(() => {
|
||||
if (this.needsStop()) {
|
||||
this.stop();
|
||||
this.stop().then(undefined, (error) => {
|
||||
this.error(`Stopping server failed.`, error, false);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3290,26 +3292,26 @@ export abstract class BaseLanguageClient {
|
|||
}).then<InitializeResult>(undefined, (error: any) => {
|
||||
if (this._clientOptions.initializationFailedHandler) {
|
||||
if (this._clientOptions.initializationFailedHandler(error)) {
|
||||
this.initialize(connection);
|
||||
void this.initialize(connection);
|
||||
} else {
|
||||
this.stop();
|
||||
void this.stop();
|
||||
this._onReadyCallbacks.reject(error);
|
||||
}
|
||||
} else if (error instanceof ResponseError && error.data && error.data.retry) {
|
||||
Window.showErrorMessage(error.message, { title: 'Retry', id: 'retry' }).then(item => {
|
||||
void Window.showErrorMessage(error.message, { title: 'Retry', id: 'retry' }).then(item => {
|
||||
if (item && item.id === 'retry') {
|
||||
this.initialize(connection);
|
||||
void this.initialize(connection);
|
||||
} else {
|
||||
this.stop();
|
||||
void this.stop();
|
||||
this._onReadyCallbacks.reject(error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (error && error.message) {
|
||||
Window.showErrorMessage(error.message);
|
||||
void Window.showErrorMessage(error.message);
|
||||
}
|
||||
this.error('Server initialization failed.', error);
|
||||
this.stop();
|
||||
void this.stop();
|
||||
this._onReadyCallbacks.reject(error);
|
||||
}
|
||||
throw error;
|
||||
|
@ -3389,9 +3391,9 @@ export abstract class BaseLanguageClient {
|
|||
const client = this;
|
||||
function didChangeWatchedFile(this: void, event: FileEvent) {
|
||||
client._fileEvents.push(event);
|
||||
client._fileEventDelayer.trigger(() => {
|
||||
void client._fileEventDelayer.trigger(() => {
|
||||
client.onReady().then(() => {
|
||||
client.resolveConnection().then(connection => {
|
||||
void client.resolveConnection().then(connection => {
|
||||
if (client.isConnectionActive()) {
|
||||
client.forceDocumentSync();
|
||||
connection.didChangeWatchedFiles({ changes: client._fileEvents });
|
||||
|
@ -3497,7 +3499,9 @@ export abstract class BaseLanguageClient {
|
|||
let action = this._clientOptions.errorHandler!.error(error, message, count);
|
||||
if (action === ErrorAction.Shutdown) {
|
||||
this.error('Connection to server is erroring. Shutting down server.');
|
||||
this.stop();
|
||||
this.stop().then(undefined, (error) => {
|
||||
this.error(`Stopping server failed`, error, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ export class ProgressPart {
|
|||
|
||||
private begin(params: WorkDoneProgressBegin): void {
|
||||
// Since we don't use commands this will be a silent window progress with a hidden notification.
|
||||
Window.withProgress<void>({ location: ProgressLocation.Window, cancellable: params.cancellable, title: params.title}, async (progress, cancellationToken) => {
|
||||
void Window.withProgress<void>({ location: ProgressLocation.Window, cancellable: params.cancellable, title: params.title}, async (progress, cancellationToken) => {
|
||||
this._progress = progress;
|
||||
this._infinite = params.percentage === undefined;
|
||||
this._cancellationToken = cancellationToken;
|
||||
|
|
|
@ -13,9 +13,11 @@ import {
|
|||
DidSaveTextDocumentNotification, DidCloseTextDocumentNotification, LinkedMap, Touch, RAL
|
||||
} from 'vscode-languageserver-protocol';
|
||||
|
||||
import { generateUuid } from './utils/uuid';
|
||||
import {
|
||||
TextDocumentFeature, BaseLanguageClient, Middleware, LSPCancellationError, DiagnosticPullMode
|
||||
} from './client';
|
||||
import { PreviousResultId, WorkspaceDocumentDiagnosticReport } from 'vscode-languageserver-protocol/src/common/proposed.diagnostic';
|
||||
|
||||
function ensure<T, K extends keyof T>(target: T, key: K): T[K] {
|
||||
if (target[key] === void 0) {
|
||||
|
@ -87,7 +89,7 @@ namespace vscode {
|
|||
export interface DiagnosticProvider {
|
||||
onDidChangeDiagnostics: VEvent<void>;
|
||||
provideDiagnostics(textDocument: TextDocument, previousResultId: string | undefined, token: CancellationToken): ProviderResult<DocumentDiagnosticReport>;
|
||||
provideWorkspaceDiagnostics?(resultIds: PreviousResultId[], token: CancellationToken, resultReporter: ResultReporter): Promise<void>
|
||||
provideWorkspaceDiagnostics?(resultIds: PreviousResultId[], token: CancellationToken, resultReporter: ResultReporter): ProviderResult<WorkspaceDiagnosticReport>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,8 +97,13 @@ export interface ProvideDiagnosticSignature {
|
|||
(this: void, textDocument: TextDocument, previousResultId: string | undefined, token: CancellationToken): ProviderResult<vscode.DocumentDiagnosticReport>;
|
||||
}
|
||||
|
||||
export interface ProvideWorkspaceDiagnosticSignature {
|
||||
(this: void, resultIds: vscode.PreviousResultId[], token: CancellationToken, resultReporter: vscode.ResultReporter): ProviderResult<vscode.WorkspaceDiagnosticReport>;
|
||||
}
|
||||
|
||||
export interface DiagnosticProviderMiddleware {
|
||||
provideDiagnostics?: (this: void, document: TextDocument, previousResultId: string | undefined, token: CancellationToken, next: ProvideDiagnosticSignature) => ProviderResult<vscode.DocumentDiagnosticReport>;
|
||||
provideWorkspaceDiagnostics?: (this: void, resultIds: vscode.PreviousResultId[], token: CancellationToken, resultReporter: vscode.ResultReporter, next: ProvideWorkspaceDiagnosticSignature) => ProviderResult<vscode.WorkspaceDiagnosticReport>;
|
||||
}
|
||||
|
||||
enum RequestStateKind {
|
||||
|
@ -154,24 +161,32 @@ interface DocumentPullState {
|
|||
resultId: string | undefined;
|
||||
}
|
||||
|
||||
enum PullState {
|
||||
document = 1,
|
||||
workspace = 2
|
||||
}
|
||||
|
||||
class DocumentPullStateTracker {
|
||||
|
||||
private readonly states: Map<string, DocumentPullState>;
|
||||
private readonly documentPullStates: Map<string, DocumentPullState>;
|
||||
private readonly workspacePullStates: Map<string, DocumentPullState>;
|
||||
|
||||
constructor() {
|
||||
this.states = new Map();
|
||||
this.documentPullStates = new Map();
|
||||
this.workspacePullStates = new Map();
|
||||
}
|
||||
|
||||
public track(textDocument: TextDocument, resultId?: string): DocumentPullState;
|
||||
public track(uri: string, version?: number, resultId?: string): DocumentPullState;
|
||||
public track(document: TextDocument | string, arg1?: string | number, arg2?: string): DocumentPullState {
|
||||
public track(kind: PullState, textDocument: TextDocument, resultId?: string): DocumentPullState;
|
||||
public track(kind: PullState, uri: string, version?: number, resultId?: string): DocumentPullState;
|
||||
public track(kind: PullState, document: TextDocument | string, arg1?: string | number, arg2?: string): DocumentPullState {
|
||||
const states = kind === PullState.document ? this.documentPullStates : this.workspacePullStates;
|
||||
const [key, uri, version, resultId] = typeof document === 'string'
|
||||
? [document, Uri.parse(document), arg1 as number, arg2]
|
||||
: [document.uri.toString(), document.uri, document.version, arg1 as string];
|
||||
let state = this.states.get(key);
|
||||
let state = states.get(key);
|
||||
if (state === undefined) {
|
||||
state = { document: uri, pulledVersion: version, resultId };
|
||||
this.states.set(key, state);
|
||||
states.set(key, state);
|
||||
} else {
|
||||
state.pulledVersion = version;
|
||||
state.resultId = resultId;
|
||||
|
@ -179,24 +194,30 @@ class DocumentPullStateTracker {
|
|||
return state;
|
||||
}
|
||||
|
||||
public unTrack(textDocument: TextDocument): void {
|
||||
this.states.delete(textDocument.uri.toString());
|
||||
public unTrack(kind: PullState, textDocument: TextDocument): void {
|
||||
const states = kind === PullState.document ? this.documentPullStates : this.workspacePullStates;
|
||||
states.delete(textDocument.uri.toString());
|
||||
}
|
||||
|
||||
public tracks(textDocument: TextDocument): boolean;
|
||||
public tracks(uri: string): boolean;
|
||||
public tracks(document: TextDocument | string): boolean {
|
||||
public tracks(kind: PullState, textDocument: TextDocument): boolean;
|
||||
public tracks(kind: PullState, uri: string): boolean;
|
||||
public tracks(kind: PullState, document: TextDocument | string): boolean {
|
||||
const key = typeof document === 'string' ? document : document.uri.toString();
|
||||
return this.states.has(key);
|
||||
const states = kind === PullState.document ? this.documentPullStates : this.workspacePullStates;
|
||||
return states.has(key);
|
||||
}
|
||||
|
||||
public getResultId(textDocument: TextDocument): string | undefined {
|
||||
return this.states.get(textDocument.uri.toString())?.resultId;
|
||||
public getResultId(kind: PullState, textDocument: TextDocument): string | undefined {
|
||||
const states = kind === PullState.document ? this.documentPullStates : this.workspacePullStates;
|
||||
return states.get(textDocument.uri.toString())?.resultId;
|
||||
}
|
||||
|
||||
public getAllResultIds(): Proposed.PreviousResultId[] {
|
||||
const result: Proposed.PreviousResultId[] = [];
|
||||
for (const [uri, value] of this.states) {
|
||||
for (let [uri, value] of this.workspacePullStates) {
|
||||
if (this.documentPullStates.has(uri)) {
|
||||
value = this.documentPullStates.get(uri)!;
|
||||
}
|
||||
if (value.resultId !== undefined) {
|
||||
result.push({ uri, value: value.resultId });
|
||||
}
|
||||
|
@ -205,8 +226,9 @@ class DocumentPullStateTracker {
|
|||
}
|
||||
}
|
||||
|
||||
class DiagnosticRequestor {
|
||||
class DiagnosticRequestor implements Disposable {
|
||||
|
||||
private isDisposed: boolean;
|
||||
private readonly client: BaseLanguageClient;
|
||||
private readonly editorTracker: EditorTracker;
|
||||
private readonly options: Proposed.DiagnosticRegistrationOptions;
|
||||
|
@ -217,33 +239,50 @@ class DiagnosticRequestor {
|
|||
private readonly openRequests: Map<string, RequestState>;
|
||||
private readonly documentStates: DocumentPullStateTracker;
|
||||
|
||||
private workspaceErrorCounter: number;
|
||||
private workspaceCancellation: CancellationTokenSource | undefined;
|
||||
private workspaceTimeout: Disposable | undefined;
|
||||
|
||||
public constructor(client: BaseLanguageClient, editorTracker: EditorTracker, options: Proposed.DiagnosticRegistrationOptions) {
|
||||
this.client = client;
|
||||
this.editorTracker = editorTracker;
|
||||
this.options = options;
|
||||
|
||||
this.isDisposed = false;
|
||||
this.onDidChangeDiagnosticsEmitter = new EventEmitter<void>();
|
||||
this.provider = this.createProvider();
|
||||
|
||||
this.diagnostics = Languages.createDiagnosticCollection(options.identifier);
|
||||
this.openRequests = new Map();
|
||||
this.documentStates = new DocumentPullStateTracker();
|
||||
this.workspaceErrorCounter = 0;
|
||||
}
|
||||
|
||||
public knows(textDocument: TextDocument): boolean {
|
||||
return this.documentStates.tracks(textDocument);
|
||||
public knows(kind: PullState, textDocument: TextDocument): boolean {
|
||||
return this.documentStates.tracks(kind, textDocument);
|
||||
}
|
||||
|
||||
public async pull(textDocument: TextDocument): Promise<void> {
|
||||
public pull(textDocument: TextDocument, cb?: () => void): void {
|
||||
this.pullAsync(textDocument).then(() => {
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
}, (error) => {
|
||||
this.client.error(`Document pull failed for text document ${textDocument.uri.toString()}`, error, false);
|
||||
});
|
||||
}
|
||||
|
||||
private async pullAsync(textDocument: TextDocument): Promise<void> {
|
||||
const key = textDocument.uri.toString();
|
||||
const currentRequestState = this.openRequests.get(key);
|
||||
const documentState = this.documentStates.track(textDocument);
|
||||
const documentState = this.documentStates.track(PullState.document, textDocument);
|
||||
if (currentRequestState === undefined) {
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
this.openRequests.set(key, { state: RequestStateKind.active, version: textDocument.version, textDocument, tokenSource });
|
||||
let report: vscode.DocumentDiagnosticReport | undefined;
|
||||
let afterState: RequestState | undefined;
|
||||
try {
|
||||
report = await this.provider.provideDiagnostics(textDocument, this.documentStates.getResultId(textDocument), tokenSource.token) ?? { kind: vscode.DocumentDiagnosticReportKind.full, items: [] };
|
||||
report = await this.provider.provideDiagnostics(textDocument, this.documentStates.getResultId(PullState.document, textDocument), tokenSource.token) ?? { kind: vscode.DocumentDiagnosticReportKind.full, items: [] };
|
||||
} catch (error) {
|
||||
if (error instanceof LSPCancellationError && Proposed.DiagnosticServerCancellationData.is(error.data) && error.data.retriggerRequest === false) {
|
||||
afterState = { state: RequestStateKind.outDated, textDocument };
|
||||
|
@ -263,7 +302,7 @@ class DiagnosticRequestor {
|
|||
}
|
||||
this.openRequests.delete(key);
|
||||
if (!this.editorTracker.isVisible(textDocument)) {
|
||||
this.documentStates.unTrack(textDocument);
|
||||
this.documentStates.unTrack(PullState.document, textDocument);
|
||||
return;
|
||||
}
|
||||
if (afterState.state === RequestStateKind.outDated) {
|
||||
|
@ -310,8 +349,54 @@ class DiagnosticRequestor {
|
|||
}
|
||||
}
|
||||
|
||||
pullWorkspace(): void {
|
||||
public pullWorkspace(): void {
|
||||
this.pullWorkspaceAsync().then(() => {
|
||||
this.workspaceTimeout = RAL().timer.setTimeout(() => {
|
||||
this.pullWorkspace();
|
||||
}, 2000);
|
||||
}, (error) => {
|
||||
if (!(error instanceof LSPCancellationError) && !Proposed.DiagnosticServerCancellationData.is(error.data)) {
|
||||
this.client.error(`Workspace diagnostic pull failed.`, error, false);
|
||||
this.workspaceErrorCounter++;
|
||||
}
|
||||
if (this.workspaceErrorCounter <= 5) {
|
||||
this.workspaceTimeout = RAL().timer.setTimeout(() => {
|
||||
this.pullWorkspace();
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async pullWorkspaceAsync(): Promise<void> {
|
||||
if (!this.provider.provideWorkspaceDiagnostics) {
|
||||
return;
|
||||
}
|
||||
if (this.workspaceCancellation !== undefined) {
|
||||
this.workspaceCancellation.cancel();
|
||||
this.workspaceCancellation = undefined;
|
||||
}
|
||||
this.workspaceCancellation = new CancellationTokenSource();
|
||||
const previousResultIds: vscode.PreviousResultId[] = this.documentStates.getAllResultIds().map((item) => {
|
||||
return {
|
||||
uri: this.client.protocol2CodeConverter.asUri(item.uri),
|
||||
value: item.value
|
||||
};
|
||||
});
|
||||
await this.provider.provideWorkspaceDiagnostics(previousResultIds, this.workspaceCancellation.token, (chunk) => {
|
||||
if (!chunk || this.isDisposed) {
|
||||
return;
|
||||
}
|
||||
for (const item of chunk.items) {
|
||||
if (item.kind === vscode.DocumentDiagnosticReportKind.full) {
|
||||
// Favour document pull result over workspace results. So skip if it is tracked
|
||||
// as a document result.
|
||||
if (!this.documentStates.tracks(PullState.document, item.uri.toString())) {
|
||||
this.diagnostics.set(item.uri, item.items);
|
||||
}
|
||||
}
|
||||
this.documentStates.track(PullState.workspace, item.uri.toString(), item.version ?? undefined, item.resultId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private createProvider(): vscode.DiagnosticProvider {
|
||||
|
@ -320,11 +405,12 @@ class DiagnosticRequestor {
|
|||
provideDiagnostics: (textDocument, previousResultId, token) => {
|
||||
const provideDiagnostics: ProvideDiagnosticSignature = (textDocument, previousResultId, token) => {
|
||||
const params: Proposed.DocumentDiagnosticParams = {
|
||||
identifier: this.options.identifier,
|
||||
textDocument: { uri: this.client.code2ProtocolConverter.asUri(textDocument.uri) },
|
||||
previousResultId: previousResultId
|
||||
};
|
||||
return this.client.sendRequest(Proposed.DocumentDiagnosticRequest.type, params, token).then((result) => {
|
||||
if (result === undefined || result === null) {
|
||||
if (result === undefined || result === null || this.isDisposed) {
|
||||
return { kind: vscode.DocumentDiagnosticReportKind.full, items: [] };
|
||||
}
|
||||
if (result.kind === Proposed.DocumentDiagnosticReportKind.full) {
|
||||
|
@ -343,9 +429,91 @@ class DiagnosticRequestor {
|
|||
}
|
||||
};
|
||||
if (this.options.workspaceDiagnostics) {
|
||||
result.provideWorkspaceDiagnostics = (resultIds, token, resultReporter): ProviderResult<vscode.WorkspaceDiagnosticReport> => {
|
||||
const convertReport = (report: WorkspaceDocumentDiagnosticReport): vscode.WorkspaceDocumentDiagnosticReport => {
|
||||
if (report.kind === Proposed.DocumentDiagnosticReportKind.full) {
|
||||
return {
|
||||
kind: vscode.DocumentDiagnosticReportKind.full,
|
||||
uri: this.client.protocol2CodeConverter.asUri(report.uri),
|
||||
resultId: report.resultId,
|
||||
version: report.version,
|
||||
items: this.client.protocol2CodeConverter.asDiagnostics(report.items)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
kind: vscode.DocumentDiagnosticReportKind.unChanged,
|
||||
uri: this.client.protocol2CodeConverter.asUri(report.uri),
|
||||
resultId: report.resultId,
|
||||
version: report.version
|
||||
};
|
||||
}
|
||||
};
|
||||
const convertPreviousResultIds = (resultIds: vscode.PreviousResultId[]): PreviousResultId[] => {
|
||||
const converted: PreviousResultId[] = [];
|
||||
for (const item of resultIds) {
|
||||
converted.push({ uri: this.client.code2ProtocolConverter.asUri(item.uri), value: item.value});
|
||||
}
|
||||
return converted;
|
||||
};
|
||||
const provideDiagnostics: ProvideWorkspaceDiagnosticSignature = (resultIds, token): ProviderResult<vscode.WorkspaceDiagnosticReport> => {
|
||||
const partialResultToken: string = generateUuid();
|
||||
const disposable = this.client.onProgress(Proposed.WorkspaceDiagnosticRequest.partialResult, partialResultToken, (partialResult) => {
|
||||
if (partialResult === undefined || partialResult === null) {
|
||||
resultReporter(null);
|
||||
return;
|
||||
}
|
||||
const converted: vscode.WorkspaceDiagnosticReportPartialResult = {
|
||||
items: []
|
||||
};
|
||||
for (const item of partialResult.items) {
|
||||
converted.items.push(convertReport(item));
|
||||
}
|
||||
resultReporter(converted);
|
||||
});
|
||||
const params: Proposed.WorkspaceDiagnosticParams = {
|
||||
identifier: this.options.identifier,
|
||||
previousResultIds: convertPreviousResultIds(resultIds),
|
||||
partialResultToken: partialResultToken
|
||||
};
|
||||
return this.client.sendRequest(Proposed.WorkspaceDiagnosticRequest.type, params, token).then((result): vscode.WorkspaceDiagnosticReport => {
|
||||
const converted: vscode.WorkspaceDiagnosticReport = {
|
||||
items: []
|
||||
};
|
||||
for (const item of result.items) {
|
||||
converted.items.push(convertReport(item));
|
||||
}
|
||||
disposable.dispose();
|
||||
resultReporter(converted);
|
||||
return { items: [] };
|
||||
}, (error) => {
|
||||
disposable.dispose();
|
||||
return this.client.handleFailedRequest(Proposed.DocumentDiagnosticRequest.type, token, error, { items: [] });
|
||||
});
|
||||
};
|
||||
const middleware: Middleware & DiagnosticProviderMiddleware = this.client.clientOptions.middleware!;
|
||||
return middleware.provideWorkspaceDiagnostics
|
||||
? middleware.provideWorkspaceDiagnostics(resultIds, token, resultReporter, provideDiagnostics)
|
||||
: provideDiagnostics(resultIds, token, resultReporter);
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.isDisposed = true;
|
||||
|
||||
// Cancel and clear workspace pull if present.
|
||||
this.workspaceCancellation?.cancel();
|
||||
this.workspaceTimeout?.dispose();
|
||||
|
||||
// Cancel all request and mark open requests as outdated.
|
||||
for (const [key, request] of this.openRequests) {
|
||||
if (request.state === RequestStateKind.active) {
|
||||
request.tokenSource.cancel();
|
||||
}
|
||||
this.openRequests.set(key, { state: RequestStateKind.outDated, textDocument: request.textDocument });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface DiagnosticFeatureProvider {
|
||||
|
@ -353,7 +521,7 @@ export interface DiagnosticFeatureProvider {
|
|||
provider: vscode.DiagnosticProvider;
|
||||
}
|
||||
|
||||
class BackgroundScheduler {
|
||||
class BackgroundScheduler implements Disposable {
|
||||
|
||||
private readonly diagnosticRequestor: DiagnosticRequestor;
|
||||
private endDocument: TextDocument | undefined;
|
||||
|
@ -410,6 +578,11 @@ class BackgroundScheduler {
|
|||
}, 200);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.stop();
|
||||
this.documents.clear();
|
||||
}
|
||||
|
||||
private stop(): void {
|
||||
this.intervalHandle?.dispose();
|
||||
this.intervalHandle = undefined;
|
||||
|
@ -460,18 +633,14 @@ class DiagnosticFeatureProviderImpl implements DiagnosticFeatureProvider {
|
|||
disposables.push(openFeature.onNotificationSent((event) => {
|
||||
const textDocument = event.original;
|
||||
if (matches(textDocument)) {
|
||||
this.diagnosticRequestor.pull(textDocument).then(() => {
|
||||
addToBackgroundIfNeeded(textDocument);
|
||||
});
|
||||
this.diagnosticRequestor.pull(textDocument, () => { addToBackgroundIfNeeded(textDocument); });
|
||||
}
|
||||
}));
|
||||
|
||||
// Pull all diagnostics for documents that are already open
|
||||
for (const textDocument of Workspace.textDocuments) {
|
||||
if (matches(textDocument)) {
|
||||
this.diagnosticRequestor.pull(textDocument).then(() => {
|
||||
addToBackgroundIfNeeded(textDocument);
|
||||
});
|
||||
this.diagnosticRequestor.pull(textDocument, () => { addToBackgroundIfNeeded(textDocument); });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,10 +648,8 @@ class DiagnosticFeatureProviderImpl implements DiagnosticFeatureProvider {
|
|||
const changeFeature = client.getFeature(DidChangeTextDocumentNotification.method);
|
||||
disposables.push(changeFeature.onNotificationSent(async (event) => {
|
||||
const textDocument = event.original.document;
|
||||
if ((diagnosticPullOptions.filter === undefined || !diagnosticPullOptions.filter(textDocument, DiagnosticPullMode.onType)) && this.diagnosticRequestor.knows(textDocument) && event.original.contentChanges.length > 0) {
|
||||
this.diagnosticRequestor.pull(textDocument).then(() => {
|
||||
this.backgroundScheduler.trigger();
|
||||
});
|
||||
if ((diagnosticPullOptions.filter === undefined || !diagnosticPullOptions.filter(textDocument, DiagnosticPullMode.onType)) && this.diagnosticRequestor.knows(PullState.document, textDocument) && event.original.contentChanges.length > 0) {
|
||||
this.diagnosticRequestor.pull(textDocument, () => { this.backgroundScheduler.trigger(); });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -491,10 +658,8 @@ class DiagnosticFeatureProviderImpl implements DiagnosticFeatureProvider {
|
|||
const saveFeature = client.getFeature(DidSaveTextDocumentNotification.method);
|
||||
disposables.push(saveFeature.onNotificationSent((event) => {
|
||||
const textDocument = event.original;
|
||||
if ((diagnosticPullOptions.filter === undefined || !diagnosticPullOptions.filter(textDocument, DiagnosticPullMode.onSave)) && this.diagnosticRequestor.knows(textDocument)) {
|
||||
this.diagnosticRequestor.pull(event.original).then(() => {
|
||||
this.backgroundScheduler.trigger();
|
||||
});
|
||||
if ((diagnosticPullOptions.filter === undefined || !diagnosticPullOptions.filter(textDocument, DiagnosticPullMode.onSave)) && this.diagnosticRequestor.knows(PullState.document, textDocument)) {
|
||||
this.diagnosticRequestor.pull(event.original, () => { this.backgroundScheduler.trigger(); });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -516,7 +681,11 @@ class DiagnosticFeatureProviderImpl implements DiagnosticFeatureProvider {
|
|||
}
|
||||
});
|
||||
|
||||
this.disposable = Disposable.from(...disposables);
|
||||
if (options.workspaceDiagnostics === true) {
|
||||
this.diagnosticRequestor.pullWorkspace();
|
||||
}
|
||||
|
||||
this.disposable = Disposable.from(...disposables, this.backgroundScheduler, this.diagnosticRequestor);
|
||||
}
|
||||
|
||||
public get onDidChangeDiagnosticsEmitter(): EventEmitter<void> {
|
||||
|
@ -526,6 +695,8 @@ class DiagnosticFeatureProviderImpl implements DiagnosticFeatureProvider {
|
|||
public get provider(): vscode.DiagnosticProvider {
|
||||
return this.diagnosticRequestor.provider;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export class DiagnosticFeature extends TextDocumentFeature<Proposed.DiagnosticOptions, Proposed.DiagnosticRegistrationOptions, DiagnosticFeatureProvider> {
|
||||
|
@ -540,6 +711,10 @@ export class DiagnosticFeature extends TextDocumentFeature<Proposed.DiagnosticOp
|
|||
public fillClientCapabilities(capabilities: ClientCapabilities & Proposed.$DiagnosticClientCapabilities): void {
|
||||
let capability = ensure(ensure(capabilities, 'textDocument')!, 'diagnostic')!;
|
||||
capability.dynamicRegistration = true;
|
||||
// We first need to decide how a UI will look with related documents.
|
||||
// An easy implementation would be to only show related diagnostics for
|
||||
// the active editor.
|
||||
capability.relatedDocumentSupport = false;
|
||||
}
|
||||
|
||||
public initialize(capabilities: ServerCapabilities & Proposed.$DiagnosticServerCapabilities, documentSelector: DocumentSelector): void {
|
||||
|
|
|
@ -373,7 +373,7 @@ export class LanguageClient extends CommonLanguageClient {
|
|||
}
|
||||
} else {
|
||||
let pipeName: string | undefined = undefined;
|
||||
return new Promise<MessageTransports>((resolve, _reject) => {
|
||||
return new Promise<MessageTransports>((resolve, reject) => {
|
||||
let args = node.args && node.args.slice() || [];
|
||||
if (transport === TransportKind.ipc) {
|
||||
args.push('--node-ipc');
|
||||
|
@ -411,8 +411,8 @@ export class LanguageClient extends CommonLanguageClient {
|
|||
sp.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
|
||||
transport.onConnected().then((protocol) => {
|
||||
resolve({ reader: protocol[0], writer: protocol[1] });
|
||||
});
|
||||
});
|
||||
}, reject);
|
||||
}, reject);
|
||||
} else if (Transport.isSocket(transport)) {
|
||||
createClientSocketTransport(transport.port).then((transport) => {
|
||||
let sp = cp.fork(node.module, args || [], options);
|
||||
|
@ -422,8 +422,8 @@ export class LanguageClient extends CommonLanguageClient {
|
|||
sp.stdout.on('data', data => this.outputChannel.append(Is.string(data) ? data : data.toString(encoding)));
|
||||
transport.onConnected().then((protocol) => {
|
||||
resolve({ reader: protocol[0], writer: protocol[1] });
|
||||
});
|
||||
});
|
||||
}, reject);
|
||||
}, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ export class SettingMonitor {
|
|||
this.onDidChangeConfiguration();
|
||||
return new Disposable(() => {
|
||||
if (this._client.needsStop()) {
|
||||
this._client.stop();
|
||||
void this._client.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -542,7 +542,7 @@ export class SettingMonitor {
|
|||
if (enabled && this._client.needsStart()) {
|
||||
this._client.start();
|
||||
} else if (!enabled && this._client.needsStop()) {
|
||||
this._client.stop();
|
||||
void this._client.stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
{
|
||||
"extends": "../.eslintrc.base.json",
|
||||
"parserOptions": {
|
||||
"project": ["src/browser/tsconfig.json", "src/common/tsconfig.json", "src/node/tsconfig.json"]
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "error"
|
||||
"no-console": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error"
|
||||
}
|
||||
}
|
|
@ -87,5 +87,6 @@ export namespace Proposed {
|
|||
export type WorkspaceDocumentDiagnosticReport = diag.WorkspaceDocumentDiagnosticReport;
|
||||
export type WorkspaceDiagnosticReport = diag.WorkspaceDiagnosticReport;
|
||||
export type WorkspaceDiagnosticReportPartialResult = diag.WorkspaceDiagnosticReportPartialResult;
|
||||
export const WorkspaceDiagnosticRequest: typeof diag.WorkspaceDiagnosticRequest = diag.WorkspaceDiagnosticRequest;
|
||||
export const DiagnosticRefreshRequest: typeof diag.DiagnosticRefreshRequest = diag.DiagnosticRefreshRequest;
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import { RequestHandler0, RequestHandler } from 'vscode-jsonrpc';
|
||||
import { RequestHandler0, RequestHandler, ProgressType } from 'vscode-jsonrpc';
|
||||
import { TextDocumentIdentifier, Diagnostic, DocumentUri, integer } from 'vscode-languageserver-types';
|
||||
|
||||
import * as Is from './utils/is';
|
||||
|
@ -23,6 +23,11 @@ export interface DiagnosticClientCapabilities {
|
|||
* return value for the corresponding server capability as well.
|
||||
*/
|
||||
dynamicRegistration?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the clients supports related documents for document diagnostic pulls.
|
||||
*/
|
||||
relatedDocumentSupport?: boolean;
|
||||
}
|
||||
|
||||
export interface $DiagnosticClientCapabilities {
|
||||
|
@ -245,6 +250,7 @@ export interface DocumentDiagnosticReportPartialResult {
|
|||
export namespace DocumentDiagnosticRequest {
|
||||
export const method: 'textDocument/diagnostic' = 'textDocument/diagnostic';
|
||||
export const type = new ProtocolRequestType<DocumentDiagnosticParams, DocumentDiagnosticReport, DocumentDiagnosticReportPartialResult, DiagnosticServerCancellationData, DiagnosticRegistrationOptions>(method);
|
||||
export const partialResult = new ProgressType<DocumentDiagnosticReportPartialResult>();
|
||||
export type HandlerSignature = RequestHandler<DocumentDiagnosticParams, DocumentDiagnosticReport, void>;
|
||||
}
|
||||
|
||||
|
@ -356,6 +362,7 @@ export interface WorkspaceDiagnosticReportPartialResult {
|
|||
export namespace WorkspaceDiagnosticRequest {
|
||||
export const method: 'workspace/diagnostic' = 'workspace/diagnostic';
|
||||
export const type = new ProtocolRequestType<WorkspaceDiagnosticParams, WorkspaceDiagnosticReport, WorkspaceDiagnosticReportPartialResult, DiagnosticServerCancellationData, void>(method);
|
||||
export const partialResult = new ProgressType<WorkspaceDiagnosticReportPartialResult>();
|
||||
export type HandlerSignature = RequestHandler<WorkspaceDiagnosticParams, WorkspaceDiagnosticReport | null, void>;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ export interface DiagnosticClientCapabilities {
|
|||
* return value for the corresponding server capability as well.
|
||||
*/
|
||||
dynamicRegistration?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the clients supports related documents for document diagnostic pulls.
|
||||
*/
|
||||
relatedDocumentSupport?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -21,11 +21,18 @@ export interface DiagnosticsFeatureShape {
|
|||
refresh(): void;
|
||||
|
||||
/**
|
||||
* Installs a handler for the diagnostic request.
|
||||
* Installs a handler for the document diagnostic request.
|
||||
*
|
||||
* @param handler The corresponding handler.
|
||||
*/
|
||||
on(handler: ServerRequestHandler<Proposed.DocumentDiagnosticParams, Proposed.DocumentDiagnosticReport, Proposed.DocumentDiagnosticReportPartialResult, Proposed.DiagnosticServerCancellationData>): void;
|
||||
|
||||
/**
|
||||
* Installs a handler for the workspace diagnostic request.
|
||||
*
|
||||
* @param handler The corresponding handler.
|
||||
*/
|
||||
onWorkspace(handler: ServerRequestHandler<Proposed.WorkspaceDiagnosticParams, Proposed.WorkspaceDiagnosticReport, Proposed.WorkspaceDiagnosticReportPartialResult, Proposed.DiagnosticServerCancellationData>): void;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +45,12 @@ export const DiagnosticFeature: Feature<_Languages, DiagnosticsFeatureShape> = (
|
|||
},
|
||||
on: (handler: ServerRequestHandler<Proposed.DocumentDiagnosticParams, Proposed.DocumentDiagnosticReport, Proposed.DocumentDiagnosticReportPartialResult, Proposed.DiagnosticServerCancellationData>): void => {
|
||||
this.connection.onRequest(Proposed.DocumentDiagnosticRequest.type, (params, cancel) => {
|
||||
return handler(params, cancel, this.attachWorkDoneProgress(params), undefined);
|
||||
return handler(params, cancel, this.attachWorkDoneProgress(params), this.attachPartialResultProgress(Proposed.DocumentDiagnosticRequest.partialResult, params));
|
||||
});
|
||||
},
|
||||
onWorkspace: (handler: ServerRequestHandler<Proposed.WorkspaceDiagnosticParams, Proposed.WorkspaceDiagnosticReport, Proposed.WorkspaceDiagnosticReportPartialResult, Proposed.DiagnosticServerCancellationData>): void => {
|
||||
this.connection.onRequest(Proposed.WorkspaceDiagnosticRequest.type, (params, cancel) => {
|
||||
return handler(params, cancel, this.attachWorkDoneProgress(params), this.attachPartialResultProgress(Proposed.WorkspaceDiagnosticRequest.partialResult, params));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,12 +4,9 @@
|
|||
* ------------------------------------------------------------------------------------------ */
|
||||
'use strict';
|
||||
|
||||
import { promisify } from 'util';
|
||||
import * as fs from 'fs';
|
||||
|
||||
namespace pfs {
|
||||
export const readFile = promisify(fs.readFile);
|
||||
}
|
||||
import * as path from 'path';
|
||||
import * as _fs from 'fs';
|
||||
const fs = _fs.promises;
|
||||
|
||||
import { URI } from 'vscode-uri';
|
||||
|
||||
|
@ -20,7 +17,8 @@ import {
|
|||
SignatureHelp, SymbolInformation, SymbolKind, TextDocumentEdit, TextDocuments, TextDocumentSyncKind,
|
||||
TextEdit, VersionedTextDocumentIdentifier, ProposedFeatures, DiagnosticTag, Proposed, InsertTextFormat,
|
||||
SelectionRangeRequest, SelectionRange, InsertReplaceEdit, SemanticTokensClientCapabilities, SemanticTokensLegend,
|
||||
SemanticTokensBuilder, SemanticTokensRegistrationType, SemanticTokensRegistrationOptions, ProtocolNotificationType, ChangeAnnotation, AnnotatedTextEdit, WorkspaceChange,
|
||||
SemanticTokensBuilder, SemanticTokensRegistrationType, SemanticTokensRegistrationOptions, ProtocolNotificationType, ChangeAnnotation, AnnotatedTextEdit,
|
||||
WorkspaceChange,
|
||||
CompletionItemKind, DiagnosticSeverity
|
||||
} from 'vscode-languageserver/node';
|
||||
|
||||
|
@ -168,7 +166,7 @@ connection.onInitialize((params, cancel, progress): Thenable<InitializeResult> |
|
|||
diagnosticProvider: {
|
||||
identifier: 'testbed',
|
||||
interFileDependencies: true,
|
||||
workspaceDiagnostics: false
|
||||
workspaceDiagnostics: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -295,17 +293,7 @@ const patterns = [
|
|||
/\b[A-Z]{5,}\b/g
|
||||
];
|
||||
|
||||
connection.languages.diagnostics.on(async (param) => {
|
||||
const uri = URI.parse(param.textDocument.uri);
|
||||
const document = documents.get(param.textDocument.uri);
|
||||
const content = document !== undefined
|
||||
? document.getText()
|
||||
: uri.scheme === 'file'
|
||||
? await pfs.readFile(uri.fsPath, { encoding: 'utf8'} )
|
||||
: undefined;
|
||||
if (content === undefined) {
|
||||
return { kind: Proposed.DocumentDiagnosticReportKind.full, items: [] };
|
||||
}
|
||||
function computeDiagnostics(content: string): Diagnostic[] {
|
||||
const result: Diagnostic[] = [];
|
||||
const lines: string[] = content.match(/^.*(\n|\r\n|\r|$)/gm);
|
||||
let lineNumber: number = 0;
|
||||
|
@ -319,7 +307,56 @@ connection.languages.diagnostics.on(async (param) => {
|
|||
}
|
||||
lineNumber++;
|
||||
}
|
||||
return { kind: Proposed.DocumentDiagnosticReportKind.full, items: result };
|
||||
return result;
|
||||
}
|
||||
|
||||
connection.languages.diagnostics.on(async (param) => {
|
||||
const uri = URI.parse(param.textDocument.uri);
|
||||
const document = documents.get(param.textDocument.uri);
|
||||
const content = document !== undefined
|
||||
? document.getText()
|
||||
: uri.scheme === 'file'
|
||||
? await fs.readFile(uri.fsPath, { encoding: 'utf8'} )
|
||||
: undefined;
|
||||
if (content === undefined) {
|
||||
return { kind: Proposed.DocumentDiagnosticReportKind.full, items: [] };
|
||||
}
|
||||
return { kind: Proposed.DocumentDiagnosticReportKind.full, items: computeDiagnostics(content) };
|
||||
});
|
||||
|
||||
connection.languages.diagnostics.onWorkspace(async (params, token, _, resultProgress): Promise<Proposed.WorkspaceDiagnosticReport> => {
|
||||
const fsPath = URI.parse(folder).fsPath;
|
||||
|
||||
const toValidate: string[] = [];
|
||||
for (const child of await fs.readdir(fsPath)) {
|
||||
if (path.extname(child) === '.bat') {
|
||||
toValidate.push(path.join(fsPath, child));
|
||||
}
|
||||
}
|
||||
|
||||
if (toValidate.length === 0) {
|
||||
return { items: [] };
|
||||
}
|
||||
|
||||
const doValidate = async (index: number) => {
|
||||
if (index >= toValidate.length) {
|
||||
index = 0;
|
||||
}
|
||||
const diagnostics = computeDiagnostics(await fs.readFile(toValidate[index], { encoding: 'utf8'} ));
|
||||
resultProgress.report({ items: [
|
||||
{
|
||||
kind: Proposed.DocumentDiagnosticReportKind.full,
|
||||
uri: URI.file(toValidate[index]).toString(),
|
||||
version: null,
|
||||
items: diagnostics
|
||||
}
|
||||
]});
|
||||
setTimeout(() => { doValidate(++index); }, 500);
|
||||
};
|
||||
doValidate(0);
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, 120000);
|
||||
});
|
||||
});
|
||||
|
||||
connection.onCompletion((params, token): CompletionItem[] => {
|
||||
|
|
|
@ -7,4 +7,4 @@ REM .txt extension from . c:\source to c:\textkkk
|
|||
REM %%f is a variable
|
||||
FOR %%f IN (*.jpg *.png *.bmp) DO XCOPY C:\source\"%%f" c:\images /m /y
|
||||
REM This moves any files with a .jpg, .png,
|
||||
REM or .bmp extension from c:\source to c:\images;;
|
||||
REM or .bmp extension from c:\source to c:\images;;
|
|
@ -0,0 +1,10 @@
|
|||
REM @ECHO OFF
|
||||
cd c:\source
|
||||
REM This is the location of the files that you want to sort
|
||||
FOR %%f IN (*.doc *.txt) DO XCOPY c:\source\"%%f" c:\text /m /y
|
||||
REM This moves any files with a .doc or
|
||||
REM .txt extension from . c:\source to c:\textkkk
|
||||
REM %%f is a variable
|
||||
FOR %%f IN (*.jpg *.png *.bmp) DO XCOPY C:\source\"%%f" c:\images /m /y
|
||||
REM This moves any files with a .jpg, .png,
|
||||
REM or .bmp extension from c:\source to c:\images;;
|
|
@ -0,0 +1,10 @@
|
|||
REM @ECHO OFF
|
||||
cd c:\source
|
||||
REM This is the location of the files that you want to sort
|
||||
FOR %%f IN (*.doc *.txt) DO XCOPY c:\source\"%%f" c:\text /m /y
|
||||
REM This moves any files with a .doc or
|
||||
REM .txt extension from . c:\source to c:\textkkk
|
||||
REM %%f is a variable
|
||||
FOR %%f IN (*.jpg *.png *.bmp) DO XCOPY C:\source\"%%f" c:\images /m /y
|
||||
REM This moves any files with a .jpg, .png,
|
||||
REM or .bmp extension from c:\source to c:\images;;
|
|
@ -1,6 +1,10 @@
|
|||
{
|
||||
"extends": "../.eslintrc.base.json",
|
||||
"parserOptions": {
|
||||
"project": ["src/tsconfig.json", "src/test/tsconfig.json"]
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "error"
|
||||
"no-console": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error"
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
{
|
||||
"extends": "../.eslintrc.base.json",
|
||||
"parserOptions": {
|
||||
"project": ["src/tsconfig.json", "src/test/tsconfig.json"]
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "error"
|
||||
"no-console": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error"
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче