diff --git a/.vscode/launch.json b/.vscode/launch.json index d5ba4d02042..f3c2bc0510f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,9 +12,9 @@ "outFiles": [ "${workspaceFolder}/packages/utils/parcelforvscode/out/**/*.js" ], - "preLaunchTask": "npm: compile - packages/utils/parcelforvscode", + "preLaunchTask": "npm: watch - packages/utils/parcelforvscode", "request": "launch", - "type": "pwa-extensionHost" + "type": "extensionHost" } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 83cd2c35672..e2b89c07a11 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,13 +2,19 @@ "version": "2.0.0", "tasks": [ { - "type": "npm", - "script": "compile", "path": "packages/utils/parcelforvscode/", - "group": "build", - "problemMatcher": [], - "label": "npm: compile - packages/utils/parcelforvscode", - "detail": "tsc -p ./" + "label": "npm: watch - packages/utils/parcelforvscode", + "type": "npm", + "script": "watch", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never" + }, + "group": { + "kind": "build", + "isDefault": true + } } ] } diff --git a/flow-libs/vscode-jsonrpc.js.flow b/flow-libs/vscode-jsonrpc.js.flow new file mode 100644 index 00000000000..ccfaa5f2403 --- /dev/null +++ b/flow-libs/vscode-jsonrpc.js.flow @@ -0,0 +1,336 @@ +// @flow +declare module 'vscode-jsonrpc/node' { + import type {Socket} from 'net'; + import type {Readable, Writable} from 'stream'; + + declare type MessageBufferEncoding = 'ascii' | 'utf-8'; + + declare type Logger = {| + error: (message: string) => void, + warn: (message: string) => void, + info: (message: string) => void, + log: (message: string) => void, + |}; + + declare type Disposable = {| + /** + * Dispose this object. + */ + dispose(): void, + |}; + + declare interface Event { + /** + * + * @param listener The listener function will be call when the event happens. + * @param thisArgs The 'this' which will be used when calling the event listener. + * @param disposables An array to which a {{IDisposable}} will be added. The + * @return + */ + ( + listener: (e: T) => any, + thisArgs?: any, + disposables?: Disposable[], + ): Disposable; + } + + declare type PartialMessageInfo = {| + +messageToken: number, + +waitingTime: number, + |}; + + declare type DataCallback = {| + (data: Message): void, + |}; + + declare interface Message { + jsonrpc: string; + } + + declare interface NotificationMessage extends Message { + /** + * The method to be invoked. + */ + method: string; + /** + * The notification's params. + */ + params?: [] | mixed; + } + + declare export class MessageReader { + /** Raised whenever an error occurs while reading a message. */ + +onError: Event; + /** An event raised when the end of the underlying transport has been reached. */ + +onClose: Event; + /** + * An event that *may* be raised to inform the owner that only part of a message has been received. + * A MessageReader implementation may choose to raise this event after a timeout elapses while waiting for more of a partially received message to be received. + */ + +onPartialMessage: Event; + /** + * Begins listening for incoming messages. To be called at most once. + * @param callback A callback for receiving decoded messages. + */ + listen(callback: DataCallback): Disposable; + /** Releases resources incurred from reading or raising events. Does NOT close the underlying transport, if any. */ + dispose(): void; + } + + declare export class MessageWriter { + /** Raised whenever an error occurs while writing a message. */ + +onError: Event<[Error, Message | void, number | void]>; + /** An event raised when the underlying transport has closed and writing is no longer possible. */ + +onClose: Event; + /** + * Sends a JSON-RPC message. + * @param msg The JSON-RPC message to be sent. + * @description Implementations should guarantee messages are transmitted in the same order that they are received by this method. + */ + write(msg: Message): Promise; + end(): void; + /** Releases resources incurred from writing or raising events. Does NOT close the underlying transport, if any. */ + dispose(): void; + } + + declare export function createServerPipeTransport( + pipeName: string, + encoding?: MessageBufferEncoding, + ): [MessageReader, MessageWriter]; + + declare export function createMessageConnection( + reader: MessageReader, + writer: MessageWriter, + logger?: Logger, + ): MessageConnection; + declare export function createMessageConnection( + inputStream: Readable, + outputStream: Writable, + logger?: Logger, + ): MessageConnection; + + declare interface CancellationToken { + /** + * Is `true` when the token has been cancelled, `false` otherwise. + */ + +isCancellationRequested: boolean; + /** + * An [event](#Event) which fires upon cancellation. + */ + +onCancellationRequested: Event; + } + + declare export class ParameterStructures { + /** + * The parameter structure is automatically inferred on the number of parameters + * and the parameter type in case of a single param. + */ + static +auto: ParameterStructures; + /** + * Forces `byPosition` parameter structure. This is useful if you have a single + * parameter which has a literal type. + */ + static +byPosition: ParameterStructures; + /** + * Forces `byName` parameter structure. This is only useful when having a single + * parameter. The library will report errors if used with a different number of + * parameters. + */ + static +byName: ParameterStructures; + static is(value: any): Boolean; + toString(): string; + } + + declare interface MessageSignature { + +method: string; + +numberOfParams: number; + +parameterStructures: ParameterStructures; + } + + declare class AbstractMessageSignature implements MessageSignature { + +method: string; + +numberOfParams: number; + constructor(method: string, numberOfParams: number): this; + get parameterStructures(): ParameterStructures; + } + + // prettier-ignore + declare export class RequestType0 extends AbstractMessageSignature { + constructor(method: string): this; + } + // prettier-ignore + declare export class RequestType extends AbstractMessageSignature { + constructor(method: string, _parameterStructures?: ParameterStructures): this; + get parameterStructures(): ParameterStructures; + } + // prettier-ignore + declare export class RequestType1 extends AbstractMessageSignature { + constructor(method: string, _parameterStructures?: ParameterStructures): this; + get parameterStructures(): ParameterStructures; + } + // prettier-ignore + declare export class RequestType2 extends AbstractMessageSignature { + constructor(method: string): this; + } + + // prettier-ignore + declare export class NotificationType

extends AbstractMessageSignature { + constructor(method: string, _parameterStructures?: ParameterStructures): this; + get parameterStructures(): ParameterStructures; + } + // prettier-ignore + declare export class NotificationType0 extends AbstractMessageSignature { + constructor(method: string): this; + } + // prettier-ignore + declare export class NotificationType1 extends AbstractMessageSignature { + constructor(method: string, _parameterStructures?: ParameterStructures): this; + get parameterStructures(): ParameterStructures; + } + // prettier-ignore + declare export class NotificationType2 extends AbstractMessageSignature { + constructor(method: string): this; + } + + declare interface ResponseErrorLiteral { + /** + * A number indicating the error type that occured. + */ + code: number; + /** + * A string providing a short decription of the error. + */ + message: string; + /** + * A Primitive or Structured value that contains additional + * information about the error. Can be omitted. + */ + data?: D; + } + declare class ResponseError extends Error { + +code: number; + +data: D | void; + constructor(code: number, message: string, data?: D): this; + toJson(): ResponseErrorLiteral; + } + + declare type HandlerResult = + | R + | ResponseError + | Promise + | Promise> + | Promise>; + + declare interface RequestHandler0 { + (token: CancellationToken): HandlerResult; + } + declare interface RequestHandler { + (params: P, token: CancellationToken): HandlerResult; + } + declare interface RequestHandler1 { + (p1: P1, token: CancellationToken): HandlerResult; + } + declare interface RequestHandler2 { + (p1: P1, p2: P2, token: CancellationToken): HandlerResult; + } + declare interface GenericRequestHandler { + (...params: any[]): HandlerResult; + } + // prettier-ignore + declare interface StarRequestHandler { + (method: string, params: any[] | mixed | void, token: CancellationToken): HandlerResult; + } + declare interface NotificationHandler0 { + (): void; + } + declare interface NotificationHandler

{ + (params: P): void; + } + declare interface NotificationHandler1 { + (p1: P1): void; + } + declare interface NotificationHandler2 { + (p1: P1, p2: P2): void; + } + declare interface StarNotificationHandler { + (method: string, params: any[] | mixed | void): void; + } + declare interface GenericNotificationHandler { + (...params: any[]): void; + } + + declare export class ProgressType { + /** + * Clients must not use these properties. They are here to ensure correct typing. + * in TypeScript + */ + constructor(): this; + } + + declare type ProgressToken = number | string; + declare interface ProgressParams { + /** + * The progress token provided by the client or server. + */ + token: ProgressToken; + /** + * The progress data. + */ + value: T; + } + + // prettier-ignore + declare export interface MessageConnection { + sendRequest(type: RequestType0, token?: CancellationToken): Promise; + sendRequest(type: RequestType, params: P, token?: CancellationToken): Promise; + sendRequest(type: RequestType1, p1: P1, token?: CancellationToken): Promise; + sendRequest(type: RequestType2, p1: P1, p2: P2, token?: CancellationToken): Promise; + sendRequest(method: string, r0?: ParameterStructures | any, ...rest: any[]): Promise; + onRequest(type: RequestType0, handler: RequestHandler0): Disposable; + onRequest(type: RequestType, handler: RequestHandler): Disposable; + onRequest(type: RequestType1, handler: RequestHandler1): Disposable; + onRequest(type: RequestType2, handler: RequestHandler2): Disposable; + onRequest(method: string, handler: GenericRequestHandler): Disposable; + onRequest(handler: StarRequestHandler): Disposable; + sendNotification(type: NotificationType0): void; + sendNotification

(type: NotificationType

, params?: P): void; + sendNotification(type: NotificationType1, p1: P1): void; + sendNotification(type: NotificationType2, p1: P1, p2: P2): void; + sendNotification(method: string, r0?: ParameterStructures | any, ...rest: any[]): void; + onNotification(type: NotificationType0, handler: NotificationHandler0): Disposable; + onNotification

(type: NotificationType

, handler: NotificationHandler

): Disposable; + onNotification(type: NotificationType1, handler: NotificationHandler1): Disposable; + onNotification(type: NotificationType2, handler: NotificationHandler2): Disposable; + onNotification(method: string, handler: GenericNotificationHandler): Disposable; + onNotification(handler: StarNotificationHandler): Disposable; + onUnhandledNotification: Event; + onProgress

(type: ProgressType

, token: string | number, handler: NotificationHandler

): Disposable; + sendProgress

(type: ProgressType

, token: string | number, value: P): void; + onUnhandledProgress: Event>; + // trace(value: Trace, tracer: Tracer, sendNotification?: boolean): void; + // trace(value: Trace, tracer: Tracer, traceOptions?: TraceOptions): void; + onError: Event<[Error, Message | void, number | void]>; + onClose: Event; + listen(): void; + end(): void; + onDispose: Event; + dispose(): void; + inspect(): void; + } + + declare export class SocketMessageReader + extends /* ReadableStream */ MessageReader + { + constructor(socket: Socket, encoding?: MessageBufferEncoding): this; + } + + declare export class SocketMessageWriter + extends /* WriteableStream */ MessageWriter + { + constructor( + socket: Socket, + options?: MessageBufferEncoding /* | MessageWriterOptions */, + ): this; + dispose(): void; + } +} diff --git a/flow-typed/npm/vscode-jsonrpc_vx.x.x.js b/flow-typed/npm/vscode-jsonrpc_vx.x.x.js deleted file mode 100644 index 21a29ccd4d3..00000000000 --- a/flow-typed/npm/vscode-jsonrpc_vx.x.x.js +++ /dev/null @@ -1,165 +0,0 @@ -// flow-typed signature: 27e995e11a57ab7a1e817bab4b4a5c57 -// flow-typed version: <>/vscode-jsonrpc_v6.0.0/flow_v0.146.0 - -/** - * This is an autogenerated libdef stub for: - * - * 'vscode-jsonrpc' - * - * Fill this stub out by replacing all the `any` types. - * - * Once filled out, we encourage you to share your work with the - * community by sending a pull request to: - * https://github.com/flowtype/flow-typed - */ - -declare module 'vscode-jsonrpc' { - declare module.exports: any; -} - -/** - * We include stubs for each file inside this npm package in case you need to - * require those files directly. Feel free to delete any files that aren't - * needed. - */ -declare module 'vscode-jsonrpc/browser' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/browser/main' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/browser/ril' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/api' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/cancellation' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/connection' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/disposable' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/encoding' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/events' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/is' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/linkedMap' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/messageBuffer' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/messageReader' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/messages' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/messageWriter' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/ral' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/common/semaphore' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/node/main' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/lib/node/ril' { - declare module.exports: any; -} - -declare module 'vscode-jsonrpc/node' { - declare module.exports: any; -} - -// Filename aliases -declare module 'vscode-jsonrpc/browser.js' { - declare module.exports: $Exports<'vscode-jsonrpc/browser'>; -} -declare module 'vscode-jsonrpc/lib/browser/main.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/browser/main'>; -} -declare module 'vscode-jsonrpc/lib/browser/ril.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/browser/ril'>; -} -declare module 'vscode-jsonrpc/lib/common/api.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/api'>; -} -declare module 'vscode-jsonrpc/lib/common/cancellation.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/cancellation'>; -} -declare module 'vscode-jsonrpc/lib/common/connection.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/connection'>; -} -declare module 'vscode-jsonrpc/lib/common/disposable.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/disposable'>; -} -declare module 'vscode-jsonrpc/lib/common/encoding.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/encoding'>; -} -declare module 'vscode-jsonrpc/lib/common/events.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/events'>; -} -declare module 'vscode-jsonrpc/lib/common/is.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/is'>; -} -declare module 'vscode-jsonrpc/lib/common/linkedMap.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/linkedMap'>; -} -declare module 'vscode-jsonrpc/lib/common/messageBuffer.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/messageBuffer'>; -} -declare module 'vscode-jsonrpc/lib/common/messageReader.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/messageReader'>; -} -declare module 'vscode-jsonrpc/lib/common/messages.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/messages'>; -} -declare module 'vscode-jsonrpc/lib/common/messageWriter.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/messageWriter'>; -} -declare module 'vscode-jsonrpc/lib/common/ral.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/ral'>; -} -declare module 'vscode-jsonrpc/lib/common/semaphore.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/common/semaphore'>; -} -declare module 'vscode-jsonrpc/lib/node/main.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/node/main'>; -} -declare module 'vscode-jsonrpc/lib/node/ril.js' { - declare module.exports: $Exports<'vscode-jsonrpc/lib/node/ril'>; -} -declare module 'vscode-jsonrpc/node.js' { - declare module.exports: $Exports<'vscode-jsonrpc/node'>; -} diff --git a/packages/examples/simple/src/bar.js b/packages/examples/simple/src/bar.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/examples/simple/src/foo.js b/packages/examples/simple/src/foo.js index 6b6158e5c6e..ebc1446015d 100644 --- a/packages/examples/simple/src/foo.js +++ b/packages/examples/simple/src/foo.js @@ -1,3 +1,9 @@ export default function () { return 'hello!'; } + +export function foo() { + return 123; +} + +export {bar} from './bar.js'; diff --git a/packages/examples/simple/src/index.js b/packages/examples/simple/src/index.js index 0ab19b5b636..2839fd2937a 100644 --- a/packages/examples/simple/src/index.js +++ b/packages/examples/simple/src/index.js @@ -1,3 +1,3 @@ import foo from './foo'; -console.log(foo()); +console.log(foo(122222222)); diff --git a/packages/reporters/lsp-reporter/package.json b/packages/reporters/lsp-reporter/package.json index ed986b3b606..00a659ef3cd 100644 --- a/packages/reporters/lsp-reporter/package.json +++ b/packages/reporters/lsp-reporter/package.json @@ -25,7 +25,6 @@ "node-ipc": "^9.1.4", "nullthrows": "^1.1.1", "ps-node": "^0.1.6", - "vscode-jsonrpc": "^6.0.0", - "vscode-languageserver": "^7.0.0" + "vscode-jsonrpc": "^8.0.2" } } diff --git a/packages/reporters/lsp-reporter/src/LspReporter.js b/packages/reporters/lsp-reporter/src/LspReporter.js index 4e3ee4e300d..26e8dfcaf54 100644 --- a/packages/reporters/lsp-reporter/src/LspReporter.js +++ b/packages/reporters/lsp-reporter/src/LspReporter.js @@ -1,125 +1,136 @@ // @flow strict-local -/* eslint-disable no-console */ import type {Diagnostic as ParcelDiagnostic} from '@parcel/diagnostic'; -import type {FilePath} from '@parcel/types'; +import type { + BundleGraph, + DiagnosticLogEvent, + FilePath, + PackagedBundle, +} from '@parcel/types'; import type {Program, Query} from 'ps-node'; +import type {Diagnostic, PublishDiagnostic} from './protocol'; +import type {MessageConnection} from 'vscode-jsonrpc/node'; -import {DiagnosticSeverity} from 'vscode-languageserver/node'; - -import {DefaultMap, getProgressMessage} from '@parcel/utils'; +import { + DefaultMap, + getProgressMessage, + makeDeferredWithPromise, +} from '@parcel/utils'; import {Reporter} from '@parcel/plugin'; -import invariant from 'assert'; import path from 'path'; import os from 'os'; +import url from 'url'; import fs from 'fs'; import * as ps from 'ps-node'; import {promisify} from 'util'; -import ipc from 'node-ipc'; + +import {createServer} from './ipc'; +import { + DiagnosticSeverity, + DiagnosticTag, + NotificationBuildStatus, + NotificationWorkspaceDiagnostics, + RequestDocumentDiagnostics, +} from './protocol'; const lookupPid: Query => Program[] = promisify(ps.lookup); -// flowlint-next-line unclear-type:off -type LspDiagnostic = any; +const ignoreFail = func => { + try { + func(); + } catch (e) { + /**/ + } +}; + +type ParcelSeverity = DiagnosticLogEvent['level']; + +const BASEDIR = fs.realpathSync(path.join(os.tmpdir(), 'parcel-lsp')); +const SOCKET_FILE = path.join(BASEDIR, `parcel-${process.pid}`); +const META_FILE = path.join(BASEDIR, `parcel-${process.pid}.json`); + +let workspaceDiagnostics: DefaultMap< + string, + Array, +> = new DefaultMap(() => []); -type ParcelSeverity = 'error' | 'warn' | 'info' | 'verbose'; +const getWorkspaceDiagnostics = (): Array => + [...workspaceDiagnostics].map(([uri, diagnostics]) => ({uri, diagnostics})); -let watchEnded = false; -let fileDiagnostics: DefaultMap> = new DefaultMap( - () => [], -); -let pipeFilename; +let server; +let connections: Array = []; + +let bundleGraphDeferrable = + makeDeferredWithPromise>(); +let bundleGraph: Promise> = + bundleGraphDeferrable.promise; export default (new Reporter({ - async report({event, logger, options}) { + async report({event, options}) { switch (event.type) { case 'watchStart': { - let transportName = `parcel-${process.pid}`; - ipc.config.id = transportName; - ipc.config.retry = 1500; - ipc.config.logger = message => logger.verbose({message}); - ipc.serve(() => { - ipc.server.on('init', (_, socket) => { - ipc.server.emit(socket, 'message', { - type: 'parcelFileDiagnostics', - fileDiagnostics: [...fileDiagnostics], - }); - ipc.server.on('connect', () => { - ipc.server.emit(socket, 'message', { - type: 'parcelFileDiagnostics', - fileDiagnostics: [...fileDiagnostics], - }); - }); - }); - }); - ipc.server.start(); - - // Create a file to ID the transport - let pathname = path.join(os.tmpdir(), 'parcel-lsp'); - await fs.promises.mkdir(pathname, {recursive: true}); + await fs.promises.mkdir(BASEDIR, {recursive: true}); // For each existing file, check if the pid matches a running process. // If no process matches, delete the file, assuming it was orphaned // by a process that quit unexpectedly. - for (let filename of fs.readdirSync(pathname)) { - let pid = parseInt(filename, 10); + for (let filename of fs.readdirSync(BASEDIR)) { + if (filename.endsWith('.json')) continue; + let pid = parseInt(filename.slice('parcel-'.length), 10); let resultList = await lookupPid({pid}); - if (resultList.length) continue; - fs.unlinkSync(path.join(pathname, filename)); + if (resultList.length > 0) continue; + fs.unlinkSync(path.join(BASEDIR, filename)); + ignoreFail(() => + fs.unlinkSync(path.join(BASEDIR, filename + '.json')), + ); } - pipeFilename = path.join(pathname, String(process.pid)); + server = await createServer(SOCKET_FILE, connection => { + // console.log('got connection'); + connections.push(connection); + connection.onClose(() => { + connections = connections.filter(c => c !== connection); + }); + + connection.onRequest(RequestDocumentDiagnostics, async uri => { + let graph = await bundleGraph; + if (!graph) return; + + let v = await getDiagnosticsUnusedExports(graph, uri); + return v; + }); + + sendDiagnostics(); + }); await fs.promises.writeFile( - pipeFilename, + META_FILE, JSON.stringify({ - transportName, + projectRoot: options.projectRoot, pid: process.pid, argv: process.argv, }), ); - console.debug('connection listening...'); - - if (watchEnded) { - ipc.server.stop(); - invariant(pipeFilename); - fs.unlinkSync(pipeFilename); - } else if (fileDiagnostics.size > 0) { - ipc.server.broadcast('message', { - type: 'parcelFileDiagnostics', - fileDiagnostics: [...fileDiagnostics], - }); - } break; } + case 'buildStart': { - ipc.server.broadcast('message', {type: 'parcelBuildStart'}); - ipc.server.broadcast('message', { - type: 'parcelFileDiagnostics', - fileDiagnostics: [...fileDiagnostics].map(([uri]) => [uri, []]), - }); - fileDiagnostics.clear(); + bundleGraphDeferrable = makeDeferredWithPromise(); + bundleGraph = bundleGraphDeferrable.promise; + updateBuildState('start'); + clearDiagnostics(); break; } case 'buildSuccess': - ipc.server.broadcast('message', {type: 'parcelBuildSuccess'}); - ipc.server.broadcast('message', { - type: 'parcelFileDiagnostics', - fileDiagnostics: [...fileDiagnostics], - }); + bundleGraphDeferrable.deferred.resolve(event.bundleGraph); + updateBuildState('end'); + sendDiagnostics(); break; case 'buildFailure': { - updateDiagnostics( - fileDiagnostics, - event.diagnostics, - 'error', - options.projectRoot, - ); - ipc.server.broadcast('message', {type: 'parcelBuildEnd'}); - ipc.server.broadcast('message', { - type: 'parcelFileDiagnostics', - fileDiagnostics: [...fileDiagnostics], - }); + bundleGraphDeferrable.deferred.resolve(undefined); + updateDiagnostics(event.diagnostics, 'error', options.projectRoot); + updateBuildState('end'); + sendDiagnostics(); break; } case 'log': @@ -131,7 +142,6 @@ export default (new Reporter({ event.level === 'verbose') ) { updateDiagnostics( - fileDiagnostics, event.diagnostics, event.level, options.projectRoot, @@ -141,27 +151,42 @@ export default (new Reporter({ case 'buildProgress': { let message = getProgressMessage(event); if (message != null) { - ipc.server.broadcast('message', { - type: 'parcelBuildProgress', - message, - }); + updateBuildState('progress', message); } break; } case 'watchEnd': - watchEnded = true; - if (pipeFilename != null) { - fs.unlinkSync(pipeFilename); - } - ipc.server.stop(); - console.debug('connection disposed of'); + connections.forEach(c => c.end()); + await server.close(); + ignoreFail(() => fs.unlinkSync(META_FILE)); break; } }, }): Reporter); +function updateBuildState( + state: 'start' | 'progress' | 'end', + message: string | void, +) { + connections.forEach(c => + c.sendNotification(NotificationBuildStatus, state, message), + ); +} + +function clearDiagnostics() { + workspaceDiagnostics.clear(); +} +function sendDiagnostics() { + // console.log('send', getWorkspaceDiagnostics()); + connections.forEach(c => + c.sendNotification( + NotificationWorkspaceDiagnostics, + getWorkspaceDiagnostics(), + ), + ); +} + function updateDiagnostics( - fileDiagnostics: DefaultMap>, parcelDiagnostics: Array, parcelSeverity: ParcelSeverity, projectRoot: FilePath, @@ -214,7 +239,7 @@ function updateDiagnostics( } } - fileDiagnostics + workspaceDiagnostics .get(`file://${normalizeFilePath(filePath, projectRoot)}`) .push({ range: { @@ -239,7 +264,81 @@ function updateDiagnostics( } } -function parcelSeverityToLspSeverity(parcelSeverity: ParcelSeverity): mixed { +function getDiagnosticsUnusedExports( + bundleGraph: BundleGraph, + document: string, +): Array { + let filename = url.fileURLToPath(document); + let diagnostics = []; + + let asset = bundleGraph.traverse((node, context, actions) => { + if (node.type === 'asset' && node.value.filePath === filename) { + actions.stop(); + return node.value; + } + }); + + if (asset) { + const generateDiagnostic = (loc, type) => ({ + range: { + start: { + line: loc.start.line - 1, + character: loc.start.column - 1, + }, + end: { + line: loc.end.line - 1, + character: loc.end.column, + }, + }, + source: '@parcel/core', + severity: DiagnosticSeverity.Hint, + message: `Unused ${type}.`, + tags: [DiagnosticTag.Unnecessary], + }); + + let usedSymbols = bundleGraph.getUsedSymbols(asset); + if (usedSymbols) { + for (let [exported, symbol] of asset.symbols) { + if (!usedSymbols.has(exported)) { + if (symbol.loc) { + diagnostics.push(generateDiagnostic(symbol.loc, 'export')); + } + } + } + // if (usedSymbols.size === 0 && asset.sideEffects !== false) { + // diagnostics.push({ + // range: { + // start: { + // line: 0, + // character: 0, + // }, + // end: { + // line: 0, + // character: 1, + // }, + // }, + // source: '@parcel/core', + // severity: DiagnosticSeverity.Warning, + // message: `Asset has no used exports, but is not marked as sideEffect-free so it cannot be excluded automatically.`, + // }); + // } + } + + for (let dep of asset.getDependencies()) { + let usedSymbols = bundleGraph.getUsedSymbols(dep); + if (usedSymbols) { + for (let [exported, symbol] of dep.symbols) { + if (!usedSymbols.has(exported) && symbol.isWeak && symbol.loc) { + diagnostics.push(generateDiagnostic(symbol.loc, 'reexport')); + } + } + } + } + } + return diagnostics; +} + +function parcelSeverityToLspSeverity(parcelSeverity: ParcelSeverity) { switch (parcelSeverity) { case 'error': return DiagnosticSeverity.Error; diff --git a/packages/reporters/lsp-reporter/src/ipc.js b/packages/reporters/lsp-reporter/src/ipc.js new file mode 100644 index 00000000000..4822a4ce327 --- /dev/null +++ b/packages/reporters/lsp-reporter/src/ipc.js @@ -0,0 +1,55 @@ +// @flow +import * as net from 'net'; +import type { + MessageReader, + MessageWriter, + MessageConnection, +} from 'vscode-jsonrpc/node'; +import { + createMessageConnection, + SocketMessageReader, + SocketMessageWriter, +} from 'vscode-jsonrpc/node'; + +function createClientPipeTransport( + pipeName: string, + onConnected: (reader: MessageReader, writer: MessageWriter) => void, +): Promise<{|close: () => Promise|}> { + return new Promise((resolve, reject) => { + let server: net.Server = net.createServer((socket: net.Socket) => { + onConnected( + new SocketMessageReader(socket), + new SocketMessageWriter(socket), + ); + }); + server.on('error', reject); + server.listen(pipeName, () => { + server.removeListener('error', reject); + resolve({ + close() { + return new Promise((res, rej) => { + server.close(e => { + if (e) rej(e); + else res(); + }); + }); + }, + }); + }); + }); +} + +export function createServer( + filename: string, + setup: (connection: MessageConnection) => void, +): Promise<{|close: () => Promise|}> { + return createClientPipeTransport( + filename, + (reader: MessageReader, writer: MessageWriter) => { + let connection = createMessageConnection(reader, writer); + connection.listen(); + + setup(connection); + }, + ); +} diff --git a/packages/reporters/lsp-reporter/src/protocol.js b/packages/reporters/lsp-reporter/src/protocol.js new file mode 100644 index 00000000000..6b6dd759fcf --- /dev/null +++ b/packages/reporters/lsp-reporter/src/protocol.js @@ -0,0 +1,91 @@ +// @flow +import { + NotificationType, + NotificationType2, + RequestType, +} from 'vscode-jsonrpc/node'; + +opaque type ODiagnosticTag = 1 | 2 | 3 | 4; +opaque type ODiagnosticSeverity = 1 | 2 | 3 | 4; + +export const DiagnosticTag = { + /** + * Unused or unnecessary code. + * + * Clients are allowed to render diagnostics with this tag faded out instead of having + * an error squiggle. + */ + Unnecessary: (1: ODiagnosticTag), + /** + * Deprecated or obsolete code. + * + * Clients are allowed to rendered diagnostics with this tag strike through. + */ + Deprecated: (2: ODiagnosticTag), +}; + +export const DiagnosticSeverity = { + /** + * Reports an error. + */ + Error: (1: ODiagnosticSeverity), + /** + * Reports a warning. + */ + Warning: (2: ODiagnosticSeverity), + /** + * Reports an information. + */ + Information: (3: ODiagnosticSeverity), + /** + * Reports a hint. + */ + Hint: (4: ODiagnosticSeverity), +}; + +export type DocumentUri = string; +export type Position = {|line: number, character: number|}; +export type Range = {|start: Position, end: Position|}; +export type CodeDescription = {|href: string|}; +export type Location = {|uri: string, range: Range|}; +export type DiagnosticRelatedInformation = {| + location: Location, + message: string, +|}; +export type Diagnostic = {| + range: Range, + severity?: ODiagnosticSeverity, + code?: number | string, + codeDescription?: CodeDescription, + source?: string, + message: string, + tags?: ODiagnosticTag[], + relatedInformation?: DiagnosticRelatedInformation[], + data?: mixed, +|}; + +// -------------------------------- +// Keep in sync with packages/utils/parcel-lsp/src/protocol.ts! + +export type PublishDiagnostic = {| + uri: DocumentUri, + diagnostics: Array, +|}; + +// Request: Client -> Server +export const RequestDocumentDiagnostics: RequestType< + DocumentUri, + Array | void, + void, +> = new RequestType('RequestDocumentDiagnostics'); + +// Notification: Server -> Client +export const NotificationWorkspaceDiagnostics: NotificationType< + Array, +> = new NotificationType('NotificationWorkspaceDiagnostics'); + +// Notification: Server -> Client +export const NotificationBuildStatus: NotificationType2< + 'start' | 'progress' | 'end', + string | void, +> = new NotificationType2('NotificationBuildStatus'); diff --git a/packages/utils/parcel-lsp/package.json b/packages/utils/parcel-lsp/package.json index bb46927799a..745a8b4323e 100644 --- a/packages/utils/parcel-lsp/package.json +++ b/packages/utils/parcel-lsp/package.json @@ -28,23 +28,19 @@ "parcel": "^2.8.2" }, "dependencies": { - "@parcel/diagnostic": "2.8.2", - "@parcel/plugin": "2.8.2", - "@parcel/types": "2.8.2", - "@parcel/utils": "2.8.2", "@parcel/watcher": "^2.0.7", - "node-ipc": "^9.1.4", + "common-path-prefix": "^3.0.0", "nullthrows": "^1.1.1", "ps-node": "^0.1.6", - "vscode-languageclient": "^8.0.1", - "vscode-languageserver": "^8.0.1", + "vscode-languageclient": "^8.0.2", + "vscode-jsonrpc": "^8.0.2", + "vscode-languageserver": "^8.0.2", "vscode-languageserver-textdocument": "^1.0.0" }, "devDependencies": { "@types/glob": "^7.1.3", "@types/mocha": "^8.0.4", "@types/node": "^12.11.7", - "@types/node-ipc": "^9.1.3", "@types/vscode": "^1.67.0", "@typescript-eslint/eslint-plugin": "^4.14.1", "@typescript-eslint/parser": "^4.14.1", diff --git a/packages/utils/parcel-lsp/src/LspServer.ts b/packages/utils/parcel-lsp/src/LspServer.ts index 4637bac3560..dc864316828 100644 --- a/packages/utils/parcel-lsp/src/LspServer.ts +++ b/packages/utils/parcel-lsp/src/LspServer.ts @@ -1,50 +1,48 @@ -/* eslint-disable no-console */ - import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; import { createConnection, - TextDocuments, - Diagnostic, - DiagnosticSeverity, - ProposedFeatures, - InitializeParams, + DiagnosticRefreshRequest, DidChangeConfigurationNotification, - CompletionItem, - CompletionItemKind, - TextDocumentPositionParams, - TextDocumentSyncKind, + DocumentDiagnosticParams, + DocumentDiagnosticReport, + DocumentDiagnosticReportKind, + DocumentDiagnosticRequest, + DocumentUri, + InitializeParams, InitializeResult, + ProposedFeatures, + TextDocumentSyncKind, WorkDoneProgressServerReporter, } from 'vscode-languageserver/node'; import { - CloseAction, - ErrorAction, - LanguageClient, - LanguageClientOptions, - MessageTransports, -} from 'vscode-languageclient/node'; - -import * as net from 'net'; + createServerPipeTransport, + createMessageConnection, + MessageConnection, +} from 'vscode-jsonrpc/node'; import * as invariant from 'assert'; -import nullthrows from 'nullthrows'; -import {IPC} from 'node-ipc'; +import * as url from 'url'; +import commonPathPrefix = require('common-path-prefix'); -import {TextDocument} from 'vscode-languageserver-textdocument'; +// import {TextDocument} from 'vscode-languageserver-textdocument'; import * as watcher from '@parcel/watcher'; - -type IPCType = InstanceType; +import { + NotificationBuildStatus, + NotificationWorkspaceDiagnostics, + RequestDocumentDiagnostics, +} from './protocol'; const connection = createConnection(ProposedFeatures.all); // Create a simple text document manager. -const documents: TextDocuments = new TextDocuments(TextDocument); +// const documents: TextDocuments = new TextDocuments(TextDocument); let hasConfigurationCapability = false; let hasWorkspaceFolderCapability = false; -let hasDiagnosticRelatedInformationCapability = false; +// let hasDiagnosticRelatedInformationCapability = false; +let hasDiagnosticsRefreshSupport = false; connection.onInitialize((params: InitializeParams) => { const capabilities = params.capabilities; @@ -57,18 +55,22 @@ connection.onInitialize((params: InitializeParams) => { hasWorkspaceFolderCapability = !!( capabilities.workspace && !!capabilities.workspace.workspaceFolders ); - hasDiagnosticRelatedInformationCapability = !!( - capabilities.textDocument && - capabilities.textDocument.publishDiagnostics && - capabilities.textDocument.publishDiagnostics.relatedInformation + // hasDiagnosticRelatedInformationCapability = !!( + // capabilities.textDocument && + // capabilities.textDocument.publishDiagnostics && + // capabilities.textDocument.publishDiagnostics.relatedInformation + // ); + hasDiagnosticsRefreshSupport = Boolean( + capabilities.workspace?.diagnostics?.refreshSupport, ); const result: InitializeResult = { capabilities: { textDocumentSync: TextDocumentSyncKind.Incremental, // Tell the client that this server supports code completion. - completionProvider: { - resolveProvider: true, + diagnosticProvider: { + workspaceDiagnostics: false, + interFileDependencies: true, }, }, }; @@ -98,6 +100,47 @@ connection.onInitialized(() => { } }); +connection.onRequest( + DocumentDiagnosticRequest.type, + async ( + params: DocumentDiagnosticParams, + ): Promise => { + let client = findClient(params.textDocument.uri); + let result; + if (client) { + // console.log( + // 'DocumentDiagnosticRequest', + // params.textDocument.uri, + // params.previousResultId === client.lastBuild, + // ); + + if (params.previousResultId === client.lastBuild) { + return { + kind: DocumentDiagnosticReportKind.Unchanged, + resultId: client.lastBuild, + }; + } + + result = await client.connection.sendRequest( + RequestDocumentDiagnostics, + params.textDocument.uri, + ); + + if (result) { + client.uris.add(params.textDocument.uri); + } + } + + return { + kind: DocumentDiagnosticReportKind.Full, + resultId: client?.lastBuild, + items: result ?? [], + }; + }, +); + +connection.listen(); + class ProgressReporter { progressReporterPromise?: Promise | null; lastMessage?: string; @@ -132,108 +175,122 @@ class ProgressReporter { } } -function createIPCClientIfPossible( - parcelLspDir: string, - filePath: string, -): {client: IPCType; uris: Set} | undefined { - let transportName: string; - try { - transportName = JSON.parse( - fs.readFileSync(filePath, { - encoding: 'utf8', - }), - ).transportName; - } catch (e) { - // TODO: Handle this - console.log(e); - return; +function sendDiagnosticsRefresh() { + if (hasDiagnosticsRefreshSupport) { + connection.sendRequest(DiagnosticRefreshRequest.type); } +} - let uris: Set = new Set(); - let client = new IPC(); - client.config.id = `parcel-lsp-${process.pid}`; - client.config.retry = 1500; - client.connectTo(transportName, function () { - client.of[transportName].on( - 'message', //any event or message type your server listens for - function (data: any) { - switch (data.type) { - case 'parcelBuildEnd': - progressReporter.done(); - break; - - case 'parcelFileDiagnostics': - for (let [uri, diagnostics] of data.fileDiagnostics) { - connection.sendDiagnostics({uri, diagnostics}); - uris.add(uri); - } - break; - - case 'parcelBuildSuccess': - progressReporter.done(); - break; - - case 'parcelBuildStart': - uris.clear(); - progressReporter.begin(); - break; - - case 'parcelBuildProgress': - progressReporter.report(data.message); - break; - - default: - throw new Error(); - } - }, +type Client = { + connection: MessageConnection; + projectRoot: string; + uris: Set; + lastBuild: string; +}; + +const BASEDIR = fs.realpathSync(path.join(os.tmpdir(), 'parcel-lsp')); +let progressReporter = new ProgressReporter(); +let clients: Map = new Map(); + +function findClient(document: DocumentUri): Client | undefined { + let filepath = url.fileURLToPath(document); + + let longestPrefix = 0; + let bestClient; + for (let [, client] of clients) { + let prefix = commonPathPrefix([client.projectRoot, filepath]).length; + if (longestPrefix < prefix) { + longestPrefix = prefix; + bestClient = client; + } else if (longestPrefix === prefix) { + console.warn('Ambiguous client for ' + filepath); + } + } + return bestClient; +} + +function createClient(metafilepath: string) { + let metafile = JSON.parse(fs.readFileSync(metafilepath, 'utf8')); + + let socketfilepath = metafilepath.slice(0, -5); + let [reader, writer] = createServerPipeTransport(socketfilepath); + let client = createMessageConnection(reader, writer); + client.listen(); + + let uris = new Set(); + + let result = { + connection: client, + uris, + projectRoot: metafile.projectRoot, + lastBuild: '0', + }; + + client.onNotification(NotificationBuildStatus, (state, message) => { + // console.log('got NotificationBuildStatus', state, message); + if (state === 'start') { + progressReporter.begin(); + for (let uri of uris) { + connection.sendDiagnostics({uri, diagnostics: []}); + } + } else if (state === 'progress' && message != null) { + progressReporter.report(message); + } else if (state === 'end') { + result.lastBuild = String(Date.now()); + sendDiagnosticsRefresh(); + progressReporter.done(); + } + }); + + client.onNotification(NotificationWorkspaceDiagnostics, diagnostics => { + // console.log('got NotificationWorkspaceDiagnostics', diagnostics); + for (let d of diagnostics) { + uris.add(d.uri); + connection.sendDiagnostics(d); + } + }); + + client.onClose(() => { + clients.delete(metafile); + sendDiagnosticsRefresh(); + return Promise.all( + [...uris].map(uri => connection.sendDiagnostics({uri, diagnostics: []})), ); }); - return {client, uris}; + sendDiagnosticsRefresh(); + clients.set(metafile, result); } -let progressReporter = new ProgressReporter(); -let clients: Map}> = new Map(); -let parcelLspDir = path.join(fs.realpathSync(os.tmpdir()), 'parcel-lsp'); -fs.mkdirSync(parcelLspDir, {recursive: true}); +fs.mkdirSync(BASEDIR, {recursive: true}); // Search for currently running Parcel processes in the parcel-lsp dir. // Create an IPC client connection for each running process. -for (let filename of fs.readdirSync(parcelLspDir)) { - const filepath = path.join(parcelLspDir, filename); - let client = createIPCClientIfPossible(parcelLspDir, filepath); - if (client) { - clients.set(filepath, client); - } +for (let filename of fs.readdirSync(BASEDIR)) { + if (!filename.endsWith('.json')) continue; + let filepath = path.join(BASEDIR, filename); + createClient(filepath); + // console.log('connected initial', filepath); } // Watch for new Parcel processes in the parcel-lsp dir, and disconnect the // client for each corresponding connection when a Parcel process ends -watcher.subscribe(parcelLspDir, async (err, events) => { +watcher.subscribe(BASEDIR, async (err, events) => { if (err) { throw err; } for (let event of events) { - if (event.type === 'create') { - let client = createIPCClientIfPossible(parcelLspDir, event.path); - if (client) { - clients.set(event.path, client); - } - } else if (event.type === 'delete') { + if (event.type === 'create' && event.path.endsWith('.json')) { + createClient(event.path); + // console.log('connected watched', event.path); + } else if (event.type === 'delete' && event.path.endsWith('.json')) { let existing = clients.get(event.path); + // console.log('existing', event.path, existing); if (existing) { clients.delete(event.path); - for (let id of Object.keys(existing.client.of)) { - existing.client.disconnect(id); - } - await Promise.all( - [...existing.uris].map(uri => - connection.sendDiagnostics({uri, diagnostics: []}), - ), - ); + existing.connection.end(); + // console.log('disconnected watched', event.path); } } } }); - -connection.listen(); diff --git a/packages/utils/parcel-lsp/src/protocol.ts b/packages/utils/parcel-lsp/src/protocol.ts new file mode 100644 index 00000000000..17c0b3a743b --- /dev/null +++ b/packages/utils/parcel-lsp/src/protocol.ts @@ -0,0 +1,34 @@ +// @flow +import { + NotificationType, + NotificationType2, + RequestType, +} from 'vscode-jsonrpc/node'; + +import type {DocumentUri, Diagnostic} from 'vscode-languageserver'; + +// -------------------------------- +// Keep in sync with packages/reporters/lsp-reporter/src/protocol.js! + +export type PublishDiagnostic = { + uri: DocumentUri; + diagnostics: Array; +}; + +// Request: Client -> Server +export const RequestDocumentDiagnostics: RequestType< + DocumentUri, + Array | undefined, + void +> = new RequestType('RequestDocumentDiagnostics'); + +// Notification: Server -> Client +export const NotificationWorkspaceDiagnostics: NotificationType< + Array +> = new NotificationType('NotificationWorkspaceDiagnostics'); + +// Notification: Server -> Client +export const NotificationBuildStatus: NotificationType2< + 'start' | 'progress' | 'end', + string | void +> = new NotificationType2('NotificationBuildStatus'); diff --git a/packages/utils/parcelforvscode/package.json b/packages/utils/parcelforvscode/package.json index 1ba00cef269..748f97aad24 100644 --- a/packages/utils/parcelforvscode/package.json +++ b/packages/utils/parcelforvscode/package.json @@ -20,8 +20,7 @@ "compile": "tsc -p ./", "watch": "tsc -watch -p ./", "pretest": "yarn run compile && yarn run lint", - "lint": "eslint src --ext ts", - "test": "node ./out/test/runTest.js" + "lint": "eslint src --ext ts" }, "devDependencies": { "@types/glob": "^7.1.3", @@ -38,6 +37,6 @@ }, "dependencies": { "@parcel/lsp": "2.8.2", - "vscode-languageclient": "^8.0.1" + "vscode-languageclient": "^8.0.2" } } diff --git a/packages/utils/parcelforvscode/src/extension.ts b/packages/utils/parcelforvscode/src/extension.ts index cc1885a0715..d8158ca36ca 100644 --- a/packages/utils/parcelforvscode/src/extension.ts +++ b/packages/utils/parcelforvscode/src/extension.ts @@ -29,8 +29,9 @@ export function activate(context: ExtensionContext) { }; // Options to control the language client - let clientOptions: LanguageClientOptions = {}; - + let clientOptions: LanguageClientOptions = { + documentSelector: [{scheme: 'file', pattern: '**/*'}], + }; // Create the language client and start the client. client = new LanguageClient('parcel', 'Parcel', serverOptions, clientOptions); diff --git a/yarn.lock b/yarn.lock index 5c512b93c5a..da77d1a2b6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2420,13 +2420,6 @@ resolved "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0" integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw== -"@types/node-ipc@^9.1.3": - version "9.1.3" - resolved "https://registry.yarnpkg.com/@types/node-ipc/-/node-ipc-9.1.3.tgz#5381fbc910071083b28dd43225727877c108b361" - integrity sha512-ka7CPX9Dk2lwe4PxoZMLOwcQrtdcYe/7OKmH75fQbmt0jdKltWVkdGA81D5l55d0wNhkweHa3XmzFbt5C0ieOQ== - dependencies: - "@types/node" "*" - "@types/node@*", "@types/node@>= 8", "@types/node@^15.12.4": version "15.12.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.4.tgz#e1cf817d70a1e118e81922c4ff6683ce9d422e26" @@ -4111,6 +4104,11 @@ commander@^7.0.0, commander@^7.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +common-path-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0" + integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -13723,69 +13721,44 @@ void-elements@^3.1.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= -vscode-jsonrpc@6.0.0, vscode-jsonrpc@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== - -vscode-jsonrpc@8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" - integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== +vscode-jsonrpc@8.0.2, vscode-jsonrpc@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz#f239ed2cd6004021b6550af9fd9d3e47eee3cac9" + integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ== -vscode-languageclient@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.1.tgz#bf5535c4463a78daeaca0bcb4f5868aec86bb301" - integrity sha512-9XoE+HJfaWvu7Y75H3VmLo5WLCtsbxEgEhrLPqwt7eyoR49lUIyyrjb98Yfa50JCMqF2cePJAEVI6oe2o1sIhw== +vscode-languageclient@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz#f1f23ce8c8484aa11e4b7dfb24437d3e59bb61c6" + integrity sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q== dependencies: minimatch "^3.0.4" semver "^7.3.5" - vscode-languageserver-protocol "3.17.1" + vscode-languageserver-protocol "3.17.2" -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== +vscode-languageserver-protocol@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz#beaa46aea06ed061576586c5e11368a9afc1d378" + integrity sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg== dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" - -vscode-languageserver-protocol@3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" - integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== - dependencies: - vscode-jsonrpc "8.0.1" - vscode-languageserver-types "3.17.1" + vscode-jsonrpc "8.0.2" + vscode-languageserver-types "3.17.2" vscode-languageserver-textdocument@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.1.tgz#178168e87efad6171b372add1dea34f53e5d330f" integrity sha512-UIcJDjX7IFkck7cSkNNyzIz5FyvpQfY7sdzVy+wkKN/BLaD4DQ0ppXQrKePomCxTS7RrolK1I0pey0bG9eh8dA== -vscode-languageserver-types@3.16.0: - version "3.16.0" - resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== - -vscode-languageserver-types@3.17.1: - version "3.17.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" - integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== - -vscode-languageserver@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" - integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== - dependencies: - vscode-languageserver-protocol "3.16.0" +vscode-languageserver-types@3.17.2: + version "3.17.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2" + integrity sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA== -vscode-languageserver@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.1.tgz#56bd7a01f5c88af075a77f1d220edcb30fc4bdc7" - integrity sha512-sn7SjBwWm3OlmLtgg7jbM0wBULppyL60rj8K5HF0ny/MzN+GzPBX1kCvYdybhl7UW63V5V5tRVnyB8iwC73lSQ== +vscode-languageserver@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz#cfe2f0996d9dfd40d3854e786b2821604dfec06d" + integrity sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA== dependencies: - vscode-languageserver-protocol "3.17.1" + vscode-languageserver-protocol "3.17.2" vscode-test@^1.5.0: version "1.5.1"