X Tutup
The Wayback Machine - https://web.archive.org/web/20220411234352/https://github.com/microsoft/TypeScript/pull/48497
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tsserver support for a virtual filesystem #48497

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open

tsserver support for a virtual filesystem #48497

wants to merge 28 commits into from

Conversation

Copy link
Member

@sandersn sandersn commented Mar 31, 2022

  1. I moved the virtual file system with watch code to a new project. The server now depends on this new project. The split might not be perfect: there may still be some test code in the new project.
  2. I'm not at all sure that the way of starting the tsserver in vfs mode is right, and I don't know how to test it.
  3. The test of the new server message still needs to move to a separate file.

Partly fixes #47600 -- there is probably more work needed here and definitely in vs code.

@typescript-bot
Copy link
Collaborator

@typescript-bot typescript-bot commented Mar 31, 2022

Thanks for the PR! It looks like you've changed the TSServer protocol in some way. Please ensure that any changes here don't break consumers of the current TSServer API. For some extra review, we'll ping @sheetalkamat, @amcasey, @mjbvz, @minestarks for you. Feel free to loop in other consumers/maintainers if necessary

@sandersn sandersn requested a review from sheetalkamat Mar 31, 2022
@typescript-bot typescript-bot added the For Milestone Bug label Mar 31, 2022
let it;
while (!(it = createdFiles.next()).done) {
const document = it.value;
if (document.fileContent) {
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can do fs.ensureFileOrFolder?

if (deletedFiles) {
// TODO: Probably want to delete empty parent folders while they are empty too
for (const file of deletedFiles) {
fs.deleteFile(file);
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removeFileOrFolder has option to determine if its leaf node that you can use.

if (fs.fileExists(it.value.file)) {
fs.modifyFile(it.value.file, it.value.fileContent);
}
else {
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldnt be the case right.. we can just call modifyFiles.. So we dont have to check if file exists or not

* Used to specify the script kind of the file explicitly. It could be one of the following:
* "TS", "JS", "TSX", "JSX"
*/
scriptKindName?: ScriptKindName;
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats the use of this

updated: FileSystemRequestArgs[];
}

export interface FileSystemRequestArgs extends FileRequestArgs {
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should just create this without deriving from FileRequestArgs as we just need fileName and fileContent?

Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably, it should resemble OpenRequestArgs.

src/harness/virtualFileSystemWithWatch.ts Outdated Show resolved Hide resolved
// TODO: This is almost certainly in harness/virtualFileSystemHost.ts, or should be.
function verifyFileSystem(host: TestFSWithWatch.VirtualServerHost | undefined, files: protocol.FileSystemRequestArgs[]) {
// 1. make sure that everything in files is there
assert.isDefined(host);
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of this you probably want to use baselines.. this becomes hard to maintain later on..

const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs() });
// You can diff the vfs using vfs.snap and vfs.diff to add to the baseline
// Do your things here
baselineTsserverLogs("configuredProjects", "when multiple projects are open detects correct default project", session);

@@ -168,13 +168,13 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
async function * explicitReturnType10(): IterableIterator<number> {
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2741: Property '[Symbol.iterator]' is missing in type 'AsyncGenerator<number, any, undefined>' but required in type 'IterableIterator<number>'.
!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:55:5: '[Symbol.iterator]' is declared here.
!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:90:5: '[Symbol.iterator]' is declared here.
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come this changed?

@@ -120,4 +145,28 @@ namespace ts.server {
// Start listening
session.listen();
}

function startVirtualFileSystemSession(options: StartSessionOptions, logger: Logger, cancellationToken: ServerCancellationToken) {
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of this you would want to create session with optional option fsSystem which defaults to host. And then in Editor services and session you want to verify all FS events or on the FS host.. So we dont need two sessions and this can be done from any type of Session.

When testing you would want to send the VFS instance and test few operations that use FS.

Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VFS instance should the host project and services use but server host is used for everything else.. So GC and other things work as before

Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then --vfs options can be parsed in both NodeServer as well as WebServer

{ "path": "../jsTyping" },
{ "path": "../services" }
Copy link
Member

@sheetalkamat sheetalkamat Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want to strip down so that you are not depending on these but its not important as anyways this is used in server which uses these dependencies

Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, it's not at all clear why a file system would depend on these.

sandersn added 2 commits Mar 31, 2022
I'm not sure why this fails locally, I suspect I need to `npm ci`.
Copy link
Contributor

@mjbvz mjbvz left a comment

Thanks for looking into this @sandersn!

I looked over the protocol part of the change. One question I have is how we'd tell TS which file system a given file belongs to. Would this be part of the filename we give to TS?

@amcasey
Copy link
Member

@amcasey amcasey commented Apr 1, 2022

    const sys = server.createWebSystem(webHost, args, () => findArgument("--executingFilePath") || location + "");

If we're already reading arguments here, I'd probably just check for --vfs inside createWebSystem, rather than creating a new entrypoint.


Refers to: src/tsserver/webServer.ts:88 in f67ef37. [](commit_id = f67ef37, deletion_comment = False)

Copy link
Member

@amcasey amcasey left a comment

I basically just second everything @sheetalkamat said 😄

{ "path": "../jsTyping" },
{ "path": "../services" }
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, it's not at all clear why a file system would depend on these.

"compilerOptions": {
"outFile": "../../built/local/vfs.js",
"types": [
"node", "mocha", "chai"
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want product code to depend on test frameworks?

updated: FileSystemRequestArgs[];
}

export interface FileSystemRequestArgs extends FileRequestArgs {
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably, it should resemble OpenRequestArgs.

/** For now, only 'memfs', initially for exclusive in-memory operation, but it could be other in-memory names later */
fileSystem: string;
/** List of newly created or newly available files. */
created: FileSystemRequestArgs[];
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it an error to create a file that already exists? If not, what's the point of having a separate updated property? Do those files provide diffs?

[CommandNames.UpdateFileSystem]: (request: protocol.UpdateFileSystemRequest) => {
this.changeSeq++;
this.projectService.updateFileSystem(
request.arguments.created && arrayIterator(request.arguments.created),
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we turning the arrays into iterators?

Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(It looks like you're following a precedent, so I'm probably missing something.)

@@ -79,6 +79,16 @@ namespace ts.server {
if (typeof process !== "undefined") {
start(initializeNodeSystem(), require("os").platform());
}
// TODO: Not sure this is right
else if (findArgument("vfs")) {
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasArgument?

Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I don't know if we validate command line arguments but, if we do, we should probably warn/error if you pass this to a node-based server.

@@ -81,6 +93,19 @@ namespace ts.server {
}
}


function createVirtualFileSystem() {
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: consider inlining this or, at least, moving it closer to the only caller.

Debug.assert(sys === undefined);
// TODO: I don't think I need the XMLHttpRequest code since vfs will get its files from messages sent by the owner
// ...but this means I may not need the webSession-copied code in startVirtualFileSystemSession
const vfshost = TestFSWithWatch.createVirtualServerHost([]);
Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably rename TestFSWithWatch.

Copy link
Member

@amcasey amcasey Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does it relate to server.createWebSystem? Does one delegate to the other?

@sandersn sandersn added this to Not started in PR Backlog Apr 8, 2022
@sandersn sandersn moved this from Not started to Waiting on reviewers in PR Backlog Apr 8, 2022
Project, editor services, session, etc all take an optional fshost and
preferentially use it for filesystem operations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug
Projects
PR Backlog
  
Waiting on reviewers
Development

Successfully merging this pull request may close these issues.

5 participants
X Tutup