From ebce8007efa7334165492f21ee5be2d20f27f098 Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Wed, 31 Jan 2024 23:57:06 +0100 Subject: [PATCH 1/6] fix: restore handling of zipfile: schema for neovim + yarn berry --- package.json | 2 +- src/configuration/fileSchemes.test.ts | 85 +++++++ src/configuration/fileSchemes.ts | 15 ++ src/diagnostic-queue.ts | 8 +- src/features/call-hierarchy.ts | 2 +- .../code-lens/implementationsCodeLens.ts | 2 +- src/features/code-lens/referencesCodeLens.ts | 2 +- src/features/source-definition.ts | 2 +- src/lsp-server.ts | 15 +- src/protocol-translation.ts | 10 +- src/test-utils.ts | 3 +- src/ts-client.ts | 37 ++- src/typescriptService.ts | 1 + src/utils/uri.ts | 28 +++ test-data/yarn-pnp/.editorconfig | 10 + test-data/yarn-pnp/.gitattributes | 4 + test-data/yarn-pnp/.gitignore | 13 + test-data/yarn-pnp/.vim/coc-settings.json | 4 + .../yarn-pnp/.yarn/sdks/integrations.yml | 5 + .../yarn-pnp/.yarn/sdks/typescript/bin/tsc | 20 ++ .../.yarn/sdks/typescript/bin/tsserver | 20 ++ .../yarn-pnp/.yarn/sdks/typescript/lib/tsc.js | 20 ++ .../.yarn/sdks/typescript/lib/tsserver.js | 225 ++++++++++++++++++ .../sdks/typescript/lib/tsserverlibrary.js | 225 ++++++++++++++++++ .../.yarn/sdks/typescript/lib/typescript.js | 20 ++ .../.yarn/sdks/typescript/package.json | 10 + test-data/yarn-pnp/README.md | 1 + test-data/yarn-pnp/package.json | 8 + test-data/yarn-pnp/testfile.ts | 1 + test-data/yarn-pnp/tsconfig.json | 6 + test-data/yarn-pnp/yarn.lock | 113 +++++++++ 31 files changed, 890 insertions(+), 27 deletions(-) create mode 100644 src/configuration/fileSchemes.test.ts create mode 100644 src/utils/uri.ts create mode 100644 test-data/yarn-pnp/.editorconfig create mode 100644 test-data/yarn-pnp/.gitattributes create mode 100644 test-data/yarn-pnp/.gitignore create mode 100644 test-data/yarn-pnp/.vim/coc-settings.json create mode 100644 test-data/yarn-pnp/.yarn/sdks/integrations.yml create mode 100755 test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsc create mode 100755 test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsserver create mode 100644 test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsc.js create mode 100644 test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserver.js create mode 100644 test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserverlibrary.js create mode 100644 test-data/yarn-pnp/.yarn/sdks/typescript/lib/typescript.js create mode 100644 test-data/yarn-pnp/.yarn/sdks/typescript/package.json create mode 100644 test-data/yarn-pnp/README.md create mode 100644 test-data/yarn-pnp/package.json create mode 100644 test-data/yarn-pnp/testfile.ts create mode 100644 test-data/yarn-pnp/tsconfig.json create mode 100644 test-data/yarn-pnp/yarn.lock diff --git a/package.json b/package.json index 19613757..5efd9f3d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "fix": "eslint --ext \".js,.ts\" --fix src", "size": "yarn build && yarn size-limit", "postversion": "git push --follow-tags", - "prepare": "cd test-data/jsx && yarn" + "prepare": "cd test-data/jsx && yarn && cd ../yarn-pnp && yarn" }, "eslintIgnore": [ "!.eslintrc.cjs" diff --git a/src/configuration/fileSchemes.test.ts b/src/configuration/fileSchemes.test.ts new file mode 100644 index 00000000..b32d399a --- /dev/null +++ b/src/configuration/fileSchemes.test.ts @@ -0,0 +1,85 @@ +import { URI } from 'vscode-uri'; +import * as lsp from 'vscode-languageserver'; +import { beforeAll, beforeEach, afterAll, describe, it, expect } from 'vitest'; +import { uri, createServer, position, TestLspServer, openDocumentAndWaitForDiagnostics, readContents, filePath } from '../test-utils.js'; +import { ZipfileURI } from '../utils/uri.js'; + +const ZIPFILE_URI = 'zipfile:///dir/foo.zip::path/file.ts'; + +describe('uri handling', () => { + it('parses zipfile:// uri', () => { + const parsed = URI.parse(ZIPFILE_URI); + expect(parsed.scheme).toBe('zipfile'); + expect(parsed.authority).toBe(''); + expect(parsed.path).toBe('/dir/foo.zip::path/file.ts'); + expect(parsed.fsPath).toBe('/dir/foo.zip::path/file.ts'); + expect(parsed.query).toBe(''); + expect(parsed.fragment).toBe(''); + }); + + it('stringifies zipfile uri without encoding', () => { + const parsed = URI.parse(ZIPFILE_URI); + expect(parsed.toString(true)).toBe('zipfile:/dir/foo.zip::path/file.ts'); + }); + + it('stringifies zipfile uri with encoding', () => { + const parsed = URI.parse(ZIPFILE_URI); + expect(parsed.toString()).toBe('zipfile:/dir/foo.zip%3A%3Apath/file.ts'); + }); +}); + +describe('zipfileuri handling', () => { + it('parses zipfile:// uri', () => { + const parsed = ZipfileURI.parse(ZIPFILE_URI); + expect(parsed.scheme).toBe('zipfile'); + expect(parsed.authority).toBe(''); + expect(parsed.path).toBe('/dir/foo.zip::path/file.ts'); + expect(parsed.fsPath).toBe('/dir/foo.zip::path/file.ts'); + expect(parsed.query).toBe(''); + expect(parsed.fragment).toBe(''); + }); + + it('stringifies zipfile uri with and without encoding', () => { + const parsed = ZipfileURI.parse(ZIPFILE_URI); + expect(parsed.toString(true)).toBe('zipfile:///dir/foo.zip::path/file.ts'); + expect(parsed.toString()).toBe('zipfile:///dir/foo.zip::path/file.ts'); + }); +}); + +describe('nevim zipfile scheme handling with yarn pnp', () => { + let server: TestLspServer; + + beforeAll(async () => { + server = await createServer({ + rootUri: uri('yarn-pnp'), + initializationOptionsOverrides: { + hostInfo: 'neovim', + }, + publishDiagnostics() {}, + }); + }); + + beforeEach(() => { + server.closeAllForTesting(); + }); + + afterAll(() => { + server.closeAllForTesting(); + server.shutdown(); + }); + + it('returns zipfile: uri for definition inside node_modules', async () => { + const doc = { + uri: uri('yarn-pnp', 'testfile.ts'), + languageId: 'typescript', + version: 1, + text: readContents(filePath('yarn-pnp', 'testfile.ts')), + }; + await openDocumentAndWaitForDiagnostics(server, doc); + const pos = position(doc, 'AxiosHeaderValue'); + const results = await server.definition({ textDocument: doc, position: pos }); + const defintion = Array.isArray(results) ? results[0] as lsp.Location : null; + expect(defintion).toBeDefined(); + expect(defintion!.uri).toMatch(/zipfile:\/\/.+.zip::node_modules\/axios\/.+/); + }); +}); diff --git a/src/configuration/fileSchemes.ts b/src/configuration/fileSchemes.ts index 29c1fea6..b9b01479 100644 --- a/src/configuration/fileSchemes.ts +++ b/src/configuration/fileSchemes.ts @@ -14,6 +14,10 @@ export const untitled = 'untitled'; export const git = 'git'; export const github = 'github'; export const azurerepos = 'azurerepos'; +// Equivalent of "untitled" in Sublime Text. +export const buffer = 'buffer'; +// For yarn berry support in neovim. +export const zipfile = 'zipfile'; /** Live share scheme */ export const vsls = 'vsls'; @@ -23,6 +27,17 @@ export const memFs = 'memfs'; export const vscodeVfs = 'vscode-vfs'; export const officeScript = 'office-script'; +export function getSemanticSupportedSchemes(): string[] { + return [ + file, + untitled, + buffer, + // walkThroughSnippet, + // vscodeNotebookCell, + zipfile, + ]; +} + /** * File scheme for which JS/TS language feature should be disabled */ diff --git a/src/diagnostic-queue.ts b/src/diagnostic-queue.ts index 4d8d98b0..eb22d243 100644 --- a/src/diagnostic-queue.ts +++ b/src/diagnostic-queue.ts @@ -87,7 +87,7 @@ export class DiagnosticEventQueue { if (this.ignoredDiagnosticCodes.size) { diagnostics = diagnostics.filter(diagnostic => !this.isDiagnosticIgnored(diagnostic)); } - const uri = this.client.toResource(file).toString(); + const uri = this.client.toResourceUri(file); const diagnosticsForFile = this.diagnostics.get(uri) || new FileDiagnostics(uri, this.publishDiagnostics, this.client, this.features); diagnosticsForFile.update(kind, diagnostics); this.diagnostics.set(uri, diagnosticsForFile); @@ -98,12 +98,12 @@ export class DiagnosticEventQueue { } public getDiagnosticsForFile(file: string): lsp.Diagnostic[] { - const uri = this.client.toResource(file).toString(); + const uri = this.client.toResourceUri(file); return this.diagnostics.get(uri)?.getDiagnostics() || []; } public onDidCloseFile(file: string): void { - const uri = this.client.toResource(file).toString(); + const uri = this.client.toResourceUri(file); const diagnosticsForFile = this.diagnostics.get(uri); diagnosticsForFile?.onDidClose(); this.diagnostics.delete(uri); @@ -113,7 +113,7 @@ export class DiagnosticEventQueue { * A testing function to clear existing file diagnostics, request fresh ones and wait for all to arrive. */ public async waitForDiagnosticsForTesting(file: string): Promise { - const uri = this.client.toResource(file).toString(); + const uri = this.client.toResourceUri(file); let diagnosticsForFile = this.diagnostics.get(uri); if (diagnosticsForFile) { diagnosticsForFile.onDidClose(); diff --git a/src/features/call-hierarchy.ts b/src/features/call-hierarchy.ts index 59d61b03..22988d0f 100644 --- a/src/features/call-hierarchy.ts +++ b/src/features/call-hierarchy.ts @@ -26,7 +26,7 @@ export function fromProtocolCallHierarchyItem(item: ts.server.protocol.CallHiera kind: fromProtocolScriptElementKind(item.kind), name, detail, - uri: client.toResource(item.file).toString(), + uri: client.toResourceUri(item.file), range: Range.fromTextSpan(item.span), selectionRange: Range.fromTextSpan(item.selectionSpan), }; diff --git a/src/features/code-lens/implementationsCodeLens.ts b/src/features/code-lens/implementationsCodeLens.ts index 08f31637..774dc79e 100644 --- a/src/features/code-lens/implementationsCodeLens.ts +++ b/src/features/code-lens/implementationsCodeLens.ts @@ -51,7 +51,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip const locations = response.body .map(reference => // Only take first line on implementation: https://github.com/microsoft/vscode/issues/23924 - Location.create(this.client.toResource(reference.file).toString(), + Location.create(this.client.toResourceUri(reference.file), reference.start.line === reference.end.line ? typeConverters.Range.fromTextSpan(reference) : Range.create( diff --git a/src/features/code-lens/referencesCodeLens.ts b/src/features/code-lens/referencesCodeLens.ts index 9f9e2315..9de4a876 100644 --- a/src/features/code-lens/referencesCodeLens.ts +++ b/src/features/code-lens/referencesCodeLens.ts @@ -47,7 +47,7 @@ export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLens const locations = response.body.refs .filter(reference => !reference.isDefinition) .map(reference => - typeConverters.Location.fromTextSpan(this.client.toResource(reference.file).toString(), reference)); + typeConverters.Location.fromTextSpan(this.client.toResourceUri(reference.file), reference)); codeLens.command = { title: this.getCodeLensLabel(locations), diff --git a/src/features/source-definition.ts b/src/features/source-definition.ts index 13cce73e..a4ffc5d6 100644 --- a/src/features/source-definition.ts +++ b/src/features/source-definition.ts @@ -46,7 +46,7 @@ export class SourceDefinitionCommand { return; } - const document = client.toOpenDocument(client.toResource(file).toString()); + const document = client.toOpenDocument(client.toResourceUri(file)); if (!document) { lspClient.showErrorMessage('Go to Source Definition failed. File not opened in the editor.'); diff --git a/src/lsp-server.ts b/src/lsp-server.ts index 5165a3f7..ef5907d2 100644 --- a/src/lsp-server.ts +++ b/src/lsp-server.ts @@ -147,6 +147,7 @@ export class LspServer { disableAutomaticTypingAcquisition, maxTsServerMemory, npmLocation, + hostInfo, locale, plugins: plugins || [], onEvent: this.onTsEvent.bind(this), @@ -550,7 +551,7 @@ export class LspServer { async completionResolve(item: lsp.CompletionItem, token?: lsp.CancellationToken): Promise { item.data = item.data?.cacheId !== undefined ? this.completionDataCache.get(item.data.cacheId) : item.data; - const uri = this.tsClient.toResource(item.data.file).toString(); + const uri = this.tsClient.toResourceUri(item.data.file); const document = item.data?.file ? this.tsClient.toOpenDocument(uri) : undefined; if (!document) { return item; @@ -636,7 +637,7 @@ export class LspServer { const changes: lsp.WorkspaceEdit['changes'] = {}; result.locs .forEach((spanGroup) => { - const uri = this.tsClient.toResource(spanGroup.file).toString(); + const uri = this.tsClient.toResourceUri(spanGroup.file); const textEdits = changes[uri] || (changes[uri] = []); spanGroup.locs.forEach((textSpan) => { @@ -868,7 +869,7 @@ export class LspServer { if (renameLocation) { await this.options.lspClient.rename({ textDocument: { - uri: this.tsClient.toResource(args.file).toString(), + uri: this.tsClient.toResourceUri(args.file), }, position: Position.fromLocation(renameLocation), }); @@ -878,7 +879,7 @@ export class LspServer { this.tsClient.configurePlugin(pluginName, configuration); } else if (params.command === Commands.ORGANIZE_IMPORTS && params.arguments) { const file = params.arguments[0] as string; - const uri = this.tsClient.toResource(file).toString(); + const uri = this.tsClient.toResourceUri(file); const document = this.tsClient.toOpenDocument(uri); if (!document) { return; @@ -944,7 +945,7 @@ export class LspServer { } const changes: { [uri: string]: lsp.TextEdit[]; } = {}; for (const edit of edits) { - changes[this.tsClient.toResource(edit.fileName).toString()] = edit.textChanges.map(toTextEdit); + changes[this.tsClient.toResourceUri(edit.fileName)] = edit.textChanges.map(toTextEdit); } const { applied } = await this.options.lspClient.applyWorkspaceEdit({ edit: { changes }, @@ -957,7 +958,7 @@ export class LspServer { for (const rename of params.files) { const codeEdits = await this.getEditsForFileRename(rename.oldUri, rename.newUri, token); for (const codeEdit of codeEdits) { - const uri = this.tsClient.toResource(codeEdit.fileName).toString(); + const uri = this.tsClient.toResourceUri(codeEdit.fileName); const textEdits = changes[uri] || (changes[uri] = []); textEdits.push(...codeEdit.textChanges.map(toTextEdit)); } @@ -1061,7 +1062,7 @@ export class LspServer { return response.body.map(item => { return { location: { - uri: this.tsClient.toResource(item.file).toString(), + uri: this.tsClient.toResourceUri(item.file), range: { start: Position.fromLocation(item.start), end: Position.fromLocation(item.end), diff --git a/src/protocol-translation.ts b/src/protocol-translation.ts index 1b239df3..b1b45360 100644 --- a/src/protocol-translation.ts +++ b/src/protocol-translation.ts @@ -12,9 +12,9 @@ import type { ts } from './ts-protocol.js'; import { Position, Range } from './utils/typeConverters.js'; export function toLocation(fileSpan: ts.server.protocol.FileSpan, client: TsClient): lsp.Location { - const uri = client.toResource(fileSpan.file); + const uri = client.toResourceUri(fileSpan.file); return { - uri: uri.toString(), + uri, range: { start: Position.fromLocation(fileSpan.start), end: Position.fromLocation(fileSpan.end), @@ -125,11 +125,11 @@ export function toTextEdit(edit: ts.server.protocol.CodeEdit): lsp.TextEdit { } export function toTextDocumentEdit(change: ts.server.protocol.FileCodeEdits, client: TsClient): lsp.TextDocumentEdit { - const uri = client.toResource(change.fileName); - const document = client.toOpenDocument(uri.toString()); + const uri = client.toResourceUri(change.fileName); + const document = client.toOpenDocument(uri); return { textDocument: { - uri: uri.toString(), + uri, version: document?.version ?? null, }, edits: change.textChanges.map(c => toTextEdit(c)), diff --git a/src/test-utils.ts b/src/test-utils.ts index d705747b..b643f4ba 100644 --- a/src/test-utils.ts +++ b/src/test-utils.ts @@ -204,6 +204,7 @@ interface TestLspServerOptions { rootUri: string | null; publishDiagnostics: (args: lsp.PublishDiagnosticsParams) => void; clientCapabilitiesOverride?: lsp.ClientCapabilities; + initializationOptionsOverrides?: TypeScriptInitializationOptions; } export async function createServer(options: TestLspServerOptions): Promise { @@ -223,7 +224,7 @@ export async function createServer(options: TestLspServerOptions): Promise void; @@ -158,6 +164,7 @@ export class TsClient implements ITypeScriptServiceClient { private readonly logger: Logger; private readonly tsserverLogger: Logger; private readonly loadingIndicator: ServerInitializingIndicator; + private isNeovimHost: boolean = false; private tracer: Tracer | undefined; private workspaceFolders: WorkspaceFolder[] = []; private readonly documents: LspDocuments; @@ -201,7 +208,7 @@ export class TsClient implements ITypeScriptServiceClient { public toTsFilePath(stringUri: string): string | undefined { // Vim may send `zipfile:` URIs which tsserver with Yarn v2+ hook can handle. Keep as-is. // Example: zipfile:///foo/bar/baz.zip::path/to/module - if (stringUri.startsWith('zipfile:')) { + if (this.isNeovimHost && stringUri.startsWith('zipfile:')) { return stringUri; } @@ -215,7 +222,11 @@ export class TsClient implements ITypeScriptServiceClient { return resource.fsPath; } - return undefined; + return inMemoryResourcePrefix + + '/' + resource.scheme + + '/' + (resource.authority || emptyAuthority) + + (resource.path.startsWith('/') ? resource.path : '/' + resource.path) + + (resource.fragment ? '#' + resource.fragment : ''); } public toOpenDocument(textDocumentUri: DocumentUri, options: { suppressAlertOnFailure?: boolean; } = {}): LspDocument | undefined { @@ -245,14 +256,29 @@ export class TsClient implements ITypeScriptServiceClient { public toResource(filepath: string): URI { // Yarn v2+ hooks tsserver and sends `zipfile:` URIs for Vim. Keep as-is. // Example: zipfile:///foo/bar/baz.zip::path/to/module - if (filepath.startsWith('zipfile:')) { - return URI.parse(filepath); + if (this.isNeovimHost && filepath.startsWith('zipfile:')) { + return ZipfileURI.parse(filepath); + } + + if (filepath.startsWith(inMemoryResourcePrefix)) { + const parts = filepath.match(RE_IN_MEMORY_FILEPATH); + if (parts) { + const resource = URI.parse(parts[1] + '://' + (parts[2] === emptyAuthority ? '' : parts[2]) + '/' + parts[3]); + const tsFilepath = this.toTsFilePath(resource.toString()); + const document = tsFilepath && this.documents.get(tsFilepath); + return document ? document.uri : resource; + } } + const fileUri = URI.file(filepath); const document = this.documents.get(fileUri.fsPath); return document ? document.uri : fileUri; } + public toResourceUri(filepath: string): string { + return this.toResource(filepath).toString(); + } + public getWorkspaceRootForResource(resource: URI): URI | undefined { // For notebook cells, we need to use the notebook document to look up the workspace // if (resource.scheme === Schemes.notebookCell) { @@ -303,7 +329,7 @@ export class TsClient implements ITypeScriptServiceClient { switch (capability) { case ClientCapability.Semantic: { - return ['file', 'untitled'].includes(resource.scheme); + return fileSchemes.getSemanticSupportedSchemes().includes(resource.scheme); } case ClientCapability.Syntax: case ClientCapability.EnhancedSyntax: { @@ -324,6 +350,7 @@ export class TsClient implements ITypeScriptServiceClient { ): boolean { this.apiVersion = options.typescriptVersion.version || API.defaultVersion; this.typescriptVersionSource = options.typescriptVersion.source; + this.isNeovimHost = options.hostInfo === 'neovim'; this.tracer = new Tracer(this.tsserverLogger, options.trace); this.workspaceFolders = workspaceRoot ? [{ uri: URI.file(workspaceRoot) }] : []; this.useSyntaxServer = options.useSyntaxServer; diff --git a/src/typescriptService.ts b/src/typescriptService.ts index 7bfad944..465409da 100644 --- a/src/typescriptService.ts +++ b/src/typescriptService.ts @@ -80,6 +80,7 @@ export interface ITypeScriptServiceClient { * Convert a path to a resource. */ toResource(filepath: string): URI; + toResourceUri(filepath: string): string; /** * Tries to ensure that a document is open on the TS server. diff --git a/src/utils/uri.ts b/src/utils/uri.ts new file mode 100644 index 00000000..2c38f5ef --- /dev/null +++ b/src/utils/uri.ts @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { URI } from 'vscode-uri'; + +export class ZipfileURI extends URI { + private _originalUri: string; + + private constructor(uri: string, components: URI) { + super(components); + + this._originalUri = uri; + } + + override toString(_skipEncoding: boolean = false): string { + return this._originalUri; + } + + static override parse(value: string, _strict: boolean = false): ZipfileURI { + const uri = URI.parse(value, _strict); + + return new ZipfileURI(value, uri); + } +} diff --git a/test-data/yarn-pnp/.editorconfig b/test-data/yarn-pnp/.editorconfig new file mode 100644 index 00000000..1ed453a3 --- /dev/null +++ b/test-data/yarn-pnp/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.{js,json,yml}] +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/test-data/yarn-pnp/.gitattributes b/test-data/yarn-pnp/.gitattributes new file mode 100644 index 00000000..af3ad128 --- /dev/null +++ b/test-data/yarn-pnp/.gitattributes @@ -0,0 +1,4 @@ +/.yarn/** linguist-vendored +/.yarn/releases/* binary +/.yarn/plugins/**/* binary +/.pnp.* binary linguist-generated diff --git a/test-data/yarn-pnp/.gitignore b/test-data/yarn-pnp/.gitignore new file mode 100644 index 00000000..870eb6a5 --- /dev/null +++ b/test-data/yarn-pnp/.gitignore @@ -0,0 +1,13 @@ +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Swap the comments on the following lines if you wish to use zero-installs +# In that case, don't forget to run `yarn config set enableGlobalCache false`! +# Documentation here: https://yarnpkg.com/features/caching#zero-installs + +#!.yarn/cache +.pnp.* diff --git a/test-data/yarn-pnp/.vim/coc-settings.json b/test-data/yarn-pnp/.vim/coc-settings.json new file mode 100644 index 00000000..1de47983 --- /dev/null +++ b/test-data/yarn-pnp/.vim/coc-settings.json @@ -0,0 +1,4 @@ +{ + "workspace.workspaceFolderCheckCwd": false, + "tsserver.tsdk": ".yarn/sdks/typescript/lib" +} diff --git a/test-data/yarn-pnp/.yarn/sdks/integrations.yml b/test-data/yarn-pnp/.yarn/sdks/integrations.yml new file mode 100644 index 00000000..231abf42 --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/integrations.yml @@ -0,0 +1,5 @@ +# This file is automatically generated by @yarnpkg/sdks. +# Manual changes might be lost! + +integrations: + - vim diff --git a/test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsc b/test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsc new file mode 100755 index 00000000..454b950b --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsc @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/bin/tsc + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/bin/tsc your application uses +module.exports = absRequire(`typescript/bin/tsc`); diff --git a/test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsserver b/test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsserver new file mode 100755 index 00000000..d7a60568 --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/typescript/bin/tsserver @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/bin/tsserver + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/bin/tsserver your application uses +module.exports = absRequire(`typescript/bin/tsserver`); diff --git a/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsc.js b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsc.js new file mode 100644 index 00000000..2f62fc96 --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsc.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsc.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/lib/tsc.js your application uses +module.exports = absRequire(`typescript/lib/tsc.js`); diff --git a/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserver.js b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserver.js new file mode 100644 index 00000000..bbb1e465 --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserver.js @@ -0,0 +1,225 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +const moduleWrapper = tsserver => { + if (!process.versions.pnp) { + return tsserver; + } + + const {isAbsolute} = require(`path`); + const pnpApi = require(`pnpapi`); + + const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); + const isPortal = str => str.startsWith("portal:/"); + const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); + + const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { + return `${locator.name}@${locator.reference}`; + })); + + // VSCode sends the zip paths to TS using the "zip://" prefix, that TS + // doesn't understand. This layer makes sure to remove the protocol + // before forwarding it to TS, and to add it back on all returned paths. + + function toEditorPath(str) { + // We add the `zip:` prefix to both `.zip/` paths and virtual paths + if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { + // We also take the opportunity to turn virtual paths into physical ones; + // this makes it much easier to work with workspaces that list peer + // dependencies, since otherwise Ctrl+Click would bring us to the virtual + // file instances instead of the real ones. + // + // We only do this to modules owned by the the dependency tree roots. + // This avoids breaking the resolution when jumping inside a vendor + // with peer dep (otherwise jumping into react-dom would show resolution + // errors on react). + // + const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; + if (resolved) { + const locator = pnpApi.findPackageLocator(resolved); + if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { + str = resolved; + } + } + + str = normalize(str); + + if (str.match(/\.zip\//)) { + switch (hostInfo) { + // Absolute VSCode `Uri.fsPath`s need to start with a slash. + // VSCode only adds it automatically for supported schemes, + // so we have to do it manually for the `zip` scheme. + // The path needs to start with a caret otherwise VSCode doesn't handle the protocol + // + // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 + // + // 2021-10-08: VSCode changed the format in 1.61. + // Before | ^zip:/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + // 2022-04-06: VSCode changed the format in 1.66. + // Before | ^/zip//c:/foo/bar.zip/package.json + // After | ^/zip/c:/foo/bar.zip/package.json + // + // 2022-05-06: VSCode changed the format in 1.68 + // Before | ^/zip/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + case `vscode <1.61`: { + str = `^zip:${str}`; + } break; + + case `vscode <1.66`: { + str = `^/zip/${str}`; + } break; + + case `vscode <1.68`: { + str = `^/zip${str}`; + } break; + + case `vscode`: { + str = `^/zip/${str}`; + } break; + + // To make "go to definition" work, + // We have to resolve the actual file system path from virtual path + // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) + case `coc-nvim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = resolve(`zipfile:${str}`); + } break; + + // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) + // We have to resolve the actual file system path from virtual path, + // everything else is up to neovim + case `neovim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = `zipfile://${str}`; + } break; + + default: { + str = `zip:${str}`; + } break; + } + } else { + str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); + } + } + + return str; + } + + function fromEditorPath(str) { + switch (hostInfo) { + case `coc-nvim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for coc-nvim is in format of //zipfile://.yarn/... + // So in order to convert it back, we use .* to match all the thing + // before `zipfile:` + return process.platform === `win32` + ? str.replace(/^.*zipfile:\//, ``) + : str.replace(/^.*zipfile:/, ``); + } break; + + case `neovim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for neovim is in format of zipfile:////.yarn/... + return str.replace(/^zipfile:\/\//, ``); + } break; + + case `vscode`: + default: { + return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) + } break; + } + } + + // Force enable 'allowLocalPluginLoads' + // TypeScript tries to resolve plugins using a path relative to itself + // which doesn't work when using the global cache + // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 + // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but + // TypeScript already does local loads and if this code is running the user trusts the workspace + // https://github.com/microsoft/vscode/issues/45856 + const ConfiguredProject = tsserver.server.ConfiguredProject; + const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; + ConfiguredProject.prototype.enablePluginsWithOptions = function() { + this.projectService.allowLocalPluginLoads = true; + return originalEnablePluginsWithOptions.apply(this, arguments); + }; + + // And here is the point where we hijack the VSCode <-> TS communications + // by adding ourselves in the middle. We locate everything that looks + // like an absolute path of ours and normalize it. + + const Session = tsserver.server.Session; + const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; + let hostInfo = `unknown`; + + Object.assign(Session.prototype, { + onMessage(/** @type {string | object} */ message) { + const isStringMessage = typeof message === 'string'; + const parsedMessage = isStringMessage ? JSON.parse(message) : message; + + if ( + parsedMessage != null && + typeof parsedMessage === `object` && + parsedMessage.arguments && + typeof parsedMessage.arguments.hostInfo === `string` + ) { + hostInfo = parsedMessage.arguments.hostInfo; + if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { + const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( + // The RegExp from https://semver.org/ but without the caret at the start + /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ + ) ?? []).map(Number) + + if (major === 1) { + if (minor < 61) { + hostInfo += ` <1.61`; + } else if (minor < 66) { + hostInfo += ` <1.66`; + } else if (minor < 68) { + hostInfo += ` <1.68`; + } + } + } + } + + const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { + return typeof value === 'string' ? fromEditorPath(value) : value; + }); + + return originalOnMessage.call( + this, + isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) + ); + }, + + send(/** @type {any} */ msg) { + return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { + return typeof value === `string` ? toEditorPath(value) : value; + }))); + } + }); + + return tsserver; +}; + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsserver.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/lib/tsserver.js your application uses +module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`)); diff --git a/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserverlibrary.js b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserverlibrary.js new file mode 100644 index 00000000..a68f028f --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/tsserverlibrary.js @@ -0,0 +1,225 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +const moduleWrapper = tsserver => { + if (!process.versions.pnp) { + return tsserver; + } + + const {isAbsolute} = require(`path`); + const pnpApi = require(`pnpapi`); + + const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); + const isPortal = str => str.startsWith("portal:/"); + const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); + + const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { + return `${locator.name}@${locator.reference}`; + })); + + // VSCode sends the zip paths to TS using the "zip://" prefix, that TS + // doesn't understand. This layer makes sure to remove the protocol + // before forwarding it to TS, and to add it back on all returned paths. + + function toEditorPath(str) { + // We add the `zip:` prefix to both `.zip/` paths and virtual paths + if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { + // We also take the opportunity to turn virtual paths into physical ones; + // this makes it much easier to work with workspaces that list peer + // dependencies, since otherwise Ctrl+Click would bring us to the virtual + // file instances instead of the real ones. + // + // We only do this to modules owned by the the dependency tree roots. + // This avoids breaking the resolution when jumping inside a vendor + // with peer dep (otherwise jumping into react-dom would show resolution + // errors on react). + // + const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; + if (resolved) { + const locator = pnpApi.findPackageLocator(resolved); + if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) { + str = resolved; + } + } + + str = normalize(str); + + if (str.match(/\.zip\//)) { + switch (hostInfo) { + // Absolute VSCode `Uri.fsPath`s need to start with a slash. + // VSCode only adds it automatically for supported schemes, + // so we have to do it manually for the `zip` scheme. + // The path needs to start with a caret otherwise VSCode doesn't handle the protocol + // + // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 + // + // 2021-10-08: VSCode changed the format in 1.61. + // Before | ^zip:/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + // 2022-04-06: VSCode changed the format in 1.66. + // Before | ^/zip//c:/foo/bar.zip/package.json + // After | ^/zip/c:/foo/bar.zip/package.json + // + // 2022-05-06: VSCode changed the format in 1.68 + // Before | ^/zip/c:/foo/bar.zip/package.json + // After | ^/zip//c:/foo/bar.zip/package.json + // + case `vscode <1.61`: { + str = `^zip:${str}`; + } break; + + case `vscode <1.66`: { + str = `^/zip/${str}`; + } break; + + case `vscode <1.68`: { + str = `^/zip${str}`; + } break; + + case `vscode`: { + str = `^/zip/${str}`; + } break; + + // To make "go to definition" work, + // We have to resolve the actual file system path from virtual path + // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) + case `coc-nvim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = resolve(`zipfile:${str}`); + } break; + + // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) + // We have to resolve the actual file system path from virtual path, + // everything else is up to neovim + case `neovim`: { + str = normalize(resolved).replace(/\.zip\//, `.zip::`); + str = `zipfile://${str}`; + } break; + + default: { + str = `zip:${str}`; + } break; + } + } else { + str = str.replace(/^\/?/, process.platform === `win32` ? `` : `/`); + } + } + + return str; + } + + function fromEditorPath(str) { + switch (hostInfo) { + case `coc-nvim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for coc-nvim is in format of //zipfile://.yarn/... + // So in order to convert it back, we use .* to match all the thing + // before `zipfile:` + return process.platform === `win32` + ? str.replace(/^.*zipfile:\//, ``) + : str.replace(/^.*zipfile:/, ``); + } break; + + case `neovim`: { + str = str.replace(/\.zip::/, `.zip/`); + // The path for neovim is in format of zipfile:////.yarn/... + return str.replace(/^zipfile:\/\//, ``); + } break; + + case `vscode`: + default: { + return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`) + } break; + } + } + + // Force enable 'allowLocalPluginLoads' + // TypeScript tries to resolve plugins using a path relative to itself + // which doesn't work when using the global cache + // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 + // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but + // TypeScript already does local loads and if this code is running the user trusts the workspace + // https://github.com/microsoft/vscode/issues/45856 + const ConfiguredProject = tsserver.server.ConfiguredProject; + const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; + ConfiguredProject.prototype.enablePluginsWithOptions = function() { + this.projectService.allowLocalPluginLoads = true; + return originalEnablePluginsWithOptions.apply(this, arguments); + }; + + // And here is the point where we hijack the VSCode <-> TS communications + // by adding ourselves in the middle. We locate everything that looks + // like an absolute path of ours and normalize it. + + const Session = tsserver.server.Session; + const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; + let hostInfo = `unknown`; + + Object.assign(Session.prototype, { + onMessage(/** @type {string | object} */ message) { + const isStringMessage = typeof message === 'string'; + const parsedMessage = isStringMessage ? JSON.parse(message) : message; + + if ( + parsedMessage != null && + typeof parsedMessage === `object` && + parsedMessage.arguments && + typeof parsedMessage.arguments.hostInfo === `string` + ) { + hostInfo = parsedMessage.arguments.hostInfo; + if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) { + const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match( + // The RegExp from https://semver.org/ but without the caret at the start + /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ + ) ?? []).map(Number) + + if (major === 1) { + if (minor < 61) { + hostInfo += ` <1.61`; + } else if (minor < 66) { + hostInfo += ` <1.66`; + } else if (minor < 68) { + hostInfo += ` <1.68`; + } + } + } + } + + const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => { + return typeof value === 'string' ? fromEditorPath(value) : value; + }); + + return originalOnMessage.call( + this, + isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON) + ); + }, + + send(/** @type {any} */ msg) { + return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { + return typeof value === `string` ? toEditorPath(value) : value; + }))); + } + }); + + return tsserver; +}; + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript/lib/tsserverlibrary.js + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript/lib/tsserverlibrary.js your application uses +module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`)); diff --git a/test-data/yarn-pnp/.yarn/sdks/typescript/lib/typescript.js b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/typescript.js new file mode 100644 index 00000000..b5f4db25 --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/typescript/lib/typescript.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node + +const {existsSync} = require(`fs`); +const {createRequire} = require(`module`); +const {resolve} = require(`path`); + +const relPnpApiPath = "../../../../.pnp.cjs"; + +const absPnpApiPath = resolve(__dirname, relPnpApiPath); +const absRequire = createRequire(absPnpApiPath); + +if (existsSync(absPnpApiPath)) { + if (!process.versions.pnp) { + // Setup the environment to be able to require typescript + require(absPnpApiPath).setup(); + } +} + +// Defer to the real typescript your application uses +module.exports = absRequire(`typescript`); diff --git a/test-data/yarn-pnp/.yarn/sdks/typescript/package.json b/test-data/yarn-pnp/.yarn/sdks/typescript/package.json new file mode 100644 index 00000000..eb7dd745 --- /dev/null +++ b/test-data/yarn-pnp/.yarn/sdks/typescript/package.json @@ -0,0 +1,10 @@ +{ + "name": "typescript", + "version": "5.3.3-sdk", + "main": "./lib/typescript.js", + "type": "commonjs", + "bin": { + "tsc": "./bin/tsc", + "tsserver": "./bin/tsserver" + } +} diff --git a/test-data/yarn-pnp/README.md b/test-data/yarn-pnp/README.md new file mode 100644 index 00000000..1da79178 --- /dev/null +++ b/test-data/yarn-pnp/README.md @@ -0,0 +1 @@ +# yarn2 diff --git a/test-data/yarn-pnp/package.json b/test-data/yarn-pnp/package.json new file mode 100644 index 00000000..a2b5b132 --- /dev/null +++ b/test-data/yarn-pnp/package.json @@ -0,0 +1,8 @@ +{ + "name": "yarn2", + "packageManager": "yarn@4.0.2", + "dependencies": { + "axios": "1.6.7", + "typescript": "^5.3.3" + } +} diff --git a/test-data/yarn-pnp/testfile.ts b/test-data/yarn-pnp/testfile.ts new file mode 100644 index 00000000..f51c9a65 --- /dev/null +++ b/test-data/yarn-pnp/testfile.ts @@ -0,0 +1 @@ +import type { AxiosHeaderValue } from 'axios'; diff --git a/test-data/yarn-pnp/tsconfig.json b/test-data/yarn-pnp/tsconfig.json new file mode 100644 index 00000000..55eb65d8 --- /dev/null +++ b/test-data/yarn-pnp/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "module": "ES2022", + "moduleResolution": "Node16" + }, +} diff --git a/test-data/yarn-pnp/yarn.lock b/test-data/yarn-pnp/yarn.lock new file mode 100644 index 00000000..e9c72b00 --- /dev/null +++ b/test-data/yarn-pnp/yarn.lock @@ -0,0 +1,113 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d + languageName: node + linkType: hard + +"axios@npm:1.6.7": + version: 1.6.7 + resolution: "axios@npm:1.6.7" + dependencies: + follow-redirects: "npm:^1.15.4" + form-data: "npm:^4.0.0" + proxy-from-env: "npm:^1.1.0" + checksum: 131bf8e62eee48ca4bd84e6101f211961bf6a21a33b95e5dfb3983d5a2fe50d9fffde0b57668d7ce6f65063d3dc10f2212cbcb554f75cfca99da1c73b210358d + languageName: node + linkType: hard + +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: "npm:~1.0.0" + checksum: 0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + languageName: node + linkType: hard + +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 + languageName: node + linkType: hard + +"follow-redirects@npm:^1.15.4": + version: 1.15.5 + resolution: "follow-redirects@npm:1.15.5" + peerDependenciesMeta: + debug: + optional: true + checksum: 418d71688ceaf109dfd6f85f747a0c75de30afe43a294caa211def77f02ef19865b547dfb73fde82b751e1cc507c06c754120b848fe5a7400b0a669766df7615 + languageName: node + linkType: hard + +"form-data@npm:^4.0.0": + version: 4.0.0 + resolution: "form-data@npm:4.0.0" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + mime-types: "npm:^2.1.12" + checksum: cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: "npm:1.52.0" + checksum: 82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + languageName: node + linkType: hard + +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b + languageName: node + linkType: hard + +"typescript@npm:^5.3.3": + version: 5.3.3 + resolution: "typescript@npm:5.3.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: e33cef99d82573624fc0f854a2980322714986bc35b9cb4d1ce736ed182aeab78e2cb32b385efa493b2a976ef52c53e20d6c6918312353a91850e2b76f1ea44f + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^5.3.3#optional!builtin": + version: 5.3.3 + resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin::version=5.3.3&hash=e012d7" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 1d0a5f4ce496c42caa9a30e659c467c5686eae15d54b027ee7866744952547f1be1262f2d40de911618c242b510029d51d43ff605dba8fb740ec85ca2d3f9500 + languageName: node + linkType: hard + +"yarn2@workspace:.": + version: 0.0.0-use.local + resolution: "yarn2@workspace:." + dependencies: + axios: "npm:1.6.7" + typescript: "npm:^5.3.3" + languageName: unknown + linkType: soft From 1942411804c84702519723f7329aa2f2fd341cdf Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Thu, 1 Feb 2024 00:10:20 +0100 Subject: [PATCH 2/6] corepack enable --- .github/workflows/ci.yaml | 1 + .github/workflows/release.yaml | 1 + .github/workflows/size-limit.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b0443fdf..1df21369 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,7 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: yarn + - run: corepack enable - name: yarn install run: yarn - name: build diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a7a3cf96..6aafcb0c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -21,6 +21,7 @@ jobs: with: node-version: 18 registry-url: https://registry.npmjs.org + - run: corepack enable - name: Lint and Test if: ${{ steps.release.outputs.release_created }} run: yarn && yarn build && yarn lint diff --git a/.github/workflows/size-limit.yaml b/.github/workflows/size-limit.yaml index 4be381e1..7befd7c1 100644 --- a/.github/workflows/size-limit.yaml +++ b/.github/workflows/size-limit.yaml @@ -24,6 +24,7 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: yarn + - run: corepack enable - name: yarn install run: yarn - name: build From a4a5642a81306a0c8a3923980d4189497dc417e1 Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Thu, 1 Feb 2024 00:22:01 +0100 Subject: [PATCH 3/6] trying --- .github/workflows/ci.yaml | 2 +- src/configuration/fileSchemes.test.ts | 2 +- test-data/yarn-pnp/package.json | 2 +- test-data/yarn-pnp/yarn.lock | 22 +++++++++++----------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1df21369..8ac68bae 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,12 +22,12 @@ jobs: name: ${{ matrix.os }} (Node.js ${{ matrix.node-version }}) steps: - uses: actions/checkout@v4 + - run: corepack enable - name: Setup node uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: yarn - - run: corepack enable - name: yarn install run: yarn - name: build diff --git a/src/configuration/fileSchemes.test.ts b/src/configuration/fileSchemes.test.ts index b32d399a..2f1d859f 100644 --- a/src/configuration/fileSchemes.test.ts +++ b/src/configuration/fileSchemes.test.ts @@ -46,7 +46,7 @@ describe('zipfileuri handling', () => { }); }); -describe('nevim zipfile scheme handling with yarn pnp', () => { +describe('neovim zipfile scheme handling with yarn pnp', () => { let server: TestLspServer; beforeAll(async () => { diff --git a/test-data/yarn-pnp/package.json b/test-data/yarn-pnp/package.json index a2b5b132..3588b15f 100644 --- a/test-data/yarn-pnp/package.json +++ b/test-data/yarn-pnp/package.json @@ -1,6 +1,6 @@ { "name": "yarn2", - "packageManager": "yarn@4.0.2", + "packageManager": "yarn@4.1.0", "dependencies": { "axios": "1.6.7", "typescript": "^5.3.3" diff --git a/test-data/yarn-pnp/yarn.lock b/test-data/yarn-pnp/yarn.lock index e9c72b00..25f5791c 100644 --- a/test-data/yarn-pnp/yarn.lock +++ b/test-data/yarn-pnp/yarn.lock @@ -8,7 +8,7 @@ __metadata: "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" - checksum: d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d + checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d languageName: node linkType: hard @@ -19,7 +19,7 @@ __metadata: follow-redirects: "npm:^1.15.4" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: 131bf8e62eee48ca4bd84e6101f211961bf6a21a33b95e5dfb3983d5a2fe50d9fffde0b57668d7ce6f65063d3dc10f2212cbcb554f75cfca99da1c73b210358d + checksum: 10c0/131bf8e62eee48ca4bd84e6101f211961bf6a21a33b95e5dfb3983d5a2fe50d9fffde0b57668d7ce6f65063d3dc10f2212cbcb554f75cfca99da1c73b210358d languageName: node linkType: hard @@ -28,14 +28,14 @@ __metadata: resolution: "combined-stream@npm:1.0.8" dependencies: delayed-stream: "npm:~1.0.0" - checksum: 0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 + checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 languageName: node linkType: hard "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" - checksum: d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 + checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 languageName: node linkType: hard @@ -45,7 +45,7 @@ __metadata: peerDependenciesMeta: debug: optional: true - checksum: 418d71688ceaf109dfd6f85f747a0c75de30afe43a294caa211def77f02ef19865b547dfb73fde82b751e1cc507c06c754120b848fe5a7400b0a669766df7615 + checksum: 10c0/418d71688ceaf109dfd6f85f747a0c75de30afe43a294caa211def77f02ef19865b547dfb73fde82b751e1cc507c06c754120b848fe5a7400b0a669766df7615 languageName: node linkType: hard @@ -56,14 +56,14 @@ __metadata: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e + checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e languageName: node linkType: hard "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" - checksum: 0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa languageName: node linkType: hard @@ -72,14 +72,14 @@ __metadata: resolution: "mime-types@npm:2.1.35" dependencies: mime-db: "npm:1.52.0" - checksum: 82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 languageName: node linkType: hard "proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" - checksum: fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b + checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b languageName: node linkType: hard @@ -89,7 +89,7 @@ __metadata: bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: e33cef99d82573624fc0f854a2980322714986bc35b9cb4d1ce736ed182aeab78e2cb32b385efa493b2a976ef52c53e20d6c6918312353a91850e2b76f1ea44f + checksum: 10c0/e33cef99d82573624fc0f854a2980322714986bc35b9cb4d1ce736ed182aeab78e2cb32b385efa493b2a976ef52c53e20d6c6918312353a91850e2b76f1ea44f languageName: node linkType: hard @@ -99,7 +99,7 @@ __metadata: bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 1d0a5f4ce496c42caa9a30e659c467c5686eae15d54b027ee7866744952547f1be1262f2d40de911618c242b510029d51d43ff605dba8fb740ec85ca2d3f9500 + checksum: 10c0/1d0a5f4ce496c42caa9a30e659c467c5686eae15d54b027ee7866744952547f1be1262f2d40de911618c242b510029d51d43ff605dba8fb740ec85ca2d3f9500 languageName: node linkType: hard From 64b55798e5fcdfded026cca8eba164aafee06739 Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Thu, 1 Feb 2024 00:25:43 +0100 Subject: [PATCH 4/6] no cache --- .github/workflows/ci.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8ac68bae..b968db8b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,12 +22,11 @@ jobs: name: ${{ matrix.os }} (Node.js ${{ matrix.node-version }}) steps: - uses: actions/checkout@v4 - - run: corepack enable - name: Setup node uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: yarn + - run: corepack enable - name: yarn install run: yarn - name: build From d6d76b0b0c6cd494ebfa1a56cd8dfd586a8aa9e1 Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Thu, 1 Feb 2024 00:34:52 +0100 Subject: [PATCH 5/6] fix? --- .github/workflows/ci.yaml | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b968db8b..c3b340e7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -26,9 +26,12 @@ jobs: uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} + cache: yarn - run: corepack enable - name: yarn install run: yarn + - name: prepare yarnpnp + run: cd test-data/yarn-pnp && yarn - name: build run: yarn build - name: Unittest diff --git a/package.json b/package.json index 5efd9f3d..19613757 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "fix": "eslint --ext \".js,.ts\" --fix src", "size": "yarn build && yarn size-limit", "postversion": "git push --follow-tags", - "prepare": "cd test-data/jsx && yarn && cd ../yarn-pnp && yarn" + "prepare": "cd test-data/jsx && yarn" }, "eslintIgnore": [ "!.eslintrc.cjs" From 4ae990e3207d0035357958870b23c969d211544c Mon Sep 17 00:00:00 2001 From: Rafal Chlodnicki Date: Thu, 1 Feb 2024 00:42:56 +0100 Subject: [PATCH 6/6] fix windows --- src/configuration/fileSchemes.test.ts | 6 +++--- src/test-utils.ts | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/configuration/fileSchemes.test.ts b/src/configuration/fileSchemes.test.ts index 2f1d859f..193e3404 100644 --- a/src/configuration/fileSchemes.test.ts +++ b/src/configuration/fileSchemes.test.ts @@ -1,7 +1,7 @@ import { URI } from 'vscode-uri'; import * as lsp from 'vscode-languageserver'; import { beforeAll, beforeEach, afterAll, describe, it, expect } from 'vitest'; -import { uri, createServer, position, TestLspServer, openDocumentAndWaitForDiagnostics, readContents, filePath } from '../test-utils.js'; +import { uri, createServer, position, TestLspServer, openDocumentAndWaitForDiagnostics, readContents, filePath, isWindows } from '../test-utils.js'; import { ZipfileURI } from '../utils/uri.js'; const ZIPFILE_URI = 'zipfile:///dir/foo.zip::path/file.ts'; @@ -12,7 +12,7 @@ describe('uri handling', () => { expect(parsed.scheme).toBe('zipfile'); expect(parsed.authority).toBe(''); expect(parsed.path).toBe('/dir/foo.zip::path/file.ts'); - expect(parsed.fsPath).toBe('/dir/foo.zip::path/file.ts'); + expect(parsed.fsPath).toBe(isWindows ? '\\dir\\foo.zip::path\\file.ts' : '/dir/foo.zip::path/file.ts'); expect(parsed.query).toBe(''); expect(parsed.fragment).toBe(''); }); @@ -34,7 +34,7 @@ describe('zipfileuri handling', () => { expect(parsed.scheme).toBe('zipfile'); expect(parsed.authority).toBe(''); expect(parsed.path).toBe('/dir/foo.zip::path/file.ts'); - expect(parsed.fsPath).toBe('/dir/foo.zip::path/file.ts'); + expect(parsed.fsPath).toBe(isWindows ? '\\dir\\foo.zip::path\\file.ts' : '/dir/foo.zip::path/file.ts'); expect(parsed.query).toBe(''); expect(parsed.fragment).toBe(''); }); diff --git a/src/test-utils.ts b/src/test-utils.ts index b643f4ba..702ddb6e 100644 --- a/src/test-utils.ts +++ b/src/test-utils.ts @@ -72,6 +72,8 @@ const DEFAULT_TEST_CLIENT_INITIALIZATION_OPTIONS: TypeScriptInitializationOption const DEFAULT_WORKSPACE_SETTINGS: WorkspaceConfiguration = {}; +export const isWindows = process.platform === 'win32'; + export async function openDocumentAndWaitForDiagnostics(server: TestLspServer, textDocument: lsp.TextDocumentItem): Promise { server.didOpenTextDocument({ textDocument }); await server.waitForDiagnosticsForFile(textDocument.uri); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy