microsoft / microsoft/vscode-languageserver-node

Consider supporting/merging with the `cancellationtoken` npm package

Open
#855 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

feature-request help wanted
Dominant language
TypeScript
Stars
1.8k
Forks
404
Avg merge
2d 8h
Merged PRs (30d)
14

Description

vscode-jsonrpc defines its own CancellationToken interface which is modeled after the .NET type by the same name. While this is a fine type to use, it's tucked inside an RPC library which doesn't make it particularly nice to use in other settings.

There is a cancellationtoken npm package that focuses just on such a token. It is a more capable token, offering throwIfCancelled(), timeouts, optional reasons for cancellation, an api to race a token against another promise, and combining multiple tokens into one as a race or as a union of all. While it can do everything the .NET version can, the API is designed to be more javascript-esque, so it feels more native.

Given these two options, in some libraries I would tend to prefer the latter token. But where I have to interop with vscode-jsonrpc this complicates the story and leads to potential bugs when the wrong token is given or expected.

Can vscode-jsonrpc be updated to support this cancellationtoken npm package?
In particular, I'm thinking you could do duck-type checking to detect which kind it is and work with both. When creating a token to pass to RPC servers, perhaps you could create a token which fulfills the API obligations of both so that the RPC server can be implemented to receive either one.

Here are adapters I wrote that makes either token look like the other, to demonstrate how simple this is. Note that creating a union type to provide to RPC server methods would probably be more complicated.

import CancellationToken from 'cancellationtoken';
import {
    CancellationToken as vscodeCancellationToken,
    CancellationTokenSource as vscodeCancellationTokenSource,
} from 'vscode-jsonrpc';

export class CancellationTokenAdapters {
    /** Tests whether an object satisfies the {@link vscodeCancellationToken} interface. */
    static IsVSCode(value: any): value is vscodeCancellationToken {
        return vscodeCancellationToken.is(value);
    }

    /** Tests whether an object satisfies the {@link CancellationToken} interface. */
    static IsCancellationToken(value: any): value is CancellationToken {
        return value
            && typeof value.throwIfCancelled === 'function'
            && typeof value.onCancelled === 'function'
            && value.isCancelled !== undefined
            && value.canBeCancelled !== undefined;
    }

    /** Returns a {@link CancellationToken} that is linked to the given {@link vscodeCancellationToken}. */
    static VSCodeToCancellationToken(cancellationToken: vscodeCancellationToken): CancellationToken {
        if (cancellationToken.isCancellationRequested) {
            return CancellationToken.CANCELLED;
        } else if (cancellationToken === vscodeCancellationToken.None) {
            return CancellationToken.CONTINUE;
        } else {
            const result = CancellationToken.create();
            cancellationToken.onCancellationRequested(_ => result.cancel());
            return result.token;
        }
    }

    /** Returns a {@link vscodeCancellationToken} that is linked to the given {@link CancellationToken}. */
    static CancellationTokenToVSCode(cancellationToken: CancellationToken): vscodeCancellationToken {
        if (cancellationToken.isCancelled) {
            return vscodeCancellationToken.Cancelled;
        } else if (cancellationToken.canBeCancelled) {
            const cts = new vscodeCancellationTokenSource();
            cancellationToken.onCancelled(_ => cts.cancel());
            return cts.token;
        } else {
            return vscodeCancellationToken.None;
        }
    }
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the vscode-jsonrpc CancellationToken and CancellationTokenSource APIs, then compare them with the cancellationtoken package and the adapters shown in the issue. Done should mean vscode-jsonrpc can interoperate with both token shapes without breaking existing consumers, but the issue does not name files or tests to run.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.