Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/compiler/moduleNameResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import {
PackageId,
packageIdToString,
Path,
pathIsAbsolute,
pathIsRelative,
Pattern,
patternText,
Expand Down Expand Up @@ -2531,6 +2532,9 @@ function extensionIsOk(extensions: Extensions, extension: string): boolean {

/** @internal */
export function parsePackageName(moduleName: string): { packageName: string; rest: string; } {
if (pathIsRelative(moduleName) || pathIsAbsolute(moduleName)) {
return { packageName: "", rest: moduleName };
}
let idx = moduleName.indexOf(directorySeparator);
if (moduleName[0] === "@") {
idx = moduleName.indexOf(directorySeparator, idx + 1);
Expand Down
15 changes: 13 additions & 2 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
DocumentRegistry,
DocumentRegistryBucketKeyWithMode,
emptyOptions,
ensurePathIsNonModuleName,
ensureTrailingDirectorySeparator,
ExtendedConfigCacheEntry,
FileExtensionInfo,
Expand Down Expand Up @@ -4487,8 +4488,18 @@ export class ProjectService {
}

this.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`);
if (!pluginConfigEntry.name || parsePackageName(pluginConfigEntry.name).rest) {
this.logger.info(`Skipped loading plugin ${pluginConfigEntry.name || JSON.stringify(pluginConfigEntry)} because only package name is allowed plugin name`);
if (!pluginConfigEntry.name) {
this.logger.info(`Skipped loading plugin ${JSON.stringify(pluginConfigEntry)} because plugin name was not specified`);
return;
}

const parsedPackageName = parsePackageName(pluginConfigEntry.name);
if (
!parsedPackageName.packageName ||
normalizePath(parsedPackageName.rest) !== parsedPackageName.rest ||
ensurePathIsNonModuleName(parsedPackageName.rest) === parsedPackageName.rest
) {
this.logger.info(`Skipped loading plugin ${pluginConfigEntry.name} because only package name is allowed plugin name`);
return;
}

Expand Down
32 changes: 28 additions & 4 deletions src/testRunner/unittests/tsserver/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
26 changes: 26 additions & 0 deletions tests/baselines/reference/tsserver/plugins/With-global-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
Expand Down
64 changes: 63 additions & 1 deletion tests/baselines/reference/tsserver/plugins/With-local-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down Expand Up @@ -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"
}
Expand All @@ -96,16 +132,36 @@ 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] Skipped loading plugin {"transform":"some-transform"} because plugin name was not specified
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 Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
Expand Down Expand Up @@ -155,6 +211,12 @@ Info seq [hh:mm:ss:mss] event:
},
"compilerOptions": {
"plugins": [
"",
"",
"",
"",
"",
"",
"",
"",
"",
Expand Down