Allow plugins to be loaded from package subpaths (#57266)

Co-authored-by: Sheetal Nandi <sheetalkamat@users.noreply.github.com>
This commit is contained in:
Phil Pluckthun
2024-02-21 21:55:47 +00:00
committed by GitHub
parent 1c0fd31223
commit ef091bf755
4 changed files with 122 additions and 6 deletions

View File

@@ -66,6 +66,7 @@ import {
IncompleteCompletionsCache,
IndentStyle,
isArray,
isExternalModuleNameRelative,
isIgnoredFileFromWildCardWatching,
isInsideNodeModules,
isJsonEqual,
@@ -90,7 +91,6 @@ import {
ParsedCommandLine,
parseJsonSourceFileConfigFileContent,
parseJsonText,
parsePackageName,
Path,
PerformanceEvent,
PluginImport,
@@ -4474,7 +4474,11 @@ export class ProjectService {
}
this.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`);
if (!pluginConfigEntry.name || parsePackageName(pluginConfigEntry.name).rest) {
if (
!pluginConfigEntry.name ||
isExternalModuleNameRelative(pluginConfigEntry.name) ||
/[\\/]\.\.?($|[\\/])/.test(pluginConfigEntry.name)
) {
this.logger.info(`Skipped loading plugin ${pluginConfigEntry.name || JSON.stringify(pluginConfigEntry)} because only package name is allowed plugin name`);
return;
}

View File

@@ -45,8 +45,20 @@ describe("unittests:: tsserver:: plugins:: loading", () => {
}
it("With local plugins", () => {
const expectedToLoad = ["@myscoped/plugin", "unscopedPlugin"];
const notToLoad = ["../myPlugin", "myPlugin/../malicious"];
const expectedToLoad = [
"@myscoped/plugin",
"@myscoped/plugin/subpath",
"@myscoped/plugin/sub/path",
"unscopedPlugin",
"unscopedPlugin/subpath",
"unscopedPlugin/sub/path",
];
const notToLoad = [
"../myPlugin",
"@myscoped/plugin/../malicious",
"myPlugin/../malicious",
"myPlugin/subpath/../../malicious",
];
const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` };
const tsconfig: File = {
path: "/tsconfig.json",
@@ -65,8 +77,20 @@ describe("unittests:: tsserver:: plugins:: loading", () => {
});
it("With global plugins", () => {
const expectedToLoad = ["@myscoped/plugin", "unscopedPlugin"];
const notToLoad = ["../myPlugin", "myPlugin/../malicious"];
const expectedToLoad = [
"@myscoped/plugin",
"@myscoped/plugin/subpath",
"@myscoped/plugin/sub/path",
"unscopedPlugin",
"unscopedPlugin/subpath",
"unscopedPlugin/sub/path",
];
const notToLoad = [
"../myPlugin",
"@myscoped/plugin/../malicious",
"myPlugin/../malicious",
"myPlugin/subpath/../../malicious",
];
const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` };
const tsconfig: File = {
path: "/tsconfig.json",

View File

@@ -60,17 +60,43 @@ Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin from candidate paths:
Info seq [hh:mm:ss:mss] Loading @myscoped/plugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: @myscoped/plugin
Info seq [hh:mm:ss:mss] Plugin validation succeeded
Info seq [hh:mm:ss:mss] Loading global plugin @myscoped/plugin/subpath
Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/subpath from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: @myscoped/plugin/subpath
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Loading global plugin @myscoped/plugin/sub/path
Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/sub/path from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: @myscoped/plugin/sub/path
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Loading global plugin unscopedPlugin
Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading unscopedPlugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: unscopedPlugin
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Loading global plugin unscopedPlugin/subpath
Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/subpath from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading unscopedPlugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: unscopedPlugin/subpath
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Loading global plugin unscopedPlugin/sub/path
Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/sub/path from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading unscopedPlugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: unscopedPlugin/sub/path
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Loading global plugin ../myPlugin
Info seq [hh:mm:ss:mss] Enabling plugin ../myPlugin from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin ../myPlugin because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] Loading global plugin @myscoped/plugin/../malicious
Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/../malicious from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin @myscoped/plugin/../malicious because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] Loading global plugin myPlugin/../malicious
Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/../malicious from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/../malicious because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] Loading global plugin myPlugin/subpath/../../malicious
Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/subpath/../../malicious from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/subpath/../../malicious because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms

View File

@@ -11,15 +11,33 @@ class c { prop = "hello"; foo() { return this.prop; } }
{
"name": "@myscoped/plugin"
},
{
"name": "@myscoped/plugin/subpath"
},
{
"name": "@myscoped/plugin/sub/path"
},
{
"name": "unscopedPlugin"
},
{
"name": "unscopedPlugin/subpath"
},
{
"name": "unscopedPlugin/sub/path"
},
{
"name": "../myPlugin"
},
{
"name": "@myscoped/plugin/../malicious"
},
{
"name": "myPlugin/../malicious"
},
{
"name": "myPlugin/subpath/../../malicious"
},
{
"transform": "some-transform"
}
@@ -74,15 +92,33 @@ Info seq [hh:mm:ss:mss] Config: /tsconfig.json : {
{
"name": "@myscoped/plugin"
},
{
"name": "@myscoped/plugin/subpath"
},
{
"name": "@myscoped/plugin/sub/path"
},
{
"name": "unscopedPlugin"
},
{
"name": "unscopedPlugin/subpath"
},
{
"name": "unscopedPlugin/sub/path"
},
{
"name": "../myPlugin"
},
{
"name": "@myscoped/plugin/../malicious"
},
{
"name": "myPlugin/../malicious"
},
{
"name": "myPlugin/subpath/../../malicious"
},
{
"transform": "some-transform"
}
@@ -96,14 +132,34 @@ Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin from candidate paths:
Info seq [hh:mm:ss:mss] Loading @myscoped/plugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: @myscoped/plugin
Info seq [hh:mm:ss:mss] Plugin validation succeeded
Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/subpath from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: @myscoped/plugin/subpath
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/sub/path from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: @myscoped/plugin/sub/path
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading unscopedPlugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: unscopedPlugin
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/subpath from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading unscopedPlugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: unscopedPlugin/subpath
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/sub/path from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Loading unscopedPlugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
Loading plugin: unscopedPlugin/sub/path
Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand"
Info seq [hh:mm:ss:mss] Enabling plugin ../myPlugin from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin ../myPlugin because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/../malicious from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin @myscoped/plugin/../malicious because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/../malicious from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/../malicious because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/subpath/../../malicious from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/subpath/../../malicious because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] Enabling plugin undefined from candidate paths: /a/lib/tsc.js/../../..
Info seq [hh:mm:ss:mss] Skipped loading plugin {"transform":"some-transform"} because only package name is allowed plugin name
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info
@@ -155,6 +211,12 @@ Info seq [hh:mm:ss:mss] event:
},
"compilerOptions": {
"plugins": [
"",
"",
"",
"",
"",
"",
"",
"",
"",