Skip to content

Commit b34a8f5

Browse files
committed
chore: update Yarn editor sdks
1 parent 1b49eb6 commit b34a8f5

File tree

12 files changed

+345
-36
lines changed

12 files changed

+345
-36
lines changed

.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"eslint.nodePath": ".yarn/sdks",
33
"typescript.tsdk": ".yarn/sdks/typescript/lib",
4-
"typescript.enablePromptUseWorkspaceTsdk": true
4+
"typescript.enablePromptUseWorkspaceTsdk": true,
5+
"search.exclude": {
6+
"**/.yarn": true,
7+
"**/.pnp.*": true
8+
}
59
}

.yarn/sdks/eslint/bin/eslint.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const {existsSync} = require(`fs`);
44
const {createRequire, createRequireFromPath} = require(`module`);
55
const {resolve} = require(`path`);
66

7-
const relPnpApiPath = "../../../../.pnp.js";
7+
const relPnpApiPath = "../../../../.pnp.cjs";
88

99
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
1010
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);

.yarn/sdks/eslint/lib/api.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const {existsSync} = require(`fs`);
44
const {createRequire, createRequireFromPath} = require(`module`);
55
const {resolve} = require(`path`);
66

7-
const relPnpApiPath = "../../../../.pnp.js";
7+
const relPnpApiPath = "../../../../.pnp.cjs";
88

99
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
1010
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);

.yarn/sdks/eslint/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint",
3-
"version": "7.7.0-pnpify",
3+
"version": "8.1.0-sdk",
44
"main": "./lib/api.js",
55
"type": "commonjs"
6-
}
6+
}

.yarn/sdks/integrations.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# This file is automatically generated by PnPify.
2-
# Manual changes will be lost!
1+
# This file is automatically generated by @yarnpkg/sdks.
2+
# Manual changes might be lost!
33

44
integrations:
55
- vscode

.yarn/sdks/typescript/bin/tsc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const {existsSync} = require(`fs`);
44
const {createRequire, createRequireFromPath} = require(`module`);
55
const {resolve} = require(`path`);
66

7-
const relPnpApiPath = "../../../../.pnp.js";
7+
const relPnpApiPath = "../../../../.pnp.cjs";
88

99
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
1010
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);

.yarn/sdks/typescript/bin/tsserver

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const {existsSync} = require(`fs`);
44
const {createRequire, createRequireFromPath} = require(`module`);
55
const {resolve} = require(`path`);
66

7-
const relPnpApiPath = "../../../../.pnp.js";
7+
const relPnpApiPath = "../../../../.pnp.cjs";
88

99
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
1010
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);

.yarn/sdks/typescript/lib/tsc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const {existsSync} = require(`fs`);
44
const {createRequire, createRequireFromPath} = require(`module`);
55
const {resolve} = require(`path`);
66

7-
const relPnpApiPath = "../../../../.pnp.js";
7+
const relPnpApiPath = "../../../../.pnp.cjs";
88

99
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
1010
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);

.yarn/sdks/typescript/lib/tsserver.js

Lines changed: 144 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,173 @@ const {existsSync} = require(`fs`);
44
const {createRequire, createRequireFromPath} = require(`module`);
55
const {resolve} = require(`path`);
66

7-
const relPnpApiPath = "../../../../.pnp.js";
7+
const relPnpApiPath = "../../../../.pnp.cjs";
88

99
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
1010
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
1111

1212
const moduleWrapper = tsserver => {
13+
if (!process.versions.pnp) {
14+
return tsserver;
15+
}
16+
17+
const {isAbsolute} = require(`path`);
18+
const pnpApi = require(`pnpapi`);
19+
20+
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
21+
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
22+
23+
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
24+
return `${locator.name}@${locator.reference}`;
25+
}));
26+
1327
// VSCode sends the zip paths to TS using the "zip://" prefix, that TS
1428
// doesn't understand. This layer makes sure to remove the protocol
1529
// before forwarding it to TS, and to add it back on all returned paths.
1630

17-
const {isAbsolute} = require(`path`);
31+
function toEditorPath(str) {
32+
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
33+
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
34+
// We also take the opportunity to turn virtual paths into physical ones;
35+
// this makes it much easier to work with workspaces that list peer
36+
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
37+
// file instances instead of the real ones.
38+
//
39+
// We only do this to modules owned by the the dependency tree roots.
40+
// This avoids breaking the resolution when jumping inside a vendor
41+
// with peer dep (otherwise jumping into react-dom would show resolution
42+
// errors on react).
43+
//
44+
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
45+
if (resolved) {
46+
const locator = pnpApi.findPackageLocator(resolved);
47+
if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
48+
str = resolved;
49+
}
50+
}
51+
52+
str = normalize(str);
53+
54+
if (str.match(/\.zip\//)) {
55+
switch (hostInfo) {
56+
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
57+
// VSCode only adds it automatically for supported schemes,
58+
// so we have to do it manually for the `zip` scheme.
59+
// The path needs to start with a caret otherwise VSCode doesn't handle the protocol
60+
//
61+
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
62+
//
63+
// Update Oct 8 2021: VSCode changed their format in 1.61.
64+
// Before | ^zip:/c:/foo/bar.zip/package.json
65+
// After | ^/zip//c:/foo/bar.zip/package.json
66+
//
67+
case `vscode <1.61`: {
68+
str = `^zip:${str}`;
69+
} break;
70+
71+
case `vscode`: {
72+
str = `^/zip/${str}`;
73+
} break;
74+
75+
// To make "go to definition" work,
76+
// We have to resolve the actual file system path from virtual path
77+
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
78+
case `coc-nvim`: {
79+
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
80+
str = resolve(`zipfile:${str}`);
81+
} break;
82+
83+
// Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
84+
// We have to resolve the actual file system path from virtual path,
85+
// everything else is up to neovim
86+
case `neovim`: {
87+
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
88+
str = `zipfile:${str}`;
89+
} break;
90+
91+
default: {
92+
str = `zip:${str}`;
93+
} break;
94+
}
95+
}
96+
}
97+
98+
return str;
99+
}
100+
101+
function fromEditorPath(str) {
102+
switch (hostInfo) {
103+
case `coc-nvim`:
104+
case `neovim`: {
105+
str = str.replace(/\.zip::/, `.zip/`);
106+
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
107+
// So in order to convert it back, we use .* to match all the thing
108+
// before `zipfile:`
109+
return process.platform === `win32`
110+
? str.replace(/^.*zipfile:\//, ``)
111+
: str.replace(/^.*zipfile:/, ``);
112+
} break;
113+
114+
case `vscode`:
115+
default: {
116+
return process.platform === `win32`
117+
? str.replace(/^\^?(zip:|\/zip)\/+/, ``)
118+
: str.replace(/^\^?(zip:|\/zip)\/+/, `/`);
119+
} break;
120+
}
121+
}
122+
123+
// Force enable 'allowLocalPluginLoads'
124+
// TypeScript tries to resolve plugins using a path relative to itself
125+
// which doesn't work when using the global cache
126+
// https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
127+
// VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
128+
// TypeScript already does local loads and if this code is running the user trusts the workspace
129+
// https://github.com/microsoft/vscode/issues/45856
130+
const ConfiguredProject = tsserver.server.ConfiguredProject;
131+
const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
132+
ConfiguredProject.prototype.enablePluginsWithOptions = function() {
133+
this.projectService.allowLocalPluginLoads = true;
134+
return originalEnablePluginsWithOptions.apply(this, arguments);
135+
};
136+
137+
// And here is the point where we hijack the VSCode <-> TS communications
138+
// by adding ourselves in the middle. We locate everything that looks
139+
// like an absolute path of ours and normalize it.
18140

19141
const Session = tsserver.server.Session;
20142
const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
143+
let hostInfo = `unknown`;
21144

22-
return Object.assign(Session.prototype, {
145+
Object.assign(Session.prototype, {
23146
onMessage(/** @type {string} */ message) {
24-
return originalOnMessage.call(this, JSON.stringify(JSON.parse(message), (key, value) => {
25-
return typeof value === 'string' ? removeZipPrefix(value) : value;
147+
const parsedMessage = JSON.parse(message)
148+
149+
if (
150+
parsedMessage != null &&
151+
typeof parsedMessage === `object` &&
152+
parsedMessage.arguments &&
153+
typeof parsedMessage.arguments.hostInfo === `string`
154+
) {
155+
hostInfo = parsedMessage.arguments.hostInfo;
156+
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK && process.env.VSCODE_IPC_HOOK.match(/Code\/1\.([1-5][0-9]|60)\./)) {
157+
hostInfo += ` <1.61`;
158+
}
159+
}
160+
161+
return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {
162+
return typeof value === `string` ? fromEditorPath(value) : value;
26163
}));
27164
},
28165

29166
send(/** @type {any} */ msg) {
30167
return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
31-
return typeof value === 'string' ? addZipPrefix(value) : value;
168+
return typeof value === `string` ? toEditorPath(value) : value;
32169
})));
33170
}
34171
});
35172

36-
function addZipPrefix(str) {
37-
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
38-
if (isAbsolute(str) && !str.match(/^zip:/) && (str.match(/\.zip\//) || str.match(/\$\$virtual\//))) {
39-
// Absolute VSCode `Uri.fsPath`s need to start with a slash.
40-
// VSCode only adds it automatically for supported schemes,
41-
// so we have to do it manually for the `zip` scheme.
42-
return `zip:${str.replace(/^\/?/, `/`)}`;
43-
} else {
44-
return str;
45-
}
46-
}
47-
48-
function removeZipPrefix(str) {
49-
return process.platform === 'win32'
50-
? str.replace(/^zip:\//, ``)
51-
: str.replace(/^zip:/, ``);
52-
}
173+
return tsserver;
53174
};
54175

55176
if (existsSync(absPnpApiPath)) {

0 commit comments

Comments
 (0)